1 // Created on: 2016-07-04
2 // Copyright (c) 2016 OPEN CASCADE SAS
3 // Created by: Oleg AGASHIN
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <BRepMesh_ModelPreProcessor.hxx>
17 #include <BRepMesh_Deflection.hxx>
18 #include <BRepMesh_ShapeTool.hxx>
19 #include <BRep_Tool.hxx>
20 #include <IMeshData_Model.hxx>
21 #include <IMeshData_Edge.hxx>
22 #include <IMeshData_Wire.hxx>
23 #include <IMeshData_PCurve.hxx>
24 #include <OSD_Parallel.hxx>
25 #include <BRepMesh_ConeRangeSplitter.hxx>
29 //! Checks consistency of triangulation stored in topological face.
30 class TriangulationConsistency
34 TriangulationConsistency(const Handle(IMeshData_Model)& theModel,
35 const Standard_Boolean theAllowQualityDecrease)
37 , myAllowQualityDecrease (theAllowQualityDecrease)
42 void operator()(const Standard_Integer theFaceIndex) const
44 const IMeshData::IFaceHandle& aDFace = myModel->GetFace(theFaceIndex);
45 if (aDFace->IsSet(IMeshData_Outdated))
51 const Handle(Poly_Triangulation)& aTriangulation =
52 BRep_Tool::Triangulation(aDFace->GetFace(), aLoc);
54 if (!aTriangulation.IsNull())
56 Standard_Boolean isTriangulationConsistent =
57 BRepMesh_Deflection::IsConsistent (aTriangulation->Deflection(),
58 aDFace->GetDeflection(),
59 myAllowQualityDecrease);
61 if (isTriangulationConsistent)
63 // #25080: check that indices of links forming triangles are in range.
64 const Standard_Integer aNodesNb = aTriangulation->NbNodes();
65 const Poly_Array1OfTriangle& aTriangles = aTriangulation->Triangles();
67 Standard_Integer i = aTriangles.Lower();
68 for (; i <= aTriangles.Upper() && isTriangulationConsistent; ++i)
70 const Poly_Triangle& aTriangle = aTriangles(i);
72 Standard_Integer aNode[3];
73 aTriangle.Get(aNode[0], aNode[1], aNode[2]);
74 for (Standard_Integer j = 0; j < 3 && isTriangulationConsistent; ++j)
76 isTriangulationConsistent = (aNode[j] >= 1 && aNode[j] <= aNodesNb);
81 if (isTriangulationConsistent)
83 aDFace->SetStatus(IMeshData_Reused);
84 aDFace->SetDeflection(aTriangulation->Deflection());
88 aDFace->SetStatus(IMeshData_Outdated);
95 Handle(IMeshData_Model) myModel;
96 Standard_Boolean myAllowQualityDecrease; //!< Flag used for consistency check
99 //! Adds additional points to seam edges on specific surfaces.
100 class SeamEdgeAmplifier
104 SeamEdgeAmplifier(const Handle(IMeshData_Model)& theModel,
105 const IMeshTools_Parameters& theParameters)
107 , myParameters (theParameters)
112 void operator()(const Standard_Integer theFaceIndex) const
114 const IMeshData::IFaceHandle& aDFace = myModel->GetFace(theFaceIndex);
115 if (aDFace->GetSurface()->GetType() != GeomAbs_Cone)
120 const IMeshData::IWireHandle& aDWire = aDFace->GetWire (0);
121 for (Standard_Integer aEdgeIdx = 0; aEdgeIdx < aDWire->EdgesNb() - 1; ++aEdgeIdx)
123 const IMeshData::IEdgePtr& aDEdge = aDWire->GetEdge (aEdgeIdx);
125 if (aDEdge->GetPCurve(aDFace.get(), TopAbs_FORWARD) != aDEdge->GetPCurve(aDFace.get(), TopAbs_REVERSED))
127 if (aDEdge->GetCurve()->ParametersNb() == 2)
129 if (splitEdge (aDEdge, Abs (getConeStep (aDFace))))
131 TopLoc_Location aLoc;
132 const Handle (Poly_Triangulation)& aTriangulation =
133 BRep_Tool::Triangulation (aDFace->GetFace (), aLoc);
135 if (!aTriangulation.IsNull ())
137 aDFace->SetStatus (IMeshData_Outdated);
148 //! Returns step for splitting seam edge of a cone.
149 Standard_Real getConeStep(const IMeshData::IFaceHandle& theDFace) const
151 BRepMesh_ConeRangeSplitter aSplitter;
152 aSplitter.Reset (theDFace, myParameters);
154 const IMeshData::IWireHandle& aDWire = theDFace->GetWire (0);
155 for (Standard_Integer aEdgeIt = 0; aEdgeIt < aDWire->EdgesNb(); ++aEdgeIt)
157 const IMeshData::IEdgeHandle aDEdge = aDWire->GetEdge(aEdgeIt);
158 const IMeshData::IPCurveHandle& aPCurve = aDEdge->GetPCurve(
159 theDFace.get(), aDWire->GetEdgeOrientation(aEdgeIt));
161 for (Standard_Integer aPointIt = 0; aPointIt < aPCurve->ParametersNb(); ++aPointIt)
163 const gp_Pnt2d& aPnt2d = aPCurve->GetPoint(aPointIt);
164 aSplitter.AddPoint(aPnt2d);
168 std::pair<Standard_Integer, Standard_Integer> aStepsNb;
169 std::pair<Standard_Real, Standard_Real> aSteps = aSplitter.GetSplitSteps (myParameters, aStepsNb);
170 return aSteps.second;
173 //! Splits 3D and all pcurves accoring using the specified step.
174 Standard_Boolean splitEdge(const IMeshData::IEdgePtr& theDEdge,
175 const Standard_Real theDU) const
177 if (!splitCurve<gp_XYZ> (theDEdge->GetCurve (), theDU))
179 return Standard_False;
182 for (Standard_Integer aPCurveIdx = 0; aPCurveIdx < theDEdge->PCurvesNb(); ++aPCurveIdx)
184 splitCurve<gp_XY> (theDEdge->GetPCurve (aPCurveIdx), theDU);
187 return Standard_True;
190 //! Splits the given curve using the specified step.
191 template<class PointType, class Curve>
192 Standard_Boolean splitCurve(Curve& theCurve, const Standard_Real theDU) const
194 Standard_Boolean isUpdated = Standard_False;
195 PointType aDir = theCurve->GetPoint(theCurve->ParametersNb() - 1).Coord() - theCurve->GetPoint(0).Coord();
196 const Standard_Real aModulus = aDir.Modulus();
197 if (aModulus < gp::Resolution())
203 const Standard_Real aLastParam = theCurve->GetParameter(theCurve->ParametersNb() - 1);
204 const Standard_Boolean isReversed = theCurve->GetParameter(0) > aLastParam;
205 for (Standard_Integer aPointIdx = 1; ; ++aPointIdx)
207 const Standard_Real aCurrParam = theCurve->GetParameter(0) + aPointIdx * theDU * (isReversed ? -1.0 : 1.0);
208 if (( isReversed && (aCurrParam < aLastParam)) ||
209 (!isReversed && !(aCurrParam < aLastParam)))
214 theCurve->InsertPoint(theCurve->ParametersNb() - 1,
215 theCurve->GetPoint(0).Translated (aDir * aPointIdx * theDU),
218 isUpdated = Standard_True;
226 Handle(IMeshData_Model) myModel;
227 IMeshTools_Parameters myParameters;
231 //=======================================================================
232 // Function: Constructor
234 //=======================================================================
235 BRepMesh_ModelPreProcessor::BRepMesh_ModelPreProcessor()
239 //=======================================================================
240 // Function: Destructor
242 //=======================================================================
243 BRepMesh_ModelPreProcessor::~BRepMesh_ModelPreProcessor()
247 //=======================================================================
250 //=======================================================================
251 Standard_Boolean BRepMesh_ModelPreProcessor::performInternal(
252 const Handle(IMeshData_Model)& theModel,
253 const IMeshTools_Parameters& theParameters)
255 if (theModel.IsNull())
257 return Standard_False;
260 const Standard_Integer aFacesNb = theModel->FacesNb();
261 const Standard_Boolean isOneThread = !theParameters.InParallel;
262 OSD_Parallel::For(0, aFacesNb, SeamEdgeAmplifier (theModel, theParameters), isOneThread);
263 OSD_Parallel::For(0, aFacesNb, TriangulationConsistency (theModel, theParameters.AllowQualityDecrease), isOneThread);
265 // Clean edges and faces from outdated polygons.
266 Handle(NCollection_IncAllocator) aTmpAlloc(new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE));
267 NCollection_Map<IMeshData_Face*> aUsedFaces(1, aTmpAlloc);
268 for (Standard_Integer aEdgeIt = 0; aEdgeIt < theModel->EdgesNb(); ++aEdgeIt)
270 const IMeshData::IEdgeHandle& aDEdge = theModel->GetEdge(aEdgeIt);
271 if (aDEdge->IsFree())
273 if (aDEdge->IsSet(IMeshData_Outdated))
275 TopLoc_Location aLoc;
276 BRep_Tool::Polygon3D(aDEdge->GetEdge(), aLoc);
277 BRepMesh_ShapeTool::NullifyEdge(aDEdge->GetEdge(), aLoc);
283 for (Standard_Integer aPCurveIt = 0; aPCurveIt < aDEdge->PCurvesNb(); ++aPCurveIt)
285 // Find adjacent outdated face.
286 const IMeshData::IFaceHandle aDFace = aDEdge->GetPCurve(aPCurveIt)->GetFace();
287 if (!aUsedFaces.Contains(aDFace.get()))
289 aUsedFaces.Add(aDFace.get());
290 if (aDFace->IsSet(IMeshData_Outdated))
292 TopLoc_Location aLoc;
293 const Handle(Poly_Triangulation)& aTriangulation =
294 BRep_Tool::Triangulation(aDFace->GetFace(), aLoc);
296 // Clean all edges of oudated face.
297 for (Standard_Integer aWireIt = 0; aWireIt < aDFace->WiresNb(); ++aWireIt)
299 const IMeshData::IWireHandle& aDWire = aDFace->GetWire(aWireIt);
300 for (Standard_Integer aWireEdgeIt = 0; aWireEdgeIt < aDWire->EdgesNb(); ++aWireEdgeIt)
302 const IMeshData::IEdgeHandle aTmpDEdge = aDWire->GetEdge(aWireEdgeIt);
303 BRepMesh_ShapeTool::NullifyEdge(aTmpDEdge->GetEdge(), aTriangulation, aLoc);
307 BRepMesh_ShapeTool::NullifyFace(aDFace->GetFace());
313 return Standard_True;