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