Coverage Report

Created: 2026-07-30 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/assimp/code/AssetLib/Step/StepExporter.cpp
Line
Count
Source
1
/*
2
Open Asset Import Library (assimp)
3
----------------------------------------------------------------------
4
5
Copyright (c) 2006-2026, assimp team
6
7
All rights reserved.
8
9
Redistribution and use of this software in source and binary forms,
10
with or without modification, are permitted provided that the
11
following conditions are met:
12
13
* Redistributions of source code must retain the above
14
  copyright notice, this list of conditions and the
15
  following disclaimer.
16
17
* Redistributions in binary form must reproduce the above
18
  copyright notice, this list of conditions and the
19
  following disclaimer in the documentation and/or other
20
  materials provided with the distribution.
21
22
* Neither the name of the assimp team, nor the names of its
23
  contributors may be used to endorse or promote products
24
  derived from this software without specific prior
25
  written permission of the assimp team.
26
27
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39
----------------------------------------------------------------------
40
*/
41
42
#ifndef ASSIMP_BUILD_NO_EXPORT
43
#ifndef ASSIMP_BUILD_NO_STEP_EXPORTER
44
45
#include "AssetLib/Step/StepExporter.h"
46
#include "PostProcessing/ConvertToLHProcess.h"
47
48
#include <assimp/Bitmap.h>
49
#include <assimp/BaseImporter.h>
50
#include <assimp/fast_atof.h>
51
#include <assimp/SceneCombiner.h>
52
#include <assimp/Exceptional.h>
53
#include <assimp/DefaultIOSystem.h>
54
#include <assimp/IOSystem.hpp>
55
#include <assimp/scene.h>
56
#include <assimp/light.h>
57
58
#include <iostream>
59
#include <ctime>
60
#include <set>
61
#include <map>
62
#include <list>
63
#include <memory>
64
65
//
66
#if _MSC_VER > 1500 || (defined __GNUC__)
67
#   define ASSIMP_STEP_USE_UNORDERED_MULTIMAP
68
#   else
69
#   define step_unordered_map map
70
#   define step_unordered_multimap multimap
71
#endif
72
73
#ifdef ASSIMP_STEP_USE_UNORDERED_MULTIMAP
74
#   include <unordered_map>
75
#   if defined(_MSC_VER) && _MSC_VER <= 1600
76
#       define step_unordered_map tr1::unordered_map
77
#       define step_unordered_multimap tr1::unordered_multimap
78
#   else
79
#       define step_unordered_map unordered_map
80
#       define step_unordered_multimap unordered_multimap
81
#   endif
82
#endif
83
84
typedef std::step_unordered_map<aiVector3D*, int> VectorIndexUMap;
85
86
/* Tested with Step viewer v4 from www.ida-step.net */
87
88
using namespace Assimp;
89
90
namespace Assimp
91
{
92
93
// ------------------------------------------------------------------------------------------------
94
// Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
95
void ExportSceneStep(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
96
1.54k
{
97
1.54k
    std::string path = DefaultIOSystem::absolutePath(std::string(pFile));
98
1.54k
    std::string file = DefaultIOSystem::completeBaseName(std::string(pFile));
99
100
    // create/copy Properties
101
1.54k
    ExportProperties props(*pProperties);
102
103
    // invoke the exporter
104
1.54k
    StepExporter iDoTheExportThing( pScene, pIOSystem, path, file, &props);
105
106
    // we're still here - export successfully completed. Write result to the given IOSYstem
107
1.54k
    std::unique_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
108
1.54k
    if (outfile == nullptr) {
109
0
        throw DeadlyExportError("could not open output .stp file: " + std::string(pFile));
110
0
    }
111
112
    // XXX maybe use a small wrapper around IOStream that behaves like std::stringstream in order to avoid the extra copy.
113
1.54k
    outfile->Write( iDoTheExportThing.mOutput.str().c_str(), static_cast<size_t>(iDoTheExportThing.mOutput.tellp()),1);
114
1.54k
}
115
116
} // end of namespace Assimp
117
118
119
namespace {
120
    // Collect world transformations for each node
121
12.6k
    void CollectTrafos(const aiNode* node, std::map<const aiNode*, aiMatrix4x4>& trafos) {
122
12.6k
        const aiMatrix4x4& parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4();
123
12.6k
        trafos[node] = parent * node->mTransformation;
124
23.8k
        for (unsigned int i = 0; i < node->mNumChildren; ++i) {
125
11.1k
            CollectTrafos(node->mChildren[i], trafos);
126
11.1k
        }
127
12.6k
    }
128
129
    // Generate a flat list of the meshes (by index) assigned to each node
130
12.6k
    void CollectMeshes(const aiNode* node, std::multimap<const aiNode*, unsigned int>& meshes) {
131
17.3k
        for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
132
4.64k
            meshes.insert(std::make_pair(node, node->mMeshes[i]));
133
4.64k
        }
134
23.8k
        for (unsigned int i = 0; i < node->mNumChildren; ++i) {
135
11.1k
            CollectMeshes(node->mChildren[i], meshes);
136
11.1k
        }
137
12.6k
    }
138
}
139
140
// ------------------------------------------------------------------------------------------------
141
// Constructor for a specific scene to export
142
StepExporter::StepExporter(const aiScene* pScene, IOSystem* pIOSystem, const std::string& path,
143
    const std::string& file, const ExportProperties* pProperties) :
