Solvespace

Форк
0
/
exportstep.cpp 
409 строк · 13.4 Кб
1
//-----------------------------------------------------------------------------
2
// Export a STEP file describing our ratpoly shell.
3
//
4
// Copyright 2008-2013 Jonathan Westhues.
5
//-----------------------------------------------------------------------------
6
#include "solvespace.h"
7

8
void StepFileWriter::WriteHeader() {
9
    fprintf(f,
10
"ISO-10303-21;\n"
11
"HEADER;\n"
12
"\n"
13
"FILE_DESCRIPTION((''), '2;1');\n"
14
"\n"
15
"FILE_NAME(\n"
16
"    'output_file',\n"
17
"    '2009-06-07T17:44:47-07:00',\n"
18
"    (''),\n"
19
"    (''),\n"
20
"    'SolveSpace',\n"
21
"    '',\n"
22
"    ''\n"
23
");\n"
24
"\n"
25
"FILE_SCHEMA (('CONFIG_CONTROL_DESIGN'));\n"
26
"ENDSEC;\n"
27
"\n"
28
"DATA;\n"
29
"\n"
30
"/**********************************************************\n"
31
" * This defines the units and tolerances for the file. It\n"
32
" * is always the same, independent of the actual data.\n"
33
" **********************************************************/\n"
34
"#158=(\n"
35
"LENGTH_UNIT()\n"
36
"NAMED_UNIT(*)\n"
37
"SI_UNIT(.MILLI.,.METRE.)\n"
38
");\n"
39
"#161=(\n"
40
"NAMED_UNIT(*)\n"
41
"PLANE_ANGLE_UNIT()\n"
42
"SI_UNIT($,.RADIAN.)\n"
43
");\n"
44
"#166=(\n"
45
"NAMED_UNIT(*)\n"
46
"SI_UNIT($,.STERADIAN.)\n"
47
"SOLID_ANGLE_UNIT()\n"
48
");\n"
49
"#167=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.001),#158,\n"
50
"'DISTANCE_ACCURACY_VALUE',\n"
51
"'string');\n"
52
"#168=(\n"
53
"GEOMETRIC_REPRESENTATION_CONTEXT(3)\n"
54
"GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#167))\n"
55
"GLOBAL_UNIT_ASSIGNED_CONTEXT((#166,#161,#158))\n"
56
"REPRESENTATION_CONTEXT('ID1','3D')\n"
57
");\n"
58
"#169=SHAPE_REPRESENTATION('',(#170),#168);\n"
59
"#170=AXIS2_PLACEMENT_3D('',#173,#171,#172);\n"
60
"#171=DIRECTION('',(0.,0.,1.));\n"
61
"#172=DIRECTION('',(1.,0.,0.));\n"
62
"#173=CARTESIAN_POINT('',(0.,0.,0.));\n"
63
"\n"
64
    );
65

66
    // Start the ID somewhere beyond the header IDs.
67
    id = 200;
68
}
69
void StepFileWriter::WriteProductHeader() {
70
	fprintf(f,
71
		"#175 = SHAPE_DEFINITION_REPRESENTATION(#176, #169);\n"
72
		"#176 = PRODUCT_DEFINITION_SHAPE('Version', 'Test Part', #177);\n"
73
		"#177 = PRODUCT_DEFINITION('Version', 'Test Part', #182, #178);\n"
74
		"#178 = DESIGN_CONTEXT('3D Mechanical Parts', #181, 'design');\n"
75
		"#179 = PRODUCT('1', 'Product', 'Test Part', (#180));\n"
76
		"#180 = MECHANICAL_CONTEXT('3D Mechanical Parts', #181, 'mechanical');\n"
77
		"#181 = APPLICATION_CONTEXT(\n"
78
		"'configuration controlled 3d designs of mechanical parts and assemblies');\n"
79
		"#182 = PRODUCT_DEFINITION_FORMATION_WITH_SPECIFIED_SOURCE('Version',\n"
80
		"'Test Part', #179, .MADE.);\n"
81
		"\n"
82
		);
83
}
84
int StepFileWriter::ExportCurve(SBezier *sb) {
85
    int i, ret = id;
86

87
    fprintf(f, "#%d=(\n", ret);
88
    fprintf(f, "BOUNDED_CURVE()\n");
89
    fprintf(f, "B_SPLINE_CURVE(%d,(", sb->deg);
90
    for(i = 0; i <= sb->deg; i++) {
91
        fprintf(f, "#%d", ret + i + 1);
92
        if(i != sb->deg) fprintf(f, ",");
93
    }
94
    fprintf(f, "),.UNSPECIFIED.,.F.,.F.)\n");
95
    fprintf(f, "B_SPLINE_CURVE_WITH_KNOTS((%d,%d),",
96
        (sb->deg + 1), (sb-> deg + 1));
97
    fprintf(f, "(0.000,1.000),.UNSPECIFIED.)\n");
98
    fprintf(f, "CURVE()\n");
99
    fprintf(f, "GEOMETRIC_REPRESENTATION_ITEM()\n");
100
    fprintf(f, "RATIONAL_B_SPLINE_CURVE((");
101
    for(i = 0; i <= sb->deg; i++) {
102
        fprintf(f, "%.10f", sb->weight[i]);
103
        if(i != sb->deg) fprintf(f, ",");
104
    }
105
    fprintf(f, "))\n");
106
    fprintf(f, "REPRESENTATION_ITEM('')\n);\n");
107

108
    for(i = 0; i <= sb->deg; i++) {
109
        fprintf(f, "#%d=CARTESIAN_POINT('',(%.10f,%.10f,%.10f));\n",
110
            id + 1 + i,
111
            CO(sb->ctrl[i]));
112
    }
113
    fprintf(f, "\n");
114

115
    id = ret + 1 + (sb->deg + 1);
116
    return ret;
117
}
118

