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