block by mbostock 6905926

Snowflake Simplification

Full Screen

An update of Jason Davies’ Quadratic Koch Island Simplification stress test.

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<style>

.koch {
  fill: #eee;
  stroke: #000;
}

.overlay {
  fill: none;
  pointer-events: all;
}

</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script>

var width = 960,
    height = 500;

var area = 1, simplify = d3.geo.transform({
  point: function(x, y, z) {
    if (z >= area) this.stream.point(x, y);
  }
});

var x = d3.scale.sqrt()
    .domain([0, 1e4])
    .range([0, width]);

var path = d3.geo.path()
    .projection(simplify);

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

svg.append("rect")
    .attr("class", "overlay")
    .attr("width", width)
    .attr("height", height)
    .on("mousemove", mousemoved);

d3.json("snowflake.json", function(error, topo) {
  if (error) throw error;

  svg.insert("path", ".overlay")
      .datum(topojson.feature(topojson.presimplify(topo), topo.objects.snowflake))
      .attr("class", "koch")
      .attr("d", path);
});

function mousemoved() {
  area = x.invert(d3.mouse(this)[0]);
  svg.select(".koch").attr("d", path);
}

</script>

Makefile

all: snowflake.json

clean:
	rm -f -- snowflake.json

snowflake.json: create-snowflake
	./create-snowflake | \
		node_modules/.bin/topojson \
			-o $@ \
			-q 0 \
			--cartesian \
			-- \
			snowflake=/dev/stdin

create-snowflake

#!/usr/bin/env node

var width = 960,
    height = 500;

console.log(JSON.stringify({
  type: "GeometryCollection",
  geometries: [
    lSystem("FRFRFRFR", "FLFRFRFFLFLFRF", -Math.PI / 2, Math.PI / 2)(-128 + width * .35, height / 4),
    lSystem("FRFRFRFR", "FLFRFRFFLFLFRF", -Math.PI / 2, Math.PI / 2)(128 + width * .35, height / 4)
  ]
}));

function lSystem(initial, replacement, left, right) {
  var segments = initial.match(/F/g).length;
  return function(x, y) {
    var flake = initial,
        iterations = 3,
        d = 64 / Math.pow(segments, iterations - 1),
        line = [];

    for (var i = 0; i < iterations; ++i) flake = flake.replace(/F/g, replacement);
    for (var angle = 0, move, i = 0, n = flake.length; i < n; ++i) {
      move = flake.charAt(i);
      if (move === "F") {
        line.push([
          x += d * Math.cos(angle) | 0,
          y += d * Math.sin(angle) | 0
        ]);
      } else {
        angle += move === "L" ? left : right;
      }
    }
    line.push(line[0]);
    return {type: "Polygon", coordinates: [line]};
  };
}

package.json

{
  "name": "anonymous",
  "version": "0.0.1",
  "private": true,
  "devDependencies": {
    "topojson": "1"
  }
}