0033661: Data Exchange, Step Import - Tessellated GDTs are not imported
[occt.git] / src / BRepMesh / BRepMesh_ModelPreProcessor.cxx
CommitLineData
7bd071ed 1// Created on: 2016-07-04
2// Copyright (c) 2016 OPEN CASCADE SAS
3// Created by: Oleg AGASHIN
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 <BRepMesh_ModelPreProcessor.hxx>
33a4d46b 17
128654b6 18#include <BRepMesh_Deflection.hxx>
7bd071ed 19#include <BRepMesh_ShapeTool.hxx>
7bd071ed 20#include <IMeshData_Model.hxx>
21#include <IMeshData_Edge.hxx>
22#include <IMeshData_Wire.hxx>
23#include <IMeshData_PCurve.hxx>
33a4d46b 24#include <IMeshTools_Parameters.hxx>
7bd071ed 25#include <OSD_Parallel.hxx>
dc57476a 26#include <BRepMesh_ConeRangeSplitter.hxx>
f1c034f9 27#include <Poly_TriangulationParameters.hxx>
7bd071ed 28
4945e8be 29IMPLEMENT_STANDARD_RTTIEXT(BRepMesh_ModelPreProcessor, IMeshTools_ModelAlgo)
30
7bd071ed 31namespace
32{
33 //! Checks consistency of triangulation stored in topological face.
34 class TriangulationConsistency
35 {
36 public:
37 //! Constructor
128654b6 38 TriangulationConsistency(const Handle(IMeshData_Model)& theModel,
39 const Standard_Boolean theAllowQualityDecrease)
7bd071ed 40 : myModel (theModel)
128654b6 41 , myAllowQualityDecrease (theAllowQualityDecrease)
7bd071ed 42 {
43 }
44
45 //! Main functor.
46 void operator()(const Standard_Integer theFaceIndex) const
47 {
48 const IMeshData::IFaceHandle& aDFace = myModel->GetFace(theFaceIndex);
1593d38b 49 if (aDFace->IsSet(IMeshData_Outdated) ||
50 aDFace->GetFace().IsNull())
7bd071ed 51 {
52 return;
53 }
54
55 TopLoc_Location aLoc;
56 const Handle(Poly_Triangulation)& aTriangulation =
57 BRep_Tool::Triangulation(aDFace->GetFace(), aLoc);
58
59 if (!aTriangulation.IsNull())
60 {
f1c034f9 61 // If there is an info about initial parameters, use it due to deflection kept
62 // by Poly_Triangulation is generally an estimation upon generated mesh and can
63 // be either less or even greater than specified value.
64 const Handle(Poly_TriangulationParameters)& aSourceParams = aTriangulation->Parameters();
65 const Standard_Real aDeflection = (!aSourceParams.IsNull() && aSourceParams->HasDeflection()) ?
66 aSourceParams->Deflection() : aTriangulation->Deflection();
67
7bd071ed 68 Standard_Boolean isTriangulationConsistent =
f1c034f9 69 BRepMesh_Deflection::IsConsistent (aDeflection,
128654b6 70 aDFace->GetDeflection(),
71 myAllowQualityDecrease);
7bd071ed 72
73 if (isTriangulationConsistent)
74 {
75 // #25080: check that indices of links forming triangles are in range.
a8b605eb 76 for (Standard_Integer i = 1; i <= aTriangulation->NbTriangles() && isTriangulationConsistent; ++i)
7bd071ed 77 {
a8b605eb 78 const Poly_Triangle aTriangle = aTriangulation->Triangle (i);
7bd071ed 79
80 Standard_Integer aNode[3];
81 aTriangle.Get(aNode[0], aNode[1], aNode[2]);
82 for (Standard_Integer j = 0; j < 3 && isTriangulationConsistent; ++j)
83 {
a8b605eb 84 isTriangulationConsistent = (aNode[j] >= 1 && aNode[j] <= aTriangulation->NbNodes());
7bd071ed 85 }
86 }
87 }
88
89 if (isTriangulationConsistent)
90 {
91 aDFace->SetStatus(IMeshData_Reused);
92 aDFace->SetDeflection(aTriangulation->Deflection());
93 }
94 else
95 {
96 aDFace->SetStatus(IMeshData_Outdated);
97 }
98 }
99 }
100
101 private:
102
103 Handle(IMeshData_Model) myModel;
128654b6 104 Standard_Boolean myAllowQualityDecrease; //!< Flag used for consistency check
7bd071ed 105 };
dc57476a 106
107 //! Adds additional points to seam edges on specific surfaces.
108 class SeamEdgeAmplifier
109 {
110 public:
111 //! Constructor
112 SeamEdgeAmplifier(const Handle(IMeshData_Model)& theModel,
113 const IMeshTools_Parameters& theParameters)
114 : myModel (theModel)
115 , myParameters (theParameters)
116 {
117 }
118
119 //! Main functor.
120 void operator()(const Standard_Integer theFaceIndex) const
121 {
122 const IMeshData::IFaceHandle& aDFace = myModel->GetFace(theFaceIndex);
1593d38b 123 if (aDFace->GetSurface()->GetType() != GeomAbs_Cone || aDFace->IsSet(IMeshData_Failure))
dc57476a 124 {
125 return;
126 }
127
128 const IMeshData::IWireHandle& aDWire = aDFace->GetWire (0);
129 for (Standard_Integer aEdgeIdx = 0; aEdgeIdx < aDWire->EdgesNb() - 1; ++aEdgeIdx)
130 {
131 const IMeshData::IEdgePtr& aDEdge = aDWire->GetEdge (aEdgeIdx);
1593d38b 132
dc57476a 133 if (aDEdge->GetPCurve(aDFace.get(), TopAbs_FORWARD) != aDEdge->GetPCurve(aDFace.get(), TopAbs_REVERSED))
134 {
135 if (aDEdge->GetCurve()->ParametersNb() == 2)
136 {
0b6a0adb 137 if (splitEdge (aDEdge, aDFace, Abs (getConeStep (aDFace))))
dc57476a 138 {
139 TopLoc_Location aLoc;
140 const Handle (Poly_Triangulation)& aTriangulation =
141 BRep_Tool::Triangulation (aDFace->GetFace (), aLoc);
142
143 if (!aTriangulation.IsNull ())
144 {
145 aDFace->SetStatus (IMeshData_Outdated);
146 }
147 }
148 }
149 return;
1593d38b 150 }
dc57476a 151 }
152 }
153
154 private:
155
156 //! Returns step for splitting seam edge of a cone.
157 Standard_Real getConeStep(const IMeshData::IFaceHandle& theDFace) const
158 {
159 BRepMesh_ConeRangeSplitter aSplitter;
160 aSplitter.Reset (theDFace, myParameters);
161
162 const IMeshData::IWireHandle& aDWire = theDFace->GetWire (0);
163 for (Standard_Integer aEdgeIt = 0; aEdgeIt < aDWire->EdgesNb(); ++aEdgeIt)
164 {
165 const IMeshData::IEdgeHandle aDEdge = aDWire->GetEdge(aEdgeIt);
166 const IMeshData::IPCurveHandle& aPCurve = aDEdge->GetPCurve(
167 theDFace.get(), aDWire->GetEdgeOrientation(aEdgeIt));
168
169 for (Standard_Integer aPointIt = 0; aPointIt < aPCurve->ParametersNb(); ++aPointIt)
170 {
171 const gp_Pnt2d& aPnt2d = aPCurve->GetPoint(aPointIt);
172 aSplitter.AddPoint(aPnt2d);
173 }
174 }
175
176 std::pair<Standard_Integer, Standard_Integer> aStepsNb;
177 std::pair<Standard_Real, Standard_Real> aSteps = aSplitter.GetSplitSteps (myParameters, aStepsNb);
178 return aSteps.second;
179 }
180
b81b237f 181 //! Splits 3D and all pcurves accordingly using the specified step.
0b6a0adb 182 Standard_Boolean splitEdge(const IMeshData::IEdgePtr& theDEdge,
183 const IMeshData::IFaceHandle& theDFace,
184 const Standard_Real theDU) const
dc57476a 185 {
0b6a0adb 186 TopoDS_Edge aE = theDEdge->GetEdge();
187 const TopoDS_Face& aF = theDFace->GetFace();
188
189 Standard_Real aFParam, aLParam;
190
191 Handle(Geom_Curve) aHC = BRep_Tool::Curve (aE, aFParam, aLParam);
192
193 const IMeshData::IPCurveHandle& aIPC1 = theDEdge->GetPCurve(0);
194 const IMeshData::IPCurveHandle& aIPC2 = theDEdge->GetPCurve(1);
195
196 // Calculate the step by parameter of the curve.
197 const gp_Pnt2d& aFPntOfIPC1 = aIPC1->GetPoint (0);
198 const gp_Pnt2d& aLPntOfIPC1 = aIPC1->GetPoint (aIPC1->ParametersNb() - 1);
199 const Standard_Real aMod = Abs (aFPntOfIPC1.Y() - aLPntOfIPC1.Y());
200
201 if (aMod < gp::Resolution())
202 {
203 return Standard_False;
204 }
205
206 const Standard_Real aDT = Abs (aLParam - aFParam) / aMod * theDU;
207
208 if (!splitCurve<gp_Pnt> (aHC, theDEdge->GetCurve(), aDT))
209 {
210 return Standard_False;
211 }
212
213 // Define two pcurves of the seam-edge.
214 Handle(Geom2d_Curve) aPC1, aPC2;
215 Standard_Real af, al;
216
217 aE.Orientation (TopAbs_FORWARD);
218 aPC1 = BRep_Tool::CurveOnSurface (aE, aF, af, al);
219
220 aE.Orientation (TopAbs_REVERSED);
221 aPC2 = BRep_Tool::CurveOnSurface (aE, aF, af, al);
222
223 if (aPC1.IsNull() || aPC2.IsNull())
dc57476a 224 {
225 return Standard_False;
226 }
227
0b6a0adb 228 // Select the correct pcurve of the seam-edge.
229 const gp_Pnt2d& aFPntOfPC1 = aPC1->Value (aPC1->FirstParameter());
230
231 if (Abs (aLPntOfIPC1.X() - aFPntOfPC1.X()) > Precision::Confusion())
dc57476a 232 {
0b6a0adb 233 std::swap (aPC1, aPC2);
dc57476a 234 }
235
0b6a0adb 236 splitCurve<gp_Pnt2d> (aPC1, aIPC1, aDT);
237 splitCurve<gp_Pnt2d> (aPC2, aIPC2, aDT);
238
dc57476a 239 return Standard_True;
240 }
241
242 //! Splits the given curve using the specified step.
0b6a0adb 243 template<class PointType, class GeomCurve, class Curve>
244 Standard_Boolean splitCurve(GeomCurve& theGeomCurve,
245 Curve& theCurve,
246 const Standard_Real theDT) const
dc57476a 247 {
248 Standard_Boolean isUpdated = Standard_False;
dc57476a 249
0b6a0adb 250 const Standard_Real aFirstParam = theCurve->GetParameter (0);
251 const Standard_Real aLastParam = theCurve->GetParameter (theCurve->ParametersNb() - 1);
252 const Standard_Boolean isReversed = aFirstParam > aLastParam;
253
dc57476a 254 for (Standard_Integer aPointIdx = 1; ; ++aPointIdx)
255 {
0b6a0adb 256 const Standard_Real aCurrParam = aFirstParam + aPointIdx * theDT * (isReversed ? -1.0 : 1.0);
257 if (( isReversed && (aCurrParam - aLastParam < Precision::PConfusion())) ||
258 (!isReversed && !(aCurrParam - aLastParam < - Precision::PConfusion())))
dc57476a 259 {
260 break;
261 }
262
0b6a0adb 263 theCurve->InsertPoint (theCurve->ParametersNb() - 1,
264 theGeomCurve->Value (aCurrParam),
dc57476a 265 aCurrParam);
266
267 isUpdated = Standard_True;
268 }
269
270 return isUpdated;
271 }
272
273 private:
274
275 Handle(IMeshData_Model) myModel;
276 IMeshTools_Parameters myParameters;
277 };
7bd071ed 278}
279
280//=======================================================================
281// Function: Constructor
282// Purpose :
283//=======================================================================
284BRepMesh_ModelPreProcessor::BRepMesh_ModelPreProcessor()
285{
286}
287
288//=======================================================================
289// Function: Destructor
290// Purpose :
291//=======================================================================
292BRepMesh_ModelPreProcessor::~BRepMesh_ModelPreProcessor()
293{
294}
295
296//=======================================================================
297// Function: Perform
298// Purpose :
299//=======================================================================
c2a25d52 300Standard_Boolean BRepMesh_ModelPreProcessor::performInternal(
7bd071ed 301 const Handle(IMeshData_Model)& theModel,
ce97cd97 302 const IMeshTools_Parameters& theParameters,
303 const Message_ProgressRange& theRange)
7bd071ed 304{
ce97cd97 305 (void )theRange;
7bd071ed 306 if (theModel.IsNull())
307 {
308 return Standard_False;
309 }
310
128654b6 311 const Standard_Integer aFacesNb = theModel->FacesNb();
312 const Standard_Boolean isOneThread = !theParameters.InParallel;
313 OSD_Parallel::For(0, aFacesNb, SeamEdgeAmplifier (theModel, theParameters), isOneThread);
314 OSD_Parallel::For(0, aFacesNb, TriangulationConsistency (theModel, theParameters.AllowQualityDecrease), isOneThread);
7bd071ed 315
316 // Clean edges and faces from outdated polygons.
317 Handle(NCollection_IncAllocator) aTmpAlloc(new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE));
318 NCollection_Map<IMeshData_Face*> aUsedFaces(1, aTmpAlloc);
319 for (Standard_Integer aEdgeIt = 0; aEdgeIt < theModel->EdgesNb(); ++aEdgeIt)
320 {
321 const IMeshData::IEdgeHandle& aDEdge = theModel->GetEdge(aEdgeIt);
322 if (aDEdge->IsFree())
323 {
324 if (aDEdge->IsSet(IMeshData_Outdated))
325 {
326 TopLoc_Location aLoc;
327 BRep_Tool::Polygon3D(aDEdge->GetEdge(), aLoc);
328 BRepMesh_ShapeTool::NullifyEdge(aDEdge->GetEdge(), aLoc);
329 }
330
331 continue;
332 }
333
334 for (Standard_Integer aPCurveIt = 0; aPCurveIt < aDEdge->PCurvesNb(); ++aPCurveIt)
335 {
336 // Find adjacent outdated face.
337 const IMeshData::IFaceHandle aDFace = aDEdge->GetPCurve(aPCurveIt)->GetFace();
338 if (!aUsedFaces.Contains(aDFace.get()))
339 {
340 aUsedFaces.Add(aDFace.get());
341 if (aDFace->IsSet(IMeshData_Outdated))
342 {
343 TopLoc_Location aLoc;
344 const Handle(Poly_Triangulation)& aTriangulation =
345 BRep_Tool::Triangulation(aDFace->GetFace(), aLoc);
346
347 // Clean all edges of oudated face.
348 for (Standard_Integer aWireIt = 0; aWireIt < aDFace->WiresNb(); ++aWireIt)
349 {
350 const IMeshData::IWireHandle& aDWire = aDFace->GetWire(aWireIt);
351 for (Standard_Integer aWireEdgeIt = 0; aWireEdgeIt < aDWire->EdgesNb(); ++aWireEdgeIt)
352 {
353 const IMeshData::IEdgeHandle aTmpDEdge = aDWire->GetEdge(aWireEdgeIt);
354 BRepMesh_ShapeTool::NullifyEdge(aTmpDEdge->GetEdge(), aTriangulation, aLoc);
355 }
356 }
357
358 BRepMesh_ShapeTool::NullifyFace(aDFace->GetFace());
359 }
360 }
361 }
362 }
363
364 return Standard_True;
365}
366