0031642: Visualization - crash in Graphic3d_Structure::SetVisual() on redisplaying...
[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
35 static void Correct2dPoint(const TopoDS_Face& theF, gp_Pnt2d& theP2d);
36 //
37
38 //=======================================================================
39 //function : DefineConnectType
40 //purpose  : 
41 //=======================================================================
42 ChFiDS_TypeOfConcavity ChFi3d::DefineConnectType(const TopoDS_Edge&     E,
43                                                  const TopoDS_Face&     F1,
44                                                  const TopoDS_Face&     F2,
45                                                  const Standard_Real    SinTol,
46                                                  const Standard_Boolean CorrectPoint)
47 {
48   const Handle(Geom_Surface)& S1 = BRep_Tool::Surface(F1);
49   const Handle(Geom_Surface)& S2 = BRep_Tool::Surface(F2);
50   //
51   Standard_Real   f,l;
52   Handle (Geom2d_Curve) C1 = BRep_Tool::CurveOnSurface(E,F1,f,l);
53   //For the case of seam edge
54   TopoDS_Edge EE = E;
55   if (F1.IsSame(F2))
56     EE.Reverse();
57   Handle (Geom2d_Curve) C2 = BRep_Tool::CurveOnSurface(EE,F2,f,l);
58   if (C1.IsNull() || C2.IsNull())
59     return ChFiDS_Other;
60
61   BRepAdaptor_Curve C(E);
62   f = C.FirstParameter();
63   l = C.LastParameter();
64 //
65   Standard_Real ParOnC = 0.5*(f+l);
66   gp_Vec T1 = C.DN(ParOnC,1);
67   if (T1.SquareMagnitude() <= gp::Resolution())
68   {
69     ParOnC = IntTools_Tools::IntermediatePoint(f,l);
70     T1 = C.DN(ParOnC,1);
71   }
72   if (T1.SquareMagnitude() > gp::Resolution()) {
73     T1.Normalize();
74   }
75   
76   if (BRepTools::OriEdgeInFace(E,F1) == TopAbs_REVERSED) {
77     T1.Reverse();
78   }
79   if (F1.Orientation() == TopAbs_REVERSED) T1.Reverse();
80
81   gp_Pnt2d P  = C1->Value(ParOnC);
82   gp_Pnt   P3;
83   gp_Vec   D1U,D1V;
84   
85   if(CorrectPoint) 
86     Correct2dPoint(F1, P);
87   //
88   S1->D1(P.X(),P.Y(),P3,D1U,D1V);
89   gp_Vec DN1(D1U^D1V);
90   if (F1.Orientation() == TopAbs_REVERSED) DN1.Reverse();
91   
92   P = C2->Value(ParOnC);
93   if(CorrectPoint) 
94     Correct2dPoint(F2, P);
95   S2->D1(P.X(),P.Y(),P3,D1U,D1V);
96   gp_Vec DN2(D1U^D1V);
97   if (F2.Orientation() == TopAbs_REVERSED) DN2.Reverse();
98
99   DN1.Normalize();
100   DN2.Normalize();
101
102   gp_Vec        ProVec     = DN1^DN2;
103   Standard_Real NormProVec = ProVec.Magnitude(); 
104
105   if (NormProVec < SinTol) {
106     // plane
107     if (DN1.Dot(DN2) > 0) {   
108       //Tangent
109       return ChFiDS_Tangential;
110     }
111     else  {                   
112       //Mixed not finished!
113 #ifdef OCCT_DEBUG
114       std::cout <<" faces locally mixed"<<std::endl;
115 #endif
116       return ChFiDS_Convex;
117     }
118   }
119   else {  
120     if (NormProVec > gp::Resolution())
121       ProVec /= NormProVec;
122     Standard_Real Prod  = T1.Dot(ProVec);
123     if (Prod > 0.) {       
124       //
125       return ChFiDS_Convex;
126     }
127     else {                       
128       //reenters
129       return ChFiDS_Concave;
130     }
131   }
132 }
133
134 //=======================================================================
135 //function : ConcaveSide
136 //purpose  : calculate the concave face at the neighborhood of the border of
137 //           2 faces.
138 //=======================================================================
139 Standard_Integer ChFi3d::ConcaveSide(const BRepAdaptor_Surface& S1, 
140                                      const BRepAdaptor_Surface& S2, 
141                                      const TopoDS_Edge& E, 
142                                      TopAbs_Orientation& Or1, 
143                                      TopAbs_Orientation& Or2)
144
145 {
146   Standard_Integer ChoixConge;
147   Or1 = Or2 = TopAbs_FORWARD;
148   BRepAdaptor_Curve CE(E);
149   Standard_Real first = CE.FirstParameter();
150   Standard_Real last = CE.LastParameter();
151   Standard_Real par = 0.691254*first + 0.308746*last;
152
153   gp_Pnt pt, pt1, pt2; gp_Vec tgE, tgE1, tgE2, ns1, ns2, dint1, dint2;
154   TopoDS_Face F1 = S1.Face();
155   TopoDS_Face F2 = S2.Face();
156   //F1.Orientation(TopAbs_FORWARD);
157   //F2.Orientation(TopAbs_FORWARD);
158   
159   CE.D1(par,pt,tgE);
160   tgE.Normalize();
161   tgE2 = tgE1 = tgE;
162   if(E.Orientation() == TopAbs_REVERSED) tgE.Reverse();
163
164   TopoDS_Edge E1 = E, E2 = E;
165   E1.Orientation(TopAbs_FORWARD);
166   E2.Orientation(TopAbs_FORWARD);
167
168   if(F1.IsSame(F2) && BRep_Tool::IsClosed(E,F1)) {
169     E2.Orientation(TopAbs_REVERSED);
170     tgE2.Reverse();
171   }
172   else {
173     TopExp_Explorer Exp;
174     Standard_Boolean found = 0;
175     for (Exp.Init(F1,TopAbs_EDGE); 
176          Exp.More() && !found; 
177          Exp.Next()) {
178       if (E.IsSame(TopoDS::Edge(Exp.Current()))){
179         if(Exp.Current().Orientation() == TopAbs_REVERSED) tgE1.Reverse();
180         found = Standard_True;
181       }
182     }
183     if (!found) { return 0; }
184     found = 0;
185     for (Exp.Init(F2,TopAbs_EDGE); 
186          Exp.More() && !found; 
187          Exp.Next()) {
188       if (E.IsSame(TopoDS::Edge(Exp.Current()))){
189         if(Exp.Current().Orientation() == TopAbs_REVERSED) tgE2.Reverse();
190         found = Standard_True;
191       }
192     }
193     if (!found) { return 0; }
194   }
195   BRepAdaptor_Curve2d pc1(E1,F1);
196   BRepAdaptor_Curve2d pc2(E2,F2);
197   gp_Pnt2d p2d1,p2d2;
198   gp_Vec DU1,DV1,DU2,DV2;
199   p2d1 = pc1.Value(par);
200   p2d2 = pc2.Value(par);
201   S1.D1(p2d1.X(),p2d1.Y(),pt1,DU1,DV1);
202   ns1 = DU1.Crossed(DV1);
203   ns1.Normalize();
204   if (F1.Orientation() == TopAbs_REVERSED)
205     ns1.Reverse();
206   S2.D1(p2d2.X(),p2d2.Y(),pt2,DU2,DV2);
207   ns2 = DU2.Crossed(DV2);
208   ns2.Normalize();
209   if (F2.Orientation() == TopAbs_REVERSED)
210     ns2.Reverse();
211
212   dint1 = ns1.Crossed(tgE1);
213   dint2 = ns2.Crossed(tgE2);
214   Standard_Real ang = ns1.CrossMagnitude(ns2);
215   if(ang > 0.0001*M_PI){
216     Standard_Real scal = ns2.Dot(dint1);
217     if ( scal <= 0. ){
218       ns2.Reverse();
219       Or2 = TopAbs_REVERSED; 
220     }
221     scal = ns1.Dot(dint2);
222     if ( scal <= 0. ){
223       ns1.Reverse();
224       Or1 = TopAbs_REVERSED; 
225     }
226   }
227   else { 
228     //the faces are locally tangent - this is fake!
229     if(dint1.Dot(dint2) < 0.){
230       //This is a forgotten regularity
231       gp_Vec DDU, DDV, DDUV;
232       S1.D2(p2d1.X(),p2d1.Y(),pt1,DU1,DV1,DDU,DDV,DDUV);
233       DU1 += ( DU1 * dint1 < 0) ? -DDU : DDU;
234       DV1 += ( DV1 * dint1 < 0) ? -DDV : DDV;
235       ns1 = DU1.Crossed(DV1);
236       ns1.Normalize();
237       if (F1.Orientation() == TopAbs_REVERSED)
238         ns1.Reverse();
239       S2.D2(p2d2.X(),p2d2.Y(),pt2,DU2,DV2,DDU,DDV,DDUV);
240       DU2 += ( DU2 * dint2 < 0) ? -DDU : DDU;
241       DV2 += ( DV2 * dint2 < 0) ? -DDV : DDV;
242       ns2 = DU2.Crossed(DV2);
243       ns2.Normalize();
244       if (F2.Orientation() == TopAbs_REVERSED)
245         ns2.Reverse();
246       
247       dint1 = ns1.Crossed(tgE1);
248       dint2 = ns2.Crossed(tgE2);
249       ang = ns1.CrossMagnitude(ns2);
250       if(ang > 0.0001*M_PI){
251         Standard_Real scal = ns2.Dot(dint1);
252         if ( scal <= 0. ){
253           ns2.Reverse();
254           Or2 = TopAbs_REVERSED; 
255         }
256         scal = ns1.Dot(dint2);
257         if ( scal <= 0. ){
258           ns1.Reverse();
259           Or1 = TopAbs_REVERSED; 
260         }
261       }
262       else {
263 #ifdef OCCT_DEBUG
264         std::cout<<"ConcaveSide : no concave face"<<std::endl;
265 #endif
266         //This 10 shows that the face at end is in the extension of one of two base faces
267         return 10;
268       }
269     }
270     else {
271       //here it turns back, the points are taken in faces
272       //neither too close nor too far as much as possible.
273       Standard_Real u,v;
274 #ifdef OCCT_DEBUG
275 //      Standard_Real deport = 1000*BRep_Tool::Tolerance(E);
276 #endif
277       ChFi3d_Coefficient(dint1,DU1,DV1,u,v);
278       p2d1.SetX(p2d1.X() + u); p2d1.SetY(p2d1.Y() + v);
279       ChFi3d_Coefficient(dint1,DU2,DV2,u,v);
280       p2d2.SetX(p2d2.X() + u); p2d2.SetY(p2d2.Y() + v);
281       S1.D1(p2d1.X(),p2d1.Y(),pt1,DU1,DV1);
282       ns1 = DU1.Crossed(DV1);
283       if (F1.Orientation() == TopAbs_REVERSED)
284         ns1.Reverse();
285       S2.D1(p2d2.X(),p2d2.Y(),pt2,DU2,DV2);
286       ns2 = DU2.Crossed(DV2);
287       if (F2.Orientation() == TopAbs_REVERSED)
288         ns2.Reverse();
289       gp_Vec vref(pt1,pt2);
290       if(ns1.Dot(vref) < 0.){
291         Or1 = TopAbs_REVERSED;
292       }
293       if(ns2.Dot(vref) > 0.){
294         Or2 = TopAbs_REVERSED;
295       }
296     }
297   }
298
299
300   if (Or1 == TopAbs_FORWARD) {
301     if (Or2 == TopAbs_FORWARD) ChoixConge = 1;
302     else ChoixConge = 7;
303   }
304   else {
305     if (Or2 == TopAbs_FORWARD) ChoixConge = 3;
306     else ChoixConge = 5;
307   }
308   if ((ns1.Crossed(ns2)).Dot(tgE) >= 0.) ChoixConge++ ;
309   return ChoixConge;
310 }
311
312 //=======================================================================
313 //function : NextSide
314 //purpose  : 
315 //           
316 //=======================================================================
317
318 Standard_Integer  ChFi3d::NextSide(TopAbs_Orientation& Or1, 
319                                    TopAbs_Orientation& Or2,
320                                    const TopAbs_Orientation OrSave1, 
321                                    const TopAbs_Orientation OrSave2,
322                                    const Standard_Integer ChoixSave)
323 {
324   if (Or1 == TopAbs_FORWARD){Or1 = OrSave1;}
325   else {
326     Or1 = TopAbs::Reverse(OrSave1);
327   }
328   if (Or2 == TopAbs_FORWARD){Or2 = OrSave2;}
329   else {
330     Or2 = TopAbs::Reverse(OrSave2);
331   }
332
333   Standard_Integer ChoixConge;
334   if (Or1 == TopAbs_FORWARD) {
335     if (Or2 == TopAbs_FORWARD) ChoixConge = 1;
336     else {
337       if(ChoixSave < 0) ChoixConge = 3;
338       else ChoixConge = 7;
339     }
340   }
341   else {
342     if (Or2 == TopAbs_FORWARD) {
343       if(ChoixSave < 0) ChoixConge = 7;
344       else ChoixConge = 3;
345     }
346     else ChoixConge = 5;
347   }
348   if (Abs(ChoixSave)%2 == 0) ChoixConge++;
349   return ChoixConge;
350 }
351
352
353 //=======================================================================
354 //function : NextSide
355 //purpose  : 
356 //           
357 //=======================================================================
358
359 void ChFi3d::NextSide(TopAbs_Orientation& Or, 
360                      const TopAbs_Orientation OrSave, 
361                      const TopAbs_Orientation OrFace) 
362 {
363   if (Or == OrFace){Or = OrSave;}
364   else {
365     Or = TopAbs::Reverse(OrSave);
366   }
367 }
368
369
370
371 //=======================================================================
372 //function : SameSide
373 //purpose  : 
374 //           
375 //=======================================================================
376
377 Standard_Boolean  ChFi3d::SameSide(const TopAbs_Orientation Or, 
378                                    const TopAbs_Orientation OrSave1, 
379                                    const TopAbs_Orientation OrSave2,
380                                    const TopAbs_Orientation OrFace1, 
381                                    const TopAbs_Orientation OrFace2)
382 {
383   TopAbs_Orientation o1,o2;
384   if (Or == OrFace1){o1 = OrSave1;}
385   else {
386     o1 = TopAbs::Reverse(OrSave1);
387   }
388   if (Or == OrFace2){o2 = OrSave2;}
389   else {
390     o2 = TopAbs::Reverse(OrSave2);
391   }
392   return (o1 == o2);
393 }
394
395 //=======================================================================
396 //function : Correct2dPoint
397 //purpose  : 
398 //=======================================================================
399 void Correct2dPoint(const TopoDS_Face& theF, gp_Pnt2d& theP2d)
400 {
401   BRepAdaptor_Surface aBAS(theF, Standard_False);
402   if (aBAS.GetType() < GeomAbs_BezierSurface) {
403     return;
404   }
405   //
406   const Standard_Real coeff = 0.01;
407   Standard_Real eps;
408   Standard_Real u1, u2, v1, v2;
409   //
410   aBAS.Initialize(theF, Standard_True);
411   u1 = aBAS.FirstUParameter();
412   u2 = aBAS.LastUParameter();
413   v1 = aBAS.FirstVParameter();
414   v2 = aBAS.LastVParameter();
415   if (!(Precision::IsInfinite(u1) || Precision::IsInfinite(u2)))
416   {
417     eps = Max(coeff*(u2 - u1), Precision::PConfusion());
418     if (Abs(theP2d.X() - u1) < eps)
419     {
420       theP2d.SetX(u1 + eps);
421     }
422     if (Abs(theP2d.X() - u2) < eps)
423     {
424       theP2d.SetX(u2 - eps);
425     }
426   }
427   if (!(Precision::IsInfinite(v1) || Precision::IsInfinite(v2)))
428   {
429     eps = Max(coeff*(v2 - v1), Precision::PConfusion());
430     if (Abs(theP2d.Y() - v1) < eps)
431     {
432       theP2d.SetY(v1 + eps);
433     }
434     if (Abs(theP2d.Y() - v2) < eps)
435     {
436       theP2d.SetY(v2 - eps);
437     }
438   }
439 }