From efca4891d1ae67a4e585de88acd35f5b95d2e5c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Hon?= Date: Tue, 4 Apr 2023 19:19:35 +0200 Subject: [PATCH] Add JS bindings for triangulation (#393) * js binding for triangulation * don't use CrossSection class as it alters the order of the vertices * remove unused code, rename original Triangulate to TriangulateIdx, move TriangulateJS from bindings.cpp to polygon.cpp, rename TrinagulateJS to Triangulate for consistent C++ and JS API, add optional precision parameter --- bindings/wasm/CMakeLists.txt | 2 +- bindings/wasm/bindings.cpp | 2 ++ bindings/wasm/bindings.js | 7 +++++ .../wasm/manifold-encapsulated-types.d.ts | 10 +++++++ bindings/wasm/manifold.d.ts | 1 + src/manifold/src/constructors.cpp | 2 +- src/manifold/src/face_op.cpp | 2 +- src/polygon/include/polygon.h | 7 +++-- src/polygon/src/polygon.cpp | 26 ++++++++++++++++++- test/polygon_test.cpp | 6 ++--- 10 files changed, 56 insertions(+), 9 deletions(-) diff --git a/bindings/wasm/CMakeLists.txt b/bindings/wasm/CMakeLists.txt index 35966cc91..5ec57a18e 100644 --- a/bindings/wasm/CMakeLists.txt +++ b/bindings/wasm/CMakeLists.txt @@ -19,7 +19,7 @@ add_executable(manifoldjs bindings.cpp) # make sure that we recompile the wasm when bindings.js is being modified set_source_files_properties(bindings.cpp OBJECT_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bindings.js) -target_link_libraries(manifoldjs manifold sdf cross_section) +target_link_libraries(manifoldjs manifold sdf cross_section polygon) target_compile_options(manifoldjs PRIVATE ${MANIFOLD_FLAGS} -fexceptions) target_link_options(manifoldjs PUBLIC --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/bindings.js --bind -sALLOW_TABLE_GROWTH=1 -sEXPORTED_RUNTIME_METHODS=addFunction,removeFunction -sMODULARIZE=1 -sEXPORT_ES6=1) diff --git a/bindings/wasm/bindings.cpp b/bindings/wasm/bindings.cpp index 8747d8b53..ccb9dde6f 100644 --- a/bindings/wasm/bindings.cpp +++ b/bindings/wasm/bindings.cpp @@ -20,6 +20,7 @@ using namespace emscripten; #include +#include #include using namespace manifold; @@ -266,6 +267,7 @@ EMSCRIPTEN_BINDINGS(whatever) { function("tetrahedron", &Manifold::Tetrahedron); function("_Smooth", &Smooth); function("_Extrude", &Extrude); + function("_Triangulate", &Triangulate); function("_Revolve", &Revolve); function("_LevelSet", &LevelSetJs); diff --git a/bindings/wasm/bindings.js b/bindings/wasm/bindings.js index f29b3b3cc..fc77fd844 100644 --- a/bindings/wasm/bindings.js +++ b/bindings/wasm/bindings.js @@ -302,6 +302,13 @@ Module.setup = function() { return result; }; + Module.triangulate = function(polygons, precision = -1) { + const polygonsVec = polygons2vec(polygons); + const result = fromVec(Module._Triangulate(polygonsVec, precision), (x) => [x[0], x[1], x[2]]); + disposePolygons(polygonsVec); + return result; + } + Module.revolve = function(polygons, circularSegments = 0) { const polygonsVec = polygons2vec(polygons); const result = Module._Revolve(polygonsVec, circularSegments); diff --git a/bindings/wasm/manifold-encapsulated-types.d.ts b/bindings/wasm/manifold-encapsulated-types.d.ts index f8d481af9..0e75ca9c0 100644 --- a/bindings/wasm/manifold-encapsulated-types.d.ts +++ b/bindings/wasm/manifold-encapsulated-types.d.ts @@ -108,6 +108,16 @@ export function extrude( crossSection: Polygons, height: number, nDivisions?: number, twistDegrees?: number, scaleTop?: Vec2): Manifold; +/** + * Triangulates a set of /epsilon-valid polygons. + * + * @param polygons The set of polygons, wound CCW and representing multiple + * polygons and/or holes. + * @param precision The value of epsilon, bounding the uncertainty of the input + * @return The triangles, referencing the original polygon points in order. + */ +export function triangulate(polygons: Polygons, precision?: number): Vec3[]; + /** * Constructs a manifold from a set of polygons by revolving this cross-section * around its Y-axis and then setting this as the Z-axis of the resulting diff --git a/bindings/wasm/manifold.d.ts b/bindings/wasm/manifold.d.ts index 04fd612f4..03db96088 100644 --- a/bindings/wasm/manifold.d.ts +++ b/bindings/wasm/manifold.d.ts @@ -25,6 +25,7 @@ export interface ManifoldStatic { smooth: typeof T.smooth; tetrahedron: typeof T.tetrahedron; extrude: typeof T.extrude; + triangulate: typeof T.triangulate; revolve: typeof T.revolve; union: typeof T.union; difference: typeof T.difference; diff --git a/src/manifold/src/constructors.cpp b/src/manifold/src/constructors.cpp index 9243bdef6..ed5d484ed 100644 --- a/src/manifold/src/constructors.cpp +++ b/src/manifold/src/constructors.cpp @@ -293,7 +293,7 @@ Manifold Manifold::Extrude(const CrossSection& crossSection, float height, if (isCone) for (int j = 0; j < polygons.size(); ++j) // Duplicate vertex for Genus vertPos.push_back({0.0f, 0.0f, height}); - std::vector top = Triangulate(polygonsIndexed); + std::vector top = TriangulateIdx(polygonsIndexed); for (const glm::ivec3& tri : top) { triVerts.push_back({tri[0], tri[2], tri[1]}); if (!isCone) triVerts.push_back(tri + nCrossSection * nDivisions); diff --git a/src/manifold/src/face_op.cpp b/src/manifold/src/face_op.cpp index 0a148cbec..0437ad39a 100644 --- a/src/manifold/src/face_op.cpp +++ b/src/manifold/src/face_op.cpp @@ -121,7 +121,7 @@ void Manifold::Impl::Face2Tri(const VecDH& faceEdge, const PolygonsIdx polys = Face2Polygons(face, projection, faceEdge); - std::vector newTris = Triangulate(polys, precision_); + std::vector newTris = TriangulateIdx(polys, precision_); for (auto tri : newTris) { triVerts.push_back(tri); diff --git a/src/polygon/include/polygon.h b/src/polygon/include/polygon.h index 3133426da..1af13b8a8 100644 --- a/src/polygon/include/polygon.h +++ b/src/polygon/include/polygon.h @@ -36,8 +36,11 @@ struct PolyVert { using SimplePolygonIdx = std::vector; using PolygonsIdx = std::vector; -std::vector Triangulate(const PolygonsIdx &polys, - float precision = -1); +std::vector TriangulateIdx(const PolygonsIdx &polys, + float precision = -1); + +std::vector Triangulate( + std::vector> &polygons, float precision = -1); ExecutionParams &PolygonParams(); /** @} */ diff --git a/src/polygon/src/polygon.cpp b/src/polygon/src/polygon.cpp index acd40069d..3ce81203f 100644 --- a/src/polygon/src/polygon.cpp +++ b/src/polygon/src/polygon.cpp @@ -1042,7 +1042,8 @@ namespace manifold { * @return std::vector The triangles, referencing the original * vertex indicies. */ -std::vector Triangulate(const PolygonsIdx &polys, float precision) { +std::vector TriangulateIdx(const PolygonsIdx &polys, + float precision) { std::vector triangles; try { Monotones monotones(polys, precision); @@ -1069,6 +1070,29 @@ std::vector Triangulate(const PolygonsIdx &polys, float precision) { return triangles; } +/** + * @brief Triangulates a set of /epsilon-valid polygons. + * + * @param polygons The set of polygons, wound CCW and representing multiple + * polygons and/or holes. + * @param precision The value of epsilon, bounding the uncertainty of the input + * @return std::vector The triangles, referencing the original + * polygon points in order. + */ +std::vector Triangulate( + std::vector> &polygons, float precision) { + int idx = 0; + PolygonsIdx polygonsIndexed; + for (auto &poly : polygons) { + SimplePolygonIdx simpleIndexed; + for (const glm::vec2 &polyVert : poly) { + simpleIndexed.push_back({polyVert, idx++}); + } + polygonsIndexed.push_back(simpleIndexed); + } + return TriangulateIdx(polygonsIndexed, precision); +} + ExecutionParams &PolygonParams() { return params; } } // namespace manifold diff --git a/test/polygon_test.cpp b/test/polygon_test.cpp index 8c6d3e9b5..ccbb73ff8 100644 --- a/test/polygon_test.cpp +++ b/test/polygon_test.cpp @@ -91,13 +91,13 @@ void TestPoly(const PolygonsIdx &polys, int expectedNumTri, PolygonParams().verbose = options.params.verbose; std::vector triangles; - EXPECT_NO_THROW(triangles = Triangulate(polys, precision)); + EXPECT_NO_THROW(triangles = TriangulateIdx(polys, precision)); EXPECT_EQ(triangles.size(), expectedNumTri) << "Basic"; - EXPECT_NO_THROW(triangles = Triangulate(Turn180(polys), precision)); + EXPECT_NO_THROW(triangles = TriangulateIdx(Turn180(polys), precision)); EXPECT_EQ(triangles.size(), expectedNumTri) << "Turn 180"; - EXPECT_NO_THROW(triangles = Triangulate(Duplicate(polys), precision)); + EXPECT_NO_THROW(triangles = TriangulateIdx(Duplicate(polys), precision)); EXPECT_EQ(triangles.size(), 2 * expectedNumTri) << "Duplicate"; PolygonParams().verbose = false;