| 12345678910111213141516171819202122232425262728293031 |
- // Deterministic balanced pilot selection for the CAD BIM pipeline.
- // Keeps the city-core and southern/river masks represented, with both asset and exact-outline massing.
- import { readFileSync, writeFileSync } from 'node:fs'
- const source = JSON.parse(readFileSync('tools/city-massing/city/cad-bim/seated-plan.json', 'utf8'))
- const targets = new Map([[66, 1800], [65, 700], [130, 300], [126, 200]])
- const hash = (id) => {
- let value = 2166136261
- for (const ch of id) value = ((value ^ ch.charCodeAt(0)) * 16777619) >>> 0
- return value
- }
- const selected = []
- const details = {}
- for (const [maskId, target] of targets) {
- const group = source.buildings.filter((b) => Number(b.maskId) === maskId)
- const ordered = [...group].sort((a, b) => hash(a.id) - hash(b.id))
- const take = ordered.slice(0, Math.min(target, ordered.length))
- selected.push(...take)
- details[maskId] = { available: group.length, selected: take.length }
- }
- const out = {
- ...source,
- buildings: selected,
- pilot: {
- name: 'urban-mask-cad-bim-pilot-3000',
- selection: details,
- note: 'Bounded first CIM pass; full 48k seated buildings remain a later batched export.',
- },
- }
- writeFileSync('tools/city-massing/city/cad-bim/seated-pilot.json', JSON.stringify(out, null, 2))
- console.log(JSON.stringify({ selected: selected.length, byMask: details, byKind: Object.fromEntries([...new Set(selected.map((b) => b.kind))].map((k) => [k, selected.filter((b) => b.kind === k).length])) }))
|