| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 |
- // Select a seated CAD BIM subset for a batched export.
- // The full 48k plan cannot be exported in one Blender pass, so batches are cut by tier and mask;
- // every batch keeps the same schema so the exporter and verifier need no changes.
- import { readFileSync, writeFileSync } from 'node:fs'
- // Accept both `--key=value` and `--key value`; a bare `--key` means true.
- const argv = process.argv.slice(2)
- const args = {}
- for (let i = 0; i < argv.length; i++) {
- if (!argv[i].startsWith('--')) continue
- const key = argv[i].slice(2)
- const eq = key.indexOf('=')
- if (eq >= 0) {
- args[key.slice(0, eq)] = key.slice(eq + 1)
- } else if (i + 1 < argv.length && !argv[i + 1].startsWith('--')) {
- args[key] = argv[++i]
- } else {
- args[key] = true
- }
- }
- const source = JSON.parse(readFileSync('tools/city-massing/city/cad-bim/seated-plan.json', 'utf8'))
- let buildings = source.buildings
- // `--exclude <manifest.json>` removes buildings already exported in an earlier batch, so
- // successive batches tile the seated plan without duplication.
- let excludedIds = new Set()
- if (args.exclude) {
- for (const path of String(args.exclude).split(',')) {
- const manifest = JSON.parse(readFileSync(path, 'utf8'))
- for (const cell of manifest.cells) for (const id of cell.buildingIds) excludedIds.add(id)
- }
- buildings = buildings.filter((b) => !excludedIds.has(b.id))
- }
- if (args.tier) buildings = buildings.filter((b) => b.tier === args.tier)
- if (args.mask) buildings = buildings.filter((b) => Number(b.maskId) === Number(args.mask))
- if (args.max) {
- // Deterministic pick so a re-run selects the same buildings.
- const hash = (id) => {
- let value = 2166136261
- for (const ch of id) value = ((value ^ ch.charCodeAt(0)) * 16777619) >>> 0
- return value
- }
- buildings = [...buildings].sort((a, b) => hash(a.id) - hash(b.id)).slice(0, Number(args.max))
- }
- if (!buildings.length) throw new Error('selection is empty; check --tier/--mask/--max/--exclude')
- const out = {
- ...source,
- buildings,
- batch: {
- tier: args.tier || 'all',
- mask: args.mask || 'all',
- selected: buildings.length,
- excludedByEarlierBatches: excludedIds.size,
- note: 'One batch of the seated CAD BIM plan for a bounded Blender export.',
- },
- }
- const outFile = args.out || 'tools/city-massing/city/cad-bim/seated-batch.json'
- writeFileSync(outFile, JSON.stringify(out, null, 2))
- console.log(JSON.stringify({
- out: outFile,
- selected: buildings.length,
- byKind: Object.fromEntries([...new Set(buildings.map((b) => b.kind))].map((k) => [k, buildings.filter((b) => b.kind === k).length])),
- byMask: Object.fromEntries([...new Set(buildings.map((b) => String(b.maskId)))].map((k) => [k, buildings.filter((b) => String(b.maskId) === k).length])),
- }))
|