Published
Edited
Sep 17, 2019
Importers
40 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
if (animateRotation || animateTranslation) {
let height = ~~(width*9/16);
let a = 0;
let t = 0;
let da = animateRotation? 0.1 : 0;
let dt = animateTranslation ? 0.005 : 0;
while (true) {
a += da; if (a >= 360) a = 0;
t += dt; if (t >= 1) t = 0;
let group = d3.select("svg#mainview g");
let trans = t1.add(t2).scale(t).scale(edgeLength);
group.attr("transform", `rotate(${a},${width/2},${height/2})
translate(${trans.x},${trans.y})
translate(${width/2},${height/2})
scale(${edgeLength})`);
yield comment('_Function to animate the pattern transform_');
}
}
else {
return comment('No rotation or translation animation')
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
galebach = d3.json("https://gist.githubusercontent.com/esperanc/7728941a9fe4c937f0899b5f69c58c8f/raw/f42bd52cff7fb835ca9e08a943fade621942b633/Galebach.json")
Insert cell
saesa = d3.json("https://gist.githubusercontent.com/esperanc/9b3651eb2fbff9bb04de23d594a0a361/raw/a46b20b967726a17d9c4b11edc909a92a57e6e41/SaeSa.json")
Insert cell
databases = ({"Galebach": galebach, "Sá e Sá" : saesa})
Insert cell
Insert cell
w = [Vec(1, 0), // w^0
Vec(0.8660254037844386, 0.5), // w^1
Vec(0.5, 0.8660254037844386), // w^2
Vec(0, 1) // w^3
]
Insert cell
Insert cell
tiling = databases[databaseName][pattern]
Insert cell
Insert cell
toVec = T => w[0].scale(T[0]).add(w[1].scale(T[1])).add(w[2].scale(T[2])).add(w[3].scale(T[3]))
Insert cell
Insert cell
t1 = toVec(tiling.T1)
Insert cell
t2 = toVec(tiling.T2)
Insert cell
Insert cell
seeds = tiling.Seed.map(toVec)
Insert cell
Insert cell
seedsBox = new MBR(...seeds)
Insert cell
Insert cell
tileDisplacements = {
let displacements = [];
for (let i of [0,-1,1,2]) {
for (let j of [0,-1,1,2]) {
displacements.push (t1.scale(i).add(t2.scale(j)));
}
}
return displacements;
}
Insert cell
Insert cell
createSvgAndGroup = function () {
let svgNode = html`<svg width = 400 height=400 style="border:1px solid gray;margin:-2px 2px;"></svg>`;
let svg = d3.select(svgNode);
let center = seedsBox.max.add(seedsBox.min).scale(-0.5);
let group = svg.append("g")
.attr("transform", `translate(200,200) scale(${edgeLength}) translate(${center.x},${center.y})`);
let tile = [Vec(0,0),t1,t1.add(t2),t2].map(p=>`${p.x},${p.y}`).join(" ");
group.selectAll("polygon.tile").data(tileDisplacements).enter()
.append("polygon")
.attr("points",tile)
.style("fill", (d,i) => (i==0 ? "rgb(240,240,240)" : "none"))
.style("stroke","gray")
.style("stroke-width",0.5/edgeLength)
.attr("transform", d => `translate(${d.x},${d.y})`);
return [svgNode,group];
}
Insert cell
Insert cell
seedPlot = function() {
let [svgNode,group] = createSvgAndGroup ();
group.selectAll("line")
.data([t1,t2]).enter()
.append("line")
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", d=>d.x)
.attr("y2", d=>d.y)
.style("stroke", "black")
.style("stroke-width", 1.5/edgeLength)
group.selectAll("circle")
.data(seeds).enter()
.append("circle")
.attr("cx", d=>d.x)
.attr("cy", d=>d.y)
.attr("r", 0.2)
.attr("fill", "gray")
return svgNode;
}
Insert cell
Insert cell
Insert cell
vtx = {
let vtx = []
for (let d of tileDisplacements) {
for (let seed of seeds) {
vtx.push(seed.add(d))
}
}
return vtx;
}
Insert cell
Insert cell
edges = {
let n = seeds.length;
let m = vtx.length;
let edges = [];
for (let i = 0; i < n; i++) {
let p = seeds[i];
for (let j = i+1; j < m; j++) {
let q = vtx[j];
let d = p.dist(q);
if (d > 0.99 && d < 1.01) {
edges.push([p,q])
}
}
}
return edges;
}
Insert cell
Insert cell
edgePlot = function () {
let [svgNode,group] = createSvgAndGroup ();
let n = seeds.length;
group.selectAll("line")
.data(edges).enter()
.append("line")
.attr("x1", d=>d[0].x)
.attr("y1", d=>d[0].y)
.attr("x2", d=>d[1].x)
.attr("y2", d=>d[1].y)
.style("stroke", "black")
.style("stroke-width", 1.5/edgeLength)
group.selectAll("circle").data(vtx).enter().append("circle")
.attr("r", (d,i) => i < n ? 4/edgeLength : 2/edgeLength)
.attr("cx", d=>d.x)
.attr("cy", d=>d.y)
.style("fill","gray")
.append("title").text(d=>`(${d.x},${d.y})`)
return svgNode;
}
Insert cell
Insert cell
Insert cell
mutable iedges = []
Insert cell
Insert cell
centers = {
let n = seeds.length;
let incidentEdges = [];
let bisector = function (a,b) {
let midpoint = a.add(b).scale(0.5);
let dir = b.sub(a);
return new Ray(midpoint,Vec(-dir.y,dir.x))
}
for (let i = 0; i < n; i++) {
incidentEdges[i] = [];
let s = seeds[i];
for (let [p,q] of edges) {
if (q.dist(s) < 0.001) [p,q] = [q,p];
if (p.dist(s) < 0.001 && (q.x > p.x || (Math.abs(q.x - p.x)<0.001 && q.y < p.y))) incidentEdges[i].push(q);
}
incidentEdges[i].sort((a,b) => a.y-b.y);
}
mutable iedges = incidentEdges;
let centers = [];
for (let i = 0; i < n; i++) {
let k = incidentEdges[i].length;
if (k < 2) continue;
let s = seeds[i];
for (let j = 1; j < k; j++) {
let ray1 = bisector(s,incidentEdges[i][j-1]);
let ray2 = bisector(s,incidentEdges[i][j]);
let [t,u] = ray1.intersectRay (ray2);
let center = ray1.point(t);
centers.push ({o : center, d:center.dist(s), s:s});
}
}
return centers;
}
Insert cell
Insert cell
centersPlot = function () {
let [svgNode,group] = createSvgAndGroup ();
group.selectAll("g.center")
.data(centers).enter()
.append("g")
.attr("class", "center")
.each(function(d,i) {
let group = d3.select(this);
group.append("circle")
.attr("cx", d=>d.o.x)
.attr("cy", d=>d.o.y)
.attr("r", 3/edgeLength)
.attr("fill", "gray")
group.append("circle")
.attr("cx", d=>d.o.x)
.attr("cy", d=>d.o.y)
.attr("r", d=>d.d)
.style("fill","none")
.style("stroke","gray")
.style("stroke-width", 1/edgeLength)
.style("stroke-dasharray", "0.1,0.1")
});
return svgNode;
}
Insert cell
Insert cell
faces = {
let faces = [];
for (let {o,d} of centers) {
let face = [];
for (let v of vtx) {
let vdist = v.dist(o);
if (vdist > d*0.99 && vdist < d*1.01) {
let dir = v.sub(o);
face.push({v:v, angle:Math.atan2(dir.y,dir.x)});
}
}
face.sort((a,b)=>a.angle-b.angle);
faces.push(face.map(d=>d.v))
}
return faces
}

Insert cell
Insert cell
patchMBR = {
let mbr = new MBR();
for (let f of faces) for (let v of f) mbr.add(v)
return mbr;
}
Insert cell
Insert cell
facesPlot = function () {
let [svgNode,group] = createSvgAndGroup ();
group.selectAll("g.patch")
.data([Vec(0,0)]/*tileDisplacements*/).enter()
.append("g")
.attr("class","patch")
.attr("transform",d=>`translate(${d.x},${d.y})`)
.style("opacity",0.8)
.selectAll("polygon")
.data(faces).enter()
.append("polygon")
.attr("points", d => d.map(p=>`${p.x},${p.y}`).join(" "))
.style("fill","lightgray")
.style("stroke","gray")
.style("stroke-width", 1/edgeLength);
return svgNode;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof edgeLength = new View(30)
Insert cell
viewof edgeThickness = new View(2)
Insert cell
viewof databaseName = new View("Sá e Sá")
Insert cell
viewof pattern = new View("HNR")
Insert cell
viewof edgeColor = new View ("#222222")
Insert cell
viewof colorPalette = new View("Pastel2")
Insert cell
viewof colorShift = new View(1)
Insert cell
viewof animateTranslation = new View(true)
Insert cell
viewof animateRotation = new View(true)
Insert cell
Insert cell
Insert cell
d3 = require("d3@5")
Insert cell
import { bindRadioGroup, bindSliderNumber, bindSelect, bindColor, bindCheckbox, View } from "@esperanc/inline-inputs"
Insert cell
import { Vec, Vector, MBR, Ray } from "@esperanc/2d-geometry-utils"
Insert cell
import {comment,util_style} from "@esperanc/notebook-css-utilities"
Insert cell
util_style
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more