0025632: IGES writer looses face orientation
[occt.git] / src / BRepToIGES / BRepToIGES_BRShell.cxx
1 // Created on: 1995-01-30
2 // Created by: Marie Jose MARTZ
3 // Copyright (c) 1995-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 //:n3 abv 8 Feb 99: PRO17820: BRepTools::OuterWire() -> ShapeAnalysis::OuterWire
18 //szv#4 S4163
19
20 #include <BRepToIGES_BRShell.ixx>
21 #include <BRepToIGES_BRWire.hxx>
22
23 #include <BRep_Builder.hxx>
24 #include <BRep_Tool.hxx>
25 #include <BRepTools.hxx>
26
27 #include <gp.hxx>
28 #include <gp_Trsf.hxx>
29
30 #include <Geom_ConicalSurface.hxx>
31 #include <Geom_CylindricalSurface.hxx>
32 #include <Geom_RectangularTrimmedSurface.hxx>
33 #include <Geom_SphericalSurface.hxx>
34 #include <Geom_Surface.hxx>
35 #include <Geom_SurfaceOfRevolution.hxx>
36 #include <Geom_ToroidalSurface.hxx>
37 #include <Geom2d_Curve.hxx>
38
39 #include <GeomToIGES_GeomSurface.hxx>
40
41 #include <IGESBasic_Group.hxx>
42 #include <IGESData_HArray1OfIGESEntity.hxx>
43 #include <IGESData_IGESEntity.hxx>
44
45 #include <IGESGeom_CurveOnSurface.hxx>
46 #include <IGESGeom_HArray1OfCurveOnSurface.hxx>
47 #include <IGESGeom_TrimmedSurface.hxx>
48 #include <IGESGeom_SurfaceOfRevolution.hxx>
49
50 #include <Interface_Macros.hxx>
51
52 #include <NCollection_Map.hxx>
53 #include <NCollection_IncAllocator.hxx>
54
55 #include <TColStd_HSequenceOfTransient.hxx>
56
57 #include <TopLoc_Location.hxx>
58
59 #include <TopTools_ShapeMapHasher.hxx>
60
61 #include <TopoDS.hxx>
62 #include <TopoDS_Vertex.hxx>
63 #include <TopoDS_Edge.hxx>
64 #include <TopoDS_Face.hxx>
65 #include <TopoDS_Shell.hxx>
66 #include <TopoDS_Wire.hxx>
67 #include <TopoDS_Shape.hxx>
68
69 #include <TopAbs_ShapeEnum.hxx>
70 #include <TopExp.hxx>
71 #include <TopExp_Explorer.hxx>
72
73 #include <ShapeAlgo.hxx>
74 #include <ShapeAlgo_AlgoContainer.hxx>
75
76 #include <Message_ProgressIndicator.hxx>
77 #include <Transfer_FinderProcess.hxx>
78
79 //=============================================================================
80 // BRepToIGES_BRShell
81 //=============================================================================
82
83 BRepToIGES_BRShell::BRepToIGES_BRShell()
84 {
85 }
86
87
88 //=============================================================================
89 // BRepToIGES_BRShell
90 //=============================================================================
91
92 BRepToIGES_BRShell::BRepToIGES_BRShell
93 (const BRepToIGES_BREntity& BR)
94 : BRepToIGES_BREntity(BR)
95 {
96 }
97
98
99 //=============================================================================
100 // TransferShell
101 //=============================================================================
102
103 Handle(IGESData_IGESEntity) BRepToIGES_BRShell ::TransferShell(const TopoDS_Shape& start)
104 {
105   Handle(IGESData_IGESEntity) res;
106
107   if (start.IsNull())  return  res;
108
109   if (start.ShapeType() == TopAbs_FACE) {
110     TopoDS_Face F =  TopoDS::Face(start);
111     res = TransferFace(F);
112   }  
113   else if (start.ShapeType() == TopAbs_SHELL) {
114     TopoDS_Shell S =  TopoDS::Shell(start);
115     res = TransferShell(S);
116   }  
117   else {
118     // message d`erreur
119   }  
120   return res;
121 }
122
123
124 //=============================================================================
125 // TransferFace
126 // 
127 //=============================================================================
128
129 Handle(IGESData_IGESEntity) BRepToIGES_BRShell ::TransferFace(const TopoDS_Face& start)
130 {
131   Handle(IGESData_IGESEntity) res;
132
133   Handle(Message_ProgressIndicator) progress = GetTransferProcess()->GetProgress();
134   if ( ! progress.IsNull() ) {
135     if ( progress->UserBreak() ) return res;
136     progress->Increment();
137   }
138   
139   if ( start.IsNull()) {
140     return res;
141   }
142
143   // pour explorer la face , il faut la mettre fORWARD.
144   TopoDS_Face myface;
145   if (start.Orientation() == TopAbs_REVERSED) {
146     //create face with redirected surface
147     BRep_Builder B;
148     TopLoc_Location aLoc;
149     Handle(Geom_Surface) aSurf = BRep_Tool::Surface(start, aLoc);
150     aSurf = aSurf->UReversed();
151     Standard_Real U1, U2, V1, V2;
152     aSurf->Bounds(U1, U2, V1, V2);
153     Standard_Real aTol = BRep_Tool::Tolerance(start);
154     B.MakeFace(myface, aSurf, aLoc ,aTol);
155     // set specifics flags of a Face
156           B.NaturalRestriction(myface, BRep_Tool::NaturalRestriction(start));
157     //add wires
158     TopoDS_Wire anOuter = TopoDS::Wire(ShapeAlgo::AlgoContainer()->OuterWire(start));
159     TopExp_Explorer ex;
160     for (ex.Init(start,TopAbs_WIRE); ex.More(); ex.Next()) {
161       TopoDS_Wire W = TopoDS::Wire(ex.Current());
162       if (!W.IsNull() && W.IsSame(anOuter)) {
163         B.Add(myface, W);
164         break;
165       }
166     }     
167     for (ex.Init(start,TopAbs_WIRE); ex.More(); ex.Next()) {
168       TopoDS_Wire W = TopoDS::Wire(ex.Current());
169       if (!W.IsNull() && !W.IsSame(anOuter)) {
170         B.Add(myface, W);
171       }
172     }
173     // mirror pcurves
174     NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aMap (101, new NCollection_IncAllocator);
175     for (ex.Init(myface,TopAbs_EDGE);ex.More(); ex.Next()) {
176       TopoDS_Edge anEdge = TopoDS::Edge(ex.Current());
177       if (!aMap.Add(anEdge))
178         // seam edge has been already updated
179         continue;
180       Standard_Real f, l;
181       Handle(Geom2d_Curve) aCurve1, aCurve2;
182       aCurve1 = BRep_Tool::CurveOnSurface(anEdge, start, f, l);
183       aTol = BRep_Tool::Tolerance(anEdge);
184       gp_Trsf2d T;
185       gp_Ax2d axis(gp_Pnt2d(0.5 * (U1 + U2), V1), gp_Dir2d(0.,1.));
186       T.SetMirror(axis);
187       if (!aCurve1.IsNull()) {
188         aCurve1 = Handle(Geom2d_Curve)::DownCast(aCurve1->Transformed(T));
189         if (BRepTools::IsReallyClosed(anEdge, start)) {
190           TopoDS_Edge revEdge = TopoDS::Edge(anEdge.Reversed());
191           aCurve2 = BRep_Tool::CurveOnSurface(revEdge, start, f, l);
192           if (!aCurve2.IsNull()) {
193             aCurve2 = Handle(Geom2d_Curve)::DownCast(aCurve2->Transformed(T));
194             B.UpdateEdge(anEdge, aCurve1, aCurve2, myface, aTol);
195           }
196           else {
197             B.UpdateEdge(anEdge, aCurve1, myface, aTol);
198           }
199         }
200         else {
201           B.UpdateEdge(anEdge, aCurve1, myface, aTol);
202         }
203       }
204     }
205   }
206   else {
207     myface = start;
208   }
209
210   //Standard_Integer Nb = 0; //szv#4:S4163:12Mar99 unused
211   Standard_Real Length = 1.;
212   Handle(IGESData_IGESEntity) ISurf;
213
214   // returns the face surface
215   // ------------------------
216
217   Handle(Geom_Surface) Surf = BRep_Tool::Surface(myface);
218   Handle(Geom_Surface) Surf1;
219
220   if (!Surf.IsNull()) {
221     Standard_Real U1, U2, V1, V2;
222     // pour limiter les surfaces de base
223     BRepTools::UVBounds(myface, U1, U2, V1, V2);  
224     GeomToIGES_GeomSurface GS;
225     GS.SetModel(GetModel());
226     ISurf = GS.TransferSurface(Surf, U1, U2, V1, V2);
227     if (ISurf.IsNull()) {
228       AddWarning (start, "the basic surface is a null entity");
229       return res;
230     }
231     Length = GS.Length();
232
233     // modif mjm du 17/07/97
234     if (Surf->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) { 
235       DeclareAndCast(Geom_RectangularTrimmedSurface, rectang, Surf);
236       Surf1 = rectang->BasisSurface();
237     }
238     else 
239       Surf1 = Surf;
240   }
241
242
243   // returns the wires of the face
244   // -----------------------------
245
246   BRepToIGES_BRWire BW(*this);
247   Standard_Integer Imode = 0; 
248   Standard_Integer Iprefer = 0; 
249   Handle(IGESData_IGESEntity) ICurve2d;
250
251   // outer wire
252   //:n3  TopoDS_Wire Outer = BRepTools::OuterWire(myface);
253   TopoDS_Wire Outer = ShapeAlgo::AlgoContainer()->OuterWire(myface); //:n3 
254   Handle(IGESGeom_CurveOnSurface) IOuter = new IGESGeom_CurveOnSurface;
255   if (!Outer.IsNull()) {
256     Handle(IGESData_IGESEntity) ICurve3d = 
257       BW.TransferWire(Outer, myface, ICurve2d, Length);
258     if ((!ICurve3d.IsNull()) && (!ICurve2d.IsNull())) Iprefer = 3; 
259     if ((!ICurve3d.IsNull()) && (ICurve2d.IsNull())) Iprefer = 2; 
260     if ((ICurve3d.IsNull()) && (!ICurve2d.IsNull())) Iprefer = 1; 
261     IOuter -> Init (Imode, ISurf, ICurve2d, ICurve3d, Iprefer);
262   }
263
264   // inners wires
265   TopExp_Explorer Ex;
266   Handle(TColStd_HSequenceOfTransient) Seq = new TColStd_HSequenceOfTransient();
267
268   for (Ex.Init(myface,TopAbs_WIRE); Ex.More(); Ex.Next()) {
269     TopoDS_Wire W = TopoDS::Wire(Ex.Current());
270     Handle(IGESGeom_CurveOnSurface) Curve = new IGESGeom_CurveOnSurface;
271     if (W.IsNull()) {
272       AddWarning(start," an Wire is a null entity");
273     }
274     else if (!W.IsSame(Outer)) {
275       Handle(IGESData_IGESEntity) ICurve3d = 
276               BW.TransferWire(W, myface, ICurve2d, Length);
277       if ((!ICurve3d.IsNull()) && (!ICurve2d.IsNull())) Iprefer = 3; 
278       if ((!ICurve3d.IsNull()) && (ICurve2d.IsNull())) Iprefer = 2; 
279       if ((ICurve3d.IsNull()) && (!ICurve2d.IsNull())) Iprefer = 1; 
280       Curve-> Init (Imode, ISurf, ICurve2d, ICurve3d, Iprefer);
281       if (!Curve.IsNull()) Seq->Append(Curve);
282     }
283   }
284
285   // all inners edges not in a wire
286   for (Ex.Init(myface,TopAbs_EDGE,TopAbs_WIRE); Ex.More(); Ex.Next()) {
287     TopoDS_Edge E = TopoDS::Edge(Ex.Current());
288     Handle(IGESGeom_CurveOnSurface) Curve = new IGESGeom_CurveOnSurface;
289     if (E.IsNull()) {
290       AddWarning(start," an Edge is a null entity");
291     }
292     else {
293       Handle(IGESData_IGESEntity) ICurve3d = BW.TransferEdge(E, Standard_False);
294       Handle(IGESData_IGESEntity) newICurve2d = BW.TransferEdge(E, myface, Length, Standard_False);
295       if ((!ICurve3d.IsNull()) && (!newICurve2d.IsNull())) Iprefer = 3; 
296       if ((!ICurve3d.IsNull()) && (newICurve2d.IsNull())) Iprefer = 2; 
297       if ((ICurve3d.IsNull()) && (!newICurve2d.IsNull())) Iprefer = 1; 
298       Curve-> Init (Imode, ISurf, newICurve2d, ICurve3d, Iprefer);
299       if (!Curve.IsNull()) Seq->Append(Curve);
300     }
301   }
302
303
304   Standard_Integer nbent = Seq->Length();
305   Handle(IGESGeom_HArray1OfCurveOnSurface) Tab;
306   if (nbent >=1) {
307     Tab = new IGESGeom_HArray1OfCurveOnSurface(1,nbent);
308     for (Standard_Integer itab = 1; itab <= nbent; itab++) {
309       Handle(IGESGeom_CurveOnSurface) item = GetCasted(IGESGeom_CurveOnSurface, Seq->Value(itab));
310       Tab->SetValue(itab,item);
311     }
312   }
313
314   // returns the TrimmedSurface
315   // --------------------------
316   Standard_Boolean Flag = Standard_True; 
317   Handle(IGESGeom_TrimmedSurface) TrimmedSurf = new IGESGeom_TrimmedSurface;
318   if (BRep_Tool::NaturalRestriction(start)) {
319     //if face bounds and surface bounds are same, outer wire is unnecessary
320     Standard_Boolean Flag = Standard_False; 
321     TrimmedSurf-> Init (ISurf, Flag, NULL, Tab);
322   }
323   else
324     TrimmedSurf-> Init (ISurf, Flag, IOuter, Tab);
325
326   res = TrimmedSurf;
327   SetShapeResult ( start, res );
328   return res;
329 }
330
331
332 //=============================================================================
333 // TransferShell
334 //=============================================================================
335
336 Handle(IGESData_IGESEntity) BRepToIGES_BRShell::TransferShell(const TopoDS_Shell& start)
337 {
338   Handle(IGESData_IGESEntity) res;
339   if ( start.IsNull()) return res;
340
341   TopExp_Explorer Ex;
342   Handle(IGESBasic_Group) IGroup = new IGESBasic_Group;
343   Handle(TColStd_HSequenceOfTransient) Seq = new TColStd_HSequenceOfTransient();
344   Handle(IGESData_IGESEntity) IFace;
345
346   for (Ex.Init(start,TopAbs_FACE); Ex.More(); Ex.Next()) {
347     TopoDS_Face F = TopoDS::Face(Ex.Current());
348     if (F.IsNull()) {
349       AddWarning(start," a Face is a null entity");
350     }
351     else {
352       IFace = TransferFace(F);
353       if (!IFace.IsNull()) Seq->Append(IFace);
354     }
355   }
356
357
358   Standard_Integer nbfaces = Seq->Length();  
359   Handle(IGESData_HArray1OfIGESEntity) Tab;
360   if ( nbfaces >= 1) {
361     Tab = new IGESData_HArray1OfIGESEntity(1,nbfaces);
362     for (Standard_Integer itab = 1; itab <= nbfaces; itab++) {
363       Handle(IGESData_IGESEntity) item = GetCasted(IGESData_IGESEntity, Seq->Value(itab));
364       Tab->SetValue(itab,item);
365     }
366   }
367
368   if (nbfaces == 1) {
369     res = IFace;
370   }
371   else {
372     IGroup->Init(Tab);
373     res = IGroup;
374   }
375
376   SetShapeResult ( start, res );
377
378   return res;
379 }
380
381
382
383