diff --git a/src/csg/impl/csg_types.hpp b/src/csg/impl/csg_types.hpp index c1725fe98ec5318eeb5af4e1f7d56bba6293472b..0cf25494e37ca86160da2dca5fcc540e8b701a65 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 32161382828be434ef26c10eba42d5b325bfe140..1eee5aac2f79b256896eb6a98e088d4e9de5d487 100644 --- a/src/csg/impl/levelset_3d.cpp +++ b/src/csg/impl/levelset_3d.cpp @@ -129,11 +129,16 @@ 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); + // TODO: Support scale + 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); + 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 22417da9231f6743a42ad16c5e8e56851a82d8e2..3e1429bd0d49a76a302b3996514f60640080ce1f 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 5938db2f533bfdf520a8bb6d547e91e23ee99f54..6629bed95950ddcae36bd77531955bf00224360e 100644 --- a/src/csg/tests/levelset/extrude.t.cpp +++ b/src/csg/tests/levelset/extrude.t.cpp @@ -6,8 +6,58 @@ namespace { -TEST_CASE("two shape linear", "[Levelset Extrude]") { - auto my_lin_ext = csg::LinearExtrude(); +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{ + .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); @@ -24,6 +74,8 @@ TEST_CASE("two shape linear", "[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)); @@ -31,8 +83,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 48ab4e01c0de0f8d2273eab3fa7b8353576b2bb7..3cebfeff4a2038a452ea8d4b85a5e2aba3dd9a33 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); @@ -99,11 +108,12 @@ linear_extrude(height = 10, center = false, twist = 5) { auto [xx, yy] = sq.size; CHECK(xx == 4); CHECK(yy == 5); + CHECK(sq.center == false); } 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); }