Skip to content

Instantly share code, notes, and snippets.

@sebassdc
Last active May 30, 2018 11:23
Show Gist options
  • Save sebassdc/fd6f12820ba5cddcbab908479323666e to your computer and use it in GitHub Desktop.
Save sebassdc/fd6f12820ba5cddcbab908479323666e to your computer and use it in GitHub Desktop.
const degToRad = deg => (deg / 180) * Math.PI
const radToDeg = rad => rad * 180 / Math.PI;
class Turtle {
constructor(ctx) {
this.ctx = ctx
// Set initial orientation and position
this.orientation = 0;
this.position = {x: 0, y: 0}
}
// Make a cartesian cordinate system
_centerCoords() {
this.ctx.translate(this.ctx.canvas.width / 2, this.ctx.canvas.height / 2);
this.ctx.transform(1, 0, 0, -1, 0, 0);
}
_clearContext() {
this.ctx.save();
this.ctx.setTransform(1,0,0,1,0,0);
this.ctx.clearRect(0,0,this.ctx.canvas.width,this.ctx.canvas.height);
this.ctx.restore();
}
goto(x, y){
this.position = { x, y }
}
fd(length) {
// Ctx stuff
this.ctx.save()
this._centerCoords()
this.ctx.beginPath()
// Calculate new position
const { x, y } = this.position
const newX = x + Math.sin(this.orientation) * length
const newY = y + Math.cos(this.orientation) * length
// The thing
this.ctx.moveTo(x,y) // Move the turtle to the current position
this.ctx.lineTo(newX, newY)
//Store new position
this.position = {
x: newX,
y: newY,
}
this.ctx.stroke(); // Draw
this.ctx.restore(); // Get old context mode
}
bk(length) {
// Ctx stuff
this.ctx.save()
this._centerCoords()
this.ctx.beginPath()
// Calculate new position
const { x, y } = this.position
const newX = x + Math.sin(this.orientation + degToRad(180)) * length
const newY = y + Math.cos(this.orientation + degToRad(180)) * length
// The thing
console.log(newX, newY)
this.ctx.moveTo(x,y) // Move the turtle to the current position
this.ctx.lineTo(newX, newY)
//Store new position
this.position = {
x: newX,
y: newY,
}
this.ctx.stroke(); // Draw
this.ctx.restore(); // Get old context mode
}
rt(angle) {
this.orientation += degToRad(angle)
}
lt(angle) {
this.orientation -= degToRad(angle)
}
}
/// range(5) -> [0, 1, 2, 3, 4]
const range = n => [...Array(n).keys()]
const genSystem = ({
inicio = '',
variables = [],
constantes = [],
reglas = {},
}) => n =>
range(n+1)
.reduce(
(acc, actu, index, arr) => [
...acc,
acc[index]
.split('')
.map(e => (constantes.indexOf(e) === -1) ? reglas[e] : e)
.join('')
],
[inicio]
)[n]
const genDrawer = ({turtle, angle, length, descriptor}) =>
Object
.keys(descriptor)
.map(e => () =>
turtle[descriptor[e]](
descriptor[e] == 'rt' || descriptor[e] == 'lt'
? angle
: length
)
)
.reduce(
(acc, actu, index, arr) => ({
...acc,
[Object.keys(descriptor)[index]]: actu,
}),
{}
)
const drawSystem = ({sys, n, ...rest}) => {
const drawer = genDrawer(rest)
sys(n)
.split('')
.forEach(e =>
(drawer[e] || (()=>{}))()
)
}
const genSystemDrawer = ({
descriptor,
sys,
angle,
}) => turtle => iterStuff => {
drawSystem({
sys,
turtle,
descriptor,
angle,
...iterStuff
})
}
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
const bob = new Turtle(ctx)
const standartDescriptor = {
'F': 'fd',
'+': 'rt',
'-': 'lt'
}
const kotchCurve90 = genSystemDrawer({
angle: 90,
sys: genSystem({
variables: ['F'],
constantes: ['+', '-'],
reglas: {
'F': 'F-F+F+F-F',
},
inicio: 'F'
}),
descriptor: standartDescriptor,
})
const kotchCurve60 = genSystemDrawer({
angle: 60,
sys: genSystem({
variables: ['F'],
constantes: ['+', '-'],
reglas: {
'F': 'F+F--F+F',
},
inicio: 'F'
}),
descriptor: standartDescriptor
})
const curve32Seg = genSystemDrawer({
angle: 90,
sys: genSystem({
variables: ['F'],
constantes: ['+', '-'],
reglas: {
'F': '-F+F-F-F+F+FF-F+F+FF+F-F-FF+FF-FF+F+F-FF-F-F+FF-F-F+F+F-F+'
},
inicio: 'F',
}),
descriptor: standartDescriptor,
})
const hilbertCurve = genSystemDrawer({
angle: 90,
sys: genSystem({
variables: ['L', 'R'],
constantes: ['+', '-', 'F'],
reglas: {
'L': '+RF-LFL-FR+',
'R': '-LF+RFR+FL-'
},
inicio: 'L',
}),
descriptor: standartDescriptor,
})
const sierpinskiTriangle = genSystemDrawer({
angle: 120,
sys: genSystem({
variables: ['F', 'G'],
constantes: ['+', '-'],
inicio: 'F-G-G',
reglas: {
'F': 'F-G+F+G-F',
'G': 'GG'
},
}),
descriptor: {
'F': 'fd',
'G': 'fd',
'+': 'lt',
'-': 'rt',
},
})
const sierpinskiCurve = genSystemDrawer({
angle: 60,
sys: genSystem({
variables: ['A', 'B'],
constantes: ['+', '-'],
inicio: 'A',
reglas: {
'A': 'B-A-B',
'B': 'A+B+A'
},
}),
descriptor: {
'A': 'fd',
'B': 'fd',
'+': 'lt',
'-': 'rt',
},
})
const dragonCurve = genSystemDrawer({
sys: genSystem({
inicio: 'FX',
variables: ['X', 'Y'],
constantes: ['F', '+', '-'],
reglas: {
'X': 'X+YF+',
'Y': '-FX-Y',
}
}),
angle: 90,
descriptor: standartDescriptor,
})
const peanoGosperCurve = genSystemDrawer({
sys: genSystem({
inicio: 'X',
variables: ['X', 'Y'],
constantes: ['F', '+', '-'],
reglas: {
'X': 'X+YF++YF-FX--FXFX-YF+',
'Y': '-FX+YFYF++YF+FX--FX-Y',
}
}),
angle: 60,
descriptor: standartDescriptor,
})
const peanoCurve = genSystemDrawer({
sys: genSystem({
inicio: 'F',
variables: ['F'],
constantes: ['+', '-'],
reglas: {
'F': 'F+F-F-F-F+F+F+F-F',
}
}),
angle: 90,
descriptor: standartDescriptor,
})
const quadraticKochIsland = genSystemDrawer({
sys: genSystem({
inicio: 'F-F-F-F',
variables: ['F'],
constantes: ['+', '-'],
reglas: {
'F': 'F-F+F+FFF-F-F+F',
}
}),
angle: 90,
descriptor: standartDescriptor,
})
const squareCurve = genSystemDrawer({
sys: genSystem({
inicio: 'F+XF+F+XF',
variables: ['X'],
constantes: ['+', '-', 'F'],
reglas: {
'X': 'XF-F+F-XF+F+XF-F+F-X',
}
}),
angle: 90,
descriptor: standartDescriptor,
})
bob.goto(0, 300)
bob.rt(90)
squareCurve(bob)({
n: 5,
length: 4.7,
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment