0027821: Visualization, AIS_Shape - add NULL checks for displaying TopoDS_Face with...
[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 Standard_Integer aNbIsoU = theUIsoParams.Length();
235   const Standard_Integer aNbIsoV = theVIsoParams.Length();
236
237   SeqOfVecOfSegments aUPolylines, aVPolylines;
238
239   const Poly_Array1OfTriangle& aTriangles = theTriangulation->Triangles();
240   const TColgp_Array1OfPnt&    aNodes     = theTriangulation->Nodes();
241   const TColgp_Array1OfPnt2d&  aUVNodes   = theTriangulation->UVNodes();
242
243   TColStd_Array1OfInteger aUIsoIndexes (1, aNbIsoU);
244   TColStd_Array1OfInteger aVIsoIndexes (1, aNbIsoV);
245   aUIsoIndexes.Init (-1);
246   aVIsoIndexes.Init (-1);
247
248   for (Standard_Integer anI = aTriangles.Lower(); anI <= aTriangles.Upper(); ++anI)
249   {
250     Standard_Integer aNodeIdxs[3];
251     aTriangles.Value (anI).Get (aNodeIdxs[0], aNodeIdxs[1],aNodeIdxs[2]);
252     const gp_Pnt aNodesXYZ[3] = { aNodes.Value (aNodeIdxs[0]),
253                                   aNodes.Value (aNodeIdxs[1]),
254                                   aNodes.Value (aNodeIdxs[2]) };
255     const gp_Pnt2d aNodesUV[3] = { aUVNodes.Value (aNodeIdxs[0]),
256                                    aUVNodes.Value (aNodeIdxs[1]),
257                                    aUVNodes.Value (aNodeIdxs[2]) };
258
259     // Evaluate polyline points for u isolines.
260     for (Standard_Integer anIsoIdx = 1; anIsoIdx <= aNbIsoU; ++anIsoIdx)
261     {
262       SegOnIso aSegment;
263       const gp_Lin2d anIsolineUV = isoU (theUIsoParams.Value (anIsoIdx));
264
265       // Find intersections with triangle in uv space and its projection on triangulation.
266       if (!findSegmentOnTriangulation (theSurface, true, anIsolineUV, aNodesXYZ, aNodesUV, aSegment))
267       {
268         continue;
269       }
270
271       if (aUIsoIndexes.Value (anIsoIdx) == -1)
272       {
273         aUPolylines.Append (new VecOfSegments());
274         aUIsoIndexes.SetValue (anIsoIdx, aUPolylines.Size());
275       }
276
277       Handle(VecOfSegments) anIsoPnts = aUPolylines.ChangeValue (aUIsoIndexes.Value (anIsoIdx));
278       if (!theLocation.IsIdentity())
279       {
280         aSegment[0].Pnt.Transform (theLocation);
281         aSegment[1].Pnt.Transform (theLocation);
282       }
283       anIsoPnts->Append (aSegment);
284     }
285
286     // Evaluate polyline points for v isolines.
287     for (Standard_Integer anIsoIdx = 1; anIsoIdx <= aNbIsoV; ++anIsoIdx)
288     {
289       SegOnIso aSegment;
290       const gp_Lin2d anIsolineUV = isoV (theVIsoParams.Value (anIsoIdx));
291
292       if (!findSegmentOnTriangulation (theSurface, false, anIsolineUV, aNodesXYZ, aNodesUV, aSegment))
293       {
294         continue;
295       }
296
297       if (aVIsoIndexes.Value (anIsoIdx) == -1)
298       {
299         aVPolylines.Append (new VecOfSegments());
300         aVIsoIndexes.SetValue (anIsoIdx, aVPolylines.Size());
301       }
302
303       Handle(VecOfSegments) anIsoPnts = aVPolylines.ChangeValue (aVIsoIndexes.Value (anIsoIdx));
304       if (!theLocation.IsIdentity())
305       {
306         aSegment[0].Pnt.Transform (theLocation);
307         aSegment[1].Pnt.Transform (theLocation);
308       }
309       anIsoPnts->Append (aSegment);
310     }
311   }
312
313   sortSegments (aUPolylines, theUPolylines);
314   sortSegments (aVPolylines, theVPolylines);
315 }
316
317 //==================================================================
318 // function : AddOnSurface
319 // purpose  :
320 //==================================================================
321 void StdPrs_Isolines::AddOnSurface (const Handle(Prs3d_Presentation)& thePresentation,
322                                     const TopoDS_Face&                theFace,
323                                     const Handle(Prs3d_Drawer)&       theDrawer,
324                                     const Standard_Real               theDeflection)
325 {
326   Prs3d_NListOfSequenceOfPnt aUPolylines, aVPolylines;
327   AddOnSurface (theFace, theDrawer, theDeflection, aUPolylines, aVPolylines);
328   Prs3d::AddPrimitivesGroup (thePresentation, theDrawer->UIsoAspect(), aUPolylines);
329   Prs3d::AddPrimitivesGroup (thePresentation, theDrawer->VIsoAspect(), aVPolylines);
330 }
331
332 //==================================================================
333 // function : AddOnSurface
334 // purpose  :
335 //==================================================================
336 void StdPrs_Isolines::AddOnSurface (const TopoDS_Face&          theFace,
337                                     const Handle(Prs3d_Drawer)& theDrawer,
338                                     const Standard_Real         theDeflection,
339                                     Prs3d_NListOfSequenceOfPnt& theUPolylines,
340                                     Prs3d_NListOfSequenceOfPnt& theVPolylines)
341 {
342   const Standard_Integer aNbIsoU = theDrawer->UIsoAspect()->Number();
343   const Standard_Integer aNbIsoV = theDrawer->VIsoAspect()->Number();
344   if (aNbIsoU < 1 && aNbIsoV < 1)
345   {
346     return;
347   }
348
349   // Evaluate parameters for uv isolines.
350   TColStd_SequenceOfReal aUIsoParams, aVIsoParams;
351   UVIsoParameters (theFace, aNbIsoU, aNbIsoV, theDrawer->MaximalParameterValue(), aUIsoParams, aVIsoParams);
352
353   BRepAdaptor_Surface aSurface (theFace);
354   addOnSurface (new BRepAdaptor_HSurface (aSurface),
355                 theDrawer,
356                 theDeflection,
357                 aUIsoParams,
358                 aVIsoParams,
359                 theUPolylines,
360                 theVPolylines);
361 }
362
363 //==================================================================
364 // function : AddOnSurface
365 // purpose  :
366 //==================================================================
367 void StdPrs_Isolines::AddOnSurface (const Handle(Prs3d_Presentation)&   thePresentation,
368                                     const Handle(BRepAdaptor_HSurface)& theSurface,
369                                     const Handle(Prs3d_Drawer)&         theDrawer,
370                                     const Standard_Real                 theDeflection,
371                                     const TColStd_SequenceOfReal&       theUIsoParams,
372                                     const TColStd_SequenceOfReal&       theVIsoParams)
373 {
374   Prs3d_NListOfSequenceOfPnt aUPolylines, aVPolylines;
375   addOnSurface (theSurface, theDrawer, theDeflection, theUIsoParams, theVIsoParams, aUPolylines, aVPolylines);
376   Prs3d::AddPrimitivesGroup (thePresentation, theDrawer->UIsoAspect(), aUPolylines);
377   Prs3d::AddPrimitivesGroup (thePresentation, theDrawer->VIsoAspect(), aVPolylines);
378 }
379
380 //==================================================================
381 // function : addOnSurface
382 // purpose  :
383 //==================================================================
384 void StdPrs_Isolines::addOnSurface (const Handle(BRepAdaptor_HSurface)& theSurface,
385                                     const Handle(Prs3d_Drawer)&         theDrawer,
386                                     const Standard_Real                 theDeflection,
387                                     const TColStd_SequenceOfReal&       theUIsoParams,
388                                     const TColStd_SequenceOfReal&       theVIsoParams,
389                                     Prs3d_NListOfSequenceOfPnt&         theUPolylines,
390                                     Prs3d_NListOfSequenceOfPnt&         theVPolylines)
391 {
392   // Choose a deflection for sampling edge uv curves.
393   Standard_Real aUVLimit = theDrawer->MaximalParameterValue();
394   Standard_Real aUmin  = Max (theSurface->FirstUParameter(), -aUVLimit);
395   Standard_Real aUmax  = Min (theSurface->LastUParameter(),   aUVLimit);
396   Standard_Real aVmin  = Max (theSurface->FirstVParameter(), -aUVLimit);
397   Standard_Real aVmax  = Min (theSurface->LastVParameter(),   aUVLimit);
398   Standard_Real aSamplerDeflection = Max (aUmax - aUmin, aVmax - aVmin) * theDrawer->DeviationCoefficient();
399   Standard_Real aHatchingTolerance = RealLast();
400
401   try
402   {
403     OCC_CATCH_SIGNALS
404     // Determine edge points for trimming uv hatch region.
405     TColgp_SequenceOfPnt2d aTrimPoints;
406     StdPrs_ToolRFace anEdgeTool (theSurface);
407     for (anEdgeTool.Init(); anEdgeTool.More(); anEdgeTool.Next())
408     {
409       TopAbs_Orientation anOrientation = anEdgeTool.Orientation();
410       if (anOrientation != TopAbs_FORWARD && anOrientation != TopAbs_REVERSED)
411       {
412         continue;
413       }
414
415       Adaptor2d_Curve2dPtr anEdgeCurve = anEdgeTool.Value();
416       if (anEdgeCurve->GetType() != GeomAbs_Line)
417       {
418         GCPnts_QuasiUniformDeflection aSampler (*anEdgeCurve, aSamplerDeflection);
419         if (!aSampler.IsDone())
420         {
421 #ifdef OCCT_DEBUG
422           std::cout << "Cannot evaluate curve on surface" << std::endl;
423 #endif
424           continue;
425         }
426
427         Standard_Integer aNumberOfPoints = aSampler.NbPoints();
428         if (aNumberOfPoints < 2)
429         {
430           continue;
431         }
432
433         for (Standard_Integer anI = 1; anI < aNumberOfPoints; ++anI)
434         {
435           gp_Pnt2d aP1 (aSampler.Value (anI    ).X(), aSampler.Value (anI    ).Y());
436           gp_Pnt2d aP2 (aSampler.Value (anI + 1).X(), aSampler.Value (anI + 1).Y());
437
438           aHatchingTolerance = Min (aP1.SquareDistance (aP2), aHatchingTolerance);
439
440           aTrimPoints.Append (anOrientation == TopAbs_FORWARD ? aP1 : aP2);
441           aTrimPoints.Append (anOrientation == TopAbs_FORWARD ? aP2 : aP1);
442         }
443       }
444       else
445       {
446         Standard_Real aU1 = anEdgeCurve->FirstParameter();
447         Standard_Real aU2 = anEdgeCurve->LastParameter();
448
449         // MSV 17.08.06 OCC13144: U2 occured less than U1, to overcome it
450         // ensure that distance U2-U1 is not greater than aLimit*2,
451         // if greater then choose an origin and use aLimit to define
452         // U1 and U2 anew.
453         Standard_Real anOrigin = 0.0;
454
455         if (!Precision::IsNegativeInfinite (aU1) || !Precision::IsPositiveInfinite(aU2))
456         {
457           if (Precision::IsNegativeInfinite (aU1))
458           {
459             anOrigin = aU2 - aUVLimit;
460           }
461           else if (Precision::IsPositiveInfinite (aU2))
462           {
463             anOrigin = aU1 + aUVLimit;
464           }
465           else
466           {
467             anOrigin = (aU1 + aU2) * 0.5;
468           }
469         }
470
471         aU1 = Max (anOrigin - aUVLimit, aU1);
472         aU2 = Min (anOrigin + aUVLimit, aU2);
473
474         gp_Pnt2d aP1 = anEdgeCurve->Value (aU1);
475         gp_Pnt2d aP2 = anEdgeCurve->Value (aU2);
476
477         aHatchingTolerance = Min (aP1.SquareDistance(aP2), aHatchingTolerance);
478
479         aTrimPoints.Append (anOrientation == TopAbs_FORWARD ? aP1 : aP2);
480         aTrimPoints.Append (anOrientation == TopAbs_FORWARD ? aP2 : aP1);
481       }
482     }
483
484     // Compute a hatching tolerance.
485     aHatchingTolerance *= 0.1;
486     aHatchingTolerance = Max (Precision::Confusion(), aHatchingTolerance);
487     aHatchingTolerance = Min (1.0E-5, aHatchingTolerance);
488
489     // Load isolines into hatcher.
490     Hatch_Hatcher aHatcher (aHatchingTolerance, anEdgeTool.IsOriented());
491
492     for (Standard_Integer anIso = 1; anIso <= theUIsoParams.Length(); ++anIso)
493     {
494       aHatcher.AddXLine (theUIsoParams.Value (anIso));
495     }
496     for (Standard_Integer anIso = 1; anIso <= theVIsoParams.Length(); ++anIso)
497     {
498       aHatcher.AddYLine (theVIsoParams.Value (anIso));
499     }
500
501     // Trim hatching region.
502     for (Standard_Integer anI = 1; anI <= aTrimPoints.Length(); anI += 2)
503     {
504       aHatcher.Trim (aTrimPoints (anI), aTrimPoints (anI + 1));
505     }
506
507     // Use surface definition for evaluation of Bezier, B-spline surface.
508     // Use isoline adapter for other types of surfaces.
509     GeomAbs_SurfaceType  aSurfType = theSurface->GetType();
510     Handle(Geom_Surface) aBSurface;
511     GeomAdaptor_Curve    aBSurfaceCurve;
512     Adaptor3d_IsoCurve   aCanonicalCurve;
513     if (aSurfType == GeomAbs_BezierSurface)
514     {
515       aBSurface = theSurface->Bezier();
516     }
517     else if (aSurfType == GeomAbs_BSplineSurface)
518     {
519       aBSurface = theSurface->BSpline();
520     }
521     else
522     {
523       aCanonicalCurve.Load (theSurface);
524     }
525
526     // For each isoline: compute its segments.
527     for (Standard_Integer anI = 1; anI <= aHatcher.NbLines(); anI++)
528     {
529       Standard_Real anIsoParam = aHatcher.Coordinate (anI);
530       Standard_Boolean isIsoU  = aHatcher.IsXLine (anI);
531
532       // For each isoline's segment: evaluate its points.
533       for (Standard_Integer aJ = 1; aJ <= aHatcher.NbIntervals (anI); aJ++)
534       {
535         Standard_Real aSegmentP1 = aHatcher.Start (anI, aJ);
536         Standard_Real aSegmentP2 = aHatcher.End (anI, aJ);
537
538         if (!aBSurface.IsNull())
539         {
540           aBSurfaceCurve.Load (isIsoU ? aBSurface->UIso (anIsoParam) : aBSurface->VIso (anIsoParam));
541
542           findLimits (aBSurfaceCurve, aUVLimit, aSegmentP1, aSegmentP2);
543
544           if (aSegmentP2 - aSegmentP1 <= Precision::Confusion())
545           {
546             continue;
547           }
548         }
549         else
550         {
551           aCanonicalCurve.Load (isIsoU ? GeomAbs_IsoU : GeomAbs_IsoV, anIsoParam, aSegmentP1, aSegmentP2);
552
553           findLimits (aCanonicalCurve, aUVLimit, aSegmentP1, aSegmentP2);
554
555           if (aSegmentP2 - aSegmentP1 <= Precision::Confusion())
556           {
557             continue;
558           }
559         }
560         Adaptor3d_Curve* aCurve = aBSurface.IsNull() ? (Adaptor3d_Curve*) &aCanonicalCurve
561           : (Adaptor3d_Curve*) &aBSurfaceCurve;
562
563         Handle(TColgp_HSequenceOfPnt) aPoints = new TColgp_HSequenceOfPnt();
564         StdPrs_DeflectionCurve::Add (Handle(Prs3d_Presentation)(),
565                                      *aCurve,
566                                      aSegmentP1,
567                                      aSegmentP2,
568                                      theDeflection,
569                                      aPoints->ChangeSequence(),
570                                      theDrawer->DeviationAngle(),
571                                      Standard_False);
572         if (aPoints->IsEmpty())
573         {
574           continue;
575         }
576
577         if (isIsoU)
578         {
579           theUPolylines.Append (aPoints);
580         }
581         else
582         {
583           theVPolylines.Append (aPoints);
584         }
585       }
586     }
587   }
588   catch (Standard_Failure)
589   {
590     // ...
591   }
592 }
593
594 //==================================================================
595 // function : UVIsoParameters
596 // purpose  :
597 //==================================================================
598 void StdPrs_Isolines::UVIsoParameters (const TopoDS_Face&      theFace,
599                                        const Standard_Integer  theNbIsoU,
600                                        const Standard_Integer  theNbIsoV,
601                                        const Standard_Real     theUVLimit,
602                                        TColStd_SequenceOfReal& theUIsoParams,
603                                        TColStd_SequenceOfReal& theVIsoParams)
604 {
605   Standard_Real aUmin = 0.0;
606   Standard_Real aUmax = 0.0;
607   Standard_Real aVmin = 0.0;
608   Standard_Real aVmax = 0.0;
609
610   BRepTools::UVBounds (theFace, aUmin, aUmax, aVmin, aVmax);
611
612   aUmin = Max (aUmin, -theUVLimit);
613   aUmax = Min (aUmax,  theUVLimit);
614   aVmin = Max (aVmin, -theUVLimit);
615   aVmax = Min (aVmax,  theUVLimit);
616
617   TopLoc_Location aLocation;
618   const Handle(Geom_Surface)& aSurface = BRep_Tool::Surface (theFace, aLocation);
619   if (aSurface.IsNull())
620   {
621     return;
622   }
623
624   const Standard_Boolean isUClosed = aSurface->IsUClosed();
625   const Standard_Boolean isVClosed = aSurface->IsVClosed();
626
627   if (!isUClosed)
628   {
629     aUmin = aUmin + (aUmax - aUmin) / 1000.0;
630     aUmax = aUmax - (aUmax - aUmin) / 1000.0;
631   }
632
633   if (!isVClosed)
634   {
635     aVmin = aVmin + (aVmax - aVmin) / 1000.0;
636     aVmax = aVmax - (aVmax - aVmin) / 1000.0;
637   }
638
639   Standard_Real aUstep = (aUmax - aUmin) / (1 + theNbIsoU);
640   Standard_Real aVstep = (aVmax - aVmin) / (1 + theNbIsoV);
641
642   for (Standard_Integer anIso = 1; anIso <= theNbIsoU; ++anIso)
643   {
644     theUIsoParams.Append (aUmin + aUstep * anIso);
645   }
646
647   for (Standard_Integer anIso = 1; anIso <= theNbIsoV; ++anIso)
648   {
649     theVIsoParams.Append (aVmin + aVstep * anIso);
650   }
651 }
652
653 //==================================================================
654 // function : FindSegmentOnTriangulation
655 // purpose  :
656 //==================================================================
657 Standard_Boolean StdPrs_Isolines::findSegmentOnTriangulation (const Handle(Geom_Surface)& theSurface,
658                                                               const bool                  theIsU,
659                                                               const gp_Lin2d&             theIsoline,
660                                                               const gp_Pnt*               theNodesXYZ,
661                                                               const gp_Pnt2d*             theNodesUV,
662                                                               SegOnIso&                   theSegment)
663 {
664   Standard_Integer aNPoints = 0;
665
666   for (Standard_Integer aLinkIter = 0; aLinkIter < 3 && aNPoints < 2; ++aLinkIter)
667   {
668     // ...
669     // Check that uv isoline crosses the triangulation link in parametric space
670     // ...
671
672     const gp_Pnt2d& aNodeUV1 = theNodesUV[aLinkIter];
673     const gp_Pnt2d& aNodeUV2 = theNodesUV[(aLinkIter + 1) % 3];
674     const gp_Pnt& aNode1 = theNodesXYZ[aLinkIter];
675     const gp_Pnt& aNode2 = theNodesXYZ[(aLinkIter + 1) % 3];
676
677     // Compute distance of uv points to isoline taking into consideration their relative
678     // location against the isoline (left or right). Null value for a node means that the
679     // isoline crosses the node. Both positive or negative means that the isoline does not
680     // cross the segment.
681     Standard_Boolean isLeftUV1 = (theIsoline.Direction().XY() ^ gp_Vec2d (theIsoline.Location(), aNodeUV1).XY()) > 0.0;
682     Standard_Boolean isLeftUV2 = (theIsoline.Direction().XY() ^ gp_Vec2d (theIsoline.Location(), aNodeUV2).XY()) > 0.0;
683     Standard_Real aDistanceUV1 = isLeftUV1 ? theIsoline.Distance (aNodeUV1) : -theIsoline.Distance (aNodeUV1);
684     Standard_Real aDistanceUV2 = isLeftUV2 ? theIsoline.Distance (aNodeUV2) : -theIsoline.Distance (aNodeUV2);
685
686     // Isoline crosses first point of an edge.
687     if (Abs (aDistanceUV1) < Precision::PConfusion())
688     {
689       theSegment[aNPoints].Param = theIsU ? aNodeUV1.Y() : aNodeUV1.X();
690       theSegment[aNPoints].Pnt   = aNode1;
691       ++aNPoints;
692       continue;
693     }
694
695     // Isoline crosses second point of an edge.
696     if (Abs (aDistanceUV2) < Precision::PConfusion())
697     {
698       theSegment[aNPoints].Param = theIsU ? aNodeUV2.Y() : aNodeUV2.X();
699       theSegment[aNPoints].Pnt   = aNode2;
700
701       ++aNPoints;
702       ++aLinkIter;
703       continue;
704     }
705
706     // Isoline does not cross the triangle link.
707     if (aDistanceUV1 * aDistanceUV2 > 0.0)
708     {
709       continue;
710     }
711
712     // Isoline crosses degenerated link.
713     if (aNode1.SquareDistance (aNode2) < Precision::PConfusion())
714     {
715       theSegment[aNPoints].Param = theIsU ? aNodeUV1.Y() : aNodeUV1.X();
716       theSegment[aNPoints].Pnt   = aNode1;
717       ++aNPoints;
718       continue;
719     }
720
721     // ...
722     // Derive cross-point from parametric coordinates
723     // ...
724
725     Standard_Real anAlpha = Abs (aDistanceUV1) / (Abs (aDistanceUV1) + Abs (aDistanceUV2));
726
727     gp_Pnt aCross (0.0, 0.0, 0.0);
728     Standard_Real aCrossU = aNodeUV1.X() + anAlpha * (aNodeUV2.X() - aNodeUV1.X());
729     Standard_Real aCrossV = aNodeUV1.Y() + anAlpha * (aNodeUV2.Y() - aNodeUV1.Y());
730     Standard_Real aCrossParam = theIsU ? aCrossV : aCrossU;
731     if (theSurface.IsNull())
732     {
733       // Do linear interpolation of point coordinates using triangulation nodes.
734       aCross.SetX (aNode1.X() + anAlpha * (aNode2.X() - aNode1.X()));
735       aCross.SetY (aNode1.Y() + anAlpha * (aNode2.Y() - aNode1.Y()));
736       aCross.SetZ (aNode1.Z() + anAlpha * (aNode2.Z() - aNode1.Z()));
737     }
738     else
739     {
740       // Do linear interpolation of point coordinates by triangulation nodes.
741       // Get 3d point on surface.
742       Handle(Geom_Curve) anIso1, anIso2, anIso3;
743       Standard_Real aPntOnNode1Iso = 0.0;
744       Standard_Real aPntOnNode2Iso = 0.0;
745       Standard_Real aPntOnNode3Iso = 0.0;
746
747       if (theIsoline.Direction().X() == 0.0)
748       {
749         aPntOnNode1Iso = aNodeUV1.X();
750         aPntOnNode2Iso = aNodeUV2.X();
751         aPntOnNode3Iso = aCrossU;
752         anIso1 = theSurface->VIso (aNodeUV1.Y());
753         anIso2 = theSurface->VIso (aNodeUV2.Y());
754         anIso3 = theSurface->VIso (aCrossV);
755       }
756       else if (theIsoline.Direction().Y() == 0.0)
757       {
758         aPntOnNode1Iso = aNodeUV1.Y();
759         aPntOnNode2Iso = aNodeUV2.Y();
760         aPntOnNode3Iso = aCrossV;
761         anIso1 = theSurface->UIso (aNodeUV1.X());
762         anIso2 = theSurface->UIso (aNodeUV2.X());
763         anIso3 = theSurface->UIso (aCrossU);
764       }
765
766       GeomAdaptor_Curve aCurveAdaptor1 (anIso1);
767       GeomAdaptor_Curve aCurveAdaptor2 (anIso2);
768       GeomAdaptor_Curve aCurveAdaptor3 (anIso3);
769       Standard_Real aLength1 = GCPnts_AbscissaPoint::Length (aCurveAdaptor1, aPntOnNode1Iso, aPntOnNode3Iso, 1e-2);
770       Standard_Real aLength2 = GCPnts_AbscissaPoint::Length (aCurveAdaptor2, aPntOnNode2Iso, aPntOnNode3Iso, 1e-2);
771       if (Abs (aLength1) < Precision::Confusion() || Abs (aLength2) < Precision::Confusion())
772       {
773         theSegment[aNPoints].Param = aCrossParam;
774         theSegment[aNPoints].Pnt   = (aNode2.XYZ() - aNode1.XYZ()) * anAlpha + aNode1.XYZ();
775         ++aNPoints;
776         continue;
777       }
778
779       aCross = (aNode2.XYZ() - aNode1.XYZ()) * (aLength1 / (aLength1 + aLength2)) + aNode1.XYZ();
780     }
781
782     theSegment[aNPoints].Param = aCrossParam;
783     theSegment[aNPoints].Pnt   = aCross;
784     ++aNPoints;
785   }
786
787   if (aNPoints != 2
788    || Abs (theSegment[1].Param - theSegment[0].Param) <= Precision::PConfusion())
789   {
790     return false;
791   }
792
793   if (theSegment[1].Param < theSegment[0].Param)
794   {
795     std::swap (theSegment[0], theSegment[1]);
796   }
797   return true;
798 }