Public
Edited
Sep 30, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// Fetch dem data as 256 x 256 array
// Mt. Nabewari, Japan
dem = fetchTile({z: 13, x: 7262, y: 3232})
Insert cell
md`
## 2. Contouring
Same as [2D version](https://observablehq.com/@sw1227/dem-to-contour-by-d3).
`
Insert cell
// Shape of dem data
shape = ({x: dem[0].length, y: dem.length})
Insert cell
// Flatten 2D array
flatDem = [].concat.apply([], dem)
Insert cell
// min/max elevation
elevRange = d3.extent(flatDem)
Insert cell
// Thresholds for contour
thresh = d3.range(Math.round(elevRange[0]/interval)*interval, elevRange[1], interval)
Insert cell
// Dem data -> Contours
contours = d3.contours()
.size([shape.x, shape.y])
.thresholds(thresh)
(flatDem)
Insert cell
Insert cell
Insert cell
Insert cell
// TODO: 0.2: handcrafted
heightScale = d => 0.2 * (d-elevRange[0])/(elevRange[1]-elevRange[0]);
Insert cell
// Scale xy cooridinates to [0, 1]
xyContour = scaleContour(contours, 1/256)
Insert cell
// 3D lineString meshes of contours
contourLineStrings = {
const lines = [];
xyContour.forEach(polygon => {
// Set color based on elevation
const lineColor = color(polygon.value);
// 2D to 3D: be carefull about right-handed / lef-handed system
polygon.coordinates.forEach(rings => {
rings.forEach(points => {
const points3 = points.map(([x, y]) => [y-0.5, x-0.5, heightScale(polygon.value)]);
lines.push(lineString(points3, lineColor));
});
});
});
return lines;
}
Insert cell
// Create lineString mesh with given coordinates and color
function lineString(points, color) {
const material = new THREE.LineBasicMaterial({color: color, blending: THREE.AdditiveBlending});
const geometry = new THREE.Geometry();
points.forEach(p => {
geometry.vertices.push(new THREE.Vector3(...p));
});

return new THREE.Line(geometry, material);
}
Insert cell
scene = {
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x333333);
contourLineStrings.forEach(l => scene.add(l));
return scene;
}
Insert cell
camera = {
const fov = 45;
const aspect = width / height;
const near = 0.01;
const far = 1000;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0.5, 0.5, 0.5);
camera.up.set(0, 0, 1);
camera.lookAt(new THREE.Vector3(0, 0, 0));
return camera;
}
Insert cell
height = 500
Insert cell
Insert cell
Insert cell
Insert cell
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