Houses along the road 🏠🌲

Uses a circle transform from circletransform by @reinder

Log in to post a comment.

// Forked from "Houses along the road 🏠🌲" by markknol
// https://turtletoy.net/turtle/5f7fa21c7c

// Forked from "circletransform" by reinder
// https://turtletoy.net/turtle/71d524ceb5

function Translate(x,y) { return p => [p[0]+x, p[1]+y]; }
function Scale(sx, sy = sx) { return p => [p[0]*sx, p[1]*sy]; }
function Circle(r) { return p => { let ry = r - p[1], a = p[0]/r; return [ry*Math.cos(a), ry*Math.sin(a)]; } }

const elementScale = 1.0; // min=0.5, max=2, step=0.1
const roadSize = 10; // min=1, max=20, step=0.1

const display = 2; // min=1, max=2, step=1 (One, Two)

const size1 = 82; // min=20, max=100, step=1
const numElementsOutside1 = 17; // min=0, max=30, step=1
const numElementsInside1 = 12; // min=0, max=30, step=1

const size2 = 35; // min=20, max=100, step=1
const numElementsOutside2 = 7; // min=0, max=30, step=1
const numElementsInside2= 6; // min=0, max=30, step=1

function drawRoad(size, t) {
    t.jump([0, -roadSize/2]);
    t.forward(size*Math.PI);
    t.forward(size*Math.PI);
    
    t.jump([0, 0]);
    for(let i=0; i<size*2; i++) {
        if (i % 2 == 0) t.penup(); // dotted line
        else t.pendown();
        t.forward(Math.PI);
    }
    t.pendown();
    
    t.jump([0, roadSize/2]);
    t.forward(size*Math.PI);
    t.forward(size*Math.PI);
}

drawRoad(size1, new Tortoise().addTransform(Circle(size1)));
if (display == 2) drawRoad(size2, new Tortoise().addTransform(Circle(size2)));

function walk(i) {
    drawElement(i, size1,numElementsInside1, true, 2);
    drawElement(i, size1,numElementsOutside1, false, 3);
    if (display > 1) {
        drawElement(i, size2,numElementsInside2, true, 2);
        drawElement(i, size2,numElementsOutside2, false, 3);
    }
    return i < Math.max(numElementsInside1,numElementsOutside1,numElementsInside2,numElementsOutside2) - 1;
}

function drawElement(i, size, total, inside, mod) {
    if (i < total) { 
        const h = new Tortoise()
            .addTransform(Scale(.4 * elementScale))
            .addTransform(Translate(i * size * Math.PI * 2 / total, -roadSize/2));
        if (inside) {
            h.addTransform(Scale(-1)).addTransform(Translate(total * 2, 0));
        }
        h.addTransform(Circle(size));
        
        if (i % mod > 0) {
            drawHouse(h);
        } else {
            drawTree(h);
        }
    }
}

function drawTree(t) {
    square(t, [-3,-8], [3,0]);
    t.jmp(-15,-8); 
    t.goto(15,-8);
    t.goto(6,-20);
    t.goto(11,-20);
    t.goto(3,-30);
    t.goto(7,-30);
    t.goto(0,-47);
    t.goto(-7,-30);
    t.goto(-3,-30);
    t.goto(-11,-20);
    t.goto(-6,-20);
    t.goto(-15,-8);
}

function drawHouse(t) {
    square(t, [-10,-20], [30,0]);
    square(t, [-5,-15], [2,-8]); // window
    square(t, [7,0], [14,-15]); // door
    square(t, [19,-15], [25,-8]); // window
    square(t, [-25,-15], [-15,-8]); // window
    for (let i=-20; i<=20; i+=5) {
        t.jmp(i,-30); t.goto(i+10,-20); // roof hatchng
    }
    t.jmp(-20,-30); t.goto(-30,-20); t.goto(-30,0);  t.goto(-10,0);  t.goto(-10,-20); t.goto(-20,-30); 
    t.jmp(-10,-20); t.goto(-20,-30); t.goto(20,-30); t.goto(30,-20); t.goto(-10,-20);
}
function square(t, lt, rb) {
    t.jmp(lt); t.goto(lt[0], rb[1]); t.goto(rb), t.goto(rb[0], lt[1]); t.goto(lt);
}

////////////////////////////////////////////////////////////////
// Tortoise utility code (Minimal Turtle and Transforms)
// https://turtletoy.net/turtle/102cbd7c4d
////////////////////////////////////////////////////////////////

function Tortoise(x, y) {
    class Tortoise extends Turtle {
        constructor(x, y) {
            super(x, y);
            this.ps = Array.isArray(x) ? [...x] : [x || 0, y || 0];
            this.transforms = [];
        }
        addTransform(t) {
            this.transforms.push(t);
            this.jump(this.ps);
            return this;
        }
        applyTransforms(p) {
            if (!this.transforms) return p;
            let pt = [...p];
            this.transforms.map(t => { pt = t(pt); });
            return pt;
        }
        goto(x, y) {
            const p = Array.isArray(x) ? [...x] : [x, y];
            const pt = this.applyTransforms(p);
            if (this.isdown() && (this.pt[0]-pt[0])**2 + (this.pt[1]-pt[1])**2 > 4) {
               this.goto((this.ps[0]+p[0])/2, (this.ps[1]+p[1])/2);
               this.goto(p);
            } else {
                super.goto(pt);
                this.ps = p;
                this.pt = pt;
            }
        }
        position() { return this.ps; }
    }
    return new Tortoise(x,y);
}