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