A Javascript+SVG implementation of a Gosper space-filling curve. See Akiyama et al. 2007 for reference.
The code is really messy, with too few comments and not optimized. :D
A Javascript+SVG implementation of a Gosper space-filling curve. See Akiyama et al. 2007 for reference.
The code is really messy, with too few comments and not optimized. :D
| # Hexagonal Directions: | |
| # E F | |
| # | |
| # D O A | |
| # | |
| # C B | |
| HEX_DIRS = 'abcdef' | |
| GOSPER_GEN = 'AfdEAAb' # lowercase letter indicate that the generator must be applied in reverse | |
| fractalize_step = (seq, gen) -> | |
| res_seq = '' | |
| for el in seq | |
| tmp_seq = '' | |
| delta = HEX_DIRS.indexOf(el.toLowerCase()) | |
| for gen_el in gen | |
| new_el = HEX_DIRS[(HEX_DIRS.indexOf(gen_el.toLowerCase()) + delta) % 6] | |
| if gen_el.toUpperCase() == gen_el | |
| new_el = new_el.toUpperCase() | |
| tmp_seq += new_el | |
| if el.toLowerCase() == el | |
| tmp_seq = tmp_seq.split('').reverse() | |
| # the reversed sequence must also have reversed case | |
| for i in [0...tmp_seq.length] | |
| if tmp_seq[i].toLowerCase() == tmp_seq[i] | |
| tmp_seq[i] = tmp_seq[i].toUpperCase() | |
| else | |
| tmp_seq[i] = tmp_seq[i].toLowerCase() | |
| tmp_seq = tmp_seq.join('') | |
| res_seq += tmp_seq | |
| return res_seq | |
| fractalize = (gen, stage) -> | |
| seq = gen | |
| for i in [0...stage-1] | |
| seq = fractalize_step(seq, gen) | |
| return seq | |
| # this is somehow similar to a triangular grid | |
| A = 3 | |
| TRI_LINES = { | |
| 'a': "l#{2*A} 0", | |
| 'b': "l#{A} #{A*Math.sqrt(3)}", | |
| 'c': "l#{-A} #{A*Math.sqrt(3)}", | |
| 'd': "l#{-2*A} 0", | |
| 'e': "l#{-A} #{-A*Math.sqrt(3)}", | |
| 'f': "l#{A} #{-A*Math.sqrt(3)}" | |
| } | |
| window.main = () -> | |
| seq = fractalize(GOSPER_GEN, 4) | |
| d = 'M0 0' | |
| for el in seq | |
| d += TRI_LINES[el.toLowerCase()] | |
| width = 960 | |
| height = 500 | |
| svg = d3.select('body').append('svg') | |
| .attr('width', width) | |
| .attr('height', height) | |
| svg.append('path') | |
| .attr('class', 'gosper') | |
| .attr('d', d) | |
| .attr('transform', 'translate(500,390)') | |
| .gosper { | |
| fill: none; | |
| stroke: black; | |
| stroke-width: 1.5px; | |
| } |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <title>Gosper 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> |
| (function() { | |
| var A, GOSPER_GEN, HEX_DIRS, TRI_LINES, fractalize, fractalize_step; | |
| HEX_DIRS = 'abcdef'; | |
| GOSPER_GEN = 'AfdEAAb'; | |
| fractalize_step = function(seq, gen) { | |
| var delta, el, gen_el, i, new_el, res_seq, tmp_seq, _i, _j, _len, _len2, _ref; | |
| res_seq = ''; | |
| for (_i = 0, _len = seq.length; _i < _len; _i++) { | |
| el = seq[_i]; | |
| tmp_seq = ''; | |
| delta = HEX_DIRS.indexOf(el.toLowerCase()); | |
| for (_j = 0, _len2 = gen.length; _j < _len2; _j++) { | |
| gen_el = gen[_j]; | |
| new_el = HEX_DIRS[(HEX_DIRS.indexOf(gen_el.toLowerCase()) + delta) % 6]; | |
| if (gen_el.toUpperCase() === gen_el) new_el = new_el.toUpperCase(); | |
| tmp_seq += new_el; | |
| } | |
| if (el.toLowerCase() === el) { | |
| tmp_seq = tmp_seq.split('').reverse(); | |
| for (i = 0, _ref = tmp_seq.length; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) { | |
| if (tmp_seq[i].toLowerCase() === tmp_seq[i]) { | |
| tmp_seq[i] = tmp_seq[i].toUpperCase(); | |
| } else { | |
| tmp_seq[i] = tmp_seq[i].toLowerCase(); | |
| } | |
| } | |
| tmp_seq = tmp_seq.join(''); | |
| } | |
| res_seq += tmp_seq; | |
| } | |
| return res_seq; | |
| }; | |
| fractalize = function(gen, stage) { | |
| var i, seq, _ref; | |
| seq = gen; | |
| for (i = 0, _ref = stage - 1; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) { | |
| seq = fractalize_step(seq, gen); | |
| } | |
| return seq; | |
| }; | |
| A = 3; | |
| TRI_LINES = { | |
| 'a': "l" + (2 * A) + " 0", | |
| 'b': "l" + A + " " + (A * Math.sqrt(3)), | |
| 'c': "l" + (-A) + " " + (A * Math.sqrt(3)), | |
| 'd': "l" + (-2 * A) + " 0", | |
| 'e': "l" + (-A) + " " + (-A * Math.sqrt(3)), | |
| 'f': "l" + A + " " + (-A * Math.sqrt(3)) | |
| }; | |
| window.main = function() { | |
| var d, el, height, seq, svg, width, _i, _len; | |
| seq = fractalize(GOSPER_GEN, 4); | |
| d = 'M0 0'; | |
| for (_i = 0, _len = seq.length; _i < _len; _i++) { | |
| el = seq[_i]; | |
| d += TRI_LINES[el.toLowerCase()]; | |
| } | |
| width = 960; | |
| height = 500; | |
| svg = d3.select('body').append('svg').attr('width', width).attr('height', height); | |
| return svg.append('path').attr('class', 'gosper').attr('d', d).attr('transform', 'translate(500,390)'); | |
| }; | |
| }).call(this); |
| .gosper | |
| fill: none | |
| stroke: black | |
| stroke-width: 1.5px | |