From a410bae1ed6f97e9cfd61e9476f00f0f89305c95 Mon Sep 17 00:00:00 2001 From: Deepak Rangarajan Date: Wed, 27 Oct 2021 13:25:43 -0400 Subject: [PATCH] support for twist in linear extrusion --- include/csg_types.hpp | 3 +- src/csg/levelset_3d.cpp | 11 ++++++- src/csg/parser.cpp | 5 +++ src/csg/tests/levelset/extrude.t.cpp | 48 ++++++++++++++++++++++++++++ src/csg/tests/parser/extrude.t.cpp | 30 +++++++++++++++++ 5 files changed, 95 insertions(+), 2 deletions(-) diff --git a/include/csg_types.hpp b/include/csg_types.hpp index 305e29c..536c1f4 100644 --- a/include/csg_types.hpp +++ b/include/csg_types.hpp @@ -186,6 +186,7 @@ struct LinearExtrude { double height; bool center; std::tuple scale; + std::optional twist; Union group; }; @@ -202,7 +203,7 @@ private: public: std::optional name; - //TODO: Extend support beyond just sphere & cube + // TODO: Extend support beyond just sphere & cube std::tuple cube_size; std::array cube_center; double sphere_radius; diff --git a/src/csg/levelset_3d.cpp b/src/csg/levelset_3d.cpp index 00e8b57..589b092 100644 --- a/src/csg/levelset_3d.cpp +++ b/src/csg/levelset_3d.cpp @@ -137,11 +137,20 @@ 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 XX = xx; + double YY = yy; double ZZ = lin_ext.center ? zz + lin_ext.height / 2 : zz; 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); + if (lin_ext.twist.has_value()) { + double tt = + (lin_ext.twist.value() * ZZ / lin_ext.height) / DEGREES_PER_RADIAN; + XX = std::hypot(xx, yy) * std::cos(std::atan2(yy, xx) - tt); + YY = std::hypot(xx, yy) * std::sin(std::atan2(yy, xx) - tt); + } + + 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/parser.cpp b/src/csg/parser.cpp index cb16963..20f0f0d 100644 --- a/src/csg/parser.cpp +++ b/src/csg/parser.cpp @@ -472,6 +472,11 @@ template <> struct action { auto scale = std::get>(curr_attr["scale"]); lin_ext.scale = {scale[0], scale[1]}; + lin_ext.twist = std::nullopt; + if (curr_attr.count("twist") != 0) { + lin_ext.twist = std::get(curr_attr["twist"]); + } + 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 a9b15b0..cc402c2 100644 --- a/src/csg/tests/levelset/extrude.t.cpp +++ b/src/csg/tests/levelset/extrude.t.cpp @@ -279,4 +279,52 @@ TEST_CASE("sliced torus", "[Levelset Extrude]") { } } +TEST_CASE("linear with twist", "[Levelset Extrude]") { + double height = 10, radius = 1; + auto my_lin_ext = csg::LinearExtrude{.height = height, + .center = false, + .scale = {1, 1}, + .twist = 320, + .group = csg::Union2D()}; + csg::Circle my_cir{.name = std::nullopt, .radius = radius}; + auto my_mat = csg::Mulmatrix2D({{1, 0}}, {{0, 1}}); + my_mat.translation = {2, 0}; + my_mat.group.objs.push_back(my_cir); + my_lin_ext.group.objs.push_back(my_mat); + + SECTION("Not Centered") { + my_lin_ext.center = false; + 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(-1, 0, height / 2)); + CHECK_FALSE(0 < my_levelset(-2.9, 0, height / 2)); + } + + SECTION("Inside") { + CHECK(0 < my_levelset(-1.3, 0, height / 2)); + CHECK_FALSE(0 < my_levelset(-2.7, 0, height / 2)); + } + } + + SECTION("Centered") { + my_lin_ext.center = true; + 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(-1, 0, 0)); + CHECK_FALSE(0 < my_levelset(-2.9, 0, 0)); + } + + SECTION("Inside") { + CHECK(0 < my_levelset(-1.3, 0, 0)); + CHECK_FALSE(0 < my_levelset(-2.7, 0, 0)); + } + } +} + } // namespace diff --git a/src/csg/tests/parser/extrude.t.cpp b/src/csg/tests/parser/extrude.t.cpp index 749e3c1..a13b474 100644 --- a/src/csg/tests/parser/extrude.t.cpp +++ b/src/csg/tests/parser/extrude.t.cpp @@ -19,6 +19,32 @@ scale = [10,1] CHECK(lin_ext.group.objs.size() == 1); CHECK(lin_ext.height == 10); CHECK(lin_ext.center == true); + CHECK(!lin_ext.twist.has_value()); + + 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); +} + +TEST_CASE("linear extrude circle with twist", "[csg]") { + auto st = *csg::parse_csg(R"( +linear_extrude( +height = 10, +center = true, +scale = [10,1], +twist = -100 +) { + circle(r = 1); +} +)"); + auto lin_ext = std::get(st.top.objs.back()); + CHECK(lin_ext.group.objs.size() == 1); + CHECK(lin_ext.height == 10); + CHECK(lin_ext.center == true); + CHECK(lin_ext.twist == -100); auto [Sx, Sy] = lin_ext.scale; CHECK(Sx == 10); @@ -73,6 +99,7 @@ scale = [5, 3] CHECK(lin_ext.group.objs.size() == 2); CHECK(lin_ext.height == 10); CHECK(lin_ext.center == true); + CHECK(!lin_ext.twist.has_value()); auto [Sx, Sy] = lin_ext.scale; CHECK(Sx == 5); @@ -101,6 +128,7 @@ linear_extrude(height = 10, center = false, scale = [5, 3]) { CHECK(lin_ext.group.objs.size() == 2); CHECK(lin_ext.height == 10); CHECK(lin_ext.center == false); + CHECK(!lin_ext.twist.has_value()); auto [Sx, Sy] = lin_ext.scale; CHECK(Sx == 5); @@ -149,6 +177,7 @@ paths = undef); CHECK(lin_ext.group.objs.size() == 1); CHECK(lin_ext.height == 100); CHECK(lin_ext.center == true); + CHECK(!lin_ext.twist.has_value()); auto [Sx, Sy] = lin_ext.scale; CHECK(Sx == 1); @@ -177,6 +206,7 @@ paths = [[0, 1, 2], [3, 4, 5]]); CHECK(lin_ext.group.objs.size() == 1); CHECK(lin_ext.height == 100); CHECK(lin_ext.center == true); + CHECK(!lin_ext.twist.has_value()); auto [Sx, Sy] = lin_ext.scale; CHECK(Sx == 1); -- GitLab