b311480e |
1 | // Created on: 1994-07-22 |
2 | // Created by: Remi LEQUETTE |
3 | // Copyright (c) 1994-1999 Matra Datavision |
4 | // Copyright (c) 1999-2012 OPEN CASCADE SAS |
5 | // |
6 | // The content of this file is subject to the Open CASCADE Technology Public |
7 | // License Version 6.5 (the "License"). You may not use the content of this file |
8 | // except in compliance with the License. Please obtain a copy of the License |
9 | // at http://www.opencascade.org and read it completely before using this file. |
10 | // |
11 | // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its |
12 | // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. |
13 | // |
14 | // The Original Code and all software distributed under the License is |
15 | // distributed on an "AS IS" basis, without warranty of any kind, and the |
16 | // Initial Developer hereby disclaims all such warranties, including without |
17 | // limitation, any warranties of merchantability, fitness for a particular |
18 | // purpose or non-infringement. Please see the License for the specific terms |
19 | // and conditions governing the rights and limitations under the License. |
20 | |
7fd59977 |
21 | |
22 | #include <BRepLib_FindSurface.ixx> |
23 | |
24 | #include <Precision.hxx> |
25 | #include <math_Matrix.hxx> |
26 | #include <math_Vector.hxx> |
27 | #include <math_Gauss.hxx> |
28 | |
29 | #include <gp_Lin.hxx> |
30 | #include <gp_Circ.hxx> |
31 | #include <gp_Elips.hxx> |
32 | #include <gp_Hypr.hxx> |
33 | #include <gp_Parab.hxx> |
34 | #include <gp_Ax2.hxx> |
35 | #include <gp_Ax3.hxx> |
36 | #include <gp_Vec.hxx> |
37 | #include <TColgp_SequenceOfPnt.hxx> |
38 | #include <TColStd_SequenceOfReal.hxx> |
39 | #include <TColgp_Array1OfPnt.hxx> |
40 | #include <TColgp_HArray1OfPnt.hxx> |
41 | #include <Geom_Plane.hxx> |
42 | |
43 | #include <TopoDS.hxx> |
44 | #include <TopExp_Explorer.hxx> |
45 | #include <BRep_Tool.hxx> |
46 | #include <BRepAdaptor_Curve.hxx> |
47 | |
48 | #include <GeomLib.hxx> |
49 | #include <Geom2d_Curve.hxx> |
50 | #include <Geom_BezierCurve.hxx> |
51 | #include <Geom_BSplineCurve.hxx> |
52 | |
53 | //======================================================================= |
54 | //function : Controle |
55 | //purpose : |
56 | //======================================================================= |
57 | static Standard_Real Controle(const TColgp_SequenceOfPnt& thePoints, |
58 | const Handle(Geom_Plane)& thePlane) |
59 | { |
60 | Standard_Real dfMaxDist=0.; |
61 | Standard_Real a,b,c,d, dist; |
62 | Standard_Integer ii; |
63 | thePlane->Coefficients(a,b,c,d); |
64 | for (ii=1; ii<=thePoints.Length(); ii++) { |
65 | const gp_XYZ& xyz = thePoints(ii).XYZ(); |
66 | dist = Abs(a*xyz.X() + b*xyz.Y() + c*xyz.Z() + d); |
67 | if (dist > dfMaxDist) |
68 | dfMaxDist = dist; |
69 | } |
70 | |
71 | return dfMaxDist; |
72 | } |
73 | |
74 | //======================================================================= |
75 | //function : BRepLib_FindSurface |
76 | //purpose : |
77 | //======================================================================= |
78 | BRepLib_FindSurface::BRepLib_FindSurface() |
79 | { |
80 | } |
81 | //======================================================================= |
82 | //function : BRepLib_FindSurface |
83 | //purpose : |
84 | //======================================================================= |
85 | BRepLib_FindSurface::BRepLib_FindSurface(const TopoDS_Shape& S, |
86 | const Standard_Real Tol, |
87 | const Standard_Boolean OnlyPlane) |
88 | { |
89 | Init(S,Tol,OnlyPlane); |
90 | } |
91 | //======================================================================= |
92 | //function : Init |
93 | //purpose : |
94 | //======================================================================= |
95 | void BRepLib_FindSurface::Init(const TopoDS_Shape& S, |
96 | const Standard_Real Tol, |
97 | const Standard_Boolean OnlyPlane) |
98 | { |
99 | myTolerance = Tol; |
100 | myTolReached = 0.; |
101 | isExisted = Standard_False; |
102 | myLocation.Identity(); |
103 | mySurface.Nullify(); |
104 | |
105 | // compute the tolerance |
106 | TopExp_Explorer ex; |
107 | |
108 | for (ex.Init(S,TopAbs_EDGE); ex.More(); ex.Next()) { |
109 | Standard_Real t = BRep_Tool::Tolerance(TopoDS::Edge(ex.Current())); |
110 | if (t > myTolerance) myTolerance = t; |
111 | } |
112 | |
113 | // search an existing surface |
114 | ex.Init(S,TopAbs_EDGE); |
115 | if (!ex.More()) return; // no edges .... |
116 | |
117 | TopoDS_Edge E = TopoDS::Edge(ex.Current()); |
118 | Standard_Real f,l,ff,ll; |
119 | Handle(Geom2d_Curve) PC,PPC; |
120 | Handle(Geom_Surface) SS; |
121 | TopLoc_Location L; |
122 | Standard_Integer i = 0,j; |
123 | |
124 | // iterate on the surfaces of the first edge |
125 | while ( Standard_True) { |
126 | i++; |
127 | BRep_Tool::CurveOnSurface(E,PC,mySurface,myLocation,f,l,i); |
128 | if (mySurface.IsNull()) { |
129 | break; |
130 | } |
131 | // check the other edges |
132 | for (ex.Init(S,TopAbs_EDGE); ex.More(); ex.Next()) { |
133 | if (!E.IsSame(ex.Current())) { |
134 | j = 0; |
135 | while (Standard_True) { |
136 | j++; |
137 | BRep_Tool::CurveOnSurface(TopoDS::Edge(ex.Current()), |
138 | PPC,SS,L,ff,ll,j); |
139 | if (SS.IsNull()) { |
140 | break; |
141 | } |
142 | if (SS == mySurface) { |
143 | break; |
144 | } |
145 | SS.Nullify(); |
146 | } |
147 | |
148 | if (SS.IsNull()) { |
149 | mySurface.Nullify(); |
150 | break; |
151 | } |
152 | } |
153 | } |
154 | |
155 | // if OnlyPlane, eval if mySurface is a plane. |
156 | if ( OnlyPlane && !mySurface.IsNull() ) |
157 | mySurface = Handle(Geom_Plane)::DownCast(mySurface); |
158 | |
159 | if (!mySurface.IsNull()) break; |
160 | } |
161 | |
162 | if (!mySurface.IsNull()) { |
163 | isExisted = Standard_True; |
164 | return; |
165 | } |
166 | // |
167 | // no existing surface, search a plane |
168 | // 07/02/02 akm vvv : (OCC157) changed algorithm |
169 | // 1. Collect the points along all edges of the shape |
170 | // For each point calculate the WEIGHT = sum of |
171 | // distances from neighboring points (_only_ same edge) |
172 | // 2. Minimizing the weighed sum of squared deviations |
173 | // compute coefficients of the sought plane. |
174 | |
175 | TColgp_SequenceOfPnt aPoints; |
176 | TColStd_SequenceOfReal aWeight; |
177 | |
178 | // ======================= Step #1 |
179 | for (ex.Init(S,TopAbs_EDGE); ex.More(); ex.Next()) |
180 | { |
181 | BRepAdaptor_Curve c(TopoDS::Edge(ex.Current())); |
182 | |
183 | Standard_Real dfUf = c.FirstParameter(); |
184 | Standard_Real dfUl = c.LastParameter(); |
185 | if (IsEqual(dfUf,dfUl)) { |
186 | // Degenerate |
187 | continue; |
188 | } |
189 | Standard_Integer iNbPoints=0; |
190 | |
191 | // Add the points with weights to the sequences |
192 | switch (c.GetType()) |
193 | { |
194 | case GeomAbs_BezierCurve: |
195 | { |
196 | // Put all poles for bezier |
197 | Handle(Geom_BezierCurve) GC = c.Bezier(); |
198 | Standard_Integer iNbPol = GC->NbPoles(); |
199 | if ( iNbPol < 2) |
200 | // Degenerate |
201 | continue; |
202 | else |
203 | { |
204 | Handle(TColgp_HArray1OfPnt) aPoles = new (TColgp_HArray1OfPnt) (1, iNbPol); |
205 | GC->Poles(aPoles->ChangeArray1()); |
206 | gp_Pnt aPolePrev = aPoles->Value(1), aPoleNext; |
207 | Standard_Real dfDistPrev = 0., dfDistNext; |
208 | for (Standard_Integer iPol=1; iPol<=iNbPol; iPol++) |
209 | { |
210 | if (iPol<iNbPol) |
211 | { |
212 | aPoleNext = aPoles->Value(iPol+1); |
213 | dfDistNext = aPolePrev.Distance(aPoleNext); |
214 | } |
215 | else |
216 | dfDistNext = 0.; |
217 | aPoints.Append (aPolePrev); |
218 | aWeight.Append (dfDistPrev+dfDistNext); |
219 | dfDistPrev = dfDistNext; |
220 | aPolePrev = aPoleNext; |
221 | } |
222 | } |
223 | } |
224 | break; |
225 | case GeomAbs_BSplineCurve: |
226 | { |
227 | // Put all poles for bspline |
228 | Handle(Geom_BSplineCurve) GC = c.BSpline(); |
229 | Standard_Integer iNbPol = GC->NbPoles(); |
230 | if ( iNbPol < 2) |
231 | // Degenerate |
232 | continue; |
233 | else |
234 | { |
235 | Handle(TColgp_HArray1OfPnt) aPoles = new (TColgp_HArray1OfPnt) (1, iNbPol); |
236 | GC->Poles(aPoles->ChangeArray1()); |
237 | gp_Pnt aPolePrev = aPoles->Value(1), aPoleNext; |
238 | Standard_Real dfDistPrev = 0., dfDistNext; |
239 | for (Standard_Integer iPol=1; iPol<=iNbPol; iPol++) |
240 | { |
241 | if (iPol<iNbPol) |
242 | { |
243 | aPoleNext = aPoles->Value(iPol+1); |
244 | dfDistNext = aPolePrev.Distance(aPoleNext); |
245 | } |
246 | else |
247 | dfDistNext = 0.; |
248 | aPoints.Append (aPolePrev); |
249 | aWeight.Append (dfDistPrev+dfDistNext); |
250 | dfDistPrev = dfDistNext; |
251 | aPolePrev = aPoleNext; |
252 | } |
253 | } |
254 | } |
255 | break; |
256 | |
257 | case GeomAbs_Line: |
258 | case GeomAbs_Circle: |
259 | case GeomAbs_Ellipse: |
260 | case GeomAbs_Hyperbola: |
261 | case GeomAbs_Parabola: |
262 | if (c.GetType() == GeomAbs_Line) |
263 | // Two points on straight segment |
264 | iNbPoints=2; |
265 | else |
266 | // Four points on otheranalitical curves |
267 | iNbPoints=4; |
268 | default: |
269 | { |
270 | // Put some points on other curves |
271 | if (iNbPoints==0) |
272 | iNbPoints = 15 + c.NbIntervals(GeomAbs_C3); |
273 | Standard_Real dfDelta = (dfUl-dfUf)/(iNbPoints-1); |
274 | Standard_Integer iPoint; |
275 | Standard_Real dfU; |
276 | gp_Pnt aPointPrev = c.Value(dfUf), aPointNext; |
277 | Standard_Real dfDistPrev = 0., dfDistNext; |
278 | for (iPoint=1, dfU=dfUf+dfDelta; |
279 | iPoint<=iNbPoints; |
280 | iPoint++, dfU+=dfDelta) |
281 | { |
282 | if (iPoint<iNbPoints) |
283 | { |
284 | aPointNext = c.Value(dfU); |
285 | dfDistNext = aPointPrev.Distance(aPointNext); |
286 | } |
287 | else |
288 | dfDistNext = 0.; |
289 | aPoints.Append (aPointPrev); |
290 | aWeight.Append (dfDistPrev+dfDistNext); |
291 | dfDistPrev = dfDistNext; |
292 | aPointPrev = aPointNext; |
293 | } |
294 | } // default: |
295 | } // switch (c.GetType()) ... |
296 | } // for (ex.Init(S,TopAbs_EDGE); ex.More() && control; ex.Next()) ... |
297 | |
298 | if (aPoints.Length() < 3) { |
299 | return; |
300 | } |
301 | |
302 | // ======================= Step #2 |
303 | myLocation.Identity(); |
304 | Standard_Integer iPoint; |
305 | math_Matrix aMat (1,3,1,3, 0.); |
306 | math_Vector aVec (1,3, 0.); |
307 | // Find the barycenter and normalize weights |
308 | Standard_Real dfMaxWeight=0.; |
309 | gp_XYZ aBaryCenter(0.,0.,0.); |
310 | Standard_Real dfSumWeight=0.; |
311 | for (iPoint=1; iPoint<=aPoints.Length(); iPoint++) { |
312 | Standard_Real dfW = aWeight(iPoint); |
313 | aBaryCenter += dfW*aPoints(iPoint).XYZ(); |
314 | dfSumWeight += dfW; |
315 | if (dfW > dfMaxWeight) { |
316 | dfMaxWeight = dfW; |
317 | } |
318 | } |
319 | aBaryCenter /= dfSumWeight; |
320 | |
321 | // Fill the matrix and the right vector |
322 | for (iPoint=1; iPoint<=aPoints.Length(); iPoint++) { |
323 | gp_XYZ p=aPoints(iPoint).XYZ()-aBaryCenter; |
324 | Standard_Real w=aWeight(iPoint)/dfMaxWeight; |
325 | aMat(1,1)+=w*p.X()*p.X(); |
326 | aMat(1,2)+=w*p.X()*p.Y(); |
327 | aMat(1,3)+=w*p.X()*p.Z(); |
328 | aMat(2,1)+=w*p.Y()*p.X(); |
329 | aMat(2,2)+=w*p.Y()*p.Y(); |
330 | aMat(2,3)+=w*p.Y()*p.Z(); |
331 | aMat(3,1)+=w*p.Z()*p.X(); |
332 | aMat(3,2)+=w*p.Z()*p.Y(); |
333 | aMat(3,3)+=w*p.Z()*p.Z(); |
334 | aVec(1) -= w*p.X(); |
335 | aVec(2) -= w*p.Y(); |
336 | aVec(3) -= w*p.Z(); |
337 | } |
338 | |
339 | // Solve the system of equations to get plane coefficients |
340 | math_Gauss aSolver(aMat); |
341 | Standard_Boolean isSolved = aSolver.IsDone(); |
342 | // |
343 | // let us be more tolerant (occ415) |
344 | Standard_Real dfDist = RealLast(); |
345 | Handle(Geom_Plane) aPlane; |
346 | // |
347 | if (isSolved) { |
348 | aSolver.Solve(aVec); |
349 | if (aVec.Norm2()<gp::Resolution()) { |
350 | isSolved = Standard_False; |
351 | } |
352 | } |
353 | // |
354 | if (isSolved) { |
355 | aPlane = new Geom_Plane(aBaryCenter,gp_Dir(aVec(1),aVec(2),aVec(3))); |
356 | dfDist = Controle (aPoints, aPlane); |
357 | } |
358 | // |
359 | if (!isSolved || myTolerance < dfDist) { |
360 | gp_Pnt aFirstPnt=aPoints(1); |
361 | for (iPoint=2; iPoint<=aPoints.Length(); iPoint++) { |
362 | gp_Vec aDir(aFirstPnt,aPoints(iPoint)); |
363 | Standard_Real dfSide=aDir.Magnitude(); |
364 | if (dfSide<myTolerance) { |
365 | continue; // degeneration |
366 | } |
367 | for (Standard_Integer iP1=iPoint+1; iP1<=aPoints.Length(); iP1++) { |
368 | gp_Vec aCross = gp_Vec(aFirstPnt,aPoints(iP1)) ^ aDir ; |
369 | if (aCross.Magnitude() > dfSide*myTolerance) { |
370 | Handle(Geom_Plane) aPlane2 = new Geom_Plane(aFirstPnt, aCross); |
371 | Standard_Real dfDist2 = Controle (aPoints, aPlane2); |
372 | if (dfDist2 < myTolerance) { |
373 | myTolReached = dfDist2; |
374 | mySurface = aPlane2; |
375 | return; |
376 | } |
377 | if (dfDist2 < dfDist) { |
378 | dfDist = dfDist2; |
379 | aPlane = aPlane2; |
380 | } |
381 | } |
382 | } |
383 | } |
384 | } |
385 | // |
386 | //XXf |
387 | //static Standard_Real weakness = 5.0; |
388 | Standard_Real weakness = 5.0; |
389 | //XXf |
390 | if(dfDist <= myTolerance || dfDist < myTolerance*weakness && Tol<0) { |
391 | //XXf |
392 | //myTolReached = dfDist; |
393 | //XXt |
394 | mySurface = aPlane; |
395 | } |
396 | //XXf |
397 | myTolReached = dfDist; |
398 | //XXt |
399 | } |
400 | //======================================================================= |
401 | //function : Found |
402 | //purpose : |
403 | //======================================================================= |
404 | Standard_Boolean BRepLib_FindSurface::Found() const |
405 | { |
406 | return !mySurface.IsNull(); |
407 | } |
408 | //======================================================================= |
409 | //function : Surface |
410 | //purpose : |
411 | //======================================================================= |
412 | Handle(Geom_Surface) BRepLib_FindSurface::Surface() const |
413 | { |
414 | return mySurface; |
415 | } |
416 | //======================================================================= |
417 | //function : Tolerance |
418 | //purpose : |
419 | //======================================================================= |
420 | Standard_Real BRepLib_FindSurface::Tolerance() const |
421 | { |
422 | return myTolerance; |
423 | } |
424 | //======================================================================= |
425 | //function : ToleranceReached |
426 | //purpose : |
427 | //======================================================================= |
428 | Standard_Real BRepLib_FindSurface::ToleranceReached() const |
429 | { |
430 | return myTolReached; |
431 | } |
432 | //======================================================================= |
433 | //function : Existed |
434 | //purpose : |
435 | //======================================================================= |
436 | Standard_Boolean BRepLib_FindSurface::Existed() const |
437 | { |
438 | return isExisted; |
439 | } |
440 | //======================================================================= |
441 | //function : Location |
442 | //purpose : |
443 | //======================================================================= |
444 | TopLoc_Location BRepLib_FindSurface::Location() const |
445 | { |
446 | return myLocation; |
447 | } |