Salome HOME
e015dfac13331bfef8fae010b30ca9086fe50da3
[modules/geom.git] / src / ShHealOper / ShHealOper_EdgeDivide.cxx
1 // Copyright (C) 2007-2023  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 // File:      ShHealOper_EdgeDivide.cxx
24 // Created:   30.04.04 16:44:47
25 // Author:    Galina KULIKOVA
26 //
27 #include <BRep_Tool.hxx>
28 #include <GCPnts_AbscissaPoint.hxx>
29 #include <Geom2dAdaptor_Curve.hxx>
30 #include <Geom2d_Curve.hxx>
31 #include <GeomAPI_ProjectPointOnCurve.hxx>
32 #include <GeomAdaptor_Curve.hxx>
33 #include <Geom_Curve.hxx>
34 #include <Precision.hxx>
35 #include <ShHealOper_EdgeDivide.hxx>
36 #include <ShHealOper_SplitCurve2d.hxx>
37 #include <ShHealOper_SplitCurve3d.hxx>
38 #include <ShapeAnalysis_Edge.hxx>
39 #include <ShapeFix_Edge.hxx>
40 #include <ShapeUpgrade_WireDivide.hxx>
41 #include <TopExp.hxx>
42 #include <TopExp_Explorer.hxx>
43 #include <TopTools_ListIteratorOfListOfShape.hxx>
44 #include <TopTools_ListOfShape.hxx>
45 #include <TopTools_MapOfShape.hxx>
46 #include <TopoDS.hxx>
47 #include <TopoDS_Face.hxx>
48
49 //#include <.hxx>
50 //#include <.hxx>
51 //=======================================================================
52 //function : ShHealOper_EdgeDivide()
53 //purpose  : Constructor
54 //=======================================================================
55
56 ShHealOper_EdgeDivide::ShHealOper_EdgeDivide (const TopoDS_Shape& theShape) 
57 {
58   Init(theShape);
59 }
60 //=======================================================================
61 //function : Init
62 //purpose  : 
63 //=======================================================================
64
65 void ShHealOper_EdgeDivide::Init(const TopoDS_Shape& theShape)
66 {
67   ShHealOper_Tool::Init(theShape);
68   myDivideParamMode = Standard_True;
69   myMapEdgesFace.Clear();
70   TopExp::MapShapesAndAncestors(theShape,TopAbs_EDGE,TopAbs_FACE,myMapEdgesFace);
71   
72 }
73
74 //=======================================================================
75 //function : Perform
76 //purpose  : 
77 //=======================================================================
78 Standard_Boolean ShHealOper_EdgeDivide::Perform(const TopoDS_Shape& theEdge, 
79                                                 const TColStd_SequenceOfReal& theValues,
80                                                 const Standard_Boolean theDivideParamMode)
81
82   myDone = Standard_False;
83   myDivideParamMode = theDivideParamMode;
84   if(theEdge.ShapeType() != TopAbs_EDGE) {
85     myErrorStatus = ShHealOper_InvalidParameters;
86     return myDone;
87   }
88   myEdge = TopoDS::Edge(theEdge);
89   Standard_Integer i =1;
90   Handle(TColStd_HSequenceOfReal) aSeqValues = new TColStd_HSequenceOfReal;
91   for( ; i <= theValues.Length(); i++)
92       aSeqValues->Append(theValues.Value(i));
93   myDone = build(aSeqValues);
94   return myDone;
95   
96 }
97 //=======================================================================
98 //function : Perform
99 //purpose  : 
100 //=======================================================================
101
102 Standard_Boolean ShHealOper_EdgeDivide::Perform(const TopoDS_Shape& theEdge, 
103                                                 const Standard_Real theValue,
104                                                 const Standard_Boolean theDivideParamMode)
105 {
106   myDone = Standard_False;
107   myErrorStatus = ShHealOper_NotError;
108   if(theEdge.ShapeType() != TopAbs_EDGE) {
109     myErrorStatus = ShHealOper_InvalidParameters;
110     return myDone;
111   }
112   myDivideParamMode = theDivideParamMode;
113   myEdge = TopoDS::Edge(theEdge);
114   Handle(TColStd_HSequenceOfReal) aSeqValues = new TColStd_HSequenceOfReal;
115   aSeqValues->Append(theValue);
116   myDone = build(aSeqValues);
117   return myDone;
118 }
119 //=======================================================================
120 //function : Perform
121 //purpose  : 
122 //=======================================================================
123
124 Standard_Boolean ShHealOper_EdgeDivide::Perform(const TopoDS_Shape& theEdge, 
125                                                 const TopoDS_Shape& thePoints)
126 {
127   myDone = Standard_False;
128   myErrorStatus = ShHealOper_NotError;
129   if(theEdge.ShapeType() != TopAbs_EDGE) {
130     myErrorStatus = ShHealOper_InvalidParameters;
131     return myDone;
132   }
133   myDivideParamMode = true;
134   myEdge = TopoDS::Edge(theEdge);
135   Handle(TColStd_HSequenceOfReal) aSeqValues = new TColStd_HSequenceOfReal;
136
137   double aFirst,aLast;
138   Handle(Geom_Curve) aCurve = BRep_Tool::Curve(myEdge,aFirst,aLast);
139   if ( aCurve.IsNull() ) return false;
140   GeomAPI_ProjectPointOnCurve aProjector;
141   aProjector.Init( aCurve, aFirst, aLast );
142
143   TopTools_MapOfShape vMap;
144   TopExp_Explorer vertex( thePoints, TopAbs_VERTEX );
145   std::set< double > params; // to exclude equal params
146   for ( ; vertex.More(); vertex.Next() )
147   {
148     if ( !vMap.Add( vertex.Current() )) continue;
149     gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( vertex.Current() ));
150     aProjector.Perform( p );
151     if ( aProjector.NbPoints() > 0 )
152     {
153       double     u = double( aProjector.LowerDistanceParameter() );
154       double param = ( u - aFirst ) / ( aLast - aFirst );
155       params.insert( param );
156     }
157   }
158   // remove too close params
159   params.insert( 0 );
160   params.insert( 1 );
161   std::set< double >::iterator p2 = params.begin(), p1 = p2++;
162   while ( p2 != params.end() )
163   {
164     if ( Abs( *p2 - *p1 ) < 1e-3 ) // compare normalized params 
165       params.erase( p1 );
166     p1 = p2++;
167   }
168   p1 = params.begin(); ++p1; // skip aFirst
169   p2 = params.end();   --p2; // skip aLast
170   for ( ; p1 != p2; ++p1 )
171     aSeqValues->Append( *p1 );
172
173   myDone = build(aSeqValues);
174   return myDone;
175 }
176 //=======================================================================
177 //function : build
178 //purpose  :
179 //=======================================================================
180
181 Standard_Boolean ShHealOper_EdgeDivide::build(const Handle(TColStd_HSequenceOfReal)& theValues)
182 {
183   if(myEdge.IsNull() || !theValues->Length()) {
184     myErrorStatus = ShHealOper_InvalidParameters;
185     return Standard_False;
186   }
187
188   Standard_Boolean has3d = Standard_False,
189     has2d = Standard_False,
190     hasPCurves = Standard_False;
191
192   //computation of the split values in dependence from specified mode and values.
193   if(!computeValues(theValues, has3d,has2d,hasPCurves)) {
194     myErrorStatus = ShHealOper_InvalidParameters;
195     return Standard_False;
196   }
197
198   //setting split values in the splitting curve tools.
199   Handle(ShapeUpgrade_WireDivide) aSplitTool = new ShapeUpgrade_WireDivide;
200   aSplitTool->Load(myEdge);
201   aSplitTool->SetContext(myContext);
202   if(has3d) {
203     Handle(ShHealOper_SplitCurve3d) aSplitCurve3d = new ShHealOper_SplitCurve3d;
204     aSplitCurve3d->SetValues(theValues);
205     aSplitTool->SetSplitCurve3dTool(aSplitCurve3d);
206   }
207   else if(has2d) {
208     Handle(ShHealOper_SplitCurve2d) aSplitCurve2d = new ShHealOper_SplitCurve2d;
209     aSplitCurve2d->SetValues(theValues);
210     aSplitTool->SetSplitCurve2dTool(aSplitCurve2d);
211   }
212   else {
213     myErrorStatus = ShHealOper_InvalidParameters;
214     return Standard_False;
215   }
216
217   //split 3d curve and pcurve for each face referring to edge.
218   Standard_Boolean isDone = Standard_True;
219   if(hasPCurves) {
220     const TopTools_ListOfShape& lfaces  = myMapEdgesFace.FindFromKey(myEdge);
221     TopTools_ListIteratorOfListOfShape aItf(lfaces);
222     for( ; aItf.More() && isDone; aItf.Next()) {
223       TopoDS_Face aFace = TopoDS::Face(aItf.Value());
224       aSplitTool->SetFace(aFace);
225       aSplitTool->Perform();
226       isDone = aSplitTool->Status( ShapeExtend_DONE );
227       if( aSplitTool->Status( ShapeExtend_FAIL ))
228         myErrorStatus = ShHealOper_ErrorExecution;
229     }
230   }
231   else {
232      aSplitTool->Perform();
233      isDone = aSplitTool->Status( ShapeExtend_DONE );
234      if( aSplitTool->Status( ShapeExtend_FAIL ))
235         myErrorStatus = ShHealOper_ErrorExecution;
236   }
237   if(isDone)
238   {
239     myResultShape = myContext->Apply(myInitShape);
240     myStatistics.AddModif("Vertex added on edge", theValues->Length() );
241   }
242   return isDone;
243   
244 }
245 //=======================================================================
246 //function : computeValues
247 //purpose  : 
248 //=======================================================================
249
250 Standard_Boolean ShHealOper_EdgeDivide::computeValues(const Handle(TColStd_HSequenceOfReal)& theValues,
251                                                       Standard_Boolean& theHas3d,
252                                                       Standard_Boolean& theHas2d,
253                                                       Standard_Boolean& hasPCurves)
254 {
255   hasPCurves = (myMapEdgesFace.Contains(myEdge) && 
256                 myMapEdgesFace.FindFromKey(myEdge).Extent());
257   if(hasPCurves && (!BRep_Tool::SameRange(myEdge) || !BRep_Tool::SameParameter(myEdge))) {
258     ShapeFix_Edge sfe;
259     sfe.FixSameParameter(myEdge);
260   }
261   
262   Standard_Real aFirst =0.,aLast=0.;
263
264   //computation of the split values if edge should be split by parameter.
265   if(myDivideParamMode) {
266     BRep_Tool::Range(myEdge,aFirst,aLast);
267     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(myEdge,aFirst,aLast);
268     
269     theHas3d = (!aCurve.IsNull());
270     theHas2d = (aCurve.IsNull() && (fabs(aLast-aFirst) > Precision::PConfusion() ));
271     Standard_Integer i = 1;
272     for( ; i <= theValues->Length();i++) {
273       Standard_Real aVal = theValues->Value(i);
274       theValues->ChangeValue(i) = aFirst+ aVal*fabs(aLast - aFirst);
275     }
276   }
277   else {
278      //computation of the split values if edge should be split by length.
279     ShapeAnalysis_Edge sae;
280     Handle(Geom_Curve) aCurve;
281     Standard_Real aCurLen =0.;
282     GeomAdaptor_Curve aAdC;
283     Geom2dAdaptor_Curve aAdC2d;
284     if(sae.Curve3d(myEdge,aCurve,aFirst,aLast,Standard_False)) {
285       aAdC.Load(aCurve,aFirst,aLast);
286       aCurLen = GCPnts_AbscissaPoint::Length(aAdC,aFirst,aLast); 
287       theHas3d = Standard_True;
288     }
289     else {
290       if(hasPCurves) {
291         TopoDS_Face aFace = TopoDS::Face(myMapEdgesFace.FindFromKey(myEdge).First());
292         Handle(Geom2d_Curve) aCurve2d;
293         if(sae.PCurve(myEdge,aFace,aCurve2d,aFirst,aLast)) {
294           aAdC2d.Load(aCurve2d,aFirst,aLast);
295           aCurLen = GCPnts_AbscissaPoint::Length(aAdC,aFirst,aLast);
296           theHas2d = Standard_True;
297         }
298           
299       }
300     }
301     if(!theHas3d && !theHas2d)
302       return Standard_False;
303
304     Standard_Integer i = 1;
305     for( ; i <= theValues->Length();i++) {
306       Standard_Real aLen = theValues->Value(i)*aCurLen;
307       if(theHas3d) {
308         GCPnts_AbscissaPoint anAbsc(aAdC,aLen,aFirst);
309         if(anAbsc.IsDone()) 
310           theValues->ChangeValue(i) = anAbsc.Parameter();
311         else
312           theValues->Remove(i--);
313       }
314       else if(theHas2d) {
315         GCPnts_AbscissaPoint anAbsc(aAdC2d,aLen,aFirst);
316         if(anAbsc.IsDone()) 
317           theValues->ChangeValue(i) = anAbsc.Parameter();
318         else
319           theValues->Remove(i--);
320       }
321     }
322   }
323   return (theValues->Length());
324 }