ceb418e1 |
1 | // Created on: 2014-08-13 |
2 | // Created by: Oleg AGASHIN |
3 | // Copyright (c) 2011-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 <BRepMesh_EdgeTessellator.hxx> |
17 | #include <Geom_Surface.hxx> |
18 | #include <Geom_Plane.hxx> |
19 | #include <Geom2d_Curve.hxx> |
81093856 |
20 | #include <Geom2dAdaptor_Curve.hxx> |
ceb418e1 |
21 | #include <TopoDS_Edge.hxx> |
22 | #include <TopoDS_Face.hxx> |
23 | #include <BRepAdaptor_HSurface.hxx> |
24 | #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx> |
25 | #include <TopLoc_Location.hxx> |
26 | #include <BRep_Tool.hxx> |
27 | #include <TColStd_Array1OfReal.hxx> |
28 | #include <TopExp_Explorer.hxx> |
29 | #include <TopoDS_Vertex.hxx> |
30 | #include <TopoDS.hxx> |
31 | #include <TopTools_ListIteratorOfListOfShape.hxx> |
32 | #include <TopTools_ListOfShape.hxx> |
33 | #include <TColStd_Array1OfReal.hxx> |
34 | |
ceb418e1 |
35 | |
92efcf78 |
36 | IMPLEMENT_STANDARD_RTTIEXT(BRepMesh_EdgeTessellator,BRepMesh_IEdgeTool) |
37 | |
ceb418e1 |
38 | //======================================================================= |
39 | //function : Constructor |
40 | //purpose : |
41 | //======================================================================= |
42 | BRepMesh_EdgeTessellator::BRepMesh_EdgeTessellator( |
43 | const TopoDS_Edge& theEdge, |
44 | const Handle(BRepMesh_FaceAttribute)& theFaceAttribute, |
45 | const TopTools_IndexedDataMapOfShapeListOfShape& theMapOfSharedFaces, |
46 | const Standard_Real theLinDeflection, |
74da0216 |
47 | const Standard_Real theAngDeflection, |
48 | const Standard_Real theMinSize) |
ceb418e1 |
49 | : mySurface(theFaceAttribute->Surface()) |
50 | { |
51 | Standard_Real aPreciseAngDef = 0.5 * theAngDeflection; |
52 | Standard_Real aPreciseLinDef = 0.5 * theLinDeflection; |
53 | if (theEdge.Orientation() == TopAbs_INTERNAL) |
54 | aPreciseLinDef *= 0.5; |
55 | |
56 | mySquareEdgeDef = aPreciseLinDef * aPreciseLinDef; |
74da0216 |
57 | mySquareMinSize = Max(mySquareEdgeDef, theMinSize * theMinSize); |
660b601e |
58 | myEdgeSqTol = BRep_Tool::Tolerance (theEdge); |
59 | myEdgeSqTol *= myEdgeSqTol; |
ceb418e1 |
60 | |
61 | Standard_Boolean isSameParam = BRep_Tool::SameParameter(theEdge); |
62 | if (isSameParam) |
63 | myCOnS.Initialize(theEdge); |
64 | else |
65 | myCOnS.Initialize(theEdge, theFaceAttribute->Face()); |
66 | |
ceb418e1 |
67 | const GeomAbs_CurveType aCurveType = myCOnS.GetType(); |
68 | Standard_Integer aMinPntNb = (aCurveType == GeomAbs_Circle) ? 4 : 2; //OCC287 |
69 | |
81093856 |
70 | // Get 2d curve and init geom tool |
ceb418e1 |
71 | Standard_Real aFirstParam, aLastParam; |
81093856 |
72 | Handle(Geom2d_Curve) aCurve2d = |
73 | BRep_Tool::CurveOnSurface(theEdge, theFaceAttribute->Face(), aFirstParam, aLastParam); |
74 | myCurve2d.Load(aCurve2d, aFirstParam, aLastParam); |
ceb418e1 |
75 | myTool = new BRepMesh_GeomTool(myCOnS, aFirstParam, aLastParam, |
74da0216 |
76 | aPreciseLinDef, aPreciseAngDef, aMinPntNb, theMinSize); |
ceb418e1 |
77 | |
78 | if (aCurveType == GeomAbs_BSplineCurve) |
79 | { |
77e39787 |
80 | // bug24220 |
ceb418e1 |
81 | const Standard_Integer aNbInt = myCOnS.NbIntervals(GeomAbs_C1); |
cde381c4 |
82 | if ( aNbInt > 1 ) |
ceb418e1 |
83 | { |
84 | TColStd_Array1OfReal anIntervals( 1, aNbInt + 1 ); |
85 | myCOnS.Intervals(anIntervals, GeomAbs_C1); |
86 | for (Standard_Integer aIntIt = 1; aIntIt <= aNbInt; ++aIntIt) |
87 | { |
88 | const Standard_Real& aStartInt = anIntervals.Value( aIntIt ); |
89 | const Standard_Real& anEndInt = anIntervals.Value( aIntIt + 1 ); |
90 | |
91 | BRepMesh_GeomTool aDetalizator(myCOnS, aStartInt, anEndInt, |
74da0216 |
92 | aPreciseLinDef, aPreciseAngDef, aMinPntNb, theMinSize); |
ceb418e1 |
93 | |
94 | Standard_Integer aNbAddNodes = aDetalizator.NbPoints(); |
95 | for ( Standard_Integer aNodeIt = 1; aNodeIt <= aNbAddNodes; ++aNodeIt ) |
96 | { |
97 | Standard_Real aParam; |
98 | gp_Pnt aPoint3d; |
99 | gp_Pnt2d aPoint2d; |
81093856 |
100 | aDetalizator.Value( aNodeIt, aParam, aPoint3d); |
101 | myCurve2d.D0(aParam, aPoint2d); |
102 | |
ceb418e1 |
103 | myTool->AddPoint( aPoint3d, aParam, Standard_False ); |
104 | } |
105 | } |
106 | } |
107 | } |
77e39787 |
108 | |
ceb418e1 |
109 | // PTv, chl/922/G9, Take into account internal vertices |
110 | // it is necessary for internal edges, which do not split other edges, by their vertex |
111 | TopExp_Explorer aVertexIt(theEdge, TopAbs_VERTEX); |
112 | for (; aVertexIt.More(); aVertexIt.Next()) |
113 | { |
114 | const TopoDS_Vertex& aVertex = TopoDS::Vertex(aVertexIt.Current()); |
115 | if (aVertex.Orientation() != TopAbs_INTERNAL) |
116 | continue; |
117 | |
118 | myTool->AddPoint(BRep_Tool::Pnt(aVertex), |
119 | BRep_Tool::Parameter(aVertex, theEdge), Standard_True); |
120 | } |
121 | |
122 | Standard_Integer aNodesNb = myTool->NbPoints(); |
123 | //Check deflection in 2d space for improvement of edge tesselation. |
124 | if( isSameParam && aNodesNb > 1) |
125 | { |
126 | const TopTools_ListOfShape& aSharedFaces = theMapOfSharedFaces.FindFromKey(theEdge); |
127 | TopTools_ListIteratorOfListOfShape aFaceIt(aSharedFaces); |
128 | for (; aFaceIt.More(); aFaceIt.Next()) |
129 | { |
81093856 |
130 | const TopoDS_Face& aFace = TopoDS::Face(aFaceIt.Value()); |
131 | BRepAdaptor_Surface aSurf(aFace, Standard_False); |
ceb418e1 |
132 | |
81093856 |
133 | if (aSurf.GetType() == GeomAbs_Plane) |
ceb418e1 |
134 | continue; |
135 | |
136 | Standard_Real aF, aL; |
6482df81 |
137 | aCurve2d = BRep_Tool::CurveOnSurface(theEdge, aFace, aF, aL); |
ceb418e1 |
138 | if ( Abs(aF - aFirstParam) > Precision::PConfusion() || |
139 | Abs(aL - aLastParam ) > Precision::PConfusion() ) |
140 | { |
141 | continue; |
142 | } |
81093856 |
143 | Geom2dAdaptor_Curve aGACurve(aCurve2d, aF, aL); |
ceb418e1 |
144 | |
145 | aNodesNb = myTool->NbPoints(); |
146 | TColStd_Array1OfReal aParamArray(1, aNodesNb); |
147 | for (Standard_Integer i = 1; i <= aNodesNb; ++i) |
148 | { |
ceb418e1 |
149 | gp_Pnt aTmpPnt; |
150 | Standard_Real aParam; |
81093856 |
151 | myTool->Value(i, aParam, aTmpPnt); |
ceb418e1 |
152 | aParamArray.SetValue(i, aParam); |
153 | } |
154 | |
155 | for (Standard_Integer i = 1; i < aNodesNb; ++i) |
81093856 |
156 | splitSegment(aSurf, aGACurve, aParamArray(i), aParamArray(i + 1), 1); |
ceb418e1 |
157 | } |
158 | } |
660b601e |
159 | |
160 | const Standard_Real aTol = Precision::Confusion(); |
161 | const Standard_Real aDu = mySurface->UResolution (aTol); |
162 | const Standard_Real aDv = mySurface->VResolution (aTol); |
163 | |
164 | myFaceRangeU[0] = mySurface->FirstUParameter() - aDu; |
165 | myFaceRangeU[1] = mySurface->LastUParameter() + aDu; |
166 | |
167 | myFaceRangeV[0] = mySurface->FirstVParameter() - aDv; |
168 | myFaceRangeV[1] = mySurface->LastVParameter() + aDv; |
ceb418e1 |
169 | } |
170 | |
171 | //======================================================================= |
172 | //function : Value |
173 | //purpose : |
174 | //======================================================================= |
660b601e |
175 | Standard_Boolean BRepMesh_EdgeTessellator::Value( |
176 | const Standard_Integer theIndex, |
177 | Standard_Real& theParameter, |
178 | gp_Pnt& thePoint, |
179 | gp_Pnt2d& theUV) |
ceb418e1 |
180 | { |
81093856 |
181 | myTool->Value(theIndex, theParameter, thePoint); |
182 | myCurve2d.D0(theParameter, theUV); |
660b601e |
183 | |
184 | // If point coordinates are out of surface range, |
185 | // it is necessary to re-project point. |
186 | if (mySurface->GetType() != GeomAbs_BSplineSurface && |
187 | mySurface->GetType() != GeomAbs_BezierSurface && |
188 | mySurface->GetType() != GeomAbs_OtherSurface) |
189 | { |
190 | return Standard_True; |
191 | } |
192 | |
193 | // Let skip periodic case. |
194 | if (mySurface->IsUPeriodic() || mySurface->IsVPeriodic()) |
195 | return Standard_True; |
196 | |
197 | // Point lies within the surface range - nothing to do. |
198 | if (theUV.X() > myFaceRangeU[0] && theUV.X() < myFaceRangeU[1] && |
199 | theUV.Y() > myFaceRangeV[0] && theUV.Y() < myFaceRangeV[1]) |
200 | { |
201 | return Standard_True; |
202 | } |
203 | |
204 | gp_Pnt aPntOnSurf; |
205 | mySurface->D0 (theUV.X (), theUV.Y (), aPntOnSurf); |
206 | |
207 | return (thePoint.SquareDistance (aPntOnSurf) < myEdgeSqTol); |
ceb418e1 |
208 | } |
209 | |
210 | //======================================================================= |
211 | //function : splitSegment |
212 | //purpose : |
213 | //======================================================================= |
214 | void BRepMesh_EdgeTessellator::splitSegment( |
81093856 |
215 | const Adaptor3d_Surface& theSurf, |
216 | const Geom2dAdaptor_Curve& theCurve2d, |
ceb418e1 |
217 | const Standard_Real theFirst, |
218 | const Standard_Real theLast, |
219 | const Standard_Integer theNbIter) |
220 | { |
221 | // limit iteration depth |
222 | if(theNbIter > 10) |
223 | return; |
224 | |
225 | gp_Pnt2d uvf, uvl, uvm; |
226 | gp_Pnt P3dF, P3dL, midP3d, midP3dFromSurf; |
227 | Standard_Real midpar; |
228 | |
229 | if(Abs(theLast - theFirst) < 2 * Precision::PConfusion()) |
230 | return; |
231 | |
81093856 |
232 | theCurve2d.D0(theFirst, uvf); |
233 | theCurve2d.D0(theLast, uvl); |
ceb418e1 |
234 | |
81093856 |
235 | P3dF = theSurf.Value(uvf.X(), uvf.Y()); |
236 | P3dL = theSurf.Value(uvl.X(), uvl.Y()); |
ceb418e1 |
237 | |
74da0216 |
238 | if(P3dF.SquareDistance(P3dL) < mySquareMinSize) |
ceb418e1 |
239 | return; |
240 | |
241 | uvm = gp_Pnt2d((uvf.XY() + uvl.XY())*0.5); |
81093856 |
242 | midP3dFromSurf = theSurf.Value(uvm.X(), uvm.Y()); |
ceb418e1 |
243 | |
74da0216 |
244 | gp_XYZ Vec1 = midP3dFromSurf.XYZ() - P3dF.XYZ(); |
245 | if(Vec1.SquareModulus() < mySquareMinSize) |
246 | return; |
247 | |
ceb418e1 |
248 | gp_XYZ aVec = P3dL.XYZ() - P3dF.XYZ(); |
249 | aVec.Normalize(); |
250 | |
ceb418e1 |
251 | Standard_Real aModulus = Vec1.Dot(aVec); |
252 | gp_XYZ aProj = aVec * aModulus; |
253 | gp_XYZ aDist = Vec1 - aProj; |
254 | |
255 | if(aDist.SquareModulus() < mySquareEdgeDef) |
256 | return; |
257 | |
258 | midpar = (theFirst + theLast) * 0.5; |
259 | myCOnS.D0(midpar, midP3d); |
260 | myTool->AddPoint(midP3d, midpar, Standard_False); |
261 | |
262 | splitSegment(theSurf, theCurve2d, theFirst, midpar, theNbIter + 1); |
263 | splitSegment(theSurf, theCurve2d, midpar, theLast, theNbIter + 1); |
264 | } |