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