0024924: ShapeFix_SplitTool doesn't verify the new range after cutting an edge
[occt.git] / src / ShapeFix / ShapeFix_SplitTool.cxx
1 // Created on: 2004-07-14
2 // Created by: Sergey KUUL
3 // Copyright (c) 2004-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <ShapeFix_SplitTool.ixx>
17
18 #include <ShapeAnalysis_Edge.hxx>
19 #include <ShapeAnalysis_Surface.hxx>
20 #include <ShapeAnalysis_TransferParametersProj.hxx>
21 #include <ShapeFix_Edge.hxx>
22 #include <ShapeBuild_Edge.hxx>
23 #include <ShapeExtend_WireData.hxx>
24 #include <Geom_Curve.hxx>
25 #include <Geom2d_Curve.hxx>
26 #include <Geom2d_TrimmedCurve.hxx>
27 #include <Geom2d_Line.hxx>
28 #include <gp_Pnt.hxx>
29 #include <BRep_Tool.hxx>
30 #include <BRep_Builder.hxx>
31 #include <BRepTools.hxx>
32 #include <TopoDS.hxx>
33 #include <TopoDS_Wire.hxx>
34 #include <TopExp_Explorer.hxx>
35 #include <ShapeAnalysis_Curve.hxx>
36
37
38 //=======================================================================
39 //function : ShapeFix_SplitTool()
40 //purpose  : Constructor
41 //=======================================================================
42
43 ShapeFix_SplitTool::ShapeFix_SplitTool()
44 {
45 }
46
47
48 //=======================================================================
49 //function : SplitEdge
50 //purpose  : 
51 //=======================================================================
52
53 Standard_Boolean ShapeFix_SplitTool::SplitEdge(const TopoDS_Edge& edge,
54                                                const Standard_Real param,
55                                                const TopoDS_Vertex& vert,
56                                                const TopoDS_Face& face,
57                                                TopoDS_Edge& newE1,
58                                                TopoDS_Edge& newE2,
59                                                const Standard_Real tol3d,
60                                                const Standard_Real tol2d) const
61 {
62   Standard_Real a, b;
63   ShapeAnalysis_Edge sae;
64   Handle(Geom2d_Curve) c2d;
65   sae.PCurve(edge,face,c2d,a,b,Standard_True );
66   if( Abs(a-param)<tol2d || Abs(b-param)<tol2d )
67     return Standard_False;
68   // check distanse between edge and new vertex
69   gp_Pnt P1;
70   TopLoc_Location L;
71   if(BRep_Tool::SameParameter(edge)) {
72     Standard_Real f,l;
73     const Handle(Geom_Curve) c3d = BRep_Tool::Curve(edge,L,f,l);
74     if(c3d.IsNull())
75       return Standard_False;
76     P1 = c3d->Value(param);
77     if(!L.IsIdentity()) P1 = P1.Transformed(L.Transformation());
78   }
79   else {
80     Handle(Geom_Surface) surf = BRep_Tool::Surface(face,L);
81     Handle(ShapeAnalysis_Surface) sas = new ShapeAnalysis_Surface(surf);
82     P1 = sas->Value(c2d->Value(param));
83     if(!L.IsIdentity()) P1 = P1.Transformed(L.Transformation());
84   }
85   gp_Pnt P2 = BRep_Tool::Pnt(vert);
86   if(P1.Distance(P2)>tol3d) {
87     //return Standard_False;
88     BRep_Builder B;
89     B.UpdateVertex(vert,P1.Distance(P2));
90   }
91   
92   Handle(ShapeAnalysis_TransferParametersProj) transferParameters =
93     new ShapeAnalysis_TransferParametersProj;
94   transferParameters->SetMaxTolerance(tol3d);
95   transferParameters->Init(edge,face);
96   Standard_Real first, last;
97   if (a < b ) {
98     first = a; 
99     last = b;
100   }
101   else {
102     first = b; 
103     last = a;
104   }
105   
106   ShapeBuild_Edge sbe;
107   Handle(ShapeFix_Edge) sfe = new ShapeFix_Edge;
108   TopAbs_Orientation orient = edge.Orientation();
109   BRep_Builder B;
110   TopoDS_Edge wE = edge;
111   wE.Orientation ( TopAbs_FORWARD );
112   TopoDS_Shape aTmpShape = vert.Oriented(TopAbs_REVERSED); //for porting
113   newE1 = sbe.CopyReplaceVertices ( wE, sae.FirstVertex(wE), TopoDS::Vertex(aTmpShape) );
114   sbe.CopyPCurves ( newE1, wE  );
115   transferParameters->TransferRange(newE1,first,param,Standard_True);
116   B.SameRange(newE1,Standard_False);
117   sfe->FixSameParameter(newE1);
118   //B.SameParameter(newE1,Standard_False);
119   aTmpShape = vert.Oriented(TopAbs_FORWARD);
120   newE2 = sbe.CopyReplaceVertices ( wE, TopoDS::Vertex(aTmpShape),sae.LastVertex(wE) );
121   sbe.CopyPCurves ( newE2, wE  );
122   transferParameters->TransferRange(newE2,param,last,Standard_True);
123   B.SameRange(newE2,Standard_False);
124   sfe->FixSameParameter(newE2);
125   //B.SameParameter(newE2,Standard_False);
126
127   newE1.Orientation(orient);
128   newE2.Orientation(orient);
129   if (orient==TopAbs_REVERSED) { 
130     TopoDS_Edge tmp = newE2; newE2 = newE1; newE1=tmp;
131   }
132
133   return Standard_True;
134 }
135
136
137 //=======================================================================
138 //function : SplitEdge
139 //purpose  : 
140 //=======================================================================
141
142 Standard_Boolean ShapeFix_SplitTool::SplitEdge(const TopoDS_Edge& edge,
143                                                const Standard_Real param1,
144                                                const Standard_Real param2,
145                                                const TopoDS_Vertex& vert,
146                                                const TopoDS_Face& face,
147                                                TopoDS_Edge& newE1,
148                                                TopoDS_Edge& newE2,
149                                                const Standard_Real tol3d,
150                                                const Standard_Real tol2d) const
151 {
152   Standard_Real param = (param1+param2)/2;
153   if(SplitEdge(edge,param,vert,face,newE1,newE2,tol3d,tol2d)) {
154     // cut new edges by param1 and param2
155     Standard_Boolean IsCutLine;
156     Handle(Geom2d_Curve) Crv1, Crv2;
157     Standard_Real fp1,lp1,fp2,lp2;
158     ShapeAnalysis_Edge sae;
159     if(sae.PCurve ( newE1, face, Crv1, fp1, lp1, Standard_False )) {
160       if(sae.PCurve ( newE2, face, Crv2, fp2, lp2, Standard_False )) {
161         if(lp1==param) {
162           if( (lp1-fp1)*(lp1-param1)>0 ) {
163             CutEdge(newE1, fp1, param1, face, IsCutLine);
164             CutEdge(newE2, lp2, param2, face, IsCutLine);
165           }
166           else {
167             CutEdge(newE1, fp1, param2, face, IsCutLine);
168             CutEdge(newE2, lp2, param1, face, IsCutLine);
169           }
170         }
171         else {
172           if( (fp1-lp1)*(fp1-param1)>0 ) {
173             CutEdge(newE1, lp1, param1, face, IsCutLine);
174             CutEdge(newE2, fp2, param2, face, IsCutLine);
175           }
176           else {
177             CutEdge(newE1, lp1, param2, face, IsCutLine);
178             CutEdge(newE2, fp2, param1, face, IsCutLine);
179           }
180         }
181       }
182     }
183     return Standard_True;
184   }
185   return Standard_False;
186 }
187
188
189 //=======================================================================
190 //function : CutEdge
191 //purpose  : 
192 //=======================================================================
193
194 Standard_Boolean ShapeFix_SplitTool::CutEdge(const TopoDS_Edge &edge,
195                                              const Standard_Real pend,
196                                              const Standard_Real cut,
197                                              const TopoDS_Face &face,
198                                              Standard_Boolean &iscutline) const
199 {
200   if( Abs(cut-pend)<10.*Precision::PConfusion() ) return Standard_False;
201   Standard_Real aRange = Abs(cut-pend);
202   Standard_Real a, b;
203   BRep_Tool::Range(edge, a, b);
204   iscutline = Standard_False;
205   if( aRange<10.*Precision::PConfusion() ) return Standard_False;
206
207   // case pcurve is trimm of line
208   if( !BRep_Tool::SameParameter(edge) ) {
209     ShapeAnalysis_Edge sae;
210     Handle(Geom2d_Curve) Crv;
211     Standard_Real fp,lp;
212     if ( sae.PCurve(edge,face,Crv,fp,lp,Standard_False) ) {
213       if(Crv->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) {
214         Handle(Geom2d_TrimmedCurve) tc = Handle(Geom2d_TrimmedCurve)::DownCast(Crv);
215         if(tc->BasisCurve()->IsKind(STANDARD_TYPE(Geom2d_Line))) {
216           BRep_Builder B;
217           B.Range(edge,Min(pend,cut),Max(pend,cut));
218           if( Abs(pend-lp)<Precision::PConfusion() ) { // cut from the begining
219             Standard_Real cut3d = (cut-fp)*(b-a)/(lp-fp);
220             if(cut3d <= Precision::PConfusion())
221               return Standard_False;
222             B.Range(edge, a+cut3d, b, Standard_True);
223             iscutline = Standard_True;
224           }
225           else if( Abs(pend-fp)<Precision::PConfusion() ) { // cut from the end
226             Standard_Real cut3d = (lp-cut)*(b-a)/(lp-fp);
227             if(cut3d <= Precision::PConfusion())
228               return Standard_False;
229             B.Range(edge, a, b-cut3d, Standard_True);
230             iscutline = Standard_True;
231           }
232         }
233       }
234     }
235     return Standard_True;
236   }
237
238   // det-study on 03/12/01 checking the old and new ranges
239   if( Abs(Abs(a-b)-aRange) < Precision::PConfusion() ) return Standard_False;
240   if( aRange<10.*Precision::PConfusion() ) return Standard_False;
241
242   Handle(Geom_Curve) c = BRep_Tool::Curve(edge, a, b);
243   ShapeAnalysis_Curve sac;
244   a = Min(pend,cut);
245   b = Max(pend,cut);
246   Standard_Real na = a, nb = b;
247   
248   BRep_Builder B;
249   if (!BRep_Tool::Degenerated(edge) && !c.IsNull() && sac.ValidateRange(c, na, nb, Precision::PConfusion()) && (na != a || nb != b) )
250   {
251     B.Range( edge, na, nb, Standard_True );
252     ShapeAnalysis_Edge sae;
253     if(sae.HasPCurve(edge,face))
254     {
255       B.SameRange(edge,Standard_False);
256     }
257
258     ShapeFix_Edge sfe;
259     sfe.FixSameParameter(edge);
260   }
261   else
262   {
263     B.Range( edge, a, b, Standard_False );
264   }
265
266   return Standard_True;
267 }
268
269
270 //=======================================================================
271 //function : SplitEdge
272 //purpose  : 
273 //=======================================================================
274
275 Standard_Boolean ShapeFix_SplitTool::SplitEdge(const TopoDS_Edge& edge,
276                                                const Standard_Real fp,
277                                                const TopoDS_Vertex& V1,
278                                                const Standard_Real lp,
279                                                const TopoDS_Vertex& V2,
280                                                const TopoDS_Face& face,
281                                                TopTools_SequenceOfShape& SeqE,
282                                                Standard_Integer& aNum,
283                                                const Handle(ShapeBuild_ReShape)& context,
284                                                const Standard_Real tol3d,
285                                                const Standard_Real tol2d) const
286 {
287   if(fabs(lp-fp)<tol2d)
288     return Standard_False;
289   aNum = 0;
290   SeqE.Clear();
291   BRep_Builder B;
292   Standard_Real a, b;
293   ShapeAnalysis_Edge sae;
294   Handle(Geom2d_Curve) c2d;
295   sae.PCurve(edge,face,c2d,a,b,Standard_True);
296   TopoDS_Vertex VF = sae.FirstVertex(edge);
297   TopoDS_Vertex VL = sae.LastVertex(edge);
298   Standard_Real tolVF = BRep_Tool::Tolerance(VF);
299   Standard_Real tolVL = BRep_Tool::Tolerance(VL);
300   Standard_Real tolV1 = BRep_Tool::Tolerance(V1);
301   Standard_Real tolV2 = BRep_Tool::Tolerance(V2);
302   gp_Pnt PVF = BRep_Tool::Pnt(VF);
303   gp_Pnt PVL = BRep_Tool::Pnt(VL);
304   gp_Pnt PV1 = BRep_Tool::Pnt(V1);
305   gp_Pnt PV2 = BRep_Tool::Pnt(V2);
306
307   Standard_Real par1,par2;
308   Standard_Boolean IsReverse = Standard_False;
309   if( (b-a)*(lp-fp)>0 ) {
310     par1 = fp;
311     par2 = lp;
312   }
313   else {
314     par1 = lp;
315     par2 = fp;
316     IsReverse = Standard_True;
317   }
318
319   if( fabs(a-par1)<=tol2d && fabs(b-par2)<=tol2d ) {
320     if(IsReverse) {
321       Standard_Real newtol = tolVF + PVF.Distance(PV2);
322       if(tolV2<newtol) B.UpdateVertex(V2,newtol);
323       if(VF.Orientation()==V2.Orientation()) {
324         context->Replace(VF,V2);
325         VF = V2;
326       }
327       else {
328         context->Replace(VF,V2.Reversed());
329         VF = TopoDS::Vertex(V2.Reversed());
330       }
331       newtol = tolVL + PVL.Distance(PV1);
332       if(tolV1<newtol) B.UpdateVertex(V1,newtol);
333       if(VL.Orientation()==V1.Orientation()) {
334         context->Replace(VL,V1);
335         VL = V1;
336       }
337       else {
338         context->Replace(VL,V1.Reversed());
339         VL = TopoDS::Vertex(V1.Reversed());
340       }
341     }
342     else {
343       Standard_Real newtol = tolVF + PVF.Distance(PV1);
344       if(tolV1<newtol) B.UpdateVertex(V1,newtol);
345       if(VF.Orientation()==V1.Orientation()) {
346         context->Replace(VF,V1);
347         VF = V1;
348       }
349       else {
350         context->Replace(VF,V1.Reversed());
351         VF = TopoDS::Vertex(V1.Reversed());
352       }
353       newtol = tolVL + PVL.Distance(PV2);
354       if(tolV2<newtol) B.UpdateVertex(V2,newtol);
355       if(VL.Orientation()==V2.Orientation()) {
356         context->Replace(VL,V2);
357         VL = V2;
358       }
359       else {
360         context->Replace(VL,V2.Reversed());
361         VL = TopoDS::Vertex(V2.Reversed());
362       }
363     }
364     SeqE.Append(edge);
365     aNum = 1;
366   }
367   
368   if( fabs(a-par1)<=tol2d && fabs(b-par2)>tol2d ) {
369     TopoDS_Edge newE1, newE2;
370     if(IsReverse) {
371       if(!SplitEdge(edge,par2,V1,face,newE1,newE2,tol3d,tol2d))
372         return Standard_False;
373       Standard_Real newtol = tolVF + PVF.Distance(PV2);
374       if(tolV2<newtol) B.UpdateVertex(V2,newtol);
375       if(VF.Orientation()==V2.Orientation()) {
376         context->Replace(VF,V2);
377         VF = V2;
378       }
379       else {
380         context->Replace(VF,V2.Reversed());
381         VF = TopoDS::Vertex(V2.Reversed());
382       }
383     }
384     else {
385       if(!SplitEdge(edge,par2,V2,face,newE1,newE2,tol3d,tol2d))
386         return Standard_False;
387       Standard_Real newtol = tolVF + PVF.Distance(PV1);
388       if(tolV1<newtol) B.UpdateVertex(V1,newtol);
389       if(VF.Orientation()==V1.Orientation()) {
390         context->Replace(VF,V1);
391         VF = V1;
392       }
393       else {
394         context->Replace(VF,V1.Reversed());
395         VF = TopoDS::Vertex(V1.Reversed());
396       }
397     }
398     SeqE.Append(newE1);
399     SeqE.Append(newE2);
400     aNum = 1;
401   }
402
403   if( fabs(a-par1)>tol2d && fabs(b-par2)<=tol2d ) {
404     TopoDS_Edge newE1, newE2;
405     if(IsReverse) {
406       if(!SplitEdge(edge,par1,V2,face,newE1,newE2,tol3d,tol2d))
407         return Standard_False;
408       Standard_Real newtol = tolVL + PVL.Distance(PV1);
409       if(tolV1<newtol) B.UpdateVertex(V1,newtol);
410       if(VL.Orientation()==V1.Orientation()) {
411         context->Replace(VL,V1);
412         VL = V1;
413       }
414       else {
415         context->Replace(VL,V1.Reversed());
416         VL = TopoDS::Vertex(V1.Reversed());
417       }
418     }
419     else {
420       if(!SplitEdge(edge,par1,V1,face,newE1,newE2,tol3d,tol2d))
421         return Standard_False;
422       Standard_Real newtol = tolVL + PVL.Distance(PV2);
423       if(tolV2<newtol) B.UpdateVertex(V2,newtol);
424       if(VL.Orientation()==V2.Orientation()) {
425         context->Replace(VL,V2);
426         VL = V2;
427       }
428       else {
429         context->Replace(VL,V2.Reversed());
430         VL = TopoDS::Vertex(V2.Reversed());
431       }
432     }
433     SeqE.Append(newE1);
434     SeqE.Append(newE2);
435     aNum = 2;
436   }
437
438   if( fabs(a-par1)>tol2d && fabs(b-par2)>tol2d ) {
439     TopoDS_Edge newE1,newE2,newE3,newE4;
440     if(IsReverse) {
441       if(!SplitEdge(edge,par1,V2,face,newE1,newE2,tol3d,tol2d))
442         return Standard_False;
443       if(!SplitEdge(newE2,par2,V1,face,newE3,newE4,tol3d,tol2d))
444         return Standard_False;
445     }
446     else {
447       if(!SplitEdge(edge,par1,V1,face,newE1,newE2,tol3d,tol2d))
448         return Standard_False;
449       if(!SplitEdge(newE2,par2,V2,face,newE3,newE4,tol3d,tol2d))
450         return Standard_False;
451     }
452     SeqE.Append(newE1);
453     SeqE.Append(newE3);
454     SeqE.Append(newE4);
455     aNum = 2;
456   }
457
458   if(aNum==0) return Standard_False;
459
460   Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData;
461   for(Standard_Integer i=1; i<=SeqE.Length(); i++) {
462     sewd->Add(SeqE.Value(i));
463   }
464   context->Replace(edge,sewd->Wire());
465   for (TopExp_Explorer exp ( sewd->Wire(), TopAbs_EDGE ); exp.More(); exp.Next() ) {
466     TopoDS_Edge E = TopoDS::Edge ( exp.Current() );
467     BRepTools::Update(E);
468   }
469
470   return Standard_True;
471 }
472
473