From 73364fb8cded084dd957df07938a91cbac87a8f3 Mon Sep 17 00:00:00 2001 From: Emmett Lalish Date: Tue, 22 Oct 2024 09:13:13 -0700 Subject: [PATCH 1/3] rename refineToPrecision --- bindings/c/include/manifold/manifoldc.h | 2 +- bindings/c/manifoldc.cpp | 4 ++-- bindings/python/examples/all_apis.py | 2 +- bindings/python/manifold3d.cpp | 4 ++-- bindings/wasm/bindings.cpp | 2 +- bindings/wasm/examples/worker.ts | 2 +- bindings/wasm/manifold-encapsulated-types.d.ts | 2 +- include/manifold/manifold.h | 4 ++-- src/manifold.cpp | 2 +- src/subdivision.cpp | 2 +- test/manifold_test.cpp | 2 +- test/smooth_test.cpp | 2 +- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/bindings/c/include/manifold/manifoldc.h b/bindings/c/include/manifold/manifoldc.h index 79597157c..d546fd7fc 100644 --- a/bindings/c/include/manifold/manifoldc.h +++ b/bindings/c/include/manifold/manifoldc.h @@ -142,7 +142,7 @@ ManifoldManifold *manifold_smooth_out(void *mem, ManifoldManifold *m, ManifoldManifold *manifold_refine(void *mem, ManifoldManifold *m, int refine); ManifoldManifold *manifold_refine_to_length(void *mem, ManifoldManifold *m, double length); -ManifoldManifold *manifold_refine_to_precision(void *mem, ManifoldManifold *m, +ManifoldManifold *manifold_refine_to_tolerance(void *mem, ManifoldManifold *m, double precision); // Manifold Shapes / Constructors diff --git a/bindings/c/manifoldc.cpp b/bindings/c/manifoldc.cpp index 2887f5683..082fff415 100644 --- a/bindings/c/manifoldc.cpp +++ b/bindings/c/manifoldc.cpp @@ -301,9 +301,9 @@ ManifoldManifold *manifold_refine_to_length(void *mem, ManifoldManifold *m, return to_c(new (mem) Manifold(refined)); } -ManifoldManifold *manifold_refine_to_precision(void *mem, ManifoldManifold *m, +ManifoldManifold *manifold_refine_to_tolerance(void *mem, ManifoldManifold *m, double precision) { - auto refined = from_c(m)->RefineToPrecision(precision); + auto refined = from_c(m)->RefineToTolerance(precision); return to_c(new (mem) Manifold(refined)); } diff --git a/bindings/python/examples/all_apis.py b/bindings/python/examples/all_apis.py index c9fcff831..f98edc645 100644 --- a/bindings/python/examples/all_apis.py +++ b/bindings/python/examples/all_apis.py @@ -95,7 +95,7 @@ def all_manifold(): c = m.project() m = m.refine(2) m = m.refine_to_length(0.1) - m = m.refine_to_precision(0.01) + m = m.refine_to_tolerance(0.01) m = m.smooth_out() i = Manifold.reserve_ids(1) m = m.scale((1, 2, 3)) diff --git a/bindings/python/manifold3d.cpp b/bindings/python/manifold3d.cpp index cafa89a72..8b967dfe2 100644 --- a/bindings/python/manifold3d.cpp +++ b/bindings/python/manifold3d.cpp @@ -328,8 +328,8 @@ NB_MODULE(manifold3d, m) { .def("refine", &Manifold::Refine, nb::arg("n"), manifold__refine__n) .def("refine_to_length", &Manifold::RefineToLength, nb::arg("length"), manifold__refine_to_length__length) - .def("refine_to_precision", &Manifold::RefineToPrecision, - nb::arg("precision"), manifold__refine_to_precision__precision) + .def("refine_to_tolerance", &Manifold::RefineToTolerance, + nb::arg("precision"), manifold__refine_to_tolerance__precision) .def("to_mesh", &Manifold::GetMeshGL, nb::arg("normal_idx") = std::make_tuple(0, 0, 0), manifold__get_mesh_gl__normal_idx) diff --git a/bindings/wasm/bindings.cpp b/bindings/wasm/bindings.cpp index d8d4b1815..96b02215e 100644 --- a/bindings/wasm/bindings.cpp +++ b/bindings/wasm/bindings.cpp @@ -141,7 +141,7 @@ EMSCRIPTEN_BINDINGS(whatever) { .function("_GetMeshJS", &js::GetMeshJS) .function("refine", &Manifold::Refine) .function("refineToLength", &Manifold::RefineToLength) - .function("refineToPrecision", &Manifold::RefineToPrecision) + .function("refineToTolerance", &Manifold::RefineToTolerance) .function("smoothByNormals", &Manifold::SmoothByNormals) .function("_SmoothOut", &Manifold::SmoothOut) .function("_Warp", &man_js::Warp) diff --git a/bindings/wasm/examples/worker.ts b/bindings/wasm/examples/worker.ts index d8151d9b1..305e30714 100644 --- a/bindings/wasm/examples/worker.ts +++ b/bindings/wasm/examples/worker.ts @@ -74,7 +74,7 @@ const manifoldMemberFunctions = [ 'smoothOut', 'refine', 'refineToLength', - 'refineToPrecision', + 'refineToTolerance', 'setProperties', 'asOriginal', 'trimByPlane', diff --git a/bindings/wasm/manifold-encapsulated-types.d.ts b/bindings/wasm/manifold-encapsulated-types.d.ts index 24e9ce4fb..0c3726b7e 100644 --- a/bindings/wasm/manifold-encapsulated-types.d.ts +++ b/bindings/wasm/manifold-encapsulated-types.d.ts @@ -707,7 +707,7 @@ export class Manifold { * produced and the exact smoothly curving surface. All vertices are exactly * on the surface, within rounding error. */ - refineToPrecision(precision: number): Manifold; + refineToTolerance(precision: number): Manifold; /** * Create a new copy of this manifold with updated vertex properties by diff --git a/include/manifold/manifold.h b/include/manifold/manifold.h index 7d2c31ae5..58fd44e0b 100644 --- a/include/manifold/manifold.h +++ b/include/manifold/manifold.h @@ -266,7 +266,7 @@ class Manifold { Manifold SmoothOut(double minSharpAngle = 60, double minSmoothness = 0) const; Manifold Refine(int) const; Manifold RefineToLength(double) const; - Manifold RefineToPrecision(double) const; + Manifold RefineToTolerance(double) const; Manifold SetTolerance(double) const; ///@} @@ -363,7 +363,7 @@ inline std::string ToString(const Manifold::Error& error) { case Manifold::Error::InvalidConstruction: return "Invalid Construction"; default: - return "Unkown Error"; + return "Unknown Error"; }; } diff --git a/src/manifold.cpp b/src/manifold.cpp index 565437436..e5a15bf97 100644 --- a/src/manifold.cpp +++ b/src/manifold.cpp @@ -813,7 +813,7 @@ Manifold Manifold::RefineToLength(double length) const { * produced and the exact smoothly curving surface. All vertices are exactly on * the surface, within rounding error. */ -Manifold Manifold::RefineToPrecision(double precision) const { +Manifold Manifold::RefineToTolerance(double precision) const { precision = std::abs(precision); auto pImpl = std::make_shared(*GetCsgLeafNode().GetImpl()); if (!pImpl->halfedgeTangent_.empty()) { diff --git a/src/subdivision.cpp b/src/subdivision.cpp index 421e11ada..83b66d442 100644 --- a/src/subdivision.cpp +++ b/src/subdivision.cpp @@ -519,7 +519,7 @@ Vec Manifold::Impl::Subdivide( // Triangles where the greatest number of divisions exceeds the sum of the // other two sides will be triangulated as a strip, since if the sub-edges // were all equal length it would be degenerate. This leads to poor results - // with RefineToPrecision, so we avoid this case by adding some extra + // with RefineToTolerance, so we avoid this case by adding some extra // divisions to the short sides so that the triangulation has some thickness // and creates more interior facets. Vec tmp(numEdge); diff --git a/test/manifold_test.cpp b/test/manifold_test.cpp index b73a21e1d..e07a61d9e 100644 --- a/test/manifold_test.cpp +++ b/test/manifold_test.cpp @@ -506,7 +506,7 @@ TEST(Manifold, MeshRelationRefinePrecision) { const int id = inGL.runOriginalID[0]; Manifold csaszar = Manifold::Smooth(inGL); - csaszar = csaszar.RefineToPrecision(0.05); + csaszar = csaszar.RefineToTolerance(0.05); ExpectMeshes(csaszar, {{2684, 5368, 3}}); std::vector runOriginalID = csaszar.GetMeshGL().runOriginalID; EXPECT_EQ(runOriginalID.size(), 1); diff --git a/test/smooth_test.cpp b/test/smooth_test.cpp index 083616eee..bfdec58ce 100644 --- a/test/smooth_test.cpp +++ b/test/smooth_test.cpp @@ -161,7 +161,7 @@ TEST(Smooth, Precision) { const double radius = 10; const double height = 10; Manifold cylinder = Manifold::Cylinder(height, radius, radius, 8); - Manifold smoothed = cylinder.SmoothOut().RefineToPrecision(precision); + Manifold smoothed = cylinder.SmoothOut().RefineToTolerance(precision); // Makes an edge bisector, which is the worst case. MeshGL64 out = smoothed.Refine(2).GetMeshGL64(); const int numVert = out.NumVert(); From 8edfd16ca90d0584de1a30d6c89904e16533ed9d Mon Sep 17 00:00:00 2001 From: Emmett Lalish Date: Tue, 22 Oct 2024 14:46:38 -0700 Subject: [PATCH 2/3] rename kTolerance --- extras/minimize_testcase.cpp | 4 ++-- src/csg_tree.cpp | 2 +- src/polygon.cpp | 2 +- src/quickhull.cpp | 2 +- src/shared.h | 2 +- src/smoothing.cpp | 6 +++--- src/utils.h | 2 +- test/boolean_test.cpp | 6 +++--- test/properties_test.cpp | 8 ++++---- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/extras/minimize_testcase.cpp b/extras/minimize_testcase.cpp index 85561d3b8..1286d67aa 100644 --- a/extras/minimize_testcase.cpp +++ b/extras/minimize_testcase.cpp @@ -31,7 +31,7 @@ inline bool intersect(vec2 p0, vec2 p1, vec2 q0, vec2 q1, double precision) { // // note that this does not correspond to a fixed angle, // but seems to work well enough - if (rxs < kTolerance && rxs > -kTolerance) { + if (rxs < kPrecision && rxs > -kPrecision) { return false; } double u = cross(q0 - p0, r) / rxs; @@ -373,7 +373,7 @@ int main(int argc, char **argv) { bound = la::max(bound, la::abs(pt.y)); } } - precision = bound * kTolerance; + precision = bound * kPrecision; } std::cout << "------------" << std::endl; diff --git a/src/csg_tree.cpp b/src/csg_tree.cpp index ee20e56f1..0e5e0b993 100644 --- a/src/csg_tree.cpp +++ b/src/csg_tree.cpp @@ -194,7 +194,7 @@ Manifold::Impl CsgLeafNode::Compose( node->pImpl_->bBox_.Transform(node->transform_).Scale(); double nodeEpsilon = node->pImpl_->epsilon_; nodeEpsilon *= std::max(1.0, nodeNewScale / nodeOldScale); - nodeEpsilon = std::max(nodeEpsilon, kTolerance * nodeNewScale); + nodeEpsilon = std::max(nodeEpsilon, kPrecision * nodeNewScale); if (!std::isfinite(nodeEpsilon)) nodeEpsilon = -1; epsilon = std::max(epsilon, nodeEpsilon); tolerance = std::max(tolerance, node->pImpl_->tolerance_); diff --git a/src/polygon.cpp b/src/polygon.cpp index ae0ef5b3a..f7af6369a 100644 --- a/src/polygon.cpp +++ b/src/polygon.cpp @@ -650,7 +650,7 @@ class EarClip { Link(last, first); } - if (precision_ < 0) precision_ = bBox_.Scale() * kTolerance; + if (precision_ < 0) precision_ = bBox_.Scale() * kPrecision; // Slightly more than enough, since each hole can cause two extra triangles. triangles_.reserve(polygon_.size() + 2 * starts.size()); diff --git a/src/quickhull.cpp b/src/quickhull.cpp index 8c4dc6a0d..d0159136f 100644 --- a/src/quickhull.cpp +++ b/src/quickhull.cpp @@ -847,7 +847,7 @@ void Manifold::Impl::Hull(VecView vertPos) { QuickHull qh(vertPos); std::tie(halfedge_, vertPos_) = qh.buildMesh(); CalculateBBox(); - SetEpsilon(bBox_.Scale() * kTolerance); + SetEpsilon(bBox_.Scale() * kPrecision); CalculateNormals(); InitializeOriginal(); Finish(); diff --git a/src/shared.h b/src/shared.h index 4bd72e40c..0603c663b 100644 --- a/src/shared.h +++ b/src/shared.h @@ -30,7 +30,7 @@ inline vec3 SafeNormalize(vec3 v) { } inline double MaxEpsilon(double minEpsilon, const Box& bBox) { - double epsilon = std::max(minEpsilon, kTolerance * bBox.Scale()); + double epsilon = std::max(minEpsilon, kPrecision * bBox.Scale()); return std::isfinite(epsilon) ? epsilon : -1; } diff --git a/src/smoothing.cpp b/src/smoothing.cpp index 63719775d..262250e7b 100644 --- a/src/smoothing.cpp +++ b/src/smoothing.cpp @@ -23,7 +23,7 @@ using namespace manifold; // ref and altIn. vec3 OrthogonalTo(vec3 in, vec3 altIn, vec3 ref) { vec3 out = in - la::dot(in, ref) * ref; - if (la::dot(out, out) < kTolerance * la::dot(in, in)) { + if (la::dot(out, out) < kPrecision * la::dot(in, in)) { out = altIn - la::dot(altIn, ref) * ref; } return SafeNormalize(out); @@ -785,7 +785,7 @@ void Manifold::Impl::CreateTangents(int normalIdx) { const vec3 normal = GetNormal(halfedge, normalIdx); const vec3 diff = faceNormal_[halfedge / 3] - normal; return FlatNormal( - {la::dot(diff, diff) < kTolerance * kTolerance, normal}); + {la::dot(diff, diff) < kPrecision * kPrecision, normal}); }, [&faceEdges, &tangent, &fixedHalfedge, this]( int halfedge, const FlatNormal& here, const FlatNormal& next) { @@ -796,7 +796,7 @@ void Manifold::Impl::CreateTangents(int normalIdx) { // mark special edges const vec3 diff = next.normal - here.normal; const bool differentNormals = - la::dot(diff, diff) > kTolerance * kTolerance; + la::dot(diff, diff) > kPrecision * kPrecision; if (differentNormals || here.isFlatFace != next.isFlatFace) { fixedHalfedge[halfedge] = true; if (faceEdges[0] == -1) { diff --git a/src/utils.h b/src/utils.h index f3e84a919..f33f5283a 100644 --- a/src/utils.h +++ b/src/utils.h @@ -68,7 +68,7 @@ namespace manifold { return n; } -constexpr double kTolerance = 1e-12; +constexpr double kPrecision = 1e-12; inline int Next3(int i) { constexpr ivec3 next3(1, 2, 0); diff --git a/test/boolean_test.cpp b/test/boolean_test.cpp index 5321fb515..ef4d9f4ae 100644 --- a/test/boolean_test.cpp +++ b/test/boolean_test.cpp @@ -408,7 +408,7 @@ TEST(Boolean, Precision) { Manifold cube2 = cube; Manifold cube3 = cube; double distance = 100; - double scale = distance * kTolerance; + double scale = distance * kPrecision; cube2 = cube2.Scale(vec3(scale)).Translate({distance, 0, 0}); cube += cube2; @@ -423,11 +423,11 @@ TEST(Boolean, Precision2) { double scale = 1000; Manifold cube = Manifold::Cube(vec3(scale)); Manifold cube2 = cube; - double distance = scale * (1 - kTolerance / 2); + double distance = scale * (1 - kPrecision / 2); cube2 = cube2.Translate(vec3(-distance)); EXPECT_TRUE((cube ^ cube2).IsEmpty()); - cube2 = cube2.Translate(vec3(scale * kTolerance)); + cube2 = cube2.Translate(vec3(scale * kPrecision)); EXPECT_FALSE((cube ^ cube2).IsEmpty()); } diff --git a/test/properties_test.cpp b/test/properties_test.cpp index 0ce338122..f21181cad 100644 --- a/test/properties_test.cpp +++ b/test/properties_test.cpp @@ -37,17 +37,17 @@ TEST(Properties, GetProperties) { TEST(Properties, Precision) { Manifold cube = Manifold::Cube(); - EXPECT_FLOAT_EQ(cube.GetEpsilon(), kTolerance); + EXPECT_FLOAT_EQ(cube.GetEpsilon(), kPrecision); cube = cube.Scale({0.1, 1, 10}); - EXPECT_FLOAT_EQ(cube.GetEpsilon(), 10 * kTolerance); + EXPECT_FLOAT_EQ(cube.GetEpsilon(), 10 * kPrecision); cube = cube.Translate({-100, -10, -1}); - EXPECT_FLOAT_EQ(cube.GetEpsilon(), 100 * kTolerance); + EXPECT_FLOAT_EQ(cube.GetEpsilon(), 100 * kPrecision); } TEST(Properties, Precision2) { Manifold cube = Manifold::Cube(); cube = cube.Translate({-0.5, 0, 0}).Scale({2, 1, 1}); - EXPECT_FLOAT_EQ(cube.GetEpsilon(), 2 * kTolerance); + EXPECT_FLOAT_EQ(cube.GetEpsilon(), 2 * kPrecision); } TEST(Properties, Precision3) { From 3fade1cec4f1f3599fb6decb4e60b00071b1d1c6 Mon Sep 17 00:00:00 2001 From: Emmett Lalish Date: Tue, 22 Oct 2024 15:06:55 -0700 Subject: [PATCH 3/3] the precision rename --- bindings/c/include/manifold/manifoldc.h | 8 +- bindings/c/manifoldc.cpp | 20 +- bindings/python/manifold3d.cpp | 14 +- bindings/wasm/bindings.js | 8 +- bindings/wasm/helpers.cpp | 4 +- .../wasm/manifold-encapsulated-types.d.ts | 24 +-- include/manifold/manifold.h | 6 +- include/manifold/polygon.h | 4 +- src/csg_tree.cpp | 2 +- src/edge_op.cpp | 12 +- src/impl.cpp | 6 +- src/manifold.cpp | 14 +- src/polygon.cpp | 177 +++++++++--------- src/properties.cpp | 7 +- src/sdf.cpp | 12 +- src/sort.cpp | 8 +- test/polygon_test.cpp | 24 +-- test/samples_test.cpp | 6 +- test/sdf_test.cpp | 42 ++--- test/smooth_test.cpp | 8 +- 20 files changed, 200 insertions(+), 206 deletions(-) diff --git a/bindings/c/include/manifold/manifoldc.h b/bindings/c/include/manifold/manifoldc.h index d546fd7fc..5463dfcdb 100644 --- a/bindings/c/include/manifold/manifoldc.h +++ b/bindings/c/include/manifold/manifoldc.h @@ -64,10 +64,10 @@ ManifoldManifold *manifold_level_set(void *mem, double (*sdf)(double, double, double, void *), ManifoldBox *bounds, double edge_length, - double level, double precision, void *ctx); + double level, double tolerance, void *ctx); ManifoldManifold *manifold_level_set_seq( void *mem, double (*sdf)(double, double, double, void *), - ManifoldBox *bounds, double edge_length, double level, double precision, + ManifoldBox *bounds, double edge_length, double level, double tolerance, void *ctx); // Manifold Vectors @@ -143,7 +143,7 @@ ManifoldManifold *manifold_refine(void *mem, ManifoldManifold *m, int refine); ManifoldManifold *manifold_refine_to_length(void *mem, ManifoldManifold *m, double length); ManifoldManifold *manifold_refine_to_tolerance(void *mem, ManifoldManifold *m, - double precision); + double tolerance); // Manifold Shapes / Constructors @@ -180,7 +180,7 @@ size_t manifold_num_vert(ManifoldManifold *m); size_t manifold_num_edge(ManifoldManifold *m); size_t manifold_num_tri(ManifoldManifold *m); ManifoldBox *manifold_bounding_box(void *mem, ManifoldManifold *m); -double manifold_precision(ManifoldManifold *m); +double manifold_epsilon(ManifoldManifold *m); int manifold_genus(ManifoldManifold *m); ManifoldProperties manifold_get_properties(ManifoldManifold *m); int manifold_get_circular_segments(double radius); diff --git a/bindings/c/manifoldc.cpp b/bindings/c/manifoldc.cpp index 082fff415..26e9b8589 100644 --- a/bindings/c/manifoldc.cpp +++ b/bindings/c/manifoldc.cpp @@ -27,7 +27,7 @@ using namespace manifold; namespace { ManifoldManifold *level_set( void *mem, double (*sdf_context)(double, double, double, void *), - ManifoldBox *bounds, double edge_length, double level, double precision, + ManifoldBox *bounds, double edge_length, double level, double tolerance, bool seq, void *ctx) { // Bind function with context argument to one without using namespace std::placeholders; @@ -37,7 +37,7 @@ ManifoldManifold *level_set( return (sdf(v.x, v.y, v.z)); }; return to_c(new (mem) Manifold(Manifold::LevelSet( - fun, *from_c(bounds), edge_length, level, precision, !seq))); + fun, *from_c(bounds), edge_length, level, tolerance, !seq))); } } // namespace @@ -265,16 +265,16 @@ ManifoldManifold *manifold_warp(void *mem, ManifoldManifold *m, ManifoldManifold *manifold_level_set( void *mem, double (*sdf)(double, double, double, void *), - ManifoldBox *bounds, double edge_length, double level, double precision, + ManifoldBox *bounds, double edge_length, double level, double tolerance, void *ctx) { - return level_set(mem, sdf, bounds, edge_length, level, precision, false, ctx); + return level_set(mem, sdf, bounds, edge_length, level, tolerance, false, ctx); } ManifoldManifold *manifold_level_set_seq( void *mem, double (*sdf)(double, double, double, void *), - ManifoldBox *bounds, double edge_length, double level, double precision, + ManifoldBox *bounds, double edge_length, double level, double tolerance, void *ctx) { - return level_set(mem, sdf, bounds, edge_length, level, precision, true, ctx); + return level_set(mem, sdf, bounds, edge_length, level, tolerance, true, ctx); } ManifoldManifold *manifold_smooth_by_normals(void *mem, ManifoldManifold *m, @@ -302,8 +302,8 @@ ManifoldManifold *manifold_refine_to_length(void *mem, ManifoldManifold *m, } ManifoldManifold *manifold_refine_to_tolerance(void *mem, ManifoldManifold *m, - double precision) { - auto refined = from_c(m)->RefineToTolerance(precision); + double tolerance) { + auto refined = from_c(m)->RefineToTolerance(tolerance); return to_c(new (mem) Manifold(refined)); } @@ -524,9 +524,7 @@ ManifoldBox *manifold_bounding_box(void *mem, ManifoldManifold *m) { return to_c(new (mem) Box(box)); } -double manifold_precision(ManifoldManifold *m) { - return from_c(m)->GetEpsilon(); -} +double manifold_epsilon(ManifoldManifold *m) { return from_c(m)->GetEpsilon(); } uint32_t manifold_reserve_ids(uint32_t n) { return Manifold::ReserveIDs(n); } diff --git a/bindings/python/manifold3d.cpp b/bindings/python/manifold3d.cpp index 8b967dfe2..804466919 100644 --- a/bindings/python/manifold3d.cpp +++ b/bindings/python/manifold3d.cpp @@ -329,7 +329,7 @@ NB_MODULE(manifold3d, m) { .def("refine_to_length", &Manifold::RefineToLength, nb::arg("length"), manifold__refine_to_length__length) .def("refine_to_tolerance", &Manifold::RefineToTolerance, - nb::arg("precision"), manifold__refine_to_tolerance__precision) + nb::arg("tolerance"), manifold__refine_to_tolerance__tolerance) .def("to_mesh", &Manifold::GetMeshGL, nb::arg("normal_idx") = std::make_tuple(0, 0, 0), manifold__get_mesh_gl__normal_idx) @@ -437,7 +437,7 @@ NB_MODULE(manifold3d, m) { "level_set", [](const std::function &f, std::vector bounds, double edgeLength, double level = 0.0, - double precision = -1) { + double tolerance = -1) { // Same format as Manifold.bounding_box Box bound = {vec3(bounds[0], bounds[1], bounds[2]), vec3(bounds[3], bounds[4], bounds[5])}; @@ -446,11 +446,11 @@ NB_MODULE(manifold3d, m) { return f(v.x, v.y, v.z); }; return Manifold::LevelSet(cppToPython, bound, edgeLength, level, - precision, false); + tolerance, false); }, nb::arg("f"), nb::arg("bounds"), nb::arg("edgeLength"), - nb::arg("level") = 0.0, nb::arg("precision") = -1, - manifold__level_set__sdf__bounds__edge_length__level__precision__can_parallel) + nb::arg("level") = 0.0, nb::arg("tolerance") = -1, + manifold__level_set__sdf__bounds__edge_length__level__tolerance__can_parallel) .def_static( "cylinder", &Manifold::Cylinder, nb::arg("height"), nb::arg("radius_low"), nb::arg("radius_high") = -1.0f, @@ -484,7 +484,7 @@ NB_MODULE(manifold3d, m) { nb::ndarray, nb::c_contig>> &faceID, const std::optional, nb::c_contig>> &halfedgeTangent, - float precision) { + float tolerance) { new (self) MeshGL(); MeshGL &out = *self; out.numProp = vertProp.shape(1); @@ -529,7 +529,7 @@ NB_MODULE(manifold3d, m) { nb::arg("run_original_id") = nb::none(), nb::arg("run_transform") = nb::none(), nb::arg("face_id") = nb::none(), - nb::arg("halfedge_tangent") = nb::none(), nb::arg("precision") = 0) + nb::arg("halfedge_tangent") = nb::none(), nb::arg("tolerance") = 0) .def_prop_ro( "vert_properties", [](const MeshGL &self) { diff --git a/bindings/wasm/bindings.js b/bindings/wasm/bindings.js index fd2b23df6..479b15d40 100644 --- a/bindings/wasm/bindings.js +++ b/bindings/wasm/bindings.js @@ -640,7 +640,7 @@ Module.setup = function() { Module.Manifold.intersection = manifoldBatchbool('Intersection'); Module.Manifold.levelSet = function( - sdf, bounds, edgeLength, level = 0, precision = -1) { + sdf, bounds, edgeLength, level = 0, tolerance = -1) { const bounds2 = { min: {x: bounds.min[0], y: bounds.min[1], z: bounds.min[2]}, max: {x: bounds.max[0], y: bounds.max[1], z: bounds.max[2]}, @@ -653,7 +653,7 @@ Module.setup = function() { return sdf(vert); }, 'di'); const out = - Module._LevelSet(wasmFuncPtr, bounds2, edgeLength, level, precision); + Module._LevelSet(wasmFuncPtr, bounds2, edgeLength, level, tolerance); removeFunction(wasmFuncPtr); return out; }; @@ -697,10 +697,10 @@ Module.setup = function() { // Top-level functions - Module.triangulate = function(polygons, precision = -1) { + Module.triangulate = function(polygons, epsilon = -1) { const polygonsVec = polygons2vec(polygons); const result = fromVec( - Module._Triangulate(polygonsVec, precision), (x) => [x[0], x[1], x[2]]); + Module._Triangulate(polygonsVec, epsilon), (x) => [x[0], x[1], x[2]]); disposePolygons(polygonsVec); return result; }; diff --git a/bindings/wasm/helpers.cpp b/bindings/wasm/helpers.cpp index 3e442c6fe..16c99c62c 100644 --- a/bindings/wasm/helpers.cpp +++ b/bindings/wasm/helpers.cpp @@ -206,9 +206,9 @@ Manifold SetProperties(Manifold& manifold, int numProp, uintptr_t funcPtr) { } Manifold LevelSet(uintptr_t funcPtr, Box bounds, double edgeLength, - double level, double precision) { + double level, double tolerance) { double (*f)(const vec3&) = reinterpret_cast(funcPtr); - return Manifold::LevelSet(f, bounds, edgeLength, level, precision); + return Manifold::LevelSet(f, bounds, edgeLength, level, tolerance); } std::vector Split(Manifold& a, Manifold& b) { diff --git a/bindings/wasm/manifold-encapsulated-types.d.ts b/bindings/wasm/manifold-encapsulated-types.d.ts index 0c3726b7e..3b09ed841 100644 --- a/bindings/wasm/manifold-encapsulated-types.d.ts +++ b/bindings/wasm/manifold-encapsulated-types.d.ts @@ -19,10 +19,10 @@ import {Box, FillRule, JoinType, Mat3, Mat4, Polygons, Properties, Rect, SealedF * * @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 + * @param epsilon 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[]; +export function triangulate(polygons: Polygons, epsilon?: number): Vec3[]; /** * Sets an angle constraint the default number of circular segments for the @@ -569,14 +569,14 @@ export class Manifold { * performance. * @param level You can inset your Mesh by using a positive value, or outset * it with a negative value. - * @param precision Ensure each vertex is within this distance of the true + * @param tolerance Ensure each vertex is within this distance of the true * surface. Defaults to -1, which will return the interpolated * crossing-point based on the two nearest grid points. Small positive values * will require more sdf evaluations per output vertex. */ static levelSet( sdf: (point: Vec3) => number, bounds: Box, edgeLength: number, - level?: number, precision?: number): Manifold; + level?: number, tolerance?: number): Manifold; // Transformations @@ -697,17 +697,17 @@ export class Manifold { /** * Increase the density of the mesh by splitting each edge into pieces such - * that any point on the resulting triangles is roughly within precision of + * that any point on the resulting triangles is roughly within tolerance of * the smoothly curved surface defined by the tangent vectors. This means * tightly curving regions will be divided more finely than smoother regions. * If halfedgeTangents are not present, the result will simply be a copy of * the original. Quads will ignore their interior triangle bisector. * - * @param precision The desired maximum distance between the faceted mesh + * @param tolerance The desired maximum distance between the faceted mesh * produced and the exact smoothly curving surface. All vertices are exactly * on the surface, within rounding error. */ - refineToTolerance(precision: number): Manifold; + refineToTolerance(tolerance: number): Manifold; /** * Create a new copy of this manifold with updated vertex properties by @@ -929,14 +929,14 @@ export class Manifold { boundingBox(): Box; /** - * Returns the precision of this Manifold's vertices, which tracks the + * Returns the tolerance of this Manifold's vertices, which tracks the * approximate rounding error over all the transforms and operations that have - * led to this state. Any triangles that are colinear within this precision + * led to this state. Any triangles that are colinear within this tolerance * are considered degenerate and removed. This is the value of ε * defining * [ε-valid](https://github.com/elalish/manifold/wiki/Manifold-Library#definition-of-%CE%B5-valid). */ - precision(): number; + tolerance(): number; /** * The genus is a topological property of the manifold, representing the @@ -1137,8 +1137,8 @@ export class Mesh { * Updates the mergeFromVert and mergeToVert vectors in order to create a * manifold solid. If the MeshGL is already manifold, no change will occur and * the function will return false. Otherwise, this will merge verts along open - * edges within precision (the maximum of the MeshGL precision and the - * baseline bounding-box precision), keeping any from the existing merge + * edges within tolerance (the maximum of the MeshGL tolerance and the + * baseline bounding-box tolerance), keeping any from the existing merge * vectors. * * There is no guarantee the result will be manifold - this is a best-effort diff --git a/include/manifold/manifold.h b/include/manifold/manifold.h index 58fd44e0b..2392decc4 100644 --- a/include/manifold/manifold.h +++ b/include/manifold/manifold.h @@ -89,8 +89,8 @@ struct MeshGLP { /// Mesh.triVerts[tri][i] along the CCW edge. If empty, mesh is faceted. std::vector halfedgeTangent; /// Tolerance for mesh simplification. - /// When creating a Manifold, the precision used will be the maximum - /// of this and a baseline precision from the size of the bounding box. Any + /// When creating a Manifold, the tolerance used will be the maximum + /// of this and a baseline tolerance from the size of the bounding box. Any /// edge shorter than tolerance may be collapsed. /// Tolerance may be enlarged when floating point error accumulates. Precision tolerance = 0; @@ -192,7 +192,7 @@ class Manifold { double revolveDegrees = 360.0f); static Manifold LevelSet(std::function sdf, Box bounds, double edgeLength, double level = 0, - double precision = -1, bool canParallel = true); + double tolerance = -1, bool canParallel = true); ///@} /** @name Topological diff --git a/include/manifold/polygon.h b/include/manifold/polygon.h index 789b405b9..2c72acf3e 100644 --- a/include/manifold/polygon.h +++ b/include/manifold/polygon.h @@ -35,13 +35,13 @@ using SimplePolygonIdx = std::vector; using PolygonsIdx = std::vector; std::vector TriangulateIdx(const PolygonsIdx &polys, - double precision = -1); + double epsilon = -1); /** @} */ /** @ingroup Connections * @{ */ -std::vector Triangulate(const Polygons &polygons, double precision = -1); +std::vector Triangulate(const Polygons &polygons, double epsilon = -1); ExecutionParams &PolygonParams(); /** @} */ diff --git a/src/csg_tree.cpp b/src/csg_tree.cpp index 0e5e0b993..dad6461f1 100644 --- a/src/csg_tree.cpp +++ b/src/csg_tree.cpp @@ -323,7 +323,7 @@ Manifold::Impl CsgLeafNode::Compose( } } - // required to remove parts that are smaller than the precision + // required to remove parts that are smaller than the tolerance combined.SimplifyTopology(); combined.Finish(); combined.IncrementMeshIDs(); diff --git a/src/edge_op.cpp b/src/edge_op.cpp index 197585e58..6d2479062 100644 --- a/src/edge_op.cpp +++ b/src/edge_op.cpp @@ -47,14 +47,14 @@ struct DuplicateEdge { struct ShortEdge { VecView halfedge; VecView vertPos; - const double precision; + const double tolerance; bool operator()(int edge) const { if (halfedge[edge].pairedHalfedge < 0) return false; // Flag short edges const vec3 delta = vertPos[halfedge[edge].endVert] - vertPos[halfedge[edge].startVert]; - return la::dot(delta, delta) < precision * precision; + return la::dot(delta, delta) < tolerance * tolerance; } }; @@ -83,7 +83,7 @@ struct SwappableEdge { VecView halfedge; VecView vertPos; VecView triNormal; - const double precision; + const double tolerance; bool operator()(int edge) const { if (halfedge[edge].pairedHalfedge < 0) return false; @@ -94,7 +94,7 @@ struct SwappableEdge { vec2 v[3]; for (int i : {0, 1, 2}) v[i] = projection * vertPos[halfedge[triEdge[i]].startVert]; - if (CCW(v[0], v[1], v[2], precision) > 0 || !Is01Longest(v[0], v[1], v[2])) + if (CCW(v[0], v[1], v[2], tolerance) > 0 || !Is01Longest(v[0], v[1], v[2])) return false; // Switch to neighbor's projection. @@ -104,7 +104,7 @@ struct SwappableEdge { projection = GetAxisAlignedProjection(triNormal[tri]); for (int i : {0, 1, 2}) v[i] = projection * vertPos[halfedge[triEdge[i]].startVert]; - return CCW(v[0], v[1], v[2], precision) > 0 || + return CCW(v[0], v[1], v[2], tolerance) > 0 || Is01Longest(v[0], v[1], v[2]); } }; @@ -169,7 +169,7 @@ void Manifold::Impl::CleanupTopology() { } /** - * Collapses degenerate triangles by removing edges shorter than precision_ and + * Collapses degenerate triangles by removing edges shorter than tolerance_ and * any edge that is preceeded by an edge that joins the same two face relations. * It also performs edge swaps on the long edges of degenerate triangles, though * there are some configurations of degenerates that cannot be removed this way. diff --git a/src/impl.cpp b/src/impl.cpp index a887e57a7..8d6c28d8c 100644 --- a/src/impl.cpp +++ b/src/impl.cpp @@ -560,15 +560,15 @@ Manifold::Impl Manifold::Impl::Transform(const mat3x4& transform_) const { if (!result.collider_.Transform(transform_)) result.Update(); result.CalculateBBox(); - // Scale the precision by the norm of the 3x3 portion of the transform. + // Scale epsilon by the norm of the 3x3 portion of the transform. result.epsilon_ *= SpectralNorm(mat3(transform_)); - // Maximum of inherited precision loss and translational precision loss. + // Maximum of inherited epsilon loss and translational epsilon loss. result.SetEpsilon(result.epsilon_); return result; } /** - * Sets the precision based on the bounding box, and limits its minimum value + * Sets epsilon based on the bounding box, and limits its minimum value * by the optional input. */ void Manifold::Impl::SetEpsilon(double minEpsilon) { diff --git a/src/manifold.cpp b/src/manifold.cpp index e5a15bf97..8abbc8d42 100644 --- a/src/manifold.cpp +++ b/src/manifold.cpp @@ -331,7 +331,7 @@ bool Manifold::IsEmpty() const { return GetCsgLeafNode().GetImpl()->IsEmpty(); } * combined into a new Manifold via operations, the status reverts to NoError, * simply processing the problem mesh as empty. Likewise, empty meshes may still * show NoError, for instance if they are small enough relative to their - * precision to be collapsed to nothing. + * tolerance to be collapsed to nothing. */ Manifold::Error Manifold::Status() const { return GetCsgLeafNode().GetImpl()->status_; @@ -803,22 +803,22 @@ Manifold Manifold::RefineToLength(double length) const { /** * Increase the density of the mesh by splitting each edge into pieces such that - * any point on the resulting triangles is roughly within precision of the + * any point on the resulting triangles is roughly within tolerance of the * smoothly curved surface defined by the tangent vectors. This means tightly * curving regions will be divided more finely than smoother regions. If * halfedgeTangents are not present, the result will simply be a copy of the * original. Quads will ignore their interior triangle bisector. * - * @param precision The desired maximum distance between the faceted mesh + * @param tolerance The desired maximum distance between the faceted mesh * produced and the exact smoothly curving surface. All vertices are exactly on * the surface, within rounding error. */ -Manifold Manifold::RefineToTolerance(double precision) const { - precision = std::abs(precision); +Manifold Manifold::RefineToTolerance(double tolerance) const { + tolerance = std::abs(tolerance); auto pImpl = std::make_shared(*GetCsgLeafNode().GetImpl()); if (!pImpl->halfedgeTangent_.empty()) { pImpl->Refine( - [precision](vec3 edge, vec4 tangentStart, vec4 tangentEnd) { + [tolerance](vec3 edge, vec4 tangentStart, vec4 tangentEnd) { const vec3 edgeNorm = la::normalize(edge); // Weight heuristic const vec3 tStart = vec3(tangentStart); @@ -829,7 +829,7 @@ Manifold Manifold::RefineToTolerance(double precision) const { // Circular arc result plus heuristic term for non-circular curves const double d = 0.5 * (la::length(start) + la::length(end)) + la::length(start - end); - return static_cast(std::sqrt(3 * d / (4 * precision))); + return static_cast(std::sqrt(3 * d / (4 * tolerance))); }, true); } diff --git a/src/polygon.cpp b/src/polygon.cpp index f7af6369a..38d209ae6 100644 --- a/src/polygon.cpp +++ b/src/polygon.cpp @@ -108,7 +108,7 @@ void CheckTopology(const std::vector &triangles, } void CheckGeometry(const std::vector &triangles, - const PolygonsIdx &polys, double precision) { + const PolygonsIdx &polys, double epsilon) { std::unordered_map vertPos; for (const auto &poly : polys) { for (size_t i = 0; i < poly.size(); ++i) { @@ -116,15 +116,15 @@ void CheckGeometry(const std::vector &triangles, } } DEBUG_ASSERT(std::all_of(triangles.begin(), triangles.end(), - [&vertPos, precision](const ivec3 &tri) { + [&vertPos, epsilon](const ivec3 &tri) { return CCW(vertPos[tri[0]], vertPos[tri[1]], - vertPos[tri[2]], precision) >= 0; + vertPos[tri[2]], epsilon) >= 0; }), geometryErr, "triangulation is not entirely CCW!"); } -void Dump(const PolygonsIdx &polys, double precision) { - std::cout << "Polygon 0 " << precision << " " << polys.size() << std::endl; +void Dump(const PolygonsIdx &polys, double epsilon) { + std::cout << "Polygon 0 " << epsilon << " " << polys.size() << std::endl; for (auto poly : polys) { std::cout << poly.size() << std::endl; for (auto v : poly) { @@ -142,16 +142,16 @@ void Dump(const PolygonsIdx &polys, double precision) { } void PrintFailure(const std::exception &e, const PolygonsIdx &polys, - std::vector &triangles, double precision) { + std::vector &triangles, double epsilon) { std::cout << "-----------------------------------" << std::endl; - std::cout << "Triangulation failed! Precision = " << precision << std::endl; + std::cout << "Triangulation failed! Precision = " << epsilon << std::endl; std::cout << e.what() << std::endl; if (triangles.size() > 1000 && !PolygonParams().verbose) { std::cout << "Output truncated due to producing " << triangles.size() << " triangles." << std::endl; return; } - Dump(polys, precision); + Dump(polys, epsilon); std::cout << "produced this triangulation:" << std::endl; for (size_t j = 0; j < triangles.size(); ++j) { std::cout << triangles[j][0] << ", " << triangles[j][1] << ", " @@ -170,7 +170,7 @@ void PrintFailure(const std::exception &e, const PolygonsIdx &polys, * Exactly colinear edges and zero-length edges are treated conservatively as * reflex. Does not check for overlaps. */ -bool IsConvex(const PolygonsIdx &polys, double precision) { +bool IsConvex(const PolygonsIdx &polys, double epsilon) { for (const SimplePolygonIdx &poly : polys) { const vec2 firstEdge = poly[0].pos - poly[poly.size() - 1].pos; // Zero-length edges comes out NaN, which won't trip the early return, but @@ -181,8 +181,7 @@ bool IsConvex(const PolygonsIdx &polys, double precision) { const vec2 edge = v + 1 < poly.size() ? poly[v + 1].pos - poly[v].pos : firstEdge; const double det = determinant2x2(lastEdge, edge); - if (det <= 0 || - (std::abs(det) < precision && la::dot(lastEdge, edge) < 0)) + if (det <= 0 || (std::abs(det) < epsilon && la::dot(lastEdge, edge) < 0)) return false; lastEdge = la::normalize(edge); } @@ -230,12 +229,12 @@ std::vector TriangulateConvex(const PolygonsIdx &polys) { * The main adjustments for robustness involve clipping the sharpest ears first * (a known technique to get higher triangle quality), and doing an exhaustive * search to determine ear convexity exactly if the first geometric result is - * within precision. + * within epsilon. */ class EarClip { public: - EarClip(const PolygonsIdx &polys, double precision) : precision_(precision) { + EarClip(const PolygonsIdx &polys, double epsilon) : epsilon_(epsilon) { ZoneScoped; size_t numVert = 0; @@ -269,7 +268,7 @@ class EarClip { return triangles_; } - double GetPrecision() const { return precision_; } + double GetPrecision() const { return epsilon_; } private: struct Vert; @@ -303,8 +302,8 @@ class EarClip { std::vector triangles_; // Bounding box of the entire set of polygons Rect bBox_; - // Working precision: max of float error and input value. - double precision_; + // Working epsilon: max of float error and input value. + double epsilon_; struct IdxCollider { Collider collider; @@ -322,33 +321,32 @@ class EarClip { vec2 pos, rightDir; VertItr left, right; - // Shorter than half of precision, to be conservative so that it doesn't - // cause CW triangles that exceed precision due to rounding error. - bool IsShort(double precision) const { + // Shorter than half of epsilon, to be conservative so that it doesn't + // cause CW triangles that exceed epsilon due to rounding error. + bool IsShort(double epsilon) const { const vec2 edge = right->pos - pos; - return la::dot(edge, edge) * 4 < precision * precision; + return la::dot(edge, edge) * 4 < epsilon * epsilon; } // Like CCW, returns 1 if v is on the inside of the angle formed at this - // vert, -1 on the outside, and 0 if it's within precision of the boundary. - // Ensure v is more than precision from pos, as case this will not return 0. - int Interior(vec2 v, double precision) const { + // vert, -1 on the outside, and 0 if it's within epsilon of the boundary. + // Ensure v is more than epsilon from pos, as case this will not return 0. + int Interior(vec2 v, double epsilon) const { const vec2 diff = v - pos; - if (la::dot(diff, diff) < precision * precision) { + if (la::dot(diff, diff) < epsilon * epsilon) { return 0; } - return CCW(pos, left->pos, right->pos, precision) + - CCW(pos, right->pos, v, precision) + - CCW(pos, v, left->pos, precision); + return CCW(pos, left->pos, right->pos, epsilon) + + CCW(pos, right->pos, v, epsilon) + CCW(pos, v, left->pos, epsilon); } // Returns true if Vert is on the inside of the edge that goes from tail to // tail->right. This will walk the edges if necessary until a clear answer - // is found (beyond precision). If toLeft is true, this Vert will walk its + // is found (beyond epsilon). If toLeft is true, this Vert will walk its // edges to the left. This should be chosen so that the edges walk in the // same general direction - tail always walks to the right. - bool InsideEdge(VertItr tail, double precision, bool toLeft) const { - const double p2 = precision * precision; + bool InsideEdge(VertItr tail, double epsilon, bool toLeft) const { + const double p2 = epsilon * epsilon; VertItr nextL = left->right; VertItr nextR = tail->right; VertItr center = tail; @@ -381,10 +379,10 @@ class EarClip { continue; } - int convexity = CCW(nextL->pos, center->pos, nextR->pos, precision); + int convexity = CCW(nextL->pos, center->pos, nextR->pos, epsilon); if (center != last) { - convexity += CCW(last->pos, center->pos, nextL->pos, precision) + - CCW(nextR->pos, center->pos, last->pos, precision); + convexity += CCW(last->pos, center->pos, nextL->pos, epsilon) + + CCW(nextR->pos, center->pos, last->pos, epsilon); } if (convexity != 0) return convexity > 0; @@ -406,40 +404,40 @@ class EarClip { // function walks down the kinks in a degenerate portion of a polygon until // it finds a clear geometric result. In the vast majority of cases the loop // will only need one or two iterations. - bool IsConvex(double precision) const { - const int convexity = CCW(left->pos, pos, right->pos, precision); + bool IsConvex(double epsilon) const { + const int convexity = CCW(left->pos, pos, right->pos, epsilon); if (convexity != 0) { return convexity > 0; } if (la::dot(left->pos - pos, right->pos - pos) <= 0) { return true; } - return left->InsideEdge(left->right, precision, true); + return left->InsideEdge(left->right, epsilon, true); } // Subtly different from !IsConvex because IsConvex will return true for // colinear non-folded verts, while IsReflex will always check until actual // certainty is determined. - bool IsReflex(double precision) const { - return !left->InsideEdge(left->right, precision, true); + bool IsReflex(double epsilon) const { + return !left->InsideEdge(left->right, epsilon, true); } // Returns the x-value on this edge corresponding to the start.y value, // returning NAN if the edge does not cross the value from below to above, - // right of start - all within a precision tolerance. If onTop != 0, this - // restricts which end is allowed to terminate within the precision band. - double InterpY2X(vec2 start, int onTop, double precision) const { - if (la::abs(pos.y - start.y) <= precision) { - if (right->pos.y <= start.y + precision || onTop == 1) { + // right of start - all within a epsilon tolerance. If onTop != 0, this + // restricts which end is allowed to terminate within the epsilon band. + double InterpY2X(vec2 start, int onTop, double epsilon) const { + if (la::abs(pos.y - start.y) <= epsilon) { + if (right->pos.y <= start.y + epsilon || onTop == 1) { return NAN; } else { return pos.x; } - } else if (pos.y < start.y - precision) { - if (right->pos.y > start.y + precision) { + } else if (pos.y < start.y - epsilon) { + if (right->pos.y > start.y + epsilon) { return pos.x + (start.y - pos.y) * (right->pos.x - pos.x) / (right->pos.y - pos.y); - } else if (right->pos.y < start.y - precision || onTop == -1) { + } else if (right->pos.y < start.y - epsilon || onTop == -1) { return NAN; } else { return right->pos.x; @@ -453,22 +451,22 @@ class EarClip { // of the ear. Points are valid even when they touch, so long as their edge // goes to the outside. No need to check the other side, since all verts are // processed in the EarCost loop. - double SignedDist(VertItr v, vec2 unit, double precision) const { + double SignedDist(VertItr v, vec2 unit, double epsilon) const { double d = determinant2x2(unit, v->pos - pos); - if (std::abs(d) < precision) { + if (std::abs(d) < epsilon) { double dR = determinant2x2(unit, v->right->pos - pos); - if (std::abs(dR) > precision) return dR; + if (std::abs(dR) > epsilon) return dR; double dL = determinant2x2(unit, v->left->pos - pos); - if (std::abs(dL) > precision) return dL; + if (std::abs(dL) > epsilon) return dL; } return d; } // Find the cost of Vert v within this ear, where openSide is the unit // vector from Verts right to left - passed in for reuse. - double Cost(VertItr v, vec2 openSide, double precision) const { - double cost = std::min(SignedDist(v, rightDir, precision), - SignedDist(v, left->rightDir, precision)); + double Cost(VertItr v, vec2 openSide, double epsilon) const { + double cost = std::min(SignedDist(v, rightDir, epsilon), + SignedDist(v, left->rightDir, epsilon)); const double openCost = determinant2x2(openSide, v->pos - right->pos); return std::min(cost, openCost); @@ -477,8 +475,8 @@ class EarClip { // For verts outside the ear, apply a cost based on the Delaunay condition // to aid in prioritization and produce cleaner triangulations. This doesn't // affect robustness, but may be adjusted to improve output. - static double DelaunayCost(vec2 diff, double scale, double precision) { - return -precision - scale * la::dot(diff, diff); + static double DelaunayCost(vec2 diff, double scale, double epsilon) { + return -epsilon - scale * la::dot(diff, diff); } // This is the expensive part of the algorithm, checking this ear against @@ -486,20 +484,20 @@ class EarClip { // triangulator cost down from O(n^2) to O(nlogn) for most large polygons. // // Think of a cost as vaguely a distance metric - 0 is right on the edge of - // being invalid. cost > precision is definitely invalid. Cost < -precision + // being invalid. cost > epsilon is definitely invalid. Cost < -epsilon // is definitely valid, so all improvement costs are designed to always give - // values < -precision so they will never affect validity. The first + // values < -epsilon so they will never affect validity. The first // totalCost is designed to give priority to sharper angles. Any cost < (-1 - // - precision) has satisfied the Delaunay condition. - double EarCost(double precision, IdxCollider &collider) const { + // - epsilon) has satisfied the Delaunay condition. + double EarCost(double epsilon, IdxCollider &collider) const { vec2 openSide = left->pos - right->pos; const vec2 center = 0.5 * (left->pos + right->pos); const double scale = 4 / la::dot(openSide, openSide); const double radius = la::length(openSide) / 2; openSide = la::normalize(openSide); - double totalCost = la::dot(left->rightDir, rightDir) - 1 - precision; - if (CCW(pos, left->pos, right->pos, precision) == 0) { + double totalCost = la::dot(left->rightDir, rightDir) - 1 - epsilon; + if (CCW(pos, left->pos, right->pos, epsilon) == 0) { // Clip folded ears first return totalCost; } @@ -521,9 +519,9 @@ class EarClip { if (!Clipped(test) && test->mesh_idx != mesh_idx && test->mesh_idx != lid && test->mesh_idx != rid) { // Skip duplicated verts - double cost = Cost(test, openSide, precision); - if (cost < -precision) { - cost = DelaunayCost(test->pos - center, scale, precision); + double cost = Cost(test, openSide, epsilon); + if (cost < -epsilon) { + cost = DelaunayCost(test->pos - center, scale, epsilon); } return cost; } @@ -614,10 +612,10 @@ class EarClip { if (ear->left == ear->right) { return; } - if (ear->IsShort(precision_) || - (CCW(ear->left->pos, ear->pos, ear->right->pos, precision_) == 0 && + if (ear->IsShort(epsilon_) || + (CCW(ear->left->pos, ear->pos, ear->right->pos, epsilon_) == 0 && la::dot(ear->left->pos - ear->pos, ear->right->pos - ear->pos) > 0 && - ear->IsConvex(precision_))) { + ear->IsConvex(epsilon_))) { ClipEar(ear); ClipIfDegenerate(ear->left); ClipIfDegenerate(ear->right); @@ -650,7 +648,7 @@ class EarClip { Link(last, first); } - if (precision_ < 0) precision_ = bBox_.Scale() * kPrecision; + if (epsilon_ < 0) epsilon_ = bBox_.Scale() * kPrecision; // Slightly more than enough, since each hole can cause two extra triangles. triangles_.reserve(polygon_.size() + 2 * starts.size()); @@ -690,7 +688,7 @@ class EarClip { area += areaCompensation; const vec2 size = bBox.Size(); - const double minArea = precision_ * std::max(size.x, size.y); + const double minArea = epsilon_ * std::max(size.x, size.y); if (std::isfinite(maxX) && area < -minArea) { holes_.insert(start); @@ -705,24 +703,24 @@ class EarClip { // All holes must be key-holed (attached to an outer polygon) before ear // clipping can commence. Instead of relying on sorting, which may be - // incorrect due to precision, we check for polygon edges both ahead and + // incorrect due to epsilon, we check for polygon edges both ahead and // behind to ensure all valid options are found. void CutKeyhole(const VertItr start) { const Rect bBox = hole2BBox_[start]; - const int onTop = start->pos.y >= bBox.max.y - precision_ ? 1 - : start->pos.y <= bBox.min.y + precision_ ? -1 - : 0; + const int onTop = start->pos.y >= bBox.max.y - epsilon_ ? 1 + : start->pos.y <= bBox.min.y + epsilon_ ? -1 + : 0; VertItr connector = polygon_.end(); auto CheckEdge = [&](VertItr edge) { - const double x = edge->InterpY2X(start->pos, onTop, precision_); - if (std::isfinite(x) && start->InsideEdge(edge, precision_, true) && + const double x = edge->InterpY2X(start->pos, onTop, epsilon_); + if (std::isfinite(x) && start->InsideEdge(edge, epsilon_, true) && (connector == polygon_.end() || CCW({x, start->pos.y}, connector->pos, connector->right->pos, - precision_) == 1 || + epsilon_) == 1 || (connector->pos.y < edge->pos.y - ? edge->InsideEdge(connector, precision_, false) - : !connector->InsideEdge(edge, precision_, false)))) { + ? edge->InsideEdge(connector, epsilon_, false) + : !connector->InsideEdge(edge, epsilon_, false)))) { connector = edge; } }; @@ -759,19 +757,18 @@ class EarClip { : edge->right->pos.y - start->pos.y > start->pos.y - edge->pos.y ? edge : edge->right; - if (la::abs(connector->pos.y - start->pos.y) <= precision_) { + if (la::abs(connector->pos.y - start->pos.y) <= epsilon_) { return connector; } const double above = connector->pos.y > start->pos.y ? 1 : -1; auto CheckVert = [&](VertItr vert) { const double inside = - above * CCW(start->pos, vert->pos, connector->pos, precision_); - if (vert->pos.x > start->pos.x - precision_ && - vert->pos.y * above > start->pos.y * above - precision_ && + above * CCW(start->pos, vert->pos, connector->pos, epsilon_); + if (vert->pos.x > start->pos.x - epsilon_ && + vert->pos.y * above > start->pos.y * above - epsilon_ && (inside > 0 || (inside == 0 && vert->pos.x < connector->pos.x)) && - vert->InsideEdge(edge, precision_, true) && - vert->IsReflex(precision_)) { + vert->InsideEdge(edge, epsilon_, true) && vert->IsReflex(epsilon_)) { connector = vert; } }; @@ -811,11 +808,11 @@ class EarClip { earsQueue_.erase(v->ear); v->ear = earsQueue_.end(); } - if (v->IsShort(precision_)) { + if (v->IsShort(epsilon_)) { v->cost = kBest; v->ear = earsQueue_.insert(v); - } else if (v->IsConvex(2 * precision_)) { - v->cost = v->EarCost(precision_, collider); + } else if (v->IsConvex(2 * epsilon_)) { + v->cost = v->EarCost(epsilon_, collider); v->ear = earsQueue_.insert(v); } else { v->cost = 1; // not used, but marks reflex verts for debug @@ -823,7 +820,7 @@ class EarClip { } // Create a collider of all vertices in this polygon, each expanded by - // precision_. Each ear uses this BVH to quickly find a subset of vertices to + // epsilon_. Each ear uses this BVH to quickly find a subset of vertices to // check for cost. IdxCollider VertCollider(VertItr start) const { Vec vertBox; @@ -834,7 +831,7 @@ class EarClip { Loop(start, [&vertBox, &vertMorton, &itr, &box, this](VertItr v) { itr.push_back(v); const vec3 pos(v->pos, 0); - vertBox.push_back({pos - precision_, pos + precision_}); + vertBox.push_back({pos - epsilon_, pos + epsilon_}); vertMorton.push_back(Collider::MortonCode(pos, box)); }); @@ -887,7 +884,7 @@ class EarClip { const qItr ear = earsQueue_.begin(); if (ear != earsQueue_.end()) { v = *ear; - // Cost should always be negative, generally < -precision. + // Cost should always be negative, generally < -epsilon. v->PrintVert(); earsQueue_.erase(ear); } else { diff --git a/src/properties.cpp b/src/properties.cpp index 1bef3d524..24f7dbe27 100644 --- a/src/properties.cpp +++ b/src/properties.cpp @@ -24,7 +24,7 @@ using namespace manifold; struct FaceAreaVolume { VecView halfedges; VecView vertPos; - const double precision; + const double epsilon; std::pair operator()(int face) { double perimeter = 0; @@ -229,7 +229,7 @@ bool Manifold::Impl::MatchesTriNormals() const { } /** - * Returns the number of triangles that are colinear within precision_. + * Returns the number of triangles that are colinear within epsilon_. */ int Manifold::Impl::NumDegenerateTris() const { if (halfedge_.size() == 0 || faceNormal_.size() != NumTri()) return true; @@ -300,8 +300,7 @@ void Manifold::Impl::CalculateCurvature(int gaussianIdx, int meanIdx) { /** * Calculates the bounding box of the entire manifold, which is stored - * internally to short-cut Boolean operations and to serve as the precision - * range for Morton code calculation. Ignores NaNs. + * internally to short-cut Boolean operations. Ignores NaNs. */ void Manifold::Impl::CalculateBBox() { bBox_.min = diff --git a/src/sdf.cpp b/src/sdf.cpp index ab806025a..dbe47263a 100644 --- a/src/sdf.cpp +++ b/src/sdf.cpp @@ -444,7 +444,7 @@ namespace manifold { * performance. * @param level You can inset your Mesh by using a positive value, or outset * it with a negative value. - * @param precision Ensure each vertex is within this distance of the true + * @param tolerance Ensure each vertex is within this distance of the true * surface. Defaults to -1, which will return the interpolated * crossing-point based on the two nearest grid points. Small positive values * will require more sdf evaluations per output vertex. @@ -454,10 +454,10 @@ namespace manifold { * active. */ Manifold Manifold::LevelSet(std::function sdf, Box bounds, - double edgeLength, double level, double precision, + double edgeLength, double level, double tolerance, bool canParallel) { - if (precision <= 0) { - precision = std::numeric_limits::infinity(); + if (tolerance <= 0) { + tolerance = std::numeric_limits::infinity(); } auto pImpl_ = std::make_shared(); @@ -494,7 +494,7 @@ Manifold Manifold::LevelSet(std::function sdf, Box bounds, Vec index(1, 0); for_each_n(pol, countAt(0_uz), EncodeIndex(ivec4(gridSize, 1), gridPow), NearSurface({vertPos, index, gridVerts.D(), voxels, sdf, origin, - gridSize, gridPow, spacing, level, precision})); + gridSize, gridPow, spacing, level, tolerance})); if (gridVerts.Full()) { // Resize HashTable const vec3 lastVert = vertPos[index[0] - 1]; @@ -512,7 +512,7 @@ Manifold Manifold::LevelSet(std::function sdf, Box bounds, for_each_n( pol, countAt(0), gridVerts.Size(), ComputeVerts({vertPos, index, gridVerts.D(), voxels, sdf, origin, - gridSize, gridPow, spacing, level, precision})); + gridSize, gridPow, spacing, level, tolerance})); vertPos.resize(index[0]); break; } diff --git a/src/sort.cpp b/src/sort.cpp index 1ef2f6c25..8f7985adf 100644 --- a/src/sort.cpp +++ b/src/sort.cpp @@ -489,8 +489,8 @@ void Manifold::Impl::GatherFaces(const Impl& old, const Vec& faceNew2Old) { * Updates the mergeFromVert and mergeToVert vectors in order to create a * manifold solid. If the MeshGL is already manifold, no change will occur and * the function will return false. Otherwise, this will merge verts along open - * edges within precision (the maximum of the MeshGL precision and the baseline - * bounding-box precision), keeping any from the existing merge vectors. + * edges within tolerance (the maximum of the MeshGL tolerance and the baseline + * bounding-box tolerance), keeping any from the existing merge vectors. * * There is no guarantee the result will be manifold - this is a best-effort * helper function designed primarily to aid in the case where a manifold @@ -507,8 +507,8 @@ bool MeshGL::Merge() { * Updates the mergeFromVert and mergeToVert vectors in order to create a * manifold solid. If the MeshGL is already manifold, no change will occur and * the function will return false. Otherwise, this will merge verts along open - * edges within precision (the maximum of the MeshGL precision and the baseline - * bounding-box precision), keeping any from the existing merge vectors. + * edges within tolerance (the maximum of the MeshGL tolerance and the baseline + * bounding-box tolerance), keeping any from the existing merge vectors. * * There is no guarantee the result will be manifold - this is a best-effort * helper function designed primarily to aid in the case where a manifold diff --git a/test/polygon_test.cpp b/test/polygon_test.cpp index ba11fd293..77b5431a8 100644 --- a/test/polygon_test.cpp +++ b/test/polygon_test.cpp @@ -56,17 +56,17 @@ Polygons Duplicate(Polygons polys) { } void TestPoly(const Polygons &polys, int expectedNumTri, - double precision = -1.0) { + double epsilon = -1.0) { PolygonParams().verbose = options.params.verbose; std::vector triangles; - EXPECT_NO_THROW(triangles = Triangulate(polys, precision)); + EXPECT_NO_THROW(triangles = Triangulate(polys, epsilon)); EXPECT_EQ(triangles.size(), expectedNumTri) << "Basic"; - EXPECT_NO_THROW(triangles = Triangulate(Turn180(polys), precision)); + EXPECT_NO_THROW(triangles = Triangulate(Turn180(polys), epsilon)); EXPECT_EQ(triangles.size(), expectedNumTri) << "Turn 180"; - EXPECT_NO_THROW(triangles = Triangulate(Duplicate(polys), precision)); + EXPECT_NO_THROW(triangles = Triangulate(Duplicate(polys), epsilon)); EXPECT_EQ(triangles.size(), 2 * expectedNumTri) << "Duplicate"; PolygonParams().verbose = false; @@ -75,12 +75,12 @@ void TestPoly(const Polygons &polys, int expectedNumTri, class PolygonTestFixture : public testing::Test { public: Polygons polys; - double precision; + double epsilon; int expectedNumTri; - explicit PolygonTestFixture(Polygons polys, double precision, + explicit PolygonTestFixture(Polygons polys, double epsilon, int expectedNumTri) - : polys(polys), precision(precision), expectedNumTri(expectedNumTri) {} - void TestBody() { TestPoly(polys, expectedNumTri, precision); } + : polys(polys), epsilon(epsilon), expectedNumTri(expectedNumTri) {} + void TestBody() { TestPoly(polys, expectedNumTri, epsilon); } }; void RegisterPolygonTestsFile(const std::string &filename) { @@ -88,7 +88,7 @@ void RegisterPolygonTestsFile(const std::string &filename) { EXPECT_TRUE(f.is_open()); // for each test: - // test name, expectedNumTri, precision, num polygons + // test name, expectedNumTri, epsilon, num polygons // for each polygon: // num points // for each vertex: @@ -97,13 +97,13 @@ void RegisterPolygonTestsFile(const std::string &filename) { // note that we should not have commas in the file std::string name; - double precision, x, y; + double epsilon, x, y; int expectedNumTri, numPolys, numPoints; while (1) { f >> name; if (f.eof()) break; - f >> expectedNumTri >> precision >> numPolys; + f >> expectedNumTri >> epsilon >> numPolys; Polygons polys; for (int i = 0; i < numPolys; i++) { polys.emplace_back(); @@ -116,7 +116,7 @@ void RegisterPolygonTestsFile(const std::string &filename) { testing::RegisterTest( "Polygon", name.c_str(), nullptr, nullptr, __FILE__, __LINE__, [=, polys = std::move(polys)]() -> PolygonTestFixture * { - return new PolygonTestFixture(polys, precision, expectedNumTri); + return new PolygonTestFixture(polys, epsilon, expectedNumTri); }); } f.close(); diff --git a/test/samples_test.cpp b/test/samples_test.cpp index ae4e9be89..3fc2b410d 100644 --- a/test/samples_test.cpp +++ b/test/samples_test.cpp @@ -221,9 +221,9 @@ TEST(Samples, GyroidModule) { CheckGL(gyroid); const Box bounds = gyroid.BoundingBox(); - const double precision = gyroid.GetEpsilon(); - EXPECT_NEAR(bounds.min.z, 0, precision); - EXPECT_NEAR(bounds.max.z, size * std::sqrt(2.0), precision); + const double epsilon = gyroid.GetEpsilon(); + EXPECT_NEAR(bounds.min.z, 0, epsilon); + EXPECT_NEAR(bounds.max.z, size * std::sqrt(2.0), epsilon); CrossSection slice(gyroid.Slice(5)); EXPECT_EQ(slice.NumContour(), 4); diff --git a/test/sdf_test.cpp b/test/sdf_test.cpp index 21ebcfae7..16f00bcf9 100644 --- a/test/sdf_test.cpp +++ b/test/sdf_test.cpp @@ -70,7 +70,7 @@ TEST(SDF, Bounds) { Manifold cubeVoid = Manifold::LevelSet( CubeVoid(), {vec3(-size / 2), vec3(size / 2)}, edgeLength); Box bounds = cubeVoid.BoundingBox(); - const double precision = cubeVoid.GetEpsilon(); + const double epsilon = cubeVoid.GetEpsilon(); #ifdef MANIFOLD_EXPORT if (options.exportModels) ExportMesh("cubeVoid.glb", cubeVoid.GetMeshGL(), {}); @@ -79,12 +79,12 @@ TEST(SDF, Bounds) { EXPECT_EQ(cubeVoid.Status(), Manifold::Error::NoError); EXPECT_EQ(cubeVoid.Genus(), -1); const double outerBound = size / 2 + edgeLength / 2; - EXPECT_NEAR(bounds.min.x, -outerBound, precision); - EXPECT_NEAR(bounds.min.y, -outerBound, precision); - EXPECT_NEAR(bounds.min.z, -outerBound, precision); - EXPECT_NEAR(bounds.max.x, outerBound, precision); - EXPECT_NEAR(bounds.max.y, outerBound, precision); - EXPECT_NEAR(bounds.max.z, outerBound, precision); + EXPECT_NEAR(bounds.min.x, -outerBound, epsilon); + EXPECT_NEAR(bounds.min.y, -outerBound, epsilon); + EXPECT_NEAR(bounds.min.z, -outerBound, epsilon); + EXPECT_NEAR(bounds.max.x, outerBound, epsilon); + EXPECT_NEAR(bounds.max.y, outerBound, epsilon); + EXPECT_NEAR(bounds.max.z, outerBound, epsilon); } TEST(SDF, Bounds2) { @@ -94,7 +94,7 @@ TEST(SDF, Bounds2) { Manifold cubeVoid = Manifold::LevelSet( CubeVoid(), {vec3(-size / 2), vec3(size / 2)}, edgeLength); Box bounds = cubeVoid.BoundingBox(); - const double precision = cubeVoid.GetEpsilon(); + const double epsilon = cubeVoid.GetEpsilon(); #ifdef MANIFOLD_EXPORT if (options.exportModels) ExportMesh("cubeVoid2.glb", cubeVoid.GetMeshGL(), {}); @@ -103,12 +103,12 @@ TEST(SDF, Bounds2) { EXPECT_EQ(cubeVoid.Status(), Manifold::Error::NoError); EXPECT_EQ(cubeVoid.Genus(), -1); const double outerBound = size / 2 + edgeLength / 2; - EXPECT_NEAR(bounds.min.x, -outerBound, precision); - EXPECT_NEAR(bounds.min.y, -outerBound, precision); - EXPECT_NEAR(bounds.min.z, -outerBound, precision); - EXPECT_NEAR(bounds.max.x, outerBound, precision); - EXPECT_NEAR(bounds.max.y, outerBound, precision); - EXPECT_NEAR(bounds.max.z, outerBound, precision); + EXPECT_NEAR(bounds.min.x, -outerBound, epsilon); + EXPECT_NEAR(bounds.min.y, -outerBound, epsilon); + EXPECT_NEAR(bounds.min.z, -outerBound, epsilon); + EXPECT_NEAR(bounds.max.x, outerBound, epsilon); + EXPECT_NEAR(bounds.max.y, outerBound, epsilon); + EXPECT_NEAR(bounds.max.z, outerBound, epsilon); } TEST(SDF, Surface) { @@ -121,7 +121,7 @@ TEST(SDF, Surface) { Manifold cube = Manifold::Cube(vec3(size), true); cube -= cubeVoid; Box bounds = cube.BoundingBox(); - const double precision = cube.GetEpsilon(); + const double epsilon = cube.GetEpsilon(); #ifdef MANIFOLD_EXPORT if (options.exportModels) ExportMesh("cube.gltf", cube.GetMeshGL(), {}); #endif @@ -131,12 +131,12 @@ TEST(SDF, Surface) { auto prop = cube.GetProperties(); EXPECT_NEAR(prop.volume, 8, 0.001); EXPECT_NEAR(prop.surfaceArea, 24, 0.001); - EXPECT_NEAR(bounds.min.x, -1, precision); - EXPECT_NEAR(bounds.min.y, -1, precision); - EXPECT_NEAR(bounds.min.z, -1, precision); - EXPECT_NEAR(bounds.max.x, 1, precision); - EXPECT_NEAR(bounds.max.y, 1, precision); - EXPECT_NEAR(bounds.max.z, 1, precision); + EXPECT_NEAR(bounds.min.x, -1, epsilon); + EXPECT_NEAR(bounds.min.y, -1, epsilon); + EXPECT_NEAR(bounds.min.z, -1, epsilon); + EXPECT_NEAR(bounds.max.x, 1, epsilon); + EXPECT_NEAR(bounds.max.y, 1, epsilon); + EXPECT_NEAR(bounds.max.z, 1, epsilon); } TEST(SDF, Resize) { diff --git a/test/smooth_test.cpp b/test/smooth_test.cpp index bfdec58ce..cb915db76 100644 --- a/test/smooth_test.cpp +++ b/test/smooth_test.cpp @@ -156,12 +156,12 @@ TEST(Smooth, Sphere) { } TEST(Smooth, Precision) { - // Tests face precision of refinement - const double precision = 0.001; + // Tests face tolerance of refinement + const double tolerance = 0.001; const double radius = 10; const double height = 10; Manifold cylinder = Manifold::Cylinder(height, radius, radius, 8); - Manifold smoothed = cylinder.SmoothOut().RefineToTolerance(precision); + Manifold smoothed = cylinder.SmoothOut().RefineToTolerance(tolerance); // Makes an edge bisector, which is the worst case. MeshGL64 out = smoothed.Refine(2).GetMeshGL64(); const int numVert = out.NumVert(); @@ -177,7 +177,7 @@ TEST(Smooth, Precision) { maxR2 = std::max(maxR2, r2); minR2 = std::min(minR2, r2); } - EXPECT_NEAR(std::sqrt(minR2), radius - precision, 1e-4); + EXPECT_NEAR(std::sqrt(minR2), radius - tolerance, 1e-4); EXPECT_NEAR(std::sqrt(maxR2), radius, 1e-8); EXPECT_EQ(smoothed.NumTri(), 7984); #ifdef MANIFOLD_EXPORT