Loading include/csg_types.hpp +30 −1 Original line number Diff line number Diff line Loading @@ -106,6 +106,7 @@ template <Dimension dim> struct Intersection; template <Dimension dim> struct Difference; struct LinearExtrude; struct RotateExtrude; struct Hull; template <Dimension dim> struct TypeHelper; Loading @@ -120,7 +121,7 @@ template <> struct TypeHelper<Dimension::D3> { using Type = std::variant<Sphere, Cube, Cylinder, Cone, Union<Dimension::D3>, Intersection<Dimension::D3>, Difference<Dimension::D3>, Mulmatrix<Dimension::D3>, LinearExtrude, RotateExtrude, Polyhedron>; LinearExtrude, RotateExtrude, Polyhedron, Hull>; }; template <Dimension dim> struct Union { Loading Loading @@ -193,6 +194,34 @@ struct RotateExtrude { Union<Dimension::D2> group; }; struct Hull { private: std::shared_ptr<cgal_helper::Polyhedron> m_cgal_polyhedron; std::shared_ptr<cgal_helper::AABBTree> m_cgal_aabb_tree; public: std::optional<std::string> name; //TODO: Extend support beyond just sphere & cube std::tuple<double, double, double> cube_size; std::array<double, 3> cube_center; double sphere_radius; void generate_polyhedron() { m_cgal_polyhedron = cgal_helper::create_polyhedron_from_hull( cube_size, cube_center, sphere_radius); m_cgal_aabb_tree = cgal_helper::create_aabb_tree(m_cgal_polyhedron); } const std::shared_ptr<cgal_helper::Polyhedron> &cgal_polyhedron() const { return m_cgal_polyhedron; } const std::shared_ptr<cgal_helper::AABBTree> &cgal_aabb_tree() const { return m_cgal_aabb_tree; } }; struct Tree { Union<Dimension::D3> top; }; Loading src/csg/cgal_helper_polyhedron.cpp +39 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,8 @@ #include <CGAL/Polyhedron_incremental_builder_3.h> #include <CGAL/algorithm.h> #include <CGAL/boost/graph/graph_traits_Polyhedron_3.h> #include <CGAL/convex_hull_3.h> #include <CGAL/point_generators_3.h> namespace { Loading Loading @@ -96,4 +98,41 @@ bool inside(const std::shared_ptr<AABBTree> &tree, double xx, double yy, return inside_tester(pt) == CGAL::ON_BOUNDED_SIDE; } std::shared_ptr<Polyhedron> create_polyhedron_from_hull(const std::tuple<double, double, double> &cube_size, const std::array<double, 3> &cube_center, double sphere_radius) { // This is currently chosen somewhat arbitrarily // based on manual testing and CGAL examples // TODO: Is this sufficient? const int NUM_SAMPLING_PTS = 250; auto p = std::make_shared<Polyhedron>(); std::list<cgal_helper::CK::Point_3> points; CGAL::Random_points_on_sphere_3<cgal_helper::CK::Point_3> s(sphere_radius); std::copy_n(s, NUM_SAMPLING_PTS, std::back_inserter(points)); CGAL::Random_points_in_cube_3<cgal_helper::CK::Point_3> c(1.0); std::list<cgal_helper::CK::Point_3> points_c; std::copy_n(c, NUM_SAMPLING_PTS, std::back_inserter(points_c)); auto [sa, sb, sc] = cube_size; const cgal_helper::CK::Aff_transformation_3 transf( sa / 2, 0.0, 0.0, cube_center[0], 0.0, sb / 2, 0.0, cube_center[1], 0.0, 0.0, sc / 2, cube_center[2]); std::transform(points_c.begin(), points_c.end(), points_c.begin(), transf); points.insert(points.end(), points_c.begin(), points_c.end()); // compute convex hull of non-collinear points CGAL::convex_hull_3(points.begin(), points.end(), *p); CGAL_assertion(p->is_valid()); return p; } } // namespace cgal_helper src/csg/levelset_3d.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ double signed_distance_3d(const Type3D &, double, double, double); double signed_distance_3d(const LinearExtrude &, double, double, double); double signed_distance_3d(const RotateExtrude &, double, double, double); double signed_distance_3d(const Polyhedron &, double, double, double); double signed_distance_3d(const Hull &, double, double, double); double signed_distance_2d(const Union2D &, double, double); Loading Loading @@ -170,6 +171,11 @@ double signed_distance_3d(const Polyhedron &polyhedron, double xx, double yy, : -1.0; } double signed_distance_3d(const Hull &hull, double xx, double yy, double zz) { // TODO: support signed distance instead of -1.0/1.0 return cgal_helper::inside(hull.cgal_aabb_tree(), xx, yy, zz) ? 1.0 : -1.0; } double signed_distance_3d(const Type3D &obj, double xx, double yy, double zz) { return std::visit( Loading src/csg/parser.cpp +42 −1 Original line number Diff line number Diff line Loading @@ -171,6 +171,10 @@ struct extrude_lin : seq<string<'l', 'i', 'n', 'e', 'a', 'r', '_', 'e', 'x', L_FUN, attr_list, R_FUN, L_BLK<Dimension::D2>, obj_list<Dimension::D2>, R_BLK<Dimension::D2>> {}; struct hull : seq<string<'h', 'u', 'l', 'l'>, L_FUN, R_FUN, L_BLK<Dimension::D3>, obj_list<Dimension::D3>, R_BLK<Dimension::D3>> {}; struct render : seq<string<'r', 'e', 'n', 'd', 'e', 'r'>, L_FUN, attr_list, R_FUN, opt<seq<L_BLK<Dimension::D3>, obj_list<Dimension::D3>, Loading @@ -184,7 +188,7 @@ struct colorgroup : seq<string<'c', 'o', 'l', 'o', 'r'>, L_FUN, vector, R_FUN, template <Dimension dim> struct csg_obj : sor<shape<dim>, mulmat<dim>, bool_exp<dim>, group<dim>, extrude_lin, extrude_rot, render, colorgroup> {}; extrude_lin, extrude_rot, hull, render, colorgroup> {}; template <Dimension dim> struct obj_list : plus<pad<csg_obj<dim>, space>> {}; Loading Loading @@ -485,6 +489,43 @@ template <> struct action<extrude_rot> { } }; template <> struct action<hull> { template <typename Input> static void apply(const Input &in, parser_state &st) { std::stringstream ss(in.string()); csg::Hull hull; // Only a very limited hull is currently supported if (st.current_3d_group.size() == 2) { auto &obj0 = st.current_3d_group[0]; auto &obj1 = st.current_3d_group[1]; if (std::holds_alternative<csg::Mulmatrix3D>(obj0) and std::holds_alternative<csg::Sphere>(obj1)) { auto &mm = std::get<csg::Mulmatrix3D>(obj0); if (mm.group.objs.size() == 1 and std::holds_alternative<csg::Cube>(mm.group.objs[0])) { auto &cub = std::get<csg::Cube>(mm.group.objs[0]); if (cub.center) { hull.cube_size = cub.size; hull.cube_center = mm.translation; hull.sphere_radius = std::get<csg::Sphere>(obj1).radius; hull.generate_polyhedron(); st.current_3d_objs.back().push_back(hull); return; } } } } // If the conditions were not met and throw exception std::string except_src = "action<hull>"; std::string except_msg = "hull() support is limited to a multmatrix of a centered cube followed " "by a sphere; added for the CLR support"; throw csg::Exception(except_src, except_msg); } }; std::optional<std::string> get_name(AttrMap curr_attr) { if (curr_attr.count("$name")) { auto quoted_name = std::get<std::string>(curr_attr["$name"]); Loading src/csg/tests/CMakeLists.txt +2 −0 Original line number Diff line number Diff line Loading @@ -5,11 +5,13 @@ add_executable(unit_tests_csg EXCLUDE_FROM_ALL levelset/boolean.t.cpp levelset/extrude.t.cpp levelset/hull.t.cpp levelset/internal_flow.t.cpp levelset/primitives.t.cpp levelset/transform.t.cpp parser/boolean.t.cpp parser/extrude.t.cpp parser/hull.t.cpp parser/nest.cpp parser/other.t.cpp parser/primitives.t.cpp Loading Loading
include/csg_types.hpp +30 −1 Original line number Diff line number Diff line Loading @@ -106,6 +106,7 @@ template <Dimension dim> struct Intersection; template <Dimension dim> struct Difference; struct LinearExtrude; struct RotateExtrude; struct Hull; template <Dimension dim> struct TypeHelper; Loading @@ -120,7 +121,7 @@ template <> struct TypeHelper<Dimension::D3> { using Type = std::variant<Sphere, Cube, Cylinder, Cone, Union<Dimension::D3>, Intersection<Dimension::D3>, Difference<Dimension::D3>, Mulmatrix<Dimension::D3>, LinearExtrude, RotateExtrude, Polyhedron>; LinearExtrude, RotateExtrude, Polyhedron, Hull>; }; template <Dimension dim> struct Union { Loading Loading @@ -193,6 +194,34 @@ struct RotateExtrude { Union<Dimension::D2> group; }; struct Hull { private: std::shared_ptr<cgal_helper::Polyhedron> m_cgal_polyhedron; std::shared_ptr<cgal_helper::AABBTree> m_cgal_aabb_tree; public: std::optional<std::string> name; //TODO: Extend support beyond just sphere & cube std::tuple<double, double, double> cube_size; std::array<double, 3> cube_center; double sphere_radius; void generate_polyhedron() { m_cgal_polyhedron = cgal_helper::create_polyhedron_from_hull( cube_size, cube_center, sphere_radius); m_cgal_aabb_tree = cgal_helper::create_aabb_tree(m_cgal_polyhedron); } const std::shared_ptr<cgal_helper::Polyhedron> &cgal_polyhedron() const { return m_cgal_polyhedron; } const std::shared_ptr<cgal_helper::AABBTree> &cgal_aabb_tree() const { return m_cgal_aabb_tree; } }; struct Tree { Union<Dimension::D3> top; }; Loading
src/csg/cgal_helper_polyhedron.cpp +39 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,8 @@ #include <CGAL/Polyhedron_incremental_builder_3.h> #include <CGAL/algorithm.h> #include <CGAL/boost/graph/graph_traits_Polyhedron_3.h> #include <CGAL/convex_hull_3.h> #include <CGAL/point_generators_3.h> namespace { Loading Loading @@ -96,4 +98,41 @@ bool inside(const std::shared_ptr<AABBTree> &tree, double xx, double yy, return inside_tester(pt) == CGAL::ON_BOUNDED_SIDE; } std::shared_ptr<Polyhedron> create_polyhedron_from_hull(const std::tuple<double, double, double> &cube_size, const std::array<double, 3> &cube_center, double sphere_radius) { // This is currently chosen somewhat arbitrarily // based on manual testing and CGAL examples // TODO: Is this sufficient? const int NUM_SAMPLING_PTS = 250; auto p = std::make_shared<Polyhedron>(); std::list<cgal_helper::CK::Point_3> points; CGAL::Random_points_on_sphere_3<cgal_helper::CK::Point_3> s(sphere_radius); std::copy_n(s, NUM_SAMPLING_PTS, std::back_inserter(points)); CGAL::Random_points_in_cube_3<cgal_helper::CK::Point_3> c(1.0); std::list<cgal_helper::CK::Point_3> points_c; std::copy_n(c, NUM_SAMPLING_PTS, std::back_inserter(points_c)); auto [sa, sb, sc] = cube_size; const cgal_helper::CK::Aff_transformation_3 transf( sa / 2, 0.0, 0.0, cube_center[0], 0.0, sb / 2, 0.0, cube_center[1], 0.0, 0.0, sc / 2, cube_center[2]); std::transform(points_c.begin(), points_c.end(), points_c.begin(), transf); points.insert(points.end(), points_c.begin(), points_c.end()); // compute convex hull of non-collinear points CGAL::convex_hull_3(points.begin(), points.end(), *p); CGAL_assertion(p->is_valid()); return p; } } // namespace cgal_helper
src/csg/levelset_3d.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ double signed_distance_3d(const Type3D &, double, double, double); double signed_distance_3d(const LinearExtrude &, double, double, double); double signed_distance_3d(const RotateExtrude &, double, double, double); double signed_distance_3d(const Polyhedron &, double, double, double); double signed_distance_3d(const Hull &, double, double, double); double signed_distance_2d(const Union2D &, double, double); Loading Loading @@ -170,6 +171,11 @@ double signed_distance_3d(const Polyhedron &polyhedron, double xx, double yy, : -1.0; } double signed_distance_3d(const Hull &hull, double xx, double yy, double zz) { // TODO: support signed distance instead of -1.0/1.0 return cgal_helper::inside(hull.cgal_aabb_tree(), xx, yy, zz) ? 1.0 : -1.0; } double signed_distance_3d(const Type3D &obj, double xx, double yy, double zz) { return std::visit( Loading
src/csg/parser.cpp +42 −1 Original line number Diff line number Diff line Loading @@ -171,6 +171,10 @@ struct extrude_lin : seq<string<'l', 'i', 'n', 'e', 'a', 'r', '_', 'e', 'x', L_FUN, attr_list, R_FUN, L_BLK<Dimension::D2>, obj_list<Dimension::D2>, R_BLK<Dimension::D2>> {}; struct hull : seq<string<'h', 'u', 'l', 'l'>, L_FUN, R_FUN, L_BLK<Dimension::D3>, obj_list<Dimension::D3>, R_BLK<Dimension::D3>> {}; struct render : seq<string<'r', 'e', 'n', 'd', 'e', 'r'>, L_FUN, attr_list, R_FUN, opt<seq<L_BLK<Dimension::D3>, obj_list<Dimension::D3>, Loading @@ -184,7 +188,7 @@ struct colorgroup : seq<string<'c', 'o', 'l', 'o', 'r'>, L_FUN, vector, R_FUN, template <Dimension dim> struct csg_obj : sor<shape<dim>, mulmat<dim>, bool_exp<dim>, group<dim>, extrude_lin, extrude_rot, render, colorgroup> {}; extrude_lin, extrude_rot, hull, render, colorgroup> {}; template <Dimension dim> struct obj_list : plus<pad<csg_obj<dim>, space>> {}; Loading Loading @@ -485,6 +489,43 @@ template <> struct action<extrude_rot> { } }; template <> struct action<hull> { template <typename Input> static void apply(const Input &in, parser_state &st) { std::stringstream ss(in.string()); csg::Hull hull; // Only a very limited hull is currently supported if (st.current_3d_group.size() == 2) { auto &obj0 = st.current_3d_group[0]; auto &obj1 = st.current_3d_group[1]; if (std::holds_alternative<csg::Mulmatrix3D>(obj0) and std::holds_alternative<csg::Sphere>(obj1)) { auto &mm = std::get<csg::Mulmatrix3D>(obj0); if (mm.group.objs.size() == 1 and std::holds_alternative<csg::Cube>(mm.group.objs[0])) { auto &cub = std::get<csg::Cube>(mm.group.objs[0]); if (cub.center) { hull.cube_size = cub.size; hull.cube_center = mm.translation; hull.sphere_radius = std::get<csg::Sphere>(obj1).radius; hull.generate_polyhedron(); st.current_3d_objs.back().push_back(hull); return; } } } } // If the conditions were not met and throw exception std::string except_src = "action<hull>"; std::string except_msg = "hull() support is limited to a multmatrix of a centered cube followed " "by a sphere; added for the CLR support"; throw csg::Exception(except_src, except_msg); } }; std::optional<std::string> get_name(AttrMap curr_attr) { if (curr_attr.count("$name")) { auto quoted_name = std::get<std::string>(curr_attr["$name"]); Loading
src/csg/tests/CMakeLists.txt +2 −0 Original line number Diff line number Diff line Loading @@ -5,11 +5,13 @@ add_executable(unit_tests_csg EXCLUDE_FROM_ALL levelset/boolean.t.cpp levelset/extrude.t.cpp levelset/hull.t.cpp levelset/internal_flow.t.cpp levelset/primitives.t.cpp levelset/transform.t.cpp parser/boolean.t.cpp parser/extrude.t.cpp parser/hull.t.cpp parser/nest.cpp parser/other.t.cpp parser/primitives.t.cpp Loading