#pragma once #include "vde/sdf/sdf_primitives.h" #include "vde/sdf/sdf_operations.h" #include "vde/core/point.h" #include #include #include namespace vde::sdf { using core::Point3D; using core::Vector3D; // Forward declaration class SdfNode; using SdfNodePtr = std::shared_ptr; /// All node types in the CSG tree enum class SdfOp : uint8_t { // Primitives Sphere, Box, RoundBox, Torus, Capsule, Cylinder, Cone, Plane, Ellipsoid, TriangularPrism, HexPrism, Link, Wedge, // Boolean CSG Union, Intersection, Difference, SmoothUnion, SmoothIntersection, SmoothDifference, // Modifiers Round, Onion, // Domain transforms Repeat, MirrorX, MirrorY, MirrorZ, Translate, Rotate, Scale, Twist, Bend, Elongate, CheapBend, // Displacement Displace }; /// Parameter payload — one struct to rule them all struct SdfParams { // Primitives double radius = 1.0; Point3D extents = Point3D(1, 1, 1); Point3D pt_a = Point3D(0, -1, 0); Point3D pt_b = Point3D(0, 1, 0); double major_radius = 1.0; double minor_radius = 0.3; double angle_rad = 0.5; double height = 2.0; double thickness = 0.1; Vector3D normal = Vector3D(0, 1, 0); double offset = 0.0; // Operations double blend_k = 0.2; double amount = 0.5; double amplitude = 0.1; double frequency = 1.0; Point3D repeat_cell = Point3D(2, 2, 2); Point3D translate_offset = Point3D(0, 0, 0); Point3D scale_factors = Point3D(1, 1, 1); }; /// A single node in the SDF expression tree class SdfNode { public: SdfOp op; SdfParams params; std::vector children; std::string name; // ── Primitive factories ── static SdfNodePtr sphere(double r); static SdfNodePtr box(const Point3D& half_extents); static SdfNodePtr round_box(const Point3D& half_extents, double r); static SdfNodePtr cylinder(double r, double h); static SdfNodePtr torus(double major_r, double minor_r); static SdfNodePtr capsule(const Point3D& a, const Point3D& b, double r); static SdfNodePtr cone(double angle_rad, double h); static SdfNodePtr plane(const Vector3D& normal, double offset); static SdfNodePtr ellipsoid(const Point3D& radii); static SdfNodePtr triangular_prism(double h); static SdfNodePtr hex_prism(double h); static SdfNodePtr link(double r, double length, double thickness); static SdfNodePtr wedge(const Point3D& extents); // ── Boolean CSG factories (two children) ── static SdfNodePtr op_union(SdfNodePtr a, SdfNodePtr b); static SdfNodePtr op_intersection(SdfNodePtr a, SdfNodePtr b); static SdfNodePtr op_difference(SdfNodePtr a, SdfNodePtr b); static SdfNodePtr smooth_union(SdfNodePtr a, SdfNodePtr b, double k); static SdfNodePtr smooth_intersection(SdfNodePtr a, SdfNodePtr b, double k); static SdfNodePtr smooth_difference(SdfNodePtr a, SdfNodePtr b, double k); // ── Modifier factories (one child) ── static SdfNodePtr round(SdfNodePtr child, double r); static SdfNodePtr onion(SdfNodePtr child, double thickness); // ── Domain transform factories (one child) ── static SdfNodePtr repeat(SdfNodePtr child, const Point3D& cell); static SdfNodePtr mirror_x(SdfNodePtr child); static SdfNodePtr mirror_y(SdfNodePtr child); static SdfNodePtr mirror_z(SdfNodePtr child); static SdfNodePtr translate(SdfNodePtr child, const Point3D& offset); static SdfNodePtr rotate(SdfNodePtr child, double angle_rad); static SdfNodePtr scale(SdfNodePtr child, const Point3D& factors); static SdfNodePtr twist(SdfNodePtr child, double amount); static SdfNodePtr bend(SdfNodePtr child, double amount); static SdfNodePtr elongate(SdfNodePtr child, const Point3D& h); static SdfNodePtr cheap_bend(SdfNodePtr child, double amount); static SdfNodePtr displace(SdfNodePtr child, double amplitude, double frequency); /// Visit all nodes in the tree (pre-order) template void visit(Fn&& fn) { fn(*this); for (auto& c : children) c->visit(std::forward(fn)); } /// Visit all nodes in the tree (const pre-order) template void visit(Fn&& fn) const { fn(*this); for (auto& c : children) c->visit(std::forward(fn)); } public: explicit SdfNode(SdfOp o) : op(o) {} }; /// Evaluate the SDF tree at a point in world space /// Returns signed distance: negative = inside, positive = outside [[nodiscard]] double evaluate(const SdfNodePtr& root, const Point3D& p); /// Estimate bounding box of the SDF tree /// Returns the half-extent from center to corner (bounding radius) [[nodiscard]] Point3D estimate_bounds(const SdfNodePtr& root, double margin = 1.0); /// Compute full AABB from estimate_bounds result struct SdfBBox { Point3D min; Point3D max; }; [[nodiscard]] SdfBBox estimate_bbox(const SdfNodePtr& root, double margin = 1.0); } // namespace vde::sdf