1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14
15 #include <BRep_Builder.hxx>
16 #include <BRep_Tool.hxx>
17 #include <BRepLib.hxx>
18 #include <BRepTools.hxx>
19 #include <ElCLib.hxx>
20 #include <Geom2d_Curve.hxx>
21 #include <Geom_BezierSurface.hxx>
22 #include <Geom_BSplineSurface.hxx>
23 #include <Geom_Curve.hxx>
24 #include <Geom_ElementarySurface.hxx>
25 #include <Geom_Line.hxx>
26 #include <Geom_Surface.hxx>
27 #include <Geom_TrimmedCurve.hxx>
28 #include <GeomAdaptor_Curve.hxx>
29 #include <GeomAdaptor_Surface.hxx>
30 #include <GeomLib.hxx>
31 #include <gp_Dir.hxx>
32 #include <gp_Pnt.hxx>
33 #include <gp_Vec.hxx>
34 #include <Poly_Polygon3D.hxx>
35 #include <Precision.hxx>
36 #include <ShapeAnalysis_CheckSmallFace.hxx>
37 #include <ShapeAnalysis_Curve.hxx>
38 #include <ShapeAnalysis_Wire.hxx>
39 #include <ShapeAnalysis_WireOrder.hxx>
40 #include <ShapeExtend.hxx>
41 #include <ShapeExtend_WireData.hxx>
42 #include <Standard_ErrorHandler.hxx>
43 #include <TColgp_Array1OfPnt.hxx>
44 #include <TColgp_Array2OfPnt.hxx>
45 #include <TColgp_SequenceOfXYZ.hxx>
46 #include <TColStd_Array1OfReal.hxx>
47 #include <TColStd_Array2OfReal.hxx>
48 #include <TColStd_ListOfReal.hxx>
49 #include <TopExp.hxx>
50 #include <TopExp_Explorer.hxx>
51 #include <TopoDS.hxx>
52 #include <TopoDS_Builder.hxx>
53 #include <TopoDS_Compound.hxx>
54 #include <TopoDS_Edge.hxx>
55 #include <TopoDS_Face.hxx>
56 #include <TopoDS_Iterator.hxx>
57 #include <TopoDS_Shell.hxx>
58 #include <TopoDS_Vertex.hxx>
59 #include <TopoDS_Wire.hxx>
60 #include <TopTools_Array1OfShape.hxx>
61 #include <TopTools_HSequenceOfShape.hxx>
62 #include <TopTools_ListOfShape.hxx>
63
64 //#include <GeomLProp_SLProps.hxx>
65 //#include <ShapeFix_Wire.hxx>
66 //=======================================================
67 //function : ShapeAnalysis_CheckSmallFace
68 //purpose :
69 //=======================================================================
ShapeAnalysis_CheckSmallFace()70 ShapeAnalysis_CheckSmallFace::ShapeAnalysis_CheckSmallFace()
71 {
72 myStatusSpot = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
73 myStatusStrip = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
74 myStatusPin = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
75 myStatusTwisted = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
76 myStatusSplitVert = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
77
78 }
MinMaxPnt(const gp_Pnt & p,Standard_Integer & nb,Standard_Real & minx,Standard_Real & miny,Standard_Real & minz,Standard_Real & maxx,Standard_Real & maxy,Standard_Real & maxz)79 static void MinMaxPnt
80 (const gp_Pnt& p, Standard_Integer& nb,
81 Standard_Real& minx, Standard_Real& miny, Standard_Real& minz,
82 Standard_Real& maxx, Standard_Real& maxy, Standard_Real& maxz)
83 {
84 Standard_Real x,y,z;
85 p.Coord (x,y,z);
86 if (nb < 1) { minx = maxx = x; miny = maxy = y; minz = maxz = z; }
87 else
88 {
89 if (minx > x) minx = x;
90 if (maxx < x) maxx = x;
91 if (miny > y) miny = y;
92 if (maxy < y) maxy = y;
93 if (minz > z) minz = z;
94 if (maxz < z) maxz = z;
95 }
96 nb ++;
97 }
98
MinMaxSmall(const Standard_Real minx,const Standard_Real miny,const Standard_Real minz,const Standard_Real maxx,const Standard_Real maxy,const Standard_Real maxz,const Standard_Real toler)99 static Standard_Boolean MinMaxSmall
100 (const Standard_Real minx, const Standard_Real miny, const Standard_Real minz, const Standard_Real maxx, const Standard_Real maxy, const Standard_Real maxz, const Standard_Real toler)
101 {
102 Standard_Real dx = maxx - minx;
103 Standard_Real dy = maxy - miny;
104 Standard_Real dz = maxz - minz;
105
106 if ((dx > toler && !Precision::IsInfinite (dx)) ||
107 (dy > toler && !Precision::IsInfinite (dy)) ||
108 (dz > toler && !Precision::IsInfinite (dz)))
109 return Standard_False;
110 return Standard_True;
111 }
112
113 //=======================================================================
114 //function : IsSpotFace
115 //purpose :
116 //=======================================================================
117
IsSpotFace(const TopoDS_Face & F,gp_Pnt & spot,Standard_Real & spotol,const Standard_Real tol) const118 Standard_Integer ShapeAnalysis_CheckSmallFace::IsSpotFace(const TopoDS_Face& F,gp_Pnt& spot,Standard_Real& spotol,const Standard_Real tol) const
119 {
120
121 Standard_Real toler = tol; Standard_Real tolv = tol;
122 // Compute tolerance to get : from greatest tol of vertices
123 // In addition, also computes min-max of vertices
124 // To finally compare mini-max box with tolerance
125 // gka Mar2000 Protection against faces without wires
126 // but they occur due to bugs in the algorithm itself, it needs to be fixed
127 Standard_Boolean isWir = Standard_False;
128 for(TopoDS_Iterator itw(F,Standard_False) ; itw.More();itw.Next()) {
129 if(itw.Value().ShapeType() != TopAbs_WIRE)
130 continue;
131 TopoDS_Wire w1 = TopoDS::Wire(itw.Value());
132 if (!w1.IsNull()) {isWir = Standard_True; break;}
133 }
134 if(!isWir) return Standard_True;
135 Standard_Integer nbv = 0;
136 Standard_Real minx =0 ,miny = 0 ,minz = 0,maxx = Precision::Infinite(), maxy = Precision::Infinite(),maxz = Precision::Infinite();
137 TopoDS_Vertex V0;
138 Standard_Boolean same = Standard_True;
139 for (TopExp_Explorer iv(F,TopAbs_VERTEX); iv.More(); iv.Next()) {
140 TopoDS_Vertex V = TopoDS::Vertex (iv.Current());
141 if (V0.IsNull()) V0 = V;
142 else if (same) { if (!V0.IsSame(V)) same = Standard_False; }
143
144 gp_Pnt pnt = BRep_Tool::Pnt (V);
145 // Standard_Real x,y,z;
146 MinMaxPnt (pnt, nbv, minx,miny,minz, maxx,maxy,maxz);
147
148 if (tol < 0) {
149 tolv = BRep_Tool::Tolerance (V);
150 if (tolv > toler) toler = tolv;
151 }
152 }
153
154 // Now, testing
155 if (!MinMaxSmall(minx,miny,minz,maxx,maxy,maxz,toler)) return 0;
156
157 // All vertices are confused
158 // Check edges (a closed edge may be a non-null length edge !)
159 // By picking intermediate point on each one
160 for (TopExp_Explorer ie(F,TopAbs_EDGE); ie.More(); ie.Next()) {
161 TopoDS_Edge E = TopoDS::Edge (ie.Current());
162 Standard_Real cf,cl;
163 Handle(Geom_Curve) C3D = BRep_Tool::Curve (E,cf,cl);
164 if (C3D.IsNull()) continue;
165 gp_Pnt debut = C3D->Value (cf);
166 gp_Pnt milieu = C3D->Value ( (cf+cl)/2);
167 if (debut.SquareDistance(milieu) > toler*toler) return 0;
168 }
169
170 spot.SetCoord ( (minx+maxx)/2. , (miny+maxy)/2. , (minz+maxz)/2. );
171 spotol = maxx-minx;
172 spotol = Max (spotol, maxy-miny);
173 spotol = Max (spotol, maxz-minz);
174 spotol = spotol/2.;
175
176 return (same ? 2 : 1);
177 }
178
179 //=======================================================================
180 //function : CheckSpotFace
181 //purpose :
182 //=======================================================================
183
CheckSpotFace(const TopoDS_Face & F,const Standard_Real tol)184 Standard_Boolean ShapeAnalysis_CheckSmallFace::CheckSpotFace(const TopoDS_Face& F,const Standard_Real tol)
185 {
186 gp_Pnt spot;
187 Standard_Real spotol;
188 Standard_Integer stat = IsSpotFace (F,spot,spotol,tol);
189 if(!stat) return Standard_False;
190 switch(stat) {
191 case 1: myStatusSpot = ShapeExtend::EncodeStatus (ShapeExtend_DONE1); break;
192 case 2: myStatusSpot = ShapeExtend::EncodeStatus (ShapeExtend_DONE2); break;
193 default : break;
194
195 }
196 return Standard_True;
197 }
198
199 //=======================================================================
200 //function : IsStripSupport
201 //purpose :
202 //=======================================================================
203
IsStripSupport(const TopoDS_Face & F,const Standard_Real tol)204 Standard_Boolean ShapeAnalysis_CheckSmallFace::IsStripSupport(const TopoDS_Face& F,const Standard_Real tol)
205 {
206
207 Standard_Real toler = tol;
208 if (toler < 0) toler = 1.e-07; // ?? better to compute tolerance zones
209
210 TopLoc_Location loc;
211 Handle(Geom_Surface) surf = BRep_Tool::Surface (F,loc);
212 if (surf.IsNull()) return 0;
213
214 // Checking on poles for bezier-bspline
215 // A more general way is to check Values by scanning ISOS (slower)
216
217 Handle(Geom_BSplineSurface) bs = Handle(Geom_BSplineSurface)::DownCast(surf);
218 Handle(Geom_BezierSurface) bz = Handle(Geom_BezierSurface)::DownCast(surf);
219
220 // Standard_Integer stat = 2; // 2 : small in V direction
221 if (!bs.IsNull() || !bz.IsNull()) {
222 Standard_Boolean cbz = (!bz.IsNull());
223 Standard_Integer iu,iv, nbu, nbv;
224 if (cbz) { nbu = bz->NbUPoles(), nbv = bz->NbVPoles(); }
225 else { nbu = bs->NbUPoles(), nbv = bs->NbVPoles(); }
226 // Standard_Real dx = 0, dy = 0, dz = 0;
227 // Standard_Real x,y,z;
228 Standard_Real minx = 0.,miny = 0.,minz = 0.,maxx = 0.,maxy = 0.,maxz = 0.;
229 Standard_Boolean issmall = Standard_True;
230
231 for (iu = 1; iu <= nbu; iu ++) {
232 // for each U line, scan poles in V (V direction)
233 Standard_Integer nb = 0;
234 for (iv = 1; iv <= nbv; iv ++) {
235 gp_Pnt unp = (cbz ? bz->Pole(iu,iv) : bs->Pole(iu,iv));
236 MinMaxPnt (unp, nb, minx,miny,minz, maxx,maxy,maxz);
237 }
238 if (!MinMaxSmall(minx,miny,minz,maxx,maxy,maxz,toler))
239 { issmall = Standard_False; break; } // small in V ?
240 }
241 if (issmall) {
242 myStatusStrip = ShapeExtend::EncodeStatus ( ShapeExtend_DONE2);
243 return issmall; // OK, small in V
244 }
245 issmall = Standard_True;
246 for (iv = 1; iv <= nbv; iv ++) {
247 // for each V line, scan poles in U (U direction)
248 Standard_Integer nb = 0;
249 for (iu = 1; iu <= nbu; iu ++) {
250 gp_Pnt unp = (cbz ? bz->Pole(iu,iv) : bs->Pole(iu,iv));
251 MinMaxPnt (unp, nb, minx,miny,minz, maxx,maxy,maxz);
252 }
253 if (!MinMaxSmall(minx,miny,minz,maxx,maxy,maxz,toler))
254 { issmall = Standard_False; break; } // small in U ?
255 }
256 if (issmall) {
257 myStatusStrip = ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
258 return issmall;
259 }// OK, small in U
260 }
261
262 return Standard_False;
263 }
264
265 //=======================================================================
266 //function : CheckStripEdges
267 //purpose :
268 //=======================================================================
269
CheckStripEdges(const TopoDS_Edge & E1,const TopoDS_Edge & E2,const Standard_Real tol,Standard_Real & dmax) const270 Standard_Boolean ShapeAnalysis_CheckSmallFace::CheckStripEdges(const TopoDS_Edge& E1,const TopoDS_Edge& E2,const Standard_Real tol,Standard_Real& dmax) const
271 {
272 // We have the topological configuration OK : 2 edges, 2 vertices
273 // But, are these two edges well confused ?
274 Standard_Real toler = tol;
275 if (tol < 0) {
276 Standard_Real tole = BRep_Tool::Tolerance(E1) + BRep_Tool::Tolerance(E2);
277 if (toler < tole / 2.) toler = tole/2.;
278 }
279
280 // We project a list of points from each curve, on the opposite one,
281 // we check the distance
282 Standard_Integer nbint = 10;
283
284 ShapeAnalysis_Curve SAC;
285 Standard_Real cf1,cl1,cf2,cl2,u; dmax = 0;
286 Handle(Geom_Curve) C1,C2;
287 C1 = BRep_Tool::Curve (E1,cf1,cl1);
288 C2 = BRep_Tool::Curve (E2,cf2,cl2);
289 if(C1.IsNull() || C2.IsNull()) return Standard_False;
290 cf1 = Max(cf1, C1->FirstParameter());
291 cl1 = Min(cl1, C1->LastParameter());
292 Handle(Geom_TrimmedCurve) C1T = new Geom_TrimmedCurve(C1,cf1,cl1,Standard_True);
293 //pdn protection against feature in Trimmed_Curve
294 cf1 = C1T->FirstParameter();
295 cl1 = C1T->LastParameter();
296 Handle(Geom_TrimmedCurve) CC;
297 cf2 = Max(cf2, C2->FirstParameter());
298 cl2 = Min(cl2, C2->LastParameter());
299 Handle(Geom_TrimmedCurve) C2T = new Geom_TrimmedCurve(C2,cf2,cl2, Standard_True);
300 cf2 = C2T->FirstParameter();
301 cl2 = C2T->LastParameter();
302
303 Standard_Real cd1 = (cl1 - cf1)/nbint;
304 Standard_Real cd2 = (cl2 - cf2)/nbint;
305 Standard_Real f,l;
306 f = cf2; l = cl2;
307 for (int numcur = 0; numcur < 2; numcur ++) {
308 u = cf1;
309 if (numcur) { CC = C1T; C1T = C2T; C2T = CC;
310 cd1 = cd2; //smh added replacing step and replacing first
311 u = cf2; //parameter
312 f = cf1; l = cl1;
313 }
314 for (int nump = 0; nump <= nbint; nump ++) {
315 gp_Pnt p2, p1 = C1T->Value (u);
316 Standard_Real para;
317 //pdn Adaptor curve is used to avoid of enhancing of domain.
318 GeomAdaptor_Curve GAC(C2T);
319 Standard_Real dist = SAC.Project (GAC,p1,toler,p2,para);
320 //pdn check if parameter of projection is in the domain of the edge.
321 if (para < f || para > l) return Standard_False;
322 if (dist > dmax) dmax = dist;
323 if (dist > toler) return Standard_False;
324 u += cd1;
325 }
326 }
327 return (dmax < toler);
328 }
329
330 //=======================================================================
331 //function : FindStripEdges
332 //purpose :
333 //=======================================================================
334
FindStripEdges(const TopoDS_Face & F,TopoDS_Edge & E1,TopoDS_Edge & E2,const Standard_Real tol,Standard_Real & dmax)335 Standard_Boolean ShapeAnalysis_CheckSmallFace::FindStripEdges(const TopoDS_Face& F,TopoDS_Edge& E1,TopoDS_Edge& E2,const Standard_Real tol,Standard_Real& dmax)
336 {
337 E1.Nullify(); E2.Nullify();
338 Standard_Integer nb = 0;
339 for (TopExp_Explorer ex(F,TopAbs_EDGE); ex.More(); ex.Next()) {
340 TopoDS_Edge E = TopoDS::Edge (ex.Current());
341 if (nb == 1 && E.IsSame(E1))
342 continue; // ignore seam edge
343 TopoDS_Vertex V1,V2;
344 TopExp::Vertices (E,V1,V2);
345 gp_Pnt p1,p2;
346 p1 = BRep_Tool::Pnt (V1);
347 p2 = BRep_Tool::Pnt (V2);
348 Standard_Real toler = tol;
349 if (toler <= 0) toler = (BRep_Tool::Tolerance(V1) + BRep_Tool::Tolerance(V2) ) / 2.;
350
351 // Extremities
352 Standard_Real dist = p1.Distance(p2);
353 // Middle point
354 Standard_Real cf,cl;
355 Handle(Geom_Curve) CC;
356 CC = BRep_Tool::Curve (E,cf,cl);
357 Standard_Boolean isNullLength = Standard_True;
358 if (!CC.IsNull()) {
359 gp_Pnt pp = CC->Value ( (cf+cl)/2.);
360 if (pp.Distance(p1) < toler && pp.Distance(p2) < toler) continue;
361 isNullLength = Standard_False;
362 }
363 if (dist <= toler && isNullLength) continue; //smh
364 nb ++;
365 if (nb == 1) E1 = E;
366 else if (nb == 2) E2 = E;
367 else return Standard_False;
368 }
369 // Now, check these two edge to define a strip !
370 if (!E1.IsNull()&&!E2.IsNull()) {
371 if(!CheckStripEdges (E1,E2,tol,dmax)) return Standard_False;
372 else {
373 myStatusStrip = ShapeExtend::EncodeStatus (ShapeExtend_DONE3);
374 return Standard_True ;
375 }
376 }
377 return Standard_False;
378 }
379
380 //=======================================================================
381 //function : CheckSingleStrip
382 //purpose :
383 //=======================================================================
384
CheckSingleStrip(const TopoDS_Face & F,TopoDS_Edge & E1,TopoDS_Edge & E2,const Standard_Real tol)385 Standard_Boolean ShapeAnalysis_CheckSmallFace::CheckSingleStrip(const TopoDS_Face& F,
386 TopoDS_Edge& E1, TopoDS_Edge& E2,const Standard_Real tol)
387 {
388 Standard_Real toler = tol;
389 Standard_Real minx,miny,minz,maxx,maxy,maxz;
390
391 // In this case, we have 2 vertices and 2 great edges. Plus possibly 2 small
392 // edges, one on each vertex
393 TopoDS_Vertex V1,V2;
394 Standard_Integer nb = 0;
395 for (TopExp_Explorer itv (F,TopAbs_VERTEX); itv.More(); itv.Next()) {
396 TopoDS_Vertex V = TopoDS::Vertex (itv.Current());
397 if (V1.IsNull()) V1 = V;
398 else if (V1.IsSame(V)) continue;
399 else if (V2.IsNull()) V2 = V;
400 else if (V2.IsSame(V)) continue;
401 else return 0;
402 }
403
404 // Checking edges
405 //TopoDS_Edge E1,E2;
406 nb = 0;
407 for (TopExp_Explorer ite (F,TopAbs_EDGE); ite.More(); ite.Next()) {
408 TopoDS_Edge E = TopoDS::Edge (ite.Current());
409 if (nb == 1 && E.IsSame(E1))
410 continue; // ignore seam edge
411 TopoDS_Vertex VA,VB;
412 TopExp::Vertices (E,VA,VB);
413 if (tol < 0) {
414 Standard_Real tolv;
415 tolv = BRep_Tool::Tolerance (VA);
416 if (toler < tolv) toler = tolv;
417 tolv = BRep_Tool::Tolerance (VB);
418 if (toler < tolv) toler = tolv;
419 }
420
421 // Edge on same vertex : small one ?
422 if (VA.IsSame(VB)) {
423 Standard_Real cf = 0.,cl = 0.;
424 Handle(Geom_Curve) C3D;
425 if (!BRep_Tool::Degenerated(E)) C3D = BRep_Tool::Curve (E,cf,cl);
426 if (C3D.IsNull()) continue; // DGNR
427 Standard_Integer np = 0;
428 gp_Pnt deb = C3D->Value(cf);
429 MinMaxPnt (deb,np,minx,miny,minz,maxx,maxy,maxz);
430 gp_Pnt fin = C3D->Value(cl);
431 MinMaxPnt (fin,np,minx,miny,minz,maxx,maxy,maxz);
432 gp_Pnt mid = C3D->Value( (cf+cl)/2. );
433 MinMaxPnt (mid,np,minx,miny,minz,maxx,maxy,maxz);
434 if (!MinMaxSmall (minx,miny,minz,maxx,maxy,maxz,toler)) return Standard_False;
435 } else {
436 // Other case : two maximum allowed
437 nb ++;
438 if (nb > 2) return Standard_False;
439 if (nb == 1) { V1 = VA; V2 = VB; E1 = E; }
440 else if (nb == 2) {
441 if (V1.IsSame(VA) && !V2.IsSame(VB)) return Standard_False;
442 if (V1.IsSame(VB) && !V2.IsSame(VA)) return Standard_False;
443 E2 = E;
444 }
445 else return Standard_False;
446 }
447 }
448
449 if (nb < 2) return Standard_False; // only one vertex : cannot be a strip ...
450
451 // Checking if E1 and E2 define a Strip
452 Standard_Real dmax;
453 if (!CheckStripEdges (E1,E2,tol,dmax)) return Standard_False;
454 myStatusStrip = ShapeExtend::EncodeStatus (ShapeExtend_DONE3);
455 return Standard_True;
456 }
457
458 //=======================================================================
459 //function : CheckStripFace
460 //purpose :
461 //=======================================================================
462
CheckStripFace(const TopoDS_Face & F,TopoDS_Edge & E1,TopoDS_Edge & E2,const Standard_Real tol)463 Standard_Boolean ShapeAnalysis_CheckSmallFace::CheckStripFace(const TopoDS_Face& F,
464 TopoDS_Edge& E1, TopoDS_Edge& E2,const Standard_Real tol)
465 {
466
467 // Standard_Integer stat;
468 if(CheckSingleStrip (F,E1,E2,tol)) return Standard_True ; // it is a strip
469
470 // IsStripSupport used as rejection. But this kind of test may be done
471 // on ANY face, once we are SURE that FindStripEdges is reliable (and fast
472 // enough)
473
474 // ?? record a diagnostic StripFace, but without yet lists of edges
475 // ?? Record Diagnostic "StripFace", no data (should be "Edges1" "Edges2")
476 // but direction is known (1:U 2:V)
477 // TopoDS_Edge E1,E2;
478 Standard_Real dmax;
479 if(FindStripEdges (F,E1,E2,tol,dmax)) return Standard_True;
480
481 // Now, trying edges : if there are 2 and only 2 edges greater than tolerance
482 // (given or sum of vertex tolerances), do they define a strip
483 // Warning : if yes, they bring different vertices ...
484
485 return Standard_False;
486
487 }
488
489 //=======================================================================
490 //function : CheckSplittingVertices
491 //purpose :
492 //=======================================================================
493
CheckSplittingVertices(const TopoDS_Face & F,TopTools_DataMapOfShapeListOfShape & MapEdges,ShapeAnalysis_DataMapOfShapeListOfReal & MapParam,TopoDS_Compound & theAllVert)494 Standard_Integer ShapeAnalysis_CheckSmallFace::CheckSplittingVertices(const TopoDS_Face& F,
495 TopTools_DataMapOfShapeListOfShape& MapEdges,
496 ShapeAnalysis_DataMapOfShapeListOfReal& MapParam,
497 TopoDS_Compound& theAllVert)
498 {
499
500 // Prepare array of vertices with their locations //TopTools
501 Standard_Integer nbv = 0, nbp = 0;
502 //TopoDS_Compound theAllVert;
503 BRep_Builder theBuilder;
504 //theBuilder.MakeCompound(theAllVert);
505 TopExp_Explorer itv; // svv Jan11 2000 : porting on DEC
506 for (itv.Init(F,TopAbs_VERTEX); itv.More(); itv.Next()) nbv ++;
507
508 if (nbv == 0) return 0;
509 TopTools_Array1OfShape vtx (1,nbv);
510 TColgp_Array1OfPnt vtp (1,nbv);
511 TColStd_Array1OfReal vto (1,nbv);
512
513 nbp = 0;
514 for (itv.Init(F,TopAbs_VERTEX); itv.More(); itv.Next()) {
515 nbp ++;
516 TopoDS_Vertex unv = TopoDS::Vertex (itv.Current());
517 vtx.SetValue (nbp,unv);
518 gp_Pnt unp = BRep_Tool::Pnt (unv);
519 vtp.SetValue (nbp,unp);
520 Standard_Real unt = myPrecision;
521 if (unt < 0) unt =BRep_Tool::Tolerance (unv);
522 vto.SetValue (nbp,unt);
523 }
524 nbv = nbp; nbp = 0; // now, counting splitting vertices
525
526 // Check edges : are vertices (other than extremities) confused with it ?
527 ShapeAnalysis_Curve SAC;
528 for (Standard_Integer iv = 1; iv <= nbv; iv ++) {
529 TopoDS_Vertex V = TopoDS::Vertex (vtx.Value(iv));
530 TopTools_ListOfShape listEdge;
531 TColStd_ListOfReal listParam;
532 Standard_Boolean issplit = Standard_False;
533 for (TopExp_Explorer ite(F,TopAbs_EDGE); ite.More(); ite.Next()) {
534 TopoDS_Edge E = TopoDS::Edge (ite.Current());
535 TopoDS_Vertex V1,V2;
536 TopExp::Vertices (E,V1,V2);
537 Standard_Real cf,cl;
538 Handle(Geom_Curve) C3D = BRep_Tool::Curve (E,cf,cl);
539 if (C3D.IsNull()) continue;
540 if (V.IsSame(V1) || V.IsSame(V2)) continue;
541 gp_Pnt unp = vtp.Value(iv);
542 Standard_Real unt = vto.Value(iv);
543 gp_Pnt proj;
544 Standard_Real param;
545 Standard_Real dist = SAC.Project (C3D,unp,unt*10.,proj,param,cf,cl);
546 if (dist == 0.0) continue; //smh
547 // Splitting Vertex to record ?
548 if (dist < unt) {
549 // If Split occurs at beginning or end, it is not a split ...
550 Standard_Real fpar, lpar, eps = 1.e-06;
551 if (param >=cl || param <= cf) continue; // Out of range
552 fpar = param - cf; lpar = param - cl;
553 if ((Abs(fpar) < eps) || (Abs(lpar) < eps)) continue; // Near end or start
554 listEdge.Append(E);
555 listParam.Append(param);
556 issplit = Standard_True;
557
558 }
559 }
560 if(issplit) {
561 nbp ++;
562 theBuilder.Add(theAllVert, V);
563 MapEdges.Bind(V,listEdge);
564 MapParam.Bind(V,listParam);
565 }
566 }
567 if(nbp != 0)
568 myStatusSplitVert = ShapeExtend::EncodeStatus (ShapeExtend_DONE);
569 return nbp;
570 }
571
572
IsoStat(const TColgp_Array2OfPnt & poles,const Standard_Integer uorv,const Standard_Integer rank,const Standard_Real tolpin,const Standard_Real toler)573 static Standard_Integer IsoStat
574 (const TColgp_Array2OfPnt& poles,
575 const Standard_Integer uorv, const Standard_Integer rank,
576 const Standard_Real tolpin, const Standard_Real toler)
577 {
578 Standard_Integer i, np = 0;
579 Standard_Integer i0 = (uorv == 1 ? poles.LowerCol() : poles.LowerRow());
580 Standard_Integer i1 = (uorv == 1 ? poles.UpperCol() : poles.UpperRow());
581 Standard_Real xmin = 0.,ymin = 0.,zmin = 0., xmax = 0.,ymax = 0.,zmax = 0.;
582 for (i = i0; i <= i1; i ++) {
583 if (uorv == 1) MinMaxPnt (poles(rank,i),np,xmin,ymin,zmin, xmax,ymax,zmax);
584 else MinMaxPnt (poles(i,rank), np, xmin,ymin,zmin, xmax,ymax,zmax);
585 }
586 if (MinMaxSmall (xmin,ymin,zmin, xmax,ymax,zmax, tolpin)) return 0;
587 if (MinMaxSmall (xmin,ymin,zmin, xmax,ymax,zmax, toler)) return 1;
588 return 2;
589 }
590
CheckPoles(const TColgp_Array2OfPnt & poles,Standard_Integer uorv,Standard_Integer rank)591 static Standard_Boolean CheckPoles(const TColgp_Array2OfPnt& poles, Standard_Integer uorv, Standard_Integer rank)
592 {
593 Standard_Integer i0 = (uorv == 1 ? poles.LowerCol() : poles.LowerRow());
594 Standard_Integer i1 = (uorv == 1 ? poles.UpperCol() : poles.UpperRow());
595 for (Standard_Integer i = i0; i <= i1-1; i ++) {
596 if (uorv == 1) {
597 if(poles(rank,i).IsEqual(poles(rank, i+1), 1e-15)) return Standard_True;
598 } else
599 if(poles(i,rank).IsEqual(poles(i+1,rank), 1e-15)) return Standard_True;
600 }
601 return Standard_False;
602 }
603 //=======================================================================
604 //function : CheckPin
605 //purpose :
606 //=======================================================================
607
CheckPin(const TopoDS_Face & F,Standard_Integer & whatrow,Standard_Integer & sens)608 Standard_Boolean ShapeAnalysis_CheckSmallFace::CheckPin (const TopoDS_Face& F, Standard_Integer& whatrow,Standard_Integer& sens)
609 {
610 TopLoc_Location loc;
611 Handle(Geom_Surface) surf = BRep_Tool::Surface (F,loc);
612 if (surf->IsKind(STANDARD_TYPE(Geom_ElementarySurface))) return Standard_False;
613
614 Standard_Real toler = myPrecision;
615 if (toler < 0) toler = 1.e-4;
616 Standard_Real tolpin = 1.e-9; // for sharp sharp pin
617
618 // Checking the poles
619
620 // Take the poles : they give good idea of sharpness of a pin
621 Standard_Integer nbu = 0 , nbv = 0;
622 Handle(Geom_BSplineSurface) bs = Handle(Geom_BSplineSurface)::DownCast(surf);
623 Handle(Geom_BezierSurface) bz = Handle(Geom_BezierSurface)::DownCast(surf);
624 if (!bs.IsNull()) { nbu = bs->NbUPoles(); nbv = bs->NbVPoles(); }
625 if (!bz.IsNull()) { nbu = bz->NbUPoles(); nbv = bz->NbVPoles(); }
626 if (nbu == 0 || nbv == 0) return Standard_False;
627
628 TColgp_Array2OfPnt allpoles (1,nbu,1,nbv);
629 if (!bs.IsNull()) bs->Poles (allpoles);
630 if (!bz.IsNull()) bz->Poles (allpoles);
631
632 // Check each natural bound if it is a singularity (i.e. a pin)
633
634 sens = 0;
635 Standard_Integer stat = 0; // 0 none, 1 in U, 2 in V
636 whatrow = 0; // 0 no row, else rank of row
637 stat = IsoStat(allpoles,1, 1,tolpin,toler);
638 if (stat) { sens = 1; whatrow = nbu; }
639
640 stat = IsoStat(allpoles,1,nbu,tolpin,toler);
641 if (stat) { sens = 1; whatrow = nbu; }
642
643 stat = IsoStat(allpoles,2, 1,tolpin,toler);
644 if (stat) { sens = 2; whatrow = 1; }
645
646 stat = IsoStat(allpoles,2,nbv,tolpin,toler);
647 if (stat) { sens = 2; whatrow = nbv; }
648
649 if (!sens) return Standard_False; // no pin
650
651 switch(stat) {
652 case 1: myStatusPin = ShapeExtend::EncodeStatus (ShapeExtend_DONE1); break;
653 case 2: myStatusPin = ShapeExtend::EncodeStatus (ShapeExtend_DONE2); break;
654 default : break;
655 }
656 // std::cout<<(whatstat == 1 ? "Smooth" : "Sharp")<<" Pin on "<<(sens == 1 ? "U" : "V")<<" Row n0 "<<whatrow<<std::endl;
657 if (stat == 1 )
658 {
659 // Standard_Boolean EqualPoles = Standard_False;
660 if(CheckPoles(allpoles, 2, nbv)|| CheckPoles(allpoles, 2, 1)
661 ||CheckPoles(allpoles, 1, nbu)|| CheckPoles(allpoles, 1, 1))
662 myStatusPin = ShapeExtend::EncodeStatus (ShapeExtend_DONE3);
663 }
664
665
666 return Standard_True;
667 }
668
TwistedNorm(const Standard_Real x1,const Standard_Real y1,const Standard_Real z1,const Standard_Real x2,const Standard_Real y2,const Standard_Real z2)669 static Standard_Real TwistedNorm
670 (const Standard_Real x1, const Standard_Real y1, const Standard_Real z1, const Standard_Real x2, const Standard_Real y2, const Standard_Real z2)
671 { return (x1*x2) + (y1*y2) + (z1*z2); }
672
673 //=======================================================================
674 //function : CheckTwisted
675 //purpose :
676 //=======================================================================
677
CheckTwisted(const TopoDS_Face & F,Standard_Real & paramu,Standard_Real & paramv)678 Standard_Boolean ShapeAnalysis_CheckSmallFace::CheckTwisted (const TopoDS_Face& F, Standard_Real& paramu,
679 Standard_Real& paramv)
680 {
681 TopLoc_Location loc;
682 Handle(Geom_Surface) surf = BRep_Tool::Surface (F,loc);
683 if (surf->IsKind(STANDARD_TYPE(Geom_ElementarySurface))) return Standard_False;
684
685 Standard_Real toler = myPrecision;
686 if (toler < 0) toler = 1.e-4;
687 //// GeomLProp_SLProps GLS (surf,2,toler);
688 GeomAdaptor_Surface GAS (surf);
689
690 // to be done : on isos of the surface
691 // and on edges, at least of outer wire
692 Standard_Integer nbint = 5;
693 TColStd_Array2OfReal nx (1,nbint+1,1,nbint+1);
694 TColStd_Array2OfReal ny (1,nbint+1,1,nbint+1);
695 TColStd_Array2OfReal nz (1,nbint+1,1,nbint+1);
696 Standard_Integer iu,iv;
697 Standard_Real umin,umax,vmin,vmax;
698 surf->Bounds (umin,umax,vmin,vmax);
699 Standard_Real u = umin, du = (umax-umin)/nbint;
700 Standard_Real v = vmin, dv = (umax-umin)/nbint;
701
702 // gp_Dir norm;
703 for (iu = 1; iu <= nbint; iu ++) {
704 for (iv = 1; iv <= nbint; iv ++) {
705 // GLS.SetParameters (u,v);
706 // if (GLS.IsNormalDefined()) norm = GLS.Normal();
707 gp_Pnt curp; gp_Vec V1,V2,VXnorm;
708 GAS.D1 (u,v,curp,V1,V2);
709 VXnorm = V1.Crossed(V2);
710 nx.SetValue (iu,iv,VXnorm.X());
711 ny.SetValue (iu,iv,VXnorm.Y());
712 nz.SetValue (iu,iv,VXnorm.Z());
713 v += dv;
714 }
715 u += du;
716 v = vmin;
717 }
718
719 // Now, comparing normals on support surface, in both senses
720 // In principle, it suffuces to check within outer bound
721
722 for (iu = 1; iu < nbint; iu ++) {
723 for (iv = 1; iv < nbint; iv ++) {
724 // We here check each normal (iu,iv) with (iu,iv+1) and with (iu+1,iv)
725 // if for each test, we have negative scalar product, this means angle > 90deg
726 // it is the criterion to say it is twisted
727 if (TwistedNorm ( nx(iu,iv),ny(iu,iv),nz(iu,iv) , nx(iu,iv+1),ny(iu,iv+1),nz(iu,iv+1) ) < 0. ||
728 TwistedNorm ( nx(iu,iv),ny(iu,iv),nz(iu,iv) , nx(iu+1,iv),ny(iu+1,iv),nz(iu+1,iv) ) < 0. ) {
729 myStatusTwisted = ShapeExtend::EncodeStatus (ShapeExtend_DONE);
730 paramu = umin+du*iu-du/2;
731 paramv = vmin+dv*iv-dv/2;
732 return Standard_True;
733 }
734 }
735 }
736
737 // Now, comparing normals on edges ... to be done
738
739 return Standard_False;
740 }
741
742
743 //=======================================================================
744 //function : CheckPinFace
745 //purpose :
746 //=======================================================================
747 // Warning: This function not tested on many examples
748
CheckPinFace(const TopoDS_Face & F,TopTools_DataMapOfShapeShape & mapEdges,const Standard_Real toler)749 Standard_Boolean ShapeAnalysis_CheckSmallFace::CheckPinFace(const TopoDS_Face& F,
750 TopTools_DataMapOfShapeShape& mapEdges,const Standard_Real toler)
751 {
752 //ShapeFix_Wire sfw;
753 TopExp_Explorer exp_w (F,TopAbs_WIRE);
754 exp_w.More();
755 Standard_Real coef1=0, coef2; // =0 for deleting warning (skl)
756 TopoDS_Wire theCurWire = TopoDS::Wire (exp_w.Current());
757 ShapeAnalysis_WireOrder wi;
758 ShapeAnalysis_Wire sfw;
759 Handle(ShapeExtend_WireData) sbwd = new ShapeExtend_WireData(theCurWire);
760 sfw.Load(sbwd);
761 sfw.CheckOrder(wi);
762 Handle(TopTools_HSequenceOfShape) newedges = new TopTools_HSequenceOfShape();
763 Standard_Integer nb = wi.NbEdges();
764 Standard_Integer i = 0;
765 for ( i=1; i <= nb; i++ )
766 newedges->Append ( sbwd->Edge ( wi.Ordered(i) ) );
767 for ( i=1; i <= nb; i++ )
768 sbwd->Set ( TopoDS::Edge ( newedges->Value(i) ), i );
769 //sfw.Init(theCurWire, F, Precision::Confusion());
770 //sfw.FixReorder();
771 //theCurWire = sfw.Wire();
772 theCurWire = sbwd->Wire();
773 i=1;
774 Standard_Boolean done = Standard_False;
775 Standard_Real tol = Precision::Confusion();
776 TopoDS_Edge theFirstEdge, theSecondEdge;
777 Standard_Real d1=0,d2=0;
778 for (TopExp_Explorer exp_e (F,TopAbs_EDGE); exp_e.More(); exp_e.Next())
779 {
780 TopoDS_Vertex V1,V2;
781 gp_Pnt p1, p2;
782 if (i==1)
783 {
784 theFirstEdge = TopoDS::Edge (exp_e.Current());
785 V1 = TopExp::FirstVertex(theFirstEdge);
786 V2 = TopExp::LastVertex(theFirstEdge);
787 p1 = BRep_Tool::Pnt(V1);
788 p2 = BRep_Tool::Pnt(V2);
789 tol = Max(BRep_Tool::Tolerance(V1), BRep_Tool::Tolerance(V2));
790 if (toler > 0) //tol = Max(tol, toler); gka
791 tol = toler;
792 d1 = p1.Distance(p2);
793 if (d1 == 0) return Standard_False;
794 if (d1/tol>=1) coef1 = d1/tol; else continue;
795 if (coef1<=3) continue;
796 i++;
797 continue;
798 }
799 //Check the length of edge
800 theSecondEdge = TopoDS::Edge (exp_e.Current());
801 V1 = TopExp::FirstVertex(theSecondEdge);
802 V2 = TopExp::LastVertex(theSecondEdge);
803
804 p1 = BRep_Tool::Pnt(V1);
805 p2 = BRep_Tool::Pnt(V2);
806 if (toler == -1) tol = Max(BRep_Tool::Tolerance(V1), BRep_Tool::Tolerance(V2));
807 else tol= toler;
808 if (p1.Distance(p2)> tol) continue;
809 //If there are two pin edges, record them in diagnostic
810 d2 = p1.Distance(p2); //gka
811 if (d2 == 0) return Standard_False;
812 if (d2/tol >= 1) coef2 = d2/tol; else continue;
813 if (coef2<=3) continue;
814 if (coef1>coef2*10) continue;
815 if (coef2>coef1*10)
816 {
817 theFirstEdge = theSecondEdge;
818 coef1 = coef2;
819 continue;
820 }
821
822 if (CheckPinEdges(theFirstEdge, theSecondEdge, coef1, coef2,toler))
823 {
824 mapEdges.Bind(theFirstEdge,theSecondEdge);
825 myStatusPinFace = ShapeExtend::EncodeStatus (ShapeExtend_DONE);
826 done = Standard_True;
827 }
828
829 theFirstEdge = theSecondEdge;
830 coef1 = coef2;
831 //d1 = d2;
832 }
833 return done;
834 }
835
836
837 //=======================================================================
838 //function : CheckPinEdges
839 //purpose :
840 //=======================================================================
841 // Warning: This function not tested on many examples
842
CheckPinEdges(const TopoDS_Edge & theFirstEdge,const TopoDS_Edge & theSecondEdge,const Standard_Real coef1,const Standard_Real coef2,const Standard_Real toler) const843 Standard_Boolean ShapeAnalysis_CheckSmallFace::CheckPinEdges(const TopoDS_Edge& theFirstEdge,const TopoDS_Edge& theSecondEdge,const Standard_Real coef1,
844 const Standard_Real coef2,const Standard_Real toler) const
845 {
846
847 Standard_Real cf1,cl1,cf2,cl2;
848 Handle(Geom_Curve) C1,C2,C3;
849 C1 = BRep_Tool::Curve (theFirstEdge,cf1,cl1);
850 C2 = BRep_Tool::Curve (theSecondEdge,cf2,cl2);
851 gp_Pnt p1, p2, pp1, pp2, pv;
852 Standard_Real d1 = (cf1-cl1)/coef1;
853 Standard_Real d2 = (cf2-cl2)/coef2;
854 //Standard_Real d1 = cf1-cl1/30; //10; gka
855 //Standard_Real d2 = cf2-cl2/30; //10;
856 p1 = C1->Value(cf1);
857 p2 = C1->Value(cl1);
858 pp1 = C2->Value(cf2);
859 pp2 = C2->Value(cl2);
860 Standard_Real tol;
861 Standard_Real paramc1=0, paramc2=0; // =0 for deleting warning (skl)
862 TopoDS_Vertex theSharedV = TopExp::LastVertex(theFirstEdge);
863 if (toler == -1) tol = BRep_Tool::Tolerance(theSharedV); else tol = toler;
864 pv = BRep_Tool::Pnt(theSharedV);
865 if (pv.Distance(p1)<=tol) paramc1 = cf1;
866 else if(pv.Distance(p2)<=tol) paramc1 = cl1;
867 if (pv.Distance(pp1)<=tol) paramc2 = cf2;
868 else if(pv.Distance(pp2)<=tol) paramc2 = cl2;
869 //Computing first derivative vectors and compare angle
870 // gp_Vec V11, V12, V21, V22;
871 // gp_Pnt tmp;
872 // C1->D2(paramc1, tmp, V11, V21);
873 // C2->D2(paramc2, tmp, V12, V22);
874 // Standard_Real angle1, angle2;
875 // try{
876 // angle1 = V11.Angle(V12);
877 // angle2 = V21.Angle(V22);
878 // }
879 // catch (Standard_Failure)
880 // {
881 // std::cout << "Couldn't compute angle between derivative vectors" <<std::endl;
882 // return Standard_False;
883 // }
884 // std::cout << "angle1 " << angle1<< std::endl;
885 // std::cout << "angle2 " << angle2<< std::endl;
886 // if (angle1<=0.0001) return Standard_True;
887 gp_Pnt proj;
888 if (p1.Distance(p2)<pp1.Distance(pp2))
889 {
890 C3=C1;
891 if (paramc1==cf1)
892 proj = C1->Value(paramc1 + (coef1-3)*d1);
893 else proj = C1->Value(paramc1-3*d1);
894 //proj = C1->Value(paramc1 + 9*d1);
895 //else proj = C1->Value(paramc1-d1);
896 }
897 else
898 {
899 C3=C2;
900 if (paramc2==cf2)
901 proj = C2->Value(paramc2 + (coef2-3)*d2);
902 else proj = C2->Value(paramc2 -3*d2);
903 //proj = C2->Value(paramc2 + 9*d2);
904 //else proj = C2->Value(paramc2 -d2);
905 }
906 Standard_Real param;
907 GeomAdaptor_Curve GAC(C3);
908 Standard_Real f = C3->FirstParameter();
909 Standard_Real l = C3->LastParameter();
910 gp_Pnt result;
911 ShapeAnalysis_Curve SAC;
912 Standard_Real dist = SAC.Project (GAC,proj,tol,result,param);
913 //pdn check if parameter of projection is in the domain of the edge.
914 if (param < f || param > l) return Standard_False;
915 if (dist > tol) return Standard_False;
916 if (dist <= tol) {
917 //Computing first derivative vectors and compare angle
918 gp_Vec V11, V12, V21, V22;
919 gp_Pnt tmp;
920 C1->D2(paramc1, tmp, V11, V21);
921 C2->D2(paramc2, tmp, V12, V22);
922 Standard_Real angle1=0, angle2=0;
923 try{
924 angle1 = V11.Angle(V12);
925 angle2 = V21.Angle(V22);
926 }
927 catch (Standard_Failure const&)
928 {
929 #ifdef OCCT_DEBUG
930 std::cout << "Couldn't compute angle between derivative vectors" <<std::endl;
931 #endif
932 return Standard_False;
933 }
934 // std::cout << "angle1 " << angle1<< std::endl;
935 // std::cout << "angle2 " << angle2<< std::endl;
936 if ((angle1<=0.001 && angle2<=0.01) || ((M_PI-angle2)<= 0.001 && (M_PI-angle2)<= 0.01)) return Standard_True;
937 else return Standard_False;
938 }
939
940 return Standard_False;
941 }
942
943