Skip to content

Instantly share code, notes, and snippets.

@nitaku
Last active December 22, 2015 20:29
Show Gist options
  • Save nitaku/6526710 to your computer and use it in GitHub Desktop.
Save nitaku/6526710 to your computer and use it in GitHub Desktop.
Moore curve (L-system)

A Moore space-filling looping curve drawn with an implementation of an L-system renderer.

The Moore curve is a looping variation of a Hilbert curve, obtained by justaxposing 4 Hilbert curves. The last and the first point could be connected in order to draw a closed line.

The L-system rules are the same defined for the Hilbert curve, but the axiom is different.

The drawing of the line is animated using Mike Bostock's stroke dash interpolation.

### compute a Lindenmayer system given an axiom, a number of steps and rules ###
fractalize = (config) ->
input = config.axiom
for i in [0...config.steps]
output = ''
for char in input
if char of config.rules
output += config.rules[char]
else
output += char
input = output
return output
### convert a Lindenmayer string into an SVG path string ###
svg_path = (config) ->
angle = 0.0
path = 'M0 0'
for char in config.fractal
if char == '+'
angle += config.angle
else if char == '-'
angle -= config.angle
else if char == 'F'
path += "l#{config.side * Math.cos(angle)} #{config.side * Math.sin(angle)}"
return path
window.main = () ->
moore = fractalize
axiom: 'AFA+F+AFA'
steps: 5
rules:
A: '-BF+AFA+FB-'
B: '+AF-BFB-FA+'
d = svg_path
fractal: moore
side: 6
angle: Math.PI/2
width = 960
height = 500
svg = d3.select('body').append('svg')
.attr('width', width)
.attr('height', height)
svg.append('path')
.attr('class', 'curve shadow')
.attr('d', d)
.attr('transform', 'translate(300,250)')
svg.append('path')
.attr('class', 'curve')
.attr('d', d)
.attr('transform', 'translate(300,250)')
.call(transition)
### animate the path ###
### from Mike Bostock's stroke dash interpolation example http://bl.ocks.org/mbostock/5649592 ###
tweenDash = () ->
l = this.getTotalLength()
i = d3.interpolateString('0,' + l, l + ',' + l)
return (t) -> i(t)
transition = (path) ->
path.transition()
.duration(20000)
.attrTween('stroke-dasharray', tweenDash)
.curve {
fill: none;
stroke: black;
stroke-width: 1.5px;
}
.shadow {
opacity: 0.1;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Moore curve</title>
<link type="text/css" href="index.css" rel="stylesheet"/>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="index.js"></script>
</head>
<body onload="main()"></body>
</html>
/* compute a Lindenmayer system given an axiom, a number of steps and rules
*/
(function() {
var fractalize, svg_path, transition, tweenDash;
fractalize = function(config) {
var char, i, input, output, _i, _len, _ref;
input = config.axiom;
for (i = 0, _ref = config.steps; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) {
output = '';
for (_i = 0, _len = input.length; _i < _len; _i++) {
char = input[_i];
if (char in config.rules) {
output += config.rules[char];
} else {
output += char;
}
}
input = output;
}
return output;
};
/* convert a Lindenmayer string into an SVG path string
*/
svg_path = function(config) {
var angle, char, path, _i, _len, _ref;
angle = 0.0;
path = 'M0 0';
_ref = config.fractal;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
char = _ref[_i];
if (char === '+') {
angle += config.angle;
} else if (char === '-') {
angle -= config.angle;
} else if (char === 'F') {
path += "l" + (config.side * Math.cos(angle)) + " " + (config.side * Math.sin(angle));
}
}
return path;
};
window.main = function() {
var d, height, moore, svg, width;
moore = fractalize({
axiom: 'AFA+F+AFA',
steps: 5,
rules: {
A: '-BF+AFA+FB-',
B: '+AF-BFB-FA+'
}
});
d = svg_path({
fractal: moore,
side: 6,
angle: Math.PI / 2
});
width = 960;
height = 500;
svg = d3.select('body').append('svg').attr('width', width).attr('height', height);
svg.append('path').attr('class', 'curve shadow').attr('d', d).attr('transform', 'translate(300,250)');
return svg.append('path').attr('class', 'curve').attr('d', d).attr('transform', 'translate(300,250)').call(transition);
};
/* animate the path
*/
/* from Mike Bostock's stroke dash interpolation example http://bl.ocks.org/mbostock/5649592
*/
tweenDash = function() {
var i, l;
l = this.getTotalLength();
i = d3.interpolateString('0,' + l, l + ',' + l);
return function(t) {
return i(t);
};
};
transition = function(path) {
return path.transition().duration(20000).attrTween('stroke-dasharray', tweenDash);
};
}).call(this);
.curve
fill: none
stroke: black
stroke-width: 1.5px
.shadow
opacity: 0.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment