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