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