From 837628ea3ea5135a52361a8415321df41f91a685 Mon Sep 17 00:00:00 2001 From: nabijaczleweli Date: Fri, 9 Aug 2019 21:08:54 +0200 Subject: [PATCH] Add VRML (WRL) triangle mesh export. Transparency is not supported. --- CHANGELOG.md | 1 + src/export.cpp | 101 +++++++++++++++++++++++++++++++++++++++++++ src/platform/gui.cpp | 1 + src/solvespace.h | 1 + 4 files changed, 104 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 932ff6d1..de34e97e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ New export/import features: exported. This format allows to easily hack on triangle mesh data created in SolveSpace, supports colour information and is more space efficient than most other formats. + * VRML (WRL) triangle meshes can now be exported, useful for e.g. [KiCAD](http://kicad.org). * Export 2d section: custom styled entities that lie in the same plane as the exported section are included. diff --git a/src/export.cpp b/src/export.cpp index 8e0d2f60..4300495c 100644 --- a/src/export.cpp +++ b/src/export.cpp @@ -849,6 +849,8 @@ void SolveSpaceUI::ExportMeshTo(const Platform::Path &filename) { filename.HasExtension("html")) { SOutlineList *e = &(SK.GetGroup(SS.GW.activeGroup)->displayOutlines); ExportMeshAsThreeJsTo(f, filename, m, e); + } else if(filename.HasExtension("wrl")) { + ExportMeshAsVrmlTo(f, filename, m); } else { Error("Can't identify output file type from file extension of " "filename '%s'; try .stl, .obj, .js, .html.", filename.raw.c_str()); @@ -1168,6 +1170,105 @@ void SolveSpaceUI::ExportMeshAsThreeJsTo(FILE *f, const Platform::Path &filename spl.Clear(); } +//----------------------------------------------------------------------------- +// Export the mesh as a VRML text file / WRL. +//----------------------------------------------------------------------------- +void SolveSpaceUI::ExportMeshAsVrmlTo(FILE *f, const Platform::Path &filename, SMesh *sm) { + std::string basename = filename.FileStem(); + for(auto & c : basename) { + if(!(isalnum(c) || ((unsigned)c >= 0x80))) { + c = '_'; + } + } + + fprintf(f, "#VRML V2.0 utf8\n" + "#Exported from SolveSpace %s\n" + "\n" + "DEF %s Transform {\n" + " children [\n" + " Shape {\n" + " appearance Appearance {\n" + " material DEF %s_material Material {\n" + " diffuseColor %f %f %f\n" + " ambientIntensity %f\n" + " transparency 0.0\n" + " }\n" + " }\n" + " geometry IndexedFaceSet {\n" + " colorPerVertex TRUE\n" + " coord Coordinate { point [\n", + PACKAGE_VERSION, + basename.c_str(), + basename.c_str(), + SS.ambientIntensity, + SS.ambientIntensity, + SS.ambientIntensity, + SS.ambientIntensity); + + SPointList spl = {}; + + for(const auto & tr : sm->l) { + spl.IncrementTagFor(tr.a); + spl.IncrementTagFor(tr.b); + spl.IncrementTagFor(tr.c); + } + + // Output all the vertices. + for(auto sp : spl.l) { + fprintf(f, " %f %f %f,\n", + sp.p.x / SS.exportScale, + sp.p.y / SS.exportScale, + sp.p.z / SS.exportScale); + } + + fputs(" ] }\n" + " coordIndex [\n", f); + // And now all the triangular faces, in terms of those vertices. + for(const auto & tr : sm->l) { + fprintf(f, " %d, %d, %d, -1,\n", + spl.IndexForPoint(tr.a), + spl.IndexForPoint(tr.b), + spl.IndexForPoint(tr.c)); + } + + fputs(" ]\n" + " color Color { color [\n", f); + // Output triangle colors. + std::vector triangle_colour_ids; + std::vector colours_present; + for(const auto & tr : sm->l) { + const auto colour_itr = std::find_if(colours_present.begin(), colours_present.end(), + [&](const RgbaColor & c) { + return c.Equals(tr.meta.color); + }); + if(colour_itr == colours_present.end()) { + fprintf(f, " %.10f %.10f %.10f,\n", + tr.meta.color.redF(), + tr.meta.color.greenF(), + tr.meta.color.blueF()); + triangle_colour_ids.push_back(colours_present.size()); + colours_present.insert(colours_present.end(), tr.meta.color); + } else { + triangle_colour_ids.push_back(colour_itr - colours_present.begin()); + } + } + + fputs(" ] }\n" + " colorIndex [\n", f); + + for(auto colour_idx : triangle_colour_ids) { + fprintf(f, " %d, %d, %d, -1,\n", colour_idx, colour_idx, colour_idx); + } + + fputs(" ]\n" + " }\n" + " }\n" + " ]\n" + "}\n", f); + + spl.Clear(); +} + //----------------------------------------------------------------------------- // Export a view of the model as an image; we just take a screenshot, by // rendering the view in the usual way and then copying the pixels. diff --git a/src/platform/gui.cpp b/src/platform/gui.cpp index e4475c7d..b86d2ecd 100644 --- a/src/platform/gui.cpp +++ b/src/platform/gui.cpp @@ -95,6 +95,7 @@ std::vector MeshFileFilters = { { CN_("file-type", "Three.js-compatible mesh, with viewer"), { "html" } }, { CN_("file-type", "Three.js-compatible mesh, mesh only"), { "js" } }, { CN_("file-type", "Q3D Object file"), { "q3do" } }, + { CN_("file-type", "VRML text file"), { "wrl" } }, }; std::vector SurfaceFileFilters = { diff --git a/src/solvespace.h b/src/solvespace.h index 6d2687b3..4f7f3879 100644 --- a/src/solvespace.h +++ b/src/solvespace.h @@ -698,6 +698,7 @@ public: void ExportMeshAsObjTo(FILE *fObj, FILE *fMtl, SMesh *sm); void ExportMeshAsThreeJsTo(FILE *f, const Platform::Path &filename, SMesh *sm, SOutlineList *sol); + void ExportMeshAsVrmlTo(FILE *f, const Platform::Path &filename, SMesh *sm); void ExportViewOrWireframeTo(const Platform::Path &filename, bool exportWireframe); void ExportSectionTo(const Platform::Path &filename); void ExportWireframeCurves(SEdgeList *sel, SBezierList *sbl,