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 ^^^^ noPathinnode::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:

  1. Check the documentation of the svg crate to understand the new structure.
  2. 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