Arcs & Lines and Corners & Sides
All Two-Part Combinations of Arcs From Corners and Sides & Straight, Not Straight and Broken Lines by Sol Lewitt
I saw this in a museum and immediately knew that I would recreate it in a program some day. His work is generally conducive to it.
Log in to post a comment.
const turtle = new Turtle();
const squareWidth = 14;
function square() {
turtle.seth(0);
for (let i = 0; i < 4; i++) {
turtle.fd(squareWidth);
turtle.rt(90);
}
}
function moveToCorner(i) {
turtle.penup();
for (let j = 0; j < i; j++) {
turtle.fd(squareWidth);
turtle.rt(90);
}
turtle.pendown();
}
function cornerArc(i) {
return () => {
moveToCorner(i);
turtle.seth(i * 90);
turtle.circle(squareWidth, 90);
};
}
function sideArc(i) {
return () => {
moveToCorner(i);
turtle.penup();
turtle.fd(squareWidth / 2);
turtle.pendown();
turtle.seth(i * 90 + 45);
turtle.circle(Math.sqrt(2) * squareWidth / 2, 90);
};
}
function straight(length) {
turtle.fd(length);
}
// stolen
class Perlin {
constructor() {
// Quick and dirty permutation table
this.perm = (() => {
const tmp = Array.from({length: 256}, () => Math.floor(Math.random() * 256));
return tmp.concat(tmp);
})();
}
grad(i, x) {
const h = i & 0xf;
const grad = 1 + (h & 7);
if ((h & 8) !== 0) {
return -grad * x;
}
return grad * x;
}
getValue(x) {
const i0 = Math.floor(x);
const i1 = i0 + 1;
const x0 = x - i0;
const x1 = x0 - 1;
let t0 = 1 - x0 * x0;
t0 *= t0;
let t1 = 1 - x1 * x1;
t1 *= t1;
const n0 = t0 * t0 * this.grad(this.perm[i0 & 0xff], x0);
const n1 = t1 * t1 * this.grad(this.perm[i1 & 0xff], x1);
return 0.395 * (n0 + n1); //Output is between -1 and 1.
}
}
function notStraight(length) {
function envelope(x, y) {
const flatLength = Math.ceil(length / 5);
// double-sided sigmoid envelope
return Math.floor(y * ((1 / (1 + Math.pow(Math.E, flatLength - x))) + (1 / (1 + Math.pow(Math.E, x - (length - flatLength)))) - 1));
}
const range = length / 4;
const perlin = new Perlin();
const yCoords = Array.from({ length }, (_, x) => envelope(x, range * perlin.getValue(x * 0.1)));
console.log(yCoords);
let prevHeading = 0;
let prevY = 0;
for (let x = 0; x < yCoords.length; x++) {
const currY = yCoords[x];
const yDist = currY - prevY;
const currHeading = Math.atan2(yDist, 1) * 180 / Math.PI;
const dist = Math.sqrt(yDist * yDist + 1);
turtle.lt(currHeading - prevHeading);
turtle.fd(dist);
prevY = currY;
prevHeading = currHeading;
}
}
function broken(length) {
const dashLength = 2;
const gapLength = 1;
for (let i = 0; i < length; i++) {
if (i % (dashLength + gapLength) < dashLength) {
turtle.pendown();
} else {
turtle.penup();
}
turtle.fd(1);
}
}
function line(drawLine) {
return (i) => () => {
turtle.penup();
let length = 0;
switch (i) {
case 0:
turtle.fd(squareWidth / 2);
turtle.rt(90);
length = squareWidth;
break;
case 1:
turtle.rt(90);
turtle.fd(squareWidth / 2);
turtle.lt(90);
length = squareWidth;
break;
case 2:
turtle.fd(squareWidth);
turtle.rt(135);
length = Math.floor(i / 2) * Math.sqrt(2) * squareWidth;
break;
case 3:
turtle.rt(45);
length = Math.floor(i / 2) * Math.sqrt(2) * squareWidth;
break;
}
turtle.pendown();
drawLine(length);
};
}
const types = [cornerArc, sideArc, line(straight), line(notStraight), line(broken)];
const singles = Array.from({length: 20}, (_, i) => types[Math.floor(i / 4)](i % 4));
function indices(i) {
let j = 0;
for (let single1 = 0; single1 < singles.length; single1++){
for (let single2 = single1; single2 < singles.length; single2++) {
if (single1 !== single2) {
if (i === j) {
return [single1, single2];
}
j++;
}
}
}
}
Canvas.setpenopacity(1);
function walk(i) {
const rowWidth = 14;
indicesToDraw = indices(i);
console.log(i, indicesToDraw);
for (let j = 0; j < indicesToDraw.length; j++) {
turtle.penup();
turtle.seth(0);
turtle.setx((i % rowWidth) * (squareWidth) - 98);
turtle.sety(Math.floor(i / rowWidth) * (squareWidth) - 98);
turtle.pendown();
singles[indicesToDraw[j]]();
}
return i < 189;
}