scadman
scadman is a Rust library for generating OpenSCAD code programmatically. It provides a
type-safe and structured way to define 2D and 3D geometric objects, apply transformations
and operations, and output valid OpenSCAD code.
What is this library?
Instead of writing OpenSCAD code directly in .scad files, scadman allows you to define
your parametric models using Rust code. This approach leverages Rust's strong typing,
module system, testing capabilities, and build tools to manage your designs.
The library represents OpenSCAD primitives, modifiers, and blocks as distinct Rust types,
wrapped within a unified ScadObject structure. It provides traits and helper functions
to build, combine, and transform these objects, handling the complexities of OpenSCAD
syntax generation, including parameter formatting, object nesting, and indentation.
Features
- Type-Safe Object Model: Define 2D, 3D, and mixed-dimension objects using a clear
type hierarchy (
ScadObject2D,ScadObject3D,ScadObjectMixed) wrapped inScadObject. - Comprehensive Primitive Support: Create basic shapes like
square,circle,sphere,cube,cylinder,polygon,polyhedron,text, andimport. - Extensive Modifier Support: Apply transformations and operations such as
translate,rotate,scale,resize,mirror,multmatrix,offset,projection,color,hull,render,children,linear_extrude,rotate_extrude, etc. - Boolean and Block Operations: Combine objects using
union,difference, andintersection. Blocks ({ ... }) are also explicitly supported. - Operator Overloading: Use standard Rust operators (
+,-,*) forunion,difference, andintersectionoperations onScadObjects of the same dimension. - Comment Support: Easily add comments to individual objects or blocks using the
.commented()method or dedicated factory functions. - Builder Pattern: Many complex primitives and modifiers provide a type-safe builder
pattern (
...Builder) for configuring optional parameters. - Value Handling: Type-safe representation and formatting for various OpenSCAD value
types (numbers, vectors, strings, booleans, angles, colors, matrices) via the
ScadDisplaytrait. - Code Generation: Generate clean, correctly indented OpenSCAD code strings from your
Rust object structures using the
to_code()method. - Prelude: A convenient
preludemodule to easily import commonly used items and factory functions.
Installation
Add this to your Cargo.toml:
[]
= { = "v0.3.0", = "https://github.com/lum1narie/scadman.git" }
Basic Usage
Import the prelude to get access to common types and functions:
use *;
Creating Primitives
Use the primitive_2d or primitive_3d factory functions with the corresponding builder or
direct value:
// Create a square with size 10
let square = primitive_2d;
println!;
// Output: square(size = 10);
// Create a sphere with radius 5 using the builder
let sphere = primitive_3d;
println!;
// Output: sphere(r = 5);
// Create a cylinder with height 10 and radius 3
let cylinder = primitive_3d;
println!;
// Output: cylinder(h = 10, r = 3);
Applying Modifiers
Use the modifier_2d, modifier_3d, or modifier_mixed factory functions. Note that
modifiers check the dimension compatibility of their child object (except for mixed
modifiers like color).
// Translate the square by (5, 5)
let translated_square = modifier_2d;
println!;
/* Output:
translate([5, 5])
square(size = 10);
*/
// Rotate the sphere by 90 degrees around the Y axis
let rotated_sphere = modifier_3d;
println!;
/* Output:
rotate(a = [0, 90, 0])
sphere(r = 5);
*/
// Apply a color modifier (mixed dimension)
let colored_cylinder = modifier_mixed;
println!;
/* Output:
color(c = [1, 0, 0])
cylinder(h = 10, r = 3);
*/
Using Blocks and Boolean Operations
Use the block_2d, block_3d, or block_mixed factory functions, or leverage operator
overloading for boolean operations (+ for union, - for difference, * for
intersection).
let sphere = primitive_3d;
let cube = primitive_3d;
// Subtract the cube from the sphere using the difference modifier
let result_modifier = modifier_3d;
println!;
/* Output:
difference() {
sphere(r = 10);
cube(size = 15, center = true);
}
*/
// Achieve the same result using operator overloading
let result_operator = sphere - cube;
println!;
/* Output:
difference() {
sphere(r = 10);
cube(size = 15, center = true);
}
*/
Adding Comments
Use the .commented() method or the _commented variants of the factory functions:
let commented_cube = primitive_3d.commented;
println!;
/* Output:
/* This is a simple cube */
cube(size = 5);
*/
let commented_translated_square = modifier_2d_commented;
println!;
/* Output:
/* Translated square */
translate([5, 5])
square(size = 10);
*/
Example: Building Complex Models (like tests/desk_clamp.rs)
The tests/desk_clamp.rs file serves as a practical example of building a more complex model.
It demonstrates several key techniques facilitated by scadman:
- Parametric Design with Constants: Dimensions and other parameters are defined as
Rust constants (
CLAMP_Z_SIZE,HOOK_OUTER_R, etc.). This makes the design easily adjustable and readable. - Modular Design with Helper Functions: The complex clamp shape is broken down into
smaller, manageable parts (
generate_lattice_r_void,generate_clamp,generate_body). Each function constructs and returns aScadObjectrepresenting a component of the final assembly. - Composition via Modifiers and Blocks: The helper functions return
ScadObjects, which are then combined usingmodifier_3d,block_3d, and operator overloading (+,-) to build the final structure. This mirrors how objects are combined in OpenSCAD itself. - Leveraging Builders for Clarity: Builders (
Translate2D::build_with,Polygon::build_with,Cylinder::build_with, etc.) are used extensively to set parameters for primitives and modifiers, improving code readability compared to positional arguments. - Adding Comments for Readability: Comments are added to significant parts of the
model (
.commented()) to explain the purpose of different objects or sections of the code, which translates directly to comments in the generated OpenSCAD file.
This example showcases how scadman enables a structured, modular, and maintainable
approach to creating complex parametric designs in OpenSCAD using the power of Rust.
Key Concepts
ScadObject: The main container struct. It wraps the actual object body (ScadObjectBody) and holds an optional comment. All functions that build or manipulate SCAD geometry ultimately work withScadObject.ScadObjectBody: An enum (Object2D,Object3D,ObjectMixed) that holds the specific type of SCAD object (Primitive, Modifier, or Block) for a given dimension.ScadObjectTrait: A trait implemented byScadObjectand its internal body types, providing core functionality liketo_code()(generating the SCAD string) andget_type()(determining the object's dimension).ScadDisplay: A fundamental trait implemented by any type that can be represented as a string in OpenSCAD code (numbers, vectors, strings, booleans, and the specific primitive/modifier/block body types). Therepr_scad()method generates the SCAD string for that specific value or object part.ScadCommentDisplay: A trait (delegated fromScadObjectTrait) that adds the ability to generate SCAD code with a comment (repr_scad_with_comment).ScadBuilder/ScadBuildable: Traits supporting the builder pattern for configuring complex SCAD sentences with optional parameters.ScadBuildable::build_withis the primary entry point for using builders.- Primitives, Modifiers, and Blocks: These correspond directly to OpenSCAD's
structural elements. The library provides specific types (
ScadPrimitive2D,ScadModifier3D,ScadBlockMixed, etc.) and enums (ScadPrimitiveBody2D,ScadModifierBody3D,ScadModifierBodyMixed) to represent them. - Factory Functions (
primitive_,modifier_,block_): Functions likeprimitive_2d,modifier_3d,block_mixed, etc., provided in thelib.rsroot, are the primary way to constructScadObjectinstances from the specific primitive/modifier/block types defined in thescad_2d,scad_3d, andscad_mixedmodules.try_variants are provided for operations that might fail due to dimension mismatches. - Value Types: Custom types in
value_type.rs(likeAngle,RGBA,RoundSize, etc.) and standard types (f64forUnit,bool,String, vectors fromnalgebra) implementScadDisplayto ensure correct formatting in the generated SCAD code.