0024881: Wrong status returned by ShapeFix_Wire::FixGaps3d () operation
[occt.git] / src / ShapeFix / ShapeFix_Wire_1.cxx
CommitLineData
973c2be1 1// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 2//
973c2be1 3// This file is part of Open CASCADE Technology software library.
b311480e 4//
d5f74e42 5// This library is free software; you can redistribute it and/or modify it under
6// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 7// by the Free Software Foundation, with special exception defined in the file
8// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9// distribution for complete text of the license and disclaimer of any warranty.
b311480e 10//
973c2be1 11// Alternatively, this file may be used under the terms of Open CASCADE
12// commercial license or contractual agreement.
b311480e 13
7fd59977 14// szv 19.08.99: new methods for fixing gaps between edges (3d curves and pcurves)
15#include <ShapeFix_Wire.hxx>
16#include <Standard_ErrorHandler.hxx>
17#include <Standard_Failure.hxx>
18
19#include <Precision.hxx>
20#include <Bnd_Box2d.hxx>
21#include <Geom_Curve.hxx>
22#include <Geom2d_Curve.hxx>
23#include <Geom2d_Line.hxx>
24
25#include <IntRes2d_SequenceOfIntersectionPoint.hxx>
26#include <IntRes2d_IntersectionPoint.hxx>
27#include <TColgp_SequenceOfPnt.hxx>
28
29#include <TopoDS.hxx>
30#include <TopoDS_Vertex.hxx>
31#include <TopoDS_Edge.hxx>
32#include <TopTools_HSequenceOfShape.hxx>
33
34#include <BRep_Tool.hxx>
35#include <BRep_Builder.hxx>
36
37#include <ShapeExtend.hxx>
38#include <ShapeBuild_Edge.hxx>
39#include <ShapeBuild_Vertex.hxx>
40#include <ShapeAnalysis_Curve.hxx>
41#include <ShapeAnalysis_Edge.hxx>
42#include <ShapeAnalysis_Surface.hxx>
43#include <ShapeAnalysis.hxx>
44#include <GeomConvert_CompCurveToBSplineCurve.hxx>
45#include <Geom_TrimmedCurve.hxx>
46#include <gp_Pln.hxx>
47#include <GeomAPI.hxx>
48#include <TColgp_Array1OfPnt.hxx>
49#include <TColStd_Array1OfReal.hxx>
50#include <TColStd_Array1OfInteger.hxx>
51#include <Geom_BSplineCurve.hxx>
52#include <Geom_SphericalSurface.hxx> //S4135
53#include <Geom2d_BSplineCurve.hxx>
54#include <GeomAdaptor_Curve.hxx>
55#include <GeomAdaptor_HSurface.hxx>
56#include <GeomAdaptor_Surface.hxx>
57#include <TopTools_Array1OfShape.hxx>
58#include <BRepTools.hxx>
59#include <Bnd_Array1OfBox2d.hxx>
60#include <BndLib_Add2dCurve.hxx>
61#include <Geom2dAdaptor_Curve.hxx>
62#include <Geom2dConvert.hxx>
63#include <Geom2d_TrimmedCurve.hxx>
64#include <ShapeBuild_ReShape.hxx>
b311480e 65
7fd59977 66//szv
67#include <TColgp_Array1OfPnt2d.hxx>
68#include <Geom2d_Circle.hxx>
69#include <Geom2d_Ellipse.hxx>
70#include <Geom2d_Parabola.hxx>
71#include <Geom2d_Hyperbola.hxx>
72#include <Geom2d_OffsetCurve.hxx>
73#include <Geom2dInt_GInter.hxx>
74#include <IntRes2d_Domain.hxx>
75#include <IntRes2d_IntersectionSegment.hxx>
76#include <Geom2dAPI_ExtremaCurveCurve.hxx>
77#include <Geom2dAPI_ProjectPointOnCurve.hxx>
78#include <Geom2dAdaptor_HCurve.hxx>
79#include <Approx_Curve2d.hxx>
80#include <Geom2dConvert.hxx>
81
82#include <Geom_Line.hxx>
83#include <Geom_Circle.hxx>
84#include <Geom_Ellipse.hxx>
85#include <Geom_Parabola.hxx>
86#include <Geom_Hyperbola.hxx>
87#include <Geom_OffsetCurve.hxx>
88#include <GeomAPI_ExtremaCurveCurve.hxx>
89#include <GeomAPI_ProjectPointOnCurve.hxx>
90#include <GeomAdaptor_HCurve.hxx>
91#include <Approx_Curve3d.hxx>
92#include <GeomConvert.hxx>
93#include <TopoDS_Iterator.hxx>
94#include <ShapeFix_ShapeTolerance.hxx>
95#include <ShapeAnalysis_TransferParametersProj.hxx>
96//=======================================================================
97//function : FixGaps3d
98//purpose :
99//=======================================================================
100
b311480e 101Standard_Boolean ShapeFix_Wire::FixGaps3d ()
7fd59977 102{
103 myStatusGaps3d = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
104// if ( !IsReady() ) return Standard_False;
105
106 Standard_Integer i, start = ( myClosedMode ? 1 : 2 );
107 if (myFixGapsByRanges)
108 {
109 for ( i = start; i <= NbEdges(); i++ )
110 {
111 FixGap3d ( i );
112 myStatusGaps3d |= myLastFixStatus;
113 }
114 }
115 for ( i = start; i <= NbEdges(); i++ )
116 {
117 FixGap3d ( i, Standard_True );
118 myStatusGaps3d |= myLastFixStatus;
119 }
120
121 return StatusGaps3d ( ShapeExtend_DONE );
122}
123
124//=======================================================================
125//function : FixGaps2d
126//purpose :
127//=======================================================================
128
129 Standard_Boolean ShapeFix_Wire::FixGaps2d ()
130{
131 myStatusGaps2d = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
132// if ( !IsReady() ) return Standard_False;
133
134 Standard_Integer i, start = ( myClosedMode ? 1 : 2 );
135 if (myFixGapsByRanges)
136 {
137 for ( i = start; i <= NbEdges(); i++ )
138 {
139 FixGap2d ( i );
140 myStatusGaps2d |= myLastFixStatus;
141 }
142 }
143 for ( i = start; i <= NbEdges(); i++ )
144 {
145 FixGap2d ( i, Standard_True );
146 myStatusGaps2d |= myLastFixStatus;
147 }
148
149 return StatusGaps2d ( ShapeExtend_DONE );
150}
151
152//=======================================================================
153//function : FixGap3d
154//purpose :
155//=======================================================================
156
157static Standard_Real AdjustOnPeriodic3d (const Handle(Geom_Curve)& c,
158 const Standard_Boolean takefirst,
159 const Standard_Real first,
160 const Standard_Real last,
161 const Standard_Real param)
162{
163 // 15.11.2002 PTV OCC966
164 if (ShapeAnalysis_Curve::IsPeriodic(c))
165 {
166 Standard_Real T = c->Period();
167 Standard_Real shift = -IntegerPart(first/T)*T; if (first<0.) shift += T;
168 Standard_Real sfirst = first+shift, slast = last+shift;
169 if ( takefirst && (param>slast) && (param>sfirst)) return param-T-shift;
170 if (!takefirst && (param<slast) && (param<sfirst)) return param+T-shift;
171 }
172 return param;
173}
174
175 Standard_Boolean ShapeFix_Wire::FixGap3d (const Standard_Integer num,
176 const Standard_Boolean convert)
177{
178 myLastFixStatus = ShapeExtend::EncodeStatus( ShapeExtend_OK );
179// if ( !IsReady() ) return Standard_False;
180
181 //=============
182 // First phase: analysis whether the problem (gap) exists
183 //=============
184
185 if (Context().IsNull()) SetContext(new ShapeBuild_ReShape);
186
187 Standard_Real preci = Precision();
188
189 Handle(ShapeExtend_WireData) sbwd = WireData();
190 Standard_Integer n2 = ( num >0 ? num : sbwd->NbEdges() );
191 Standard_Integer n1 = ( n2 >1 ? n2-1 : sbwd->NbEdges() );
192//smh#8
193 TopoDS_Shape tmp1 = Context()->Apply(sbwd->Edge(n1)),
194 tmp2 = Context()->Apply(sbwd->Edge(n2));
195 TopoDS_Edge E1 = TopoDS::Edge(tmp1),
196 E2 = TopoDS::Edge(tmp2);
197// TopoDS_Face face = myAnalyzer->Face(); // comment by enk
198
199 // Retrieve curves on edges
200 Standard_Real cfirst1, clast1, cfirst2, clast2;
201 Handle(Geom_Curve) C1, C2;
202 ShapeAnalysis_Edge SAE;
203 if (!SAE.Curve3d(E1,C1,cfirst1,clast1) ||
204 !SAE.Curve3d(E2,C2,cfirst2,clast2))
205 {
206 myLastFixStatus |= ShapeExtend::EncodeStatus( ShapeExtend_FAIL1 );
207 return Standard_False;
208 }
209
210 // Check gap in 3d space
211 gp_Pnt cpnt1 = C1->Value(clast1), cpnt2 = C2->Value(cfirst2);
212 Standard_Real gap = cpnt1.Distance(cpnt2);
213 if (!convert && gap<=preci) return Standard_False;
214
215 //=============
216 // Second phase: collecting data necessary for further analysis
217 //=============
218
219 Standard_Boolean reversed1 = (E1.Orientation()==TopAbs_REVERSED),
220 reversed2 = (E2.Orientation()==TopAbs_REVERSED);
221
222 TopoDS_Vertex V1 = SAE.LastVertex(E1), V2 = SAE.FirstVertex(E2);
223 gp_Pnt vpnt = (V1.IsSame(V2))? BRep_Tool::Pnt(V1) :
224 gp_Pnt((BRep_Tool::Pnt(V1).XYZ()+BRep_Tool::Pnt(V2).XYZ())*0.5);
225
226 Standard_Real first1, last1, first2, last2;
227 if (reversed1)
228 {
229 first1 = clast1; last1 = cfirst1;
230 }
231 else
232 {
233 first1 = cfirst1; last1 = clast1;
234 }
235 if (reversed2)
236 {
237 first2 = clast2; last2 = cfirst2;
238 }
239 else
240 {
241 first2 = cfirst2; last2 = clast2;
242 }
243
244 Handle(Geom_Curve) c1 = C1, c2 = C2;
245
246 // Extract basic curves from trimmed and offset
247 Standard_Boolean basic = Standard_False;
248 Standard_Boolean trimmed1 = Standard_False, offset1 = Standard_False;
249 gp_XYZ offval1(0.,0.,0.);
250 while (!basic)
251 {
252 if (c1->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
253 {
254 c1 = Handle(Geom_TrimmedCurve)::DownCast(c1)->BasisCurve();
255 trimmed1 = Standard_True;
256 }
257 else if (c1->IsKind(STANDARD_TYPE(Geom_OffsetCurve)))
258 {
259 Handle(Geom_OffsetCurve) oc = Handle(Geom_OffsetCurve)::DownCast(c1);
260 c1 = oc->BasisCurve();
261 offval1 += oc->Offset()*oc->Direction().XYZ();
262 offset1 = Standard_True;
263 }
264 else basic = Standard_True;
265 }
266 basic = Standard_False;
267 Standard_Boolean trimmed2 = Standard_False, offset2 = Standard_False;
268 gp_XYZ offval2(0.,0.,0.);
269 while (!basic)
270 {
271 if (c2->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
272 {
273 c2 = Handle(Geom_TrimmedCurve)::DownCast(c2)->BasisCurve();
274 trimmed2 = Standard_True;
275 }
276 else if (c2->IsKind(STANDARD_TYPE(Geom_OffsetCurve)))
277 {
278 Handle(Geom_OffsetCurve) oc = Handle(Geom_OffsetCurve)::DownCast(c2);
279 c2 = oc->BasisCurve();
280 offval2 += oc->Offset()*oc->Direction().XYZ();
281 offset2 = Standard_True;
282 }
283 else basic = Standard_True;
284 }
285 // Restore offset curves
286 if (offset1) c1 = new Geom_OffsetCurve(c1,offval1.Modulus(),gp_Dir(offval1));
287 if (offset2) c2 = new Geom_OffsetCurve(c2,offval2.Modulus(),gp_Dir(offval2));
288
289 Standard_Boolean done1 = Standard_False, done2 = Standard_False;
290
291 if (convert)
292 {
2bfe59b6 293 // Check that gap satisfies the precision - in this case no convertation produced
294 if (cpnt1.Distance(vpnt) < preci && cpnt2.Distance(vpnt) < preci)
295 return Standard_False;
7fd59977 296
297 Handle(Geom_BSplineCurve) bsp1, bsp2;
298 Handle(Geom_Curve) c;
299 Standard_Real first, last;
300
301 // iterate on curves
302 Standard_Integer nbcurv = (n1==n2? 1 : 2);
303 for (Standard_Integer j=1; j<=nbcurv; j++)
304 {
305 //Standard_Boolean trim = Standard_False; // skl
306 if (j==1)
307 {
308 if (cpnt1.Distance(vpnt)<preci)
309 {
310 if (n1==n2)
311 {
312 if (cpnt2.Distance(vpnt)<preci) continue;
313 }
314 else continue;
315 }
316 c = c1; first = first1; last = last1; /*trim = trimmed1;*/ // skl
317 }
318 else
319 {
320 if (cpnt2.Distance(vpnt)<preci) continue;
321 c = c2; first = first2; last = last2; /*trim = trimmed2;*/ // skl
322 }
323
324 Handle(Geom_BSplineCurve) bsp;
325
326 // Convert curve to bspline
327 if (c->IsKind(STANDARD_TYPE(Geom_BSplineCurve)))
328 {
329 bsp = Handle(Geom_BSplineCurve)::DownCast(c->Copy());
330 // take segment if trim and range differ
331 Standard_Real fbsp = bsp->FirstParameter(), lbsp = bsp->LastParameter();
332 Standard_Boolean segment = Standard_False;
333 if (first>fbsp)
334 {
335 fbsp = first; segment = Standard_True;
336 }
337 if (last<lbsp)
338 {
339 lbsp = last; segment = Standard_True;
340 }
341 if (segment)
342 bsp = GeomConvert::SplitBSplineCurve(bsp,fbsp,lbsp,
343 ::Precision::Confusion());
344 }
345 else if (c->IsKind(STANDARD_TYPE(Geom_Conic)))
346 {
347 Approx_Curve3d Conv(new GeomAdaptor_HCurve(c,first,last),
348 myAnalyzer->Precision(),GeomAbs_C1,9,1000);
349 if (Conv.IsDone() || Conv.HasResult()) bsp = Conv.Curve();
350 }
351 else
352 {
353 // Restore trim for pcurve
354 Handle(Geom_Curve) tc ;
355 try
356 {
357 OCC_CATCH_SIGNALS
358 // 15.11.2002 PTV OCC966
359 if(!ShapeAnalysis_Curve::IsPeriodic(c))
360 tc = new Geom_TrimmedCurve(c,Max(first,c->FirstParameter()),Min(last,c->LastParameter()));
361 else tc = new Geom_TrimmedCurve(c,first,last);
362 bsp = GeomConvert::CurveToBSplineCurve(tc);
363 }
364 catch (Standard_Failure)
365 {
0797d9d3 366#ifdef OCCT_DEBUG
7fd59977 367 cout << "Warning: ShapeFix_Wire_1::FixGap3d: Exception in TrimmedCurve" <<first<<" " <<last<<endl;
368 Standard_Failure::Caught()->Print(cout); cout << endl;
369#endif
370 }
371 }
372
373 if (j==1) bsp1 = bsp; else bsp2 = bsp;
374 }
375
376 // Take curves ends if could not convert
377 if (bsp1.IsNull()) vpnt = cpnt1;
378 else if (bsp2.IsNull()) vpnt = cpnt2;
379
380 if (!bsp1.IsNull())
381 {
382 if(bsp1->Degree() == 1) bsp1->IncreaseDegree(2); //gka
383 if (n1==n2)
384 {
385 bsp1->SetPole(1,vpnt); bsp1->SetPole(bsp1->NbPoles(),vpnt);
386 }
387 else
388 {
389 if (reversed1) bsp1->SetPole(1,vpnt);
390 else bsp1->SetPole(bsp1->NbPoles(),vpnt);
391 }
392 first1 = bsp1->FirstParameter(); last1 = bsp1->LastParameter();
393 c1 = bsp1;
394 done1 = Standard_True;
395 }
396 if (!bsp2.IsNull())
397 {
398 if(bsp2->Degree() == 1) bsp2->IncreaseDegree(2); //gka
399 if (reversed2) bsp2->SetPole(bsp2->NbPoles(),vpnt);
400 else bsp2->SetPole(1,vpnt);
401 first2 = bsp2->FirstParameter(); last2 = bsp2->LastParameter();
402 c2 = bsp2;
403 done2 = Standard_True;
404 }
405 }
406 else
407 {
408
409 if (n1==n2)
410 {
411 if (c1->IsKind(STANDARD_TYPE(Geom_Circle)) ||
412 c1->IsKind(STANDARD_TYPE(Geom_Ellipse)))
413 {
c6541a0c 414 Standard_Real diff = M_PI - Abs(clast1-cfirst2)*0.5;
7fd59977 415 first1 -= diff; last1 += diff;
416 done1 = Standard_True;
417 }
418 }
419 else
420 {
421
422 // Determine domains for extremal points locating
423 Standard_Real domfirst1 = first1, domlast1 = last1;
424 if (c1->IsKind(STANDARD_TYPE(Geom_BSplineCurve)) ||
425 c1->IsKind(STANDARD_TYPE(Geom_BezierCurve)))
426 {
427 domfirst1 = c1->FirstParameter();
428 domlast1 = c1->LastParameter();
429 }
430 else if (c1->IsKind(STANDARD_TYPE(Geom_Line)) ||
431 c1->IsKind(STANDARD_TYPE(Geom_Parabola)) ||
432 c1->IsKind(STANDARD_TYPE(Geom_Hyperbola)))
433 {
434 Standard_Real diff = domlast1 - domfirst1;
435 if (reversed1) domfirst1 -= 10.*diff;
436 else domlast1 += 10.*diff;
437 }
438 else if (c1->IsKind(STANDARD_TYPE(Geom_Circle)) ||
439 c1->IsKind(STANDARD_TYPE(Geom_Ellipse)))
440 {
c6541a0c 441 domfirst1 = 0.; domlast1 = 2*M_PI;
7fd59977 442 }
443 Standard_Real domfirst2 = first2, domlast2 = last2;
444 if (c2->IsKind(STANDARD_TYPE(Geom_BSplineCurve)) ||
445 c2->IsKind(STANDARD_TYPE(Geom_BezierCurve)))
446 {
447 domfirst2 = c2->FirstParameter();
448 domlast2 = c2->LastParameter();
449 }
450 else if (c2->IsKind(STANDARD_TYPE(Geom_Line)) ||
451 c2->IsKind(STANDARD_TYPE(Geom_Parabola)) ||
452 c2->IsKind(STANDARD_TYPE(Geom_Hyperbola)))
453 {
454 Standard_Real diff = domlast2 - domfirst2;
455 if (reversed2) domlast2 += 10.*diff;
456 else domfirst2 -= 10.*diff;
457 }
458 else if (c2->IsKind(STANDARD_TYPE(Geom_Circle)) ||
459 c2->IsKind(STANDARD_TYPE(Geom_Ellipse)))
460 {
c6541a0c 461 domfirst2 = 0.; domlast2 = 2*M_PI;
7fd59977 462 }
463
464 Standard_Real ipar1 = clast1, ipar2 = cfirst2;
465
466 // Try to find projections of vertex point
467 GeomAPI_ProjectPointOnCurve Proj;
468 Standard_Real u1 = ipar1, u2 = ipar2;
469 Proj.Init(vpnt,c1,domfirst1,domlast1);
470 if (Proj.NbPoints())
471 {
472 Standard_Integer index = 1;
473 Standard_Real dist, mindist=-1.;
474 for (Standard_Integer i=1; i<=Proj.NbPoints(); i++)
475 {
476 dist = vpnt.Distance(Proj.Point(i));
477 if (mindist>dist || mindist<0.)
478 {
479 index = i; mindist = dist;
480 }
481 u1 = Proj.Parameter(index);
482 }
483 }
484 Proj.Init(vpnt,c2,domfirst2,domlast2);
485 if (Proj.NbPoints())
486 {
487 Standard_Integer index = 1;
488 Standard_Real dist, mindist=-1.;
489 for (Standard_Integer i=1; i<=Proj.NbPoints(); i++)
490 {
491 dist = vpnt.Distance(Proj.Point(i));
492 if (mindist>dist || mindist<0.)
493 {
494 index = i; mindist = dist;
495 }
496 u2 = Proj.Parameter(index);
497 }
498 }
499 // Ajust parameters on periodic curves
500 u1 = AdjustOnPeriodic3d(c1,reversed1,first1,last1,u1);
501 u2 = AdjustOnPeriodic3d(c2,!reversed2,first2,last2,u2);
502 // Check points to satisfy distance criterium
503 gp_Pnt p1 = c1->Value(u1), p2 = c2->Value(u2);
504 if (p1.Distance(p2)<=gap &&
505 Abs(cfirst1-u1) > ::Precision::PConfusion() &&
506 Abs(clast2-u2) > ::Precision::PConfusion() &&
507 (((u1>first1) && (u1<last1)) || ((u2>first2) && (u2<last2)) ||
508 (cpnt1.Distance(p1)<=gap) || (cpnt2.Distance(p2)<=gap)))
509 {
510 ipar1 = u1; ipar2 = u2;
511 done1 = done2 = Standard_True;
512 }
513
514 // Try to find closest points if nothing yet found
515 if (!done1)
516 {
517
518 // Recompute domains
519 if (reversed1)
520 {
521 domfirst1 = ipar1; domlast1 = last1;
522 }
523 else
524 {
525 domfirst1 = first1; domlast1 = ipar1;
526 }
527 if (reversed2)
528 {
529 domfirst2 = first2; domlast2 = ipar2;
530 }
531 else
532 {
533 domfirst2 = ipar2; domlast2 = last2;
534 }
535
536 GeomAPI_ExtremaCurveCurve Extr(c1,c2,domfirst1,domlast1,domfirst2,domlast2);
537 if (Extr.NbExtrema())
538 {
539 try
540 {
541 OCC_CATCH_SIGNALS
542 // First find all intersections
543 gp_Pnt pp1, pp2;
544 Standard_Integer index1=0, index2=0;
545 Standard_Real uu1, uu2, pardist, pardist1=-1., pardist2=-1.;
546 for (Standard_Integer i=1; i<=Extr.NbExtrema(); i++)
547 {
548 Extr.Parameters(i,uu1,uu2);
549 // Ajust parameters on periodic curves
550 uu1 = AdjustOnPeriodic3d(c1,reversed1,first1,last1,uu1);
551 uu2 = AdjustOnPeriodic3d(c2,!reversed2,first2,last2,uu2);
552 pp1 = c1->Value(uu1); pp2 = c2->Value(uu2);
553 if (pp1.Distance(pp2) < ::Precision::Confusion())
554 {
555 // assume intersection
556 pardist = Abs(cfirst1-uu1);
557 if (pardist1>pardist || pardist1<0.)
558 {
559 index1 = i; pardist1 = pardist;
560 }
561 pardist = Abs(clast2-uu2);
562 if (pardist2>pardist || pardist2<0.)
563 {
564 index2 = i; pardist2 = pardist;
565 }
566 }
567 }
568 if (index1!=0 && index2!=0)
569 {
570 if (index1!=index2)
571 {
572 // take intersection closer to vertex point
573 Extr.Parameters(index1,uu1,uu2);
574 pp1 = gp_Pnt((c1->Value(uu1).XYZ()+c2->Value(uu2).XYZ())*0.5);
575 Extr.Parameters(index2,uu1,uu2);
576 pp2 = gp_Pnt((c1->Value(uu1).XYZ()+c2->Value(uu2).XYZ())*0.5);
577 if (pp2.Distance(vpnt) < pp1.Distance(vpnt)) index1 = index2;
578 }
579 Extr.Parameters(index1,uu1,uu2);
580 }
581 else Extr.LowerDistanceParameters(uu1,uu2);
582 // Ajust parameters on periodic curves
583 uu1 = AdjustOnPeriodic3d(c1,reversed1,first1,last1,uu1);
584 uu2 = AdjustOnPeriodic3d(c2,!reversed2,first2,last2,uu2);
585 // Check points to satisfy distance criterium
586 pp1 = c1->Value(uu1), pp2 = c2->Value(uu2);
587 if (pp1.Distance(pp2)<=gap &&
588 Abs(cfirst1-uu1) > ::Precision::PConfusion() &&
589 Abs(clast2-uu2) > ::Precision::PConfusion() &&
590 (((uu1>first1) && (uu1<last1)) || ((uu2>first2) && (uu2<last2)) ||
591 (cpnt1.Distance(pp1)<=gap) || (cpnt2.Distance(pp2)<=gap)))
592 {
593 ipar1 = uu1; ipar2 = uu2;
594 done1 = done2 = Standard_True;
595 }
596 }
597 catch ( Standard_Failure )
598 {
599 }
600 }
601 }
602
603 try
604 {
605 OCC_CATCH_SIGNALS
606 if (done1)
607 {
608 if (ipar1==clast1) done1 = Standard_False;
609 else
610 {
611 // Set up new bounds for curve
612 if (reversed1) first1 = ipar1; else last1 = ipar1;
613 // Set new trim for old curve
614 if (trimmed1)
615 {
616 // Standard_Real ff1 = c1->FirstParameter();
617 // Standard_Real ll1 = c1->LastParameter();
618 c1 = new Geom_TrimmedCurve(c1,first1,last1);
619 }
620 }
621 }
622 if (done2)
623 {
624 if (ipar2==cfirst2) done2 = Standard_False;
625 else
626 {
627 // Set up new bounds for curve
628 if (reversed2) last2 = ipar2; else first2 = ipar2;
629 // Set new trim for old curve
630 if (trimmed2)
631 {
632 // Standard_Real ff2 = c2->FirstParameter();
633 // Standard_Real ll2 = c2->LastParameter();
634 c2 = new Geom_TrimmedCurve(c2,first2,last2);
635 }
636 }
637 }
638 }
639 catch (Standard_Failure)
640 {
0797d9d3 641#ifdef OCCT_DEBUG
7fd59977 642 cout << "Warning: ShapeFix_Wire_1::FixGap3d: Exception in TrimmedCurve :"<<endl;
643 Standard_Failure::Caught()->Print(cout); cout << endl;
644#endif
645 }
646 }
647 }
648
649 if (done1 || done2)
650 {
651
652 BRep_Builder B;
653 ShapeBuild_Edge SBE;
654 ShapeFix_ShapeTolerance SFST;
655
656 // Update vertices
657 TopoDS_Vertex nullV, newV1;
658//smh#8
659 TopoDS_Shape emptyCopiedV2 = V2.EmptyCopied();
660 TopoDS_Vertex newV2 = TopoDS::Vertex(emptyCopiedV2);
661 SFST.SetTolerance(newV2,::Precision::Confusion());
662 Context()->Replace(V2,newV2);
663 if (V1.IsSame(V2))
664//smh#8
665 {
666 TopoDS_Shape tmpV2 = newV2.Oriented(TopAbs_REVERSED);
667 newV1 = TopoDS::Vertex(tmpV2);
668 }
669 else
670 {
671//smh#8
672 TopoDS_Shape emptyCopied = V1.EmptyCopied();
673 newV1 = TopoDS::Vertex(emptyCopied);
674 SFST.SetTolerance(newV1,::Precision::Confusion());
675 Context()->Replace(V1,newV1);
676 }
677
678 if (done1)
679 {
680 // Update first edge
681 TopoDS_Edge newE1 = SBE.CopyReplaceVertices(E1,nullV,newV1);
682//smh#8
683 TopoDS_Shape tmpE1 = newE1.Oriented(TopAbs_FORWARD);
684 B.UpdateEdge(TopoDS::Edge(tmpE1),c1,0.);
685 SBE.SetRange3d(TopoDS::Edge(tmpE1),first1,last1);
686 SFST.SetTolerance(newE1,::Precision::Confusion(),TopAbs_EDGE);
687 B.SameRange(newE1,Standard_False);
688// B.SameParameter(newE1,Standard_False);
689
690 //To keep NM vertices belonging initial edges
691 TopoDS_Iterator aItv(E1,Standard_False);
692 for( ; aItv.More(); aItv.Next()) {
693 if(aItv.Value().Orientation() == TopAbs_INTERNAL ||
694 aItv.Value().Orientation() == TopAbs_EXTERNAL) {
695 TopoDS_Vertex aOldV = TopoDS::Vertex(aItv.Value());
696 TopoDS_Vertex anewV = ShapeAnalysis_TransferParametersProj::CopyNMVertex(aOldV,newE1,E1);
697 B.Add(newE1,anewV);
698 Context()->Replace(aOldV,anewV);
699 }
700 }
701
702 Context()->Replace(E1,newE1);
703 sbwd->Set(newE1,n1);
704 }
705
706 if (done2)
707 {
708 // Update second edge
709 TopoDS_Edge newE2 = SBE.CopyReplaceVertices(E2,newV2,nullV);
710//smh#8
711 TopoDS_Shape tmpE2 = newE2.Oriented(TopAbs_FORWARD);
712 B.UpdateEdge(TopoDS::Edge(tmpE2),c2,0.);
713 SBE.SetRange3d(TopoDS::Edge(tmpE2),first2,last2);
714 SFST.SetTolerance(newE2,::Precision::Confusion(),TopAbs_EDGE);
715 B.SameRange(newE2,Standard_False);
716// B.SameParameter(newE2,Standard_False);
717
718 //To keep NM vertices belonging initial edges
719 TopoDS_Iterator aItv(E2,Standard_False);
720 for( ; aItv.More(); aItv.Next()) {
721 if(aItv.Value().Orientation() == TopAbs_INTERNAL ||
722 aItv.Value().Orientation() == TopAbs_EXTERNAL) {
723 TopoDS_Vertex aOldV = TopoDS::Vertex(aItv.Value());
724 TopoDS_Vertex anewV = ShapeAnalysis_TransferParametersProj::CopyNMVertex(aOldV,newE2,E2);
725 B.Add(newE2,anewV);
726 Context()->Replace(aOldV,anewV);
727 }
728 }
729 Context()->Replace(E2,newE2);
730 sbwd->Set(newE2,n2);
731 }
732
733 myLastFixStatus |= ShapeExtend::EncodeStatus( ShapeExtend_DONE1 );
734 }
735 else
736 if (convert)
737 myLastFixStatus |= ShapeExtend::EncodeStatus( ShapeExtend_FAIL2 );
738
739 return (done1 || done2);
740}
741
742//=======================================================================
743//function : FixGap2d
744//purpose :
745//=======================================================================
746
747static Standard_Real AdjustOnPeriodic2d (const Handle(Geom2d_Curve)& pc,
748 const Standard_Boolean takefirst,
749 const Standard_Real first,
750 const Standard_Real last,
751 const Standard_Real param)
752{
753 // 15.11.2002 PTV OCC966
754 if (ShapeAnalysis_Curve::IsPeriodic(pc))
755 {
756 Standard_Real T = pc->Period();
757 Standard_Real shift = -IntegerPart(first/T)*T; if (first<0.) shift += T;
758 Standard_Real sfirst = first+shift, slast = last+shift;
759 if ( takefirst && (param>slast) && (param>sfirst)) return param-T-shift;
760 if (!takefirst && (param<slast) && (param<sfirst)) return param+T-shift;
761 }
762 return param;
763}
764
765 Standard_Boolean ShapeFix_Wire::FixGap2d (const Standard_Integer num,
766 const Standard_Boolean convert)
767{
768 myLastFixStatus = ShapeExtend::EncodeStatus( ShapeExtend_OK );
769 if ( !IsReady() ) return Standard_False;
770
771 //=============
772 // First phase: analysis whether the problem (gap) exists
773 //=============
774
775 if (Context().IsNull()) SetContext(new ShapeBuild_ReShape);
776
777 Standard_Real preci = ::Precision::PConfusion();
778 //Standard_Real preci = Precision();
779 //GeomAdaptor_Surface& SA = Analyzer().Surface()->Adaptor()->ChangeSurface();
780 //preci = Max(SA.UResolution(preci), SA.VResolution(preci));
781
782 Handle(ShapeExtend_WireData) sbwd = WireData();
783 Standard_Integer n2 = ( num >0 ? num : sbwd->NbEdges() );
784 Standard_Integer n1 = ( n2 >1 ? n2-1 : sbwd->NbEdges() );
785//smh#8
786 TopoDS_Shape tmp1 = Context()->Apply(sbwd->Edge(n1)),
787 tmp2 = Context()->Apply(sbwd->Edge(n2));
788 TopoDS_Edge E1 = TopoDS::Edge(tmp1),
789 E2 = TopoDS::Edge(tmp2);
790 TopoDS_Face face = myAnalyzer->Face();
791
792 // Retrieve pcurves on edges
793 Standard_Real cfirst1, clast1, cfirst2, clast2;
794 Handle(Geom2d_Curve) PC1, PC2;
795 ShapeAnalysis_Edge SAE;
796 if (!SAE.PCurve(E1,face,PC1,cfirst1,clast1) ||
797 !SAE.PCurve(E2,face,PC2,cfirst2,clast2) ||
798 sbwd->IsSeam(n1) || sbwd->IsSeam(n2))
799 {
800 myLastFixStatus |= ShapeExtend::EncodeStatus( ShapeExtend_FAIL1 );
801 return Standard_False;
802 }
803
804 // Check gap in 2d space
805 gp_Pnt2d cpnt1 = PC1->Value(clast1), cpnt2 = PC2->Value(cfirst2);
806 Standard_Real gap = cpnt1.Distance(cpnt2);
807 if (gap<=preci) return Standard_False;
808
809 //=============
810 // Second phase: collecting data necessary for further analysis
811 //=============
812
813 Standard_Boolean reversed1 = (E1.Orientation()==TopAbs_REVERSED),
814 reversed2 = (E2.Orientation()==TopAbs_REVERSED);
815
816 Standard_Real first1, last1, first2, last2;
817 if (reversed1)
818 {
819 first1 = clast1; last1 = cfirst1;
820 }
821 else
822 {
823 first1 = cfirst1; last1 = clast1;
824 }
825 if (reversed2)
826 {
827 first2 = clast2; last2 = cfirst2;
828 }
829 else
830 {
831 first2 = cfirst2; last2 = clast2;
832 }
833
834 Handle(Geom2d_Curve) pc1 = PC1, pc2 = PC2;
835
836 // Extract basic curves from trimmed and offset
837 Standard_Boolean basic = Standard_False;
838 Standard_Boolean trimmed1 = Standard_False, offset1 = Standard_False;
839 Standard_Real offval1 = 0.;
840 while (!basic)
841 {
842 if (pc1->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve)))
843 {
844 pc1 = Handle(Geom2d_TrimmedCurve)::DownCast(pc1)->BasisCurve();
845 trimmed1 = Standard_True;
846 }
847 else if (pc1->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve)))
848 {
849 Handle(Geom2d_OffsetCurve) oc = Handle(Geom2d_OffsetCurve)::DownCast(pc1);
850 pc1 = oc->BasisCurve();
851 offval1 += oc->Offset();
852 offset1 = Standard_True;
853 }
854 else basic = Standard_True;
855 }
856 basic = Standard_False;
857 Standard_Boolean trimmed2 = Standard_False, offset2 = Standard_False;
858 Standard_Real offval2 = 0.;
859 while (!basic)
860 {
861 if (pc2->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve)))
862 {
863 pc2 = Handle(Geom2d_TrimmedCurve)::DownCast(pc2)->BasisCurve();
864 trimmed2 = Standard_True;
865 }
866 else if (pc2->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve)))
867 {
868 Handle(Geom2d_OffsetCurve) oc = Handle(Geom2d_OffsetCurve)::DownCast(pc2);
869 pc2 = oc->BasisCurve();
870 offval2 += oc->Offset();
871 offset2 = Standard_True;
872 }
873 else basic = Standard_True;
874 }
875 // Restore offset curves
876 if (offset1) pc1 = new Geom2d_OffsetCurve(pc1,offval1);
877 if (offset2) pc2 = new Geom2d_OffsetCurve(pc2,offval2);
878
879 Standard_Boolean done1 = Standard_False, done2 = Standard_False;
880
881 // Determine same edge case
882 if (convert)
883 {
884
885 Handle(Geom2d_BSplineCurve) bsp1, bsp2;
886 Handle(Geom2d_Curve) pc;
887 Standard_Real first, last;
888
889 // iterate on pcurves
890 Standard_Integer nbcurv = (n1==n2? 1 : 2);
891 for (Standard_Integer j=1; j<=nbcurv; j++)
892 {
893 //Standard_Integer trim = Standard_False; // skl
894 Handle(Geom2d_BSplineCurve) bsp;
895
896 if (j==1)
897 {
898 pc = pc1; first = first1; last = last1; /*trim = trimmed1;*/
899 } // skl
900 else
901 {
902 pc = pc2; first = first2; last = last2; /*trim = trimmed2;*/
903 } // skl
904
905 // Convert pcurve to bspline
906 if (pc->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve)))
907 {
908 bsp = Handle(Geom2d_BSplineCurve)::DownCast(pc->Copy());
909 // take segment if trim and range differ
910 Standard_Real fbsp = bsp->FirstParameter(), lbsp = bsp->LastParameter();
911 Standard_Boolean segment = Standard_False;
912 if (first>fbsp)
913 {
914 fbsp = first; segment = Standard_True;
915 }
916 if (last<lbsp)
917 {
918 lbsp = last; segment = Standard_True;
919 }
920 if (segment)
921 bsp = Geom2dConvert::SplitBSplineCurve(bsp,fbsp,lbsp,
922 ::Precision::PConfusion());
923 }
924 else if (pc->IsKind(STANDARD_TYPE(Geom2d_Conic)))
925 {
926 GeomAdaptor_Surface& AS = myAnalyzer->Surface()->Adaptor3d()->ChangeSurface();
927 Standard_Real tolu = AS.UResolution(myAnalyzer->Precision()),
928 tolv = AS.VResolution(myAnalyzer->Precision());
929 Approx_Curve2d Conv(new Geom2dAdaptor_HCurve(pc,first,last),
930 first,last,tolu,tolv,GeomAbs_C1,9,1000);
931 if (Conv.IsDone() || Conv.HasResult()) bsp = Conv.Curve();
932 }
933 else
934 {
935 // Restore trim for pcurve
936 try
937 {
938 OCC_CATCH_SIGNALS
939 Handle(Geom2d_Curve) c;
940 // 15.11.2002 PTV OCC966
941 if(!ShapeAnalysis_Curve::IsPeriodic(pc))
942 c = new Geom2d_TrimmedCurve(pc,Max(first,pc->FirstParameter()),Min(last,pc->LastParameter()));
943 else
944 c = new Geom2d_TrimmedCurve(pc,first,last);
945 bsp = Geom2dConvert::CurveToBSplineCurve(c);
946 }
947 catch (Standard_Failure)
948 {
0797d9d3 949#ifdef OCCT_DEBUG
7fd59977 950 cout << "Warning: ShapeFix_Wire_1::FixGap2d: Exception in TrimmedCurve2d" <<first<<" " <<last<<endl;
951 Standard_Failure::Caught()->Print(cout); cout << endl;
952#endif
953 }
954 }
955
956 if (j==1) bsp1 = bsp; else bsp2 = bsp;
957 }
958
959 // Take curves ends if could not convert
960 gp_Pnt2d mpnt((cpnt1.XY()+cpnt2.XY())*0.5);
961 if (bsp1.IsNull()) mpnt = cpnt1;
962 else if (bsp2.IsNull()) mpnt = cpnt2;
963
964 if (!bsp1.IsNull())
965 {
966 if(bsp1->Degree() == 1) bsp1->IncreaseDegree(2);
967 if (n1==n2)
968 {
969 bsp1->SetPole(1,mpnt); bsp1->SetPole(bsp1->NbPoles(),mpnt);
970 }
971 else
972 {
973 if (reversed1) bsp1->SetPole(1,mpnt);
974 else bsp1->SetPole(bsp1->NbPoles(),mpnt);
975 }
976 first1 = bsp1->FirstParameter(); last1 = bsp1->LastParameter();
977 pc1 = bsp1;
978 done1 = Standard_True;
979 }
980 if (!bsp2.IsNull())
981 {
982 if(bsp2->Degree() == 1) bsp2->IncreaseDegree(2);
983 if (reversed2) bsp2->SetPole(bsp2->NbPoles(),mpnt);
984 else bsp2->SetPole(1,mpnt);
985 first2 = bsp2->FirstParameter(); last2 = bsp2->LastParameter();
986 pc2 = bsp2;
987 done2 = Standard_True;
988 }
989 }
990 else
991 {
992
993 if (n1==n2)
994 {
995 if (pc1->IsKind(STANDARD_TYPE(Geom2d_Circle)) ||
996 pc1->IsKind(STANDARD_TYPE(Geom2d_Ellipse)))
997 {
c6541a0c 998 Standard_Real diff = M_PI - Abs(clast1-cfirst2)*0.5;
7fd59977 999 first1 -= diff; last1 += diff;
1000 done1 = Standard_True;
1001 }
1002 }
1003 else
1004 {
1005
1006 // Determine domains for extremal points locating
1007 Standard_Real domfirst1 = first1, domlast1 = last1;
1008 if (pc1->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve)) ||
1009 pc1->IsKind(STANDARD_TYPE(Geom2d_BezierCurve)))
1010 {
1011 domfirst1 = pc1->FirstParameter();
1012 domlast1 = pc1->LastParameter();
1013 }
1014 else if (pc1->IsKind(STANDARD_TYPE(Geom2d_Line)) ||
1015 pc1->IsKind(STANDARD_TYPE(Geom2d_Parabola)) ||
1016 pc1->IsKind(STANDARD_TYPE(Geom2d_Hyperbola)))
1017 {
1018 Standard_Real diff = domlast1 - domfirst1;
1019 if (reversed1) domfirst1 -= 10.*diff;
1020 else domlast1 += 10.*diff;
1021 }
1022 else if (pc1->IsKind(STANDARD_TYPE(Geom2d_Circle)) ||
1023 pc1->IsKind(STANDARD_TYPE(Geom2d_Ellipse)))
1024 {
c6541a0c 1025 domfirst1 = 0.; domlast1 = 2*M_PI;
7fd59977 1026 }
1027 Standard_Real domfirst2 = first2, domlast2 = last2;
1028 if (pc2->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve)) ||
1029 pc2->IsKind(STANDARD_TYPE(Geom2d_BezierCurve)))
1030 {
1031 domfirst2 = pc2->FirstParameter();
1032 domlast2 = pc2->LastParameter();
1033 }
1034 else if (pc2->IsKind(STANDARD_TYPE(Geom2d_Line)) ||
1035 pc2->IsKind(STANDARD_TYPE(Geom2d_Parabola)) ||
1036 pc2->IsKind(STANDARD_TYPE(Geom2d_Hyperbola)))
1037 {
1038 Standard_Real diff = domlast2 - domfirst2;
1039 if (reversed2) domlast2 += 10.*diff;
1040 else domfirst2 -= 10.*diff;
1041 }
1042 else if (pc2->IsKind(STANDARD_TYPE(Geom2d_Circle)) ||
1043 pc2->IsKind(STANDARD_TYPE(Geom2d_Ellipse)))
1044 {
c6541a0c 1045 domfirst2 = 0.; domlast2 = 2*M_PI;
7fd59977 1046 }
1047
1048 Standard_Real ipar1 = clast1, ipar2 = cfirst2;
1049
1050 Geom2dInt_GInter Inter;
1051 Standard_Real tolint = ::Precision::PConfusion();
1052
1053 Geom2dAdaptor_Curve AC1(pc1), AC2(pc2);
1054
1055 // Try to find intersection points
1056 IntRes2d_Domain dom1(pc1->Value(domfirst1),domfirst1,tolint,
1057 pc1->Value(domlast1),domlast1,tolint);
1058 IntRes2d_Domain dom2(pc2->Value(domfirst2),domfirst2,tolint,
1059 pc2->Value(domlast2),domlast2,tolint);
1060 Inter.Perform( AC1, dom1, AC2, dom2, tolint, tolint );
1061 if (Inter.IsDone())
1062 {
1063 if (Inter.NbPoints() || Inter.NbSegments())
1064 {
1065 Standard_Integer i, index1 = 0, index2 = 0;
1066 Standard_Real pardist, pardist1=-1., pardist2=-1.;
1067 // iterate on intersection points
1068 IntRes2d_IntersectionPoint IP;
1069 for ( i=1; i<=Inter.NbPoints(); i++ )
1070 {
1071 IP = Inter.Point(i);
1072 // Adjust parameters on periodic curves
1073 Standard_Real u1 = AdjustOnPeriodic2d(pc1,reversed1,first1,last1,
1074 IP.ParamOnFirst());
1075 Standard_Real u2 = AdjustOnPeriodic2d(pc2,!reversed2,first2,last2,
1076 IP.ParamOnSecond());
1077 pardist = Abs(cfirst1-u1);
1078 if (pardist1>pardist || pardist1<0.)
1079 {
1080 index1 = i; pardist1 = pardist;
1081 }
1082 pardist = Abs(clast2-u2);
1083 if (pardist2>pardist || pardist2<0.)
1084 {
1085 index2 = i; pardist2 = pardist;
1086 }
1087 }
1088 Standard_Integer flag1 = 0, flag2 = 0;
1089 // iterate on intersection segments
1090 IntRes2d_IntersectionSegment IS;
1091 for ( i=1; i<=Inter.NbSegments(); i++ )
1092 {
1093 IS = Inter.Segment(i);
1094 for (Standard_Integer j=1; j<=2; j++)
1095 {
1096 if ((j==1 && IS.HasFirstPoint()) ||
1097 (j==2 && IS.HasLastPoint()))
1098 {
1099 if (j==1) IP = IS.FirstPoint();
1100 else IP = IS.LastPoint();
1101 // Adjust parameters on periodic curves
1102 Standard_Real u1 = AdjustOnPeriodic2d(pc1,reversed1,first1,last1,
1103 IP.ParamOnFirst());
1104 Standard_Real u2 = AdjustOnPeriodic2d(pc2,!reversed2,first2,last2,
1105 IP.ParamOnSecond());
1106 pardist = Abs(cfirst1-u1);
1107 if (pardist1>pardist || pardist1<0.)
1108 {
1109 flag1 = j; index1 = i; pardist1 = pardist;
1110 }
1111 pardist = Abs(clast2-u2);
1112 if (pardist2>pardist || pardist2<0.)
1113 {
1114 flag2 = j; index2 = i; pardist2 = pardist;
1115 }
1116 }
1117 }
1118 }
1119 if (index1!=index2 || flag1!=flag2)
1120 {
1121 // take intersection closer to mean point
1122 gp_Pnt2d pt1, pt2;
1123 if (flag1==0) pt1 = Inter.Point(index1).Value();
1124 else
1125 {
1126 IS = Inter.Segment(index1);
1127 if (flag1==1) pt1 = IS.FirstPoint().Value();
1128 else pt1 = IS.LastPoint().Value();
1129 }
1130 if (flag2==0) pt2 = Inter.Point(index2).Value();
1131 else
1132 {
1133 IS = Inter.Segment(index2);
1134 if (flag2==1) pt2 = IS.FirstPoint().Value();
1135 else pt2 = IS.LastPoint().Value();
1136 }
1137 gp_Pnt2d mpnt((cpnt1.XY()+cpnt2.XY())*0.5);
1138 if (pt2.Distance(mpnt) < pt1.Distance(mpnt))
1139 {
1140 index1 = index2; flag1 = flag2;
1141 }
1142 }
1143 if (flag1==0) IP = Inter.Point(index1);
1144 else
1145 {
1146 IS = Inter.Segment(index1);
1147 if (flag1==1) IP = IS.FirstPoint();
1148 else IP = IS.LastPoint();
1149 }
1150 // Ajust parameters on periodic curves
1151 Standard_Real u1 = AdjustOnPeriodic2d(pc1,reversed1,first1,last1,
1152 IP.ParamOnFirst());
1153 Standard_Real u2 = AdjustOnPeriodic2d(pc2,!reversed2,first2,last2,
1154 IP.ParamOnSecond());
1155 // Check points to satisfy distance criterium
1156 gp_Pnt2d p1 = pc1->Value(u1), p2 = pc2->Value(u2);
1157 if (p1.Distance(p2)<=gap &&
1158 Abs(cfirst1-u1) > ::Precision::PConfusion() &&
1159 Abs(clast2 -u2) > ::Precision::PConfusion() &&
1160 (((u1>first1) && (u1<last1)) || ((u2>first2) && (u2<last2)) ||
1161 (cpnt1.Distance(p1)<=gap) || (cpnt2.Distance(p2)<=gap)))
1162 {
1163 ipar1 = u1; ipar2 = u2;
1164 done1 = done2 = Standard_True;
1165 }
1166 }
1167 }
1168
1169 // Try to find closest points if nothing yet found
1170 if (!done1)
1171 {
1172 Geom2dAPI_ExtremaCurveCurve Extr(pc1,pc2,domfirst1,domlast1,domfirst2,domlast2);
1173 if (Extr.NbExtrema())
1174 {
1175 Standard_Real u1, u2;
1176 Extr.LowerDistanceParameters(u1,u2);
1177 // Ajust parameters on periodic curves
1178 u1 = AdjustOnPeriodic2d(pc1,reversed1,first1,last1,u1);
1179 u2 = AdjustOnPeriodic2d(pc2,!reversed2,first2,last2,u2);
1180 // Check points to satisfy distance criterium
1181 gp_Pnt2d p1 = pc1->Value(u1), p2 = pc2->Value(u2);
1182 if (p1.Distance(p2)<=gap &&
1183 Abs(cfirst1-u1) > ::Precision::PConfusion() &&
1184 Abs(clast2 -u2) > ::Precision::PConfusion() &&
1185 (((u1>first1) && (u1<last1)) || ((u2>first2) && (u2<last2)) ||
1186 (cpnt1.Distance(p1)<=gap) || (cpnt2.Distance(p2)<=gap)))
1187 {
1188 ipar1 = u1; ipar2 = u2;
1189 done1 = done2 = Standard_True;
1190 }
1191 }
1192 }
1193
1194 // Try to find projections if nothing yet found
1195 if (!done1)
1196 {
1197 Geom2dAPI_ProjectPointOnCurve Proj;
1198 gp_Pnt2d ipnt1 = cpnt1, ipnt2 = cpnt2;
1199 Standard_Real u1 = ipar1, u2 = ipar2;
1200 Proj.Init(cpnt2,pc1,domfirst1,domlast1);
1201 if (Proj.NbPoints())
1202 {
1203 Standard_Integer index = 1;
1204 Standard_Real dist, mindist=-1.;
1205 for (Standard_Integer i=1; i<=Proj.NbPoints(); i++)
1206 {
1207 dist = cpnt2.Distance(Proj.Point(i));
1208 if (mindist>dist || mindist<0.)
1209 {
1210 index = i; mindist = dist;
1211 }
1212 ipnt1 = Proj.Point(index);
1213 u1 = Proj.Parameter(index);
1214 }
1215 }
1216 Proj.Init(cpnt1,pc2,domfirst2,domlast2);
1217 if (Proj.NbPoints())
1218 {
1219 Standard_Integer index = 1;
1220 Standard_Real dist, mindist=-1.;
1221 for (Standard_Integer i=1; i<=Proj.NbPoints(); i++)
1222 {
1223 dist = cpnt1.Distance(Proj.Point(i));
1224 if (mindist>dist || mindist<0.)
1225 {
1226 index = i; mindist = dist;
1227 }
1228 ipnt2 = Proj.Point(index);
1229 u2 = Proj.Parameter(index);
1230 }
1231 }
1232 // Ajust parameters on periodic curves
1233 u1 = AdjustOnPeriodic2d(pc1,reversed1,first1,last1,u1);
1234 u2 = AdjustOnPeriodic2d(pc2,!reversed2,first2,last2,u2);
1235 // Process special case of projection
1236 if ((((reversed1 && u1>clast1) || (!reversed1 && u1<clast1)) &&
1237 ((reversed2 && u2<cfirst2) || (!reversed2 && u2>cfirst2))) ||
1238 (((reversed1 && u1<clast1) || (!reversed1 && u1>clast1)) &&
1239 ((reversed2 && u2>cfirst2) || (!reversed2 && u2<cfirst2))))
1240 {
1241 // both projections lie inside/outside initial domains
1242 // project mean point
1243 gp_Pnt2d mpnt((cpnt1.XY()+cpnt2.XY())*0.5);
1244 u1 = ipar1; u2 = ipar2;
1245 Proj.Init(mpnt,pc1,domfirst1,domlast1);
1246 if (Proj.NbPoints())
1247 {
1248 Standard_Integer index = 1;
1249 Standard_Real dist, mindist=-1.;
1250 for (Standard_Integer i=1; i<=Proj.NbPoints(); i++)
1251 {
1252 dist = mpnt.Distance(Proj.Point(i));
1253 if (mindist>dist || mindist<0.)
1254 {
1255 index = i; mindist = dist;
1256 }
1257 ipnt1 = Proj.Point(index);
1258 u1 = Proj.Parameter(index);
1259 }
1260 }
1261 Proj.Init(mpnt,pc2,domfirst2,domlast2);
1262 if (Proj.NbPoints())
1263 {
1264 Standard_Integer index = 1;
1265 Standard_Real dist, mindist=-1.;
1266 for (Standard_Integer i=1; i<=Proj.NbPoints(); i++)
1267 {
1268 dist = mpnt.Distance(Proj.Point(i));
1269 if (mindist>dist || mindist<0.)
1270 {
1271 index = i; mindist = dist;
1272 }
1273 ipnt2 = Proj.Point(index);
1274 u2 = Proj.Parameter(index);
1275 }
1276 }
1277 }
1278 else
1279 {
1280 if (cpnt1.Distance(ipnt2)<cpnt2.Distance(ipnt1)) u1 = ipar1;
1281 else u2 = ipar2;
1282 }
1283 // Ajust parameters on periodic curves
1284 u1 = AdjustOnPeriodic2d(pc1,reversed1,first1,last1,u1);
1285 u2 = AdjustOnPeriodic2d(pc2,!reversed2,first2,last2,u2);
1286 // Check points to satisfy distance criterium
1287 gp_Pnt2d p1 = pc1->Value(u1), p2 = pc2->Value(u2);
1288 if (p1.Distance(p2)<=gap &&
1289 Abs(cfirst1-u1) > ::Precision::PConfusion() &&
1290 Abs(clast2 -u2) > ::Precision::PConfusion() &&
1291 (((u1>first1) && (u1<last1)) || ((u2>first2) && (u2<last2)) ||
1292 (cpnt1.Distance(p1)<=gap) || (cpnt2.Distance(p2)<=gap)))
1293 {
1294 ipar1 = u1; ipar2 = u2;
1295 done1 = done2 = Standard_True;
1296 }
1297 }
1298
1299 if (done1)
1300 {
1301
1302 if (ipar1<first1 || ipar1>last1 || ipar2<first2 || ipar2>last2)
1303 {
1304
1305 // Check whether new points lie inside the surface bounds
1306 Standard_Real umin, umax, vmin, vmax;
1307 myAnalyzer->Surface()->Surface()->Bounds(umin,umax,vmin,vmax);
1308 if (::Precision::IsInfinite(umin) || ::Precision::IsInfinite(umax) ||
1309 ::Precision::IsInfinite(vmin) || ::Precision::IsInfinite(vmax))
1310 {
1311 Standard_Real fumin, fumax, fvmin, fvmax;
1312 BRepTools::UVBounds(face,fumin,fumax,fvmin,fvmax);
1313 if (::Precision::IsInfinite(umin)) umin = fumin-preci;
1314 if (::Precision::IsInfinite(umax)) umax = fumax+preci;
1315 if (::Precision::IsInfinite(vmin)) vmin = fvmin-preci;
1316 if (::Precision::IsInfinite(vmax)) vmax = fvmax+preci;
1317 }
1318
1319 gp_Pnt2d ipnt, P1, P2;
1320 Standard_Real u, v;
1321 Standard_Boolean out;
1322 // iterate on curves
1323 for (Standard_Integer j=1; j<=2; j++)
1324 {
1325
1326 if (j==1)
1327 {
1328 if (ipar1>=first1 && ipar1<=last1) continue;
1329 ipnt = pc1->Value(ipar1);
1330 }
1331 else
1332 {
1333 if (ipar2>=first2 && ipar2<=last2) continue;
1334 ipnt = pc2->Value(ipar2);
1335 }
1336
1337 // iterate on bounding lines
1338 for (Standard_Integer k=1; k<=2; k++)
1339 {
1340
1341 u = ipnt.X(); v = ipnt.Y();
1342
1343 out = Standard_True;
1344 if (k==1)
1345 {
1346 if (u<umin)
1347 {
1348 P1 = gp_Pnt2d(umin,vmin); P2 = gp_Pnt2d(umin,vmax);
1349 }
1350 else if (u>umax)
1351 {
1352 P1 = gp_Pnt2d(umax,vmin); P2 = gp_Pnt2d(umax,vmax);
1353 }
1354 else out = Standard_False;
1355 }
1356 else
1357 {
1358 if (v<vmin)
1359 {
1360 P1 = gp_Pnt2d(umin,vmin); P2 = gp_Pnt2d(umax,vmin);
1361 }
1362 else if (v>vmax)
1363 {
1364 P1 = gp_Pnt2d(umin,vmax); P2 = gp_Pnt2d(umax,vmax);
1365 }
1366 else out = Standard_False;
1367 }
1368
1369 if (out)
1370 {
1371 // Intersect pcurve with bounding line
1372 Handle(Geom2d_Line) lin = new Geom2d_Line(P1,gp_Dir2d(gp_Vec2d(P1,P2)));
1373 Geom2dAdaptor_Curve ACL(lin);
1374 IntRes2d_Domain dlin(P1,0.,tolint,P2,P1.Distance(P2),tolint);
1375
1376 Handle(Geom2d_Curve) pc;
1377 Standard_Real fpar, lpar;
1378 if (j==1)
1379 {
1380 if (cfirst1<ipar1)
1381 {
1382 fpar = cfirst1, lpar = ipar1;
1383 }
1384 else
1385 {
1386 fpar = ipar1, lpar = cfirst1;
1387 }
1388 pc = pc1;
1389 }
1390 else
1391 {
1392 if (clast2<ipar2)
1393 {
1394 fpar = clast2, lpar = ipar2;
1395 }
1396 else
1397 {
1398 fpar = ipar2, lpar = clast2;
1399 }
1400 pc = pc2;
1401 }
1402 Geom2dAdaptor_Curve ACC(pc);
1403 IntRes2d_Domain domc(pc->Value(fpar),fpar,tolint,
1404 pc->Value(lpar),lpar,tolint);
1405
1406 // Intersect line with the pcurve
1407 Inter.Perform( ACL, dlin, ACC, domc, tolint, tolint );
1408 if (Inter.IsDone())
1409 {
1410 if (Inter.NbPoints() || Inter.NbSegments())
1411 {
1412 Standard_Integer i, index = 1;
1413 Standard_Real uu, dist, mindist=-1.;
1414 // iterate on intersection points
1415 for ( i=1; i<=Inter.NbPoints(); i++ )
1416 {
1417 // Adjust parameters on periodic curve
1418 uu = AdjustOnPeriodic2d(pc,(j==1? reversed1 : !reversed2),
1419 fpar,lpar,Inter.Point(i).ParamOnSecond());
1420 dist = Abs((j==1? cfirst1 : clast2)-uu);
1421 if (mindist>dist || mindist<0.)
1422 {
1423 index = i; mindist = dist;
1424 }
1425 }
1426 // iterate on intersection segments
1427 Standard_Integer flag = 0;
1428 IntRes2d_IntersectionPoint IP;
1429 IntRes2d_IntersectionSegment IS;
1430 for ( i=1; i<=Inter.NbSegments(); i++ )
1431 {
1432 IS = Inter.Segment(i);
1433 for (Standard_Integer jj=1; jj<=2; jj++)
1434 {
1435 if ((jj==1 && IS.HasFirstPoint()) ||
1436 (jj==2 && IS.HasLastPoint()))
1437 {
1438 if (jj==1) IP = IS.FirstPoint();
1439 else IP = IS.LastPoint();
1440 // Adjust parameters on periodic curve
1441 uu = AdjustOnPeriodic2d(pc,(jj==1? reversed1 : !reversed2),
1442 fpar,lpar,IP.ParamOnSecond());
1443 dist = Abs((jj==1? cfirst1 : clast2)-uu);
1444 if (mindist>dist || mindist<0.)
1445 {
1446 flag = jj; index = i; mindist = dist;
1447 }
1448 }
1449 }
1450 }
1451 if (flag==0) IP = Inter.Point(index);
1452 else
1453 {
1454 IS = Inter.Segment(index);
1455 if (flag==1) IP = IS.FirstPoint();
1456 else IP = IS.LastPoint();
1457 }
1458 // Ajust parameters on periodic curve
1459 uu = AdjustOnPeriodic2d(pc,(j==1? reversed1 : !reversed2),
1460 fpar,lpar,IP.ParamOnSecond());
1461 if (j==1 && Abs(cfirst1-uu) > ::Precision::PConfusion())
1462 {
1463 ipar1 = uu; ipnt = IP.Value();
1464 }
1465 if (j==2 && Abs(clast2-uu) > ::Precision::PConfusion())
1466 {
1467 ipar2 = uu; ipnt = IP.Value();
1468 }
1469 }
1470 }
1471 }
1472 }
1473
1474 // Adjust if intersection lies inside old bounds
1475 if (j==1)
1476 {
1477 if (reversed1)
1478 {
1479 if (ipar1>first1) ipar1 = first1;
1480 }
1481 else
1482 {
1483 if (ipar1<last1) ipar1 = last1;
1484 }
1485 }
1486 else
1487 {
1488 if (reversed2)
1489 {
1490 if (ipar2<last2) ipar2 = last2;
1491 }
1492 else
1493 {
1494 if (ipar2>first2) ipar2 = first2;
1495 }
1496 }
1497 }
1498 }
1499 }
1500 try
1501 {
1502 OCC_CATCH_SIGNALS
1503 if (done1)
1504 {
1505 if (ipar1==clast1) done1 = Standard_False;
1506 else
1507 {
1508 // Set up new bounds for pcurve
1509 if (reversed1) first1 = ipar1; else last1 = ipar1;
1510 // Set new trim for old pcurve
1511 if (trimmed1) pc1 = new Geom2d_TrimmedCurve(pc1,first1,last1);
1512 }
1513 }
1514 if (done2)
1515 {
1516 if (ipar2==cfirst2) done2 = Standard_False;
1517 else
1518 {
1519 // Set up new bounds for pcurve
1520 if (reversed2) last2 = ipar2; else first2 = ipar2;
1521 // Set new trim for old pcurve
1522 if (trimmed2) pc2 = new Geom2d_TrimmedCurve(pc2,first2,last2);
1523 }
1524 }
1525 }
1526 catch (Standard_Failure)
1527 {
1528
0797d9d3 1529#ifdef OCCT_DEBUG
7fd59977 1530 cout << "Warning: ShapeFix_Wire_1::FixGap2d: Exception in TrimmedCurve2d :"<<endl;
1531 Standard_Failure::Caught()->Print(cout); cout << endl;
1532#endif
1533 }
1534 }
1535 }
1536
1537 if (done1 || done2)
1538 {
1539
1540 BRep_Builder B;
1541 ShapeBuild_Edge SBE;
1542 ShapeFix_ShapeTolerance SFST;
1543
1544 // Update vertices
1545 TopoDS_Vertex V1 = SAE.LastVertex(E1), V2 = SAE.FirstVertex(E2);
1546 TopoDS_Vertex nullV, newV1;
1547//smh#8
1548 TopoDS_Shape emptyCopiedV2 = V2.EmptyCopied();
1549 TopoDS_Vertex newV2 = TopoDS::Vertex(emptyCopiedV2);
1550 SFST.SetTolerance(newV2,::Precision::Confusion());
1551 Context()->Replace(V2,newV2);
1552 if (V1.IsSame(V2))
1553//smh#8
1554 {
1555 TopoDS_Shape tmpVertexRev = newV2.Oriented(TopAbs_REVERSED);
1556 newV1 = TopoDS::Vertex(tmpVertexRev);
1557 }
1558 else
1559 {
1560//smh#8
1561 TopoDS_Shape emptyCopiedV1 = V1.EmptyCopied();
1562 newV1 = TopoDS::Vertex(emptyCopiedV1);
1563 SFST.SetTolerance(newV1,::Precision::Confusion());
1564 Context()->Replace(V1,newV1);
1565 }
1566
1567 if (done1)
1568 {
1569 // Update first edge
1570 TopoDS_Edge newE1 = SBE.CopyReplaceVertices(E1,nullV,newV1);
1571//smh#8
1572 TopoDS_Shape tmpE1 = newE1.Oriented(TopAbs_FORWARD);
1573 B.UpdateEdge(TopoDS::Edge(tmpE1),pc1,face,0.);
1574 B.Range(TopoDS::Edge(tmpE1),face,first1,last1);
1575 SFST.SetTolerance(newE1,::Precision::Confusion(),TopAbs_EDGE);
1576 B.SameRange(newE1,Standard_False);
1577// B.SameParameter(newE1,Standard_False);
1578
1579 //To keep NM vertices belonging initial edges
1580 TopoDS_Iterator aItv(E1,Standard_False);
1581 for( ; aItv.More(); aItv.Next()) {
1582 if(aItv.Value().Orientation() == TopAbs_INTERNAL ||
1583 aItv.Value().Orientation() == TopAbs_EXTERNAL) {
1584 TopoDS_Vertex aOldV = TopoDS::Vertex(aItv.Value());
1585 TopoDS_Vertex anewV = ShapeAnalysis_TransferParametersProj::CopyNMVertex(aOldV,newE1,E1);
1586 B.Add(newE1,anewV);
1587 Context()->Replace(aOldV,anewV);
1588 }
1589 }
1590
1591 Context()->Replace(E1,newE1);
1592 sbwd->Set(newE1,n1);
1593 }
1594
1595 if (done2)
1596 {
1597 // Update second edge
1598 TopoDS_Edge newE2 = SBE.CopyReplaceVertices(E2,newV2,nullV);
1599//smh#8
1600 TopoDS_Shape tmpE2 = newE2.Oriented(TopAbs_FORWARD);
1601 B.UpdateEdge(TopoDS::Edge(tmpE2),pc2,face,0.);
1602 B.Range(TopoDS::Edge(tmpE2),face,first2,last2);
1603 SFST.SetTolerance(newE2,::Precision::Confusion(),TopAbs_EDGE);
1604 B.SameRange(newE2,Standard_False);
1605// B.SameParameter(newE2,Standard_False);
1606 //To keep NM vertices belonging initial edges
1607 TopoDS_Iterator aItv(E2,Standard_False);
1608 for( ; aItv.More(); aItv.Next()) {
1609 if(aItv.Value().Orientation() == TopAbs_INTERNAL ||
1610 aItv.Value().Orientation() == TopAbs_EXTERNAL) {
1611 TopoDS_Vertex aOldV = TopoDS::Vertex(aItv.Value());
1612 TopoDS_Vertex anewV = ShapeAnalysis_TransferParametersProj::CopyNMVertex(aOldV,newE2,E2);
1613 B.Add(newE2,anewV);
1614 Context()->Replace(aOldV,anewV);
1615 }
1616 }
1617 Context()->Replace(E2,newE2);
1618 sbwd->Set(newE2,n2);
1619 }
1620
1621 myLastFixStatus |= ShapeExtend::EncodeStatus( ShapeExtend_DONE1 );
1622 }
1623 else
1624 if (convert)
1625 myLastFixStatus |= ShapeExtend::EncodeStatus( ShapeExtend_FAIL2 );
1626
1627 return (done1 || done2);
1628}