0028385: Improve drawing isolines (DBRep_IsoBuilder algorithm)
[occt.git] / src / DBRep / DBRep_IsoBuilder.cxx
CommitLineData
b311480e 1// Created on: 1994-03-25
2// Created by: Jean Marc LACHAUME
3// Copyright (c) 1994-1999 Matra Datavision
973c2be1 4// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 5//
973c2be1 6// This file is part of Open CASCADE Technology software library.
b311480e 7//
d5f74e42 8// This library is free software; you can redistribute it and/or modify it under
9// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 10// by the Free Software Foundation, with special exception defined in the file
11// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12// distribution for complete text of the license and disclaimer of any warranty.
b311480e 13//
973c2be1 14// Alternatively, this file may be used under the terms of Open CASCADE
15// commercial license or contractual agreement.
7fd59977 16
7fd59977 17
7fd59977 18#include <BRep_Tool.hxx>
b6cf8ffa 19#include <BRepAdaptor_Surface.hxx>
42cf5bc1 20#include <BRepTools.hxx>
b6cf8ffa 21#include <BRepTools_WireExplorer.hxx>
42cf5bc1 22#include <DBRep_Face.hxx>
23#include <DBRep_IsoBuilder.hxx>
7fd59977 24#include <Geom2d_Curve.hxx>
25#include <Geom2d_Line.hxx>
26#include <Geom2d_TrimmedCurve.hxx>
42cf5bc1 27#include <Geom2dAdaptor_Curve.hxx>
28#include <Geom2dHatch_Intersector.hxx>
29#include <gp_Dir2d.hxx>
30#include <gp_Pnt2d.hxx>
7fd59977 31#include <HatchGen_Domain.hxx>
32#include <Precision.hxx>
33#include <TopAbs_ShapeEnum.hxx>
b6cf8ffa 34#include <TopExp.hxx>
7fd59977 35#include <TopExp_Explorer.hxx>
36#include <TopoDS.hxx>
37#include <TopoDS_Edge.hxx>
42cf5bc1 38#include <TopoDS_Face.hxx>
b6cf8ffa 39#include <TopoDS_Wire.hxx>
7fd59977 40
b6cf8ffa 41#include <NCollection_IndexedDataMap.hxx>
42#include <TopTools_OrientedShapeMapHasher.hxx>
43
44// Providing consistency with intersection tolerance for the linear curves
45static Standard_Real IntersectorConfusion = Precision::PConfusion();
46static Standard_Real IntersectorTangency = Precision::PConfusion();
7fd59977 47static Standard_Real HatcherConfusion2d = 1.e-8 ;
48static Standard_Real HatcherConfusion3d = 1.e-8 ;
49
50//=======================================================================
51// Function : DBRep_IsoBuilder
52// Purpose : Constructeur.
53//=======================================================================
54
55DBRep_IsoBuilder::DBRep_IsoBuilder (const TopoDS_Face& TopologicalFace,
ecc4f148 56 const Standard_Real Infinite,
57 const Standard_Integer NbIsos) :
58Geom2dHatch_Hatcher (Geom2dHatch_Intersector (IntersectorConfusion,
59 IntersectorTangency),
60 HatcherConfusion2d,
61 HatcherConfusion3d,
62 Standard_True,
63 Standard_False) ,
64 myInfinite (Infinite) ,
65 myUMin (0.0) ,
66 myUMax (0.0) ,
67 myVMin (0.0) ,
68 myVMax (0.0) ,
69 myUPrm (1, NbIsos) ,
70 myUInd (1, NbIsos) ,
71 myVPrm (1, NbIsos) ,
72 myVInd (1, NbIsos) ,
73 myNbDom (0)
7fd59977 74{
75 myUInd.Init(0);
76 myVInd.Init(0);
77
ecc4f148 78 //-----------------------------------------------------------------------
79 // If the Min Max bounds are infinite, there are bounded to Infinite
80 // value.
81 //-----------------------------------------------------------------------
7fd59977 82
83 BRepTools::UVBounds (TopologicalFace, myUMin, myUMax, myVMin, myVMax) ;
84 Standard_Boolean InfiniteUMin = Precision::IsNegativeInfinite (myUMin) ;
85 Standard_Boolean InfiniteUMax = Precision::IsPositiveInfinite (myUMax) ;
86 Standard_Boolean InfiniteVMin = Precision::IsNegativeInfinite (myVMin) ;
87 Standard_Boolean InfiniteVMax = Precision::IsPositiveInfinite (myVMax) ;
88 if (InfiniteUMin && InfiniteUMax) {
89 myUMin = - Infinite ;
90 myUMax = Infinite ;
91 } else if (InfiniteUMin) {
92 myUMin = myUMax - Infinite ;
93 } else if (InfiniteUMax) {
94 myUMax = myUMin + Infinite ;
95 }
96 if (InfiniteVMin && InfiniteVMax) {
97 myVMin = - Infinite ;
98 myVMax = Infinite ;
99 } else if (InfiniteVMin) {
100 myVMin = myVMax - Infinite ;
101 } else if (InfiniteVMax) {
102 myVMax = myVMin + Infinite ;
103 }
104
ecc4f148 105 //-----------------------------------------------------------------------
b6cf8ffa 106 // Retrieving the edges and its p-curves for further trimming
107 // and loading them into the hatcher
ecc4f148 108 //-----------------------------------------------------------------------
b6cf8ffa 109 DataMapOfEdgePCurve anEdgePCurveMap;
7fd59977 110
ffe74e46
K
111 TopExp_Explorer ExpEdges;
112 for (ExpEdges.Init (TopologicalFace, TopAbs_EDGE); ExpEdges.More(); ExpEdges.Next())
113 {
114 const TopoDS_Edge& TopologicalEdge = TopoDS::Edge (ExpEdges.Current());
115 Standard_Real U1, U2;
116 const Handle(Geom2d_Curve) PCurve = BRep_Tool::CurveOnSurface (TopologicalEdge, TopologicalFace, U1, U2);
117
118 if (PCurve.IsNull())
119 {
0797d9d3 120#ifdef OCCT_DEBUG
ffe74e46 121 cout << "DBRep_IsoBuilder : PCurve is null\n";
ecc4f148 122#endif
7fd59977 123 return;
124 }
ffe74e46
K
125 else if (U1 == U2)
126 {
0797d9d3 127#ifdef OCCT_DEBUG
ffe74e46 128 cout << "DBRep_IsoBuilder PCurve : U1==U2\n";
ecc4f148 129#endif
7fd59977 130 return;
131 }
132
133 //-- Test if a TrimmedCurve is necessary
ffe74e46 134 if (Abs(PCurve->FirstParameter()-U1)<= Precision::PConfusion()
ecc4f148 135 && Abs(PCurve->LastParameter()-U2)<= Precision::PConfusion())
ffe74e46 136 {
b6cf8ffa 137 anEdgePCurveMap.Add(TopologicalEdge, PCurve);
7fd59977 138 }
ffe74e46
K
139 else
140 {
141 if (!PCurve->IsPeriodic())
142 {
143 Handle (Geom2d_TrimmedCurve) TrimPCurve = Handle(Geom2d_TrimmedCurve)::DownCast (PCurve);
144 if (!TrimPCurve.IsNull())
145 {
146 if (TrimPCurve->BasisCurve()->FirstParameter() - U1 > Precision::PConfusion() ||
ecc4f148 147 TrimPCurve->BasisCurve()->FirstParameter() - U2 > Precision::PConfusion() ||
148 U1 - TrimPCurve->BasisCurve()->LastParameter() > Precision::PConfusion() ||
149 U2 - TrimPCurve->BasisCurve()->LastParameter() > Precision::PConfusion())
ffe74e46 150 {
0797d9d3 151#ifdef OCCT_DEBUG
ffe74e46
K
152 cout << "DBRep_IsoBuilder TrimPCurve : parameters out of range\n";
153 cout << " U1(" << U1 << "), Umin(" << PCurve->FirstParameter()
ecc4f148 154 << "), U2(" << U2 << "), Umax(" << PCurve->LastParameter() << ")\n";
155#endif
ffe74e46
K
156 return;
157 }
158 }
159 else
160 {
161 if (PCurve->FirstParameter() - U1 > Precision::PConfusion())
162 {
0797d9d3 163#ifdef OCCT_DEBUG
ffe74e46
K
164 cout << "DBRep_IsoBuilder PCurve : parameters out of range\n";
165 cout << " U1(" << U1 << "), Umin(" << PCurve->FirstParameter() << ")\n";
ecc4f148 166#endif
ffe74e46
K
167 U1 = PCurve->FirstParameter();
168 }
169 if (PCurve->FirstParameter() - U2 > Precision::PConfusion())
170 {
0797d9d3 171#ifdef OCCT_DEBUG
ffe74e46
K
172 cout << "DBRep_IsoBuilder PCurve : parameters out of range\n";
173 cout << " U2(" << U2 << "), Umin(" << PCurve->FirstParameter() << ")\n";
ecc4f148 174#endif
ffe74e46
K
175 U2 = PCurve->FirstParameter();
176 }
177 if (U1 - PCurve->LastParameter() > Precision::PConfusion())
178 {
0797d9d3 179#ifdef OCCT_DEBUG
ffe74e46
K
180 cout << "DBRep_IsoBuilder PCurve : parameters out of range\n";
181 cout << " U1(" << U1 << "), Umax(" << PCurve->LastParameter() << ")\n";
ecc4f148 182#endif
ffe74e46
K
183 U1 = PCurve->LastParameter();
184 }
185 if (U2 - PCurve->LastParameter() > Precision::PConfusion())
186 {
0797d9d3 187#ifdef OCCT_DEBUG
ffe74e46
K
188 cout << "DBRep_IsoBuilder PCurve : parameters out of range\n";
189 cout << " U2(" << U2 << "), Umax(" << PCurve->LastParameter() << ")\n";
ecc4f148 190#endif
ffe74e46
K
191 U2 = PCurve->LastParameter();
192 }
193 }
7fd59977 194 }
ffe74e46
K
195
196 // if U1 and U2 coincide-->do nothing
197 if (Abs (U1 - U2) <= Precision::PConfusion()) continue;
198 Handle (Geom2d_TrimmedCurve) TrimPCurve = new Geom2d_TrimmedCurve (PCurve, U1, U2);
b6cf8ffa 199 anEdgePCurveMap.Add(TopologicalEdge, TrimPCurve);
7fd59977 200 }
201 }
202
b6cf8ffa 203 // Fill the gaps between 2D curves, and trim the intersecting ones.
204 FillGaps(TopologicalFace, anEdgePCurveMap);
205
206 // Load trimmed curves to the hatcher
207 Standard_Integer aNbE = anEdgePCurveMap.Extent();
208 for (Standard_Integer iE = 1; iE <= aNbE; ++iE)
209 {
210 AddElement(Geom2dAdaptor_Curve(anEdgePCurveMap(iE)),
211 anEdgePCurveMap.FindKey(iE).Orientation());
212 }
ecc4f148 213 //-----------------------------------------------------------------------
214 // Loading and trimming the hatchings.
215 //-----------------------------------------------------------------------
7fd59977 216
217 Standard_Integer IIso ;
218 Standard_Real DeltaU = Abs (myUMax - myUMin) ;
219 Standard_Real DeltaV = Abs (myVMax - myVMin) ;
220 Standard_Real confusion = Min (DeltaU, DeltaV) * HatcherConfusion3d ;
221 Confusion3d (confusion) ;
222
223 Standard_Real StepU = DeltaU / (Standard_Real) NbIsos ;
224 if (StepU > confusion) {
225 Standard_Real UPrm = myUMin + StepU / 2. ;
226 gp_Dir2d Dir (0., 1.) ;
227 for (IIso = 1 ; IIso <= NbIsos ; IIso++) {
228 myUPrm(IIso) = UPrm ;
229 gp_Pnt2d Ori (UPrm, 0.) ;
230 Geom2dAdaptor_Curve HCur (new Geom2d_Line (Ori, Dir)) ;
231 myUInd(IIso) = AddHatching (HCur) ;
232 UPrm += StepU ;
233 }
234 }
235
236 Standard_Real StepV = DeltaV / (Standard_Real) NbIsos ;
237 if (StepV > confusion) {
238 Standard_Real VPrm = myVMin + StepV / 2. ;
239 gp_Dir2d Dir (1., 0.) ;
240 for (IIso = 1 ; IIso <= NbIsos ; IIso++) {
241 myVPrm(IIso) = VPrm ;
242 gp_Pnt2d Ori (0., VPrm) ;
243 Geom2dAdaptor_Curve HCur (new Geom2d_Line (Ori, Dir)) ;
244 myVInd(IIso) = AddHatching (HCur) ;
245 VPrm += StepV ;
246 }
247 }
248
ecc4f148 249 //-----------------------------------------------------------------------
250 // Computation.
251 //-----------------------------------------------------------------------
7fd59977 252
253 Trim() ;
254
255 myNbDom = 0 ;
ecc4f148 256 for (IIso = 1 ; IIso <= NbIsos ; IIso++)
257 {
7fd59977 258 Standard_Integer Index ;
259
260 Index = myUInd(IIso) ;
ecc4f148 261 if (Index != 0)
262 {
263 if (TrimDone (Index) && !TrimFailed (Index))
264 {
265 ComputeDomains (Index);
266 if (IsDone (Index))
267 myNbDom = myNbDom + Geom2dHatch_Hatcher::NbDomains (Index) ;
7fd59977 268 }
269 }
270
271 Index = myVInd(IIso) ;
ecc4f148 272 if (Index != 0)
273 {
274 if (TrimDone (Index) && !TrimFailed (Index))
275 {
276 ComputeDomains (Index);
277 if (IsDone (Index))
278 myNbDom = myNbDom + Geom2dHatch_Hatcher::NbDomains (Index) ;
7fd59977 279 }
280 }
281 }
282}
283
284//=======================================================================
285// Function : LoadIsos
286// Purpose : Loading of the isoparametric curves in the Data Structure
287// of a drawable face.
288//=======================================================================
289
290void DBRep_IsoBuilder::LoadIsos (const Handle(DBRep_Face)& Face) const
291{
292 Standard_Integer NumIso = 0 ;
293
294 for (Standard_Integer UIso = myUPrm.Lower() ; UIso <= myUPrm.Upper() ; UIso++) {
295 Standard_Integer UInd = myUInd.Value (UIso) ;
296 if (UInd != 0) {
297 Standard_Real UPrm = myUPrm.Value (UIso) ;
298 if (!IsDone (UInd)) {
299 cout << "DBRep_IsoBuilder:: U iso of parameter: " << UPrm ;
300 switch (Status (UInd)) {
301 case HatchGen_NoProblem : cout << " No Problem" << endl ; break ;
302 case HatchGen_TrimFailure : cout << " Trim Failure" << endl ; break ;
303 case HatchGen_TransitionFailure : cout << " Transition Failure" << endl ; break ;
304 case HatchGen_IncoherentParity : cout << " Incoherent Parity" << endl ; break ;
305 case HatchGen_IncompatibleStates : cout << " Incompatible States" << endl ; break ;
306 }
307 } else {
308 Standard_Integer NbDom = Geom2dHatch_Hatcher::NbDomains (UInd) ;
309 for (Standard_Integer IDom = 1 ; IDom <= NbDom ; IDom++) {
310 const HatchGen_Domain& Dom = Domain (UInd, IDom) ;
311 Standard_Real V1 = Dom.HasFirstPoint() ? Dom.FirstPoint().Parameter() : myVMin - myInfinite ;
312 Standard_Real V2 = Dom.HasSecondPoint() ? Dom.SecondPoint().Parameter() : myVMax + myInfinite ;
313 NumIso++ ;
314 Face->Iso (NumIso, GeomAbs_IsoU, UPrm, V1, V2) ;
315 }
316 }
317 }
318 }
319
320 for (Standard_Integer VIso = myVPrm.Lower() ; VIso <= myVPrm.Upper() ; VIso++) {
321 Standard_Integer VInd = myVInd.Value (VIso) ;
322 if (VInd != 0) {
323 Standard_Real VPrm = myVPrm.Value (VIso) ;
324 if (!IsDone (VInd)) {
325 cout << "DBRep_IsoBuilder:: V iso of parameter: " << VPrm ;
326 switch (Status (VInd)) {
327 case HatchGen_NoProblem : cout << " No Problem" << endl ; break ;
328 case HatchGen_TrimFailure : cout << " Trim Failure" << endl ; break ;
329 case HatchGen_TransitionFailure : cout << " Transition Failure" << endl ; break ;
330 case HatchGen_IncoherentParity : cout << " Incoherent Parity" << endl ; break ;
331 case HatchGen_IncompatibleStates : cout << " Incompatible States" << endl ; break ;
332 }
333 } else {
334 Standard_Integer NbDom = Geom2dHatch_Hatcher::NbDomains (VInd) ;
335 for (Standard_Integer IDom = 1 ; IDom <= NbDom ; IDom++) {
336 const HatchGen_Domain& Dom = Domain (VInd, IDom) ;
337 Standard_Real U1 = Dom.HasFirstPoint() ? Dom.FirstPoint().Parameter() : myVMin - myInfinite ;
338 Standard_Real U2 = Dom.HasSecondPoint() ? Dom.SecondPoint().Parameter() : myVMax + myInfinite ;
339 NumIso++ ;
340 Face->Iso (NumIso, GeomAbs_IsoV, VPrm, U1, U2) ;
341 }
342 }
343 }
344 }
345}
b6cf8ffa 346
347//=======================================================================
348// Function : FillGaps
349// Purpose :
350//=======================================================================
351void DBRep_IsoBuilder::FillGaps(const TopoDS_Face& theFace,
352 DataMapOfEdgePCurve& theEdgePCurveMap)
353{
354
355 // Get surface of the face for getting the 3D points from 2D coordinates
356 // of the p-curves bounds
357 BRepAdaptor_Surface aBASurf(theFace, Standard_False);
358
359 // Analyze each wire of the face separately
360 TopoDS_Iterator aItW(theFace);
361 for (; aItW.More(); aItW.Next())
362 {
363 const TopoDS_Shape& aW = aItW.Value();
364 if (aW.ShapeType() != TopAbs_WIRE)
365 continue;
366
367 // Use WireExplorer to iterate on edges of the wire
368 // to get the pairs of connected edges.
369 // Using WireExplorer will also allow avoiding treatment
370 // of the internal wires.
371 BRepTools_WireExplorer aWExp;
372 aWExp.Init(TopoDS::Wire(aW), theFace, myUMin, myUMax, myVMin, myVMax);
373 if (!aWExp.More())
374 continue;
375
376 // Check the number of edges in the wire, not to
377 // miss the wires containing one edge only
378 Standard_Boolean SingleEdge = Standard_True;
379 {
380 TopoDS_Iterator itE(aW);
381 if (!itE.More())
382 continue;
383 itE.Next();
384 SingleEdge = !itE.More();
385 }
386
387 TopoDS_Edge aPrevEdge, aCurrEdge;
388
389 // Get first edge and its p-curve
390 aCurrEdge = aWExp.Current();
391
392 // Ensure analysis of the pair of first and last edges
393 TopoDS_Edge aFirstEdge = aCurrEdge;
394 Standard_Real bStop = Standard_False;
395
396 // Iterate on all other edges
397 while (!bStop)
398 {
399 // Iteration to the next edge
400 aPrevEdge = aCurrEdge;
401 aWExp.Next();
402 // Get the current edge for analysis
403 if (aWExp.More())
404 {
405 aCurrEdge = aWExp.Current();
406 }
407 else
408 {
409 aCurrEdge = aFirstEdge;
410 bStop = Standard_True;
411 }
412
413 if (aPrevEdge.IsEqual(aCurrEdge) && !SingleEdge)
414 continue;
415
416 // Get p-curves
417 Handle(Geom2d_Curve)* pPC1 = theEdgePCurveMap.ChangeSeek(aPrevEdge);
418 Handle(Geom2d_Curve)* pPC2 = theEdgePCurveMap.ChangeSeek(aCurrEdge);
419 if (!pPC1 || !pPC2)
420 continue;
421
422 Handle(Geom2d_Curve)& aPrevC2d = *pPC1;
423 Handle(Geom2d_Curve)& aCurrC2d = *pPC2;
424
425 // Get p-curves parameters
426 Standard_Real fp, lp, fc, lc;
427 fp = aPrevC2d->FirstParameter();
428 lp = aPrevC2d->LastParameter();
429 fc = aCurrC2d->FirstParameter();
430 lc = aCurrC2d->LastParameter();
431
432 // Get common vertex to check if the gap between two edges is closed
433 // by the tolerance value of this vertex.
434 // Take into account the orientation of the edges to obtain the correct
435 // parameter of the vertex on edges.
436
437 // Get vertex on the previous edge
438 TopoDS_Vertex aCVOnPrev = TopExp::LastVertex(aPrevEdge, Standard_True);
439 if (aCVOnPrev.IsNull())
440 continue;
441
442 // Get parameter of the vertex on the previous edge
443 Standard_Real aTPrev = BRep_Tool::Parameter(aCVOnPrev, aPrevEdge);
444 if (aTPrev < fp)
445 aTPrev = fp;
446 else if (aTPrev > lp)
447 aTPrev = lp;
448
449 // Get vertex on the current edge
450 TopoDS_Vertex aCVOnCurr = TopExp::FirstVertex(aCurrEdge, Standard_True);
451 if (aCVOnCurr.IsNull() || !aCVOnPrev.IsSame(aCVOnCurr))
452 continue;
453
454 // Get parameter of the vertex on the current edge
455 Standard_Real aTCurr = BRep_Tool::Parameter(aCVOnCurr, aCurrEdge);
456 if (aTCurr < fc)
457 aTCurr = fc;
458 else if (aTCurr > lc)
459 aTCurr = lc;
460
461 // Get bounding points on the edges corresponding to the current vertex
462 gp_Pnt2d aPrevP2d = aPrevC2d->Value(aTPrev),
463 aCurrP2d = aCurrC2d->Value(aTCurr);
464
465 // Check if the vertex covers these bounding points by its tolerance
466 Standard_Real aTolV2 = BRep_Tool::Tolerance(aCVOnPrev);
467 gp_Pnt aPV = BRep_Tool::Pnt(aCVOnPrev);
468 // There is no need to check the distance if the tolerance
469 // of vertex is infinite (like in the test case sewing/tol_1/R2)
470 if (aTolV2 < Precision::Infinite())
471 {
472 aTolV2 *= aTolV2;
473
474 // Convert bounding point on previous edge into 3D
475 gp_Pnt aPrevPS = aBASurf.Value(aPrevP2d.X(), aPrevP2d.Y());
476
477 // Check if the vertex closes the gap
478 if (aPV.SquareDistance(aPrevPS) > aTolV2)
479 continue;
480
481 // Convert bounding point on current edge into 3D
482 gp_Pnt aCurrPS = aBASurf.Value(aCurrP2d.X(), aCurrP2d.Y());
483
484 // Check if the vertex closes the gap
485 if (aPV.SquareDistance(aCurrPS) > aTolV2)
486 continue;
487 }
488
489 // Create the segment
490 gp_Vec2d aV2d(aPrevP2d, aCurrP2d);
491 Standard_Real aSegmLen = aV2d.Magnitude();
492 // Do not add too small segments
493 Standard_Boolean bAddSegment = (aSegmLen > Precision::PConfusion());
494 // Check for periodic surfaces
495 if (bAddSegment)
496 {
497 if (aBASurf.IsUPeriodic())
498 bAddSegment = aSegmLen < aBASurf.UPeriod() / 4.;
499
500 if (bAddSegment && aBASurf.IsVPeriodic())
501 bAddSegment = aSegmLen < aBASurf.VPeriod() / 4.;
502 }
503
504 // Check that p-curves do not interfere near the vertex.
505 // And, if they do interfere, avoid creation of the segment.
506 if (bAddSegment && !aPrevEdge.IsEqual(aCurrEdge))
507 {
508 Geom2dAdaptor_Curve aPrevGC(aPrevC2d, fp, lp), aCurrGC(aCurrC2d, fc, lc);
509 Geom2dInt_GInter anInter(aPrevGC, aCurrGC, Precision::PConfusion(), Precision::PConfusion());
510 if (anInter.IsDone() && !anInter.IsEmpty())
511 {
512 // Collect intersection points
513 NCollection_List<IntRes2d_IntersectionPoint> aLPInt;
514 // Get bounding points from segments
515 Standard_Integer iP, aNbInt = anInter.NbSegments();
516 for (iP = 1; iP <= aNbInt; ++iP)
517 {
518 aLPInt.Append(anInter.Segment(iP).FirstPoint());
519 aLPInt.Append(anInter.Segment(iP).LastPoint());
520 }
521 // Get intersection points
522 aNbInt = anInter.NbPoints();
523 for (iP = 1; iP <= aNbInt; ++iP)
524 aLPInt.Append(anInter.Point(iP));
525
526 // Analyze the points and find the one closest to the current vertex
527 Standard_Boolean bPointFound = Standard_False;
528 Standard_Real aTPrevClosest = 0., aTCurrClosest = 0.;
529 Standard_Real aDeltaPrev = ::RealLast(), aDeltaCurr = ::RealLast();
530
531 NCollection_List<IntRes2d_IntersectionPoint>::Iterator aItLPInt(aLPInt);
532 for (; aItLPInt.More(); aItLPInt.Next())
533 {
534 const IntRes2d_IntersectionPoint& aPnt = aItLPInt.Value();
535 const Standard_Real aTIntPrev = aPnt.ParamOnFirst();
536 const Standard_Real aTIntCurr = aPnt.ParamOnSecond();
537 // Check if the intersection point is in range
538 if (aTIntPrev < fp || aTIntPrev > lp ||
539 aTIntCurr < fc || aTIntCurr > lc)
540 {
541 continue;
542 }
543
544 Standard_Real aDelta1 = Abs(aTIntPrev - aTPrev);
545 Standard_Real aDelta2 = Abs(aTIntCurr - aTCurr);
546 if (aDelta1 < aDeltaPrev || aDelta2 < aDeltaCurr)
547 {
548 aTPrevClosest = aTIntPrev;
549 aTCurrClosest = aTIntCurr;
550 aDeltaPrev = aDelta1;
551 aDeltaCurr = aDelta2;
552 bPointFound = Standard_True;
553 }
554 }
555
556 if (bPointFound)
557 {
558 // Check the number of common vertices between edges.
559 // If on the other end, there is also a common vertex,
560 // check where the intersection point is located. It might
561 // be closer to the other vertex than to the current one.
562 // And here we just need to close the gap, avoiding the trimming.
563 // If the common vertex is only one, do not create the segment,
564 // as we have the intersection of the edges and trimmed the 2d curves.
565 Standard_Integer aNbCV = 0;
566 for (TopoDS_Iterator it1(aPrevEdge); it1.More(); it1.Next())
567 {
568 for (TopoDS_Iterator it2(aCurrEdge); it2.More(); it2.Next())
569 {
570 if (it1.Value().IsSame(it2.Value()))
571 ++aNbCV;
572 }
573 }
574
575 // Trim PCurves only if the intersection belongs to current parameter
576 Standard_Boolean bTrim = (aNbCV == 1 ||
577 (Abs(aTPrev - aTPrevClosest) < (lp - fp) / 2. ||
578 Abs(aTCurr - aTCurrClosest) < (lc - fc) / 2.));
579
580 if (bTrim)
581 {
582 // Check that the intersection point is covered by vertex tolerance
583 gp_Pnt2d aPInt = aPrevC2d->Value(aTPrevClosest);
584 const gp_Pnt aPOnS = aBASurf.Value(aPInt.X(), aPInt.Y());
585 if (aTolV2 > Precision::Infinite() || aPOnS.SquareDistance(aPV) < aTolV2)
586 {
587 Standard_Real f, l;
588
589 // Trim the curves with found parameters
590
591 // Prepare trimming parameters for previous curve
592 if (Abs(fp - aTPrev) < Abs(lp - aTPrev))
593 {
594 f = aTPrevClosest;
595 l = lp;
596 }
597 else
598 {
599 f = fp;
600 l = aTPrevClosest;
601 }
602
603 // Trim previous p-curve
604 if (l - f > Precision::PConfusion())
605 aPrevC2d = new Geom2d_TrimmedCurve(aPrevC2d, f, l);
606
607 // Prepare trimming parameters for current p-curve
608 if (Abs(fc - aTCurr) < Abs(lc - aTCurr))
609 {
610 f = aTCurrClosest;
611 l = lc;
612 }
613 else
614 {
615 f = fc;
616 l = aTCurrClosest;
617 }
618
619 // Trim current p-curve
620 if (l - f > Precision::PConfusion())
621 aCurrC2d = new Geom2d_TrimmedCurve(aCurrC2d, f, l);
622
623 // Do not create the segment, as we performed the trimming
624 // to the intersection point.
625 bAddSegment = Standard_False;
626 }
627 }
628 }
629 }
630 }
631
632 if (bAddSegment)
633 {
634 // Add segment to the hatcher to trim the iso-lines
635 Handle(Geom2d_Line) aLine = new Geom2d_Line(aPrevP2d, aV2d);
636 Handle(Geom2d_TrimmedCurve) aLineSegm = new Geom2d_TrimmedCurve(aLine, 0.0, aSegmLen);
637 AddElement(Geom2dAdaptor_Curve(aLineSegm), TopAbs_FORWARD);
638 }
639 }
640 }
641}