NEWPOLY

From "Turtle Geometry" by Harold Abelson, 1980

I tried making a self-centering turtle for this, since the book's examples don't seem to care about absolute position.

ANGLE = 104: NEWPOLY (variation)

Variations from the book:
ANGLE = 30: NEWPOLY (variation)
ANGLE = 144: NEWPOLY (variation)
ANGLE = 45: NEWPOLY (variation)
ANGLE = 125: NEWPOLY (variation)

Log in to post a comment.

class AutoTurtle{#pos=[0,0];#heading=0;#pen_down=true;#is_radians=false;#current_line=[];#lines=[];#bounds;goto(loc){if(this.#pen_down){if(this.#current_line.length===0){this.#current_line.push(this.#pos);this.#bounds=update_bounds(this.#pos,this.#bounds)}this.#current_line.push(loc);this.#bounds=update_bounds(loc,this.#bounds)}this.#pos=loc}jump(loc){const start_down=this.#pen_down;if(start_down)this.penup();this.goto(loc);if(start_down)this.pendown()}forward(distance){const next=vector_from(this.#pos,this.#heading,distance);this.goto(next)}backward(distance){this.forward(-distance)}right(angle){if(!this.#is_radians)angle=degToRad(angle);this.#heading+=angle}left(angle){this.right(-angle)}degrees(){this.#is_radians=false}radians(){this.#is_radians=true}pendown(){this.#pen_down=true}penup(){if(this.#current_line.length!==0){this.#lines.push(this.#current_line);this.#current_line=[]}this.#pen_down=false}pos(){return this.#pos}*lines(){yield*this.#lines;if(this.#current_line.length!==0)yield this.#current_line}exportToTurtle(turtle,opt={}){const margin=opt?.margin??0;const scale=opt?.scale??true;const shift=opt?.shift??true;const export_bounds=[[-100+margin,-100+margin],[100-margin,100-margin]];if(this.#lines.length===0&&this.#current_line.length===0)throw"Empty Turtle";const[shift_by,scale_by]=center_within(this.#bounds,export_bounds);const[shift_x,shift_y]=shift?shift_by:[0,0];const[scale_x,scale_y]=scale?scale_by:[1,1];const convert=([x,y])=>[(x+shift_x)*scale_x,(y+shift_y)*scale_y];for(const line of this.lines()){turtle.pendown();turtle.jump(convert(line[0]));for(const point of line){turtle.goto(convert(point))}}turtle.penup()}}function degToRad(degrees){return degrees*(Math.PI/180)}function radToDeg(rad){return rad/(Math.PI/180)}function vector_from([x,y],angle,distance){const dx=Math.cos(angle)*distance;const dy=Math.sin(angle)*distance;return[x+dx,y+dy]}function*flatten(iteriter){for(const iter of iteriter){for(const item of iter){yield item}}}function update_bounds(point,bounds){if(bounds===void 0)return[point,point];const[x,y]=point;let[[min_x,min_y],[max_x,max_y]]=bounds;if(x<min_x)min_x=x;if(y<min_y)min_y=y;if(x>max_x)max_x=x;if(y>max_y)max_y=y;return[[min_x,min_y],[max_x,max_y]]}function size_of(bounds){const width=bounds[1][0]-bounds[0][0];const height=bounds[1][1]-bounds[0][1];return[width,height]}function center_of(bounds){const[width,height]=size_of(bounds);return[bounds[0][0]+width/2,bounds[0][1]+height/2]}function center_within(original,desired){const[original_width,original_height]=size_of(original);const[desired_width,desired_height]=size_of(desired);const delta_width=desired_width/original_width;const delta_height=desired_height/original_height;const scale_factor=delta_height<=delta_width?delta_height:delta_width;const original_center=center_of(original);const desired_center=center_of(desired);const shift_factor=[desired_center[0]-original_center[0],desired_center[1]-original_center[1]];return[shift_factor,[scale_factor,scale_factor]]}function bounds_of(point_iter){let bounds;for(const point of point_iter){bounds=update_bounds(point,bounds)}return bounds}

const ANGLE = 56; // min=1, max=179, step=1
const SIDE = 10; // min=1, max=100, step=1
const auto_fit = 1; // min=0, max=1, step=1 (No, Yes)
const MAX_ITER = 256;

const t = auto_fit ? new AutoTurtle() : new Turtle();

for (let i = 0; i < MAX_ITER; i++) {
    t.forward(SIDE);
    t.right(ANGLE);
    t.forward(SIDE);
    t.right(2*ANGLE);
}

if (auto_fit) {
    const real_turtle = new Turtle();
    t.exportToTurtle(real_turtle, {margin: 20});
}