0031668: Visualization - WebGL sample doesn't work on Emscripten 1.39
[occt.git] / src / ChFi3d / ChFi3d.cxx
1 // Created on: 1993-12-21
2 // Created by: Isabelle GRIGNON
3 // Copyright (c) 1993-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
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
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.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17
18 #include <BRep_Tool.hxx>
19 #include <BRepAdaptor_Curve.hxx>
20 #include <BRepAdaptor_Curve2d.hxx>
21 #include <BRepAdaptor_Surface.hxx>
22 #include <ChFi3d.hxx>
23 #include <ChFi3d_Builder_0.hxx>
24 #include <gp_Pnt.hxx>
25 #include <gp_Pnt2d.hxx>
26 #include <gp_Vec.hxx>
27 #include <gp_Vec2d.hxx>
28 #include <Precision.hxx>
29 #include <TopExp_Explorer.hxx>
30 #include <TopoDS.hxx>
31 #include <TopoDS_Edge.hxx>
32 #include <BRepTools.hxx>
33 #include <IntTools_Tools.hxx>
34 #include <BRepAdaptor_HSurface.hxx>
35 #include <BRepTopAdaptor_TopolTool.hxx>
36 #include <LocalAnalysis_SurfaceContinuity.hxx>
37 #include <TopOpeBRepTool_TOOL.hxx>
38
39
40 static void Correct2dPoint(const TopoDS_Face& theF, gp_Pnt2d& theP2d);
41 //
42
43 //=======================================================================
44 //function : DefineConnectType
45 //purpose  : 
46 //=======================================================================
47 ChFiDS_TypeOfConcavity ChFi3d::DefineConnectType(const TopoDS_Edge&     E,
48                                                  const TopoDS_Face&     F1,
49                                                  const TopoDS_Face&     F2,
50                                                  const Standard_Real    SinTol,
51                                                  const Standard_Boolean CorrectPoint)
52 {
53   const Handle(Geom_Surface)& S1 = BRep_Tool::Surface(F1);
54   const Handle(Geom_Surface)& S2 = BRep_Tool::Surface(F2);
55   //
56   Standard_Real   f,l;
57   Handle (Geom2d_Curve) C1 = BRep_Tool::CurveOnSurface(E,F1,f,l);
58   //For the case of seam edge
59   TopoDS_Edge EE = E;
60   if (F1.IsSame(F2))
61     EE.Reverse();
62   Handle (Geom2d_Curve) C2 = BRep_Tool::CurveOnSurface(EE,F2,f,l);
63   if (C1.IsNull() || C2.IsNull())
64     return ChFiDS_Other;
65
66   BRepAdaptor_Curve C(E);
67   f = C.FirstParameter();
68   l = C.LastParameter();
69 //
70   Standard_Real ParOnC = 0.5*(f+l);
71   gp_Vec T1 = C.DN(ParOnC,1);
72   if (T1.SquareMagnitude() <= gp::Resolution())
73   {
74     ParOnC = IntTools_Tools::IntermediatePoint(f,l);
75     T1 = C.DN(ParOnC,1);
76   }
77   if (T1.SquareMagnitude() > gp::Resolution()) {
78     T1.Normalize();
79   }
80   
81   if (BRepTools::OriEdgeInFace(E,F1) == TopAbs_REVERSED) {
82     T1.Reverse();
83   }
84   if (F1.Orientation() == TopAbs_REVERSED) T1.Reverse();
85
86   gp_Pnt2d P  = C1->Value(ParOnC);
87   gp_Pnt   P3;
88   gp_Vec   D1U,D1V;
89   
90   if(CorrectPoint) 
91     Correct2dPoint(F1, P);
92   //
93   S1->D1(P.X(),P.Y(),P3,D1U,D1V);
94   gp_Vec DN1(D1U^D1V);
95   if (F1.Orientation() == TopAbs_REVERSED) DN1.Reverse();
96   
97   P = C2->Value(ParOnC);
98   if(CorrectPoint) 
99     Correct2dPoint(F2, P);
100   S2->D1(P.X(),P.Y(),P3,D1U,D1V);
101   gp_Vec DN2(D1U^D1V);
102   if (F2.Orientation() == TopAbs_REVERSED) DN2.Reverse();
103
104   DN1.Normalize();
105   DN2.Normalize();
106
107   gp_Vec        ProVec     = DN1^DN2;
108   Standard_Real NormProVec = ProVec.Magnitude(); 
109   if (NormProVec < SinTol) {
110     // plane
111     if (DN1.Dot(DN2) > 0) {   
112       //Tangent
113       return ChFiDS_Tangential;
114     }
115     else  {                   
116       //Mixed not finished!
117 #ifdef OCCT_DEBUG
118       std::cout <<" faces locally mixed"<<std::endl;
119 #endif
120       return ChFiDS_Convex;
121     }
122   }
123   else {  
124     if (NormProVec > gp::Resolution())
125       ProVec /= NormProVec;
126     Standard_Real Prod  = T1.Dot(ProVec);
127     if (Prod > 0.) {       
128       //
129       return ChFiDS_Convex;
130     }
131     else {                       
132       //reenters
133       return ChFiDS_Concave;
134     }
135   }
136 }
137
138 //=======================================================================
139 //function : IsTangentFaces
140 //purpose  : 
141 //=======================================================================
142 Standard_Boolean ChFi3d::IsTangentFaces(const TopoDS_Edge& theEdge,
143                                         const TopoDS_Face& theFace1,
144                                         const TopoDS_Face& theFace2,
145                                         const GeomAbs_Shape Order)
146 {
147   if (Order == GeomAbs_G1 && BRep_Tool::Continuity(theEdge, theFace1, theFace2) != GeomAbs_C0)
148     return Standard_True;
149
150   Standard_Real TolC0 = Max(0.001, 1.5*BRep_Tool::Tolerance(theEdge));
151
152   Standard_Real aFirst;
153   Standard_Real aLast;
154
155   // Obtaining of pcurves of edge on two faces.
156   const Handle(Geom2d_Curve) aC2d1 = BRep_Tool::CurveOnSurface
157     (theEdge, theFace1, aFirst, aLast);
158   //For the case of seam edge
159   TopoDS_Edge EE = theEdge;
160   if (theFace1.IsSame(theFace2))
161     EE.Reverse();
162   const Handle(Geom2d_Curve) aC2d2 = BRep_Tool::CurveOnSurface
163     (EE, theFace2, aFirst, aLast);
164   if (aC2d1.IsNull() || aC2d2.IsNull())
165     return Standard_False;
166
167   // Obtaining of two surfaces from adjacent faces.
168   Handle(Geom_Surface) aSurf1 = BRep_Tool::Surface(theFace1);
169   Handle(Geom_Surface) aSurf2 = BRep_Tool::Surface(theFace2);
170
171   if (aSurf1.IsNull() || aSurf2.IsNull())
172     return Standard_False;
173
174   // Computation of the number of samples on the edge.
175   BRepAdaptor_Surface              aBAS1(theFace1);
176   BRepAdaptor_Surface              aBAS2(theFace2);
177   Handle(BRepAdaptor_HSurface)     aBAHS1 = new BRepAdaptor_HSurface(aBAS1);
178   Handle(BRepAdaptor_HSurface)     aBAHS2 = new BRepAdaptor_HSurface(aBAS2);
179   Handle(BRepTopAdaptor_TopolTool) aTool1 = new BRepTopAdaptor_TopolTool(aBAHS1);
180   Handle(BRepTopAdaptor_TopolTool) aTool2 = new BRepTopAdaptor_TopolTool(aBAHS2);
181   Standard_Integer                 aNbSamples1 = aTool1->NbSamples();
182   Standard_Integer                 aNbSamples2 = aTool2->NbSamples();
183   Standard_Integer                 aNbSamples = Max(aNbSamples1, aNbSamples2);
184
185   // Computation of the continuity.
186   Standard_Real    aPar;
187   Standard_Real    aDelta = (aLast - aFirst) / (aNbSamples - 1);
188   Standard_Integer i, nbNotDone = 0;
189
190   for (i = 1, aPar = aFirst; i <= aNbSamples; i++, aPar += aDelta) {
191     if (i == aNbSamples) aPar = aLast;
192
193     LocalAnalysis_SurfaceContinuity aCont(aC2d1, aC2d2, aPar,
194       aSurf1, aSurf2, Order,
195       0.001, TolC0, 0.1, 0.1, 0.1);
196     if (!aCont.IsDone())
197     {
198       nbNotDone++;
199       continue;
200     }
201
202     if (Order == GeomAbs_G1)
203     {
204       if (!aCont.IsG1())
205         return Standard_False;
206     }
207     else if (!aCont.IsG2())
208       return Standard_False;
209   }
210
211   if (nbNotDone == aNbSamples)
212     return Standard_False;
213
214   //Compare normals of tangent faces in the middle point
215   Standard_Real MidPar = (aFirst + aLast) / 2.;
216   gp_Pnt2d uv1 = aC2d1->Value(MidPar);
217   gp_Pnt2d uv2 = aC2d2->Value(MidPar);
218   gp_Dir normal1, normal2;
219   TopOpeBRepTool_TOOL::Nt(uv1, theFace1, normal1);
220   TopOpeBRepTool_TOOL::Nt(uv2, theFace2, normal2);
221   Standard_Real dot = normal1.Dot(normal2);
222   if (dot < 0.)
223     return Standard_False;
224   return Standard_True;
225 }
226
227 //=======================================================================
228 //function : ConcaveSide
229 //purpose  : calculate the concave face at the neighborhood of the border of
230 //           2 faces.
231 //=======================================================================
232 Standard_Integer ChFi3d::ConcaveSide(const BRepAdaptor_Surface& S1, 
233                                      const BRepAdaptor_Surface& S2, 
234                                      const TopoDS_Edge& E, 
235                                      TopAbs_Orientation& Or1, 
236                                      TopAbs_Orientation& Or2)
237
238 {
239   Standard_Integer ChoixConge;
240   Or1 = Or2 = TopAbs_FORWARD;
241   BRepAdaptor_Curve CE(E);
242   Standard_Real first = CE.FirstParameter();
243   Standard_Real last = CE.LastParameter();
244   Standard_Real par = 0.691254*first + 0.308746*last;
245
246   gp_Pnt pt, pt1, pt2; gp_Vec tgE, tgE1, tgE2, ns1, ns2, dint1, dint2;
247   TopoDS_Face F1 = S1.Face();
248   TopoDS_Face F2 = S2.Face();
249   //F1.Orientation(TopAbs_FORWARD);
250   //F2.Orientation(TopAbs_FORWARD);
251   
252   CE.D1(par,pt,tgE);
253   tgE.Normalize();
254   tgE2 = tgE1 = tgE;
255   if(E.Orientation() == TopAbs_REVERSED) tgE.Reverse();
256
257   TopoDS_Edge E1 = E, E2 = E;
258   E1.Orientation(TopAbs_FORWARD);
259   E2.Orientation(TopAbs_FORWARD);
260
261   if(F1.IsSame(F2) && BRep_Tool::IsClosed(E,F1)) {
262     E2.Orientation(TopAbs_REVERSED);
263     tgE2.Reverse();
264   }
265   else {
266     TopExp_Explorer Exp;
267     Standard_Boolean found = 0;
268     for (Exp.Init(F1,TopAbs_EDGE); 
269          Exp.More() && !found; 
270          Exp.Next()) {
271       if (E.IsSame(TopoDS::Edge(Exp.Current()))){
272         if(Exp.Current().Orientation() == TopAbs_REVERSED) tgE1.Reverse();
273         found = Standard_True;
274       }
275     }
276     if (!found) { return 0; }
277     found = 0;
278     for (Exp.Init(F2,TopAbs_EDGE); 
279          Exp.More() && !found; 
280          Exp.Next()) {
281       if (E.IsSame(TopoDS::Edge(Exp.Current()))){
282         if(Exp.Current().Orientation() == TopAbs_REVERSED) tgE2.Reverse();
283         found = Standard_True;
284       }
285     }
286     if (!found) { return 0; }
287   }
288   BRepAdaptor_Curve2d pc1(E1,F1);
289   BRepAdaptor_Curve2d pc2(E2,F2);
290   gp_Pnt2d p2d1,p2d2;
291   gp_Vec DU1,DV1,DU2,DV2;
292   p2d1 = pc1.Value(par);
293   p2d2 = pc2.Value(par);
294   S1.D1(p2d1.X(),p2d1.Y(),pt1,DU1,DV1);
295   ns1 = DU1.Crossed(DV1);
296   ns1.Normalize();
297   if (F1.Orientation() == TopAbs_REVERSED)
298     ns1.Reverse();
299   S2.D1(p2d2.X(),p2d2.Y(),pt2,DU2,DV2);
300   ns2 = DU2.Crossed(DV2);
301   ns2.Normalize();
302   if (F2.Orientation() == TopAbs_REVERSED)
303     ns2.Reverse();
304
305   dint1 = ns1.Crossed(tgE1);
306   dint2 = ns2.Crossed(tgE2);
307   Standard_Real ang = ns1.CrossMagnitude(ns2);
308   if(ang > 0.0001*M_PI){
309     Standard_Real scal = ns2.Dot(dint1);
310     if ( scal <= 0. ){
311       ns2.Reverse();
312       Or2 = TopAbs_REVERSED; 
313     }
314     scal = ns1.Dot(dint2);
315     if ( scal <= 0. ){
316       ns1.Reverse();
317       Or1 = TopAbs_REVERSED; 
318     }
319   }
320   else { 
321     //the faces are locally tangent - this is fake!
322     if(dint1.Dot(dint2) < 0.){
323       //This is a forgotten regularity
324       gp_Vec DDU, DDV, DDUV;
325       S1.D2(p2d1.X(),p2d1.Y(),pt1,DU1,DV1,DDU,DDV,DDUV);
326       DU1 += ( DU1 * dint1 < 0) ? -DDU : DDU;
327       DV1 += ( DV1 * dint1 < 0) ? -DDV : DDV;
328       ns1 = DU1.Crossed(DV1);
329       ns1.Normalize();
330       if (F1.Orientation() == TopAbs_REVERSED)
331         ns1.Reverse();
332       S2.D2(p2d2.X(),p2d2.Y(),pt2,DU2,DV2,DDU,DDV,DDUV);
333       DU2 += ( DU2 * dint2 < 0) ? -DDU : DDU;
334       DV2 += ( DV2 * dint2 < 0) ? -DDV : DDV;
335       ns2 = DU2.Crossed(DV2);
336       ns2.Normalize();
337       if (F2.Orientation() == TopAbs_REVERSED)
338         ns2.Reverse();
339       
340       dint1 = ns1.Crossed(tgE1);
341       dint2 = ns2.Crossed(tgE2);
342       ang = ns1.CrossMagnitude(ns2);
343       if(ang > 0.0001*M_PI){
344         Standard_Real scal = ns2.Dot(dint1);
345         if ( scal <= 0. ){
346           ns2.Reverse();
347           Or2 = TopAbs_REVERSED; 
348         }
349         scal = ns1.Dot(dint2);
350         if ( scal <= 0. ){
351           ns1.Reverse();
352           Or1 = TopAbs_REVERSED; 
353         }
354       }
355       else {
356 #ifdef OCCT_DEBUG
357         std::cout<<"ConcaveSide : no concave face"<<std::endl;
358 #endif
359         //This 10 shows that the face at end is in the extension of one of two base faces
360         return 10;
361       }
362     }
363     else {
364       //here it turns back, the points are taken in faces
365       //neither too close nor too far as much as possible.
366       Standard_Real u,v;
367 #ifdef OCCT_DEBUG
368 //      Standard_Real deport = 1000*BRep_Tool::Tolerance(E);
369 #endif
370       ChFi3d_Coefficient(dint1,DU1,DV1,u,v);
371       p2d1.SetX(p2d1.X() + u); p2d1.SetY(p2d1.Y() + v);
372       ChFi3d_Coefficient(dint1,DU2,DV2,u,v);
373       p2d2.SetX(p2d2.X() + u); p2d2.SetY(p2d2.Y() + v);
374       S1.D1(p2d1.X(),p2d1.Y(),pt1,DU1,DV1);
375       ns1 = DU1.Crossed(DV1);
376       if (F1.Orientation() == TopAbs_REVERSED)
377         ns1.Reverse();
378       S2.D1(p2d2.X(),p2d2.Y(),pt2,DU2,DV2);
379       ns2 = DU2.Crossed(DV2);
380       if (F2.Orientation() == TopAbs_REVERSED)
381         ns2.Reverse();
382       gp_Vec vref(pt1,pt2);
383       if(ns1.Dot(vref) < 0.){
384         Or1 = TopAbs_REVERSED;
385       }
386       if(ns2.Dot(vref) > 0.){
387         Or2 = TopAbs_REVERSED;
388       }
389     }
390   }
391
392
393   if (Or1 == TopAbs_FORWARD) {
394     if (Or2 == TopAbs_FORWARD) ChoixConge = 1;
395     else ChoixConge = 7;
396   }
397   else {
398     if (Or2 == TopAbs_FORWARD) ChoixConge = 3;
399     else ChoixConge = 5;
400   }
401   if ((ns1.Crossed(ns2)).Dot(tgE) >= 0.) ChoixConge++ ;
402   return ChoixConge;
403 }
404
405 //=======================================================================
406 //function : NextSide
407 //purpose  : 
408 //           
409 //=======================================================================
410
411 Standard_Integer  ChFi3d::NextSide(TopAbs_Orientation& Or1, 
412                                    TopAbs_Orientation& Or2,
413                                    const TopAbs_Orientation OrSave1, 
414                                    const TopAbs_Orientation OrSave2,
415                                    const Standard_Integer ChoixSave)
416 {
417   if (Or1 == TopAbs_FORWARD){Or1 = OrSave1;}
418   else {
419     Or1 = TopAbs::Reverse(OrSave1);
420   }
421   if (Or2 == TopAbs_FORWARD){Or2 = OrSave2;}
422   else {
423     Or2 = TopAbs::Reverse(OrSave2);
424   }
425
426   Standard_Integer ChoixConge;
427   if (Or1 == TopAbs_FORWARD) {
428     if (Or2 == TopAbs_FORWARD) ChoixConge = 1;
429     else {
430       if(ChoixSave < 0) ChoixConge = 3;
431       else ChoixConge = 7;
432     }
433   }
434   else {
435     if (Or2 == TopAbs_FORWARD) {
436       if(ChoixSave < 0) ChoixConge = 7;
437       else ChoixConge = 3;
438     }
439     else ChoixConge = 5;
440   }
441   if (Abs(ChoixSave)%2 == 0) ChoixConge++;
442   return ChoixConge;
443 }
444
445
446 //=======================================================================
447 //function : NextSide
448 //purpose  : 
449 //           
450 //=======================================================================
451
452 void ChFi3d::NextSide(TopAbs_Orientation& Or, 
453                      const TopAbs_Orientation OrSave, 
454                      const TopAbs_Orientation OrFace) 
455 {
456   if (Or == OrFace){Or = OrSave;}
457   else {
458     Or = TopAbs::Reverse(OrSave);
459   }
460 }
461
462
463
464 //=======================================================================
465 //function : SameSide
466 //purpose  : 
467 //           
468 //=======================================================================
469
470 Standard_Boolean  ChFi3d::SameSide(const TopAbs_Orientation Or, 
471                                    const TopAbs_Orientation OrSave1, 
472                                    const TopAbs_Orientation OrSave2,
473                                    const TopAbs_Orientation OrFace1, 
474                                    const TopAbs_Orientation OrFace2)
475 {
476   TopAbs_Orientation o1,o2;
477   if (Or == OrFace1){o1 = OrSave1;}
478   else {
479     o1 = TopAbs::Reverse(OrSave1);
480   }
481   if (Or == OrFace2){o2 = OrSave2;}
482   else {
483     o2 = TopAbs::Reverse(OrSave2);
484   }
485   return (o1 == o2);
486 }
487
488 //=======================================================================
489 //function : Correct2dPoint
490 //purpose  : 
491 //=======================================================================
492 void Correct2dPoint(const TopoDS_Face& theF, gp_Pnt2d& theP2d)
493 {
494   BRepAdaptor_Surface aBAS(theF, Standard_False);
495   if (aBAS.GetType() < GeomAbs_BezierSurface) {
496     return;
497   }
498   //
499   const Standard_Real coeff = 0.01;
500   Standard_Real eps;
501   Standard_Real u1, u2, v1, v2;
502   //
503   aBAS.Initialize(theF, Standard_True);
504   u1 = aBAS.FirstUParameter();
505   u2 = aBAS.LastUParameter();
506   v1 = aBAS.FirstVParameter();
507   v2 = aBAS.LastVParameter();
508   if (!(Precision::IsInfinite(u1) || Precision::IsInfinite(u2)))
509   {
510     eps = Max(coeff*(u2 - u1), Precision::PConfusion());
511     if (Abs(theP2d.X() - u1) < eps)
512     {
513       theP2d.SetX(u1 + eps);
514     }
515     if (Abs(theP2d.X() - u2) < eps)
516     {
517       theP2d.SetX(u2 - eps);
518     }
519   }
520   if (!(Precision::IsInfinite(v1) || Precision::IsInfinite(v2)))
521   {
522     eps = Max(coeff*(v2 - v1), Precision::PConfusion());
523     if (Abs(theP2d.Y() - v1) < eps)
524     {
525       theP2d.SetY(v1 + eps);
526     }
527     if (Abs(theP2d.Y() - v2) < eps)
528     {
529       theP2d.SetY(v2 - eps);
530     }
531   }
532 }