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