144
1.54k
    mProperties(pProperties), mIOSystem(pIOSystem), mFile(file), mPath(path),
145
1.54k
    mScene(pScene), endstr(";\n") {
146
1.54k
    CollectTrafos(pScene->mRootNode, trafos);
147
1.54k
    CollectMeshes(pScene->mRootNode, meshes);
148
149
    // make sure that all formatting happens using the standard, C locale and not the user's current locale
150
1.54k
    mOutput.imbue(std::locale("C"));
151
1.54k
    mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION);
152
153
    // start writing
154
1.54k
    WriteFile();
155
1.54k
}
156
157
// ------------------------------------------------------------------------------------------------
158
// Starts writing the contents
159
void StepExporter::WriteFile()
160
1.54k
{
161
    // see http://shodhganga.inflibnet.ac.in:8080/jspui/bitstream/10603/14116/11/11_chapter%203.pdf
162
    // note, that all realnumber values must be comma separated in x files
163
1.54k
    mOutput.setf(std::ios::fixed);
164
    // precision for double
165
    // see http://stackoverflow.com/questions/554063/how-do-i-print-a-double-value-with-full-precision-using-cout
166
1.54k
    mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION);
167
168
    // standard color
169
1.54k
    aiColor4D fColor;
170
1.54k
    fColor.r = 0.8f;
171
1.54k
    fColor.g = 0.8f;
172
1.54k
    fColor.b = 0.8f;
173
174
1.54k
    int ind = 100; // the start index to be used
175
1.54k
    std::vector<int> faceEntryLen; // numbers of entries for a triangle/face
176
    // prepare unique (count triangles and vertices)
177
178
1.54k
    VectorIndexUMap uniqueVerts; // use a map to reduce find complexity to log(n)
179
1.54k
    VectorIndexUMap::iterator it;
180
181
6.17k
    for (unsigned int i=0; i<mScene->mNumMeshes; ++i)
182
4.62k
    {
183
4.62k
        aiMesh* mesh = mScene->mMeshes[i];
184
557k
        for (unsigned int j=0; j<mesh->mNumFaces; ++j)
185
552k
        {
186
552k
            aiFace* face = &(mesh->mFaces[j]);
187
188
552k
            if (face->mNumIndices >= 3) faceEntryLen.push_back(15 + 5 * face->mNumIndices);
189
552k
        }
190
408k
        for (unsigned int j=0; j<mesh->mNumVertices; ++j)
191
403k
        {
192
403k
            aiVector3D* v = &(mesh->mVertices[j]);
193
403k
            it =uniqueVerts.find(v);
194
403k
            if (it == uniqueVerts.end())
195
403k
            {
196
403k
                uniqueVerts[v] = -1; // first mark the vector as not transformed
197
403k
            }
198
403k
        }
199
4.62k
    }
