diff --git a/Makefile b/Makefile index a68318d..4522cbc 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,7 @@ SSOBJS = $(OBJDIR)\solvespace.obj \ $(OBJDIR)\ttf.obj \ $(OBJDIR)\generate.obj \ $(OBJDIR)\export.obj \ + $(OBJDIR)\exportstep.obj \ SRFOBJS = $(OBJDIR)\ratpoly.obj \ $(OBJDIR)\curve.obj \ diff --git a/exportstep.cpp b/exportstep.cpp new file mode 100644 index 0000000..8cd4f99 --- /dev/null +++ b/exportstep.cpp @@ -0,0 +1,243 @@ +#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" + ); +} + +int StepFileWriter::ExportCurve(SBezier *sb) { + int i, ret = id; + + fprintf(f, "#%d=B_SPLINE_CURVE_WITH_KNOTS('',%d,(", + ret, sb->deg, (sb->deg + 1), (sb->deg + 1)); + for(i = 0; i <= sb->deg; i++) { + fprintf(f, "#%d", ret + i + 1); + if(i != sb->deg) fprintf(f, ","); + } + fprintf(f, "),.UNSPECIFIED.,.F.,.F.,(%d, %d),", + (sb->deg + 1), (sb-> deg + 1)); + fprintf(f, "(0.000,1.000),.UNSPECIFIED.);\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::ExportSurface(SSurface *ss) { + int i, j, srfid = id; + + fprintf(f, "#%d=B_SPLINE_SURFACE_WITH_KNOTS('',%d,%d,(", + srfid, 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.,(%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"); + + 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); + + SBezierList sbl; + SPolygon sp; + ZERO(&sbl); + ZERO(&sp); + SEdge errorAt; + bool allClosed; + ss->MakeSectionEdgesInto(shell, NULL, &sbl); + SBezierLoopSet sbls = SBezierLoopSet::From(&sbl, &sp, &allClosed, &errorAt); + + List listOfLoops; + ZERO(&listOfLoops); + + SBezierLoop *loop; + for(loop = sbls.l.First(); loop; loop = sbls.l.NextAfter(loop)) { + List listOfTrims; + ZERO(&listOfTrims); + + SBezier *sb; + for(sb = loop->l.First(); sb; sb = loop->l.NextAfter(sb)) { + int curveId = ExportCurve(sb); + + fprintf(f, "#%d=CARTESIAN_POINT('',(%.10f,%.10f,%.10f));\n", + id, CO(sb->Start())); + fprintf(f, "#%d=VERTEX_POINT('',#%d);\n", id+1, id); + fprintf(f, "#%d=CARTESIAN_POINT('',(%.10f,%.10f,%.10f));\n", + id+2, CO(sb->Finish())); + fprintf(f, "#%d=VERTEX_POINT('',#%d);\n", id+3, id+2); + fprintf(f, "#%d=EDGE_CURVE('',#%d,#%d,#%d,%s);\n", + id+4, id+1, id+3, curveId, ".T."); + fprintf(f, "#%d=ORIENTED_EDGE('',*,*,#%d,.T.);\n", + id+5, id+4); + + i = id+5; + listOfTrims.Add(&i); + + id += 6; + } + + fprintf(f, "#%d=EDGE_LOOP('',(", id); + int *ei; + for(ei = listOfTrims.First(); ei; ei = listOfTrims.NextAfter(ei)) { + fprintf(f, "#%d", *ei); + if(listOfTrims.NextAfter(ei) != NULL) fprintf(f, ","); + } + fprintf(f, "));\n"); + + int fb = id + 1; + fprintf(f, "#%d=FACE_OUTER_BOUND('',#%d,.T.);\n", fb, id); + listOfLoops.Add(&fb); + + id += 2; + listOfTrims.Clear(); + } + + 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"); + + id++; + + listOfLoops.Clear(); + return advFaceId; +} + +void StepFileWriter::ExportTo(char *file) { + Group *g = SK.GetGroup(SS.GW.activeGroup); + 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\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(); + + id = 200; + + List ls; + ZERO(&ls); + + SSurface *ss; + for(ss = shell->surface.First(); ss; ss = shell->surface.NextAfter(ss)) { + if(ss->trim.n == 0) continue; + + int sid = ExportSurface(ss); + ls.Add(&sid); + } + + fprintf(f, "#%d=CLOSED_SHELL('',(", id); + int *es; + for(es = ls.First(); es; es = ls.NextAfter(es)) { + fprintf(f, "#%d", *es); + if(ls.NextAfter(es) != NULL) fprintf(f, ","); + } + fprintf(f, "));\n"); + fprintf(f, "#%d=MANIFOLD_SOLID_BREP('brep_1',#%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); + + fprintf(f, +"\n" +"ENDSEC;\n" +"\n" +"END-ISO-10303-21;\n" + ); + + fclose(f); + ls.Clear(); +} + diff --git a/graphicswin.cpp b/graphicswin.cpp index 97e3274..3d3dd4c 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -22,7 +22,8 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = { { 1, "Export &Image...", MNU_EXPORT_PNG, 0, mFile }, { 1, "Export 2d &View...", MNU_EXPORT_VIEW, 0, mFile }, { 1, "Export 2d &Section...", MNU_EXPORT_SECTION, 0, mFile }, -{ 1, "Export &Mesh...", MNU_EXPORT_MESH, 0, mFile }, +{ 1, "Export Triangle &Mesh...", MNU_EXPORT_MESH, 0, mFile }, +{ 1, "Export &Surfaces...", MNU_EXPORT_SURFACES,0, mFile }, { 1, NULL, 0, 0, NULL }, { 1, "E&xit", MNU_EXIT, 0, mFile }, diff --git a/solvespace.cpp b/solvespace.cpp index 0d9b995..4a0585c 100644 --- a/solvespace.cpp +++ b/solvespace.cpp @@ -380,6 +380,15 @@ void SolveSpace::MenuFile(int id) { break; } + case GraphicsWindow::MNU_EXPORT_SURFACES: { + char exportFile[MAX_PATH] = ""; + if(!GetSaveFile(exportFile, SRF_EXT, SRF_PATTERN)) break; + StepFileWriter sfw; + ZERO(&sfw); + sfw.ExportTo(exportFile); + break; + } + case GraphicsWindow::MNU_EXIT: if(!SS.OkayToStartNewFile()) break; SS.Exit(); diff --git a/solvespace.h b/solvespace.h index 8a60a79..2de289e 100644 --- a/solvespace.h +++ b/solvespace.h @@ -80,6 +80,9 @@ int SaveFileYesNoCancel(void); #define PNG_EXT "png" #define STL_PATTERN "STL Mesh (*.stl)\0*.stl\0All Files (*)\0*\0\0" #define STL_EXT "stl" +#define SRF_PATTERN "STEP File (*.step;*.stp)\0*.step;*.stp\0" \ + "All Files(*)\0*\0\0" +#define SRF_EXT "step" #define VEC_PATTERN "DXF File (*.dxf)\0*.dxf\0" \ "Encapsulated PostScript (*.eps;*.ps)\0*.eps;*.ps\0" \ "PDF File (*.pdf)\0*.pdf\0" \ @@ -422,6 +425,18 @@ public: void FinishAndCloseFile(void); }; +class StepFileWriter { +public: + void ExportTo(char *filename); + void WriteHeader(void); + int ExportCurve(SBezier *sb); + int ExportSurface(SSurface *ss); + + SShell *shell; + FILE *f; + int id; +}; + #ifdef LIBRARY # define ENTITY EntityBase # define CONSTRAINT ConstraintBase diff --git a/srf/surface.cpp b/srf/surface.cpp index 20fa20e..05ca22a 100644 --- a/srf/surface.cpp +++ b/srf/surface.cpp @@ -274,7 +274,7 @@ void SSurface::MakeSectionEdgesInto(SShell *shell, SCurve *sc = shell->curve.FindById(stb->curve); SBezier *sb = &(sc->exact); - if(sbl && sc->isExact && sb->deg != 1) { + if(sbl && sc->isExact && (sb->deg != 1 || !sel)) { double ts, tf; if(stb->backwards) { sb->ClosestPointTo(stb->start, &tf); @@ -294,7 +294,7 @@ void SSurface::MakeSectionEdgesInto(SShell *shell, sbl->l.Add(&keep_bef); } else { - MakeTrimEdgesInto(sel, false, sc, stb); + if(sel) MakeTrimEdgesInto(sel, false, sc, stb); } } } diff --git a/ui.h b/ui.h index ffa05c4..0594961 100644 --- a/ui.h +++ b/ui.h @@ -185,6 +185,7 @@ public: MNU_SAVE_AS, MNU_EXPORT_PNG, MNU_EXPORT_MESH, + MNU_EXPORT_SURFACES, MNU_EXPORT_VIEW, MNU_EXPORT_SECTION, MNU_EXIT,