Polygone kirigami

Polygone kirigami (outter boundary uncomment at the end)
Problem from svg file when sent to laser cutter...

Log in to post a comment.

Canvas.setpenopacity(1);

const turtle = new Turtle();

let scale = 1; // min=0, max=20, step=0.1


// ============================================================
// PARAMETERS
// ============================================================

// Polygon geometry
let sides = 8; // min=3, max=100, step=1

// Number of drawable sections
let sections = 4; // min=1, max=100, step=1

// Starting radius
let R_min = 15; // min=1, max=50, step=1

// Outer radius
let r_max = 62; // min=10, max=500, step=1

// Spacing between rings
let spacing = 2; // min=1, max=50, step=0.5

let spacing_min = spacing;
let spacing_max = 2 * spacing;


// ============================================================
// SPACING MODES
// ============================================================

// 1 = constant
// 2 = increasing
// 3 = decreasing

let spacing_mode = 1;  // min=1, max=3, step=1

if (spacing_mode == 1) {

    function spacing_slope() {
        return spacing;
    }

} else if (spacing_mode == 2) {

    function spacing_slope(r) {

        let t =
            (r - R_min) /
            (r_max - R_min);

        return spacing_min +
               (spacing_max - spacing_min) * t;
    }

} else {

    function spacing_slope(r) {

        let t =
            (r - R_min) /
            (r_max - R_min);

        return spacing_min -
               (spacing_max - spacing_min) * t;
    }
}


// ============================================================
// OVERLAP
// ============================================================

let overlap = 6;  // min=1, max=100, step=0.5


// ============================================================
// OVERLAP MODES
// ============================================================

let overlap_mode = 1;  // min=1, max=4, step=1

if (overlap_mode == 1) {

    function D_slope() {
        return overlap;
    }

} else if (overlap_mode == 2) {

    function D_slope(n) {
        return 0.2 * (overlap + n);
    }

} else if (overlap_mode == 3) {

    function D_slope(n) {
        return 0.25 * overlap - n * 0.15;
    }

} else {

    function D_slope(n) {
        return overlap *
               (1 + 0.4 * Math.sin(n / 4));
    }
}


// ============================================================
// SPIRAL
// ============================================================

let offset = 0;  // min=0, max=100, step=1


// ============================================================
// CUTTING MODE
// ============================================================

// 1 = section starts at boundary
// 2 = section shifted by half a section

let mode = 1;


// ============================================================
// POLYGON GEOMETRY
// ============================================================

const sideAngle =
    2 * Math.PI / sides;


function side_length(radius) {

    return 2 *
           radius *
           Math.sin(Math.PI / sides);
}


function polygon_point(
    radius,
    distance,
    rotation
) {

    let sideLen =
        side_length(radius);

    let perimeter =
        sideLen * sides;

    distance =
        ((distance % perimeter) +
         perimeter) % perimeter;

    let side =
        Math.floor(distance / sideLen);

    let t =
        (distance - side * sideLen) /
        sideLen;

    let a1 =
        -Math.PI / 2 +
        side * sideAngle +
        rotation;

    let a2 =
        -Math.PI / 2 +
        (side + 1) * sideAngle +
        rotation;

    let x1 =
        radius * Math.cos(a1);

    let y1 =
        radius * Math.sin(a1);

    let x2 =
        radius * Math.cos(a2);

    let y2 =
        radius * Math.sin(a2);

    return {
        x: x1 + (x2 - x1) * t,
        y: y1 + (y2 - y1) * t
    };
}


function section_position(
    radius,
    sectionIndex
) {

    let sideLen =
        side_length(radius);

    let perimeter =
        sideLen * sides;

    return (
        sectionIndex *
        perimeter /
        sections
    );
}


// ============================================================
// SEGMENT STORAGE
// ============================================================

let segments = [];


function add_segment(p1, p2) {

    segments.push({
        x1: p1.x,
        y1: p1.y,
        x2: p2.x,
        y2: p2.y
    });
}


function collect_polygon_segment(
    radius,
    start,
    end,
    rotation
) {

    let length =
        end - start;

    let steps =
        Math.max(
            2,
            Math.ceil(
                Math.abs(length) / 2
            )
        );

    let previous = null;

    for (let k = 0; k <= steps; k++) {

        let d =
            start +
            length * k / steps;

        let p =
            polygon_point(
                radius,
                d,
                rotation
            );

        if (previous !== null) {

            add_segment(
                previous,
                p
            );
        }

        previous = p;
    }
}


// ============================================================
// DRAW ONE SECTION
// ============================================================

function draw_section(
    radius,
    sectionIndex,
    rotation,
    overlapAmount
) {

    let sideLen =
        side_length(radius);

    let perimeter =
        sideLen * sides;

    let sectionLength =
        perimeter / sections;

    let start =
        section_position(
            radius,
            sectionIndex
        );

    if (mode == 2) {

        start +=
            sectionLength / 2;
    }

    let end =
        start +
        sectionLength;

    collect_polygon_segment(
        radius,
        start - overlapAmount,
        end + overlapAmount,
        rotation
    );
}


// ============================================================
// DUPLICATE REMOVAL
// ============================================================

function deduplicate_segments() {

    const precision = 1000000;

    let unique = [];
    let seen = new Set();

    for (let s of segments) {

        let a =
            Math.round(
                s.x1 * precision
            ) +
            "," +
            Math.round(
                s.y1 * precision
            );

        let b =
            Math.round(
                s.x2 * precision
            ) +
            "," +
            Math.round(
                s.y2 * precision
            );

        let key =
            a < b
            ? a + "|" + b
            : b + "|" + a;

        if (!seen.has(key)) {

            seen.add(key);
            unique.push(s);
        }
    }

    segments = unique;
}


// ============================================================
// OUTPUT
// ============================================================

function output_segments() {

    for (let s of segments) {

        turtle.penup();

        turtle.goto(
            scale * s.x1,
            scale * s.y1
        );

        turtle.pendown();

        turtle.goto(
            scale * s.x2,
            scale * s.y2
        );
    }
}


// ============================================================
// COMPUTE RING COUNT
// ============================================================

let polygon_number = 0;

let temp_r = R_min;

while (temp_r < r_max) {

    temp_r +=
        spacing_slope(
            polygon_number
        );

    polygon_number++;
}


// ============================================================
// WALK
// ============================================================

function walk(i) {

    if (i > 0) return false;

    let r = R_min;

    let spiral = 0;

    for (
        let n = 0;
        n < polygon_number;
        n++
    ) {

        let eps =
            D_slope(n);

        let firstSection =
            n % 2;

        for (
            let j = firstSection;
            j < sections;
            j += 2
        ) {

            draw_section(
                r,
                j,
                spiral,
                eps
            );

            spiral +=
                offset / r;
        }

        r +=
            spacing_slope(n);
    }

    deduplicate_segments();

    output_segments();

    return false;
}

walk(0);