200
201
1.54k
    static const unsigned int date_nb_chars = 20;
202
1.54k
    char date_str[date_nb_chars];
203
1.54k
    std::time_t date = std::time(nullptr);
204
1.54k
    std::strftime(date_str, date_nb_chars, "%Y-%m-%dT%H:%M:%S", std::localtime(&date));
205
206
    // write the header
207
1.54k
    mOutput << "ISO-10303-21" << endstr;
208
1.54k
    mOutput << "HEADER" << endstr;
209
1.54k
    mOutput << "FILE_DESCRIPTION(('STEP AP214'),'1')" << endstr;
210
1.54k
    mOutput << "FILE_NAME('" << mFile << ".stp','" << date_str << "',(' '),(' '),'Spatial InterOp 3D',' ',' ')" << endstr;
211
1.54k
    mOutput << "FILE_SCHEMA(('automotive_design'))" << endstr;
212
1.54k
    mOutput << "ENDSEC" << endstr;
213
214
    // write the top of data
215
1.54k
    mOutput << "DATA" << endstr;
216
1.54k
    mOutput << "#1=MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION(' ',(";
217
1.54k
    size_t countFace = faceEntryLen.size();
218
1.54k
    size_t faceLenIndex = ind + 2 * uniqueVerts.size();
219
428k
    for (size_t i=0; i<countFace; ++i)
220
427k
    {
221
427k
        mOutput << "#" << faceLenIndex;
222
427k
        if (i!=countFace-1) mOutput << ",";
223
427k
        faceLenIndex += faceEntryLen[i];
224
427k
    }
225
1.54k
    mOutput << "),#6)" << endstr;
226
227
1.54k
    mOutput << "#2=PRODUCT_DEFINITION_CONTEXT('',#7,'design')" << endstr;
228
1.54k
    mOutput << "#3=APPLICATION_PROTOCOL_DEFINITION('INTERNATIONAL STANDARD','automotive_design',1994,#7)" << endstr;
229
1.54k
    mOutput << "#4=PRODUCT_CATEGORY_RELATIONSHIP('NONE','NONE',#8,#9)" << endstr;
230
1.54k
    mOutput << "#5=SHAPE_DEFINITION_REPRESENTATION(#10,#11)" << endstr;
231
1.54k
    mOutput << "#6= (GEOMETRIC_REPRESENTATION_CONTEXT(3)GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#12))GLOBAL_UNIT_ASSIGNED_CONTEXT((#13,#14,#15))REPRESENTATION_CONTEXT('NONE','WORKSPACE'))" << endstr;
232
1.54k
    mOutput << "#7=APPLICATION_CONTEXT(' ')" << endstr;
233
1.54k
    mOutput << "#8=PRODUCT_CATEGORY('part','NONE')" << endstr;
234
1.54k
    mOutput << "#9=PRODUCT_RELATED_PRODUCT_CATEGORY('detail',' ',(#17))" << endstr;
235
1.54k
    mOutput << "#10=PRODUCT_DEFINITION_SHAPE('NONE','NONE',#18)" << endstr;
236
1.54k
    mOutput << "#11=MANIFOLD_SURFACE_SHAPE_REPRESENTATION('Root',(#16,#19),#6)" << endstr;
237
1.54k
    mOutput << "#12=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.0E-006),#13,'','')" << endstr;
238
1.54k
    mOutput << "#13=(CONVERSION_BASED_UNIT('METRE',#20)LENGTH_UNIT()NAMED_UNIT(#21))" << endstr;
239
1.54k
    mOutput << "#14=(NAMED_UNIT(#22)PLANE_ANGLE_UNIT()SI_UNIT($,.RADIAN.))" << endstr;
