From aa3074fcac3d88114a0779012d3434433d072f2b Mon Sep 17 00:00:00 2001 From: Deepak Rangarajan Date: Tue, 19 May 2020 17:39:49 -0400 Subject: [PATCH 1/5] support linear extrude height & scale --- src/csg/impl/csg_types.hpp | 3 ++- src/csg/impl/levelset_3d.cpp | 17 +++++++++---- src/csg/impl/parser.cpp | 3 ++- src/csg/tests/levelset/extrude.t.cpp | 36 +++++++++++++++++++++++++--- src/csg/tests/parser/extrude.t.cpp | 23 ++++++++++++------ 5 files changed, 65 insertions(+), 17 deletions(-) diff --git a/src/csg/impl/csg_types.hpp b/src/csg/impl/csg_types.hpp index c1725fe..0cf2549 100644 --- a/src/csg/impl/csg_types.hpp +++ b/src/csg/impl/csg_types.hpp @@ -131,10 +131,11 @@ public: const matrix::Mat2d &rotation_inv() const { return m_rotation_inv; } }; +// TODO: Support twist & slices struct LinearExtrude { double height; bool center; - double twist; + std::tuple scale; Union group; }; diff --git a/src/csg/impl/levelset_3d.cpp b/src/csg/impl/levelset_3d.cpp index 3216138..8256860 100644 --- a/src/csg/impl/levelset_3d.cpp +++ b/src/csg/impl/levelset_3d.cpp @@ -129,11 +129,18 @@ double signed_distance_3d(const Cylinder &cyl, double xx, double yy, double signed_distance_3d(const LinearExtrude &lin_ext, double xx, double yy, double zz) { - // TODO: support height, center and twist - double sign_z = (0 <= zz && zz <= lin_ext.height) - ? 1.0 - : 1.0; // unused zz warning workaround - return sign_z * signed_distance_2d(lin_ext.group, xx, yy); + double ZZ = lin_ext.center ? zz + lin_ext.height / 2 : zz; + auto [Sx, Sy] = lin_ext.scale; + double XX = xx / Sx; + double YY = yy / Sy; + double sign_z = (ZZ >= 0 && ZZ <= lin_ext.height) ? -1.0 : 1.0; + auto dist_z = std::min(std::fabs(ZZ), std::fabs(ZZ - lin_ext.height)); + + auto sd_2d = signed_distance_2d(lin_ext.group, XX, YY); + double sign_2d = sd_2d >= 0 ? -1.0 : 1.0; + auto dist_2d = std::fabs(sd_2d); + + return EXTERNAL_FLOW * std::max(sign_z * dist_z, sign_2d * dist_2d); } double signed_distance_3d(const RotateExtrude &rot_ext, double xx, double yy, diff --git a/src/csg/impl/parser.cpp b/src/csg/impl/parser.cpp index 22417da..3e1429b 100644 --- a/src/csg/impl/parser.cpp +++ b/src/csg/impl/parser.cpp @@ -431,7 +431,8 @@ template <> struct action { auto &curr_attr = st.curr_attrs.back(); lin_ext.height = std::get(curr_attr["height"]); lin_ext.center = std::get(curr_attr["center"]); - lin_ext.twist = std::get(curr_attr["twist"]); + auto scale = std::get>(curr_attr["scale"]); + lin_ext.scale = {scale[0], scale[1]}; for (const auto &curr_obj : st.current_2d_group) { lin_ext.group.objs.push_back(curr_obj); diff --git a/src/csg/tests/levelset/extrude.t.cpp b/src/csg/tests/levelset/extrude.t.cpp index 5938db2..19e9569 100644 --- a/src/csg/tests/levelset/extrude.t.cpp +++ b/src/csg/tests/levelset/extrude.t.cpp @@ -6,8 +6,38 @@ namespace { -TEST_CASE("two shape linear", "[Levelset Extrude]") { +TEST_CASE("linear extrude pyramid", "[Levelset Extrude]") { auto my_lin_ext = csg::LinearExtrude(); + my_lin_ext.height = 10; + my_lin_ext.center = false; + my_lin_ext.scale = {0, 0}; + + csg::Square my_sq{.name = std::nullopt, .size = {10, 10}, .center = true}; + my_lin_ext.group.objs.push_back(my_sq); + + auto my_tree = std::make_shared(); + my_tree->top.objs.push_back(my_lin_ext); + csg::CsgIF my_levelset(my_tree); + + SECTION("Outside") { + CHECK_FALSE(0 < my_levelset(5.01, 0.01, 0.01)); + CHECK_FALSE(0 < my_levelset(0.01, 2.6, 5)); + CHECK_FALSE(0 < my_levelset(-0.01, -2.6, 5)); + CHECK_FALSE(0 < my_levelset(0, 0, 10.01)); + } + SECTION("Inside") { + CHECK_FALSE(0 < my_levelset(4.9, 0.01, 0.01)); + CHECK_FALSE(0 < my_levelset(0.01, 2.2, 5)); + CHECK_FALSE(0 < my_levelset(-0.01, -2.2, 5)); + CHECK_FALSE(0 < my_levelset(0, 0, 9.99)); + } +} + +TEST_CASE("two shape linear extrude", "[Levelset Extrude]") { + auto my_lin_ext = csg::LinearExtrude(); + my_lin_ext.height = 100; + my_lin_ext.center = true; + my_lin_ext.scale = {1, 1}; csg::Circle my_cir{.name = std::nullopt, .radius = 1}; my_lin_ext.group.objs.push_back(my_cir); @@ -31,8 +61,8 @@ TEST_CASE("two shape linear", "[Levelset Extrude]") { CHECK(0 < my_levelset(-0.5, 0, 0)); CHECK(0 < my_levelset(4.5, 0, 0)); CHECK(0 < my_levelset(3.5, 0, 0)); - CHECK(0 < my_levelset(3.5, 0, 100)); - CHECK(0 < my_levelset(3.5, 0, -100)); + CHECK(0 < my_levelset(3.5, 0, 49)); + CHECK(0 < my_levelset(3.5, 0, -49)); } } diff --git a/src/csg/tests/parser/extrude.t.cpp b/src/csg/tests/parser/extrude.t.cpp index 48ab4e0..f674af8 100644 --- a/src/csg/tests/parser/extrude.t.cpp +++ b/src/csg/tests/parser/extrude.t.cpp @@ -10,7 +10,7 @@ TEST_CASE("linear extrude", "[csg]") { linear_extrude( height = 10, center = true, -twist = 0 +scale = [10,1] ) { circle(r = 1); } @@ -19,7 +19,10 @@ twist = 0 CHECK(lin_ext.group.objs.size() == 1); CHECK(lin_ext.height == 10); CHECK(lin_ext.center == true); - CHECK(lin_ext.twist == 0); + + auto [Sx, Sy] = lin_ext.scale; + CHECK(Sx == 10); + CHECK(Sy == 1); auto cir = std::get(lin_ext.group.objs.at(0)); CHECK(cir.radius == 1); @@ -48,7 +51,7 @@ TEST_CASE("extrude two shapes", "[csg]") { linear_extrude( height = 10, center = true, -twist = 0 +scale = [5, 3] ) { circle(r = 1); square(size = [2, 2], center = false); @@ -59,7 +62,10 @@ twist = 0 CHECK(lin_ext.group.objs.size() == 2); CHECK(lin_ext.height == 10); CHECK(lin_ext.center == true); - CHECK(lin_ext.twist == 0); + + auto [Sx, Sy] = lin_ext.scale; + CHECK(Sx == 5); + CHECK(Sy == 3); auto cir = std::get(lin_ext.group.objs.at(0)); CHECK(cir.radius == 1); @@ -72,7 +78,7 @@ twist = 0 TEST_CASE("extrude with mulmatrix", "[csg]") { auto st = *csg::parse_csg(R"( -linear_extrude(height = 10, center = false, twist = 5) { +linear_extrude(height = 10, center = false, scale = [5, 3]) { circle(r = 2); multmatrix([[1, 0, 0, 5], [0, 1, 0, 5], [0, 0, 1, 0], [0, 0, 0, 1]]) { square(size = [4, 5], center = false); @@ -84,7 +90,10 @@ linear_extrude(height = 10, center = false, twist = 5) { CHECK(lin_ext.group.objs.size() == 2); CHECK(lin_ext.height == 10); CHECK(lin_ext.center == false); - CHECK(lin_ext.twist == 5); + + auto [Sx, Sy] = lin_ext.scale; + CHECK(Sx == 5); + CHECK(Sy == 3); auto cir = std::get(lin_ext.group.objs.at(0)); CHECK(cir.radius == 2); @@ -103,7 +112,7 @@ linear_extrude(height = 10, center = false, twist = 5) { TEST_CASE("extrude with 3D object", "[csg]") { auto st = csg::parse_csg(R"( -linear_extrude(height = 10, center = false, twist = 5) { +linear_extrude(height = 10, center = false, scale = [5, 5]) { multmatrix([[1, 0, 0, 5], [0, 1, 0, 5], [0, 0, 1, 0], [0, 0, 0, 1]]) { sphere(r = 8); } -- GitLab From 3b94e03a73a4db786ccf8f3792cd18b39a838156 Mon Sep 17 00:00:00 2001 From: Deepak Rangarajan Date: Tue, 19 May 2020 18:09:27 -0400 Subject: [PATCH 2/5] Remove scale levelset support since it doesn't work --- src/csg/impl/levelset_3d.cpp | 6 ++---- src/csg/tests/levelset/extrude.t.cpp | 27 --------------------------- 2 files changed, 2 insertions(+), 31 deletions(-) diff --git a/src/csg/impl/levelset_3d.cpp b/src/csg/impl/levelset_3d.cpp index 8256860..1eee5aa 100644 --- a/src/csg/impl/levelset_3d.cpp +++ b/src/csg/impl/levelset_3d.cpp @@ -129,14 +129,12 @@ double signed_distance_3d(const Cylinder &cyl, double xx, double yy, double signed_distance_3d(const LinearExtrude &lin_ext, double xx, double yy, double zz) { + // TODO: Support scale double ZZ = lin_ext.center ? zz + lin_ext.height / 2 : zz; - auto [Sx, Sy] = lin_ext.scale; - double XX = xx / Sx; - double YY = yy / Sy; double sign_z = (ZZ >= 0 && ZZ <= lin_ext.height) ? -1.0 : 1.0; auto dist_z = std::min(std::fabs(ZZ), std::fabs(ZZ - lin_ext.height)); - auto sd_2d = signed_distance_2d(lin_ext.group, XX, YY); + auto sd_2d = signed_distance_2d(lin_ext.group, xx, yy); double sign_2d = sd_2d >= 0 ? -1.0 : 1.0; auto dist_2d = std::fabs(sd_2d); diff --git a/src/csg/tests/levelset/extrude.t.cpp b/src/csg/tests/levelset/extrude.t.cpp index 19e9569..9851ba6 100644 --- a/src/csg/tests/levelset/extrude.t.cpp +++ b/src/csg/tests/levelset/extrude.t.cpp @@ -6,33 +6,6 @@ namespace { -TEST_CASE("linear extrude pyramid", "[Levelset Extrude]") { - auto my_lin_ext = csg::LinearExtrude(); - my_lin_ext.height = 10; - my_lin_ext.center = false; - my_lin_ext.scale = {0, 0}; - - csg::Square my_sq{.name = std::nullopt, .size = {10, 10}, .center = true}; - my_lin_ext.group.objs.push_back(my_sq); - - auto my_tree = std::make_shared(); - my_tree->top.objs.push_back(my_lin_ext); - csg::CsgIF my_levelset(my_tree); - - SECTION("Outside") { - CHECK_FALSE(0 < my_levelset(5.01, 0.01, 0.01)); - CHECK_FALSE(0 < my_levelset(0.01, 2.6, 5)); - CHECK_FALSE(0 < my_levelset(-0.01, -2.6, 5)); - CHECK_FALSE(0 < my_levelset(0, 0, 10.01)); - } - SECTION("Inside") { - CHECK_FALSE(0 < my_levelset(4.9, 0.01, 0.01)); - CHECK_FALSE(0 < my_levelset(0.01, 2.2, 5)); - CHECK_FALSE(0 < my_levelset(-0.01, -2.2, 5)); - CHECK_FALSE(0 < my_levelset(0, 0, 9.99)); - } -} - TEST_CASE("two shape linear extrude", "[Levelset Extrude]") { auto my_lin_ext = csg::LinearExtrude(); my_lin_ext.height = 100; -- GitLab From edd4a62a6d7e4f5fc5df80389a1a553c9bd6beb5 Mon Sep 17 00:00:00 2001 From: Deepak Rangarajan Date: Tue, 19 May 2020 18:11:56 -0400 Subject: [PATCH 3/5] more checks in test --- src/csg/tests/levelset/extrude.t.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/csg/tests/levelset/extrude.t.cpp b/src/csg/tests/levelset/extrude.t.cpp index 9851ba6..5207434 100644 --- a/src/csg/tests/levelset/extrude.t.cpp +++ b/src/csg/tests/levelset/extrude.t.cpp @@ -27,6 +27,8 @@ TEST_CASE("two shape linear extrude", "[Levelset Extrude]") { SECTION("Outside") { CHECK_FALSE(0 < my_levelset(0, 2, 0)); CHECK_FALSE(0 < my_levelset(-4, 0, 0)); + CHECK_FALSE(0 < my_levelset(3.5, 0, 51)); + CHECK_FALSE(0 < my_levelset(3.5, 0, -51)); } SECTION("Inside") { CHECK(0 < my_levelset(0, 0, 0)); -- GitLab From 367c5e51e4465ed33e563991e081972a4082b87c Mon Sep 17 00:00:00 2001 From: Deepak Rangarajan Date: Tue, 19 May 2020 18:15:01 -0400 Subject: [PATCH 4/5] one more check --- src/csg/tests/parser/extrude.t.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/csg/tests/parser/extrude.t.cpp b/src/csg/tests/parser/extrude.t.cpp index f674af8..3cebfef 100644 --- a/src/csg/tests/parser/extrude.t.cpp +++ b/src/csg/tests/parser/extrude.t.cpp @@ -108,6 +108,7 @@ linear_extrude(height = 10, center = false, scale = [5, 3]) { auto [xx, yy] = sq.size; CHECK(xx == 4); CHECK(yy == 5); + CHECK(sq.center == false); } TEST_CASE("extrude with 3D object", "[csg]") { -- GitLab From c2f86aa527404a0159e13c9a01bd09835e29701e Mon Sep 17 00:00:00 2001 From: Deepak Rangarajan Date: Tue, 19 May 2020 18:36:21 -0400 Subject: [PATCH 5/5] Add test --- src/csg/tests/levelset/extrude.t.cpp | 55 ++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/src/csg/tests/levelset/extrude.t.cpp b/src/csg/tests/levelset/extrude.t.cpp index 5207434..6629bed 100644 --- a/src/csg/tests/levelset/extrude.t.cpp +++ b/src/csg/tests/levelset/extrude.t.cpp @@ -6,11 +6,58 @@ namespace { +TEST_CASE("linear", "[Levelset Extrude]") { + double height = 100, radius = 10; + auto my_lin_ext = csg::LinearExtrude{ + .height = 100, .center = false, .scale = {1, 1}, .group = csg::Union2D()}; + csg::Circle my_cir{.name = std::nullopt, .radius = 10}; + + SECTION("Not centered") { + my_lin_ext.center = false; + my_lin_ext.group.objs.push_back(my_cir); + auto my_tree = std::make_shared(); + my_tree->top.objs.push_back(my_lin_ext); + csg::CsgIF my_levelset(my_tree); + + SECTION("Outside") { + CHECK_FALSE(0 < my_levelset(0, radius * 0.99, -0.01 * height)); + CHECK_FALSE(0 < my_levelset(0, radius * 1.01, 0.01 * height)); + CHECK_FALSE(0 < my_levelset(0, radius * 0.99, 1.01 * height)); + CHECK_FALSE(0 < my_levelset(radius * 0.99, 0, 1.01 * height)); + } + SECTION("Inside") { + CHECK(0 < my_levelset(0, radius * 0.99, 0.01 * height)); + CHECK(0 < my_levelset(radius * 0.99, 0, 0.01 * height)); + CHECK(0 < my_levelset(0, radius * 0.99, 0.99 * height)); + CHECK(0 < my_levelset(radius * 0.99, 0, 0.99 * height)); + } + } + + SECTION("Centered") { + my_lin_ext.center = true; + my_lin_ext.group.objs.push_back(my_cir); + auto my_tree = std::make_shared(); + my_tree->top.objs.push_back(my_lin_ext); + csg::CsgIF my_levelset(my_tree); + + SECTION("Outside") { + CHECK_FALSE(0 < my_levelset(0, radius * 0.99, -1.01 * height / 2)); + CHECK_FALSE(0 < my_levelset(0, radius * 1.01, 0.01 * height)); + CHECK_FALSE(0 < my_levelset(0, radius * 0.99, 1.01 * height / 2)); + CHECK_FALSE(0 < my_levelset(radius * 0.99, 0, 1.01 * height / 2)); + } + SECTION("Inside") { + CHECK(0 < my_levelset(0, radius * 0.99, -0.99 * height / 2)); + CHECK(0 < my_levelset(radius * 0.99, 0, 0.01 * height / 2)); + CHECK(0 < my_levelset(0, radius * 0.99, 0.99 * height / 2)); + CHECK(0 < my_levelset(radius * 0.99, 0, 0.99 * height / 2)); + } + } +} + TEST_CASE("two shape linear extrude", "[Levelset Extrude]") { - auto my_lin_ext = csg::LinearExtrude(); - my_lin_ext.height = 100; - my_lin_ext.center = true; - my_lin_ext.scale = {1, 1}; + auto my_lin_ext = csg::LinearExtrude{ + .height = 100, .center = true, .scale = {1, 1}, .group = csg::Union2D()}; csg::Circle my_cir{.name = std::nullopt, .radius = 1}; my_lin_ext.group.objs.push_back(my_cir); -- GitLab