Polygone kirigami

Polygone kirigami (outter boundary uncomment at the end)

Log in to post a comment.

Canvas.setpenopacity(1);

const turtle = new Turtle();

// adjust to fit canvas
let scale = 1; // min=0, max=20, step=0.1


// ----------------------
// PARAMETERS
// ----------------------

// Number of polygon sides
// AND number of possible sections
let part = 4; // min=2, max=50, step=2

// 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 polygon 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(n) {
        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 if (spacing_mode == 3) {

    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=0, max=20, step=0.1


// ----------------------
// OVERLAP MODES
// ----------------------

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

if (overlap_mode == 1) {

    function D_slope(n) {
        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=20, step=0.5


// ----------------------
// Cutting mode
// ----------------------

let mode = 0; // min=1, max=2, step=1

// ----------------------
// POLYGON GEOMETRY
// ----------------------

const sideAngle =
    2 * Math.PI / part;


// Length of one polygon side
function side_length(radius) {

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


// Get point along polygon perimeter
function polygon_point(
    radius,
    distance,
    rotation
) {

    let sideLen =
        side_length(radius);

    let perimeter =
        sideLen * part;


    // Wrap distance around perimeter
    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
    };
}


// ----------------------
// ----------------------
// ----------------------
// DRAW ONE SECTION
// ----------------------
//
// mode 1:
//     Sections start/end at polygon corners.
//
//     part = 4:
//
//     Ring 0 -> section 0, section 2
//     Ring 1 -> section 1, section 3
//
//
// mode 2:
//     Sections are shifted by HALF A SIDE.
//
//     The boundaries are now at the
//     middle of polygon sides.
//
//     This means the section passes through
//     a polygon corner:
//
//        midpoint |--- corner ---| midpoint
//
// ----------------------

function draw_polygon_side(
    radius,
    side,
    rotation,
    overlapAmount
) {

    let sideLen =
        side_length(radius);


    // ==================================================
    // MODE 1
    // ==================================================
    //
    // Normal polygon sections.
    //
    // Start and end at polygon corners.
    //
    //       overlap
    //          ↓
    //
    //    <===================>
    //    ↑                   ↑
    //  corner              corner
    //
    // ==================================================

    if (mode == 1) {

        let start =
            side * sideLen -
            overlapAmount;

        let end =
            (side + 1) * sideLen +
            overlapAmount;


        draw_polygon_segment(
            radius,
            start,
            end,
            rotation
        );

        return;
    }


    // ==================================================
    // MODE 2
    // ==================================================
    //
    // Shift the section by HALF A SIDE.
    //
    // Therefore the section runs from the
    // midpoint of one side, through a corner,
    // to the midpoint of the next side.
    //
    //
    //       midpoint              midpoint
    //           |                    |
    //           |---- overlap ----|  |
    //                 corner
    //
    // ==================================================

    if (mode == 2) {

        let halfSide =
            sideLen / 2;


        // Start/end of the section are shifted
        // by half a side.
        //
        // Original:
        //
        //     side -------- side
        //
        // New:
        //
        //       midpoint -- corner -- midpoint

        let start =
            side * sideLen +
            halfSide -
            overlapAmount;

        let end =
            (side + 1) * sideLen +
            halfSide +
            overlapAmount;


        draw_polygon_segment(
            radius,
            start,
            end,
            rotation
        );
    }
}



// ----------------------
// DRAW POLYGON SEGMENT
// ----------------------

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

    let length =
        end - start;


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


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

        let d =
            start +
            length * k / steps;


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


        let x =
            scale * p.x;

        let y =
            scale * p.y;


        if (k === 0) {

            turtle.penup();
            turtle.goto(x, y);
            turtle.pendown();

        } else {

            turtle.goto(x, y);
        }
    }
}


// ----------------------
// DRAW FULL POLYGON
// ----------------------

function draw_polygon(
    radius,
    rotation
) {

    let sideLen =
        side_length(radius);

    let perimeter =
        sideLen * part;


    let steps =
        Math.max(
            2 * part,
            Math.floor(perimeter)
        );


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

        let d =
            perimeter * k / steps;


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


        let x =
            scale * p.x;

        let y =
            scale * p.y;


        if (k === 0) {

            turtle.penup();
            turtle.goto(x, y);
            turtle.pendown();

        } else {

            turtle.goto(x, y);
        }
    }
}


// ----------------------
// COMPUTE NUMBER OF RINGS
// ----------------------

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;


    // Cumulative spiral rotation
    let spiral = 0;


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

        let eps =
            D_slope(n);


        // ======================================
        // ======================================
        // ALTERNATING POSITIONS
        // ======================================
        //
        // mode 1:
        //
        //   Ring 0 -> sides 0, 2, 4...
        //   Ring 1 -> sides 1, 3, 5...
        //
        //
        // mode 2:
        //
        //   Ring 0 -> middle of sides 0, 2, 4...
        //   Ring 1 -> middle of sides 1, 3, 5...
        //
        // ======================================
        
        let firstSide = n % 2;
        
        for (
            let j = firstSide;
            j < part;
            j += 2
        ) {
        
            draw_polygon_side(
                r,
                j,
                spiral,
                eps
            );
        
            spiral += offset / r;
        }



        // Next polygon ring
        r += spacing_slope(n);
    }


    // ----------------------
    // OUTER BOUNDARY
    // ----------------------

   //draw_polygon(r+10,spiral);


    return false;
}


walk(0);