Dragon curve/D/QD
Appearance
module lsystem;
import qd;
interface LSystemI {
void setCallback(void delegate(int, int) cb);
void BaseStep(int depth);
int x(); int y();
int x(int); int y(int);
}
class LSystem(int ANGLES) : LSystemI {
int angle, _x, _y;
// define as properties so they can appear in the interface description
int x() { return _x; }
int y() { return _y; }
int x(int i) { return _x = i; }
int y(int i) { return _y = i; }
static assert(ANGLES == 4 || ANGLES == 8, "Unsupported number of angles!");
void right() { angle ++; if (angle == ANGLES) angle = 0; }
void left() { angle --; if (angle == -1) angle = ANGLES - 1; }
int stepsize;
void delegate(int, int) dgPoint;
void setCallback(typeof(dgPoint) cb) { dgPoint = cb; }
void step() {
static if (ANGLES == 4) {
// 0
// 3 1
// 2
const xshift = [0, 1, 0, -1];
const yshift = [-1, 0, 1, 0];
} else {
// 701
// 6 2
// 543
const xshift = [-1, 0, 1, 1, 1, 0, -1, -1];
const yshift = [-1, -1, -1, 0, 1, 1, 1, 0];
}
auto
newx = x + xshift[angle] * stepsize,
newy = y + yshift[angle] * stepsize;
dgPoint(newx, newy);
x = newx; y = newy;
}
abstract void BaseStep(int depth);
}
import tools.base;
// compile-time function
string LSysFunc(string syntax) {
auto namepos = syntax.ctFind("->");
assert(namepos != -1, "LSystem function definition syntax: Varname -> Replacement");
auto name = syntax[0 .. namepos].ctStrip(); syntax = syntax[namepos+2 .. $].ctStrip();
auto endpos = syntax.ctFind("/");
string endact;
if (endpos != -1) {
endact = syntax[endpos+1 .. $].ctStrip();
syntax = syntax[0 .. endpos].ctStrip();
}
if (endact.length && endact[$-1] != ';') endact ~= ';'; // terminate statement
string res = "void "~name~"(int depth) { if (!depth) { "~endact~" return; } ";
foreach (ch; syntax) {
if (ch == '+') res ~= "right; ";
else if (ch == '-') res ~= "left; ";
else if (ch == 'F') res ~= "step; ";
else res ~= ch~"(depth - 1); ";
}
res ~= " }";
return res;
}
class Heighway : LSystem!(4) {
mixin(LSysFunc("X -> X+YF+"));
mixin(LSysFunc("Y -> -FX-Y"));
override void BaseStep(int depth) { X(depth); }
}
class Lévy : LSystem!(8) {
mixin(LSysFunc("X -> +X--X+ / step"));
override void BaseStep(int depth) { X(depth); }
}
void drawSystemFade(rgb start, rgb end, LSystemI ls, int depth) {
with (ls) {
int numPoints;
// acquire number of points
setCallback = (int x, int y) { numPoints ++; };
BaseStep(depth);
// draw with fade from red to green
int count;
setCallback = (int newx, int newy) {
auto color = start.blend(end, count * 1.0 / numPoints);
line(x, y, newx, newy, color);
count ++;
};
BaseStep(depth);
}
}
import tools.time: sleep;
void main() {
screen(640, 480);
auto h = new Heighway;
h.x = screen.width * 5 / 8;
h.y = screen.height * 5 / 6;
h.stepsize = 1;
drawSystemFade(Red, Green, h, 16);
auto l = new Lévy;
l.x = screen.width * 1 / 6;
l.y = screen.height * 5 / 6;
l.stepsize = 1;
l.right;
drawSystemFade(Red, Green, l, 14);
while (true) { flip; events; }
}
Screenshot: [1]