0026627: [Regression] Shape Healing hangs as of OCC 6.8.0
[occt.git] / src / BRepClass3d / BRepClass3d_SClassifier.cxx
CommitLineData
b311480e 1// Created on: 1996-07-15
2// Created by: Laurent BUCHARD
3// Copyright (c) 1996-1999 Matra Datavision
973c2be1 4// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 5//
973c2be1 6// This file is part of Open CASCADE Technology software library.
b311480e 7//
d5f74e42 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
973c2be1 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.
b311480e 13//
973c2be1 14// Alternatively, this file may be used under the terms of Open CASCADE
15// commercial license or contractual agreement.
7fd59977 16
17// Modified by skv - Thu Sep 4 11:22:05 2003 OCC578
18
42cf5bc1 19#include <BRep_Tool.hxx>
7fd59977 20#include <BRepClass3d_Intersector3d.hxx>
42cf5bc1 21#include <BRepClass3d_SClassifier.hxx>
22#include <BRepClass3d_SolidExplorer.hxx>
23#include <BRepTopAdaptor_FClass2d.hxx>
7fd59977 24#include <ElCLib.hxx>
bd05fabf 25#include <Geom_Surface.hxx>
42cf5bc1 26#include <gp_Lin.hxx>
27#include <gp_Pnt.hxx>
28#include <gp_Vec.hxx>
29#include <IntCurvesFace_Intersector.hxx>
fd3ba7a1 30#include <math_BullardGenerator.hxx>
42cf5bc1 31#include <Precision.hxx>
32#include <Standard_DomainError.hxx>
33#include <TopoDS.hxx>
34#include <TopoDS_Face.hxx>
7fd59977 35
79e9ce0e 36#include <vector>
37
42cf5bc1 38// modified by NIZHNY-MKK Mon Jun 21 15:13:40 2004
bd05fabf 39static
be7c077a 40 Standard_Boolean FaceNormal (const TopoDS_Face& aF,
41 const Standard_Real U,
42 const Standard_Real V,
43 gp_Dir& aDN);
7fd59977 44
bd05fabf
S
45static
46 Standard_Real GetAddToParam(const gp_Lin& L,const Standard_Real P,const Bnd_Box& B);
7fd59977 47
48
bd05fabf
S
49
50//=======================================================================
51//function : BRepClass3d_SClassifier
52//purpose :
53//=======================================================================
7fd59977 54BRepClass3d_SClassifier::BRepClass3d_SClassifier()
55{
56}
57
58
bd05fabf
S
59//=======================================================================
60//function : BRepClass3d_SClassifier
61//purpose :
62//=======================================================================
7fd59977 63BRepClass3d_SClassifier::BRepClass3d_SClassifier(BRepClass3d_SolidExplorer& S,
64 const gp_Pnt& P,
65 const Standard_Real Tol) {
66 if(S.Reject(P)) {
c898afce 67 myState=3; //-- in ds solid case without face
7fd59977 68 }
69 else {
70 Perform(S,P,Tol);
71 }
72}
73
74
bd05fabf
S
75//=======================================================================
76//function : PerformInfinitePoint
77//purpose :
78//=======================================================================
79void BRepClass3d_SClassifier::PerformInfinitePoint(BRepClass3d_SolidExplorer& aSE,
7fd59977 80 const Standard_Real /*Tol*/) {
7fd59977 81
be7c077a 82 //Take a normal to the first extracted face in its random inner point
83 //and intersect this reversed normal with the faces of the solid.
84 //If the min.par.-intersection point is
85 // a) inner point of a face
86 // b) transition is not TANGENT
87 // (the line does not touch the face but pierces it)
88 //then set <myState> to IN or OUT according to transition
89 //else take the next random point inside the min.par.-intersected face
90 //and continue
91
bd05fabf 92 if(aSE.Reject(gp_Pnt(0,0,0))) {
c898afce 93 myState=3; //-- in ds solid case without face
7fd59977 94 return;
95 }
bd05fabf
S
96 //
97 //------------------------------------------------------------
98 // 1
be7c077a 99 Standard_Boolean bFound;
100 Standard_Real aParam, aU = 0., aV = 0.;
101 gp_Pnt aPoint;
102 gp_Dir aDN;
103
fd3ba7a1 104 math_BullardGenerator aRandomGenerator;
7fd59977 105 myFace.Nullify();
be7c077a 106 myState=2;
107
79e9ce0e 108 // Collect faces in sequence to iterate
109 std::vector<TopoDS_Face> aFaces;
110 for (aSE.InitShell(); aSE.MoreShell(); aSE.NextShell())
111 {
112 for (aSE.InitFace(); aSE.MoreFace(); aSE.NextFace())
113 {
114 aFaces.push_back (aSE.CurrentFace());
115 }
116 }
117
118 // iteratively try up to 10 probing points from each face
119 const int NB_MAX_POINTS_PER_FACE = 10;
120 for (int itry = 0; itry < NB_MAX_POINTS_PER_FACE; itry++)
be7c077a 121 {
79e9ce0e 122 for (std::vector<TopoDS_Face>::iterator iFace = aFaces.begin(); iFace != aFaces.end(); ++iFace)
be7c077a 123 {
79e9ce0e 124 TopoDS_Face aF = *iFace;
125
be7c077a 126 TopAbs_State aState = TopAbs_OUT;
127 IntCurveSurface_TransitionOnCurve aTransition = IntCurveSurface_Tangent;
be7c077a 128
79e9ce0e 129 aParam = 0.1 + 0.8 * aRandomGenerator.NextReal(); // random number in range [0.1, 0.9]
130 bFound = aSE.FindAPointInTheFace(aF, aPoint, aU, aV, aParam);
131 if (!bFound || !FaceNormal(aF, aU, aV, aDN))
132 continue;
133
134 gp_Lin aLin(aPoint, -aDN);
135 Standard_Real parmin = RealLast();
136 for (aSE.InitShell();aSE.MoreShell();aSE.NextShell()) {
137 if (aSE.RejectShell(aLin) == Standard_False) {
138 for (aSE.InitFace();aSE.MoreFace(); aSE.NextFace()) {
139 if (aSE.RejectFace(aLin) == Standard_False) {
140 TopoDS_Shape aLocalShape = aSE.CurrentFace();
141 TopoDS_Face CurFace = TopoDS::Face(aLocalShape);
142 IntCurvesFace_Intersector& Intersector3d = aSE.Intersector(CurFace);
143 Intersector3d.Perform(aLin,-RealLast(),parmin);
144
145 if(Intersector3d.IsDone()) {
146 if(Intersector3d.NbPnt()) {
147 Standard_Integer imin = 1;
148 for (Standard_Integer i = 2; i <= Intersector3d.NbPnt(); i++)
149 if (Intersector3d.WParameter(i) < Intersector3d.WParameter(imin))
150 imin = i;
151 parmin = Intersector3d.WParameter(imin);
152 aState = Intersector3d.State(imin);
153 aTransition = Intersector3d.Transition(imin);
be7c077a 154 }
155 }
156 }
157 }
79e9ce0e 158 }
159 else
160 myState = 1;
161 } //end of loop on the whole solid
be7c077a 162
79e9ce0e 163 if (aState == TopAbs_IN)
164 {
165 if (aTransition == IntCurveSurface_Out) {
166 //-- The line is going from inside the solid to outside
167 //-- the solid.
168 myState = 3; //-- IN --
169 return;
170 }
171 else if (aTransition == IntCurveSurface_In) {
172 myState = 4; //-- OUT --
173 return;
be7c077a 174 }
7fd59977 175 }
79e9ce0e 176 } // iteration by faces
177 } // iteration by points
7fd59977 178}
be7c077a 179
7fd59977 180//=======================================================================
181//function : Perform
182//purpose :
183//=======================================================================
bd05fabf
S
184void BRepClass3d_SClassifier::Perform(BRepClass3d_SolidExplorer& SolidExplorer,
185 const gp_Pnt& P,
186 const Standard_Real Tol)
7fd59977 187{
188
189
190 if(SolidExplorer.Reject(P)) {
c898afce 191 myState=3; //-- in ds solid case without face
7fd59977 192 return;
193 }
194
195
196 myFace.Nullify();
197 myState = 0;
198 if(SolidExplorer.Reject(P) == Standard_False) {
199 gp_Lin L;
200 Standard_Real Par;
201 //-- We compute the intersection betwwen the line builded in the Solid Explorer
202 //-- and the shape.
203
204 //-- --------------------------------------------------------------------------------
c898afce
Y
205 //-- Calculate intersection with the face closest to the direction of bounding boxes
206 //-- by priority so that to have the smallest possible parmin.
207 //-- optimization to produce as much as possible rejections with other faces.
7fd59977 208 Standard_Integer iFlag;
209 //
210
211 // Modified by skv - Thu Sep 4 11:22:05 2003 OCC578 Begin
212 // If found line passes through a bound of any face, it means that the line
213 // is not found properly and it is necessary to repeat whole procedure.
214 // That's why the main loop while is added.
215 Standard_Boolean isFaultyLine = Standard_True;
216 Standard_Integer anIndFace = 0;
1d47d8d0 217 Standard_Real parmin = 0.;
7fd59977 218
219 while (isFaultyLine) {
220 if (anIndFace == 0) {
221 iFlag = SolidExplorer.Segment(P,L,Par);
222 } else {
223 iFlag = SolidExplorer.OtherSegment(P,L,Par);
224 }
225
226 Standard_Integer aCurInd = SolidExplorer.GetFaceSegmentIndex();
227
228 if (aCurInd > anIndFace) {
229 anIndFace = aCurInd;
230 } else {
231 myState = 1;
232
233 return;
234 }
235 // Modified by skv - Thu Sep 4 11:22:10 2003 OCC578 End
236
237 if (iFlag==1) {
238 // IsOnFace
239 // iFlag==1 i.e face is Infinite
240 myState=2;
241
242 return;
243 }
244 //SolidExplorer.Segment(P,L,Par);
7fd59977 245 //
246 //process results from uncorrected shells
247 //
7fd59977 248 //if(Par > 1.e+100 && L.Direction().IsParallel(gp_Dir(0.,0.,1.),1.e-8)) {
249 if (iFlag==2) {
7fd59977 250 myState = 4;
251 return;
252 }
253 //-- BRepClass3d_Intersector3d Intersector3d;
254
255 // Modified by skv - Thu Sep 4 13:48:27 2003 OCC578 Begin
256 // Check if the point is ON surface but OUT of the face.
257 // Just skip this face because it is bad for classification.
258 if (iFlag == 3)
259 continue;
260
261 isFaultyLine = Standard_False;
262// Standard_Real parmin = RealLast();
263
264// for(SolidExplorer.InitShell();
265// SolidExplorer.MoreShell();
266// SolidExplorer.NextShell()) {
267 parmin = RealLast();
268
269 for(SolidExplorer.InitShell();
270 SolidExplorer.MoreShell() && !isFaultyLine;
271 SolidExplorer.NextShell()) {
272// Modified by skv - Thu Sep 4 13:48:27 2003 OCC578 End
273
274 if(SolidExplorer.RejectShell(L) == Standard_False) {
275
276// Modified by skv - Thu Sep 4 13:48:27 2003 OCC578 Begin
277// for(SolidExplorer.InitFace();
278// SolidExplorer.MoreFace();
279// SolidExplorer.NextFace()) {
280 for(SolidExplorer.InitFace();
281 SolidExplorer.MoreFace() && !isFaultyLine;
282 SolidExplorer.NextFace()) {
283// Modified by skv - Thu Sep 4 13:48:27 2003 OCC578 End
284
285 if(SolidExplorer.RejectFace(L) == Standard_False) {
286
287 //-- Intersector3d.Perform(L,Par,Tol,SolidExplorer.CurrentFace());
288 TopoDS_Shape aLocalShape = SolidExplorer.CurrentFace();
289 TopoDS_Face f = TopoDS::Face(aLocalShape);
290 // TopoDS_Face f = TopoDS::Face(SolidExplorer.CurrentFace());
291 IntCurvesFace_Intersector& Intersector3d = SolidExplorer.Intersector(f);
292
293 // MSV Oct 25, 2001: prolong segment, since there are cases when
294 // the intersector does not find intersection points with the original
295 // segment due to rough triangulation of a parametrized surface
296 Standard_Real addW = Max(10*Tol, 0.01*Par);
297 Standard_Real AddW = addW;
298
299 Bnd_Box aBoxF = Intersector3d.Bounding();
300
301 // MSV 23.09.2004: the box must be finite in order to
302 // correctly prolong the segment to its bounds
303 if (!aBoxF.IsVoid() && !aBoxF.IsWhole()) {
304 Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
305 aBoxF.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
306
307 Standard_Real boxaddW = GetAddToParam(L,Par,aBoxF);
308 addW = Max(addW,boxaddW);
309 }
310
311 Standard_Real minW = -AddW;//-addW;
312 Standard_Real maxW = Min(Par*10,Par+addW);//Par+addW;
313 //cout << "range [" << minW << "," << maxW << "]" << endl << endl;
314 Intersector3d.Perform(L,minW,maxW);
315 //Intersector3d.Perform(L,-Tol,Par+10.0*Tol);
316 if(Intersector3d.IsDone()) {
317 Standard_Integer i;
318 for (i=1; i <= Intersector3d.NbPnt(); i++) {
3922a2ec 319 if(Abs(Intersector3d.WParameter(i)) < Abs(parmin) - Precision::PConfusion()) {
7fd59977 320
321 parmin = Intersector3d.WParameter(i);
322 // Modified by skv - Thu Sep 4 12:46:32 2003 OCC578 Begin
323 TopAbs_State aState = Intersector3d.State(i);
324 // Modified by skv - Thu Sep 4 12:46:33 2003 OCC578 End
325 if(Abs(parmin)<=Tol) {
326 myState = 2;
327 myFace = f;
328 }
329 // Modified by skv - Thu Sep 4 12:46:32 2003 OCC578 Begin
330 // Treatment of case TopAbs_ON separately.
331
332 else if(aState==TopAbs_IN) {
333 // Modified by skv - Thu Sep 4 12:46:32 2003 OCC578 End
334
335 //-- The intersection point between the line and a face F
336 // -- of the solid is in the face F
337
338 IntCurveSurface_TransitionOnCurve tran = Intersector3d.Transition(i);
339 if (tran == IntCurveSurface_Tangent) {
0797d9d3 340#ifdef OCCT_DEBUG
c898afce 341 cout<<"*Problem ds BRepClass3d_SClassifier.cxx"<<endl;
7fd59977 342#endif
343 continue; // ignore this point
344 }
345 // if parmin is negative we should reverse transition
346 if (parmin < 0)
347 tran = (tran == IntCurveSurface_Out
348 ? IntCurveSurface_In : IntCurveSurface_Out);
349 if(tran == IntCurveSurface_Out) {
350 //-- The line is going from inside the solid to outside
351 //-- the solid.
352 myState = 3; //-- IN --
353 }
354 else /* if(tran == IntCurveSurface_In) */ {
355 myState = 4; //-- OUT --
356 }
357 myFace = f;
358 }
359 // Modified by skv - Thu Sep 4 12:48:50 2003 OCC578 Begin
360 // If the state is TopAbs_ON, it is necessary to chose
361 // another line and to repeat the whole procedure.
362 else if(aState==TopAbs_ON) {
363 isFaultyLine = Standard_True;
364
365 break;
366 }
367 // Modified by skv - Thu Sep 4 12:48:50 2003 OCC578 End
368 }
369 else {
370 //-- No point has been found by the Intersector3d.
371 //-- Or a Point has been found with a greater parameter.
372 }
373 } //-- loop by intersection points
374 } //-- Face has not been rejected
375 else {
376 myState = 1;
377 }
378 }
379 } //-- Exploration of the faces
380 } //-- Shell has not been rejected
381 else {
382 myState=1;
383 }
384 } //-- Exploration of the shells
385
386 // Modified by skv - Thu Sep 4 11:42:03 2003 OCC578 Begin
387 // The end of main loop.
388 }
389 // Modified by skv - Thu Sep 4 11:42:03 2003 OCC578 End
390
0797d9d3 391#ifdef OCCT_DEBUG
7fd59977 392 //#################################################
393 SolidExplorer.DumpSegment(P,L,parmin,State());
394 //#################################################
395#endif
396
397 } //-- Solid has not been rejected
398 else {
399 myState = 1;
400 }
401}
402
403
404TopAbs_State BRepClass3d_SClassifier::State() const {
405 if(myState==2) return(TopAbs_ON);
406 if(myState==4) return(TopAbs_OUT); //--
407 else if(myState==3) return(TopAbs_IN); //--
408 return(TopAbs_OUT);
409}
410
411TopoDS_Face BRepClass3d_SClassifier::Face() const {
412 return(myFace);
413}
414
415Standard_Boolean BRepClass3d_SClassifier::Rejected() const {
416 return(myState==1);
417}
418
419
420Standard_Boolean BRepClass3d_SClassifier::IsOnAFace() const {
421 return(myState==2);
422}
423
424
425void BRepClass3d_SClassifier::ForceIn() {
426 myState=3;
427}
428
429void BRepClass3d_SClassifier::ForceOut() {
430 myState=4;
431}
432
433Standard_Real GetAddToParam(const gp_Lin& L,
434 const Standard_Real P,
435 const Bnd_Box& B)
436{
437 Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
438 B.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
439 Standard_Real x[2] = {aXmin,aXmax}, y[2] = {aYmin,aYmax}, z[2] = {aZmin,aZmax};
440 Standard_Integer i = 0, j = 0, k = 0;
441 Standard_Real Par = P;
442 for(i = 0 ; i < 2; i++) {
443 for(j = 0; j < 2; j++) {
444 for(k = 0; k < 2; k++) {
445 Standard_Real X = fabs(x[i]-L.Location().X());
446 Standard_Real Y = fabs(y[j]-L.Location().Y());
447 Standard_Real Z = fabs(z[k]-L.Location().Z());
448 if(X < 1.e+20 && Y < 1.e+20 && Z < 1.e+20) {
449 gp_Pnt aP(x[i],y[j],z[k]);
450 Standard_Real par = ElCLib::Parameter(L,aP);
451 if(par > Par)
452 Par = par;
453 }
454 else
455 return 1.e+20;
456 }
457 }
458 }
459 return Par - P;
460}
bd05fabf
S
461//=======================================================================
462//function : FaceNormal
463//purpose :
464//=======================================================================
be7c077a 465Standard_Boolean FaceNormal (const TopoDS_Face& aF,
466 const Standard_Real U,
467 const Standard_Real V,
468 gp_Dir& aDN)
bd05fabf
S
469{
470 gp_Pnt aPnt ;
471 gp_Vec aD1U, aD1V, aN;
472 Handle(Geom_Surface) aS;
473
474 aS=BRep_Tool::Surface(aF);
475 aS->D1 (U, V, aPnt, aD1U, aD1V);
476 aN=aD1U.Crossed(aD1V);
be7c077a 477 if (aN.Magnitude() <= gp::Resolution())
478 return Standard_False;
479
bd05fabf
S
480 aN.Normalize();
481 aDN.SetXYZ(aN.XYZ());
482 if (aF.Orientation() == TopAbs_REVERSED){
483 aDN.Reverse();
484 }
be7c077a 485 return Standard_True;
bd05fabf 486}