0030686: Visualization, SelectMgr_ViewerSelector - sorting issues of transformation...
[occt.git] / src / StdPrs / StdPrs_Isolines.cxx
1 // Created on: 2014-10-14
2 // Created by: Anton POLETAEV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <StdPrs_Isolines.hxx>
17
18 #include <Adaptor3d_IsoCurve.hxx>
19 #include <BRepTools.hxx>
20 #include <BRep_Tool.hxx>
21 #include <GCPnts_AbscissaPoint.hxx>
22 #include <GCPnts_QuasiUniformDeflection.hxx>
23 #include <Geom_BezierSurface.hxx>
24 #include <Geom_BSplineSurface.hxx>
25 #include <Geom_Plane.hxx>
26 #include <Geom_Line.hxx>
27 #include <Geom2d_Line.hxx>
28 #include <Geom2dAdaptor_Curve.hxx>
29 #include <GeomAdaptor_Curve.hxx>
30 #include <GeomLib_Tool.hxx>
31 #include <gp_Lin2d.hxx>
32 #include <Hatch_Hatcher.hxx>
33 #include <NCollection_Shared.hxx>
34 #include <Prs3d.hxx>
35 #include <Prs3d_IsoAspect.hxx>
36 #include <Poly_Array1OfTriangle.hxx>
37 #include <Poly_Triangulation.hxx>
38 #include <StdPrs_DeflectionCurve.hxx>
39 #include <StdPrs_ToolRFace.hxx>
40 #include <TColgp_SequenceOfPnt2d.hxx>
41 #include <Standard_ErrorHandler.hxx>
42 #include <Geom_Surface.hxx>
43
44 #include <algorithm>
45
46 namespace
47 {
48   const gp_Lin2d isoU (const Standard_Real theU) { return gp_Lin2d (gp_Pnt2d (theU, 0.0), gp::DY2d()); }
49   const gp_Lin2d isoV (const Standard_Real theV) { return gp_Lin2d (gp_Pnt2d (0.0, theV), gp::DX2d()); }
50
51   typedef NCollection_Shared< NCollection_Vector<StdPrs_Isolines::SegOnIso> > VecOfSegments;
52   typedef NCollection_Sequence<Handle(VecOfSegments)> SeqOfVecOfSegments;
53
54   //! Pack isoline segments into polylines.
55   static void sortSegments (const SeqOfVecOfSegments&   theSegments,
56                             Prs3d_NListOfSequenceOfPnt& thePolylines)
57   {
58     for (SeqOfVecOfSegments::Iterator aLineIter (theSegments); aLineIter.More(); aLineIter.Next())
59     {
60       Handle(VecOfSegments)& anIsoSegs = aLineIter.ChangeValue();
61       std::stable_sort (anIsoSegs->begin(), anIsoSegs->end());
62
63       Handle(TColgp_HSequenceOfPnt) aPolyline = new TColgp_HSequenceOfPnt();
64       thePolylines.Append (aPolyline);
65       Standard_Real aLast = 0.0;
66       for (VecOfSegments::Iterator aSegIter (*anIsoSegs); aSegIter.More(); aSegIter.Next())
67       {
68         if (!aPolyline->IsEmpty()
69          && Abs (aSegIter.Value()[0].Param - aLast) > Precision::PConfusion())
70         {
71           aPolyline = new TColgp_HSequenceOfPnt();
72           thePolylines.Append (aPolyline);
73         }
74
75         aPolyline->Append (aSegIter.Value()[0].Pnt);
76         aPolyline->Append (aSegIter.Value()[1].Pnt);
77         aLast = aSegIter.Value()[1].Param;
78       }
79     }
80   }
81
82   //! Reoder and adjust to the limit a curve's parameter values.
83   //! @param theCurve [in] the curve.
84   //! @param theLimit [in] the parameter limit value.
85   //! @param theFirst [in/out] the first parameter value.
86   //! @param theLast  [in/out] the last parameter value.
87   static void findLimits (const Adaptor3d_Curve& theCurve,
88                           const Standard_Real    theLimit,
89                           Standard_Real&         theFirst,
90                           Standard_Real&         theLast)
91   {
92     theFirst = Max (theCurve.FirstParameter(), theFirst);
93     theLast  = Min (theCurve.LastParameter(), theLast);
94
95     Standard_Boolean isFirstInf = Precision::IsNegativeInfinite (theFirst);
96     Standard_Boolean isLastInf  = Precision::IsPositiveInfinite (theLast);
97
98     if (!isFirstInf && !isLastInf)
99     {
100       return;
101     }
102
103     gp_Pnt aP1, aP2;
104     Standard_Real aDelta = 1.0;
105     if (isFirstInf && isLastInf)
106     {
107       do
108       {
109         aDelta *= 2.0;
110         theFirst = -aDelta;
111         theLast  =  aDelta;
112         theCurve.D0 (theFirst, aP1);
113         theCurve.D0 (theLast,  aP2);
114       }
115       while (aP1.Distance (aP2) < theLimit);
116     }
117     else if (isFirstInf)
118     {
119       theCurve.D0 (theLast, aP2);
120       do
121       {
122         aDelta *= 2.0;
123         theFirst = theLast - aDelta;
124         theCurve.D0 (theFirst, aP1);
125       }
126       while (aP1.Distance (aP2) < theLimit);
127     }
128     else if (isLastInf)
129     {
130       theCurve.D0 (theFirst, aP1);
131       do
132       {
133         aDelta *= 2.0;
134         theLast = theFirst + aDelta;
135         theCurve.D0 (theLast, aP2);
136       }
137       while (aP1.Distance (aP2) < theLimit);
138     }
139   }
140
141 }
142
143 //==================================================================
144 // function : AddOnTriangulation
145 // purpose  :
146 //==================================================================
147 void StdPrs_Isolines::AddOnTriangulation (const Handle(Prs3d_Presentation)& thePresentation,
148                                           const TopoDS_Face&                theFace,
149                                           const Handle(Prs3d_Drawer)&       theDrawer)
150 {
151   Prs3d_NListOfSequenceOfPnt aUPolylines, aVPolylines;
152   AddOnTriangulation (theFace, theDrawer, aUPolylines, aVPolylines);
153   Prs3d::AddPrimitivesGroup (thePresentation, theDrawer->UIsoAspect(), aUPolylines);
154   Prs3d::AddPrimitivesGroup (thePresentation, theDrawer->VIsoAspect(), aVPolylines);
155 }
156
157 //==================================================================
158 // function : AddOnTriangulation
159 // purpose  :
160 //==================================================================
161 void StdPrs_Isolines::AddOnTriangulation (const TopoDS_Face&          theFace,
162                                           const Handle(Prs3d_Drawer)& theDrawer,
163                                           Prs3d_NListOfSequenceOfPnt& theUPolylines,
164                                           Prs3d_NListOfSequenceOfPnt& theVPolylines)
165 {
166   const Standard_Integer aNbIsoU = theDrawer->UIsoAspect()->Number();
167   const Standard_Integer aNbIsoV = theDrawer->VIsoAspect()->Number();
168   if (aNbIsoU < 1 && aNbIsoV < 1)
169   {
170     return;
171   }
172
173   // Evaluate parameters for uv isolines.
174   TColStd_SequenceOfReal aUIsoParams;
175   TColStd_SequenceOfReal aVIsoParams;
176   UVIsoParameters (theFace, aNbIsoU, aNbIsoV, theDrawer->MaximalParameterValue(), aUIsoParams, aVIsoParams);
177
178   // Access surface definition.
179   TopLoc_Location aLocSurface;
180   Handle(Geom_Surface) aSurface = BRep_Tool::Surface (theFace, aLocSurface);
181   if (aSurface.IsNull())
182   {
183     return;
184   }
185
186   // Access triangulation.
187   TopLoc_Location aLocTriangulation;
188   const Handle(Poly_Triangulation)& aTriangulation = BRep_Tool::Triangulation (theFace, aLocTriangulation);
189   if (aTriangulation.IsNull())
190   {
191     return;
192   }
193
194   // Setup equal location for surface and triangulation.
195   if (!aLocTriangulation.IsEqual (aLocSurface))
196   {
197     aSurface = Handle (Geom_Surface)::DownCast (
198       aSurface->Transformed ((aLocSurface / aLocTriangulation).Transformation()));
199   }
200
201   addOnTriangulation (aTriangulation, aSurface, aLocTriangulation, aUIsoParams, aVIsoParams, theUPolylines, theVPolylines);
202 }
203
204 //==================================================================
205 // function : AddOnTriangulation
206 // purpose  :
207 //==================================================================
208 void StdPrs_Isolines::AddOnTriangulation (const Handle(Prs3d_Presentation)& thePresentation,
209                                           const Handle(Poly_Triangulation)& theTriangulation,
210                                           const Handle(Geom_Surface)&       theSurface,
211                                           const TopLoc_Location&            theLocation,
212                                           const Handle(Prs3d_Drawer)&       theDrawer,
213                                           const TColStd_SequenceOfReal&     theUIsoParams,
214                                           const TColStd_SequenceOfReal&     theVIsoParams)
215 {
216   Prs3d_NListOfSequenceOfPnt aUPolylines, aVPolylines;
217   addOnTriangulation (theTriangulation, theSurface, theLocation, theUIsoParams, theVIsoParams, aUPolylines, aVPolylines);
218   Prs3d::AddPrimitivesGroup (thePresentation, theDrawer->UIsoAspect(), aUPolylines);
219   Prs3d::AddPrimitivesGroup (thePresentation, theDrawer->VIsoAspect(), aVPolylines);
220 }
221
222 //==================================================================
223 // function : addOnTriangulation
224 // purpose  :
225 //==================================================================
226 void StdPrs_Isolines::addOnTriangulation (const Handle(Poly_Triangulation)& theTriangulation,
227                                           const Handle(Geom_Surface)&       theSurface,
228                                           const TopLoc_Location&            theLocation,
229                                           const TColStd_SequenceOfReal&     theUIsoParams,
230                                           const TColStd_SequenceOfReal&     theVIsoParams,
231                                           Prs3d_NListOfSequenceOfPnt&       theUPolylines,
232                                           Prs3d_NListOfSequenceOfPnt&       theVPolylines)
233 {
234   const Poly_Array1OfTriangle& aTriangles = theTriangulation->Triangles();
235   const TColgp_Array1OfPnt&    aNodes     = theTriangulation->Nodes();
236   const TColgp_Array1OfPnt2d&  aUVNodes   = theTriangulation->UVNodes();
237   for (Standard_Integer anUVIter = 0; anUVIter < 2; ++anUVIter)
238   {
239     const Standard_Boolean        isUIso      = anUVIter == 0;
240     const TColStd_SequenceOfReal& anIsoParams = isUIso ? theUIsoParams : theVIsoParams;
241     const Standard_Integer aNbIsolines = anIsoParams.Length();
242     if (aNbIsolines == 0)
243     {
244       continue;
245     }
246
247     SeqOfVecOfSegments aPolylines;
248     TColStd_Array1OfInteger anIsoIndexes (1, aNbIsolines);
249     anIsoIndexes.Init (-1);
250     for (Standard_Integer anIsoIdx = 1; anIsoIdx <= aNbIsolines; ++anIsoIdx)
251     {
252       const gp_Lin2d anIsolineUV = isUIso ? isoU (anIsoParams.Value (anIsoIdx)) : isoV (anIsoParams.Value (anIsoIdx));
253       Handle(VecOfSegments) anIsoPnts;
254       if (anIsoIndexes.Value (anIsoIdx) != -1)
255       {
256         anIsoPnts = aPolylines.ChangeValue (anIsoIndexes.Value (anIsoIdx));
257       }
258
259       for (Standard_Integer aTriIter = aTriangles.Lower(); aTriIter <= aTriangles.Upper(); ++aTriIter)
260       {
261         Standard_Integer aNodeIdxs[3];
262         aTriangles.Value (aTriIter).Get (aNodeIdxs[0], aNodeIdxs[1],aNodeIdxs[2]);
263         const gp_Pnt aNodesXYZ[3] = { aNodes.Value (aNodeIdxs[0]),
264                                       aNodes.Value (aNodeIdxs[1]),
265                                       aNodes.Value (aNodeIdxs[2]) };
266         const gp_Pnt2d aNodesUV[3] = { aUVNodes.Value (aNodeIdxs[0]),
267                                        aUVNodes.Value (aNodeIdxs[1]),
268                                        aUVNodes.Value (aNodeIdxs[2]) };
269
270         // Find intersections with triangle in uv space and its projection on triangulation.
271         SegOnIso aSegment;
272         if (!findSegmentOnTriangulation (theSurface, isUIso, anIsolineUV, aNodesXYZ, aNodesUV, aSegment))
273         {
274           continue;
275         }
276
277         if (anIsoPnts.IsNull())
278         {
279           aPolylines.Append (new VecOfSegments());
280           anIsoIndexes.SetValue (anIsoIdx, aPolylines.Size());
281           anIsoPnts = aPolylines.ChangeValue (anIsoIndexes.Value (anIsoIdx));
282         }
283
284         if (!theLocation.IsIdentity())
285         {
286           aSegment[0].Pnt.Transform (theLocation);
287           aSegment[1].Pnt.Transform (theLocation);
288         }
289         anIsoPnts->Append (aSegment);
290       }
291     }
292
293     sortSegments (aPolylines, isUIso ? theUPolylines : theVPolylines);
294   }
295 }
296
297 //==================================================================
298 // function : AddOnSurface
299 // purpose  :
300 //==================================================================
301 void StdPrs_Isolines::AddOnSurface (const Handle(Prs3d_Presentation)& thePresentation,
302                                     const TopoDS_Face&                theFace,
303                                     const Handle(Prs3d_Drawer)&       theDrawer,
304                                     const Standard_Real               theDeflection)
305 {
306   Prs3d_NListOfSequenceOfPnt aUPolylines, aVPolylines;
307   AddOnSurface (theFace, theDrawer, theDeflection, aUPolylines, aVPolylines);
308   Prs3d::AddPrimitivesGroup (thePresentation, theDrawer->UIsoAspect(), aUPolylines);
309   Prs3d::AddPrimitivesGroup (thePresentation, theDrawer->VIsoAspect(), aVPolylines);
310 }
311
312 //==================================================================
313 // function : AddOnSurface
314 // purpose  :
315 //==================================================================
316 void StdPrs_Isolines::AddOnSurface (const TopoDS_Face&          theFace,
317                                     const Handle(Prs3d_Drawer)& theDrawer,
318                                     const Standard_Real         theDeflection,
319                                     Prs3d_NListOfSequenceOfPnt& theUPolylines,
320                                     Prs3d_NListOfSequenceOfPnt& theVPolylines)
321 {
322   const Standard_Integer aNbIsoU = theDrawer->UIsoAspect()->Number();
323   const Standard_Integer aNbIsoV = theDrawer->VIsoAspect()->Number();
324   if (aNbIsoU < 1 && aNbIsoV < 1)
325   {
326     return;
327   }
328
329   // Evaluate parameters for uv isolines.
330   TColStd_SequenceOfReal aUIsoParams, aVIsoParams;
331   UVIsoParameters (theFace, aNbIsoU, aNbIsoV, theDrawer->MaximalParameterValue(), aUIsoParams, aVIsoParams);
332
333   BRepAdaptor_Surface aSurface (theFace);
334   addOnSurface (new BRepAdaptor_HSurface (aSurface),
335                 theDrawer,
336                 theDeflection,
337                 aUIsoParams,
338                 aVIsoParams,
339                 theUPolylines,
340                 theVPolylines);
341 }
342
343 //==================================================================
344 // function : AddOnSurface
345 // purpose  :
346 //==================================================================
347 void StdPrs_Isolines::AddOnSurface (const Handle(Prs3d_Presentation)&   thePresentation,
348                                     const Handle(BRepAdaptor_HSurface)& theSurface,
349                                     const Handle(Prs3d_Drawer)&         theDrawer,
350                                     const Standard_Real                 theDeflection,
351                                     const TColStd_SequenceOfReal&       theUIsoParams,
352                                     const TColStd_SequenceOfReal&       theVIsoParams)
353 {
354   Prs3d_NListOfSequenceOfPnt aUPolylines, aVPolylines;
355   addOnSurface (theSurface, theDrawer, theDeflection, theUIsoParams, theVIsoParams, aUPolylines, aVPolylines);
356   Prs3d::AddPrimitivesGroup (thePresentation, theDrawer->UIsoAspect(), aUPolylines);
357   Prs3d::AddPrimitivesGroup (thePresentation, theDrawer->VIsoAspect(), aVPolylines);
358 }
359
360 //==================================================================
361 // function : addOnSurface
362 // purpose  :
363 //==================================================================
364 void StdPrs_Isolines::addOnSurface (const Handle(BRepAdaptor_HSurface)& theSurface,
365                                     const Handle(Prs3d_Drawer)&         theDrawer,
366                                     const Standard_Real                 theDeflection,
367                                     const TColStd_SequenceOfReal&       theUIsoParams,
368                                     const TColStd_SequenceOfReal&       theVIsoParams,
369                                     Prs3d_NListOfSequenceOfPnt&         theUPolylines,
370                                     Prs3d_NListOfSequenceOfPnt&         theVPolylines)
371 {
372   // Choose a deflection for sampling edge uv curves.
373   Standard_Real aUVLimit = theDrawer->MaximalParameterValue();
374   Standard_Real aUmin  = Max (theSurface->FirstUParameter(), -aUVLimit);
375   Standard_Real aUmax  = Min (theSurface->LastUParameter(),   aUVLimit);
376   Standard_Real aVmin  = Max (theSurface->FirstVParameter(), -aUVLimit);
377   Standard_Real aVmax  = Min (theSurface->LastVParameter(),   aUVLimit);
378   Standard_Real aSamplerDeflection = Max (aUmax - aUmin, aVmax - aVmin) * theDrawer->DeviationCoefficient();
379   Standard_Real aHatchingTolerance = RealLast();
380
381   try
382   {
383     OCC_CATCH_SIGNALS
384     // Determine edge points for trimming uv hatch region.
385     TColgp_SequenceOfPnt2d aTrimPoints;
386     StdPrs_ToolRFace anEdgeTool (theSurface);
387     for (anEdgeTool.Init(); anEdgeTool.More(); anEdgeTool.Next())
388     {
389       TopAbs_Orientation anOrientation = anEdgeTool.Orientation();
390       const Adaptor2d_Curve2d* anEdgeCurve = &anEdgeTool.Value();
391       if (anEdgeCurve->GetType() != GeomAbs_Line)
392       {
393         GCPnts_QuasiUniformDeflection aSampler (*anEdgeCurve, aSamplerDeflection);
394         if (!aSampler.IsDone())
395         {
396 #ifdef OCCT_DEBUG
397           std::cout << "Cannot evaluate curve on surface" << std::endl;
398 #endif
399           continue;
400         }
401
402         Standard_Integer aNumberOfPoints = aSampler.NbPoints();
403         if (aNumberOfPoints < 2)
404         {
405           continue;
406         }
407
408         for (Standard_Integer anI = 1; anI < aNumberOfPoints; ++anI)
409         {
410           gp_Pnt2d aP1 (aSampler.Value (anI    ).X(), aSampler.Value (anI    ).Y());
411           gp_Pnt2d aP2 (aSampler.Value (anI + 1).X(), aSampler.Value (anI + 1).Y());
412
413           aHatchingTolerance = Min (aP1.SquareDistance (aP2), aHatchingTolerance);
414
415           aTrimPoints.Append (anOrientation == TopAbs_FORWARD ? aP1 : aP2);
416           aTrimPoints.Append (anOrientation == TopAbs_FORWARD ? aP2 : aP1);
417         }
418       }
419       else
420       {
421         Standard_Real aU1 = anEdgeCurve->FirstParameter();
422         Standard_Real aU2 = anEdgeCurve->LastParameter();
423
424         // MSV 17.08.06 OCC13144: U2 occured less than U1, to overcome it
425         // ensure that distance U2-U1 is not greater than aLimit*2,
426         // if greater then choose an origin and use aLimit to define
427         // U1 and U2 anew.
428         Standard_Real anOrigin = 0.0;
429
430         if (!Precision::IsNegativeInfinite (aU1) || !Precision::IsPositiveInfinite(aU2))
431         {
432           if (Precision::IsNegativeInfinite (aU1))
433           {
434             anOrigin = aU2 - aUVLimit;
435           }
436           else if (Precision::IsPositiveInfinite (aU2))
437           {
438             anOrigin = aU1 + aUVLimit;
439           }
440           else
441           {
442             anOrigin = (aU1 + aU2) * 0.5;
443           }
444         }
445
446         aU1 = Max (anOrigin - aUVLimit, aU1);
447         aU2 = Min (anOrigin + aUVLimit, aU2);
448
449         gp_Pnt2d aP1 = anEdgeCurve->Value (aU1);
450         gp_Pnt2d aP2 = anEdgeCurve->Value (aU2);
451
452         aHatchingTolerance = Min (aP1.SquareDistance(aP2), aHatchingTolerance);
453
454         aTrimPoints.Append (anOrientation == TopAbs_FORWARD ? aP1 : aP2);
455         aTrimPoints.Append (anOrientation == TopAbs_FORWARD ? aP2 : aP1);
456       }
457     }
458
459     // Compute a hatching tolerance.
460     aHatchingTolerance *= 0.1;
461     aHatchingTolerance = Max (Precision::Confusion(), aHatchingTolerance);
462     aHatchingTolerance = Min (1.0E-5, aHatchingTolerance);
463
464     // Load isolines into hatcher.
465     Hatch_Hatcher aHatcher (aHatchingTolerance, anEdgeTool.IsOriented());
466
467     for (Standard_Integer anIso = 1; anIso <= theUIsoParams.Length(); ++anIso)
468     {
469       aHatcher.AddXLine (theUIsoParams.Value (anIso));
470     }
471     for (Standard_Integer anIso = 1; anIso <= theVIsoParams.Length(); ++anIso)
472     {
473       aHatcher.AddYLine (theVIsoParams.Value (anIso));
474     }
475
476     // Trim hatching region.
477     for (Standard_Integer anI = 1; anI <= aTrimPoints.Length(); anI += 2)
478     {
479       aHatcher.Trim (aTrimPoints (anI), aTrimPoints (anI + 1));
480     }
481
482     // Use surface definition for evaluation of Bezier, B-spline surface.
483     // Use isoline adapter for other types of surfaces.
484     GeomAbs_SurfaceType  aSurfType = theSurface->GetType();
485     Handle(Geom_Surface) aBSurface;
486     GeomAdaptor_Curve    aBSurfaceCurve;
487     Adaptor3d_IsoCurve   aCanonicalCurve;
488     if (aSurfType == GeomAbs_BezierSurface)
489     {
490       aBSurface = theSurface->Bezier();
491     }
492     else if (aSurfType == GeomAbs_BSplineSurface)
493     {
494       aBSurface = theSurface->BSpline();
495     }
496     else
497     {
498       aCanonicalCurve.Load (theSurface);
499     }
500
501     // For each isoline: compute its segments.
502     for (Standard_Integer anI = 1; anI <= aHatcher.NbLines(); anI++)
503     {
504       Standard_Real anIsoParam = aHatcher.Coordinate (anI);
505       Standard_Boolean isIsoU  = aHatcher.IsXLine (anI);
506
507       // For each isoline's segment: evaluate its points.
508       for (Standard_Integer aJ = 1; aJ <= aHatcher.NbIntervals (anI); aJ++)
509       {
510         Standard_Real aSegmentP1 = aHatcher.Start (anI, aJ);
511         Standard_Real aSegmentP2 = aHatcher.End (anI, aJ);
512
513         if (!aBSurface.IsNull())
514         {
515           aBSurfaceCurve.Load (isIsoU ? aBSurface->UIso (anIsoParam) : aBSurface->VIso (anIsoParam));
516
517           findLimits (aBSurfaceCurve, aUVLimit, aSegmentP1, aSegmentP2);
518
519           if (aSegmentP2 - aSegmentP1 <= Precision::Confusion())
520           {
521             continue;
522           }
523         }
524         else
525         {
526           aCanonicalCurve.Load (isIsoU ? GeomAbs_IsoU : GeomAbs_IsoV, anIsoParam, aSegmentP1, aSegmentP2);
527
528           findLimits (aCanonicalCurve, aUVLimit, aSegmentP1, aSegmentP2);
529
530           if (aSegmentP2 - aSegmentP1 <= Precision::Confusion())
531           {
532             continue;
533           }
534         }
535         Adaptor3d_Curve* aCurve = aBSurface.IsNull() ? (Adaptor3d_Curve*) &aCanonicalCurve
536           : (Adaptor3d_Curve*) &aBSurfaceCurve;
537
538         Handle(TColgp_HSequenceOfPnt) aPoints = new TColgp_HSequenceOfPnt();
539         StdPrs_DeflectionCurve::Add (Handle(Prs3d_Presentation)(),
540                                      *aCurve,
541                                      aSegmentP1,
542                                      aSegmentP2,
543                                      theDeflection,
544                                      aPoints->ChangeSequence(),
545                                      theDrawer->DeviationAngle(),
546                                      Standard_False);
547         if (aPoints->IsEmpty())
548         {
549           continue;
550         }
551
552         if (isIsoU)
553         {
554           theUPolylines.Append (aPoints);
555         }
556         else
557         {
558           theVPolylines.Append (aPoints);
559         }
560       }
561     }
562   }
563   catch (Standard_Failure const&)
564   {
565     // ...
566   }
567 }
568
569 //==================================================================
570 // function : UVIsoParameters
571 // purpose  :
572 //==================================================================
573 void StdPrs_Isolines::UVIsoParameters (const TopoDS_Face&      theFace,
574                                        const Standard_Integer  theNbIsoU,
575                                        const Standard_Integer  theNbIsoV,
576                                        const Standard_Real     theUVLimit,
577                                        TColStd_SequenceOfReal& theUIsoParams,
578                                        TColStd_SequenceOfReal& theVIsoParams)
579 {
580   Standard_Real aUmin = 0.0;
581   Standard_Real aUmax = 0.0;
582   Standard_Real aVmin = 0.0;
583   Standard_Real aVmax = 0.0;
584
585   BRepTools::UVBounds (theFace, aUmin, aUmax, aVmin, aVmax);
586
587   if (Precision::IsInfinite (aUmin))
588     aUmin = -theUVLimit;
589   if (Precision::IsInfinite (aUmax))
590     aUmax = theUVLimit;
591   if (Precision::IsInfinite (aVmin))
592     aVmin = -theUVLimit;
593   if (Precision::IsInfinite (aVmax))
594     aVmax = theUVLimit;
595
596   TopLoc_Location aLocation;
597   const Handle(Geom_Surface)& aSurface = BRep_Tool::Surface (theFace, aLocation);
598   if (aSurface.IsNull())
599   {
600     return;
601   }
602
603   const Standard_Boolean isUClosed = aSurface->IsUClosed();
604   const Standard_Boolean isVClosed = aSurface->IsVClosed();
605
606   if (!isUClosed)
607   {
608     aUmin = aUmin + (aUmax - aUmin) / 1000.0;
609     aUmax = aUmax - (aUmax - aUmin) / 1000.0;
610   }
611
612   if (!isVClosed)
613   {
614     aVmin = aVmin + (aVmax - aVmin) / 1000.0;
615     aVmax = aVmax - (aVmax - aVmin) / 1000.0;
616   }
617
618   Standard_Real aUstep = (aUmax - aUmin) / (1 + theNbIsoU);
619   Standard_Real aVstep = (aVmax - aVmin) / (1 + theNbIsoV);
620
621   for (Standard_Integer anIso = 1; anIso <= theNbIsoU; ++anIso)
622   {
623     theUIsoParams.Append (aUmin + aUstep * anIso);
624   }
625
626   for (Standard_Integer anIso = 1; anIso <= theNbIsoV; ++anIso)
627   {
628     theVIsoParams.Append (aVmin + aVstep * anIso);
629   }
630 }
631
632 //==================================================================
633 // function : FindSegmentOnTriangulation
634 // purpose  :
635 //==================================================================
636 Standard_Boolean StdPrs_Isolines::findSegmentOnTriangulation (const Handle(Geom_Surface)& theSurface,
637                                                               const bool                  theIsU,
638                                                               const gp_Lin2d&             theIsoline,
639                                                               const gp_Pnt*               theNodesXYZ,
640                                                               const gp_Pnt2d*             theNodesUV,
641                                                               SegOnIso&                   theSegment)
642 {
643   Standard_Integer aNPoints = 0;
644
645   for (Standard_Integer aLinkIter = 0; aLinkIter < 3 && aNPoints < 2; ++aLinkIter)
646   {
647     // ...
648     // Check that uv isoline crosses the triangulation link in parametric space
649     // ...
650
651     const gp_Pnt2d& aNodeUV1 = theNodesUV[aLinkIter];
652     const gp_Pnt2d& aNodeUV2 = theNodesUV[(aLinkIter + 1) % 3];
653     const gp_Pnt& aNode1 = theNodesXYZ[aLinkIter];
654     const gp_Pnt& aNode2 = theNodesXYZ[(aLinkIter + 1) % 3];
655
656     // Compute distance of uv points to isoline taking into consideration their relative
657     // location against the isoline (left or right). Null value for a node means that the
658     // isoline crosses the node. Both positive or negative means that the isoline does not
659     // cross the segment.
660     Standard_Boolean isLeftUV1 = (theIsoline.Direction().XY() ^ gp_Vec2d (theIsoline.Location(), aNodeUV1).XY()) > 0.0;
661     Standard_Boolean isLeftUV2 = (theIsoline.Direction().XY() ^ gp_Vec2d (theIsoline.Location(), aNodeUV2).XY()) > 0.0;
662     Standard_Real aDistanceUV1 = isLeftUV1 ? theIsoline.Distance (aNodeUV1) : -theIsoline.Distance (aNodeUV1);
663     Standard_Real aDistanceUV2 = isLeftUV2 ? theIsoline.Distance (aNodeUV2) : -theIsoline.Distance (aNodeUV2);
664
665     // Isoline crosses first point of an edge.
666     if (Abs (aDistanceUV1) < Precision::PConfusion())
667     {
668       theSegment[aNPoints].Param = theIsU ? aNodeUV1.Y() : aNodeUV1.X();
669       theSegment[aNPoints].Pnt   = aNode1;
670       ++aNPoints;
671       continue;
672     }
673
674     // Isoline crosses second point of an edge.
675     if (Abs (aDistanceUV2) < Precision::PConfusion())
676     {
677       theSegment[aNPoints].Param = theIsU ? aNodeUV2.Y() : aNodeUV2.X();
678       theSegment[aNPoints].Pnt   = aNode2;
679
680       ++aNPoints;
681       ++aLinkIter;
682       continue;
683     }
684
685     // Isoline does not cross the triangle link.
686     if (aDistanceUV1 * aDistanceUV2 > 0.0)
687     {
688       continue;
689     }
690
691     // Isoline crosses degenerated link.
692     if (aNode1.SquareDistance (aNode2) < Precision::PConfusion())
693     {
694       theSegment[aNPoints].Param = theIsU ? aNodeUV1.Y() : aNodeUV1.X();
695       theSegment[aNPoints].Pnt   = aNode1;
696       ++aNPoints;
697       continue;
698     }
699
700     // ...
701     // Derive cross-point from parametric coordinates
702     // ...
703
704     Standard_Real anAlpha = Abs (aDistanceUV1) / (Abs (aDistanceUV1) + Abs (aDistanceUV2));
705
706     gp_Pnt aCross (0.0, 0.0, 0.0);
707     Standard_Real aCrossU = aNodeUV1.X() + anAlpha * (aNodeUV2.X() - aNodeUV1.X());
708     Standard_Real aCrossV = aNodeUV1.Y() + anAlpha * (aNodeUV2.Y() - aNodeUV1.Y());
709     Standard_Real aCrossParam = theIsU ? aCrossV : aCrossU;
710     if (theSurface.IsNull())
711     {
712       // Do linear interpolation of point coordinates using triangulation nodes.
713       aCross.SetX (aNode1.X() + anAlpha * (aNode2.X() - aNode1.X()));
714       aCross.SetY (aNode1.Y() + anAlpha * (aNode2.Y() - aNode1.Y()));
715       aCross.SetZ (aNode1.Z() + anAlpha * (aNode2.Z() - aNode1.Z()));
716     }
717     else
718     {
719       // Do linear interpolation of point coordinates by triangulation nodes.
720       // Get 3d point on surface.
721       Handle(Geom_Curve) anIso1, anIso2, anIso3;
722       Standard_Real aPntOnNode1Iso = 0.0;
723       Standard_Real aPntOnNode2Iso = 0.0;
724       Standard_Real aPntOnNode3Iso = 0.0;
725
726       if (theIsoline.Direction().X() == 0.0)
727       {
728         aPntOnNode1Iso = aNodeUV1.X();
729         aPntOnNode2Iso = aNodeUV2.X();
730         aPntOnNode3Iso = aCrossU;
731         anIso1 = theSurface->VIso (aNodeUV1.Y());
732         anIso2 = theSurface->VIso (aNodeUV2.Y());
733         anIso3 = theSurface->VIso (aCrossV);
734       }
735       else if (theIsoline.Direction().Y() == 0.0)
736       {
737         aPntOnNode1Iso = aNodeUV1.Y();
738         aPntOnNode2Iso = aNodeUV2.Y();
739         aPntOnNode3Iso = aCrossV;
740         anIso1 = theSurface->UIso (aNodeUV1.X());
741         anIso2 = theSurface->UIso (aNodeUV2.X());
742         anIso3 = theSurface->UIso (aCrossU);
743       }
744
745       GeomAdaptor_Curve aCurveAdaptor1 (anIso1);
746       GeomAdaptor_Curve aCurveAdaptor2 (anIso2);
747       GeomAdaptor_Curve aCurveAdaptor3 (anIso3);
748       Standard_Real aLength1 = GCPnts_AbscissaPoint::Length (aCurveAdaptor1, aPntOnNode1Iso, aPntOnNode3Iso, 1e-2);
749       Standard_Real aLength2 = GCPnts_AbscissaPoint::Length (aCurveAdaptor2, aPntOnNode2Iso, aPntOnNode3Iso, 1e-2);
750       if (Abs (aLength1) < Precision::Confusion() || Abs (aLength2) < Precision::Confusion())
751       {
752         theSegment[aNPoints].Param = aCrossParam;
753         theSegment[aNPoints].Pnt   = (aNode2.XYZ() - aNode1.XYZ()) * anAlpha + aNode1.XYZ();
754         ++aNPoints;
755         continue;
756       }
757
758       aCross = (aNode2.XYZ() - aNode1.XYZ()) * (aLength1 / (aLength1 + aLength2)) + aNode1.XYZ();
759     }
760
761     theSegment[aNPoints].Param = aCrossParam;
762     theSegment[aNPoints].Pnt   = aCross;
763     ++aNPoints;
764   }
765
766   if (aNPoints != 2
767    || Abs (theSegment[1].Param - theSegment[0].Param) <= Precision::PConfusion())
768   {
769     return false;
770   }
771
772   if (theSegment[1].Param < theSegment[0].Param)
773   {
774     std::swap (theSegment[0], theSegment[1]);
775   }
776   return true;
777 }