
contours go with which outer contour) out of exportstep.cpp, since I'll need that to do filled contour export for the 2d file formats. Also add user interface to specify fill color. [git-p4: depot-paths = "//depot/solvespace/": change = 2057]
346 lines
10 KiB
C++
346 lines
10 KiB
C++
#include "solvespace.h"
|
|
|
|
void StepFileWriter::WriteHeader(void) {
|
|
fprintf(f,
|
|
"ISO-10303-21;\n"
|
|
"HEADER;\n"
|
|
"\n"
|
|
"FILE_DESCRIPTION((''), '2;1');\n"
|
|
"\n"
|
|
"FILE_NAME(\n"
|
|
" 'output_file',\n"
|
|
" '2009-06-07T17:44:47-07:00',\n"
|
|
" (''),\n"
|
|
" (''),\n"
|
|
" 'SolveSpace',\n"
|
|
" '',\n"
|
|
" ''\n"
|
|
");\n"
|
|
"\n"
|
|
"FILE_SCHEMA (('CONFIG_CONTROL_DESIGN'));\n"
|
|
"ENDSEC;\n"
|
|
"\n"
|
|
"DATA;\n"
|
|
"\n"
|
|
"/**********************************************************\n"
|
|
" * This defines the units and tolerances for the file. It\n"
|
|
" * is always the same, independent of the actual data.\n"
|
|
" **********************************************************/\n"
|
|
"#158=(\n"
|
|
"LENGTH_UNIT()\n"
|
|
"NAMED_UNIT(*)\n"
|
|
"SI_UNIT(.MILLI.,.METRE.)\n"
|
|
");\n"
|
|
"#161=(\n"
|
|
"NAMED_UNIT(*)\n"
|
|
"PLANE_ANGLE_UNIT()\n"
|
|
"SI_UNIT($,.RADIAN.)\n"
|
|
");\n"
|
|
"#166=(\n"
|
|
"NAMED_UNIT(*)\n"
|
|
"SI_UNIT($,.STERADIAN.)\n"
|
|
"SOLID_ANGLE_UNIT()\n"
|
|
");\n"
|
|
"#167=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.001),#158,\n"
|
|
"'DISTANCE_ACCURACY_VALUE',\n"
|
|
"'string');\n"
|
|
"#168=(\n"
|
|
"GEOMETRIC_REPRESENTATION_CONTEXT(3)\n"
|
|
"GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#167))\n"
|
|
"GLOBAL_UNIT_ASSIGNED_CONTEXT((#166,#161,#158))\n"
|
|
"REPRESENTATION_CONTEXT('ID1','3D')\n"
|
|
");\n"
|
|
"#169=SHAPE_REPRESENTATION('',(#170),#168);\n"
|
|
"#170=AXIS2_PLACEMENT_3D('',#173,#171,#172);\n"
|
|
"#171=DIRECTION('',(0.,0.,1.));\n"
|
|
"#172=DIRECTION('',(1.,0.,0.));\n"
|
|
"#173=CARTESIAN_POINT('',(0.,0.,0.));\n"
|
|
"\n"
|
|
);
|
|
|
|
// Start the ID somewhere beyond the header IDs.
|
|
id = 200;
|
|
}
|
|
|
|
int StepFileWriter::ExportCurve(SBezier *sb) {
|
|
int i, ret = id;
|
|
|
|
fprintf(f, "#%d=(\n", ret);
|
|
fprintf(f, "BOUNDED_CURVE()\n");
|
|
fprintf(f, "B_SPLINE_CURVE(%d,(", sb->deg);
|
|
for(i = 0; i <= sb->deg; i++) {
|
|
fprintf(f, "#%d", ret + i + 1);
|
|
if(i != sb->deg) fprintf(f, ",");
|
|
}
|
|
fprintf(f, "),.UNSPECIFIED.,.F.,.F.)\n");
|
|
fprintf(f, "B_SPLINE_CURVE_WITH_KNOTS((%d,%d),",
|
|
(sb->deg + 1), (sb-> deg + 1));
|
|
fprintf(f, "(0.000,1.000),.UNSPECIFIED.)\n");
|
|
fprintf(f, "CURVE()\n");
|
|
fprintf(f, "GEOMETRIC_REPRESENTATION_ITEM()\n");
|
|
fprintf(f, "RATIONAL_B_SPLINE_CURVE((");
|
|
for(i = 0; i <= sb->deg; i++) {
|
|
fprintf(f, "%.10f", sb->weight[i]);
|
|
if(i != sb->deg) fprintf(f, ",");
|
|
}
|
|
fprintf(f, "))\n");
|
|
fprintf(f, "REPRESENTATION_ITEM('')\n);\n");
|
|
|
|
for(i = 0; i <= sb->deg; i++) {
|
|
fprintf(f, "#%d=CARTESIAN_POINT('',(%.10f,%.10f,%.10f));\n",
|
|
id + 1 + i,
|
|
CO(sb->ctrl[i]));
|
|
}
|
|
fprintf(f, "\n");
|
|
|
|
id = ret + 1 + (sb->deg + 1);
|
|
return ret;
|
|
}
|
|
|
|
int StepFileWriter::ExportCurveLoop(SBezierLoop *loop, bool inner) {
|
|
if(loop->l.n < 1) oops();
|
|
|
|
List<int> listOfTrims;
|
|
ZERO(&listOfTrims);
|
|
|
|
SBezier *sb = &(loop->l.elem[loop->l.n - 1]);
|
|
|
|
// Generate "exactly closed" contours, with the same vertex id for the
|
|
// finish of a previous edge and the start of the next one. So we need
|
|
// the finish of the last Bezier in the loop before we start our process.
|
|
fprintf(f, "#%d=CARTESIAN_POINT('',(%.10f,%.10f,%.10f));\n",
|
|
id, CO(sb->Finish()));
|
|
fprintf(f, "#%d=VERTEX_POINT('',#%d);\n", id+1, id);
|
|
int lastFinish = id + 1, prevFinish = lastFinish;
|
|
id += 2;
|
|
|
|
for(sb = loop->l.First(); sb; sb = loop->l.NextAfter(sb)) {
|
|
int curveId = ExportCurve(sb);
|
|
|
|
int thisFinish;
|
|
if(loop->l.NextAfter(sb) != NULL) {
|
|
fprintf(f, "#%d=CARTESIAN_POINT('',(%.10f,%.10f,%.10f));\n",
|
|
id, CO(sb->Finish()));
|
|
fprintf(f, "#%d=VERTEX_POINT('',#%d);\n", id+1, id);
|
|
thisFinish = id + 1;
|
|
id += 2;
|
|
} else {
|
|
thisFinish = lastFinish;
|
|
}
|
|
|
|
fprintf(f, "#%d=EDGE_CURVE('',#%d,#%d,#%d,%s);\n",
|
|
id, prevFinish, thisFinish, curveId, ".T.");
|
|
fprintf(f, "#%d=ORIENTED_EDGE('',*,*,#%d,.T.);\n",
|
|
id+1, id);
|
|
|
|
int oe = id+1;
|
|
listOfTrims.Add(&oe);
|
|
id += 2;
|
|
|
|
prevFinish = thisFinish;
|
|
}
|
|
|
|
fprintf(f, "#%d=EDGE_LOOP('',(", id);
|
|
int *oe;
|
|
for(oe = listOfTrims.First(); oe; oe = listOfTrims.NextAfter(oe)) {
|
|
fprintf(f, "#%d", *oe);
|
|
if(listOfTrims.NextAfter(oe) != NULL) fprintf(f, ",");
|
|
}
|
|
fprintf(f, "));\n");
|
|
|
|
int fb = id + 1;
|
|
fprintf(f, "#%d=%s('',#%d,.T.);\n",
|
|
fb, inner ? "FACE_BOUND" : "FACE_OUTER_BOUND", id);
|
|
|
|
id += 2;
|
|
listOfTrims.Clear();
|
|
|
|
return fb;
|
|
}
|
|
|
|
void StepFileWriter::ExportSurface(SSurface *ss, SBezierList *sbl) {
|
|
int i, j, srfid = id;
|
|
|
|
// First, we create the untrimmed surface. We always specify a rational
|
|
// B-spline surface (in fact, just a Bezier surface).
|
|
fprintf(f, "#%d=(\n", srfid);
|
|
fprintf(f, "BOUNDED_SURFACE()\n");
|
|
fprintf(f, "B_SPLINE_SURFACE(%d,%d,(", ss->degm, ss->degn);
|
|
for(i = 0; i <= ss->degm; i++) {
|
|
fprintf(f, "(");
|
|
for(j = 0; j <= ss->degn; j++) {
|
|
fprintf(f, "#%d", srfid + 1 + j + i*(ss->degn + 1));
|
|
if(j != ss->degn) fprintf(f, ",");
|
|
}
|
|
fprintf(f, ")");
|
|
if(i != ss->degm) fprintf(f, ",");
|
|
}
|
|
fprintf(f, "),.UNSPECIFIED.,.F.,.F.,.F.)\n");
|
|
fprintf(f, "B_SPLINE_SURFACE_WITH_KNOTS((%d,%d),(%d,%d),",
|
|
(ss->degm + 1), (ss->degm + 1),
|
|
(ss->degn + 1), (ss->degn + 1));
|
|
fprintf(f, "(0.000,1.000),(0.000,1.000),.UNSPECIFIED.)\n");
|
|
fprintf(f, "GEOMETRIC_REPRESENTATION_ITEM()\n");
|
|
fprintf(f, "RATIONAL_B_SPLINE_SURFACE((");
|
|
for(i = 0; i <= ss->degm; i++) {
|
|
fprintf(f, "(");
|
|
for(j = 0; j <= ss->degn; j++) {
|
|
fprintf(f, "%.10f", ss->weight[i][j]);
|
|
if(j != ss->degn) fprintf(f, ",");
|
|
}
|
|
fprintf(f, ")");
|
|
if(i != ss->degm) fprintf(f, ",");
|
|
}
|
|
fprintf(f, "))\n");
|
|
fprintf(f, "REPRESENTATION_ITEM('')\n");
|
|
fprintf(f, "SURFACE()\n");
|
|
fprintf(f, ");\n");
|
|
|
|
// The control points for the untrimmed surface.
|
|
for(i = 0; i <= ss->degm; i++) {
|
|
for(j = 0; j <= ss->degn; j++) {
|
|
fprintf(f, "#%d=CARTESIAN_POINT('',(%.10f,%.10f,%.10f));\n",
|
|
srfid + 1 + j + i*(ss->degn + 1),
|
|
CO(ss->ctrl[i][j]));
|
|
}
|
|
}
|
|
fprintf(f, "\n");
|
|
|
|
id = srfid + 1 + (ss->degm + 1)*(ss->degn + 1);
|
|
|
|
// Now we do the trim curves. We must group each outer loop separately
|
|
// along with its inner faces, so do that now.
|
|
SBezierLoopSetSet sblss;
|
|
ZERO(&sblss);
|
|
sblss.FindOuterFacesFrom(sbl, ss);
|
|
|
|
// So in our list of SBezierLoopSet, each set contains at least one loop
|
|
// (the outer boundary), plus any inner loops associated with that outer
|
|
// loop.
|
|
SBezierLoopSet *sbls;
|
|
for(sbls = sblss.l.First(); sbls; sbls = sblss.l.NextAfter(sbls)) {
|
|
SBezierLoop *loop = sbls->l.First();
|
|
|
|
List<int> listOfLoops;
|
|
ZERO(&listOfLoops);
|
|
// Create the face outer boundary from the outer loop.
|
|
int fob = ExportCurveLoop(loop, false);
|
|
listOfLoops.Add(&fob);
|
|
|
|
// And create the face inner boundaries from any inner loops that
|
|
// lie within this contour.
|
|
loop = sbls->l.NextAfter(loop);
|
|
for(; loop; loop = sbls->l.NextAfter(loop)) {
|
|
int fib = ExportCurveLoop(loop, true);
|
|
listOfLoops.Add(&fib);
|
|
}
|
|
|
|
// And now create the face that corresponds to this outer loop
|
|
// and all of its holes.
|
|
int advFaceId = id;
|
|
fprintf(f, "#%d=ADVANCED_FACE('',(", advFaceId);
|
|
int *fb;
|
|
for(fb = listOfLoops.First(); fb; fb = listOfLoops.NextAfter(fb)) {
|
|
fprintf(f, "#%d", *fb);
|
|
if(listOfLoops.NextAfter(fb) != NULL) fprintf(f, ",");
|
|
}
|
|
|
|
fprintf(f, "),#%d,.T.);\n", srfid);
|
|
fprintf(f, "\n");
|
|
advancedFaces.Add(&advFaceId);
|
|
|
|
id++;
|
|
listOfLoops.Clear();
|
|
}
|
|
sblss.Clear();
|
|
}
|
|
|
|
void StepFileWriter::WriteFooter(void) {
|
|
fprintf(f,
|
|
"\n"
|
|
"ENDSEC;\n"
|
|
"\n"
|
|
"END-ISO-10303-21;\n"
|
|
);
|
|
}
|
|
|
|
void StepFileWriter::ExportSurfacesTo(char *file) {
|
|
Group *g = SK.GetGroup(SS.GW.activeGroup);
|
|
SShell *shell = &(g->runningShell);
|
|
|
|
if(shell->surface.n == 0) {
|
|
Error("The model does not contain any surfaces to export.%s",
|
|
g->runningMesh.l.n > 0 ?
|
|
"\r\n\r\nThe model does contain triangles from a mesh, but "
|
|
"a triangle mesh cannot be exported as a STEP file. Try "
|
|
"File -> Export Mesh... instead." : "");
|
|
return;
|
|
}
|
|
|
|
f = fopen(file, "wb");
|
|
if(!f) {
|
|
Error("Couldn't write to '%s'", file);
|
|
return;
|
|
}
|
|
|
|
WriteHeader();
|
|
|
|
ZERO(&advancedFaces);
|
|
|
|
SSurface *ss;
|
|
for(ss = shell->surface.First(); ss; ss = shell->surface.NextAfter(ss)) {
|
|
if(ss->trim.n == 0) continue;
|
|
|
|
// Get all of the loops of Beziers that trim our surface (with each
|
|
// Bezier split so that we use the section as t goes from 0 to 1), and
|
|
// the piecewise linearization of those loops in xyz space.
|
|
SBezierList sbl;
|
|
ZERO(&sbl);
|
|
ss->MakeSectionEdgesInto(shell, NULL, &sbl);
|
|
|
|
// Apply the export scale factor.
|
|
ss->ScaleSelfBy(1.0/SS.exportScale);
|
|
sbl.ScaleSelfBy(1.0/SS.exportScale);
|
|
|
|
ExportSurface(ss, &sbl);
|
|
|
|
sbl.Clear();
|
|
}
|
|
|
|
fprintf(f, "#%d=CLOSED_SHELL('',(", id);
|
|
int *af;
|
|
for(af = advancedFaces.First(); af; af = advancedFaces.NextAfter(af)) {
|
|
fprintf(f, "#%d", *af);
|
|
if(advancedFaces.NextAfter(af) != NULL) fprintf(f, ",");
|
|
}
|
|
fprintf(f, "));\n");
|
|
fprintf(f, "#%d=MANIFOLD_SOLID_BREP('brep',#%d);\n", id+1, id);
|
|
fprintf(f, "#%d=ADVANCED_BREP_SHAPE_REPRESENTATION('',(#%d,#170),#168);\n",
|
|
id+2, id+1);
|
|
fprintf(f, "#%d=SHAPE_REPRESENTATION_RELATIONSHIP($,$,#169,#%d);\n",
|
|
id+3, id+2);
|
|
|
|
WriteFooter();
|
|
|
|
fclose(f);
|
|
advancedFaces.Clear();
|
|
}
|
|
|
|
void StepFileWriter::WriteWireframe(void) {
|
|
fprintf(f, "#%d=GEOMETRIC_CURVE_SET('curves',(", id);
|
|
int *c;
|
|
for(c = curves.First(); c; c = curves.NextAfter(c)) {
|
|
fprintf(f, "#%d", *c);
|
|
if(curves.NextAfter(c) != NULL) fprintf(f, ",");
|
|
}
|
|
fprintf(f, "));\n");
|
|
fprintf(f, "#%d=GEOMETRICALLY_BOUNDED_WIREFRAME_SHAPE_REPRESENTATION"
|
|
"('',(#%d,#170),#168);\n", id+1, id);
|
|
fprintf(f, "#%d=SHAPE_REPRESENTATION_RELATIONSHIP($,$,#169,#%d);\n",
|
|
id+2, id+1);
|
|
|
|
id += 3;
|
|
curves.Clear();
|
|
}
|
|
|