| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768 |
- // Seats only measured footprint modules; excludes relief beyond the sample's foundation budget.
- import { readFileSync, writeFileSync } from 'node:fs'
- import { Cartesian3, Cartographic, Matrix4, Math as CM } from 'cesium'
- const dir = 'tools/city-massing/district/',
- p = JSON.parse(readFileSync(dir + 'plan.json'))
- const s = JSON.parse(readFileSync(dir + 'terrain-samples.json'))
- if (JSON.stringify(p.samples) !== JSON.stringify(s.planPoints))
- throw Error('DEM cache belongs to another footprint plan')
- const inv = Matrix4.inverseTransformation(Matrix4.fromArray(p.transform), new Matrix4())
- const buildings = [],
- excluded = [...p.excluded.map((x) => ({ ...x, stage: 'source-outline' }))]
- for (const m of p.modules) {
- const h = m.sampleIndices.map((i) => s.heights[i])
- if (h.some((x) => !Number.isFinite(x))) throw Error('Missing DEM ' + m.id)
- const min = Math.min(...h),
- max = Math.max(...h),
- range = max - min
- // Avoid fabricating a tall platform to compensate for a hillside footprint.
- if (range > 2.5) {
- excluded.push({
- id: m.id,
- reason: 'footprint relief exceeds 2.5m sample limit; needs stepped/custom model',
- range,
- })
- continue
- }
- const floorHeight = max - 0.25,
- foot = Matrix4.multiplyByPoint(
- inv,
- Cartesian3.fromDegrees(m.center.lon, m.center.lat, floorHeight),
- new Cartesian3()
- )
- const foundationBottom = Matrix4.multiplyByPoint(
- inv,
- Cartesian3.fromDegrees(m.center.lon, m.center.lat, min - 3),
- new Cartesian3()
- ).z
- const groundControls = m.sampleIndices.map((i) => {
- let q = p.samples[i]
- let v = Matrix4.multiplyByPoint(inv, Cartesian3.fromDegrees(q.lon, q.lat, s.heights[i]), new Cartesian3())
- return [v.x, v.y, v.z]
- })
- buildings.push({
- ...m,
- positionENU: [foot.x, foot.y, foot.z],
- floorHeight,
- terrainMin: min,
- terrainMax: max,
- terrainRelief: range,
- foundationBottom,
- groundControls,
- })
- }
- const report = {
- ...p,
- modules: undefined,
- samples: undefined,
- buildings,
- excluded,
- notice: 'Prototype neighborhood, individually traced/OSM footprints; facade and floor counts estimated. Steep modules explicitly excluded, not sunk or lifted.',
- }
- writeFileSync(dir + 'seated-plan.json', JSON.stringify(report, null, 2))
- console.log({
- buildings: buildings.length,
- sources: new Set(buildings.map((b) => b.sourceId)).size,
- excluded: excluded.length,
- maxVisibleFoundation: Math.max(...buildings.map((b) => b.floorHeight - b.terrainMin)).toFixed(2),
- })
|