This commit is contained in:
qwertzuiopy 2025-04-07 22:54:05 +02:00
commit ddc7e4f6ce
9 changed files with 741 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

250
Cargo.lock generated Normal file
View file

@ -0,0 +1,250 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "bitflags"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "deckbox"
version = "0.1.0"
dependencies = [
"glam",
"rand",
]
[[package]]
name = "getrandom"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
dependencies = [
"cfg-if",
"libc",
"wasi",
"windows-targets",
]
[[package]]
name = "glam"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17fcdf9683c406c2fc4d124afd29c0d595e22210d633cbdb8695ba9935ab1dc6"
[[package]]
name = "libc"
version = "0.2.170"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828"
[[package]]
name = "ppv-lite86"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
"zerocopy 0.7.35",
]
[[package]]
name = "proc-macro2"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
dependencies = [
"rand_chacha",
"rand_core",
"zerocopy 0.8.23",
]
[[package]]
name = "rand_chacha"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
"getrandom",
]
[[package]]
name = "syn"
version = "2.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "wasi"
version = "0.13.3+wasi-0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
dependencies = [
"wit-bindgen-rt",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "wit-bindgen-rt"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
dependencies = [
"bitflags",
]
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive 0.7.35",
]
[[package]]
name = "zerocopy"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6"
dependencies = [
"zerocopy-derive 0.8.23",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

8
Cargo.toml Normal file
View file

@ -0,0 +1,8 @@
[package]
name = "deckbox"
version = "0.1.0"
edition = "2021"
[dependencies]
glam = "0.30.0"
rand = "0.9.0"

BIN
deckbox.stl Normal file

Binary file not shown.

BIN
deckbox_part2.stl Normal file

Binary file not shown.

BIN
deckbox_part3.stl Normal file

Binary file not shown.

1
output/output.scad Normal file
View file

@ -0,0 +1 @@
$fa= 0.1;$fn= 150;difference(){ union(){ translate([-3, -3, -3]) { cube([25, 25, 15], center=false); } translate([1.5, 1.5, 12]) { cube([20.5, 20.5, 1], center=false); } } cube([50, 50, 7], center=false); {translate([-3, -3, 0]) { rotate([0, 0, 45]) { cube([2, 50, 50], center=true); } }mirror([0, 1, 0]) { rotate([90, 0, 0]) { translate([-3, -3, 0]) { rotate([0, 0, 45]) { cube([2, 50, 50], center=true); } } } }mirror([1, 0, 0]) { rotate([0, -90, 0]) { translate([-3, -3, 0]) { rotate([0, 0, 45]) { cube([2, 50, 50], center=true); } } } }} {translate([22, -3, 0]) { rotate([0, 0, -45]) { cube([2, 50, 50], center=true); } }mirror([0, 1, 0]) { rotate([90, 0, 0]) { translate([22, -3, 0]) { rotate([0, 0, -45]) { cube([2, 50, 50], center=true); } } } }mirror([1, 0, 0]) { rotate([0, -90, 0]) { translate([22, -3, 0]) { rotate([0, 0, -45]) { cube([2, 50, 50], center=true); } } } }} {translate([-3, 22, 0]) { rotate([0, 0, -45]) { cube([2, 50, 50], center=true); } }mirror([0, 1, 0]) { rotate([90, 0, 0]) { translate([-3, 22, 0]) { rotate([0, 0, -45]) { cube([2, 50, 50], center=true); } } } }mirror([1, 0, 0]) { rotate([0, -90, 0]) { translate([-3, 22, 0]) { rotate([0, 0, -45]) { cube([2, 50, 50], center=true); } } } }} translate([10, 10, 0]) { cube([50, 50, 50], center=false); } translate([5, 5, 8.9]) { cylinder(h=2.2, r1=3.2, r2=3.2); } translate([5, 5, 8.9]) { rotate([0, 0, 45]) { translate([0, -3.2, 0]) { cube([50, 6.4, 2.2], center=false); } } } }translate([7, 7, 0]) { cube([15, 15, 3], center=false); }translate([-0.001, -0.001, -0.001]) { cube([7.001, 7.001, 7.001], center=false); }

288
src/main.rs Normal file
View file

@ -0,0 +1,288 @@
mod rcad;
use crate::rcad::*;
const STICK: f32 = 7.;
const WOOD: f32 = 4.;
const SIDEPLATE_LENGTH: f32 = 25.;
const SIDEPLATE_THICK: f32 = 3.;
const TAMPER: f32 = 2.;
const TOP_HEIGHT: f32 = 10.;
const TOP_OVERLAP_TOP: f32 = 5.;
const TOP_OVERLAP_MIDDLE: f32 = 3.;
const TOP_OVERLAP_INNER: f32 = 3.;
const MAGNET_RADIUS: f32 = 3.2;
const MAGNET_THICK: f32 = 2.2;
const INSET_HEIGHT: f32 = 1.;
const INSET_RIM: f32 = 1.;
const INSET_GAP: f32 = 0.5;
const TOP_TOP_HEIGHT: f32 = 15.;
fn main() -> Result<(), std::io::Error> {
let mut data = init()?;
data.push_str(&top_top()?);
process(data)?;
Ok(())
}
fn top_top() -> Result<String, std::io::Error> {
let mut data = String::new();
data.push_str(&difference(&vec![
union(&vec![
translate(
-SIDEPLATE_THICK,
-SIDEPLATE_THICK,
-SIDEPLATE_THICK,
cube(SIDEPLATE_LENGTH, SIDEPLATE_LENGTH, TOP_TOP_HEIGHT, false),
),
translate(
INSET_RIM + INSET_GAP,
INSET_RIM + INSET_GAP,
TOP_TOP_HEIGHT - SIDEPLATE_THICK,
cube(
SIDEPLATE_LENGTH - SIDEPLATE_THICK - INSET_RIM - INSET_GAP,
SIDEPLATE_LENGTH - SIDEPLATE_THICK - INSET_RIM - INSET_GAP,
INSET_HEIGHT,
false,
),
),
]),
cube(INF, INF, STICK, false),
corner_mirror(translate(
-SIDEPLATE_THICK,
-SIDEPLATE_THICK,
0.,
rotate(0., 0., 45., cube(TAMPER, INF, INF, true)),
)),
corner_mirror(translate(
SIDEPLATE_LENGTH - SIDEPLATE_THICK,
-SIDEPLATE_THICK,
0.,
rotate(0., 0., -45., cube(TAMPER, INF, INF, true)),
)),
corner_mirror(translate(
-SIDEPLATE_THICK,
SIDEPLATE_LENGTH - SIDEPLATE_THICK,
0.,
rotate(0., 0., -45., cube(TAMPER, INF, INF, true)),
)),
translate(
TOP_OVERLAP_MIDDLE + STICK,
TOP_OVERLAP_MIDDLE + STICK,
0.,
cube(INF, INF, INF, false),
),
translate(
(TOP_OVERLAP_MIDDLE + STICK) / 2.,
(TOP_OVERLAP_MIDDLE + STICK) / 2.,
(TOP_TOP_HEIGHT - SIDEPLATE_THICK + INSET_HEIGHT - MAGNET_THICK + STICK) / 2.,
cylinder(MAGNET_THICK, MAGNET_RADIUS),
),
translate(
(TOP_OVERLAP_MIDDLE + STICK) / 2.,
(TOP_OVERLAP_MIDDLE + STICK) / 2.,
(TOP_TOP_HEIGHT - SIDEPLATE_THICK + INSET_HEIGHT - MAGNET_THICK + STICK) / 2.,
rotate(
0.,
0.,
45.,
translate(
0.,
-MAGNET_RADIUS,
0.,
cube(INF, MAGNET_RADIUS * 2., MAGNET_THICK, false),
),
),
),
]));
data.push_str(&translate(
STICK,
STICK,
0.,
cube(
SIDEPLATE_LENGTH - STICK - SIDEPLATE_THICK,
SIDEPLATE_LENGTH - STICK - SIDEPLATE_THICK,
STICK - WOOD,
false,
),
));
data.push_str(
&(translate(
-EPS,
-EPS,
-EPS,
cube(STICK + EPS, STICK + EPS, STICK + EPS, false),
)),
);
Ok(data)
}
fn top() -> Result<String, std::io::Error> {
let mut data = String::new();
data.push_str(&difference(&vec![
translate(
-SIDEPLATE_THICK,
-SIDEPLATE_THICK,
0.,
cube(
SIDEPLATE_LENGTH,
SIDEPLATE_LENGTH,
TOP_HEIGHT + TOP_OVERLAP_TOP,
false,
),
),
translate(0., 0., -EPS, cube(INF, INF, TOP_HEIGHT + EPS, false)),
translate(
TOP_OVERLAP_MIDDLE + STICK,
TOP_OVERLAP_MIDDLE + STICK,
0.,
cube(INF, INF, INF, false),
),
translate(
-SIDEPLATE_THICK,
-SIDEPLATE_THICK,
0.,
rotate(0., 0., 45., cube(TAMPER, INF, INF, true)),
),
translate(
SIDEPLATE_LENGTH - SIDEPLATE_THICK,
-SIDEPLATE_THICK,
0.,
rotate(0., 0., -45., cube(TAMPER, INF, INF, true)),
),
translate(
-SIDEPLATE_THICK,
SIDEPLATE_LENGTH - SIDEPLATE_THICK,
0.,
rotate(0., 0., -45., cube(TAMPER, INF, INF, true)),
),
mirror(
1.,
-1.,
0.,
translate(
-SIDEPLATE_THICK,
0.,
0.,
rotate(0., -45., 0., cube(TAMPER, INF, INF, true)),
),
),
translate(
(TOP_OVERLAP_MIDDLE + STICK) / 2.,
(TOP_OVERLAP_MIDDLE + STICK) / 2.,
TOP_HEIGHT + TOP_OVERLAP_TOP / 2. - MAGNET_THICK / 2. - INSET_HEIGHT / 2.,
cylinder(MAGNET_THICK, MAGNET_RADIUS),
),
translate(
(TOP_OVERLAP_MIDDLE + STICK) / 2.,
(TOP_OVERLAP_MIDDLE + STICK) / 2.,
TOP_HEIGHT + TOP_OVERLAP_TOP / 2. - MAGNET_THICK / 2. - INSET_HEIGHT / 2.,
rotate(
0.,
0.,
45.,
translate(
0.,
-MAGNET_RADIUS,
0.,
cube(INF, MAGNET_RADIUS * 2., MAGNET_THICK, false),
),
),
),
translate(
INSET_RIM,
INSET_RIM,
TOP_HEIGHT + TOP_OVERLAP_TOP - INSET_HEIGHT,
cube(INF, INF, INSET_HEIGHT + EPS, false),
),
]));
data.push_str(&mirror(
1.,
-1.,
0.,
translate(
0.,
STICK,
0.,
cube(
STICK - WOOD,
SIDEPLATE_LENGTH - STICK - SIDEPLATE_THICK,
TOP_HEIGHT,
false,
),
),
));
data.push_str(&mirror(
1.,
-1.,
0.,
translate(
STICK,
STICK,
TOP_HEIGHT - TOP_OVERLAP_INNER,
cube(
TOP_OVERLAP_MIDDLE,
SIDEPLATE_LENGTH - STICK - SIDEPLATE_THICK,
TOP_OVERLAP_INNER,
false,
),
),
));
Ok(data)
}
fn full_corner() -> Result<(), std::io::Error> {
let mut data = init()?;
data.push_str(&difference(&vec![
translate(
-SIDEPLATE_THICK,
-SIDEPLATE_THICK,
-SIDEPLATE_THICK,
cube(SIDEPLATE_LENGTH, SIDEPLATE_LENGTH, SIDEPLATE_LENGTH, false),
),
cube(INF, INF, INF, false),
corner_mirror(translate(
-SIDEPLATE_THICK,
-SIDEPLATE_THICK,
0.,
rotate(0., 0., 45., cube(TAMPER, INF, INF, true)),
)),
corner_mirror(translate(
SIDEPLATE_LENGTH - SIDEPLATE_THICK,
-SIDEPLATE_THICK,
0.,
rotate(0., 0., -45., cube(TAMPER, INF, INF, true)),
)),
corner_mirror(translate(
-SIDEPLATE_THICK,
SIDEPLATE_LENGTH - SIDEPLATE_THICK,
0.,
rotate(0., 0., -45., cube(TAMPER, INF, INF, true)),
)),
]));
data.push_str(&corner_mirror(translate(
STICK,
STICK,
0.,
cube(
SIDEPLATE_LENGTH - STICK - SIDEPLATE_THICK,
SIDEPLATE_LENGTH - STICK - SIDEPLATE_THICK,
STICK - WOOD,
false,
),
)));
data.push_str(
&(translate(
-EPS,
-EPS,
-EPS,
cube(STICK + EPS, STICK + EPS, STICK + EPS, false),
)),
);
process(data)?;
Ok(())
}

193
src/rcad/mod.rs Normal file
View file

@ -0,0 +1,193 @@
use glam::f32::Vec2;
use rand::Rng;
use std::process::Command;
use std::{fs, io};
pub const EPS: f32 = 0.001;
pub const INF: f32 = 50.;
pub fn init() -> Result<String, io::Error> {
if fs::exists("output")? {
println!("output dir already exists, emptying");
fs::remove_dir_all("output")?;
}
if let Ok(_) = fs::create_dir("output") {
println!("successfully created output directory");
} else {
println!("could not create output directory");
}
let mut data = String::new();
data.push_str(&set("fa".into(), 0.1));
data.push_str(&set("fn".into(), 150.));
return Ok(data);
}
pub fn process(data: String) -> Result<(), io::Error> {
fs::write("./output/output.scad", data)?;
let output = Command::new("flatpak")
.arg("run")
.arg("org.openscad.OpenSCAD")
.arg("./output/output.scad")
.output()?;
println!("{:?}", output);
Ok(())
}
pub fn corner_mirror(what: String) -> String {
let mut res = String::new();
res.push_str("{");
res.push_str(&what);
res.push_str(&mirror_nocopy(
0.,
1.,
0.,
rotate(90., 0., 0., what.clone()),
));
res.push_str(&mirror_nocopy(1., 0., 0., rotate(0., -90., 0., what)));
res.push_str("}");
res
}
fn process_svg(path: &str) {
let output = Command::new("inkscape")
.arg(format!(
"--actions=select:path1; object-stroke-to-path; export-filename:{};export-do",
path
))
.arg(format!("{path}"))
.output()
.expect("Could not execute command");
print!("{:?}", output);
}
pub enum Path {
Move(Vec2),
Line(Vec2),
Bezier((Vec2, Vec2, Vec2)),
Close,
}
fn path_to_svg(path: &Vec<Path>, stroke: Option<f32>) -> String {
let mut s = String::from("<svg xmlns='http://www.w3.org/2000/svg'><path id='path1' ");
if let Some(w) = stroke {
s.push_str(&format!("fill='none' stroke='black' stroke-width='{w}' "));
} else {
s.push_str("fill='black' stroke='none' ");
}
s.push_str("d='");
for i in path {
match i {
Path::Move(p) => s.push_str(&format!("M {} {} ", p.x, p.y)),
Path::Line(p) => s.push_str(&format!("L {} {} ", p.x, p.y)),
Path::Bezier((c1, c2, p)) => s.push_str(&format!(
"C {} {}, {} {}, {} {} ",
c1.x, c1.y, c2.x, c2.y, p.x, p.y
)),
Path::Close => s.push_str("Z "),
}
}
s.push_str("'/></svg>");
s
}
fn path(path: &Vec<Path>, stroke: Option<f32>) -> String {
let mut name = String::from("blah");
let mut rng = rand::rng();
name.push_str(&rng.random::<u32>().to_string());
name.push_str(".svg");
fs::write(format!("output/{}", name), path_to_svg(&path, stroke))
.expect("Unable to write file");
process_svg(&name);
include(&name)
}
pub fn set(var: String, value: f32) -> String {
format!("${var}= {value};")
}
pub struct ExOptions {
height: f32,
center: bool,
convexity: f32,
twist: f32,
slices: f32,
scale: f32,
}
impl Default for ExOptions {
fn default() -> ExOptions {
ExOptions {
height: 1.0,
center: true,
convexity: 10.0,
twist: 0.0,
slices: 20.0,
scale: 1.0,
}
}
}
pub fn include(what: &str) -> String {
format!("import(file=\"{what}\");")
}
pub fn linear_extrude(opt: ExOptions, what: String) -> String {
format!("linear_extrude(height={height}, center={center}, convexity={convexity}, twist={twist}, slices={slices}, scale={scale}) {{ {what} }}",
height=opt.height, center=opt.center,convexity=opt.convexity,twist=opt.twist,slices=opt.slices,scale=opt.scale)
}
pub fn rotate_extrude(angle: f32, convexity: f32, what: String) -> String {
format!("rotate_extrude(angle={angle}, convexity={convexity}) {{ {what} }}")
}
pub fn circle(radius: f32) -> String {
format!("circle({radius});")
}
pub fn sphere(radius: f32) -> String {
format!("sphere({});", radius)
}
pub fn cube(width: f32, depth: f32, height: f32, center: bool) -> String {
format!(
"cube([{}, {}, {}], center={});",
width, depth, height, center
)
}
pub fn cylinder(height: f32, radius: f32) -> String {
format!("cylinder(h={height}, r1={radius}, r2={radius});")
}
pub fn translate(x: f32, y: f32, z: f32, what: String) -> String {
format!("translate([{}, {}, {}]) {{ {} }}", x, y, z, what)
}
pub fn rotate(x: f32, y: f32, z: f32, what: String) -> String {
format!("rotate([{}, {}, {}]) {{ {} }}", x, y, z, what)
}
pub fn mirror(x: f32, y: f32, z: f32, what: String) -> String {
format!(
"mirror([{}, {}, {}]) {{ {} }} {{ {} }}",
x, y, z, what, what
)
}
pub fn mirror_nocopy(x: f32, y: f32, z: f32, what: String) -> String {
format!("mirror([{}, {}, {}]) {{ {} }}", x, y, z, what)
}
pub fn intersection(what: &[String]) -> String {
let mut s = format!("intersection(){{ ");
for i in what.iter() {
s = format!("{} {}", s, i);
}
format!("{} }}", s)
}
pub fn union(what: &[String]) -> String {
let mut s = format!("union(){{ ");
for i in what.iter() {
s = format!("{} {}", s, i);
}
format!("{} }}", s)
}
pub fn difference(what: &[String]) -> String {
let mut s = format!("difference(){{ ");
for i in what.iter() {
s = format!("{} {}", s, i);
}
format!("{} }}", s)
}