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