From f6bb6809782d7b8f21d6953fd01c654af344fdba Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Mon, 12 Oct 2009 03:34:43 -0800 Subject: [PATCH] Add Wavefront OBJ support, to supplement the existing STL mesh export. That doesn't seem very useful, but it's only a few dozen lines of code. [git-p4: depot-paths = "//depot/solvespace/": change = 2054] --- export.cpp | 75 +++++++++++++++++++++++++++++++++++++------------- polygon.cpp | 14 +++++++--- polygon.h | 1 + solvespace.cpp | 2 +- solvespace.h | 10 +++++-- util.cpp | 14 ++++++++++ 6 files changed, 89 insertions(+), 27 deletions(-) diff --git a/export.cpp b/export.cpp index 38b8d09..1b05e94 100644 --- a/export.cpp +++ b/export.cpp @@ -340,19 +340,6 @@ double VectorFileWriter::MmToPts(double mm) { return (mm/25.4)*72; } -bool VectorFileWriter::StringEndsIn(char *str, char *ending) { - int i, ls = strlen(str), le = strlen(ending); - - if(ls < le) return false; - - for(i = 0; i < le; i++) { - if(tolower(ending[le-i-1]) != tolower(str[ls-i-1])) { - return false; - } - } - return true; -} - VectorFileWriter *VectorFileWriter::ForFile(char *filename) { VectorFileWriter *ret; if(StringEndsIn(filename, ".dxf")) { @@ -552,8 +539,7 @@ void VectorFileWriter::BezierAsNonrationalCubic(DWORD rgb, double width, } //----------------------------------------------------------------------------- -// Export the mesh as an STL file; it should always be vertex-to-vertex and -// not self-intersecting, so not much to do. +// Export a triangle mesh, in the requested format. //----------------------------------------------------------------------------- void SolveSpace::ExportMeshTo(char *filename) { SMesh *m = &(SK.GetGroup(SS.GW.activeGroup)->displayMesh); @@ -567,18 +553,36 @@ void SolveSpace::ExportMeshTo(char *filename) { Error("Couldn't write to '%s'", filename); return; } + + if(StringEndsIn(filename, ".stl")) { + ExportMeshAsStlTo(f, m); + } else if(StringEndsIn(filename, ".obj")) { + ExportMeshAsObjTo(f, m); + } else { + Error("Can't identify output file type from file extension of " + "filename '%s'; try .stl, .obj.", filename); + } + + fclose(f); +} + +//----------------------------------------------------------------------------- +// Export the mesh as an STL file; it should always be vertex-to-vertex and +// not self-intersecting, so not much to do. +//----------------------------------------------------------------------------- +void SolveSpace::ExportMeshAsStlTo(FILE *f, SMesh *sm) { char str[80]; memset(str, 0, sizeof(str)); strcpy(str, "STL exported mesh"); fwrite(str, 1, 80, f); - DWORD n = m->l.n; + DWORD n = sm->l.n; fwrite(&n, 4, 1, f); double s = SS.exportScale; int i; - for(i = 0; i < m->l.n; i++) { - STriangle *tr = &(m->l.elem[i]); + for(i = 0; i < sm->l.n; i++) { + STriangle *tr = &(sm->l.elem[i]); Vector n = tr->Normal().WithMagnitude(1); float w; w = (float)n.x; fwrite(&w, 4, 1, f); @@ -596,8 +600,41 @@ void SolveSpace::ExportMeshTo(char *filename) { fputc(0, f); fputc(0, f); } +} - fclose(f); +//----------------------------------------------------------------------------- +// Export the mesh as Wavefront OBJ format. This requires us to reduce all the +// identical vertices to the same identifier, so do that first. +//----------------------------------------------------------------------------- +void SolveSpace::ExportMeshAsObjTo(FILE *f, SMesh *sm) { + SPointList spl; + ZERO(&spl); + STriangle *tr; + for(tr = sm->l.First(); tr; tr = sm->l.NextAfter(tr)) { + spl.IncrementTagFor(tr->a); + spl.IncrementTagFor(tr->b); + spl.IncrementTagFor(tr->c); + } + + // Output all the vertices. + SPoint *sp; + for(sp = spl.l.First(); sp; sp = spl.l.NextAfter(sp)) { + fprintf(f, "v %.10f %.10f %.10f\r\n", + sp->p.x / SS.exportScale, + sp->p.y / SS.exportScale, + sp->p.z / SS.exportScale); + } + + // And now all the triangular faces, in terms of those vertices. The + // file format counts from 1, not 0. + for(tr = sm->l.First(); tr; tr = sm->l.NextAfter(tr)) { + fprintf(f, "f %d %d %d\r\n", + spl.IndexForPoint(tr->a) + 1, + spl.IndexForPoint(tr->b) + 1, + spl.IndexForPoint(tr->c) + 1); + } + + spl.Clear(); } //----------------------------------------------------------------------------- diff --git a/polygon.cpp b/polygon.cpp index 9a6eba3..8e99db6 100644 --- a/polygon.cpp +++ b/polygon.cpp @@ -313,13 +313,19 @@ void SPointList::Clear(void) { } bool SPointList::ContainsPoint(Vector pt) { - SPoint *p; - for(p = l.First(); p; p = l.NextAfter(p)) { + return (IndexForPoint(pt) >= 0); +} + +int SPointList::IndexForPoint(Vector pt) { + int i; + for(i = 0; i < l.n; i++) { + SPoint *p = &(l.elem[i]); if(pt.Equals(p->p)) { - return true; + return i; } } - return false; + // Not found, so return negative to indicate that. + return -1; } void SPointList::IncrementTagFor(Vector pt) { diff --git a/polygon.h b/polygon.h index f0863c4..790f6df 100644 --- a/polygon.h +++ b/polygon.h @@ -53,6 +53,7 @@ public: void Clear(void); bool ContainsPoint(Vector pt); + int IndexForPoint(Vector pt); void IncrementTagFor(Vector pt); void Add(Vector pt); }; diff --git a/solvespace.cpp b/solvespace.cpp index 0cfbdcc..377e9f9 100644 --- a/solvespace.cpp +++ b/solvespace.cpp @@ -435,7 +435,7 @@ void SolveSpace::MenuFile(int id) { case GraphicsWindow::MNU_EXPORT_MESH: { char exportFile[MAX_PATH] = ""; - if(!GetSaveFile(exportFile, STL_EXT, STL_PATTERN)) break; + if(!GetSaveFile(exportFile, MESH_EXT, MESH_PATTERN)) break; SS.ExportMeshTo(exportFile); break; } diff --git a/solvespace.h b/solvespace.h index ceadee5..9d615fd 100644 --- a/solvespace.h +++ b/solvespace.h @@ -82,8 +82,10 @@ int SaveFileYesNoCancel(void); #define PNG_PATTERN "PNG (*.png)\0*.png\0All Files (*)\0*\0\0" #define PNG_EXT "png" // Triangle mesh -#define STL_PATTERN "STL Mesh (*.stl)\0*.stl\0All Files (*)\0*\0\0" -#define STL_EXT "stl" +#define MESH_PATTERN "STL Mesh (*.stl)\0*.stl\0" \ + "Wavefront OBJ Mesh (*.obj)\0*.obj\0" \ + "All Files (*)\0*\0\0" +#define MESH_EXT "stl" // NURBS surfaces #define SRF_PATTERN "STEP File (*.step;*.stp)\0*.step;*.stp\0" \ "All Files(*)\0*\0\0" @@ -228,6 +230,7 @@ void MakeMatrix(double *mat, double a11, double a12, double a13, double a14, void MakePathRelative(char *base, char *path); void MakePathAbsolute(char *base, char *path); bool StringAllPrintable(char *str); +bool StringEndsIn(char *str, char *ending); class System { public: @@ -406,7 +409,6 @@ public: Vector ptMin, ptMax; static double MmToPts(double mm); - static bool StringEndsIn(char *str, char *ending); static VectorFileWriter *ForFile(char *file); @@ -629,6 +631,8 @@ public: // And the various export options void ExportAsPngTo(char *file); void ExportMeshTo(char *file); + void ExportMeshAsStlTo(FILE *f, SMesh *sm); + void ExportMeshAsObjTo(FILE *f, SMesh *sm); void ExportViewOrWireframeTo(char *file, bool wireframe); void ExportSectionTo(char *file); void ExportWireframeCurves(SEdgeList *sel, SBezierList *sbl, diff --git a/util.cpp b/util.cpp index bfa207c..fa76bcf 100644 --- a/util.cpp +++ b/util.cpp @@ -88,6 +88,20 @@ bool StringAllPrintable(char *str) return true; } +bool StringEndsIn(char *str, char *ending) +{ + int i, ls = strlen(str), le = strlen(ending); + + if(ls < le) return false; + + for(i = 0; i < le; i++) { + if(tolower(ending[le-i-1]) != tolower(str[ls-i-1])) { + return false; + } + } + return true; +} + void MakeMatrix(double *mat, double a11, double a12, double a13, double a14, double a21, double a22, double a23, double a24, double a31, double a32, double a33, double a34,