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 //=======================================================================
ShapeFix_SplitTool()45 ShapeFix_SplitTool::ShapeFix_SplitTool()
46 {
47 }
48
49
50 //=======================================================================
51 //function : SplitEdge
52 //purpose :
53 //=======================================================================
54
SplitEdge(const TopoDS_Edge & edge,const Standard_Real param,const TopoDS_Vertex & vert,const TopoDS_Face & face,TopoDS_Edge & newE1,TopoDS_Edge & newE2,const Standard_Real tol3d,const Standard_Real tol2d) const55 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
SplitEdge(const TopoDS_Edge & edge,const Standard_Real param1,const Standard_Real param2,const TopoDS_Vertex & vert,const TopoDS_Face & face,TopoDS_Edge & newE1,TopoDS_Edge & newE2,const Standard_Real tol3d,const Standard_Real tol2d) const144 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
CutEdge(const TopoDS_Edge & edge,const Standard_Real pend,const Standard_Real cut,const TopoDS_Face & face,Standard_Boolean & iscutline) const196 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 beginning
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
SplitEdge(const TopoDS_Edge & edge,const Standard_Real fp,const TopoDS_Vertex & V1,const Standard_Real lp,const TopoDS_Vertex & V2,const TopoDS_Face & face,TopTools_SequenceOfShape & SeqE,Standard_Integer & aNum,const Handle (ShapeBuild_ReShape)& context,const Standard_Real tol3d,const Standard_Real tol2d) const277 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
476