Public
Edited
Apr 18, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
simplify = (geo, val) => {
let simplified = topojson.presimplify(geo);
let min_weight = topojson.quantile(simplified, val);
return topojson.simplify(simplified, min_weight);
}
Insert cell
topoJSON = {
let t = data
if (data.type === "Topology") { return t; }
else {
// Here we convert the file to geoJSON
let topoJSON = topojson.topology({ name: t });
return simplify(topoJSON, object.weight)
}
}
Insert cell
function initSVGObject(geojson, groupOn, bll, h, w){
//Define map and path projection then update the bounding box
var projection = d3.geoMercator().translate([0, 0]).scale(1);
const path = d3.geoPath().projection(projection);
var b = path.bounds( geojson );
var s = .95 / Math.max((b[1][0] - b[0][0]) / w, (b[1][1] - b[0][1]) / h);
var t = [(w - s * (b[1][0] + b[0][0])) / 2, (h - s * (b[1][1] + b[0][1])) / 2];
projection.scale(s).translate(t)
//Create SVG element points
var svg = d3.select(DOM.svg()).attr("width", w).attr("height", h).attr("id", 'line')
.attr("fill", 'black').attr("stroke", 'gray') // fill="none"
//Bind data and create one path per GeoJSON feature
svg.selectAll("path").data(geojson.features).enter().append("path").attr("d", path)
.attr('groupOn', function(e){ return JSON.stringify(e.properties[groupOn]) } )
return svg.node()
}
Insert cell
data2 = topojson.feature(topoJSON, topoJSON.objects[object.feature])
Insert cell
geomBounds = initSVGObject(data2, object.label, object.convex, 600, width)
Insert cell
Insert cell
hull = {
// Start by adding a baselayer by using Turf.JS to create a convex hull of our geometry
var hull = turf.convex( data );
hull.properties[object.label] = object.convex
return initSVGObject(turf.featureCollection( [hull] ), object.label, object.convex, 600, width)
}
Insert cell
hull.outerHTML
Insert cell
Insert cell
// svgPointsLines = initSVGObject(connectingLines, object.label, object.convex, 600, width)
Insert cell
Insert cell
Insert cell
merged = topojson.mesh( topoJSON ) // Merge into a single path (faster to draw // no overlapping borders)
Insert cell
normalized_geom = {
// minX, minY, maxX, maxY
let bounds = turf.bbox(merged)
let midX = bounds[2] - bounds[0]
let midY = bounds[3] - bounds[1]
let mid = [midX, midY]
return merged.coordinates.map( lines => {
return lines.map( line => {
return [ parseFloat((( (line[0] - bounds[0] ) / mid[0]).toFixed(4) * 100).toFixed(4)), -parseFloat((( (line[1] - bounds[1] )/ mid[1] ) * 100).toFixed(4)) ]
})
})
}
Insert cell
mergedGeojson = { return {
type: "FeatureCollection",
features: [{
type: "MultiPolygon",
properties: {CSA2010: "All Geometries"},
geometry: {type: "MultiPolygon", coordinates: normalized_geom}
}]
} }
Insert cell
Insert cell
Insert cell
// geomBoundsLines = create3dFromSvgV8(geomBounds, 'lines', object.weight*10)
Insert cell
geomBounds3D = create3dFromSvgV8(geomBounds, 'extrude', object.weight*10-.015)
Insert cell
hull3D = create3dFromSvgV8(hull, 'geoms', object.weight*10)
Insert cell
Insert cell
meshRes = {
const material = new THREE.MeshNormalMaterial();
new THREE.MeshBasicMaterial( { side: THREE.DoubleSide } ); material.color = new THREE.Color().setStyle( 'orange' )
// const material = new THREE.MeshLambertMaterial( { color: 0xb00000, wireframe: false } );
let meshA = hull3D.children[0]
let meshB = geomBounds3D.children[0]
let bspA = ''
let bspResult = ''
let i = 0;

meshA.updateMatrix()
meshB.updateMatrix()
// console.log( i++)
bspA = CSG.fromMesh( meshA )
let bspB = CSG.fromMesh( meshB )
bspResult = bspA.subtract(bspB)
var mesh = CSG.toMesh( bspResult, meshA.matrix, meshA.material )
mesh.geometry.computeVertexNormals()

var bufferGeometry = new THREE.BufferGeometry().fromGeometry( mesh.geometry );
mesh = new THREE.Mesh( bufferGeometry, material )
mesh.material = material
mesh.scale.setScalar( 1 / 3 );
mesh.rotateY(Math.PI)
mesh.rotateZ(Math.PI)
var center = { x: width/2, y: 600/2 };
mesh.translateY( - center.y /2 + 100);
mesh.translateX( - center.x /2 + 100 );
return mesh
}
Insert cell
scene = {
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x333333);
scene.add(new THREE.AxesHelper(100));
// scene.add(geomBounds3D);
// scene.add(hull3D);
// scene.add(geomBoundsLines);
scene.add(meshRes);
return scene;
}
Insert cell
{
// Equirectangular Background
const renderer = new THREE.WebGLRenderer({ antialias: true });
const controls = new THREE.OrbitControls(camera, renderer.domElement);
invalidation.then(() => (controls.dispose(), renderer.dispose()));
renderer.setSize(width, 600);
renderer.setPixelRatio(devicePixelRatio);
controls.addEventListener("change", () => renderer.render(scene, camera));
renderer.render(scene, camera);
return renderer.domElement;
}
Insert cell
Insert cell
{
let exporter = new STLExporter.STLExporter();
let exportScene = (meshThis, name) => {
// console.log('exportScene', meshThis)
let buffer = exporter.parse( meshThis )
let filename = name+'.stl'
let blobby = new Blob( [ buffer ], { type: "text/stl" } )
return DOM.download(blobby, filename, "Download "+name)
}
// ${exportScene(geomBounds3D, 'geomBoundsLines')}
return html`
${exportScene(meshRes, 'meshRes')}
${ exportScene(hull3D, 'hull3D')}
${exportScene(geomBounds3D, 'geomBounds3D')} }
`}
Insert cell
//https://sbcode.net/threejs/geometry-to-buffergeometry/
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