Skip to content

Instantly share code, notes, and snippets.

@edin-m
Last active October 19, 2018 22:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save edin-m/eed2af5542d60acc6bd7bdc82f9e38a6 to your computer and use it in GitHub Desktop.
Save edin-m/eed2af5542d60acc6bd7bdc82f9e38a6 to your computer and use it in GitHub Desktop.
L-Systems
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas id="canvas" width="600" height="600" style="border: 1px solid black"></canvas>
<script src="index.js"></script>
</body>
</html>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext('2d');
const canvasSize = { width: 600, height: 600 };
const lSystem = {
_rules: {
'0': '1[0]0',
'1': '11'
},
_applyRules: function(ch) {
let newStr = '';
if (this._rules[ch]) {
newStr = this._rules[ch];
} else {
newStr = ch;
}
return newStr;
},
createLSystem: function(numIter, axiom) {
let system = axiom;
while(numIter-- > 0) {
system = this._processString(system);
console.log(numIter, system);
}
return system;
},
_processString: function(oldStr) {
let newStr = '';
for (let i = 0; i < oldStr.length; i++) {
let ch = oldStr.charAt(i);
let rules = this._applyRules(ch);
newStr += rules;
}
return newStr;
}
};
function Vec2d(x, y) {
if (!(this instanceof Vec2d)) {
return new Vec2d(x, y);
}
this.x = x;
this.y = y;
this.add = function(vec) {
this.x += vec.x;
this.y += vec.y;
return this;
};
this.scale = function(factor) {
this.x *= factor;
this.y *= factor;
return this;
};
}
function LSystemPainter(ctx, size, startPoint, lSystemStr) {
this.ctx = ctx;
this.size = size;
this.startPoint = startPoint;
this.lSystemStr = lSystemStr;
this.angleStepDeg = 45;
this.angleRad = toRad(this.angleStepDeg);
this.segmentLength = 5;
this.currentAngle = -90;
this.stack = [];
this._actions = {
'1': function() {
this.pos.add(vecFromAngle(this.currentAngle).scale(this.segmentLength));
this.ctx.lineTo(this.pos.x, this.pos.y);
},
'0': function() {
this.pos.add(vecFromAngle(this.currentAngle).scale(this.segmentLength));
this.ctx.lineTo(this.pos.x, this.pos.y);
this.ctx.save();
this.ctx.fillRect(this.pos.x - 3, this.pos.y - 3, 6, 6);
},
'[': function() {
this._pushStack(this.pos);
},
']': function() {
this._popStack(this.pos);
}
};
this.draw = function() {
this.pos = Vec2d(this.startPoint.x, this.startPoint.y);
this.ctx.beginPath();
this.ctx.moveTo(this.pos.x, this.pos.y);
for (let i = 0; i < this.lSystemStr.length; i++) {
let ch = this.lSystemStr.charAt(i);
if (this._actions[ch] !== null) {
this._actions[ch].call(this);
}
}
this.ctx.stroke();
};
this._addAngle = function(angle) {
this.currentAngle += angle;
this.currentAngle = this.currentAngle % 360;
};
this._pushStack = function(pos) {
this.stack.push({
currentAngle: this.currentAngle,
pos: { x: pos.x, y: pos.y }
});
this._addAngle(-this.angleStepDeg);
};
this._popStack = function() {
if (this.stack.length > 0) {
const item = this.stack.pop();
this.currentAngle = item.currentAngle;
this.pos.x = item.pos.x;
this.pos.y = item.pos.y;
this._addAngle(this.angleStepDeg);
this.ctx.moveTo(this.pos.x, this.pos.y);
}
};
}
const lSystemStr = lSystem.createLSystem(7, '0');
console.log(lSystemStr);
const painter = new LSystemPainter(ctx, canvasSize, { x: 300, y: 598 }, lSystemStr);
painter.draw();
// ---
function vecFromAngle(angle) {
const rad = toRad(angle);
return Vec2d(Math.cos(rad), Math.sin(rad));
}
function toDeg(x) {
return x * 180 / Math.PI;
}
function toRad(x) {
return x * Math.PI / 180.0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment