0029915: Porting to VC 2017 : Regressions in Modeling Algorithms on VC 2017
[occt.git] / src / BRepOffset / BRepOffset_SimpleOffset.cxx
CommitLineData
8013367c 1// Created on: 2016-10-14
2// Created by: Alexander MALYSHEV
3// Copyright (c) 1995-1999 Matra Datavision
4// Copyright (c) 1999-2016 OPEN CASCADE SAS
5//
6// This file is part of Open CASCADE Technology software library.
7//
8// This library is free software; you can redistribute it and/or modify it under
9// the terms of the GNU Lesser General Public License version 2.1 as published
10// by the Free Software Foundation, with special exception defined in the file
11// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12// distribution for complete text of the license and disclaimer of any warranty.
13//
14// Alternatively, this file may be used under the terms of Open CASCADE
15// commercial license or contractual agreement.
16
17// Include self.
18#include <BRepOffset_SimpleOffset.hxx>
19
20#include <Adaptor3d_CurveOnSurface.hxx>
21#include <BRepBuilderAPI_MakeEdge.hxx>
22#include <BRepLib.hxx>
23#include <BRep_Tool.hxx>
8574e329 24#include <BRepOffset.hxx>
8013367c 25#include <Geom_OffsetSurface.hxx>
26#include <GeomAdaptor_Curve.hxx>
27#include <Geom2dAdaptor_HCurve.hxx>
28#include <GeomAdaptor_HSurface.hxx>
29#include <NCollection_Vector.hxx>
30#include <ShapeAnalysis_Edge.hxx>
31#include <TopExp.hxx>
32#include <TopExp_Explorer.hxx>
33#include <TopoDS.hxx>
34#include <TopoDS_Face.hxx>
35#include <TopoDS_Edge.hxx>
36#include <TopoDS_Vertex.hxx>
37
38static const Standard_Integer NCONTROL=22;
39
40
41//=============================================================================
42//function : BRepOffset_SimpleOffset
43//purpose : Constructor
44//=============================================================================
45BRepOffset_SimpleOffset::BRepOffset_SimpleOffset(const TopoDS_Shape& theInputShape,
8574e329 46 const Standard_Real theOffsetValue,
47 const Standard_Real theTolerance)
48: myOffsetValue(theOffsetValue),
49 myTolerance(theTolerance)
8013367c 50{
51 FillOffsetData(theInputShape);
52}
53
54//=============================================================================
55//function : NewSurface
56//purpose :
57//=============================================================================
58Standard_Boolean BRepOffset_SimpleOffset::NewSurface(const TopoDS_Face& F,
59 Handle(Geom_Surface)& S,
60 TopLoc_Location& L,
61 Standard_Real& Tol,
62 Standard_Boolean& RevWires,
63 Standard_Boolean& RevFace)
64{
65 if (!myFaceInfo.IsBound(F))
66 return Standard_False;
67
68 const NewFaceData& aNFD = myFaceInfo.Find(F);
69
70 S = aNFD.myOffsetS;
71 L = aNFD.myL;
72 Tol = aNFD.myTol;
73 RevWires = aNFD.myRevWires;
74 RevFace = aNFD.myRevFace;
75
76 return Standard_True;
77}
78
79//=============================================================================
80//function : NewCurve
81//purpose :
82//=============================================================================
83Standard_Boolean BRepOffset_SimpleOffset::NewCurve(const TopoDS_Edge& E,
84 Handle(Geom_Curve)& C,
85 TopLoc_Location& L,
86 Standard_Real& Tol)
87{
88 if (!myEdgeInfo.IsBound(E))
89 return Standard_False;
90
91 const NewEdgeData& aNED = myEdgeInfo.Find(E);
92
93 C = aNED.myOffsetC;
94 L = aNED.myL;
95 Tol = aNED.myTol;
96
97 return Standard_True;
98}
99
100//=============================================================================
101//function : NewPoint
102//purpose :
103//=============================================================================
104Standard_Boolean BRepOffset_SimpleOffset::NewPoint (const TopoDS_Vertex& V,
105 gp_Pnt& P,
106 Standard_Real& Tol)
107{
108 if (!myVertexInfo.IsBound(V))
109 return Standard_False;
110
111 const NewVertexData& aNVD = myVertexInfo.Find(V);
112
113 P = aNVD.myP;
114 Tol = aNVD.myTol;
115
116 return Standard_True;
117}
118
119//=============================================================================
120//function : NewCurve2d
121//purpose :
122//=============================================================================
123Standard_Boolean BRepOffset_SimpleOffset::NewCurve2d (const TopoDS_Edge& E,
124 const TopoDS_Face& F,
125 const TopoDS_Edge& /*NewE*/,
126 const TopoDS_Face& /*NewF*/,
127 Handle(Geom2d_Curve)& C,
128 Standard_Real& Tol)
129{
130 // Use original pcurve.
131 Standard_Real aF, aL;
132 C = BRep_Tool::CurveOnSurface(E, F, aF, aL);
133 Tol = BRep_Tool::Tolerance(E);
134
135 if (myEdgeInfo.IsBound(E))
136 Tol = myEdgeInfo.Find(E).myTol;
137
138 return Standard_True;
139}
140
141//=============================================================================
142//function : NewParameter
143//purpose :
144//=============================================================================
145Standard_Boolean BRepOffset_SimpleOffset::NewParameter (const TopoDS_Vertex& V,
146 const TopoDS_Edge& E,
147 Standard_Real& P,
148 Standard_Real& Tol)
149{
150 // Use original parameter.
151 P = BRep_Tool::Parameter(V, E);
152 Tol = BRep_Tool::Tolerance(V);
153
154 if (myVertexInfo.IsBound(V))
155 Tol = myVertexInfo.Find(V).myTol;
156
157 return Standard_True;
158}
159
160//=============================================================================
161//function : NewParameter
162//purpose :
163//=============================================================================
164GeomAbs_Shape BRepOffset_SimpleOffset::Continuity (const TopoDS_Edge& E,
165 const TopoDS_Face& F1,
166 const TopoDS_Face& F2,
167 const TopoDS_Edge& /*NewE*/,
168 const TopoDS_Face& /*NewF1*/,
169 const TopoDS_Face& /*NewF2*/)
170{
171 // Compute result using original continuity.
172 return BRep_Tool::Continuity(E, F1, F2);
173}
174
175//=============================================================================
176//function : FillOffsetData
177//purpose :
178//=============================================================================
179void BRepOffset_SimpleOffset::FillOffsetData(const TopoDS_Shape& theShape)
180{
181 // Clears old data.
182 myFaceInfo.Clear();
183 myEdgeInfo.Clear();
184 myVertexInfo.Clear();
185
186 // Faces loop. Compute offset surface for each face.
187 TopExp_Explorer anExpSF(theShape, TopAbs_FACE);
188 for(; anExpSF.More(); anExpSF.Next())
189 {
190 const TopoDS_Face& aCurrFace = TopoDS::Face(anExpSF.Current());
191 FillFaceData(aCurrFace);
192 }
193
194 // Iterate over edges to compute 3d curve.
195 TopTools_IndexedDataMapOfShapeListOfShape aEdgeFaceMap;
196 TopExp::MapShapesAndAncestors(theShape, TopAbs_EDGE, TopAbs_FACE, aEdgeFaceMap);
197 for (Standard_Integer anIdx = 1; anIdx <= aEdgeFaceMap.Size(); ++anIdx)
198 {
199 const TopoDS_Edge& aCurrEdge = TopoDS::Edge(aEdgeFaceMap.FindKey(anIdx));
200 FillEdgeData(aCurrEdge, aEdgeFaceMap, anIdx);
201 }
202
203 // Iterate over vertices to compute new vertex.
204 TopTools_IndexedDataMapOfShapeListOfShape aVertexEdgeMap;
205 TopExp::MapShapesAndAncestors(theShape, TopAbs_VERTEX, TopAbs_EDGE, aVertexEdgeMap);
206 for (Standard_Integer anIdx = 1; anIdx <= aVertexEdgeMap.Size(); ++anIdx)
207 {
208 const TopoDS_Vertex & aCurrVertex = TopoDS::Vertex(aVertexEdgeMap.FindKey(anIdx));
209 FillVertexData(aCurrVertex, aVertexEdgeMap, anIdx);
210 }
211}
212
213//=============================================================================
214//function : FillFaceData
215//purpose :
216//=============================================================================
217void BRepOffset_SimpleOffset::FillFaceData(const TopoDS_Face& theFace)
218{
219 NewFaceData aNFD;
220 aNFD.myRevWires = Standard_False;
221 aNFD.myRevFace = Standard_False;
222 aNFD.myTol = BRep_Tool::Tolerance(theFace);
223
224 // Create offset surface.
225
226 // Any existing transformation is applied to the surface.
227 // New face will have null transformation.
228 Handle(Geom_Surface) aS = BRep_Tool::Surface(theFace);
8574e329 229 aS = BRepOffset::CollapseSingularities (aS, theFace, myTolerance);
8013367c 230
231 // Take into account face orientation.
232 Standard_Real aMult = 1.0;
233 if (theFace.Orientation() == TopAbs_REVERSED)
234 aMult = -1.0;
235
236 aNFD.myOffsetS = new Geom_OffsetSurface(aS, aMult * myOffsetValue, Standard_True);
237 aNFD.myL = TopLoc_Location(); // Null transformation.
238
239 // Save offset surface in map.
240 myFaceInfo.Bind(theFace, aNFD);
241}
242
243//=============================================================================
244//function : FillEdgeData
245//purpose :
246//=============================================================================
247void BRepOffset_SimpleOffset::FillEdgeData(const TopoDS_Edge& theEdge,
248 const TopTools_IndexedDataMapOfShapeListOfShape& theEdgeFaceMap,
249 const Standard_Integer theIdx)
250{
251 const TopTools_ListOfShape& aFacesList = theEdgeFaceMap(theIdx);
252
253 if (aFacesList.Size() == 0)
254 return; // Free edges are skipped.
255
256 // Get offset surface.
257 const TopoDS_Face& aCurrFace = TopoDS::Face(aFacesList.First());
258
259 if (!myFaceInfo.IsBound(aCurrFace))
260 return;
261
262 // No need to deal with transformation - it is applied in fill faces data method.
263 const NewFaceData & aNFD = myFaceInfo.Find(aCurrFace);
264 Handle(Geom_Surface) anOffsetSurf = aNFD.myOffsetS;
265
266 // Compute offset 3d curve.
267 Standard_Real aF, aL;
268 Handle(Geom2d_Curve) aC2d = BRep_Tool::CurveOnSurface(theEdge, aCurrFace, aF, aL);
269
270 BRepBuilderAPI_MakeEdge anEdgeMaker(aC2d, anOffsetSurf, aF, aL);
271 TopoDS_Edge aNewEdge = anEdgeMaker.Edge();
272
273 // Compute max tolerance. Vertex tolerance usage is taken from existing offset computation algorithm.
274 // This piece of code significantly influences resulting performance.
275 Standard_Real aTol = BRep_Tool::MaxTolerance(theEdge, TopAbs_VERTEX);
276 BRepLib::BuildCurves3d(aNewEdge, aTol);
277
278 NewEdgeData aNED;
279 aNED.myOffsetC = BRep_Tool::Curve(aNewEdge, aNED.myL, aF, aL);
280
281 // Iterate over adjacent faces for the current edge and compute max deviation.
282 Standard_Real anEdgeTol = 0.0;
283 TopTools_ListOfShape::Iterator anIter(aFacesList);
284 for ( ; !aNED.myOffsetC.IsNull() && anIter.More() ; anIter.Next())
285 {
286 const TopoDS_Face& aCurFace = TopoDS::Face(anIter.Value());
287
288 if (!myFaceInfo.IsBound(aCurFace))
289 continue;
290
291 // Create offset curve on surface.
4d973358 292 const Handle(Geom2d_Curve) aC2dNew = BRep_Tool::CurveOnSurface(theEdge, aCurFace, aF, aL);
293 const Handle(Adaptor2d_HCurve2d) aHCurve2d = new Geom2dAdaptor_HCurve(aC2dNew, aF, aL);
8013367c 294 const Handle(Adaptor3d_HSurface) aHSurface = new GeomAdaptor_HSurface(myFaceInfo.Find(aCurFace).myOffsetS);
295 Adaptor3d_CurveOnSurface aCurveOnSurf(aHCurve2d, aHSurface);
296
297 // Extract 3d-curve (it is not null).
298 const GeomAdaptor_Curve aCurve3d(aNED.myOffsetC, aF, aL);
299
300 // It is necessary to compute maximal deviation (tolerance).
301 Standard_Real aMaxTol = 0.0;
302 ShapeAnalysis_Edge::ComputeDeviation(aCurve3d, aCurveOnSurf, Standard_True, aMaxTol, NCONTROL);
303 anEdgeTol = Max (anEdgeTol, aMaxTol);
304 }
305 aNED.myTol = Max(BRep_Tool::Tolerance(aNewEdge), anEdgeTol);
306
307 // Save computed 3d curve in map.
308 myEdgeInfo.Bind(theEdge, aNED);
309}
310
311//=============================================================================
312//function : FillVertexData
313//purpose :
314//=============================================================================
315void BRepOffset_SimpleOffset::FillVertexData(const TopoDS_Vertex& theVertex,
316 const TopTools_IndexedDataMapOfShapeListOfShape& theVertexEdgeMap,
317 const Standard_Integer theIdx)
318{
319 // Algorithm:
320 // Find adjacent edges for the given vertex.
321 // Find corresponding end on the each adjacent edge.
322 // Get offset points for founded end.
323 // Set result vertex position as barycenter of founded points.
324
325 gp_Pnt aCurrPnt = BRep_Tool::Pnt(theVertex);
326
327 const TopTools_ListOfShape& aEdgesList = theVertexEdgeMap(theIdx);
328
329 if (aEdgesList.Size() == 0)
330 return; // Free verices are skipped.
331
332 // Array to store offset points.
333 NCollection_Vector<gp_Pnt> anOffsetPointVec;
334
335 Standard_Real aMaxEdgeTol = 0.0;
336
337 // Iterate over adjacent edges.
338 TopTools_ListOfShape::Iterator anIterEdges(aEdgesList);
339 for (; anIterEdges.More() ; anIterEdges.Next() )
340 {
341 const TopoDS_Edge& aCurrEdge = TopoDS::Edge(anIterEdges.Value());
342
343 if (!myEdgeInfo.IsBound(aCurrEdge))
344 continue; // Skip shared edges with wrong orientation.
345
346 // Find the closest bound.
347 Standard_Real aF, aL;
348 Handle(Geom_Curve) aC3d = BRep_Tool::Curve(aCurrEdge, aF, aL);
349
350 // Protection from degenerated edges.
351 if (aC3d.IsNull())
352 continue;
353
354 const gp_Pnt aPntF = aC3d->Value(aF);
355 const gp_Pnt aPntL = aC3d->Value(aL);
356
357 const Standard_Real aSqDistF = aPntF.SquareDistance(aCurrPnt);
358 const Standard_Real aSqDistL = aPntL.SquareDistance(aCurrPnt);
359
360 Standard_Real aMinParam = aF, aMaxParam = aL;
361 if (aSqDistL < aSqDistF)
362 {
363 // Square distance to last point is closer.
364 aMinParam = aL; aMaxParam = aF;
365 }
366
367 // Compute point on offset edge.
368 const NewEdgeData& aNED = myEdgeInfo.Find(aCurrEdge);
369 const Handle(Geom_Curve) &anOffsetCurve = aNED.myOffsetC;
370 const gp_Pnt anOffsetPoint = anOffsetCurve->Value(aMinParam);
371 anOffsetPointVec.Append(anOffsetPoint);
372
373 // Handle situation when edge is closed.
374 TopoDS_Vertex aV1, aV2;
375 TopExp::Vertices(aCurrEdge, aV1, aV2);
376 if (aV1.IsSame(aV2))
377 {
4d973358 378 const gp_Pnt anOffsetPointLast = anOffsetCurve->Value(aMaxParam);
379 anOffsetPointVec.Append(anOffsetPointLast);
8013367c 380 }
381
382 aMaxEdgeTol = Max(aMaxEdgeTol, aNED.myTol);
383 }
384
385 // NCollection_Vector starts from 0 by default.
386 // It's better to use lower() and upper() in this case instead of direct indexes range.
387 gp_Pnt aCenter(0.0, 0.0, 0.0);
388 for(Standard_Integer i = anOffsetPointVec.Lower();
389 i <= anOffsetPointVec.Upper();
390 ++i)
391 {
392 aCenter.SetXYZ(aCenter.XYZ() + anOffsetPointVec.Value(i).XYZ());
393 }
394 aCenter.SetXYZ(aCenter.XYZ() / anOffsetPointVec.Size());
395
396 // Compute max distance.
397 Standard_Real aSqMaxDist = 0.0;
398 for(Standard_Integer i = anOffsetPointVec.Lower();
399 i <= anOffsetPointVec.Upper();
400 ++i)
401 {
402 const Standard_Real aSqDist = aCenter.SquareDistance(anOffsetPointVec.Value(i));
403 if (aSqDist > aSqMaxDist)
404 aSqMaxDist = aSqDist;
405 }
406
407 const Standard_Real aResTol = Max(aMaxEdgeTol, Sqrt(aSqMaxDist));
408
409 const Standard_Real aMultCoeff = 1.001; // Avoid tolernace problems.
410 NewVertexData aNVD;
411 aNVD.myP = aCenter;
412 aNVD.myTol = aResTol * aMultCoeff;
413
414 // Save computed vertex info.
415 myVertexInfo.Bind(theVertex, aNVD);
416}