SVG Tile Generation
TODO: collapasable, copyable, download, etc
Can you re-write this scad code in Rust using the svg crate so that it outputs an SVG file with the poitns?
` // OpenSCAD geometry of Tile(1,1) which leads to the spectre tile // Jeffery Spirko, [email protected], GPL 3.0
// Ref: https://arxiv.org/pdf/2305.17743.pdf // authors: David Smith, Joseph Samuel Myers, // Craig S. Kaplan, and Chaim Goodman-Strauss // Figure 1.1, left
linear_extrude(1) scale(10) spectre2();
// According to the paper, each side is the same length. // Each side is along an axis or at a 30 degree angle to an axis. // So each displacement is at an angle of 30k, where k is an integer. // kvals was determined visupally from the figure. kvals = [ 0, -2, 1, 3, 3, 5, 2, 4, 7, 9, 6, 8, 11, 9 ]; sines = [ for (angle = kvals30) sin(angle) ]; cosines = [ for (angle = kvals*30) cos(angle) ]; displacements = [ for(i=0; i<len(kvals); i=i+1) [ cosines[i], sines[i] ] ];
// Roughly based on cumulative sum from // https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Tips_and_Tricks // and requires version 2019.05 or newer. // Modifications: // This starts at [0,0] not the first element. // Each curpos is calculated from the current displacement. // Note: the result of adding the last displacement isn't returned. points = [ for(i=0, curpos=[0,0]; i<len(kvals); curpos=curpos+displacements[i], i=i+1) curpos ];
module spectre() { polygon(points); }
// In the Smith, et al. paper, Figure 1.1, right, it looks like // they modified the sides to be a cubic, // for example f(x) = x*(x-1)*(x-2)/2. // n is the number of minor points between major points module spectre2(n=8) { polygon([ for (i=[0:len(points)-1]) each let(p_i = points[i], p_j = points[(i+1)%len(points)]) spoosh(p_i, p_j, n, order=(i%2==0)) ]); }
// Named spoosh to avoid a possible trademark. function spoosh(p1, p2, n=20, order=0) = [for(i=[0:n-1]) spoosh_i(p1, p2, n, i, order) ];
// spoosh_i interpolates between p1 and p2, adding a sideways // swing according to spoosh_f(x). Every other point has // the swing inverted. function spoosh_i(p1, p2, n, i, order=0) = let(displacement = p2 - p1, perp = [displacement.y, -displacement.x]) p1 + displacement * i/n + (order?1:-1) * perp * spoosh_f(order?i/n:((n-i)/n));
function spoosh_f(x) = x*(x-1)*(x-2)/2;
To recreate the OpenSCAD code using Rust with the
svg` crate, the logic in the code will be broken down step by step. Note that some changes will be made to account for differences between the OpenSCAD language and Rust, and the svg crate's capabilities.
Here is the code translated to Rust:
use svg::Document;
use svg::node::element::path::{Data, Path};
use svg::node::element::Rectangle;
use std::f64::consts::PI;
const KVALS: [i32; 14] = [0, -2, 1, 3, 3, 5, 2, 4, 7, 9, 6, 8, 11, 9];
const SCALE: f64 = 10.0;
fn main() {
let points = calculate_points();
let data = calculate_polygon_data(&points);
let document = Document::new()
.set("viewBox", (0, 0, 100, 100))
.add(Rectangle::new()
.set("width", "100%")
.set("height", "100%")
.set("fill", "none")
.set("stroke", "black"))
.add(Path::new()
.set("fill", "none")
.set("stroke", "black")
.set("d", data));
svg::save("output.svg", &document).unwrap();
}
fn calculate_points() -> Vec<[f64; 2]> {
let sines: Vec<f64> = KVALS.iter().map(|&k| (k as f64 * 30.0 * PI / 180.0).sin()).collect();
let cosines: Vec<f64> = KVALS.iter().map(|&k| (k as f64 * 30.0 * PI / 180.0).cos()).collect();
let displacements: Vec<[f64; 2]> = cosines.iter().zip(sines.iter()).map(|(&x, &y)| [x, y]).collect();
let mut points = vec![[0.0, 0.0]];
let mut curpos = [0.0, 0.0];
for displacement in &displacements {
curpos[0] += displacement[0];
curpos[1] += displacement[1];
points.push(curpos);
}
points
}
fn spoosh(p1: [f64; 2], p2: [f64; 2], n: usize, order: bool) -> Vec<[f64; 2]> {
(0..n).map(|i| spoosh_i(p1, p2, n, i, order)).collect()
}
fn spoosh_i(p1: [f64; 2], p2: [f64; 2], n: usize, i: usize, order: bool) -> [f64; 2] {
let displacement = [p2[0] - p1[0], p2[1] - p1[1]];
let perp = [displacement[1], -displacement[0]];
let factor = i as f64 / n as f64;
let x = if order { factor } else { (n - i) as f64 / n as f64 };
[
p1[0] + displacement[0] * factor + (if order { 1.0 } else { -1.0 }) * perp[0] * spoosh_f(x),
p1[1] + displacement[1] * factor + (if order { 1.0 } else { -1.0 }) * perp[1] * spoosh_f(x)
]
}
fn spoosh_f(x: f64) -> f64 {
x * (x - 1.0) * (x - 2.0) / 2.0
}
fn calculate_polygon_data(points: &[[f64; 2]]) -> Data {
let n = 8;
let mut data = Data::new().move_to((points[0][0] * SCALE, points[0][1] * SCALE));
for i in 0..points.len() - 1 {
let segment = spoosh(points[i], points[(i + 1) % points.len()], n, i % 2 == 0);
for point in segment {
data = data.line_to((point[0] * SCALE, point[1] * SCALE));
}
}
data.close()
}
This code defines the logic of the OpenSCAD code and writes the resulting shape to an SVG file named output.svg
. Before you run the code, you'll need to add the svg
crate to your Cargo.toml
:
[dependencies]
svg = "0.8"
When you run the Rust code, you should get an SVG representation of the shape. Adjust the constants and logic as needed for your specific requirements.Can you fix this error ^^^^ no
Pathin
node::element::path
The error you're seeing suggests that there's no Path
struct directly in the node::element::path
module of the svg
crate. It's possible that the API or the organization of the crate has changed since my last update.
To fix this issue:
- Check the documentation of the
svg
crate to understand the new structure. - Adjust the import paths based on the current API.
However, assuming that only the Path
struct's path has changed, you can try the following:
Replace:
use svg::node::element::path::{Data, Path};
with:
use svg::node::element::Path;
use svg::node::element::path::Data;
If the issue persists or there are more errors, you might need to check the crate's documentation or source code to understand its current organization and update your imports accordingly.
SVG Tile Generation created at Tue Jan 20 1970 13:53:48 GMT+0000 (Coordinated Universal Time)Related Chats
SVG Tile Generation 1.000
Translate OpenSCAD to Rust 0.925
Rust Marketplace Scraper. 0.345
Nested vec! Macro Usage 0.333
Implementing HTML5 Canvas Figures 0.324
MD5 Hash in Rust 0.306
Rust Shell for LLM 0.305
Scraper Implementation with Enum 0.301
Understanding 3D Transformation Matrices 0.290
Rust Enum for Strings 0.290