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