Salome HOME
ENV: Windows porting.
[modules/geom.git] / src / GEOMImpl / GEOMImpl_IHealingOperations.cxx
1 #ifdef WNT
2 #pragma warning( disable:4786 )
3 #endif
4
5 #include <Standard_Stream.hxx>
6
7 #include <GEOMImpl_IHealingOperations.hxx>
8
9 #include <GEOM_PythonDump.hxx>
10
11 #include <GEOMImpl_HealingDriver.hxx>
12 #include <GEOMImpl_Types.hxx>
13 #include <GEOMImpl_IHealing.hxx>
14 #include <GEOMImpl_CopyDriver.hxx>
15
16 #include <ShHealOper_ShapeProcess.hxx>
17
18 #include "utilities.h"
19 #include <OpUtil.hxx>
20 #include <Utils_ExceptHandlers.hxx>
21
22 #include <ShapeAnalysis_FreeBounds.hxx>
23
24 #include <TopoDS_Compound.hxx>
25 #include <TopExp_Explorer.hxx>
26
27 #include <TColStd_HArray1OfExtendedString.hxx>
28 #include <TColStd_HSequenceOfTransient.hxx>
29 #include <TCollection_AsciiString.hxx>
30
31 #include <TDF_Tool.hxx>
32
33 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
34
35
36 //=============================================================================
37 /*!
38  *   constructor:
39  */
40 //=============================================================================
41
42 GEOMImpl_IHealingOperations::GEOMImpl_IHealingOperations (GEOM_Engine* theEngine, int theDocID)
43 : GEOM_IOperations(theEngine, theDocID)
44 {
45   MESSAGE("GEOMImpl_IHealingOperations::GEOMImpl_IHealingOperations");
46 }
47
48 //=============================================================================
49 /*!
50  *  destructor
51  */
52 //=============================================================================
53
54 GEOMImpl_IHealingOperations::~GEOMImpl_IHealingOperations()
55 {
56   MESSAGE("GEOMImpl_IHealingOperations::~GEOMImpl_IHealingOperations");
57 }
58
59
60 //=============================================================================
61 /*!
62  *  ShapeProcess
63  */
64 //=============================================================================
65 Handle(GEOM_Object) GEOMImpl_IHealingOperations::ShapeProcess (Handle(GEOM_Object) theObject,
66                                   const Handle(TColStd_HArray1OfExtendedString)& theOperators,
67                                   const Handle(TColStd_HArray1OfExtendedString)& theParams,
68                                   const Handle(TColStd_HArray1OfExtendedString)& theValues)
69 {
70   // set error code, check parameters
71   SetErrorCode(KO);
72
73   if (theObject.IsNull())
74     return NULL;
75
76   if (theOperators.IsNull() || theOperators->Length() <= 0) {
77     SetErrorCode("No operators requested");
78     return NULL;
79   }
80
81   Standard_Integer nbParams = 0, nbValues = 0;
82   if (!theParams.IsNull()) {
83     nbParams = theParams->Length();
84   }
85   if (!theValues.IsNull()) {
86     nbValues = theValues->Length();
87   }
88
89   if (nbParams != nbValues) {
90     SetErrorCode("Number of parameter values must be equal to the number of parameters");
91     return NULL;
92   }
93
94   Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
95   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
96
97   // Add a new object
98   Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
99
100   //Add the function
101   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), SHAPE_PROCESS);
102
103   if (aFunction.IsNull()) return NULL;
104
105   //Check if the function is set correctly
106   if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
107
108   // prepare "data container" class IHealing
109   GEOMImpl_IHealing HI(aFunction);
110   HI.SetOriginal(aLastFunction);
111   HI.SetOperators( theOperators );
112   if (nbParams > 0) {
113     HI.SetParameters( theParams );
114     HI.SetValues( theValues );
115   }
116
117   //Compute the translation
118   try
119   {
120     if (!GetSolver()->ComputeFunction(aFunction))
121     {
122       SetErrorCode("Shape Healing algorithm failed");
123       return NULL;
124     }
125   }
126   catch (Standard_Failure)
127   {
128     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
129     SetErrorCode(aFail->GetMessageString());
130     return NULL;
131   }
132
133   //Make a Python command
134   GEOM::TPythonDump pd (aFunction);
135   pd << aNewObject << " = geompy.ProcessShape(" << theObject << ", [";
136
137   // list of operators
138   int i = theOperators->Lower(), nb = theOperators->Upper();
139   for ( ; i <= nb; i++) {
140     pd << "\"" << TCollection_AsciiString(theOperators->Value( i )).ToCString()
141       << (( i < nb ) ? "\", " : "\"");
142   }
143   pd << "], [";
144   // list of parameters
145   i = theParams->Lower(); nb = theParams->Upper();
146   for ( ; i <= nb; i++) {
147     pd << "\"" << TCollection_AsciiString(theParams->Value( i )).ToCString()
148       << (( i < nb ) ? "\", " : "\"");
149   }
150   pd << "], [";
151   // list of values
152   i = theValues->Lower(); nb = theValues->Upper();
153   for ( ; i <= nb; i++) {
154     pd << "\"" << TCollection_AsciiString(theValues->Value( i )).ToCString()
155       << (( i < nb ) ? "\", " : "\"");
156   }
157   pd << "])";
158
159   SetErrorCode(OK);
160   return aNewObject;
161 }
162
163 //=============================================================================
164 /*!
165  *  ShapeProcess
166  */
167 //=============================================================================
168 void GEOMImpl_IHealingOperations::GetShapeProcessParameters (list<string>& theOperations,
169                                                              list<string>& theParams,
170                                                              list<string>& theValues)
171 {
172   ShHealOper_ShapeProcess aHealer;
173   TColStd_SequenceOfAsciiString anOperators;
174   int nbOperatorErrors( 0 );
175   if ( aHealer.GetOperators( anOperators ) )
176   {
177     for ( Standard_Integer i = 1; i <= anOperators.Length(); i++ )
178     {
179       string anOperation = anOperators.Value( i ).ToCString();
180       if ( GetOperatorParameters( anOperation, theParams, theValues ) )
181         theOperations.push_back( anOperation );
182       else
183         nbOperatorErrors++;
184     }
185   }
186   else
187   {
188     SetErrorCode("ERROR retrieving operators (GEOMImpl_IHealingOperations)");
189   }
190
191   if ( nbOperatorErrors ) {
192     TCollection_AsciiString aMsg ("ERRORS retrieving ShapeProcess parameters (GEOMImpl_IHealingOperations): nbOperatorErrors = ");
193     aMsg += TCollection_AsciiString( nbOperatorErrors );
194     MESSAGE(aMsg.ToCString());
195   }
196 }
197
198 //=============================================================================
199 /*!
200  *  GetOperatorParameters
201  */
202 //=============================================================================
203 bool GEOMImpl_IHealingOperations::GetOperatorParameters( const string theOperation, 
204                                                          list<string>& theParams,
205                                                          list<string>& theValues )
206 {
207   ShHealOper_ShapeProcess aHealer;
208   int nbParamValueErrors( 0 );
209   list<string> aParams;
210   if ( GetParameters( theOperation, aParams ) ) {
211     for ( list<string>::iterator it = aParams.begin(); it != aParams.end(); ++it ) {
212       TCollection_AsciiString aParam( (Standard_CString)(*it).c_str() );
213       TCollection_AsciiString aValue;
214       if ( aHealer.GetParameter( aParam, aValue ) ) {
215         theParams.push_back( aParam.ToCString() );
216         theValues.push_back( aValue.ToCString() );
217       }
218       else
219         nbParamValueErrors++;
220     }
221   }
222   else
223     return false;
224
225   if ( nbParamValueErrors ) {
226     TCollection_AsciiString aMsg ("ERRORS retrieving ShapeProcess parameter values (GEOMImpl_IHealingOperations): nbParamValueErrors = ");
227     aMsg += TCollection_AsciiString( nbParamValueErrors );
228     MESSAGE(aMsg.ToCString());
229   }
230
231   return true;
232 }
233
234 //=============================================================================
235 /*!
236  *  GetParameters
237  */
238 //=============================================================================
239 bool GEOMImpl_IHealingOperations::GetParameters (const string theOperation,
240                                                  list<string>& theParams)
241 {
242   if ( theOperation == "SplitAngle" ) {
243     theParams.push_back( "SplitAngle.Angle" );
244     theParams.push_back( "SplitAngle.MaxTolerance" );
245
246   } else if ( theOperation == "SplitClosedFaces" ) {
247     theParams.push_back( "SplitClosedFaces.NbSplitPoints" );
248
249   } else if ( theOperation == "FixFaceSize" ) {
250     theParams.push_back( "FixFaceSize.Tolerance" );
251
252   } else if( theOperation == "DropSmallEdges" ) {
253     theParams.push_back( "DropSmallEdges.Tolerance3d" );
254
255   } else if( theOperation == "BSplineRestriction" ) {
256     theParams.push_back( "BSplineRestriction.SurfaceMode" );
257     theParams.push_back( "BSplineRestriction.Curve3dMode" );
258     theParams.push_back( "BSplineRestriction.Curve2dMode" );
259     theParams.push_back( "BSplineRestriction.Tolerance3d" );
260     theParams.push_back( "BSplineRestriction.Tolerance2d" );
261     theParams.push_back( "BSplineRestriction.RequiredDegree" );
262     theParams.push_back( "BSplineRestriction.RequiredNbSegments" );
263     theParams.push_back( "BSplineRestriction.Continuity3d" );
264     theParams.push_back( "BSplineRestriction.Continuity2d" );
265
266   } else if( theOperation == "SplitContinuity" ) {
267     theParams.push_back( "SplitContinuity.Tolerance3d" );
268     theParams.push_back( "SplitContinuity.SurfaceContinuity" );
269     theParams.push_back( "SplitContinuity.CurveContinuity" );
270
271   } else if( theOperation == "ToBezier" ) {
272     theParams.push_back( "ToBezier.SurfaceMode" );
273     theParams.push_back( "ToBezier.Curve3dMode" );
274     theParams.push_back( "ToBezier.Curve2dMode" );
275     theParams.push_back( "ToBezier.MaxTolerance" );
276
277   } else if( theOperation == "SameParameter" ) {
278     theParams.push_back( "SameParameter.Tolerance3d" );
279
280   } else if( theOperation == "FixShape" ) {
281     theParams.push_back( "FixShape.Tolerance3d" );
282     theParams.push_back( "FixShape.MaxTolerance3d" );
283
284   } else {
285     return false;
286   }
287
288   return true;
289 }
290
291 //=============================================================================
292 /*!
293  *  SuppressFaces
294  */
295 //=============================================================================
296 Handle(GEOM_Object) GEOMImpl_IHealingOperations::SuppressFaces
297        (Handle(GEOM_Object) theObject, const Handle(TColStd_HArray1OfInteger)& theFaces)
298 {
299   // set error code, check parameters
300   SetErrorCode(KO);
301
302   if ( theObject.IsNull() ) // if theFaces.IsNull() - it's OK, it means that ALL faces must be removed..
303     return NULL;
304
305   Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
306   if(aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
307
308   // Add a new object
309   Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
310
311   //Add the function
312   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), SUPPRESS_FACES);
313
314   if(aFunction.IsNull()) return NULL;
315
316   //Check if the function is set correctly
317   if(aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
318
319   // prepare "data container" class IHealing
320   GEOMImpl_IHealing HI(aFunction);
321   HI.SetFaces( theFaces );
322   HI.SetOriginal( aLastFunction );
323
324   //Compute the translation
325   try
326   {
327     if (!GetSolver()->ComputeFunction(aFunction))
328     {
329       SetErrorCode("Healing driver failed");
330       return NULL;
331     }
332   }
333   catch (Standard_Failure)
334   {
335         Handle(Standard_Failure) aFail = Standard_Failure::Caught();
336     SetErrorCode(aFail->GetMessageString());
337     return NULL;
338   }
339
340   //Make a Python command
341   GEOM::TPythonDump pd (aFunction);
342   pd << aNewObject << " = geompy.SuppressFaces(" << theObject << ", [";
343
344   // list of face ids
345   int i = theFaces->Lower(), nb = theFaces->Upper();
346   for ( ; i <= nb; i++)
347     pd << theFaces->Value( i ) << (( i < nb ) ? ", " : "])");
348
349   SetErrorCode(OK);
350   return aNewObject;
351 }
352
353
354 //=============================================================================
355 /*!
356  *  CloseContour
357  */
358 //=============================================================================
359 Handle(GEOM_Object) GEOMImpl_IHealingOperations::CloseContour
360                     (Handle(GEOM_Object) theObject,
361                      const Handle(TColStd_HArray1OfInteger)& theWires,
362                      bool isCommonVertex)
363 {
364   // set error code, check parameters
365   SetErrorCode(KO);
366
367   if (theObject.IsNull())
368     return NULL;
369
370   Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
371   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
372
373   // Add a new object
374   Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
375
376   //Add the function
377   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), CLOSE_CONTOUR);
378
379   if (aFunction.IsNull()) return NULL;
380
381   //Check if the function is set correctly
382   if(aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
383
384   // prepare "data container" class IHealing
385   GEOMImpl_IHealing HI(aFunction);
386   HI.SetWires( theWires );
387   HI.SetIsCommonVertex( isCommonVertex );
388   HI.SetOriginal( aLastFunction );
389
390   //Compute the translation
391   try
392   {
393     if (!GetSolver()->ComputeFunction(aFunction))
394     {
395       SetErrorCode("Healing driver failed");
396       return NULL;
397     }
398   }
399   catch (Standard_Failure)
400   {
401         Handle(Standard_Failure) aFail = Standard_Failure::Caught();
402     SetErrorCode(aFail->GetMessageString());
403     return NULL;
404   }
405
406   //Make a Python command
407   GEOM::TPythonDump pd (aFunction);
408   pd << aNewObject << " = geompy.CloseContour(" << theObject << ", [";
409
410   // list of wire ids
411   int i = theWires->Lower(), nb = theWires->Upper();
412   for ( ; i <= nb; i++)
413     pd << theWires->Value( i ) << (( i < nb ) ? ", " : "], ");
414
415   pd << (int)isCommonVertex << ")";
416
417   SetErrorCode(OK);
418   return aNewObject;
419 }
420
421 //=============================================================================
422 /*!
423  *  RemoveIntWires
424  */
425 //=============================================================================
426 Handle(GEOM_Object) GEOMImpl_IHealingOperations::RemoveIntWires
427        (Handle(GEOM_Object) theObject, const Handle(TColStd_HArray1OfInteger)& theWires)
428 {
429   // set error code, check parameters
430   SetErrorCode(KO);
431
432   if (theObject.IsNull()) // if theWires is NULL it's OK, it means that ALL wires must be removed
433     return NULL;
434
435   Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
436   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
437
438   // Add a new object
439   Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
440
441   //Add the function
442   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), REMOVE_INT_WIRES);
443
444   if (aFunction.IsNull()) return NULL;
445
446   //Check if the function is set correctly
447   if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
448
449   // prepare "data container" class IHealing
450   GEOMImpl_IHealing HI(aFunction);
451   HI.SetWires( theWires );
452   HI.SetOriginal( aLastFunction );
453
454   //Compute the translation
455   try
456   {
457     if (!GetSolver()->ComputeFunction(aFunction))
458     {
459       SetErrorCode("Healing driver failed");
460       return NULL;
461     }
462   }
463   catch (Standard_Failure)
464   {
465     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
466     SetErrorCode(aFail->GetMessageString());
467     return NULL;
468   }
469
470   //Make a Python command
471   GEOM::TPythonDump pd (aFunction);
472   pd << aNewObject << " = geompy.SuppressInternalWires(" << theObject << ", [";
473
474   // list of wire ids
475   if (!theWires.IsNull()) {
476     int i = theWires->Lower(), nb = theWires->Upper();
477     for ( ; i <= nb; i++)
478       pd << theWires->Value( i ) << (( i < nb ) ? ", " : "])");
479   } else {
480     pd << "])";
481   }
482
483   SetErrorCode(OK);
484   return aNewObject;
485 }
486
487 //=============================================================================
488 /*!
489  *  FillHoles
490  */
491 //=============================================================================
492 Handle(GEOM_Object) GEOMImpl_IHealingOperations::FillHoles (Handle(GEOM_Object) theObject,
493                                                             const Handle(TColStd_HArray1OfInteger)& theWires)
494 {
495   // set error code, check parameters
496   SetErrorCode(KO);
497
498   if (theObject.IsNull()) // if theWires is NULL it's OK, it means that ALL holes must be removed
499     return NULL;
500
501   Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
502   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
503
504   // Add a new object
505   Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
506
507   //Add the function
508   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), FILL_HOLES);
509
510   if (aFunction.IsNull()) return NULL;
511
512   //Check if the function is set correctly
513   if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
514
515   // prepare "data container" class IHealing
516   GEOMImpl_IHealing HI(aFunction);
517   HI.SetWires( theWires );
518   HI.SetOriginal( aLastFunction );
519
520   //Compute the translation
521   try
522   {
523     if (!GetSolver()->ComputeFunction(aFunction))
524     {
525       SetErrorCode("Healing driver failed");
526       return NULL;
527     }
528   }
529   catch (Standard_Failure)
530   {
531         Handle(Standard_Failure) aFail = Standard_Failure::Caught();
532     SetErrorCode(aFail->GetMessageString());
533     return NULL;
534   }
535
536   //Make a Python command
537   GEOM::TPythonDump pd (aFunction);
538   pd << aNewObject << " = geompy.SuppressHoles(" << theObject << ", [";
539
540   // list of wire ids
541   if ( theWires.IsNull() )
542     pd << "])";
543   else {
544     int i = theWires->Lower(), nb = theWires->Upper();
545     for ( ; i <= nb; i++)
546       pd << theWires->Value( i ) << (( i < nb ) ? ", " : "])");
547   }
548
549   SetErrorCode(OK);
550   return aNewObject;
551 }
552
553 //=============================================================================
554 /*!
555  *  Sew
556  */
557 //=============================================================================
558 Handle(GEOM_Object) GEOMImpl_IHealingOperations::Sew (Handle(GEOM_Object) theObject,
559                                                       double theTolerance)
560 {
561   // set error code, check parameters
562   SetErrorCode(KO);
563
564   if (theObject.IsNull())
565     return NULL;
566
567   Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
568   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
569
570   // Add a new object
571   Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
572
573   //Add the function
574   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), SEWING);
575
576   if (aFunction.IsNull()) return NULL;
577
578   //Check if the function is set correctly
579   if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
580
581   // prepare "data container" class IHealing
582   GEOMImpl_IHealing HI(aFunction);
583   HI.SetTolerance( theTolerance );
584   HI.SetOriginal( aLastFunction );
585
586   //Compute the translation
587   try
588   {
589     if (!GetSolver()->ComputeFunction(aFunction))
590     {
591       SetErrorCode("Healing driver failed");
592       return NULL;
593     }
594   }
595   catch (Standard_Failure)
596   {
597         Handle(Standard_Failure) aFail = Standard_Failure::Caught();
598     SetErrorCode(aFail->GetMessageString());
599     return NULL;
600   }
601
602   //Make a Python command
603   GEOM::TPythonDump(aFunction) << aNewObject << " = geompy.Sew("
604                                << theObject << ", " << theTolerance << ")";
605
606   SetErrorCode(OK);
607   return aNewObject;
608 }
609
610 //=============================================================================
611 /*!
612  *  DivideEdge
613  */
614 //=============================================================================
615 Handle(GEOM_Object) GEOMImpl_IHealingOperations::DivideEdge (Handle(GEOM_Object) theObject,
616                                                              int theIndex,
617                                                              double theValue,
618                                                              bool isByParameter)
619 {
620   // set error code, check parameters
621   SetErrorCode(KO);
622
623   if (theObject.IsNull())
624     return NULL;
625
626   Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
627   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
628
629   // Add a new object
630   Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
631
632   //Add the function
633   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), DIVIDE_EDGE);
634
635   if (aFunction.IsNull()) return NULL;
636
637   //Check if the function is set correctly
638   if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
639
640   // prepare "data container" class IHealing
641   GEOMImpl_IHealing HI(aFunction);
642   HI.SetIndex( theIndex );
643   HI.SetDevideEdgeValue( theValue );
644   HI.SetIsByParameter( isByParameter );
645   HI.SetOriginal( aLastFunction );
646
647   //Compute the translation
648   try
649   {
650     if (!GetSolver()->ComputeFunction(aFunction))
651     {
652       SetErrorCode("Healing driver failed");
653       return NULL;
654     }
655   }
656   catch (Standard_Failure)
657   {
658         Handle(Standard_Failure) aFail = Standard_Failure::Caught();
659     SetErrorCode(aFail->GetMessageString());
660     return NULL;
661   }
662
663   //Make a Python command
664   GEOM::TPythonDump(aFunction) << aNewObject << " = geompy.DivideEdge(" << theObject
665     << ", " << theIndex << ", " << theValue << ", " << (int)isByParameter << ")";
666
667   SetErrorCode(OK);
668   return aNewObject;
669 }
670
671 //=============================================================================
672 /*!
673  *  GetFreeBoundary
674  */
675 //=============================================================================
676 bool GEOMImpl_IHealingOperations::GetFreeBoundary (Handle(GEOM_Object) theObject,
677                                                    Handle(TColStd_HSequenceOfTransient)& theClosed,
678                                                    Handle(TColStd_HSequenceOfTransient)& theOpen )
679 {
680   // set error code, check parameters
681   SetErrorCode(KO);
682
683   if ( theObject.IsNull() || theClosed.IsNull() || theOpen.IsNull() )
684     return false;
685
686   TopoDS_Shape aShape = theObject->GetValue();
687   if ( aShape.IsNull() )
688     return false;
689
690   // get free boundary shapes
691   ShapeAnalysis_FreeBounds anAnalizer( aShape );
692   TopoDS_Compound aClosed = anAnalizer.GetClosedWires();
693   TopoDS_Compound anOpen = anAnalizer.GetOpenWires();
694
695   // iterate through shapes and append them to the return sequence
696   Handle(GEOM_Object) anObj;
697   Handle(GEOM_Function) aFunction;
698   TopExp_Explorer anExp;
699   for ( anExp.Init( aClosed, TopAbs_WIRE ); anExp.More(); anExp.Next() )
700   {
701     anObj = GetEngine()->AddObject( GetDocID(), GEOM_FREE_BOUNDS );
702     aFunction = anObj->AddFunction( GEOMImpl_CopyDriver::GetID(), COPY_WITHOUT_REF );
703     TopoDS_Shape aValueShape = anExp.Current();
704     aFunction->SetValue( aValueShape );
705     theClosed->Append(anObj);
706   }
707   for ( anExp.Init( anOpen, TopAbs_WIRE ); anExp.More(); anExp.Next() )
708   {
709     anObj = GetEngine()->AddObject( GetDocID(), GEOM_FREE_BOUNDS );
710     aFunction = anObj->AddFunction( GEOMImpl_CopyDriver::GetID(), COPY_WITHOUT_REF );
711     TopoDS_Shape aValueShape = anExp.Current();
712     aFunction->SetValue( aValueShape );
713     theOpen->Append(anObj);
714   }
715
716   //Make a Python command
717   GEOM::TPythonDump pd (aFunction);
718
719   Standard_Integer i, aLen = theClosed->Length();
720   if (aLen > 0) {
721     pd << "(isDone, [";
722     for (i = 1; i <= aLen; i++) {
723       Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theClosed->Value(i));
724       pd << anObj_i << ((i < aLen) ? ", " : "");
725     }
726     pd << "], ";
727   } else {
728     pd << "(isDone, empty_list, ";
729   }
730
731   aLen = theOpen->Length();
732   if (aLen > 0) {
733     pd << "[";
734     for (i = 1; i <= aLen; i++) {
735       Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theOpen->Value(i));
736       pd << anObj_i << ((i < aLen) ? ", " : "");
737     }
738     pd << "]";
739   } else {
740     pd << "empty_list";
741   }
742
743   pd << ") = geompy.GetFreeBoundary(" << theObject << ")";
744
745   SetErrorCode(OK);
746   return true;
747 }