119
int StepFileWriter::ExportCurveLoop(SBezierLoop *loop, bool inner) {
120
    ssassert(loop->l.n >= 1, "Expected at least one loop");
121

122
    List<int> listOfTrims = {};
123

124
    SBezier *sb = loop->l.Last();
125

126
    // Generate "exactly closed" contours, with the same vertex id for the
127
    // finish of a previous edge and the start of the next one. So we need
128
    // the finish of the last Bezier in the loop before we start our process.
129
    fprintf(f, "#%d=CARTESIAN_POINT('',(%.10f,%.10f,%.10f));\n",
130
        id, CO(sb->Finish()));
131
    fprintf(f, "#%d=VERTEX_POINT('',#%d);\n", id+1, id);
132
    int lastFinish = id + 1, prevFinish = lastFinish;
133
    id += 2;
134

135
    for(sb = loop->l.First(); sb; sb = loop->l.NextAfter(sb)) {
136
        int curveId = ExportCurve(sb);
137

138
        int thisFinish;
139
        if(loop->l.NextAfter(sb) != NULL) {
140
            fprintf(f, "#%d=CARTESIAN_POINT('',(%.10f,%.10f,%.10f));\n",
141
                id, CO(sb->Finish()));
142
            fprintf(f, "#%d=VERTEX_POINT('',#%d);\n", id+1, id);
143
            thisFinish = id + 1;
144
            id += 2;
145
        } else {
146
            thisFinish = lastFinish;
147
        }
148

149
        fprintf(f, "#%d=EDGE_CURVE('',#%d,#%d,#%d,%s);\n",
150
            id, prevFinish, thisFinish, curveId, ".T.");
151
        fprintf(f, "#%d=ORIENTED_EDGE('',*,*,#%d,.T.);\n",
152
            id+1, id);
153

154
        int oe = id+1;
155
        listOfTrims.Add(&oe);
156
        id += 2;
157

158
        prevFinish = thisFinish;
159
    }
160

161
    fprintf(f, "#%d=EDGE_LOOP('',(", id);
162
    int *oe;
163
    for(oe = listOfTrims.First(); oe; oe = listOfTrims.NextAfter(oe)) {
164
        fprintf(f, "#%d", *oe);
165
        if(listOfTrims.NextAfter(oe) != NULL) fprintf(f, ",");
166
    }
167
    fprintf(f, "));\n");
168

169
    int fb = id + 1;
170
        fprintf(f, "#%d=%s('',#%d,.T.);\n",
171
            fb, inner ? "FACE_BOUND" : "FACE_OUTER_BOUND", id);
172

173
    id += 2;
174
    listOfTrims.Clear();
175

176
    return fb;
177
}
178

179
void StepFileWriter::ExportSurface(SSurface *ss, SBezierList *sbl) {
180
    int i, j, srfid = id;
181

182
    // First, we create the untrimmed surface. We always specify a rational
183
    // B-spline surface (in fact, just a Bezier surface).
184
    fprintf(f, "#%d=(\n", srfid);
185
    fprintf(f, "BOUNDED_SURFACE()\n");
186
    fprintf(f, "B_SPLINE_SURFACE(%d,%d,(", ss->degm, ss->degn);
187
    for(i = 0; i <= ss->degm; i++) {
188
        fprintf(f, "(");
189
        for(j = 0; j <= ss->degn; j++) {
190
            fprintf(f, "#%d", srfid + 1 + j + i*(ss->degn + 1));
191
            if(j != ss->degn) fprintf(f, ",");
192
        }
193
        fprintf(f, ")");
194
        if(i != ss->degm) fprintf(f, ",");
195
    }
196
    fprintf(f, "),.UNSPECIFIED.,.F.,.F.,.F.)\n");
197
    fprintf(f, "B_SPLINE_SURFACE_WITH_KNOTS((%d,%d),(%d,%d),",
198
        (ss->degm + 1), (ss->degm + 1),
199
        (ss->degn + 1), (ss->degn + 1));
200
    fprintf(f, "(0.000,1.000),(0.000,1.000),.UNSPECIFIED.)\n");
201
    fprintf(f, "GEOMETRIC_REPRESENTATION_ITEM()\n");
202
    fprintf(f, "RATIONAL_B_SPLINE_SURFACE((");
203
    for(i = 0; i <= ss->degm; i++) {
204
        fprintf(f, "(");
205
        for(j = 0; j <= ss->degn; j++) {
206
            fprintf(f, "%.10f", ss->weight[i][j]);
207
            if(j != ss->degn) fprintf(f, ",");
208
        }
209
        fprintf(f, ")");
210
        if(i != ss->degm) fprintf(f, ",");
211
    }
212
    fprintf(f, "))\n");
213
    fprintf(f, "REPRESENTATION_ITEM('')\n");
214
    fprintf(f, "SURFACE()\n");
215
    fprintf(f, ");\n");
216

217
    // The control points for the untrimmed surface.
218
    for(i = 0; i <= ss->degm; i++) {
219
        for(j = 0; j <= ss->degn; j++) {
220
            fprintf(f, "#%d=CARTESIAN_POINT('',(%.10f,%.10f,%.10f));\n",
221
                srfid + 1 + j + i*(ss->degn + 1),
222
                CO(ss->ctrl[i][j]));
223
        }
224
    }
225
    fprintf(f, "\n");
226

227
    id = srfid + 1 + (ss->degm + 1)*(ss->degn + 1);
228

229
    // Now we do the trim curves. We must group each outer loop separately
230
    // along with its inner faces, so do that now.
231
    SBezierLoopSetSet sblss = {};
232
    SPolygon spxyz = {};
233
    bool allClosed;
234
    SEdge notClosedAt;
235
    // We specify a surface, so it doesn't check for coplanarity; and we
236
    // don't want it to give us any open contours. The polygon and chord
237
    // tolerance are required, because they are used to calculate the
238
    // contour directions and determine inner vs. outer contours.
239
    sblss.FindOuterFacesFrom(sbl, &spxyz, ss,
240
                             SS.ExportChordTolMm(),
241
                             &allClosed, &notClosedAt,
242
                             NULL, NULL,
243
                             NULL);
244

245
    // So in our list of SBezierLoopSet, each set contains at least one loop
246
    // (the outer boundary), plus any inner loops associated with that outer
247
    // loop.
248
    SBezierLoopSet *sbls;
249
    for(sbls = sblss.l.First(); sbls; sbls = sblss.l.NextAfter(sbls)) {
250
        SBezierLoop *loop = sbls->l.First();
251

252
        List<int> listOfLoops = {};
253
        // Create the face outer boundary from the outer loop.
254
        int fob = ExportCurveLoop(loop, /*inner=*/false);
255
        listOfLoops.Add(&fob);
256

257
        // And create the face inner boundaries from any inner loops that
258
        // lie within this contour.
259
        loop = sbls->l.NextAfter(loop);
260
        for(; loop; loop = sbls->l.NextAfter(loop)) {
261
            int fib = ExportCurveLoop(loop, /*inner=*/true);
262
            listOfLoops.Add(&fib);
263
        }
264

265
        // And now create the face that corresponds to this outer loop
266
        // and all of its holes.
267
        int advFaceId = id;
268
        fprintf(f, "#%d=ADVANCED_FACE('',(", advFaceId);
269
        int *fb;
270
        for(fb = listOfLoops.First(); fb; fb = listOfLoops.NextAfter(fb)) {
271
            fprintf(f, "#%d", *fb);
272
            if(listOfLoops.NextAfter(fb) != NULL) fprintf(f, ",");
273
        }
274

275
        fprintf(f, "),#%d,.T.);\n", srfid);
276
        advancedFaces.Add(&advFaceId);
277

278
        // Export the surface color and transparency
279
        // https://www.cax-if.org/documents/rec_prac_styling_org_v16.pdf sections 4.4.2 4.2.4 etc.
280
        // https://tracker.dev.opencascade.org/view.php?id=31550
281
        fprintf(f, "#%d=COLOUR_RGB('',%.2f,%.2f,%.2f);\n", ++id, ss->color.redF(),
282
                ss->color.greenF(), ss->color.blueF());
283

284
/*      // This works in Kisters 3DViewStation but not in KiCAD and Horison EDA,
285
        // it seems they do not support transparency so use the more verbose one below
286
        fprintf(f, "#%d=SURFACE_STYLE_TRANSPARENT(%.2f);\n", ++id, 1.0 - ss->color.alphaF());
287
        ++id;
288
        fprintf(f, "#%d=SURFACE_STYLE_RENDERING_WITH_PROPERTIES(.NORMAL_SHADING.,#%d,(#%d));\n",
289
                id, id - 2, id - 1);
290
        ++id;
291
        fprintf(f, "#%d=SURFACE_SIDE_STYLE('',(#%d));\n", id, id - 1);
292
*/
293

294
        // This works in Horison EDA but is more verbose.
295
        ++id;
296
        fprintf(f, "#%d=FILL_AREA_STYLE_COLOUR('',#%d);\n", id, id - 1);
297
        ++id;
298
        fprintf(f, "#%d=FILL_AREA_STYLE('',(#%d));\n", id, id - 1);
299
        ++id;
300
        fprintf(f, "#%d=SURFACE_STYLE_FILL_AREA(#%d);\n", id, id - 1);
301
        fprintf(f, "#%d=SURFACE_STYLE_TRANSPARENT(%.2f);\n", ++id, 1.0 - ss->color.alphaF());
302
        ++id;
303
        fprintf(f, "#%d=SURFACE_STYLE_RENDERING_WITH_PROPERTIES(.NORMAL_SHADING.,#%d,(#%d));\n", id, id - 5, id - 1);
304
        ++id;
305
        fprintf(f, "#%d=SURFACE_SIDE_STYLE('',(#%d, #%d));\n", id, id - 3, id - 1);
306

307
        ++id;
308
        fprintf(f, "#%d=SURFACE_STYLE_USAGE(.BOTH.,#%d);\n", id, id - 1);
309
        ++id;
310
        fprintf(f, "#%d=PRESENTATION_STYLE_ASSIGNMENT((#%d));\n", id, id - 1);
311
        ++id;
312
        fprintf(f, "#%d=STYLED_ITEM('',(#%d),#%d);\n", id, id - 1, advFaceId);
313
        fprintf(f, "\n");        
314
        
315
        id++;
316
        listOfLoops.Clear();
317
    }
318
    sblss.Clear();
319
    spxyz.Clear();
320
}
321

322
void StepFileWriter::WriteFooter() {
323
    fprintf(f,
324
"\n"
325
"ENDSEC;\n"
326
"\n"
327
"END-ISO-10303-21;\n"
328
        );
329
}
330

331
void StepFileWriter::ExportSurfacesTo(const Platform::Path &filename) {
332
    Group *g = SK.GetGroup(SS.GW.activeGroup);
333
    SShell *shell = &(g->runningShell);
334

335
    if(shell->surface.IsEmpty()) {
336
        Error("The model does not contain any surfaces to export.%s",
337
              !g->runningMesh.l.IsEmpty()
338
                  ? "\n\nThe model does contain triangles from a mesh, but "
339
                    "a triangle mesh cannot be exported as a STEP file. Try "
340
                    "File -> Export Mesh... instead."
341
                  : "");
342
        return;
343
    }
344

345
    f = OpenFile(filename, "wb");
346
    if(!f) {
347
        Error("Couldn't write to '%s'", filename.raw.c_str());
348
        return;
349
    }
350

351
    WriteHeader();
352
	WriteProductHeader();
353

354
    advancedFaces = {};
355

356
    for(SSurface &ss : shell->surface) {
357
        if(ss.trim.IsEmpty())
358
            continue;
359

360
        // Get all of the loops of Beziers that trim our surface (with each
361
        // Bezier split so that we use the section as t goes from 0 to 1), and
362
        // the piecewise linearization of those loops in xyz space.
363
        SBezierList sbl = {};
364
        ss.MakeSectionEdgesInto(shell, NULL, &sbl);
365

366
        // Apply the export scale factor.
367
        ss.ScaleSelfBy(1.0/SS.exportScale);
368
        sbl.ScaleSelfBy(1.0/SS.exportScale);
369

370
        ExportSurface(&ss, &sbl);
371

372
        sbl.Clear();
373
    }
374

375
    fprintf(f, "#%d=CLOSED_SHELL('',(", id);
376
    int *af;
377
    for(af = advancedFaces.First(); af; af = advancedFaces.NextAfter(af)) {
378
        fprintf(f, "#%d", *af);
379
        if(advancedFaces.NextAfter(af) != NULL) fprintf(f, ",");
380
    }
381
    fprintf(f, "));\n");
382
    fprintf(f, "#%d=MANIFOLD_SOLID_BREP('brep',#%d);\n", id+1, id);
383
    fprintf(f, "#%d=ADVANCED_BREP_SHAPE_REPRESENTATION('',(#%d,#170),#168);\n",
384
        id+2, id+1);
385
    fprintf(f, "#%d=SHAPE_REPRESENTATION_RELATIONSHIP($,$,#169,#%d);\n",
386
        id+3, id+2);
387

388
    WriteFooter();
389

390
    fclose(f);
391
    advancedFaces.Clear();
392
}
393

394
void StepFileWriter::WriteWireframe() {
395
    fprintf(f, "#%d=GEOMETRIC_CURVE_SET('curves',(", id);
396
    int *c;
397
    for(c = curves.First(); c; c = curves.NextAfter(c)) {
398
        fprintf(f, "#%d", *c);
399
        if(curves.NextAfter(c) != NULL) fprintf(f, ",");
400
    }
401
    fprintf(f, "));\n");
402
    fprintf(f, "#%d=GEOMETRICALLY_BOUNDED_WIREFRAME_SHAPE_REPRESENTATION"
403
                    "('',(#%d,#170),#168);\n", id+1, id);
404
    fprintf(f, "#%d=SHAPE_REPRESENTATION_RELATIONSHIP($,$,#169,#%d);\n",
405
        id+2, id+1);
406

407
    id += 3;
408
    curves.Clear();
409
}
410

411

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.