Salome HOME
0022746: [EDF] Improvement of Glue Faces and Glue Edges operations
[modules/geom.git] / src / GEOMImpl / GEOMImpl_IHealingOperations.cxx
1 // Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #ifdef WIN32
24 #pragma warning( disable:4786 )
25 #endif
26
27 #include <Standard_Version.hxx>
28 #include <Standard_Stream.hxx>
29
30 #include <GEOMImpl_IHealingOperations.hxx>
31 #include <GEOM_PythonDump.hxx>
32 #include <GEOMImpl_HealingDriver.hxx>
33 #include <GEOMImpl_Types.hxx>
34 #include <GEOMImpl_IHealing.hxx>
35 #include <GEOMImpl_IVector.hxx>
36 #include <GEOMImpl_VectorDriver.hxx>
37 #include <GEOMImpl_CopyDriver.hxx>
38
39 #include <Basics_OCCTVersion.hxx>
40
41 #include <utilities.h>
42 #include <OpUtil.hxx>
43 #include <Utils_ExceptHandlers.hxx>
44
45 #include <BRep_Builder.hxx>
46 #include <ShHealOper_ShapeProcess.hxx>
47 #include <ShapeAnalysis_FreeBounds.hxx>
48 #include <TColStd_HArray1OfExtendedString.hxx>
49 #include <TColStd_HSequenceOfTransient.hxx>
50 #include <TCollection_AsciiString.hxx>
51 #include <TDF_Tool.hxx>
52 #include <TopExp_Explorer.hxx>
53 #include <TopTools_SequenceOfShape.hxx>
54 #include <TopoDS_Compound.hxx>
55
56 #include <Standard_Failure.hxx>
57 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
58
59 //=============================================================================
60 /*!
61  *   constructor:
62  */
63 //=============================================================================
64 GEOMImpl_IHealingOperations::GEOMImpl_IHealingOperations (GEOM_Engine* theEngine, int theDocID)
65 : GEOM_IOperations(theEngine, theDocID)
66 {
67   MESSAGE("GEOMImpl_IHealingOperations::GEOMImpl_IHealingOperations");
68 }
69
70 //=============================================================================
71 /*!
72  *  destructor
73  */
74 //=============================================================================
75 GEOMImpl_IHealingOperations::~GEOMImpl_IHealingOperations()
76 {
77   MESSAGE("GEOMImpl_IHealingOperations::~GEOMImpl_IHealingOperations");
78 }
79
80
81 //=============================================================================
82 /*!
83  *  ShapeProcess
84  */
85 //=============================================================================
86 Handle(GEOM_Object) GEOMImpl_IHealingOperations::ShapeProcess (Handle(GEOM_Object) theObject,
87                                   const Handle(TColStd_HArray1OfExtendedString)& theOperators,
88                                   const Handle(TColStd_HArray1OfExtendedString)& theParams,
89                                   const Handle(TColStd_HArray1OfExtendedString)& theValues)
90 {
91   // set error code, check parameters
92   SetErrorCode(KO);
93
94   if (theObject.IsNull())
95     return NULL;
96
97   if (theOperators.IsNull() || theOperators->Length() <= 0) {
98     SetErrorCode("No operators requested");
99     return NULL;
100   }
101
102   Standard_Integer nbParams = 0, nbValues = 0;
103   if (!theParams.IsNull()) {
104     nbParams = theParams->Length();
105   }
106   if (!theValues.IsNull()) {
107     nbValues = theValues->Length();
108   }
109
110   if (nbParams != nbValues) {
111     SetErrorCode("Number of parameter values must be equal to the number of parameters");
112     return NULL;
113   }
114
115   Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
116   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
117
118   // Add a new object
119   Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
120
121   //Add the function
122   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), SHAPE_PROCESS);
123
124   if (aFunction.IsNull()) return NULL;
125
126   //Check if the function is set correctly
127   if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
128
129   // prepare "data container" class IHealing
130   GEOMImpl_IHealing HI(aFunction);
131   HI.SetOriginal(aLastFunction);
132   HI.SetOperators( theOperators );
133   if (nbParams > 0) {
134     HI.SetParameters( theParams );
135     HI.SetValues( theValues );
136   }
137
138   //Compute the translation
139   try {
140     OCC_CATCH_SIGNALS;
141     if (!GetSolver()->ComputeFunction(aFunction))
142     {
143       SetErrorCode("Shape Healing algorithm failed");
144       return NULL;
145     }
146   }
147   catch (Standard_Failure)
148   {
149     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
150     SetErrorCode(aFail->GetMessageString());
151     return NULL;
152   }
153
154   //Make a Python command
155   GEOM::TPythonDump pd (aFunction);
156   pd << aNewObject << " = geompy.ProcessShape(" << theObject << ", [";
157
158   // list of operators
159   int i = theOperators->Lower(), nb = theOperators->Upper();
160   for ( ; i <= nb; i++) {
161     pd << "\"" << TCollection_AsciiString(theOperators->Value( i )).ToCString()
162       << (( i < nb ) ? "\", " : "\"");
163   }
164   pd << "], [";
165   // list of parameters
166   i = theParams->Lower(); nb = theParams->Upper();
167   for ( ; i <= nb; i++) {
168     pd << "\"" << TCollection_AsciiString(theParams->Value( i )).ToCString()
169       << (( i < nb ) ? "\", " : "\"");
170   }
171   pd << "], [";
172   // list of values
173   i = theValues->Lower(); nb = theValues->Upper();
174   for ( ; i <= nb; i++) {
175     pd << "\"" << TCollection_AsciiString(theValues->Value( i )).ToCString()
176       << (( i < nb ) ? "\", " : "\"");
177   }
178   pd << "])";
179
180   SetErrorCode(OK);
181   return aNewObject;
182 }
183
184 //=============================================================================
185 /*!
186  *  ShapeProcess
187  */
188 //=============================================================================
189 void GEOMImpl_IHealingOperations::GetShapeProcessParameters (std::list<std::string>& theOperations,
190                                                              std::list<std::string>& theParams,
191                                                              std::list<std::string>& theValues)
192 {
193   ShHealOper_ShapeProcess aHealer;
194   TColStd_SequenceOfAsciiString anOperators;
195   int nbOperatorErrors( 0 );
196   if ( aHealer.GetOperators( anOperators ) )
197   {
198     for ( Standard_Integer i = 1; i <= anOperators.Length(); i++ )
199     {
200       std::string anOperation = anOperators.Value( i ).ToCString();
201       if ( GetOperatorParameters( anOperation, theParams, theValues ) )
202         theOperations.push_back( anOperation );
203       else
204         nbOperatorErrors++;
205     }
206   }
207   else
208   {
209     SetErrorCode("ERROR retrieving operators (GEOMImpl_IHealingOperations)");
210   }
211
212   if ( nbOperatorErrors ) {
213     TCollection_AsciiString aMsg ("ERRORS retrieving ShapeProcess parameters (GEOMImpl_IHealingOperations): nbOperatorErrors = ");
214     aMsg += TCollection_AsciiString( nbOperatorErrors );
215     MESSAGE(aMsg.ToCString());
216   }
217 }
218
219 //=============================================================================
220 /*!
221  *  GetOperatorParameters
222  */
223 //=============================================================================
224 bool GEOMImpl_IHealingOperations::GetOperatorParameters( const std::string &     theOperation,
225                                                          std::list<std::string>& theParams,
226                                                          std::list<std::string>& theValues )
227 {
228   ShHealOper_ShapeProcess aHealer;
229   int nbParamValueErrors( 0 );
230   std::list<std::string> aParams;
231   if ( GetParameters( theOperation, aParams ) ) {
232     for ( std::list<std::string>::iterator it = aParams.begin(); it != aParams.end(); ++it ) {
233       TCollection_AsciiString aParam( (Standard_CString)(*it).c_str() );
234       TCollection_AsciiString aValue;
235       if ( aHealer.GetParameter( aParam, aValue ) ) {
236         theParams.push_back( aParam.ToCString() );
237         theValues.push_back( aValue.ToCString() );
238       }
239       else
240         nbParamValueErrors++;
241     }
242   }
243   else
244     return false;
245
246   if ( nbParamValueErrors ) {
247     TCollection_AsciiString aMsg ("ERRORS retrieving ShapeProcess parameter values (GEOMImpl_IHealingOperations): nbParamValueErrors = ");
248     aMsg += TCollection_AsciiString( nbParamValueErrors );
249     MESSAGE(aMsg.ToCString());
250   }
251
252   return true;
253 }
254
255 //=============================================================================
256 /*!
257  *  GetParameters
258  */
259 //=============================================================================
260 bool GEOMImpl_IHealingOperations::GetParameters (const std::string theOperation,
261                                                  std::list<std::string>& theParams)
262 {
263   if ( theOperation == "SplitAngle" ) {
264     theParams.push_back( "SplitAngle.Angle" );
265     theParams.push_back( "SplitAngle.MaxTolerance" );
266
267   } else if ( theOperation == "SplitClosedFaces" ) {
268     theParams.push_back( "SplitClosedFaces.NbSplitPoints" );
269
270   } else if ( theOperation == "FixFaceSize" ) {
271     theParams.push_back( "FixFaceSize.Tolerance" );
272
273   } else if( theOperation == "DropSmallEdges" ) {
274     theParams.push_back( "DropSmallEdges.Tolerance3d" );
275
276   } else if( theOperation == "BSplineRestriction" ) {
277     theParams.push_back( "BSplineRestriction.SurfaceMode" );
278     theParams.push_back( "BSplineRestriction.Curve3dMode" );
279     theParams.push_back( "BSplineRestriction.Curve2dMode" );
280     theParams.push_back( "BSplineRestriction.Tolerance3d" );
281     theParams.push_back( "BSplineRestriction.Tolerance2d" );
282     theParams.push_back( "BSplineRestriction.RequiredDegree" );
283     theParams.push_back( "BSplineRestriction.RequiredNbSegments" );
284     theParams.push_back( "BSplineRestriction.Continuity3d" );
285     theParams.push_back( "BSplineRestriction.Continuity2d" );
286
287   } else if( theOperation == "SplitContinuity" ) {
288     theParams.push_back( "SplitContinuity.Tolerance3d" );
289     theParams.push_back( "SplitContinuity.SurfaceContinuity" );
290     theParams.push_back( "SplitContinuity.CurveContinuity" );
291
292   } else if( theOperation == "ToBezier" ) {
293     theParams.push_back( "ToBezier.SurfaceMode" );
294     theParams.push_back( "ToBezier.Curve3dMode" );
295     theParams.push_back( "ToBezier.Curve2dMode" );
296     theParams.push_back( "ToBezier.MaxTolerance" );
297
298   } else if( theOperation == "SameParameter" ) {
299     theParams.push_back( "SameParameter.Tolerance3d" );
300
301   } else if( theOperation == "FixShape" ) {
302     theParams.push_back( "FixShape.Tolerance3d" );
303     theParams.push_back( "FixShape.MaxTolerance3d" );
304
305   } else {
306     return false;
307   }
308
309   return true;
310 }
311
312 //=============================================================================
313 /*!
314  *  SuppressFaces
315  */
316 //=============================================================================
317 Handle(GEOM_Object) GEOMImpl_IHealingOperations::SuppressFaces
318        (Handle(GEOM_Object) theObject, const Handle(TColStd_HArray1OfInteger)& theFaces)
319 {
320   // set error code, check parameters
321   SetErrorCode(KO);
322
323   if (theObject.IsNull()) // if theFaces.IsNull() - it's OK, it means that ALL faces must be removed..
324     return NULL;
325
326   Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
327   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
328
329   // Add a new object
330   Handle(GEOM_Object) aNewObject = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
331
332   //Add the function
333   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), SUPPRESS_FACES);
334
335   if (aFunction.IsNull()) return NULL;
336
337   //Check if the function is set correctly
338   if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
339
340   // prepare "data container" class IHealing
341   GEOMImpl_IHealing HI (aFunction);
342   HI.SetFaces(theFaces);
343   HI.SetOriginal(aLastFunction);
344
345   //Compute the translation
346   try {
347     OCC_CATCH_SIGNALS;
348     if (!GetSolver()->ComputeFunction(aFunction))
349     {
350       SetErrorCode("Healing driver failed");
351       return NULL;
352     }
353   }
354   catch (Standard_Failure)
355   {
356     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
357     SetErrorCode(aFail->GetMessageString());
358     return NULL;
359   }
360
361   //Make a Python command
362   GEOM::TPythonDump pd (aFunction);
363   pd << aNewObject << " = geompy.SuppressFaces(" << theObject << ", [";
364
365   // list of face ids
366   int i = theFaces->Lower(), nb = theFaces->Upper();
367   for ( ; i <= nb; i++)
368     pd << theFaces->Value( i ) << (( i < nb ) ? ", " : "])");
369
370   SetErrorCode(OK);
371   return aNewObject;
372 }
373
374 //=============================================================================
375 /*!
376  *  CloseContour
377  */
378 //=============================================================================
379 Handle(GEOM_Object) GEOMImpl_IHealingOperations::CloseContour
380                     (Handle(GEOM_Object) theObject,
381                      const Handle(TColStd_HArray1OfInteger)& theWires,
382                      bool isCommonVertex)
383 {
384   // set error code, check parameters
385   SetErrorCode(KO);
386
387   if (theObject.IsNull())
388   {
389     SetErrorCode("NULL object given");
390     return NULL;
391   }
392
393   Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
394   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
395
396   // Add a new object
397   Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
398
399   //Add the function
400   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), CLOSE_CONTOUR);
401
402   if (aFunction.IsNull()) return NULL;
403
404   //Check if the function is set correctly
405   if(aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
406
407   // prepare "data container" class IHealing
408   GEOMImpl_IHealing HI(aFunction);
409   HI.SetWires( theWires );
410   HI.SetIsCommonVertex( isCommonVertex );
411   HI.SetOriginal( aLastFunction );
412
413   //Compute the translation
414   try {
415     OCC_CATCH_SIGNALS;
416     if (!GetSolver()->ComputeFunction(aFunction))
417     {
418       SetErrorCode("Healing driver failed");
419       return NULL;
420     }
421   }
422   catch (Standard_Failure)
423   {
424         Handle(Standard_Failure) aFail = Standard_Failure::Caught();
425     SetErrorCode(aFail->GetMessageString());
426     return NULL;
427   }
428
429   //Make a Python command
430   GEOM::TPythonDump pd (aFunction);
431   pd << aNewObject << " = geompy.CloseContour(" << theObject << ", [";
432
433   // list of wire ids
434   if (!theWires.IsNull())
435   {
436     int i = theWires->Lower(), nb = theWires->Upper();
437     pd << theWires->Value(i++);
438     while (i <= nb)
439       pd << ", " << theWires->Value(i++);
440   }
441   pd << "], " << (int)isCommonVertex << ")";
442
443   SetErrorCode(OK);
444   return aNewObject;
445 }
446
447 //=============================================================================
448 /*!
449  *  RemoveIntWires
450  */
451 //=============================================================================
452 Handle(GEOM_Object) GEOMImpl_IHealingOperations::RemoveIntWires
453        (Handle(GEOM_Object) theObject, const Handle(TColStd_HArray1OfInteger)& theWires)
454 {
455   // set error code, check parameters
456   SetErrorCode(KO);
457
458   if (theObject.IsNull()) // if theWires is NULL it's OK, it means that ALL wires must be removed
459     return NULL;
460
461   Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
462   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
463
464   // Add a new object
465   Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
466
467   //Add the function
468   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), REMOVE_INT_WIRES);
469
470   if (aFunction.IsNull()) return NULL;
471
472   //Check if the function is set correctly
473   if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
474
475   // prepare "data container" class IHealing
476   GEOMImpl_IHealing HI(aFunction);
477   HI.SetWires( theWires );
478   HI.SetOriginal( aLastFunction );
479
480   //Compute the translation
481   try {
482     OCC_CATCH_SIGNALS;
483     if (!GetSolver()->ComputeFunction(aFunction))
484     {
485       SetErrorCode("Healing driver failed");
486       return NULL;
487     }
488   }
489   catch (Standard_Failure)
490   {
491     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
492     SetErrorCode(aFail->GetMessageString());
493     return NULL;
494   }
495
496   //Make a Python command
497   GEOM::TPythonDump pd (aFunction);
498   pd << aNewObject << " = geompy.SuppressInternalWires(" << theObject << ", [";
499
500   // list of wire ids
501   if (!theWires.IsNull()) {
502     int i = theWires->Lower(), nb = theWires->Upper();
503     for ( ; i <= nb; i++)
504       pd << theWires->Value( i ) << (( i < nb ) ? ", " : "])");
505   } else {
506     pd << "])";
507   }
508
509   SetErrorCode(OK);
510   return aNewObject;
511 }
512
513 //=============================================================================
514 /*!
515  *  FillHoles
516  */
517 //=============================================================================
518 Handle(GEOM_Object) GEOMImpl_IHealingOperations::FillHoles (Handle(GEOM_Object) theObject,
519                                                             const Handle(TColStd_HArray1OfInteger)& theWires)
520 {
521   // set error code, check parameters
522   SetErrorCode(KO);
523
524   if (theObject.IsNull()) // if theWires is NULL it's OK, it means that ALL holes must be removed
525     return NULL;
526
527   Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
528   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
529
530   // Add a new object
531   Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
532
533   //Add the function
534   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), FILL_HOLES);
535
536   if (aFunction.IsNull()) return NULL;
537
538   //Check if the function is set correctly
539   if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
540
541   // prepare "data container" class IHealing
542   GEOMImpl_IHealing HI(aFunction);
543   HI.SetWires( theWires );
544   HI.SetOriginal( aLastFunction );
545
546   //Compute the translation
547   try {
548     OCC_CATCH_SIGNALS;
549     if (!GetSolver()->ComputeFunction(aFunction))
550     {
551       SetErrorCode("Healing driver failed");
552       return NULL;
553     }
554   }
555   catch (Standard_Failure)
556   {
557         Handle(Standard_Failure) aFail = Standard_Failure::Caught();
558     SetErrorCode(aFail->GetMessageString());
559     return NULL;
560   }
561
562   //Make a Python command
563   GEOM::TPythonDump pd (aFunction);
564   pd << aNewObject << " = geompy.SuppressHoles(" << theObject << ", [";
565
566   // list of wire ids
567   if ( theWires.IsNull() )
568     pd << "])";
569   else {
570     int i = theWires->Lower(), nb = theWires->Upper();
571     for ( ; i <= nb; i++)
572       pd << theWires->Value( i ) << (( i < nb ) ? ", " : "])");
573   }
574
575   SetErrorCode(OK);
576   return aNewObject;
577 }
578
579 //=============================================================================
580 /*!
581  *  Sew
582  */
583 //=============================================================================
584 Handle(GEOM_Object)
585 GEOMImpl_IHealingOperations::Sew (std::list<Handle(GEOM_Object)>& theObjects,
586                                   double                          theTolerance,
587                                   bool                            isAllowNonManifold)
588 {
589   // set error code, check parameters
590   SetErrorCode(KO);
591
592   if (theObjects.empty())
593     return NULL;
594
595   Handle(TColStd_HSequenceOfTransient) objects =
596     GEOM_Object::GetLastFunctions( theObjects );
597   if ( objects.IsNull() || objects->IsEmpty() ) {
598     SetErrorCode("NULL argument shape");
599     return NULL;
600   }
601
602   // Add a new object
603   Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
604
605   //Add the function
606   int aFunctionType = (isAllowNonManifold ? SEWING_NON_MANIFOLD : SEWING);
607   Handle(GEOM_Function) aFunction =
608     aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), aFunctionType);
609   if (aFunction.IsNull()) return NULL;
610
611   //Check if the function is set correctly
612   if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
613
614   // prepare "data container" class IHealing
615   GEOMImpl_IHealing HI(aFunction);
616   HI.SetTolerance( theTolerance );
617   HI.SetOriginal( theObjects.front()->GetLastFunction() ); objects->Remove(1);
618   HI.SetShapes( objects );
619
620   //Compute the result
621   try {
622     OCC_CATCH_SIGNALS;
623     if (!GetSolver()->ComputeFunction(aFunction))
624     {
625       SetErrorCode("Healing driver failed");
626       return NULL;
627     }
628   }
629   catch (Standard_Failure) {
630     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
631     SetErrorCode(aFail->GetMessageString());
632     return NULL;
633   }
634
635   //Make a Python command
636   GEOM::TPythonDump pd(aFunction);
637   
638   pd << aNewObject << " = geompy.Sew(" << theObjects << ", " << theTolerance;
639
640   if (isAllowNonManifold) {
641     pd << ", True";
642   }
643
644   pd << ")";
645
646   SetErrorCode(OK);
647   return aNewObject;
648 }
649
650 //=============================================================================
651 /*!
652  *  RemoveInternalFaces
653  */
654 //=============================================================================
655 Handle(GEOM_Object) GEOMImpl_IHealingOperations::RemoveInternalFaces (Handle(GEOM_Object) theObject)
656 {
657   // set error code, check parameters
658   SetErrorCode(KO);
659
660   if (theObject.IsNull())
661     return NULL;
662
663   Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
664   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
665
666   // Add a new object
667   Handle(GEOM_Object) aNewObject = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
668
669   //Add the function
670   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), REMOVE_INTERNAL_FACES);
671   if (aFunction.IsNull()) return NULL;
672
673   //Check if the function is set correctly
674   if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
675
676   // prepare "data container" class IHealing
677   GEOMImpl_IHealing HI (aFunction);
678   HI.SetOriginal(aLastFunction);
679
680   //Compute the result
681   try {
682     OCC_CATCH_SIGNALS;
683     if (!GetSolver()->ComputeFunction(aFunction))
684     {
685       SetErrorCode("Healing driver failed");
686       return NULL;
687     }
688   }
689   catch (Standard_Failure) {
690     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
691     SetErrorCode(aFail->GetMessageString());
692     return NULL;
693   }
694
695   //Make a Python command
696   GEOM::TPythonDump(aFunction) << aNewObject << " = geompy.RemoveInternalFaces(" << theObject << ")";
697
698   SetErrorCode(OK);
699   return aNewObject;
700 }
701
702 //=============================================================================
703 /*!
704  *  DivideEdge
705  */
706 //=============================================================================
707 Handle(GEOM_Object) GEOMImpl_IHealingOperations::DivideEdge (Handle(GEOM_Object) theObject,
708                                                              int theIndex,
709                                                              double theValue,
710                                                              bool isByParameter)
711 {
712   // set error code, check parameters
713   SetErrorCode(KO);
714
715   if (theObject.IsNull())
716     return NULL;
717
718   Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
719   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be processed
720
721   // Add a new object
722   Handle(GEOM_Object) aNewObject = GetEngine()->AddObject( GetDocID(), GEOM_COPY );
723
724   //Add the function
725   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), DIVIDE_EDGE);
726
727   if (aFunction.IsNull()) return NULL;
728
729   //Check if the function is set correctly
730   if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
731
732   // prepare "data container" class IHealing
733   GEOMImpl_IHealing HI(aFunction);
734   HI.SetIndex( theIndex );
735   HI.SetDevideEdgeValue( theValue );
736   HI.SetIsByParameter( isByParameter );
737   HI.SetOriginal( aLastFunction );
738
739   //Compute the translation
740   try {
741     OCC_CATCH_SIGNALS;
742     if (!GetSolver()->ComputeFunction(aFunction)) {
743       SetErrorCode("Healing driver failed");
744       return NULL;
745     }
746   }
747   catch (Standard_Failure) {
748     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
749     SetErrorCode(aFail->GetMessageString());
750     return NULL;
751   }
752
753   //Make a Python command
754   GEOM::TPythonDump(aFunction) << aNewObject << " = geompy.DivideEdge(" << theObject
755     << ", " << theIndex << ", " << theValue << ", " << (int)isByParameter << ")";
756
757   SetErrorCode(OK);
758   return aNewObject;
759 }
760
761 //=============================================================================
762 /*!
763  *  FuseCollinearEdgesWithinWire
764  */
765 //=============================================================================
766 Handle(GEOM_Object) GEOMImpl_IHealingOperations::FuseCollinearEdgesWithinWire
767                                    (Handle(GEOM_Object) theWire,
768                                     std::list<Handle(GEOM_Object)> theVertices)
769 {
770   SetErrorCode(KO);
771
772   if (theWire.IsNull()) return NULL;
773
774   // Add a new object
775   Handle(GEOM_Object) aRes = GetEngine()->AddObject(GetDocID(), theWire->GetType());
776
777   // Add a new function
778   Handle(GEOM_Function) aFunction;
779   aFunction = aRes->AddFunction(GEOMImpl_HealingDriver::GetID(), FUSE_COLLINEAR_EDGES);
780   if (aFunction.IsNull()) return NULL;
781
782   // Check if the function is set correctly
783   if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
784
785   GEOMImpl_IHealing aCI (aFunction);
786
787   Handle(GEOM_Function) aRefShape = theWire->GetLastFunction();
788   if (aRefShape.IsNull()) return NULL;
789   aCI.SetOriginal(aRefShape);
790
791   Handle(TColStd_HSequenceOfTransient) aVertices = new TColStd_HSequenceOfTransient;
792   std::list<Handle(GEOM_Object)>::iterator it = theVertices.begin();
793   for (; it != theVertices.end(); it++) {
794     Handle(GEOM_Function) aRefSh = (*it)->GetLastFunction();
795     if (aRefSh.IsNull()) {
796       SetErrorCode("NULL argument shape for the shape construction");
797       return NULL;
798     }
799     aVertices->Append(aRefSh);
800   }
801   aCI.SetShapes(aVertices);
802
803   // Compute the new wire
804   try {
805     OCC_CATCH_SIGNALS;
806     if (!GetSolver()->ComputeFunction(aFunction)) {
807       SetErrorCode("Healing driver failed");
808       return NULL;
809     }
810   }
811   catch (Standard_Failure) {
812     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
813     SetErrorCode(aFail->GetMessageString());
814     return NULL;
815   }
816
817   // Make a Python command
818   GEOM::TPythonDump pd (aFunction);
819   pd << aRes << " = geompy.FuseCollinearEdgesWithinWire(" << theWire << ", [";
820   // Vertices
821   it = theVertices.begin();
822   if (it != theVertices.end()) {
823     pd << (*it++);
824     while (it != theVertices.end()) {
825       pd << ", " << (*it++);
826     }
827   }
828   pd << "])";
829
830   SetErrorCode(OK);
831   return aRes;
832 }
833
834 //=============================================================================
835 /*!
836  *  GetFreeBoundary
837  */
838 //=============================================================================
839 bool GEOMImpl_IHealingOperations::GetFreeBoundary (Handle(TColStd_HSequenceOfTransient)& theObjects,
840                                                    Handle(TColStd_HSequenceOfTransient)& theClosed,
841                                                    Handle(TColStd_HSequenceOfTransient)& theOpen )
842 {
843   // set error code, check parameters
844   SetErrorCode(KO);
845
846   if ( theObjects.IsNull() || theObjects->Length() == 0 ||
847        theClosed.IsNull()  || theOpen.IsNull() )
848     return false;
849
850   TopoDS_Shape aShape;
851   TopTools_SequenceOfShape shapes;
852   for ( int ind = 1; ind <= theObjects->Length(); ind++)
853   {
854     Handle(GEOM_Object) aRefShape = Handle(GEOM_Object)::DownCast( theObjects->Value(ind));
855     if ( aRefShape.IsNull() )
856       return false;
857     aShape = aRefShape->GetValue();
858     if ( aShape.IsNull() )
859       return false;
860     shapes.Append( aShape );
861   }
862
863   if ( shapes.Length() > 1 )
864   {
865     TopoDS_Compound compound;
866     BRep_Builder builder;
867     builder.MakeCompound( compound );
868     for ( int i = 1; i <= shapes.Length(); ++i )
869       builder.Add( compound, shapes( i ) );
870
871     aShape = compound;
872   }
873
874   // get free boundary shapes
875
876   ShapeAnalysis_FreeBounds anAnalizer(aShape, Standard_False,
877                                       Standard_True, Standard_True);
878   TopoDS_Compound aClosed = anAnalizer.GetClosedWires();
879   TopoDS_Compound anOpen = anAnalizer.GetOpenWires();
880
881   // iterate through shapes and append them to the return sequence
882   Handle(GEOM_Object) anObj;
883   Handle(GEOM_Function) aFunction;
884   TopExp_Explorer anExp;
885   for ( anExp.Init( aClosed, TopAbs_WIRE ); anExp.More(); anExp.Next() )
886   {
887     anObj = GetEngine()->AddObject( GetDocID(), GEOM_FREE_BOUNDS );
888     aFunction = anObj->AddFunction( GEOMImpl_CopyDriver::GetID(), COPY_WITHOUT_REF );
889     TopoDS_Shape aValueShape = anExp.Current();
890     aFunction->SetValue( aValueShape );
891     theClosed->Append(anObj);
892   }
893   for ( anExp.Init( anOpen, TopAbs_WIRE ); anExp.More(); anExp.Next() )
894   {
895     anObj = GetEngine()->AddObject( GetDocID(), GEOM_FREE_BOUNDS );
896     aFunction = anObj->AddFunction( GEOMImpl_CopyDriver::GetID(), COPY_WITHOUT_REF );
897     TopoDS_Shape aValueShape = anExp.Current();
898     aFunction->SetValue( aValueShape );
899     theOpen->Append(anObj);
900   }
901
902   if(!aFunction.IsNull()) {
903
904     //Make a Python command
905     GEOM::TPythonDump pd (aFunction);
906
907     Standard_Integer i, aLen = theClosed->Length();
908     if (aLen > 0) {
909       pd << "(isDone, [";
910       for (i = 1; i <= aLen; i++) {
911         Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theClosed->Value(i));
912         pd << anObj_i << ((i < aLen) ? ", " : "");
913       }
914       pd << "], ";
915     } else {
916       pd << "(isDone, empty_list, ";
917     }
918
919     aLen = theOpen->Length();
920     if (aLen > 0) {
921       pd << "[";
922       for (i = 1; i <= aLen; i++) {
923         Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theOpen->Value(i));
924         pd << anObj_i << ((i < aLen) ? ", " : "");
925       }
926       pd << "]";
927     } else {
928       pd << "empty_list";
929     }
930
931     pd << ") = geompy.GetFreeBoundary(" << theObjects << ")";
932   }
933
934   SetErrorCode(OK);
935   return true;
936 }
937
938
939 //=============================================================================
940 /*!
941  *  ChangeOrientation
942  */
943 //=============================================================================
944 Handle(GEOM_Object) GEOMImpl_IHealingOperations::ChangeOrientation (Handle(GEOM_Object) theObject)
945 {
946   // set error code, check parameters
947   SetErrorCode(KO);
948
949   if (theObject.IsNull())
950     return NULL;
951
952   if (!theObject->IsMainShape()) {
953     SetErrorCode("Sub-shape cannot be transformed - need to create a copy");
954     return NULL;
955   }
956
957   Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
958   if (aLastFunction.IsNull())
959     return NULL; //There is no function which creates an object to be processed
960
961   if (theObject->GetType() == GEOM_VECTOR) { // Mantis issue 21066
962     //Add the function
963     aFunction = theObject->AddFunction(GEOMImpl_VectorDriver::GetID(), VECTOR_REVERSE);
964
965     //Check if the function is set correctly
966     if (aFunction.IsNull()) return NULL;
967     if (aFunction->GetDriverGUID() != GEOMImpl_VectorDriver::GetID()) return NULL;
968
969     // prepare "data container" class IVector
970     GEOMImpl_IVector aVI (aFunction);
971     aVI.SetCurve(aLastFunction);
972   }
973   else {
974     //Add the function
975     aFunction = theObject->AddFunction(GEOMImpl_HealingDriver::GetID(), CHANGE_ORIENTATION);
976
977     //Check if the function is set correctly
978     if (aFunction.IsNull()) return NULL;
979     if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
980
981     // prepare "data container" class IHealing
982     GEOMImpl_IHealing HI (aFunction);
983     HI.SetOriginal(aLastFunction);
984   }
985
986   //Compute the translation
987   try {
988     OCC_CATCH_SIGNALS;
989     if (!GetSolver()->ComputeFunction(aFunction)) {
990       SetErrorCode("Healing driver failed");
991       return NULL;
992     }
993   }
994   catch (Standard_Failure) {
995     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
996     SetErrorCode(aFail->GetMessageString());
997     return NULL;
998   }
999
1000   //Make a Python command
1001   GEOM::TPythonDump(aFunction) << "geompy.ChangeOrientationShell("
1002                                << theObject << ")";
1003
1004   SetErrorCode(OK);
1005   return theObject;
1006 }
1007
1008 //=============================================================================
1009 /*!
1010  *  ChangeOrientationCopy
1011  */
1012 //=============================================================================
1013 Handle(GEOM_Object) GEOMImpl_IHealingOperations::ChangeOrientationCopy (Handle(GEOM_Object) theObject)
1014 {
1015   // set error code, check parameters
1016   SetErrorCode(KO);
1017
1018   if (theObject.IsNull())
1019     return NULL;
1020
1021   Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
1022   if (aLastFunction.IsNull())
1023     return NULL; //There is no function which creates an object to be processed
1024
1025   // Add a new object
1026   Handle(GEOM_Object) aNewObject = GetEngine()->AddObject(GetDocID(), theObject->GetType());
1027
1028   if (theObject->GetType() == GEOM_VECTOR) { // Mantis issue 21066
1029     //Add the function
1030     aFunction = aNewObject->AddFunction(GEOMImpl_VectorDriver::GetID(), VECTOR_REVERSE);
1031
1032     //Check if the function is set correctly
1033     if (aFunction.IsNull()) return NULL;
1034     if (aFunction->GetDriverGUID() != GEOMImpl_VectorDriver::GetID()) return NULL;
1035
1036     // prepare "data container" class IVector
1037     GEOMImpl_IVector aVI (aFunction);
1038     aVI.SetCurve(aLastFunction);
1039   }
1040   else {
1041     //Add the function
1042     aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), CHANGE_ORIENTATION);
1043
1044     //Check if the function is set correctly
1045     if (aFunction.IsNull()) return NULL;
1046     if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
1047
1048     // prepare "data container" class IHealing
1049     GEOMImpl_IHealing aHI (aFunction);
1050     aHI.SetOriginal(aLastFunction);
1051   }
1052
1053   // Compute the result
1054   try {
1055     OCC_CATCH_SIGNALS;
1056     if (!GetSolver()->ComputeFunction(aFunction)) {
1057       SetErrorCode("Healing driver failed");
1058       return NULL;
1059     }
1060   }
1061   catch (Standard_Failure) {
1062     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1063     SetErrorCode(aFail->GetMessageString());
1064     return NULL;
1065   }
1066
1067   //Make a Python command
1068   GEOM::TPythonDump(aFunction) << aNewObject << " = geompy.ChangeOrientationShellCopy("
1069                                << theObject << ")";
1070
1071   SetErrorCode(OK);
1072   return aNewObject;
1073 }
1074
1075 //=============================================================================
1076 /*!
1077  *  LimitTolerance
1078  */
1079 //=============================================================================
1080 Handle(GEOM_Object) GEOMImpl_IHealingOperations::LimitTolerance (Handle(GEOM_Object) theObject,
1081                                                                  double theTolerance)
1082 {
1083   // Set error code, check parameters
1084   SetErrorCode(KO);
1085
1086   if (theObject.IsNull())
1087     return NULL;
1088
1089   Handle(GEOM_Function) aFunction, aLastFunction = theObject->GetLastFunction();
1090   if (aLastFunction.IsNull())
1091     return NULL; // There is no function which creates an object to be processed
1092
1093   // Add a new object
1094   Handle(GEOM_Object) aNewObject = GetEngine()->AddObject(GetDocID(), theObject->GetType());
1095
1096   // Add the function
1097   aFunction = aNewObject->AddFunction(GEOMImpl_HealingDriver::GetID(), LIMIT_TOLERANCE);
1098
1099   if (aFunction.IsNull())
1100     return NULL;
1101
1102   // Check if the function is set correctly
1103   if (aFunction->GetDriverGUID() != GEOMImpl_HealingDriver::GetID()) return NULL;
1104
1105   // Prepare "data container" class IHealing
1106   GEOMImpl_IHealing HI (aFunction);
1107   HI.SetOriginal(aLastFunction);
1108   HI.SetTolerance(theTolerance);
1109
1110   // Compute
1111   try {
1112     OCC_CATCH_SIGNALS;
1113     if (!GetSolver()->ComputeFunction(aFunction)) {
1114       SetErrorCode("Healing driver failed");
1115       return NULL;
1116     }
1117   }
1118   catch (Standard_Failure) {
1119     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1120     SetErrorCode(aFail->GetMessageString());
1121     return NULL;
1122   }
1123
1124   // Make a Python command
1125   GEOM::TPythonDump(aFunction) << aNewObject << " = geompy.LimitTolerance("
1126                                << theObject << ", " << theTolerance << ")";
1127
1128   SetErrorCode(OK);
1129   return aNewObject;
1130 }