0025729: algorith BRepOffset_MakeOffset(...) produces wrong result for join type...
[occt.git] / src / BRepOffset / BRepOffset_Analyse.cxx
CommitLineData
b311480e 1// Created on: 1995-10-20
2// Created by: Yves FRICAUD
3// Copyright (c) 1995-1999 Matra Datavision
973c2be1 4// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 5//
973c2be1 6// This file is part of Open CASCADE Technology software library.
b311480e 7//
d5f74e42 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
973c2be1 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.
b311480e 13//
973c2be1 14// Alternatively, this file may be used under the terms of Open CASCADE
15// commercial license or contractual agreement.
7fd59977 16
17#include <BRepOffset_Analyse.ixx>
18#include <BRepOffset_Interval.hxx>
19#include <BRepOffset_Tool.hxx>
20#include <BRepOffset_ListIteratorOfListOfInterval.hxx>
21#include <BRep_Tool.hxx>
22#include <BRepTools.hxx>
23#include <BRep_Builder.hxx>
24
25#include <BRepAdaptor_Curve.hxx>
26
27#include <gp.hxx>
28#include <gp_Vec.hxx>
29#include <gp_Dir.hxx>
30#include <gp_Pnt.hxx>
31#include <gp_Pnt2d.hxx>
32
33#include <Geom_Surface.hxx>
34#include <Geom_Curve.hxx>
35#include <Geom2d_Curve.hxx>
36
37#include <TopExp.hxx>
38#include <TopExp_Explorer.hxx>
39
40#include <TopoDS.hxx>
41#include <TopoDS_Face.hxx>
42#include <TopoDS_Edge.hxx>
43#include <TopTools_ListIteratorOfListOfShape.hxx>
44#include <TopTools_MapOfShape.hxx>
45
46#include <Precision.hxx>
47#include <gp.hxx>
b0091bc9 48#include <BRepAdaptor_Surface.hxx>
49#include <Adaptor3d_Surface.hxx>
50//
51static void Correct2dPoint(const Adaptor3d_Surface& theS, gp_Pnt2d& theP2d);
52//
53static BRepOffset_Type DefineConnectType(const TopoDS_Edge& E,
54 const TopoDS_Face& F1,
55 const TopoDS_Face& F2,
56 const Standard_Real SinTol,
57 const Standard_Boolean CorrectPoint);
58//
d804b26d 59static void CorrectOrientationOfTangent(gp_Vec& TangVec,
60 const TopoDS_Vertex& aVertex,
61 const TopoDS_Edge& anEdge)
62{
63 TopoDS_Vertex Vlast = TopExp::LastVertex(anEdge);
64 if (aVertex.IsSame(Vlast))
65 TangVec.Reverse();
66}
7fd59977 67//=======================================================================
68//function : BRepOffset_Analyse
69//purpose :
70//=======================================================================
71
72BRepOffset_Analyse::BRepOffset_Analyse()
73:myDone(Standard_False)
74{
75}
76
77
78//=======================================================================
79//function : BRepOffset_Analyse
80//purpose :
81//=======================================================================
82
83BRepOffset_Analyse::BRepOffset_Analyse(const TopoDS_Shape& S,
84 const Standard_Real Angle)
85:myDone(Standard_False)
86{
87 Perform( S, Angle);
88}
89
90//=======================================================================
91//function : EdgeAnlyse
92//purpose :
93//=======================================================================
94
95static void EdgeAnalyse(const TopoDS_Edge& E,
b0091bc9 96 const TopoDS_Face& F1,
97 const TopoDS_Face& F2,
98 const Standard_Real SinTol,
99 BRepOffset_ListOfInterval& LI)
7fd59977 100{
7fd59977 101
7fd59977 102 Standard_Real f,l;
b0091bc9 103 BRep_Tool::Range(E, F1, f, l);
104 BRepOffset_Interval I;
105 I.First(f); I.Last(l);
106 //
0d969553 107 // Tangent if the regularity is at least G1.
7fd59977 108 if (BRep_Tool::HasContinuity(E,F1,F2)) {
109 if (BRep_Tool::Continuity(E,F1,F2) > GeomAbs_C0) {
7fd59977 110 I.Type(BRepOffset_Tangent);
111 LI.Append(I);
112 return;
113 }
114 }
b0091bc9 115 //
116 BRepOffset_Type aType = DefineConnectType(E, F1, F2, SinTol, Standard_False);
117 if(aType != BRepOffset_Tangent)
118 {
119 aType = DefineConnectType(E, F1, F2, SinTol, Standard_True);
7fd59977 120 }
b0091bc9 121 I.Type(aType);
7fd59977 122 LI.Append(I);
123}
124
125//=======================================================================
126//function : BuildAncestors
127//purpose :
128//=======================================================================
129
130static void BuildAncestors (const TopoDS_Shape& S,
131 TopTools_IndexedDataMapOfShapeListOfShape& MA)
132{
133 MA.Clear();
134 TopExp::MapShapesAndAncestors(S,TopAbs_VERTEX,TopAbs_EDGE,MA);
135 TopExp::MapShapesAndAncestors(S,TopAbs_EDGE ,TopAbs_FACE,MA);
136
0d969553 137 // Purge ancestors.
7fd59977 138 TopTools_MapOfShape Map;
139 for (Standard_Integer i = 1; i <= MA.Extent(); i++) {
140 Map.Clear();
141 TopTools_ListOfShape& L = MA(i);
142 TopTools_ListIteratorOfListOfShape it(L);
143 while (it.More()) {
144 if (!Map.Add(it.Value())) {
145 L.Remove(it);
146 }
147 else {
148 it.Next();
149 }
150 }
151 }
152}
153
154//=======================================================================
155//function : IsDone
156//purpose :
157//=======================================================================
158
159Standard_Boolean BRepOffset_Analyse::IsDone() const
160{
161 return myDone;
162}
163
164
165//=======================================================================
166//function : Perform
167//purpose :
168//=======================================================================
169
170void BRepOffset_Analyse::Perform (const TopoDS_Shape& S,
171 const Standard_Real Angle)
172{
173 myShape = S;
174
175 angle = Angle;
176 Standard_Real SinTol = sin(Angle);
177
178 // Build ancestors.
179 BuildAncestors (S,ancestors);
180
181
182 TopExp_Explorer Exp(S.Oriented(TopAbs_FORWARD),TopAbs_EDGE);
183 for ( ; Exp.More(); Exp.Next()) {
184 const TopoDS_Edge& E = TopoDS::Edge(Exp.Current());
185 if (!mapEdgeType.IsBound(E)) {
186 BRepOffset_ListOfInterval LI;
187 mapEdgeType.Bind(E,LI);
188
189 const TopTools_ListOfShape& L = Ancestors(E);
190 if ( L.IsEmpty())
191 continue;
192
193 if (L.Extent() == 2) {
194 const TopoDS_Face& F1 = TopoDS::Face(L.First());
195 const TopoDS_Face& F2 = TopoDS::Face(L.Last ());
196 EdgeAnalyse(E,F1,F2,SinTol,mapEdgeType(E));
197 }
198 else if (L.Extent() == 1) {
199 Standard_Real U1,U2;
200 const TopoDS_Face& F = TopoDS::Face(L.First());
201 BRep_Tool::Range(E,F,U1,U2);
202 BRepOffset_Interval Inter(U1,U2,BRepOffset_Other);
203
204 if (! BRepTools::IsReallyClosed(E,F)) {
205 Inter.Type(BRepOffset_FreeBoundary);
206 }
207 mapEdgeType(E).Append(Inter);
208 }
209 else {
0797d9d3 210#ifdef OCCT_DEBUG
7fd59977 211 cout <<"edge shared by more than two faces"<<endl;
212#endif
213 }
214 }
215 }
216 myDone = Standard_True;
217}
218
219//=======================================================================
220//function : Clear
221//purpose :
222//=======================================================================
223
224void BRepOffset_Analyse::Clear()
225{
226 myDone = Standard_False;
227 myShape .Nullify();
228 mapEdgeType.Clear();
229 ancestors .Clear();
230}
231
232
233
234
235
236//=======================================================================
237//function : BRepOffset_ListOfInterval&
238//purpose :
239//=======================================================================
240
241const BRepOffset_ListOfInterval& BRepOffset_Analyse::Type(const TopoDS_Edge& E)
242const
243{
244 return mapEdgeType (E);
245}
246
247
248//=======================================================================
249//function : Edges
250//purpose :
251//=======================================================================
252
253void BRepOffset_Analyse::Edges(const TopoDS_Vertex& V,
254 const BRepOffset_Type T,
255 TopTools_ListOfShape& LE)
256const
257{
258 LE.Clear();
259 const TopTools_ListOfShape& L = Ancestors (V);
260 TopTools_ListIteratorOfListOfShape it(L);
261
262 for ( ;it.More(); it.Next()) {
263 const TopoDS_Edge& E = TopoDS::Edge(it.Value());
264 TopoDS_Vertex V1,V2;
265 BRepOffset_Tool::EdgeVertices (E,V1,V2);
266 if (V1.IsSame(V)) {
267 if (mapEdgeType(E).Last().Type() == T)
268 LE.Append(E);
269 }
270 if (V2.IsSame(V)) {
271 if (mapEdgeType(E).First().Type() == T)
272 LE.Append(E);
273 }
274 }
275}
276
277
278//=======================================================================
279//function : Edges
280//purpose :
281//=======================================================================
282
283void BRepOffset_Analyse::Edges(const TopoDS_Face& F,
284 const BRepOffset_Type T,
285 TopTools_ListOfShape& LE)
286const
287{
288 LE.Clear();
289 TopExp_Explorer exp(F, TopAbs_EDGE);
290
291 for ( ;exp.More(); exp.Next()) {
292 const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
293
294 const BRepOffset_ListOfInterval& Lint = Type(E);
295 BRepOffset_ListIteratorOfListOfInterval it(Lint);
296 for ( ;it.More(); it.Next()) {
297 if (it.Value().Type() == T) LE.Append(E);
298 }
299 }
300}
301
302//=======================================================================
303//function : TangentEdges
304//purpose :
305//=======================================================================
306
307void BRepOffset_Analyse::TangentEdges(const TopoDS_Edge& Edge ,
308 const TopoDS_Vertex& Vertex,
309 TopTools_ListOfShape& Edges ) const
310{
311 gp_Vec V,VRef;
312
313
314 Standard_Real U,URef;
315 BRepAdaptor_Curve C3d, C3dRef;
316
317 URef = BRep_Tool::Parameter(Vertex,Edge);
318 C3dRef = BRepAdaptor_Curve(Edge);
319 VRef = C3dRef.DN(URef,1);
d804b26d 320 CorrectOrientationOfTangent(VRef, Vertex, Edge);
7fd59977 321 if (VRef.SquareMagnitude() < gp::Resolution()) return;
322
323 Edges.Clear();
324
325 const TopTools_ListOfShape& Anc = Ancestors(Vertex);
326 TopTools_ListIteratorOfListOfShape it(Anc);
327 for ( ; it.More(); it.Next()) {
328 const TopoDS_Edge& CurE = TopoDS::Edge(it.Value());
329 if ( CurE.IsSame(Edge)) continue;
330 U = BRep_Tool::Parameter(Vertex,CurE);
331 C3d = BRepAdaptor_Curve(CurE);
332 V = C3d.DN(U,1);
d804b26d 333 CorrectOrientationOfTangent(V, Vertex, CurE);
7fd59977 334 if (V.SquareMagnitude() < gp::Resolution()) continue;
d804b26d 335 if (V.IsOpposite(VRef,angle)) {
7fd59977 336 Edges.Append(CurE);
337 }
338 }
339}
340
341
342
343//=======================================================================
344//function : HasAncestor
345//purpose :
346//=======================================================================
347
348Standard_Boolean BRepOffset_Analyse::HasAncestor (const TopoDS_Shape& S) const
349{
350 return ancestors.Contains(S);
351}
352
353
354//=======================================================================
355//function : Ancestors
356//purpose :
357//=======================================================================
358
359const TopTools_ListOfShape& BRepOffset_Analyse::Ancestors
360(const TopoDS_Shape& S) const
361{
362 return ancestors.FindFromKey(S);
363}
364
365
366//=======================================================================
367//function : Explode
368//purpose :
369//=======================================================================
370
371void BRepOffset_Analyse::Explode( TopTools_ListOfShape& List,
372 const BRepOffset_Type T ) const
373{
374 List.Clear();
375 BRep_Builder B;
376 TopTools_MapOfShape Map;
377
378 TopExp_Explorer Fexp;
379 for (Fexp.Init(myShape,TopAbs_FACE); Fexp.More(); Fexp.Next()) {
380 if ( Map.Add(Fexp.Current())) {
381 TopoDS_Face Face = TopoDS::Face(Fexp.Current());
382 TopoDS_Compound Co;
383 B.MakeCompound(Co);
384 B.Add(Co,Face);
0d969553
Y
385 // add to Co all faces from the cloud of faces
386 // G1 created from <Face>
7fd59977 387 AddFaces(Face,Co,Map,T);
388 List.Append(Co);
389 }
390 }
391}
392
393//=======================================================================
394//function : Explode
395//purpose :
396//=======================================================================
397
398void BRepOffset_Analyse::Explode( TopTools_ListOfShape& List,
399 const BRepOffset_Type T1,
400 const BRepOffset_Type T2) const
401{
402 List.Clear();
403 BRep_Builder B;
404 TopTools_MapOfShape Map;
405
406 TopExp_Explorer Fexp;
407 for (Fexp.Init(myShape,TopAbs_FACE); Fexp.More(); Fexp.Next()) {
408 if ( Map.Add(Fexp.Current())) {
409 TopoDS_Face Face = TopoDS::Face(Fexp.Current());
410 TopoDS_Compound Co;
411 B.MakeCompound(Co);
412 B.Add(Co,Face);
0d969553
Y
413 // add to Co all faces from the cloud of faces
414 // G1 created from <Face>
7fd59977 415 AddFaces(Face,Co,Map,T1,T2);
416 List.Append(Co);
417 }
418 }
419}
420
421
422//=======================================================================
423//function : AddFaces
424//purpose :
425//=======================================================================
426
427void BRepOffset_Analyse::AddFaces (const TopoDS_Face& Face,
428 TopoDS_Compound& Co,
429 TopTools_MapOfShape& Map,
430 const BRepOffset_Type T) const
431{
432 BRep_Builder B;
433 TopExp_Explorer exp(Face,TopAbs_EDGE);
434 for ( ; exp.More(); exp.Next()) {
435 const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
436 const BRepOffset_ListOfInterval& LI = Type(E);
437 if (!LI.IsEmpty() && LI.First().Type() == T) {
0d969553 438 // so <NewFace> is attached to G1 by <Face>
7fd59977 439 const TopTools_ListOfShape& L = Ancestors(E);
440 if (L.Extent() == 2) {
441 TopoDS_Face F1 = TopoDS::Face(L.First());
442 if ( F1.IsSame(Face))
443 F1 = TopoDS::Face(L.Last ());
444 if ( Map.Add(F1)) {
445 B.Add(Co,F1);
446 AddFaces(F1,Co,Map,T);
447 }
448 }
449 }
450 }
451}
452//=======================================================================
453//function : AddFaces
454//purpose :
455//=======================================================================
456
457void BRepOffset_Analyse::AddFaces (const TopoDS_Face& Face,
458 TopoDS_Compound& Co,
459 TopTools_MapOfShape& Map,
460 const BRepOffset_Type T1,
461 const BRepOffset_Type T2) const
462{
463 BRep_Builder B;
464 TopExp_Explorer exp(Face,TopAbs_EDGE);
465 for ( ; exp.More(); exp.Next()) {
466 const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
467 const BRepOffset_ListOfInterval& LI = Type(E);
468 if (!LI.IsEmpty() &&
469 (LI.First().Type() == T1 || LI.First().Type() == T2)) {
0d969553 470 // so <NewFace> is attached to G1 by <Face>
7fd59977 471 const TopTools_ListOfShape& L = Ancestors(E);
472 if (L.Extent() == 2) {
473 TopoDS_Face F1 = TopoDS::Face(L.First());
474 if ( F1.IsSame(Face))
475 F1 = TopoDS::Face(L.Last ());
476 if ( Map.Add(F1)) {
477 B.Add(Co,F1);
478 AddFaces(F1,Co,Map,T1,T2);
479 }
480 }
481 }
482 }
483}
b0091bc9 484
485//=======================================================================
486//function : Correct2dPoint
487//purpose :
488//=======================================================================
489void Correct2dPoint(const Adaptor3d_Surface& theS, gp_Pnt2d& theP2d)
490{
491 const Standard_Real coeff = 0.01;
492 Standard_Real eps;
493 Standard_Real u1, u2, v1, v2;
494 if(theS.GetType() >= GeomAbs_BezierSurface)
495 {
496 u1 = theS.FirstUParameter();
497 u2 = theS.LastUParameter();
498 v1 = theS.FirstVParameter();
499 v2 = theS.LastVParameter();
500 if(!(Precision::IsInfinite(u1) || Precision::IsInfinite(u2)))
501 {
502 eps = Max(coeff*(u2-u1), Precision::PConfusion());
503 if(Abs(theP2d.X()-u1) < eps)
504 {
505 theP2d.SetX(u1 + eps);
506 }
507 if(Abs(theP2d.X()-u2) < eps)
508 {
509 theP2d.SetX(u2 - eps);
510 }
511 }
512 if(!(Precision::IsInfinite(v1) || Precision::IsInfinite(v2)))
513 {
514 eps = Max(coeff*(v2-v1), Precision::PConfusion());
515 if(Abs(theP2d.Y()-v1) < eps)
516 {
517 theP2d.SetY(v1 + eps);
518 }
519 if(Abs(theP2d.Y()-v2) < eps)
520 {
521 theP2d.SetY(v2 - eps);
522 }
523 }
524 }
525}
526
527//=======================================================================
528//function : DefineConnectType
529//purpose :
530//=======================================================================
531BRepOffset_Type DefineConnectType(const TopoDS_Edge& E,
532 const TopoDS_Face& F1,
533 const TopoDS_Face& F2,
534 const Standard_Real SinTol,
535 const Standard_Boolean CorrectPoint)
536{
537 TopLoc_Location L;
538 Standard_Real f,l;
539
540 BRepAdaptor_Surface S1(F1), S2(F2);
541 Handle (Geom2d_Curve) C1 = BRep_Tool::CurveOnSurface(E,F1,f,l);
542 Handle (Geom2d_Curve) C2 = BRep_Tool::CurveOnSurface(E,F2,f,l);
543
544 BRepAdaptor_Curve C(E);
545 f = C.FirstParameter();
546 l = C.LastParameter();
547//
548 Standard_Real ParOnC = 0.5*(f+l);
549 gp_Vec T1 = C.DN(ParOnC,1).Transformed(L.Transformation());
550 if (T1.SquareMagnitude() > gp::Resolution()) {
551 T1.Normalize();
552 }
553
554 if (BRepOffset_Tool::OriEdgeInFace(E,F1) == TopAbs_REVERSED) {
555 T1.Reverse();
556 }
557 if (F1.Orientation() == TopAbs_REVERSED) T1.Reverse();
558
559 gp_Pnt2d P = C1->Value(ParOnC);
560 gp_Pnt P3;
561 gp_Vec D1U,D1V;
562
563 if(CorrectPoint)
564 Correct2dPoint(S1, P);
565 //
566 S1.D1(P.X(),P.Y(),P3,D1U,D1V);
567 gp_Vec DN1(D1U^D1V);
568 if (F1.Orientation() == TopAbs_REVERSED) DN1.Reverse();
569
570 P = C2->Value(ParOnC);
571 if(CorrectPoint)
572 Correct2dPoint(S2, P);
573 S2.D1(P.X(),P.Y(),P3,D1U,D1V);
574 gp_Vec DN2(D1U^D1V);
575 if (F2.Orientation() == TopAbs_REVERSED) DN2.Reverse();
576
577 DN1.Normalize();
578 DN2.Normalize();
579
580 gp_Vec ProVec = DN1^DN2;
581 Standard_Real NormProVec = ProVec.Magnitude();
582
583 if (Abs(NormProVec) < SinTol) {
584 // plane
585 if (DN1.Dot(DN2) > 0) {
586 //Tangent
587 return BRepOffset_Tangent;
588 }
589 else {
590 //Mixed not finished!
591#ifdef OCCT_DEBUG
592 cout <<" faces locally mixed"<<endl;
593#endif
594 return BRepOffset_Convex;
595 }
596 }
597 else {
598 if (NormProVec > gp::Resolution())
599 ProVec.Normalize();
600 Standard_Real Prod = T1.Dot(DN1^DN2);
601 if (Prod > 0.) {
602 //
603 return BRepOffset_Convex;
604 }
605 else {
606 //reenters
607 return BRepOffset_Concave;
608 }
609 }
610}