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