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