240
1.54k
    mOutput << "#15=(NAMED_UNIT(#22)SOLID_ANGLE_UNIT()SI_UNIT($,.STERADIAN.))" << endstr;
241
1.54k
    mOutput << "#16=SHELL_BASED_SURFACE_MODEL('Root',(#29))" << endstr;
242
1.54k
    mOutput << "#17=PRODUCT('Root','Root','Root',(#23))" << endstr;
243
1.54k
    mOutput << "#18=PRODUCT_DEFINITION('NONE','NONE',#24,#2)" << endstr;
244
1.54k
    mOutput << "#19=AXIS2_PLACEMENT_3D('',#25,#26,#27)" << endstr;
245
1.54k
    mOutput << "#20=LENGTH_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.0),#28)" << endstr;
246
1.54k
    mOutput << "#21=DIMENSIONAL_EXPONENTS(1.0,0.0,0.0,0.0,0.0,0.0,0.0)" << endstr;
247
1.54k
    mOutput << "#22=DIMENSIONAL_EXPONENTS(0.0,0.0,0.0,0.0,0.0,0.0,0.0)" << endstr;
248
1.54k
    mOutput << "#23=PRODUCT_CONTEXT('',#7,'mechanical')" << endstr;
249
1.54k
    mOutput << "#24=PRODUCT_DEFINITION_FORMATION_WITH_SPECIFIED_SOURCE(' ','NONE',#17,.NOT_KNOWN.)" << endstr;
250
1.54k
    mOutput << "#25=CARTESIAN_POINT('',(0.0,0.0,0.0))" << endstr;
251
1.54k
    mOutput << "#26=DIRECTION('',(0.0,0.0,1.0))" << endstr;
252
1.54k
    mOutput << "#27=DIRECTION('',(1.0,0.0,0.0))" << endstr;
253
1.54k
    mOutput << "#28= (NAMED_UNIT(#21)LENGTH_UNIT()SI_UNIT(.MILLI.,.METRE.))" << endstr;
254
1.54k
    mOutput << "#29=CLOSED_SHELL('',(";
255
1.54k
    faceLenIndex = ind + 2 * uniqueVerts.size() + 8;
256
428k
    for (size_t i=0; i<countFace; ++i)
257
427k
    {
258
427k
        mOutput << "#" << faceLenIndex;
259
427k
        if (i!=countFace-1) mOutput << ",";
260
427k
        faceLenIndex += faceEntryLen[i];
261
427k
    }
262
1.54k
    mOutput << "))" << endstr;
263
264
    // write all the unique transformed CARTESIAN and VERTEX
265
6.18k
    for (MeshesByNodeMap::const_iterator it2 = meshes.begin(); it2 != meshes.end(); ++it2)
266
4.64k
    {
267
4.64k
        const aiNode& node = *(*it2).first;
268
4.64k
        unsigned int mesh_idx = (*it2).second;
269
270
4.64k
        const aiMesh* mesh = mScene->mMeshes[mesh_idx];
271
4.64k
        aiMatrix4x4& trafo = trafos[&node];
272
408k
        for (unsigned int i = 0; i < mesh->mNumVertices; ++i)
273
403k
        {
274
403k
            aiVector3D* v = &(mesh->mVertices[i]);
275
403k
            it = uniqueVerts.find(v);
276
403k
            if (it->second >=0 ) continue;
277
403k
            it->second = ind; // this one is new, so set the index (ind)
278
403k
            aiVector3D vt = trafo * (*v); // transform the coordinate
279
403k
            mOutput << "#" << it->second << "=CARTESIAN_POINT('',(" << vt.x << "," << vt.y << "," << vt.z << "))" << endstr;
280
403k
            mOutput << "#" << it->second+1 << "=VERTEX_POINT('',#" << it->second << ")" << endstr;
281
403k
            ind += 2;
282
403k
        }
283
4.64k
    }
284
285
    // write the triangles
286
6.17k
    for (unsigned int i=0; i<mScene->mNumMeshes; ++i)
