pub struct CSG<S: Clone> {
pub polygons: Vec<Polygon<S>>,
pub geometry: GeometryCollection<Real>,
pub metadata: Option<S>,
}Expand description
The main CSG solid structure. Contains a list of 3D polygons, 2D polylines, and some metadata.
Fields§
§polygons: Vec<Polygon<S>>3D polygons for volumetric shapes
geometry: GeometryCollection<Real>2D geometry
metadata: Option<S>Metadata
Implementations§
Source§impl<S: Clone + Debug + Send + Sync> CSG<S>
impl<S: Clone + Debug + Send + Sync> CSG<S>
Sourcepub fn from_polygons(polygons: &[Polygon<S>]) -> Self
pub fn from_polygons(polygons: &[Polygon<S>]) -> Self
Build a CSG from an existing polygon list
Sourcepub fn to_polygons(&self) -> Vec<Polygon<S>>
pub fn to_polygons(&self) -> Vec<Polygon<S>>
Convert internal polylines into polygons and return along with any existing internal polygons.
Sourcepub fn from_geo(geometry: GeometryCollection<Real>, metadata: Option<S>) -> Self
pub fn from_geo(geometry: GeometryCollection<Real>, metadata: Option<S>) -> Self
Create a CSG that holds only 2D geometry in a geo::GeometryCollection.
Sourcepub fn to_multipolygon(&self) -> MultiPolygon<Real>
pub fn to_multipolygon(&self) -> MultiPolygon<Real>
Take the geo::Polygon’s from the CSG’s geometry collection
pub fn tessellate_2d( outer: &[[Real; 2]], holes: &[&[[Real; 2]]], ) -> Vec<[Point3<Real>; 3]>
Sourcepub fn union(&self, other: &CSG<S>) -> CSG<S>
pub fn union(&self, other: &CSG<S>) -> CSG<S>
Return a new CSG representing union of the two CSG’s.
let c = a.union(b);
+-------+ +-------+
| | | |
| a | | c |
| +--+----+ = | +----+
+----+--+ | +----+ |
| b | | c |
| | | |
+-------+ +-------+Sourcepub fn difference(&self, other: &CSG<S>) -> CSG<S>
pub fn difference(&self, other: &CSG<S>) -> CSG<S>
Return a new CSG representing diffarence of the two CSG’s.
let c = a.difference(b);
+-------+ +-------+
| | | |
| a | | c |
| +--+----+ = | +--+
+----+--+ | +----+
| b |
| |
+-------+Sourcepub fn intersection(&self, other: &CSG<S>) -> CSG<S>
pub fn intersection(&self, other: &CSG<S>) -> CSG<S>
Return a new CSG representing intersection of the two CSG’s.
let c = a.intersect(b);
+-------+
| |
| a |
| +--+----+ = +--+
+----+--+ | +--+
| b |
| |
+-------+Sourcepub fn xor(&self, other: &CSG<S>) -> CSG<S>
pub fn xor(&self, other: &CSG<S>) -> CSG<S>
Return a new CSG representing space in this CSG excluding the space in the other CSG plus the space in the other CSG excluding the space in this CSG.
let c = a.xor(b);
+-------+ +-------+
| | | |
| a | | a |
| +--+----+ = | +--+----+
+----+--+ | +----+--+ |
| b | | |
| | | |
+-------+ +-------+Sourcepub fn transform(&self, mat: &Matrix4<Real>) -> CSG<S>
pub fn transform(&self, mat: &Matrix4<Real>) -> CSG<S>
Apply an arbitrary 3D transform (as a 4x4 matrix) to both polygons and polylines. The polygon z-coordinates and normal vectors are fully transformed in 3D, and the 2D polylines are updated by ignoring the resulting z after transform.
Sourcepub fn translate(&self, x: Real, y: Real, z: Real) -> CSG<S>
pub fn translate(&self, x: Real, y: Real, z: Real) -> CSG<S>
Returns a new CSG translated by x, y, and z.
Sourcepub fn translate_vector(&self, vector: Vector3<Real>) -> CSG<S>
pub fn translate_vector(&self, vector: Vector3<Real>) -> CSG<S>
Returns a new CSG translated by vector.
Sourcepub fn center(&self) -> Self
pub fn center(&self) -> Self
Returns a new CSG translated so that its bounding-box center is at the origin (0,0,0).
Sourcepub fn float(&self) -> Self
pub fn float(&self) -> Self
Translates the CSG so that its bottommost point(s) sit exactly at z=0.
- Shifts all vertices up or down such that the minimum z coordinate of the bounding box becomes 0.
§Example
let csg = CSG::cube(1.0, 1.0, 3.0, None).translate(2.0, 1.0, -2.0);
let floated = csg.float();
assert_eq!(floated.bounding_box().mins.z, 0.0);Sourcepub fn rotate(&self, x_deg: Real, y_deg: Real, z_deg: Real) -> CSG<S>
pub fn rotate(&self, x_deg: Real, y_deg: Real, z_deg: Real) -> CSG<S>
Rotates the CSG by x_degrees, y_degrees, z_degrees
Sourcepub fn scale(&self, sx: Real, sy: Real, sz: Real) -> CSG<S>
pub fn scale(&self, sx: Real, sy: Real, sz: Real) -> CSG<S>
Scales the CSG by scale_x, scale_y, scale_z
Sourcepub fn mirror(&self, plane: Plane) -> Self
pub fn mirror(&self, plane: Plane) -> Self
Reflect (mirror) this CSG about an arbitrary plane plane.
The plane is specified by:
plane.normal = the plane’s normal vector (need not be unit),
plane.w = the dot-product with that normal for points on the plane (offset).
Returns a new CSG whose geometry is mirrored accordingly.
Sourcepub fn distribute_arc(
&self,
count: usize,
radius: Real,
start_angle_deg: Real,
end_angle_deg: Real,
) -> CSG<S>
pub fn distribute_arc( &self, count: usize, radius: Real, start_angle_deg: Real, end_angle_deg: Real, ) -> CSG<S>
Distribute this CSG count times around an arc (in XY plane) of radius,
from start_angle_deg to end_angle_deg.
Returns a new CSG with all copies (their polygons).
Sourcepub fn distribute_linear(
&self,
count: usize,
dir: Vector3<Real>,
spacing: Real,
) -> CSG<S>
pub fn distribute_linear( &self, count: usize, dir: Vector3<Real>, spacing: Real, ) -> CSG<S>
Distribute this CSG count times along a straight line (vector),
each copy spaced by spacing.
E.g. if dir=(1.0,0.0,0.0) and spacing=2.0, you get copies at
x=0, x=2, x=4, … etc.
Sourcepub fn distribute_grid(
&self,
rows: usize,
cols: usize,
dx: Real,
dy: Real,
) -> CSG<S>
pub fn distribute_grid( &self, rows: usize, cols: usize, dx: Real, dy: Real, ) -> CSG<S>
Distribute this CSG in a grid of rows x cols, with spacing dx, dy in XY plane.
top-left or bottom-left depends on your usage of row/col iteration.
Sourcepub fn subdivide_triangles(&self, levels: u32) -> CSG<S>
pub fn subdivide_triangles(&self, levels: u32) -> CSG<S>
Subdivide all polygons in this CSG ‘levels’ times, returning a new CSG. This results in a triangular mesh with more detail.
Sourcepub fn renormalize(&mut self)
pub fn renormalize(&mut self)
Renormalize all polygons in this CSG by re-computing each polygon’s plane and assigning that plane’s normal to all vertices.
Sourcepub fn ray_intersections(
&self,
origin: &Point3<Real>,
direction: &Vector3<Real>,
) -> Vec<(Point3<Real>, Real)>
pub fn ray_intersections( &self, origin: &Point3<Real>, direction: &Vector3<Real>, ) -> Vec<(Point3<Real>, Real)>
Casts a ray defined by origin + t * direction against all triangles
of this CSG and returns a list of (intersection_point, distance),
sorted by ascending distance.
§Parameters
origin: The ray’s start point.direction: The ray’s direction vector.
§Returns
A Vec of (Point3<Real>, Real) where:
Point3<Real>is the intersection coordinate in 3D,Realis the distance (the ray parameter t) fromorigin.
Sourcepub fn bounding_box(&self) -> Aabb
pub fn bounding_box(&self) -> Aabb
Returns a [parry3d::bounding_volume::Aabb] by merging:
- The 3D bounds of all
polygons. - The 2D bounding rectangle of
self.geometry, interpreted at z=0.
Sourcepub fn tessellate(&self) -> CSG<S>
pub fn tessellate(&self) -> CSG<S>
Triangulate each polygon in the CSG returning a CSG containing triangles
Sourcepub fn to_trimesh(&self) -> SharedShape
pub fn to_trimesh(&self) -> SharedShape
Convert the polygons in this CSG to a Parry TriMesh. Useful for collision detection or physics simulations.
Sourcepub fn mass_properties(
&self,
density: Real,
) -> (Real, Point3<Real>, Unit<Quaternion<Real>>)
pub fn mass_properties( &self, density: Real, ) -> (Real, Point3<Real>, Unit<Quaternion<Real>>)
Approximate mass properties using Rapier.
Sourcepub fn to_rigid_body(
&self,
rb_set: &mut RigidBodySet,
co_set: &mut ColliderSet,
translation: Vector3<Real>,
rotation: Vector3<Real>,
density: Real,
) -> RigidBodyHandle
pub fn to_rigid_body( &self, rb_set: &mut RigidBodySet, co_set: &mut ColliderSet, translation: Vector3<Real>, rotation: Vector3<Real>, density: Real, ) -> RigidBodyHandle
Create a Rapier rigid body + collider from this CSG, using
an axis-angle rotation in 3D (the vector’s length is the
rotation in radians, and its direction is the axis).
Source§impl<S> CSG<S>
impl<S> CSG<S>
Sourcepub fn circle(radius: Real, segments: usize, metadata: Option<S>) -> Self
pub fn circle(radius: Real, segments: usize, metadata: Option<S>) -> Self
Creates a 2D circle in the XY plane.
Sourcepub fn right_triangle(width: Real, height: Real, metadata: Option<S>) -> Self
pub fn right_triangle(width: Real, height: Real, metadata: Option<S>) -> Self
Right triangle from (0,0) to (width,0) to (0,height).
Sourcepub fn rounded_rectangle(
width: Real,
height: Real,
corner_radius: Real,
corner_segments: usize,
metadata: Option<S>,
) -> Self
pub fn rounded_rectangle( width: Real, height: Real, corner_radius: Real, corner_segments: usize, metadata: Option<S>, ) -> Self
Rounded rectangle in XY plane, from (0,0) to (width,height) with radius for corners.
corner_segments controls the smoothness of each rounded corner.
Sourcepub fn ellipse(
width: Real,
height: Real,
segments: usize,
metadata: Option<S>,
) -> Self
pub fn ellipse( width: Real, height: Real, segments: usize, metadata: Option<S>, ) -> Self
Ellipse in XY plane, centered at (0,0), with full width width, full height height.
segments is the number of polygon edges approximating the ellipse.
Sourcepub fn regular_ngon(sides: usize, radius: Real, metadata: Option<S>) -> Self
pub fn regular_ngon(sides: usize, radius: Real, metadata: Option<S>) -> Self
Regular N-gon in XY plane, centered at (0,0), with circumscribed radius radius.
sides is how many edges (>=3).
Sourcepub fn trapezoid(
top_width: Real,
bottom_width: Real,
height: Real,
top_offset: Real,
metadata: Option<S>,
) -> Self
pub fn trapezoid( top_width: Real, bottom_width: Real, height: Real, top_offset: Real, metadata: Option<S>, ) -> Self
Trapezoid from (0,0) -> (bottom_width,0) -> (top_width+top_offset,height) -> (top_offset,height) Note: this is a simple shape that can represent many trapezoids or parallelograms.
Sourcepub fn star(
num_points: usize,
outer_radius: Real,
inner_radius: Real,
metadata: Option<S>,
) -> Self
pub fn star( num_points: usize, outer_radius: Real, inner_radius: Real, metadata: Option<S>, ) -> Self
Star shape (typical “spiky star”) with num_points, outer_radius, inner_radius.
The star is centered at (0,0).
Sourcepub fn teardrop_outline(
width: Real,
length: Real,
segments: usize,
metadata: Option<S>,
) -> CSG<S>
pub fn teardrop_outline( width: Real, length: Real, segments: usize, metadata: Option<S>, ) -> CSG<S>
Teardrop shape. A simple approach:
- a circle arc for the “round” top
- it tapers down to a cusp at bottom. This is just one of many possible “teardrop” definitions.
Sourcepub fn egg_outline(
width: Real,
length: Real,
segments: usize,
metadata: Option<S>,
) -> CSG<S>
pub fn egg_outline( width: Real, length: Real, segments: usize, metadata: Option<S>, ) -> CSG<S>
Egg outline. Approximate an egg shape using a parametric approach. This is only a toy approximation. It creates a closed “egg-ish” outline around the origin.
Sourcepub fn squircle(
width: Real,
height: Real,
segments: usize,
metadata: Option<S>,
) -> CSG<S>
pub fn squircle( width: Real, height: Real, segments: usize, metadata: Option<S>, ) -> CSG<S>
Squircle (superellipse) centered at (0,0) with bounding box width×height.
We use an exponent = 4.0 for “classic” squircle shape. segments controls the resolution.
Sourcepub fn keyhole(
circle_radius: Real,
handle_width: Real,
handle_height: Real,
segments: usize,
metadata: Option<S>,
) -> CSG<S>
pub fn keyhole( circle_radius: Real, handle_width: Real, handle_height: Real, segments: usize, metadata: Option<S>, ) -> CSG<S>
Keyhole shape (simple version): a large circle + a rectangle “handle”. This does not have a hole. If you want a literal hole, you’d do difference ops. Here we do union of a circle and a rectangle.
Sourcepub fn reuleaux_polygon(
sides: usize,
diameter: Real,
circle_segments: usize,
metadata: Option<S>,
) -> CSG<S>
pub fn reuleaux_polygon( sides: usize, diameter: Real, circle_segments: usize, metadata: Option<S>, ) -> CSG<S>
Reuleaux polygon (constant–width curve) built as the intersection of
sides equal–radius disks whose centres are the vertices of a regular
n-gon.
sides≥ 3diameterdesired constant width (equals the distance between adjacent vertices, i.e. the polygon’s edge length)circle_segmentshow many segments to use for each disk
For sides == 3 this gives the canonical Reuleaux triangle; for any
larger sides it yields the natural generalisation (odd-sided shapes
retain constant width, even-sided ones do not but are still smooth).
Sourcepub fn ring(
id: Real,
thickness: Real,
segments: usize,
metadata: Option<S>,
) -> CSG<S>
pub fn ring( id: Real, thickness: Real, segments: usize, metadata: Option<S>, ) -> CSG<S>
Ring with inner diameter = id and (radial) thickness = thickness.
Outer diameter = id + 2*thickness. This yields an annulus in the XY plane.
segments controls how smooth the outer/inner circles are.
Internally, we do:
outer = circle(outer_radius)
inner = circle(inner_radius)
ring = outer.difference(inner)
Then we call flatten() to unify into a single shape that has a hole.
Sourcepub fn pie_slice(
radius: Real,
start_angle_deg: Real,
end_angle_deg: Real,
segments: usize,
metadata: Option<S>,
) -> CSG<S>
pub fn pie_slice( radius: Real, start_angle_deg: Real, end_angle_deg: Real, segments: usize, metadata: Option<S>, ) -> CSG<S>
Create a 2D “pie slice” (wedge) in the XY plane.
radius: outer radius of the slice.start_angle_deg: starting angle in degrees (measured from X-axis).end_angle_deg: ending angle in degrees.segments: how many segments to use to approximate the arc.metadata: optional user metadata for this polygon.
Sourcepub fn supershape(
a: Real,
b: Real,
m: Real,
n1: Real,
n2: Real,
n3: Real,
segments: usize,
metadata: Option<S>,
) -> CSG<S>
pub fn supershape( a: Real, b: Real, m: Real, n1: Real, n2: Real, n3: Real, segments: usize, metadata: Option<S>, ) -> CSG<S>
Create a 2D supershape in the XY plane, approximated by segments edges.
The superformula parameters are typically:
r(θ) = [ (|cos(mθ/4)/a|^n2 + |sin(mθ/4)/b|^n3) ^ (-1/n1) ]
Adjust as needed for your use-case.
Sourcepub fn circle_with_keyway(
radius: Real,
segments: usize,
key_width: Real,
key_depth: Real,
metadata: Option<S>,
) -> CSG<S>
pub fn circle_with_keyway( radius: Real, segments: usize, key_width: Real, key_depth: Real, metadata: Option<S>, ) -> CSG<S>
Creates a 2D circle with a rectangular keyway slot cut out on the +X side.
Sourcepub fn circle_with_flat(
radius: Real,
segments: usize,
flat_dist: Real,
metadata: Option<S>,
) -> CSG<S>
pub fn circle_with_flat( radius: Real, segments: usize, flat_dist: Real, metadata: Option<S>, ) -> CSG<S>
Creates a 2D “D” shape (circle with one flat chord).
radius is the circle radius,
flat_dist is how far from the center the flat chord is placed.
- If flat_dist == 0.0 => chord passes through center => a half-circle
- If flat_dist < radius => chord is inside the circle => typical “D” shape
Solve for distance from center using width of flat: let half_c = chord_len / 2.0; let flat_dist = (radiusradius - half_chalf_c).sqrt();
Sourcepub fn circle_with_two_flats(
radius: Real,
segments: usize,
flat_dist: Real,
metadata: Option<S>,
) -> CSG<S>
pub fn circle_with_two_flats( radius: Real, segments: usize, flat_dist: Real, metadata: Option<S>, ) -> CSG<S>
Circle with two parallel flat chords on opposing sides (e.g., “double D” shape).
radius => circle radius
segments => how many segments in the circle approximation
flat_dist => half-distance between flats measured from the center.
- chord at y=+flat_dist and chord at y=-flat_dist
Sourcepub fn airfoil(
code: &str,
chord: Real,
samples: usize,
metadata: Option<S>,
) -> CSG<S>
pub fn airfoil( code: &str, chord: Real, samples: usize, metadata: Option<S>, ) -> CSG<S>
Generate a NACA 4-digit airfoil (e.g. “2412”, “0015”).
code– 4 ASCII digits describing camber, camber-pos, thicknesschord– physical chord length you want (same units as the rest of your model)samples– number of points per surface (≥ 10 is sensible; NP total = 2 × samples + 1)
The function returns a single closed polygon lying in the XY plane with its leading edge at the origin and the chord running along +X.
Sourcepub fn bezier(
control: &[[Real; 2]],
segments: usize,
metadata: Option<S>,
) -> Self
pub fn bezier( control: &[[Real; 2]], segments: usize, metadata: Option<S>, ) -> Self
Sample an arbitrary-degree Bézier curve (de Casteljau). Returns a poly-line (closed if the first = last point).
control: list of 2-D control pointssegments: number of straight-line segments used for the tessellation
Sourcepub fn bspline(
control: &[[Real; 2]],
p: usize,
segments_per_span: usize,
metadata: Option<S>,
) -> Self
pub fn bspline( control: &[[Real; 2]], p: usize, segments_per_span: usize, metadata: Option<S>, ) -> Self
Sample an open-uniform B-spline of arbitrary degree (p) using the
Cox-de Boor recursion. Returns a poly-line (or a filled region if closed).
control: control pointsp: spline degree (e.g. 3 for a cubic)segments_per_span: tessellation resolution inside every knot span
Sourcepub fn involute_gear_2d(
module_: Real,
teeth: usize,
pressure_angle_deg: Real,
clearance: Real,
backlash: Real,
segments_per_flank: usize,
metadata: Option<S>,
) -> CSG<S>
pub fn involute_gear_2d( module_: Real, teeth: usize, pressure_angle_deg: Real, clearance: Real, backlash: Real, segments_per_flank: usize, metadata: Option<S>, ) -> CSG<S>
Involute gear outline (2‑D).
Sourcepub fn cycloidal_gear_2d(
module_: Real,
teeth: usize,
pin_teeth: usize,
clearance: Real,
segments_per_flank: usize,
metadata: Option<S>,
) -> CSG<S>
pub fn cycloidal_gear_2d( module_: Real, teeth: usize, pin_teeth: usize, clearance: Real, segments_per_flank: usize, metadata: Option<S>, ) -> CSG<S>
(Epicyclic) cycloidal gear outline (2‑D).
Sourcepub fn involute_rack_2d(
module_: Real,
num_teeth: usize,
pressure_angle_deg: Real,
clearance: Real,
backlash: Real,
metadata: Option<S>,
) -> CSG<S>
pub fn involute_rack_2d( module_: Real, num_teeth: usize, pressure_angle_deg: Real, clearance: Real, backlash: Real, metadata: Option<S>, ) -> CSG<S>
Linear involute rack profile (lying in the XY plane, pitch‑line on Y = 0).
The returned polygon is CCW and spans num_teeth pitches along +X.
Sourcepub fn cycloidal_rack_2d(
module_: Real,
num_teeth: usize,
generating_radius: Real,
clearance: Real,
segments_per_flank: usize,
metadata: Option<S>,
) -> CSG<S>
pub fn cycloidal_rack_2d( module_: Real, num_teeth: usize, generating_radius: Real, clearance: Real, segments_per_flank: usize, metadata: Option<S>, ) -> CSG<S>
Linear cycloidal rack profile.
The cycloidal rack is generated by rolling a circle of radius r_p along the
rack’s pitch‑line. The flanks become a trochoid; for practical purposes we
approximate with the classic curtate cycloid equations.
Source§impl<S> CSG<S>
impl<S> CSG<S>
Sourcepub fn cube(
width: Real,
length: Real,
height: Real,
metadata: Option<S>,
) -> CSG<S>
pub fn cube( width: Real, length: Real, height: Real, metadata: Option<S>, ) -> CSG<S>
Create a right prism (a box) that spans from (0, 0, 0) to (width, length, height). All dimensions must be >= 0.
Sourcepub fn sphere(
radius: Real,
segments: usize,
stacks: usize,
metadata: Option<S>,
) -> CSG<S>
pub fn sphere( radius: Real, segments: usize, stacks: usize, metadata: Option<S>, ) -> CSG<S>
Construct a sphere with radius, segments, stacks
Sourcepub fn frustum_ptp(
start: Point3<Real>,
end: Point3<Real>,
radius1: Real,
radius2: Real,
segments: usize,
metadata: Option<S>,
) -> CSG<S>
pub fn frustum_ptp( start: Point3<Real>, end: Point3<Real>, radius1: Real, radius2: Real, segments: usize, metadata: Option<S>, ) -> CSG<S>
Constructs a frustum between start and end with bottom radius = radius1 and
top radius = radius2. In the normal case, it creates side quads and cap triangles.
However, if one of the radii is 0 (within EPSILON), then the degenerate face is treated
as a single point and the side is stitched using triangles.
§Parameters
start: the center of the bottom faceend: the center of the top faceradius1: the radius at the bottom faceradius2: the radius at the top facesegments: number of segments around the circle (must be ≥ 3)metadata: optional metadata
§Example
let bottom = Point3::new(0.0, 0.0, 0.0);
let top = Point3::new(0.0, 0.0, 5.0);
// This will create a cone (bottom degenerate) because radius1 is 0:
let cone = CSG::frustum_ptp_special(bottom, top, 0.0, 2.0, 32, None);Sourcepub fn frustum(
radius1: Real,
radius2: Real,
height: Real,
segments: usize,
metadata: Option<S>,
) -> CSG<S>
pub fn frustum( radius1: Real, radius2: Real, height: Real, segments: usize, metadata: Option<S>, ) -> CSG<S>
A helper to create a vertical cylinder along Z from z=0..z=height with the specified radius (NOT diameter).
Sourcepub fn cylinder(
radius: Real,
height: Real,
segments: usize,
metadata: Option<S>,
) -> CSG<S>
pub fn cylinder( radius: Real, height: Real, segments: usize, metadata: Option<S>, ) -> CSG<S>
A helper to create a vertical cylinder along Z from z=0..z=height
Sourcepub fn polyhedron(
points: &[[Real; 3]],
faces: &[Vec<usize>],
metadata: Option<S>,
) -> CSG<S>
pub fn polyhedron( points: &[[Real; 3]], faces: &[Vec<usize>], metadata: Option<S>, ) -> CSG<S>
Creates a CSG polyhedron from raw vertex data (points) and face indices.
§Parameters
points: a slice of[x,y,z]coordinates.faces: each element is a list of indices intopoints, describing one face. Each face must have at least 3 indices.
§Example
let pts = &[
[0.0, 0.0, 0.0], // point0
[1.0, 0.0, 0.0], // point1
[1.0, 1.0, 0.0], // point2
[0.0, 1.0, 0.0], // point3
[0.5, 0.5, 1.0], // point4 - top
];
// Two faces: bottom square [0,1,2,3], and a pyramid side [0,1,4]
let fcs = vec![
vec![0, 1, 2, 3],
vec![0, 1, 4],
vec![1, 2, 4],
vec![2, 3, 4],
vec![3, 0, 4],
];
let csg_poly = CSG::polyhedron(pts, &fcs);Sourcepub fn egg(
width: Real,
length: Real,
revolve_segments: usize,
outline_segments: usize,
metadata: Option<S>,
) -> Self
pub fn egg( width: Real, length: Real, revolve_segments: usize, outline_segments: usize, metadata: Option<S>, ) -> Self
Creates a 3D “egg” shape by revolving the existing 2D egg_outline profile.
§Parameters
width: The “width” of the 2D egg outline.length: The “length” (height) of the 2D egg outline.revolve_segments: Number of segments for the revolution.outline_segments: Number of segments for the 2D egg outline itself.metadata: Optional metadata.
Sourcepub fn teardrop(
width: Real,
length: Real,
revolve_segments: usize,
shape_segments: usize,
metadata: Option<S>,
) -> Self
pub fn teardrop( width: Real, length: Real, revolve_segments: usize, shape_segments: usize, metadata: Option<S>, ) -> Self
Creates a 3D “teardrop” solid by revolving the existing 2D teardrop profile 360° around the Y-axis (via rotate_extrude).
§Parameters
width: Width of the 2D teardrop profile.length: Length of the 2D teardrop profile.revolve_segments: Number of segments for the revolution (the “circular” direction).shape_segments: Number of segments for the 2D teardrop outline itself.metadata: Optional metadata.
Sourcepub fn teardrop_cylinder(
width: Real,
length: Real,
height: Real,
shape_segments: usize,
metadata: Option<S>,
) -> Self
pub fn teardrop_cylinder( width: Real, length: Real, height: Real, shape_segments: usize, metadata: Option<S>, ) -> Self
Creates a 3D “teardrop cylinder” by extruding the existing 2D teardrop in the Z+ axis.
§Parameters
width: Width of the 2D teardrop profile.length: Length of the 2D teardrop profile.revolve_segments: Number of segments for the revolution (the “circular” direction).shape_segments: Number of segments for the 2D teardrop outline itself.metadata: Optional metadata.
Sourcepub fn ellipsoid(
rx: Real,
ry: Real,
rz: Real,
segments: usize,
stacks: usize,
metadata: Option<S>,
) -> Self
pub fn ellipsoid( rx: Real, ry: Real, rz: Real, segments: usize, stacks: usize, metadata: Option<S>, ) -> Self
Creates an ellipsoid by taking a sphere of radius=1 and scaling it by (rx, ry, rz).
§Parameters
rx: X-axis radius.ry: Y-axis radius.rz: Z-axis radius.segments: Number of horizontal segments.stacks: Number of vertical stacks.metadata: Optional metadata.
Sourcepub fn arrow(
start: Point3<Real>,
direction: Vector3<Real>,
segments: usize,
orientation: bool,
metadata: Option<S>,
) -> CSG<S>
pub fn arrow( start: Point3<Real>, direction: Vector3<Real>, segments: usize, orientation: bool, metadata: Option<S>, ) -> CSG<S>
Creates an arrow CSG. The arrow is composed of:
- a cylindrical shaft, and
- a cone–like head (a frustum from a larger base to a small tip)
built along the canonical +Z axis. The arrow is then rotated so that +Z aligns with the given
direction, and finally translated so that either its base (if
orientationis false) or its tip (iforientationis true) is located atstart.
The arrow’s dimensions (shaft radius, head dimensions, etc.) are scaled proportionally to the total arrow length (the norm of the provided direction).
§Parameters
start: the reference point (base or tip, depending on orientation)direction: the vector defining arrow length and intended pointing directionsegments: number of segments for approximating the cylinder and frustumorientation: when false (default) the arrow points away from start (its base is at start); when true the arrow points toward start (its tip is at start).metadata: optional metadata for the generated polygons.
Sourcepub fn gyroid(
&self,
resolution: usize,
period: Real,
iso_value: Real,
metadata: Option<S>,
) -> CSG<S>
pub fn gyroid( &self, resolution: usize, period: Real, iso_value: Real, metadata: Option<S>, ) -> CSG<S>
Generate a Triply Periodic Minimal Surface (Gyroid) inside the volume of self.
§Parameters
resolution: how many sampling steps along each axis (larger = finer mesh).period: controls the spatial period of the gyroid function. Larger = repeats more slowly.iso_value: the implicit surface is f(x,y,z) = iso_value. Usually 0.0 for a “standard” gyroid.
§Returns
A new CSG whose polygons approximate the gyroid surface inside the volume of self.
§Example
// Suppose `shape` is a CSG volume, e.g. a box or sphere.
let gyroid_csg = shape.tpms_gyroid(50, 2.0, 0.0);pub fn spur_gear_involute( module_: Real, teeth: usize, pressure_angle_deg: Real, clearance: Real, backlash: Real, segments_per_flank: usize, thickness: Real, metadata: Option<S>, ) -> CSG<S>
pub fn spur_gear_cycloid( module_: Real, teeth: usize, pin_teeth: usize, clearance: Real, segments_per_flank: usize, thickness: Real, metadata: Option<S>, ) -> CSG<S>
pub fn helical_involute_gear( module_: Real, teeth: usize, pressure_angle_deg: Real, clearance: Real, backlash: Real, segments_per_flank: usize, thickness: Real, helix_angle_deg: Real, slices: usize, metadata: Option<S>, ) -> CSG<S>
Source§impl<S> CSG<S>
impl<S> CSG<S>
Sourcepub fn extrude(&self, height: Real) -> CSG<S>
pub fn extrude(&self, height: Real) -> CSG<S>
Linearly extrude this (2D) shape in the +Z direction by height.
This is just a convenience wrapper around extrude_vector using Vector3::new(0.0, 0.0, height)
Sourcepub fn extrude_vector(&self, direction: Vector3<Real>) -> CSG<S>
pub fn extrude_vector(&self, direction: Vector3<Real>) -> CSG<S>
Linearly extrude any 2D geometry (Polygons, MultiPolygons, or sub-geometries
in a GeometryCollection) in self.geometry along the given direction.
Builds top, bottom, and side polygons in 3D, storing them in csg.polygons.
Returns a new CSG containing these extruded polygons (plus any existing 3D polygons
you already had in self.polygons).
Sourcepub fn extrude_between(
bottom: &Polygon<S>,
top: &Polygon<S>,
flip_bottom_polygon: bool,
) -> CSG<S>
pub fn extrude_between( bottom: &Polygon<S>, top: &Polygon<S>, flip_bottom_polygon: bool, ) -> CSG<S>
Extrudes (or “lofts”) a closed 3D volume between two polygons in space.
bottomandtopeach have the same number of verticesn, in matching order.- Returns a new CSG whose faces are:
- The
bottompolygon, - The
toppolygon, nrectangular side polygons bridging each edge ofbottomto the corresponding edge oftop.
- The
Sourcepub fn rotate_extrude(&self, angle_degs: Real, segments: usize) -> CSG<S>
pub fn rotate_extrude(&self, angle_degs: Real, segments: usize) -> CSG<S>
Rotate-extrude (revolve) only the Polygon and MultiPolygon geometry in self.geometry
around the Y-axis from 0..angle_degs in segments steps, producing side walls
in an orientation consistent with the polygon’s winding.
- Ignores
self.polygons. - Returns a new CSG containing only the newly extruded side polygons (no end caps).
angle_degs: how far to revolve, in degrees (e.g. 360 for a full revolve).segments: number of subdivisions around the revolve.
§Key Points
- Only 2D geometry in
self.geometryis used. Anyself.polygonsare ignored. - Axis of revolution: Y-axis. We treat each ring’s (x,y) -> revolve_around_y(x,y,theta).
- Exterior rings (CCW in Geo) produce outward-facing side polygons.
- Interior rings (CW) produce inward-facing side polygons (“holes”).
- If
angle_degs < 360, we add two caps: one at angle=0, one at angle=angle_degs.- Cap orientation is set so that normals face outward, consistent with a solid.
- Returns a new CSG with
.polygonscontaining only the side walls + any caps. The.geometryis empty, i.e.GeometryCollection::default().
Source§impl<S: Clone + Debug + Send + Sync> CSG<S>
impl<S: Clone + Debug + Send + Sync> CSG<S>
Sourcepub fn to_stl_ascii(&self, name: &str) -> String
pub fn to_stl_ascii(&self, name: &str) -> String
Export to ASCII STL
- 3D polygons in
self.polygons, - any 2D Polygons or MultiPolygons in
self.geometry(tessellated in XY).
Convert this CSG to an ASCII STL string with the given name.
let csg = CSG::cube(None);
let stl_text = csg.to_stl("my_solid");
println!("{}", stl_text);Sourcepub fn to_stl_binary(&self, _name: &str) -> Result<Vec<u8>>
pub fn to_stl_binary(&self, _name: &str) -> Result<Vec<u8>>
Export to BINARY STL (returns Vec
Convert this CSG to a binary STL byte vector with the given name.
The resulting Vec<u8> can then be written to a file or handled in memory:
let bytes = csg.to_stl_binary("my_solid")?;
std::fs::write("my_solid.stl", bytes)?;Source§impl<S: Clone + Debug + Send + Sync> CSG<S>
impl<S: Clone + Debug + Send + Sync> CSG<S>
Source§impl<S> CSG<S>
impl<S> CSG<S>
Sourcepub fn flatten(&self) -> CSG<S>
pub fn flatten(&self) -> CSG<S>
Flattens any 3D polygons by projecting them onto the XY plane (z=0), unifies them into one or more 2D polygons, and returns a purely 2D CSG.
- If this CSG is already 2D (
self.polygonsis empty), just returnsself.clone(). - Otherwise, all
polygonsare tessellated, projected into XY, and unioned. - We also union any existing 2D geometry (
self.geometry). - The output has
.polygonsempty and.geometrycontaining the final 2D shape.
Sourcepub fn slice(&self, plane: Plane) -> CSG<S>
pub fn slice(&self, plane: Plane) -> CSG<S>
Slice this solid by a given plane, returning a new CSG whose polygons
are either:
- The polygons that lie exactly in the slicing plane (coplanar), or
- Polygons formed by the intersection edges (each a line, possibly open or closed).
The returned CSG can contain:
- Closed polygons that are coplanar,
- Open polygons (poly-lines) if the plane cuts through edges,
- Potentially closed loops if the intersection lines form a cycle.
§Example
let cylinder = CSG::cylinder(1.0, 2.0, 32, None);
let plane_z0 = Plane { normal: Vector3::z(), w: 0.0 };
let cross_section = cylinder.slice(plane_z0);
// `cross_section` will contain:
// - Possibly an open or closed polygon(s) at z=0
// - Or empty if no intersectionSourcepub fn is_manifold(&self) -> bool
pub fn is_manifold(&self) -> bool
Checks if the CSG object is manifold.
This function defines a comparison function which takes EPSILON into account for Real coordinates, builds a hashmap key from the string representation of the coordinates, tessellates the CSG polygons, gathers each of their three edges, counts how many times each edge appears across all triangles, and returns true if every edge appears exactly 2 times, else false.
We should also check that all faces have consistent orientation and no neighbors have flipped normals.
We should also check for zero-area triangles
§Returns
true: If the CSG object is manifold.false: If the CSG object is not manifold.
Source§impl<S> CSG<S>
impl<S> CSG<S>
Sourcepub fn text(
text: &str,
font_data: &[u8],
scale: Real,
metadata: Option<S>,
) -> Self
pub fn text( text: &str, font_data: &[u8], scale: Real, metadata: Option<S>, ) -> Self
Create 2D text (outlines only) in the XY plane using ttf-utils + ttf-parser.
Each glyph’s closed contours become one or more Polygons (with holes if needed),
and any open contours become LineStrings.
§Arguments
text: the text string (no multiline logic here)font_data: raw bytes of a TTF filescale: a uniform scale factor for glyphsmetadata: optional metadata for the resultingCSG
§Returns
A CSG whose geometry contains:
- One or more
Polygons for each glyph, - A set of
LineStrings for any open contours (rare in standard fonts), all positioned in the XY plane at z=0.
Source§impl<S: Clone + Debug + Send + Sync> CSG<S>
impl<S: Clone + Debug + Send + Sync> CSG<S>
Sourcepub fn convex_hull(&self) -> CSG<S>
pub fn convex_hull(&self) -> CSG<S>
Compute the convex hull of all vertices in this CSG.
Sourcepub fn minkowski_sum(&self, other: &CSG<S>) -> CSG<S>
pub fn minkowski_sum(&self, other: &CSG<S>) -> CSG<S>
Compute the Minkowski sum: self ⊕ other
Naive approach: Take every vertex in self, add it to every vertex in other,
then compute the convex hull of all resulting points.
Source§impl<S> CSG<S>
impl<S> CSG<S>
Sourcepub fn sdf<F>(
sdf: F,
resolution: (usize, usize, usize),
min_pt: Point3<Real>,
max_pt: Point3<Real>,
iso_value: Real,
metadata: Option<S>,
) -> CSG<S>
pub fn sdf<F>( sdf: F, resolution: (usize, usize, usize), min_pt: Point3<Real>, max_pt: Point3<Real>, iso_value: Real, metadata: Option<S>, ) -> CSG<S>
Return a CSG created by meshing a signed distance field within a bounding box
// Example SDF for a sphere of radius 1.5 centered at (0,0,0)
let my_sdf = |p: &Point3
let resolution = (60, 60, 60); let min_pt = Point3::new(-2.0, -2.0, -2.0); let max_pt = Point3::new( 2.0, 2.0, 2.0); let iso_value = 0.0; // Typically zero for SDF-based surfaces
let csg_shape = CSG::from_sdf(my_sdf, resolution, min_pt, max_pt, iso_value);
// Now csg_shape is your polygon mesh as a CSG you can union, subtract, or export:
let _ = std::fs::write(“stl/sdf_sphere.stl”, csg_shape.to_stl_binary(“sdf_sphere”).unwrap());
Source§impl<S> CSG<S>
impl<S> CSG<S>
Sourcepub fn metaballs2d(
balls: &[(Point2<Real>, Real)],
resolution: (usize, usize),
iso_value: Real,
padding: Real,
metadata: Option<S>,
) -> CSG<S>
pub fn metaballs2d( balls: &[(Point2<Real>, Real)], resolution: (usize, usize), iso_value: Real, padding: Real, metadata: Option<S>, ) -> CSG<S>
Create a 2D metaball iso-contour in XY plane from a set of 2D metaballs.
balls: array of (center, radius).resolution: (nx, ny) grid resolution for marching squares.iso_value: threshold for the iso-surface.padding: extra boundary beyond each ball’s radius.metadata: optional user metadata.
Sourcepub fn metaballs(
balls: &[MetaBall],
resolution: (usize, usize, usize),
iso_value: Real,
padding: Real,
metadata: Option<S>,
) -> CSG<S>
pub fn metaballs( balls: &[MetaBall], resolution: (usize, usize, usize), iso_value: Real, padding: Real, metadata: Option<S>, ) -> CSG<S>
Creates a CSG from a list of metaballs by sampling a 3D grid and using marching cubes.
balls: slice of metaball definitions (center + radius).resolution: (nx, ny, nz) defines how many steps along x, y, z.iso_value: threshold at which the isosurface is extracted.padding: extra margin around the bounding region (e.g. 0.5) so the surface doesn’t get truncated.
Trait Implementations§
Auto Trait Implementations§
impl<S> Freeze for CSG<S>where
S: Freeze,
impl<S> RefUnwindSafe for CSG<S>where
S: RefUnwindSafe,
impl<S> Send for CSG<S>where
S: Send,
impl<S> Sync for CSG<S>where
S: Sync,
impl<S> Unpin for CSG<S>where
S: Unpin,
impl<S> UnwindSafe for CSG<S>where
S: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.