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_Surface.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 //=======================================================================
DefineConnectType(const TopoDS_Edge & E,const TopoDS_Face & F1,const TopoDS_Face & F2,const Standard_Real SinTol,const Standard_Boolean CorrectPoint)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 //=======================================================================
IsTangentFaces(const TopoDS_Edge & theEdge,const TopoDS_Face & theFace1,const TopoDS_Face & theFace2,const GeomAbs_Shape Order)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_Surface) aBAHS1 = new BRepAdaptor_Surface(aBAS1);
178 Handle(BRepAdaptor_Surface) aBAHS2 = new BRepAdaptor_Surface(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 //=======================================================================
ConcaveSide(const BRepAdaptor_Surface & S1,const BRepAdaptor_Surface & S2,const TopoDS_Edge & E,TopAbs_Orientation & Or1,TopAbs_Orientation & Or2)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
NextSide(TopAbs_Orientation & Or1,TopAbs_Orientation & Or2,const TopAbs_Orientation OrSave1,const TopAbs_Orientation OrSave2,const Standard_Integer ChoixSave)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
NextSide(TopAbs_Orientation & Or,const TopAbs_Orientation OrSave,const TopAbs_Orientation OrFace)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
SameSide(const TopAbs_Orientation Or,const TopAbs_Orientation OrSave1,const TopAbs_Orientation OrSave2,const TopAbs_Orientation OrFace1,const TopAbs_Orientation OrFace2)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 //=======================================================================
Correct2dPoint(const TopoDS_Face & theF,gp_Pnt2d & theP2d)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 }
533