TexGen
Exporter.cpp
Go to the documentation of this file.
1#include "Exporter.h"
2
3#include <gp_Pnt.hxx>
4#include <gp_Pln.hxx>
5
6#include <TopoDS_Wire.hxx>
7#include <TopTools_HSequenceOfShape.hxx>
8#include <TColgp_HArray1OfPnt.hxx>
9
10#include <BRepBuilderAPI_MakeEdge.hxx>
11#include <BRepBuilderAPI_MakeWire.hxx>
12#include <BRepBuilderAPI_MakePolygon.hxx>
13#include <BRepOffsetAPI_ThruSections.hxx>
14#include <BRepBuilderAPI_MakeFace.hxx>
15#include <BRepPrimAPI_MakeHalfSpace.hxx>
16#include <BRepPrimAPI_MakeBox.hxx>
17#include <GeomAPI_Interpolate.hxx>
18
19#include <BRepAlgoAPI_Common.hxx>
20#include <BRepAlgoAPI_Fuse.hxx>
21#include <BRepAlgoAPI_Cut.hxx>
22
23#include <BRepBuilderAPI_Transform.hxx>
24#include <BRepBuilderAPI_Copy.hxx>
25
26#include <IGESControl_Controller.hxx>
27#include <IGESControl_Writer.hxx>
28#include <Interface_Static.hxx>
29#include <STEPControl_Writer.hxx>
30#include <STEPControl_StepModelType.hxx>
31
32using namespace TexGen;
33
34CExporter::CExporter()
35: m_bFaceted(false)
36, m_bSubtractYarns(false)
37, m_bExportDomain(true)
38{
39// Interface_Static::SetIVal("write.step.assembly",1);
40}
41
43{
44}
45
46bool CExporter::OutputDomainToIGES(char szFileName[], CDomain &Domain)
47{
48 TGLOGINDENT("Saving Domain to IGES file: " << szFileName);
49 TopTools_HSequenceOfShape Shapes;
50 Shapes.Append(ConvertDomain(Domain));
51 return SaveToIGES(szFileName, Shapes);
52}
53
54bool CExporter::OutputDomainToSTEP(char szFileName[], CDomain &Domain)
55{
56 TGLOGINDENT("Saving Domain to STEP file: " << szFileName);
57 TopTools_HSequenceOfShape Shapes;
58 Shapes.Append(ConvertDomain(Domain));
59 return SaveToSTEP(szFileName, Shapes);
60}
61
62bool CExporter::OutputTextileToIGES(char szFileName[], CTextile &Textile)
63{
64 TGLOGINDENT("Saving Textile to IGES file: " << szFileName);
65 TopTools_HSequenceOfShape Shapes;
66 ConvertTextile(Shapes, Textile);
67 return SaveToIGES(szFileName, Shapes);
68}
69
70bool CExporter::OutputTextileToSTEP(char szFileName[], CTextile &Textile)
71{
72 TGLOGINDENT("Saving Textile to STEP file: " << szFileName);
73 TopTools_HSequenceOfShape Shapes;
74 ConvertTextile(Shapes, Textile);
75 return SaveToSTEP(szFileName, Shapes);
76}
77
78bool CExporter::OutputTextileToIGES(char szFileName[], string TextileName)
79{
80 CTextile *pTextile = CTexGen::GetInstance().GetTextile(TextileName);
81 if (!pTextile)
82 return false;
83
84 return OutputTextileToIGES(szFileName, *pTextile);
85}
86
87bool CExporter::OutputTextileToSTEP(char szFileName[], string TextileName)
88{
89 CTextile *pTextile = CTexGen::GetInstance().GetTextile(TextileName);
90 if (!pTextile)
91 return false;
92
93 return OutputTextileToSTEP(szFileName, *pTextile);
94}
95
96bool CExporter::SaveToSTEP(char szFileName[], TopTools_HSequenceOfShape &Shapes)
97{
98 STEPControl_Writer aWriter;
99
100 IFSelect_ReturnStatus status;
101 for (Standard_Integer i=1; i<=Shapes.Length(); i++)
102 {
103 status = aWriter.Transfer(Shapes.Value(i), STEPControl_AsIs);
104 if (status != IFSelect_RetDone)
105 {
106 return false;
107 }
108 }
109 status = aWriter.Write(szFileName);
110 return (status == IFSelect_RetDone);
111}
112
113bool CExporter::SaveToIGES(char szFileName[], TopTools_HSequenceOfShape &Shapes)
114{
115 IGESControl_Controller::Init();
116 //IGESControl_Writer ICW(Interface_Static::CVal("XSTEP.iges.unit"), 1); // Value 1 for 2nd parameter would give BRep write mode - which should it be??
117 IGESControl_Writer ICW(Interface_Static::CVal("XSTEP.iges.unit"),
118 Interface_Static::IVal("XSTEP.iges.writebrep.mode"));
119
120 for (Standard_Integer i=1;i<=Shapes.Length();i++)
121 {
122 ICW.AddShape(Shapes.Value(i));
123 }
124
125 ICW.ComputeModel();
126 Standard_Boolean result = ICW.Write(szFileName);
127 return result?true:false;
128}
129
130void CExporter::ConvertTextile(TopTools_HSequenceOfShape &Shapes, CTextile &Textile)
131{
132 Shapes.Clear();
133
134 TGLOGINDENT("Converting Textile to Open CASCADE format");
135 int i, j;
136 for (i=0; i<(int)Textile.GetYarns().size(); ++i)
137 {
138 TopTools_HSequenceOfShape Yarns;
139
140 ConvertYarn(Yarns, Textile.GetYarns()[i], Textile.GetDomain());
141 for (j=1; j<=Yarns.Length(); ++j)
142 {
143 Shapes.Append(Yarns.Value(j));
144 }
145 }
146 if (Textile.GetDomain())
147 {
148 bool bConfineSuccess;
149 TopoDS_Shape Domain = ConvertDomain(*Textile.GetDomain());
150 bConfineSuccess = ConfineYarnsToDomain(Shapes, Domain);
151 if (m_bExportDomain)
152 {
154 {
155 if ( bConfineSuccess )
156 SubtractYarnsFromDomain(Domain, Shapes);
157 else
158 TGERROR("Cannot subtract yarn from domain: errors confining yarns");
159 }
160 Shapes.Append(Domain);
161 }
162 }
163}
164
165bool CExporter::ConfineYarnsToDomain(TopTools_HSequenceOfShape &Yarns, const TopoDS_Shape &Domain)
166{
167 TGLOGINDENT("Confining yarns to the domain");
168 int i;
169 bool bSuccess = true;
170
171 for (i=1; i<=Yarns.Length(); ++i)
172 {
173 TGLOG("Confining yarn: " << i << "/" << Yarns.Length());
174 try
175 {
176 Yarns.SetValue(i, BRepAlgoAPI_Common(Yarns.Value(i), Domain));
177 }
178 catch(...)
179 {
180 TGERROR( "Failed to confine yarn " << i << " to domain" );
181 bSuccess = false;
182 }
183 }
184 return bSuccess;
185}
186
187void CExporter::SubtractYarnsFromDomain(TopoDS_Shape &Domain, const TopTools_HSequenceOfShape &Yarns)
188{
189 TGLOGINDENT("Cutting yarns out of the domain");
190 int i;
191 for (i=1; i<=Yarns.Length(); ++i)
192 {
193 TGLOG("Cutting domain with yarn: " << i << "/" << Yarns.Length());
194 Domain = BRepAlgoAPI_Cut(Domain, Yarns.Value(i));
195 }
196}
197
198void CExporter::ConvertYarn(TopTools_HSequenceOfShape &Shapes, CYarn &Yarn, const CDomain *pDomain)
199{
200 Shapes.Clear();
201 TopTools_HSequenceOfShape YarnShapes;
202
203 TGLOG("Converting Yarn to Open CASCADE format");
204
205 vector<CSlaveNode>::const_iterator itSlaveNode;
206 const vector<CSlaveNode> &SlaveNodes = Yarn.GetSlaveNodes(CYarn::SURFACE);
207
208 BRepOffsetAPI_ThruSections SectionsSolid(true, m_bFaceted);
209 for (itSlaveNode = SlaveNodes.begin(); itSlaveNode != SlaveNodes.end(); ++itSlaveNode)
210 {
211 SectionsSolid.AddWire(ConvertSection(itSlaveNode->GetSectionPoints()));
212 }
213 TopoDS_Shape Shape = SectionsSolid.Shape();
214
215 YarnShapes.Append(Shape);
216
217 if (pDomain)
218 {
219 TGLOGINDENT("Repeating Yarn to fully encompass domain");
220 vector<pair<int, int> > RepeatLimits = pDomain->GetRepeatLimits(Yarn);
221 int i;
222 for (i = 0; i < (int)RepeatLimits.size(); ++i)
223 {
224 CopyShapesToRange(YarnShapes, Yarn.GetRepeats()[i], RepeatLimits[i].first, RepeatLimits[i].second);
225 }
226 }
227
228 if ( m_bJoinYarns )
229 {
230 TGLOG("Fusing yarn sections");
231 Shapes.Append( YarnShapes.Value(1) );
232
233 for ( int i = 2; i <= YarnShapes.Length(); )
234 {
235 BRepAlgoAPI_Fuse Fused( Shapes.Value(1), YarnShapes.Value(i) );
236 if ( !Fused.ErrorStatus() ) // Error status = 0 if ok
237 {
238 Shapes.SetValue( 1, Fused.Shape() );
239 YarnShapes.Remove(i);
240 }
241 else
242 {
243 ++i;
244 }
245 }
246 }
247 else
248 Shapes = YarnShapes;
249}
250
251TopoDS_Wire CExporter::ConvertSection(const vector<XYZ> &SectionPoints)
252{
253 if (m_bFaceted)
254 {
255 BRepBuilderAPI_MakePolygon PolygonalWire;
256 vector<XYZ>::const_iterator itSectionPoint;
257 for (itSectionPoint = SectionPoints.begin(); itSectionPoint != SectionPoints.end(); ++itSectionPoint)
258 {
259 gp_Pnt Point(itSectionPoint->x, itSectionPoint->y, itSectionPoint->z);
260 PolygonalWire.Add(Point);
261 }
262 PolygonalWire.Close();
263 return PolygonalWire.Wire();
264 }
265 else
266 {
267 vector<int> Discontinuities;
268 const double dMaxAngle = 90*(PI/180.0);
269 double dAngle;
270 int i, j, iPrev, iNext;
271 XYZ V1, V2, TanV;
272 // Determine where discontinuities occur in the cross section occur (typically this will be at the edges
273 // of the yarn). Check the angle between three consecutive points, if the angle is greater than the set
274 // MaxAngle then define that middle point as a discontinuity.
275 for (i=0; i<(int)SectionPoints.size(); ++i)
276 {
277 iNext = (i+1)%SectionPoints.size();
278 if (i==0)
279 iPrev = SectionPoints.size()-1;
280 else
281 iPrev = (i-1)%SectionPoints.size();
282 V1 = SectionPoints[iNext] - SectionPoints[i];
283 V2 = SectionPoints[i] - SectionPoints[iPrev];
284 Normalise(V1);
285 Normalise(V2);
286 // Create a vector with the average of the first and last sections to specify the tangent for the spline
287 if ( i == 0 )
288 TanV = (V1 + V2)/2;
289 dAngle = acos(DotProduct(V1, V2));
290 if (dAngle > dMaxAngle)
291 {
292 Discontinuities.push_back(i);
293 }
294 }
295 // If there are no discontinuities then create a closed periodic loop
296 if (Discontinuities.empty())
297 {
298 Handle(TColgp_HArray1OfPnt) pPoints = new TColgp_HArray1OfPnt(1, SectionPoints.size()+1);
299 for (i=0; i<(int)SectionPoints.size(); ++i)
300 {
301 pPoints->SetValue(i+1, gp_Pnt(SectionPoints[i].x, SectionPoints[i].y, SectionPoints[i].z));
302 }
303 pPoints->SetValue(i+1, gp_Pnt(SectionPoints[0].x, SectionPoints[0].y, SectionPoints[0].z));
304 GeomAPI_Interpolate Interpolation(pPoints, Standard_False, 0.001);
305
306 // Set up the tangent for the start and end sections
307 gp_Vec Tangent = gp_Vec(TanV.x, TanV.y, TanV.z);
308 Interpolation.Load(Tangent,Tangent, Standard_False);
309
310 Interpolation.Perform();
311 BRepBuilderAPI_MakeEdge Edge(Interpolation.Curve());
312 BRepBuilderAPI_MakeWire Wire(Edge.Edge());
313 return Wire.Wire();
314 }
315 else
316 {
317 // Otherwise the wire will be built up of several sub-wires, 1 wire per discontinuity
318 int iStart, iEnd, iRange;
319 TopoDS_Wire CrossSectionWire;
320 for (j=0; j<(int)Discontinuities.size(); ++j)
321 {
322 // Find the start and end point of the sub-wire
323 iStart = Discontinuities[j];
324 iEnd = Discontinuities[(j+1)%Discontinuities.size()];
325 if (iEnd <= iStart)
326 iEnd += SectionPoints.size();
327 iRange = iEnd - iStart + 1;
328 // Create the sub-wire
329 Handle(TColgp_HArray1OfPnt) pPoints = new TColgp_HArray1OfPnt(1, iRange);
330 for (i=iStart; i<=iEnd; ++i)
331 {
332 XYZ Pt = SectionPoints[i%SectionPoints.size()];
333 pPoints->SetValue(i-iStart+1, gp_Pnt(Pt.x, Pt.y, Pt.z));
334 }
335 GeomAPI_Interpolate Interpolation(pPoints, Standard_False, 0.001);
336 Interpolation.Perform();
337 BRepBuilderAPI_MakeEdge Edge(Interpolation.Curve());
338 // Join the sub-wire with the rest of the CrossSectionWire
339 if (j==0)
340 {
341 BRepBuilderAPI_MakeWire Wire(Edge.Edge());
342 CrossSectionWire = Wire.Wire();
343 }
344 else
345 {
346 BRepBuilderAPI_MakeWire Wire(CrossSectionWire, Edge.Edge());
347 CrossSectionWire = Wire.Wire();
348 }
349 }
350 return CrossSectionWire;
351 }
352 }
353}
354
355void CExporter::CopyShapesToRange(TopTools_HSequenceOfShape &Shapes, XYZ Vector, int iLowerLimit, int iUpperLimit)
356{
357 int i, j;
358 XYZ Translation;
359 gp_Trsf Transform;
360 TopTools_HSequenceOfShape NewShapes;
361 for (i=iLowerLimit; i<=iUpperLimit; ++i)
362 {
363 Translation = i*Vector;
364 Transform.SetTranslation(gp_Vec(Translation.x, Translation.y, Translation.z));
365 for (j=1; j<=Shapes.Length(); ++j)
366 {
367 BRepBuilderAPI_Transform Translated(Shapes.Value(j), Transform, Standard_True);
368 NewShapes.Append(Translated.Shape());
369 }
370 }
371 Shapes = NewShapes;
372}
373
374TopoDS_Shape CExporter::ConvertDomain(const CDomain &Domain)
375{
376 TGLOGINDENT("Converting Domain to Open CASCADE format");
377 if (Domain.GetType() == "CDomainPlanes")
378 {
379 CDomainPlanes &DomainPlanes = *((CDomainPlanes*)&Domain);
380 // If the domain is a box then just make a box with MakeBox and return it
381 XYZ Min, Max;
382 if (DomainPlanes.GetBoxLimits(Min, Max))
383 {
384 return BRepPrimAPI_MakeBox(gp_Pnt(Min.x, Min.y, Min.z), gp_Pnt(Max.x, Max.y, Max.z));
385 }
386
387 // Otherwise make a AABB and then cut it up using the planes that define the boundary
388 Min = DomainPlanes.GetMesh().GetAABB().first;
389 Max = DomainPlanes.GetMesh().GetAABB().second;
390 Min -= XYZ(1, 1, 1);
391 Max += XYZ(1, 1, 1);
392 TopoDS_Shape DomainShape = BRepPrimAPI_MakeBox(gp_Pnt(Min.x, Min.y, Min.z), gp_Pnt(Max.x, Max.y, Max.z));
393 vector<PLANE>::const_iterator itPlane;
394 for (itPlane = DomainPlanes.GetPlanes().begin(); itPlane != DomainPlanes.GetPlanes().end(); ++itPlane)
395 {
396 gp_Pln Plane(itPlane->Normal.x, itPlane->Normal.y, itPlane->Normal.z, -itPlane->d);
397 BRepBuilderAPI_MakeFace Face(Plane);
398 XYZ RefPoint = (itPlane->d+1)*itPlane->Normal;
399 BRepPrimAPI_MakeHalfSpace HalfSpace(Face.Face(), gp_Pnt(RefPoint.x, RefPoint.y, RefPoint.z));
400 DomainShape = BRepAlgoAPI_Common(HalfSpace.Solid(), DomainShape);
401 }
402 return DomainShape;
403 }
404 return TopoDS_Shape();
405}
406
407
#define TGLOGINDENT(MESSAGE)
Combines the TGLOG macro and TGLOGAUTOINDENT macro in one.
Definition: Logger.h:68
#define TGERROR(MESSAGE)
Macros used to report the file name and line number to the TexGenError and TexGenLog functions.
Definition: Logger.h:29
#define TGLOG(MESSAGE)
Definition: Logger.h:36
Abstract base class representing the domain in which a textile cell may lie.
Definition: Domain.h:34
virtual string GetType() const =0
Derived class should return the class name.
const CMesh & GetMesh() const
Get the mesh representing the domain as a surface mesh.
Definition: Domain.h:73
vector< pair< int, int > > GetRepeatLimits(const CYarn &Yarn) const
Definition: Domain.cpp:148
Domain implementation described using planes, the simplest of which would be a box.
Definition: DomainPlanes.h:37
const vector< PLANE > & GetPlanes() const
Accessor method to get the planes making up this domain.
Definition: DomainPlanes.h:56
bool GetBoxLimits(XYZ &Min, XYZ &Max)
If the limits describe a box return the minimum and maximum otherwise return false.
bool OutputTextileToIGES(char szFileName[], CTextile &Textile)
Output the textile to IGES file format.
Definition: Exporter.cpp:62
bool SaveToIGES(char szFileName[], TopTools_HSequenceOfShape &Shapes)
Save sequence of shapes to IGES file.
Definition: Exporter.cpp:113
void ConvertYarn(TopTools_HSequenceOfShape &Shapes, CYarn &Yarn, const CDomain *pDomain=NULL)
Convert yarn to a sequence of OpenCascade TopoDS_Shape.
Definition: Exporter.cpp:198
void ConvertTextile(TopTools_HSequenceOfShape &Shapes, CTextile &Textile)
Convert textile to a sequence of OpenCascade TopoDS_Shape.
Definition: Exporter.cpp:130
static void CopyShapesToRange(TopTools_HSequenceOfShape &Shapes, XYZ Vector, int iLowerLimit, int iUpperLimit)
Copy the shapes to given range with given repeat vector.
Definition: Exporter.cpp:355
bool OutputDomainToIGES(char szFileName[], CDomain &Domain)
Output the domain to IGES file format.
Definition: Exporter.cpp:46
bool m_bExportDomain
Definition: Exporter.h:70
TopoDS_Shape ConvertDomain(const CDomain &Domain)
Convert domain to a OpenCascade TopoDS_Shape.
Definition: Exporter.cpp:374
bool OutputDomainToSTEP(char szFileName[], CDomain &Domain)
Output the domain to STEP file format.
Definition: Exporter.cpp:54
TopoDS_Wire ConvertSection(const vector< XYZ > &SectionPoints)
Convert a yarn section to a OpenCascade wire.
Definition: Exporter.cpp:251
bool ConfineYarnsToDomain(TopTools_HSequenceOfShape &Yarns, const TopoDS_Shape &Domain)
Trim the yarns such they fit within the domain.
Definition: Exporter.cpp:165
bool m_bSubtractYarns
Definition: Exporter.h:71
bool SaveToSTEP(char szFileName[], TopTools_HSequenceOfShape &Shapes)
Save sequence of shapes to STEP file.
Definition: Exporter.cpp:96
void SubtractYarnsFromDomain(TopoDS_Shape &Domain, const TopTools_HSequenceOfShape &Yarns)
Subtract yarns from the domain (NOTE: THIS IS UNSTABLE AND VERY SLOW)
Definition: Exporter.cpp:187
bool OutputTextileToSTEP(char szFileName[], CTextile &Textile)
Output the textile to STEP file format.
Definition: Exporter.cpp:70
pair< XYZ, XYZ > GetAABB(double dGrowDistance=0) const
Get an axis aligned bounding box for the mesh.
Definition: Mesh.cpp:340
static CTexGen & GetInstance()
Definition: Singleton.h:40
CTextile * GetTextile(string TextileName="")
Get a textile with given name.
Definition: TexGen.cpp:59
Represents a textile cell containing yarns.
Definition: Textile.h:39
const CDomain * GetDomain() const
Definition: Textile.h:287
const vector< CYarn > & GetYarns() const
Definition: Textile.cpp:676
Represents a yarn consisting of master nodes, section and interpolation function.
Definition: Yarn.h:49
const vector< CSlaveNode > & GetSlaveNodes(BUILD_TYPE Usage) const
Get the slave nodes and build them if necessary.
Definition: Yarn.cpp:1749
@ SURFACE
Definition: Yarn.h:60
const vector< XYZ > & GetRepeats() const
Definition: Yarn.h:448
#define PI
Definition: mymath.h:30
Namespace containing a series of customised math operations not found in the standard c++ library.
double Max(XYZ &Vector)
Get maximum element of vector and return it.
Definition: mymath.h:642
XYZ Min(const XYZ &P1, const XYZ &P2)
Given two points, return a new point who's coordinates are the smaller of the two.
Definition: mymath.h:1142
WXYZ & Normalise(WXYZ &Quaternion)
Normalise the quaternion and return it.
Definition: mymath.h:609
double DotProduct(const XYZ &left, const XYZ &right)
Get the dot product of two vectors.
Definition: mymath.h:512
Struct for representing points in 3D space.
Definition: mymath.h:56
double z
Definition: mymath.h:57
double x
Definition: mymath.h:57
double y
Definition: mymath.h:57