287
4.62k
    {
288
4.62k
        aiMesh* mesh = mScene->mMeshes[i];
289
557k
        for (unsigned int j=0; j<mesh->mNumFaces; ++j)
290
552k
        {
291
552k
            aiFace* face = &(mesh->mFaces[j]);
292
293
552k
            const int numIndices = face->mNumIndices;
294
552k
            if (numIndices < 3) continue;
295
296
427k
            std::vector<int> pidArray(numIndices, -1); // vertex id
297
427k
            std::vector<aiVector3D> dvArray(numIndices); // edge dir
298
1.70M
            for (int k = 0; k < numIndices; ++k)
299
1.28M
            {
300
1.28M
                aiVector3D *v1 = &(mesh->mVertices[face->mIndices[k]]);
301
1.28M
                pidArray[k] = uniqueVerts.find(v1)->second;
302
303
1.28M
                aiVector3D *v2 = nullptr;
304
1.28M
                if (k + 1 == numIndices)
305
427k
                    v2 = &(mesh->mVertices[face->mIndices[0]]);
306
854k
                else
307
854k
                    v2 = &(mesh->mVertices[face->mIndices[k + 1]]);
308
1.28M
                dvArray[k] = *v2 - *v1;
309
1.28M
                dvArray[k].Normalize();
310
1.28M
            }
311
312
427k
            aiVector3D dvY = dvArray[1];
313
427k
            aiVector3D dvX = dvY ^ dvArray[0];
314
427k
            dvX.Normalize();
315
316
            // mean vertex color for the face if available
317
427k
            if (mesh->HasVertexColors(0))
318
35.8k
            {
319
35.8k
                fColor.r = 0.0;
320
35.8k
                fColor.g = 0.0;
321
35.8k
                fColor.b = 0.0;
322
35.8k
                fColor += mesh->mColors[0][face->mIndices[0]];
323
35.8k
                fColor += mesh->mColors[0][face->mIndices[1]];
324
35.8k
                fColor += mesh->mColors[0][face->mIndices[2]];
325
35.8k
                fColor /= 3.0f;
326
35.8k
            }
327
328
427k
            int sid = ind; // the sub index
329
427k
            mOutput << "#" << sid << "=STYLED_ITEM('',(#" << sid+1 << "),#" << sid+8 << ")" << endstr; /* the item that must be referenced in #1 */
330
            /* This is the color information of the Triangle */
331
427k
            mOutput << "#" << sid+1 << "=PRESENTATION_STYLE_ASSIGNMENT((#" << sid+2 << "))" << endstr;
332
427k
            mOutput << "#" << sid+2 << "=SURFACE_STYLE_USAGE(.BOTH.,#" << sid+3 << ")" << endstr;
333
427k
            mOutput << "#" << sid+3 << "=SURFACE_SIDE_STYLE('',(#" << sid+4 << "))" << endstr;
334
427k
            mOutput << "#" << sid+4 << "=SURFACE_STYLE_FILL_AREA(#" << sid+5 << ")" << endstr;
335
427k
            mOutput << "#" << sid+5 << "=FILL_AREA_STYLE('',(#" << sid+6 << "))" << endstr;
336
427k
            mOutput << "#" << sid+6 << "=FILL_AREA_STYLE_COLOUR('',#" << sid+7 << ")" << endstr;
337
427k
            mOutput << "#" << sid+7 << "=COLOUR_RGB(''," << fColor.r << "," << fColor.g << "," << fColor.b << ")" << endstr;
338
339
            /* this is the geometry */
340
427k
            mOutput << "#" << sid+8 << "=FACE_SURFACE('',(#" << sid+13 << "),#" << sid+9<< ",.T.)" << endstr; /* the face that must be referenced in 29 */
341
342
            /* 2 directions of the plane */
343
427k
            mOutput << "#" << sid+9 << "=PLANE('',#" << sid+10 << ")" << endstr;
344
427k
            mOutput << "#" << sid+10 << "=AXIS2_PLACEMENT_3D('',#" << pidArray[0] << ",#" << sid+11 << ",#" << sid+12 << ")" << endstr;
345
346
427k
            mOutput << "#" << sid + 11 << "=DIRECTION('',(" << dvX.x << "," << dvX.y << "," << dvX.z << "))" << endstr;
347
427k
            mOutput << "#" << sid + 12 << "=DIRECTION('',(" << dvY.x << "," << dvY.y << "," << dvY.z << "))" << endstr;
348
349
427k
            mOutput << "#" << sid+13 << "=FACE_BOUND('',#" << sid+14 << ",.T.)" << endstr;
350
427k
            mOutput << "#" << sid+14 << "=EDGE_LOOP('',(";
351
427k
            int edgeLoopStart = sid + 15;
352
1.70M
            for (int k = 0; k < numIndices; ++k)
353
1.28M
            {
354
1.28M
                if (k == 0)
355
427k
                    mOutput << "#";
356
854k
                else
357
854k
                    mOutput << ",#";
358
1.28M
                mOutput << edgeLoopStart + k;
359
1.28M
            }
360
427k
            mOutput << "))" << endstr;
361
362
            /* edge loop  */
363
427k
            int orientedEdgesStart = edgeLoopStart + numIndices;
364
1.70M
            for (int k=0; k < numIndices; k++)
365
1.28M
            {
366
1.28M
                mOutput << "#" << edgeLoopStart+k << "=ORIENTED_EDGE('',*,*,#" << orientedEdgesStart + k << ",.T.)" << endstr;
367
1.28M
            }
368
369
            /* oriented edges */
370
427k
            int lineStart = orientedEdgesStart + numIndices;
371
1.70M
            for (int k=0; k < numIndices; ++k)
372
1.28M
            {
373
1.28M
                if (k == 0)
374
427k
                    mOutput << "#" << orientedEdgesStart+k << "=EDGE_CURVE('',#" << pidArray[k]+1 << ",#" << pidArray[k+1]+1 << ",#" << lineStart+k << ",.F.)" << endstr;
375
854k
                else if (k+1 == numIndices)
376
427k
                    mOutput << "#" << orientedEdgesStart+k << "=EDGE_CURVE('',#" << pidArray[k]+1 << ",#" << pidArray[0]+1 << ",#" << lineStart+k << ",.T.)" << endstr;
377
427k
                else
378
427k
                    mOutput << "#" << orientedEdgesStart+k << "=EDGE_CURVE('',#" << pidArray[k]+1 << ",#" << pidArray[k+1]+1 << ",#" << lineStart+k << ",.T.)" << endstr;
379
1.28M
            }
380
381
            /* n lines and n vectors for the lines for the n edge curves */
382
427k
            int vectorStart = lineStart + numIndices;
383
1.70M
            for (int k=0; k < numIndices; ++k)
384
1.28M
            {
385
1.28M
                mOutput << "#" << lineStart+k << "=LINE('',#" << pidArray[k] << ",#" << vectorStart+k << ")" << endstr;
386
1.28M
            }
387
388
427k
            int directionStart = vectorStart + numIndices;
389
1.70M
            for (int k=0; k < numIndices; ++k)
390
1.28M
            {
391
1.28M
                mOutput << "#" << vectorStart+k << "=VECTOR('',#" << directionStart+k << ",1.0)" << endstr;
392
1.28M
            }
393
394
1.70M
            for (int k=0; k < numIndices; ++k)
395
1.28M
            {
396
1.28M
                const aiVector3D &dv = dvArray[k];
397
1.28M
                mOutput << "#" << directionStart + k << "=DIRECTION('',(" << dv.x << "," << dv.y << "," << dv.z << "))" << endstr;
398
1.28M
            }
399
427k
            ind += 15 + 5*numIndices; // increase counter
400
427k
        }
401
4.62k
    }
402
403
1.54k
    mOutput << "ENDSEC" << endstr; // end of data section
404
1.54k
    mOutput << "END-ISO-10303-21" << endstr; // end of file
405
1.54k
}
406
407
#endif
408
#endif