Bird Nest

Recreation of a birds nest with eggs inside, draws the nest using parameterized rectangles. Egg curve function from mathcurve.com/courbes2d.gb/oeuf/oeuf.shtml.

Log in to post a comment.

const stick_count = 300; // min = 100 max = 500 step = 1
const radius_min = 50; // min = 10 max = 50 step = 1
const radius_range = 40; // min = 10 max = 50 step = 1
const height_rand = 8; 
const height_scale = 0.7; 
const width_rand = .4; 
const width_scale = 0.02; 

const egg_scale = 2.6; // min = 0.5 max = 3 step = 0.1
const egg_randomness = 0.5; // min = 0 max = 2 step = 0.1

const turtle = new Turtle();

class Rectangle {
    constructor(h, w, x_center, y_center, rot) {
        this.h = h
        this.w = w
        this.x_center = x_center
        this.y_center = y_center
        this.rot = rot
        
        this.x1 = x_center + w/2 * Math.cos(rot) - h/2 * Math.sin(rot);
        this.y1 = y_center + w/2 * Math.sin(rot) + h/2 * Math.cos(rot);
        this.x2 = x_center - w/2 * Math.cos(rot) - h/2 * Math.sin(rot);
        this.y2 = y_center - w/2 * Math.sin(rot) + h/2 * Math.cos(rot);
        this.x3 = x_center - w/2 * Math.cos(rot) + h/2 * Math.sin(rot);
        this.y3 = y_center - w/2 * Math.sin(rot) - h/2 * Math.cos(rot);
        this.x4 = x_center + w/2 * Math.cos(rot) + h/2 * Math.sin(rot);
        this.y4 = y_center + w/2 * Math.sin(rot) - h/2 * Math.cos(rot);
    }
    
    inside(x_pos, y_pos) {
        let pal1 = this.point_above_line(this.x1, this.y1, this.x2, this.y2, x_pos, y_pos);
        let pal2 = this.point_above_line(this.x2, this.y2, this.x3, this.y3, x_pos, y_pos);
        let pal3 = this.point_above_line(this.x3, this.y3, this.x4, this.y4, x_pos, y_pos);
        let pal4 = this.point_above_line(this.x4, this.y4, this.x1, this.y1, x_pos, y_pos);
        return(((pal1 && !pal3) || (!pal1 && pal3)) && ((pal2 && !pal4) || (!pal2 && pal4)));
    }
    
    point_above_line(x1, y1, x2, y2, xp, yp) {
        return(yp > (((y2-y1)/(x2-x1)) * (xp - x1) + y1));
    }
    
    draw() {
        line(this.x1, this.y1, this.x2, this.y2);
        line(this.x2, this.y2, this.x3, this.y3);
        line(this.x3, this.y3, this.x4, this.y4);
        line(this.x4, this.y4, this.x1, this.y1);
    }
}

class Circle {
    constructor(radius, steps, x_center, y_center) {
        this.radius = radius
        this.steps = steps
        this.x_center = x_center
        this.y_center = y_center
    }
    
    inside(x_pos, y_pos) {
        return(Math.sqrt((x_pos-this.x_center)*(x_pos-this.x_center) + (y_pos-this.y_center)*(y_pos-this.y_center)) <= this.radius)
    }
    
    draw() {
        let theta = Math.PI * 2 / this.steps;
        turtle.penup();
        turtle.goto(this.x_center + this.radius * Math.cos(theta * 0), this.y_center + this.radius * Math.sin(theta * 0))
        turtle.pendown();
        for(let i = 0; i <= this.steps; i++) {
            let x = this.x_center + this.radius * Math.cos(theta * i);
            let y = this.y_center + this.radius * Math.sin(theta * i);
            turtle.goto(x,y);
        }
    }
}

function line(x1,y1,x2,y2) {
    turtle.penup();
    turtle.goto(x1, y1);
    turtle.pendown();
    turtle.goto(x2, y2);
}

function egg(steps, x_center, y_center, a, b, d, theta) {
    let t = Math.PI * 2 / steps;
    turtle.penup();
    for(i = 0; i <= steps; i++) {
        if(i == 1) {
            turtle.pendown();
        }
        x = (Math.sqrt(a*a - d*d*Math.sin(t*i)*Math.sin(t*i)) + d*Math.cos(t*i))*Math.cos(t*i);
        y = b*Math.sin(t*i);
        x_r = x_center + Math.cos(theta)*x - Math.sin(theta)*y;
        y_r = y_center + Math.sin(theta)*x + Math.cos(theta)*y;
        turtle.goto(x_r,y_r);
    }
}


egg_location_list = [];
for(let i = 0; i < 15; i++) {
    let pos_radius = Math.random()*radius_min - egg_scale*5;
    let pos_angle = Math.random()*Math.PI*2;
    let x_center = Math.cos(pos_angle)*pos_radius;
    let y_center = Math.sin(pos_angle)*pos_radius;
    let rotation = Math.random()*Math.PI*2;
    let to_draw = true;
    for(let j = 0; j < egg_location_list.length; j++) {
        let distance_between_eggs = Math.sqrt(Math.pow(egg_location_list[j][0]-x_center, 2) + Math.pow(egg_location_list[j][1]-y_center, 2));
        if(distance_between_eggs < 14*egg_scale) {
            to_draw = false;
        }
    }
    if(to_draw) {
        egg_location_list.push([x_center, y_center])
        let a = 7.5*egg_scale + Math.random()*egg_randomness - egg_randomness;
        let b = 5.1*egg_scale + Math.random()*egg_randomness - egg_randomness;
        let d = 1.8*egg_scale + Math.random()*egg_randomness - egg_randomness;
        egg(50, x_center, y_center, a, b, d, rotation);
    }
}

for(let i = 0; i < stick_count; i++) {
    let pos_radius = Math.random()*radius_range+radius_min;
    let pos_angle = Math.random()*Math.PI*2;
    let x_center = Math.cos(pos_angle)*pos_radius;
    let y_center = Math.sin(pos_angle)*pos_radius;
    let height = Math.random()*height_rand+pos_radius*height_scale;
    let width = Math.random()*width_rand+pos_radius*width_scale;
    let rotation = Math.atan(y_center/x_center) + Math.random()*0.1 - 0.05;
    let rect1 = new Rectangle(height, width, x_center, y_center, rotation);
    rect1.draw();
}