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