0031301: Data Exchange - Export to STEP corrupts the shape
[occt.git] / src / TopoDSToStep / TopoDSToStep_MakeStepEdge.cxx
CommitLineData
b311480e 1// Created on: 1994-11-30
2// Created by: Frederic MAUPAS
3// Copyright (c) 1994-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
7fd59977 17
42cf5bc1 18#include <Adaptor3d_CurveOnSurface.hxx>
7fd59977 19#include <BRep_Tool.hxx>
7fd59977 20#include <BRepAdaptor_Curve.hxx>
21#include <BRepAdaptor_Surface.hxx>
42cf5bc1 22#include <BRepLib.hxx>
23#include <Geom2d_Curve.hxx>
24#include <Geom2d_Line.hxx>
25#include <Geom_BSplineCurve.hxx>
26#include <Geom_Curve.hxx>
27#include <Geom_Line.hxx>
28#include <Geom_Plane.hxx>
29#include <Geom_Surface.hxx>
30#include <GeomToStep_MakeCurve.hxx>
31#include <GeomToStep_MakeLine.hxx>
32#include <gp_Vec.hxx>
33#include <Interface_Static.hxx>
34#include <StdFail_NotDone.hxx>
7fd59977 35#include <StepGeom_HArray1OfPcurveOrSurface.hxx>
42cf5bc1 36#include <StepGeom_Line.hxx>
7fd59977 37#include <StepGeom_SeamCurve.hxx>
38#include <StepGeom_SurfaceCurve.hxx>
42cf5bc1 39#include <StepShape_EdgeCurve.hxx>
40#include <StepShape_TopologicalRepresentationItem.hxx>
41#include <StepShape_Vertex.hxx>
7fd59977 42#include <TColgp_Array1OfPnt.hxx>
42cf5bc1 43#include <TCollection_HAsciiString.hxx>
7fd59977 44#include <TColStd_Array1OfInteger.hxx>
42cf5bc1 45#include <TColStd_Array1OfReal.hxx>
7fd59977 46#include <TopExp.hxx>
42cf5bc1 47#include <TopExp_Explorer.hxx>
48#include <TopoDS.hxx>
49#include <TopoDS_Edge.hxx>
42cf5bc1 50#include <TopoDSToStep_MakeStepEdge.hxx>
51#include <TopoDSToStep_MakeStepVertex.hxx>
52#include <TopoDSToStep_Tool.hxx>
53#include <Transfer_FinderProcess.hxx>
54#include <TransferBRep.hxx>
7fd59977 55#include <TransferBRep_ShapeMapper.hxx>
7ef1f9b7 56#include <BRepTools.hxx>
57#include <ShapeAnalysis_Curve.hxx>
7fd59977 58
59// Processing of non-manifold topology (ssv; 11.11.2010)
7fd59977 60// ----------------------------------------------------------------------------
61// Constructors
62// ----------------------------------------------------------------------------
7fd59977 63TopoDSToStep_MakeStepEdge::TopoDSToStep_MakeStepEdge()
64{
65 done = Standard_False;
66}
67
68TopoDSToStep_MakeStepEdge::TopoDSToStep_MakeStepEdge
69(const TopoDS_Edge& E,
70 TopoDSToStep_Tool& T,
71 const Handle(Transfer_FinderProcess)& FP)
72{
73 done = Standard_False;
74 Init(E, T, FP);
75}
76
77// ----------------------------------------------------------------------------
78// Method : Init
79// Purpose :
80// ----------------------------------------------------------------------------
81
82void TopoDSToStep_MakeStepEdge::Init(const TopoDS_Edge& aEdge,
83 TopoDSToStep_Tool& aTool,
84 const Handle(Transfer_FinderProcess)& FP)
85{
86 // ------------------------------------------------------------------
87 // The edge is given with its relative orientation (i.e. in the wire)
88 // ------------------------------------------------------------------
89
90 aTool.SetCurrentEdge(aEdge);
91
92 // [BEGIN] Processing non-manifold topology (ssv; 11.11.2010)
dde68833 93 Standard_Boolean isNMMode = Interface_Static::IVal("write.step.nonmanifold") != 0;
7fd59977 94 if (isNMMode) {
95 Handle(StepShape_EdgeCurve) anEC;
96 Handle(TransferBRep_ShapeMapper) aSTEPMapper = TransferBRep::ShapeMapper(FP, aEdge);
97 if ( FP->FindTypedTransient(aSTEPMapper, STANDARD_TYPE(StepShape_EdgeCurve), anEC) ) {
98 // Non-manifold topology detected
99 myError = TopoDSToStep_EdgeDone;
100 myResult = anEC;
101 done = Standard_True;
102 return;
103 }
104 }
105 // [END] Processing non-manifold topology (ssv; 11.11.2010)
106
107 if (aTool.IsBound(aEdge)) {
108 myError = TopoDSToStep_EdgeDone;
109 done = Standard_True;
110 myResult = aTool.Find(aEdge);
111 return;
112 }
113
114#define Nbpt 21
7fd59977 115 Standard_Integer i;
116 Standard_Real U, U1, U2;
117 gp_Pnt P;
118
119 Standard_Boolean isSeam = BRep_Tool::IsClosed(aEdge, aTool.CurrentFace());
120
121 //:i4 abv 02 Sep 98: ProSTEP TR8 Motor.rle f3 & f62: check that edge
122 // participates twice in the wires of the face before making it seam
123 // (else it can have two pcurves on the same surface being shared by
124 // two faces on that surface)
125 // This fix is necessary because sharing of surfaces is not preserved when
126 // writing faces to STEP (see TopoDSToSTEP_MakeStepFace)
127 if ( isSeam ) {
128 Standard_Integer count = 0;
129 TopExp_Explorer exp ( aTool.CurrentFace(), TopAbs_EDGE );
130 for ( ; exp.More(); exp.Next() )
131 if ( aEdge.IsSame ( exp.Current() ) ) count++;
132 if ( count < 2 ) isSeam = Standard_False;
133 }
134
135 BRepAdaptor_Curve CA = BRepAdaptor_Curve(aEdge);
136 BRepAdaptor_Surface SA = BRepAdaptor_Surface(aTool.CurrentFace());
137
138 if (aEdge.Orientation() == TopAbs_INTERNAL ||
139 aEdge.Orientation() == TopAbs_EXTERNAL ) {
140 Handle(TransferBRep_ShapeMapper) errShape =
141 new TransferBRep_ShapeMapper(aEdge);
142 FP->AddWarning(errShape, " Edge(internal/external) from Non Manifold Topology");
143 myError = TopoDSToStep_NonManifoldEdge;
144 done = Standard_False;
145 return;
146 }
147
148 // Vertices
149
150 Handle(StepShape_Vertex) V1,V2;
151 Handle(StepShape_TopologicalRepresentationItem) Gpms2;
152 TopoDS_Vertex Vfirst, Vlast;
153
154 TopExp::Vertices(aEdge,Vfirst, Vlast);
155
156 TopoDSToStep_MakeStepVertex MkVertex;
157
158 MkVertex.Init(Vfirst, aTool, FP);
159 if (MkVertex.IsDone())
160 V1 = Handle(StepShape_Vertex)::DownCast(MkVertex.Value());
161 else {
162 Handle(TransferBRep_ShapeMapper) errShape =
163 new TransferBRep_ShapeMapper(aEdge);
164 FP->AddWarning(errShape, " First Vertex of Edge not mapped");
165 myError = TopoDSToStep_EdgeOther;
166 done = Standard_False;
167 return;
168 }
169
170 MkVertex.Init(Vlast, aTool, FP);
171 if (MkVertex.IsDone())
172 V2 = Handle(StepShape_Vertex)::DownCast(MkVertex.Value());
173 else {
174 Handle(TransferBRep_ShapeMapper) errShape =
175 new TransferBRep_ShapeMapper(aEdge);
176 FP->AddWarning(errShape, " Last Vertex of Edge not mapped");
177 myError = TopoDSToStep_EdgeOther;
178 done = Standard_False;
179 return;
180 }
181
182 // ---------------------------------------
183 // Translate 3D representation of the Edge
184 // ---------------------------------------
185
186 Handle(StepGeom_Curve) Gpms;
187 Handle(Geom_Curve) C = CA.Curve().Curve();
188 if (!C.IsNull()) {
189 C = Handle(Geom_Curve)::DownCast(C->Copy());
7ef1f9b7 190
191 // Special treatment is needed for very short edges based on periodic curves.
192 // Since edge in STEP does not store its parametric range, parameters are computed
193 // on import by projecting vertices on a curve, and for periodic curve this may
194 // lead to use of wrong part of the curve if end vertices are too close to each other
195 // (often whole curve is taken instead of its very small fragment).
196 if (C->IsPeriodic())
197 {
198 Standard_Real dpar = CA.LastParameter() - CA.FirstParameter();
199 if (dpar <= 0)
200 {
201 dpar += (ceil(fabs(dpar) / C->Period()) * C->Period());
202 }
203
204 // if range obtained from projection of vertices contradicts with range
205 // of the edge tnen vertices are swapped to keep results correct after import
206 // (see test de step_5 A1)
207 gp_Pnt aP1 = BRep_Tool::Pnt(Vfirst);
208 gp_Pnt aP2 = BRep_Tool::Pnt(Vlast);
209 gp_Pnt pproj;
210 ShapeAnalysis_Curve sac;
211 sac.Project (C, aP1, Tolerance(), pproj, U1, Standard_False);
212 sac.Project (C, aP2, Tolerance(), pproj, U2, Standard_False);
213 Standard_Real dU = U2 - U1;
214 if (dU <= 0)
215 {
216 dU += (ceil(fabs(dU) / C->Period()) * C->Period());
217 }
218 if ((dU > Precision::PConfusion() && dU <= 0.1 * C->Period() && dpar > 0.5 * C->Period()) ||
219 (dpar > Precision::PConfusion() && dpar <= 0.1 * C->Period() && dU > 0.5 * C->Period()))
220 {
221 std::swap (V1, V2);
222 }
223
224 // If vertices overlap, we cut only needed part of the BSpline curve.
225 // Note that this method cannot be used for canonic curves
226 // (STEP does not support trimmed curves in AIC 514).
227 if (C->IsKind(STANDARD_TYPE(Geom_BSplineCurve)))
228 {
229 Standard_Real aTolV1 = BRep_Tool::Tolerance(Vfirst);
230 Standard_Real aTolV2 = BRep_Tool::Tolerance(Vlast);
231 gp_Pnt aP11 = CA.Value(CA.FirstParameter());
232 gp_Pnt aP12 = CA.Value(CA.LastParameter());
233 gp_Pnt aPm = CA.Value((CA.FirstParameter() + CA.LastParameter()) * 0.5);
234 Standard_Real aDist11 = aP11.Distance(aP12);
235 Standard_Real aDist1m = aP11.Distance(aPm);
236 Standard_Real aDist2m = aP12.Distance(aPm);
237 Standard_Real aDistMax = Max(Max(aDist1m, aDist2m), aDist11);
238 Standard_Boolean isSmallCurve = (aDistMax <= aTolV1 || aDistMax <= aTolV2);
239 if (BRepTools::Compare(Vfirst, Vlast) && isSmallCurve && dpar > Precision::PConfusion() && dpar <= 0.1 * C->Period())
240 {
241 Handle(Geom_BSplineCurve) aBspl1 = Handle(Geom_BSplineCurve)::DownCast(C->Copy());
242 aBspl1->Segment(CA.FirstParameter(), CA.LastParameter());
243 C = aBspl1;
244 }
245 }
246 }
247
7fd59977 248 gp_Trsf Tr1 = CA.Trsf();
249 C->Transform(Tr1);
250 GeomToStep_MakeCurve MkCurve(C);
251 Gpms = MkCurve.Value();
252 }
253 else {
254
255 // -------------------------
256 // a 3D Curve is constructed
257 // -------------------------
258
0797d9d3 259#ifdef OCCT_DEBUG
04232180 260 std::cout << "Warning: TopoDSToStep_MakeStepEdge: edge without 3d curve; creating..." << std::endl;
7fd59977 261#endif
262 if ((SA.GetType() == GeomAbs_Plane) &&
263 (CA.GetType() == GeomAbs_Line)) {
264 U1 = CA.FirstParameter();
265 U2 = CA.LastParameter();
266 gp_Vec V = gp_Vec( CA.Value(U1), CA.Value(U2) );
267 Handle(Geom_Line) L =
268 new Geom_Line(CA.Value(U1), gp_Dir(V));
269 GeomToStep_MakeLine MkLine(L);
270 Gpms = MkLine.Value();
271 }
272 else {
273 // To Be Optimized : create an approximated BSpline
274 // using GeomAPI_PointsToBSpline
275 TColgp_Array1OfPnt Points(1,Nbpt);
276 TColStd_Array1OfReal Knots(1,Nbpt);
277 TColStd_Array1OfInteger Mult(1,Nbpt);
278 U1 = CA.FirstParameter();
279 U2 = CA.LastParameter();
280 for ( i=1; i<=Nbpt; i++ ) {
281 U = U1 + (i-1)*(U2 - U1)/(Nbpt - 1);
282 P = CA.Value(U);
283 Points.SetValue(i,P);
284 Knots.SetValue(i,U);
285 Mult.SetValue(i,1);
286 }
287 //Points.SetValue(1, BRep_Tool::Pnt(Vfirst));
288 //Points.SetValue(Nbpt, BRep_Tool::Pnt(Vlast));
289 Mult.SetValue(1,2);
290 Mult.SetValue(Nbpt,2);
c04c30b3 291 Handle(Geom_Curve) Bs =
7fd59977 292 new Geom_BSplineCurve(Points, Knots, Mult, 1);
293 GeomToStep_MakeCurve MkCurve(Bs);
294 Gpms = MkCurve.Value();
295 }
296 }
297
298 // ---------------------------------------------------------
299 // Warning : if the edge is connected aGeom->Length = 2
300 // otherwise = 1 ;
301 // and enumeration is pscrPcurveS2 or pscrPcurveS1
302 // This is corrected in the Write File phases !
303 // ---------------------------------------------------------
304
305 //:abv 25.01.00 CAX-IF TRJ3
306 // if PcurveMode is 1 (default), make surface_curve instead of simple 3d curve
307 if ( aTool.PCurveMode() != 0 ) {
308
309 Handle(StepGeom_HArray1OfPcurveOrSurface) aGeom =
310 new StepGeom_HArray1OfPcurveOrSurface(1,2);
311 Handle(TCollection_HAsciiString) aName = new TCollection_HAsciiString("");
312
313 if (!isSeam) {
314 Handle(StepGeom_SurfaceCurve) SurfaceCurve = new StepGeom_SurfaceCurve;
315 SurfaceCurve->Init(aName, Gpms, aGeom, StepGeom_pscrPcurveS1);
316 Gpms = SurfaceCurve;
317 }
318 else {
319 Handle(StepGeom_SeamCurve) SeamCurve = new StepGeom_SeamCurve;
320 SeamCurve->Init(aName, Gpms, aGeom, StepGeom_pscrPcurveS1);
321 Gpms = SeamCurve;
322 }
323 }
324
325 // Edge curve
326 Handle(StepShape_EdgeCurve) Epms = new StepShape_EdgeCurve;
327 Handle(TCollection_HAsciiString) aName = new TCollection_HAsciiString("");
328 Epms->Init(aName, V1, V2, Gpms, Standard_True);
329
330 aTool.Bind(aEdge, Epms);
331 myError = TopoDSToStep_EdgeDone;
332 myResult = Epms;
333 done = Standard_True;
334 return;
335}
336
337// ----------------------------------------------------------------------------
338// Method : Value
339// Purpose :
340// ----------------------------------------------------------------------------
341
342const Handle(StepShape_TopologicalRepresentationItem)& TopoDSToStep_MakeStepEdge::Value() const
343{
2d2b3d53 344 StdFail_NotDone_Raise_if (!done, "TopoDSToStep_MakeStepEdge::Value() - no result");
7fd59977 345 return myResult;
346}
347
348// ----------------------------------------------------------------------------
349// Method : Error
350// Purpose :
351// ----------------------------------------------------------------------------
352
353TopoDSToStep_MakeEdgeError TopoDSToStep_MakeStepEdge::Error() const
354{
355 return myError;
356}