141 lines
4.9 KiB
C++
141 lines
4.9 KiB
C++
#pragma once
|
|
#include "vde/sdf/sdf_primitives.h"
|
|
#include "vde/sdf/sdf_operations.h"
|
|
#include "vde/core/point.h"
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace vde::sdf {
|
|
using core::Point3D;
|
|
using core::Vector3D;
|
|
|
|
// Forward declaration
|
|
class SdfNode;
|
|
using SdfNodePtr = std::shared_ptr<SdfNode>;
|
|
|
|
/// 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<SdfNodePtr> 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 <typename Fn>
|
|
void visit(Fn&& fn) {
|
|
fn(*this);
|
|
for (auto& c : children) c->visit(std::forward<Fn>(fn));
|
|
}
|
|
|
|
/// Visit all nodes in the tree (const pre-order)
|
|
template <typename Fn>
|
|
void visit(Fn&& fn) const {
|
|
fn(*this);
|
|
for (auto& c : children) c->visit(std::forward<Fn>(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
|