make-cad-bim-pilot.mjs 1.5 KB

12345678910111213141516171819202122232425262728293031
  1. // Deterministic balanced pilot selection for the CAD BIM pipeline.
  2. // Keeps the city-core and southern/river masks represented, with both asset and exact-outline massing.
  3. import { readFileSync, writeFileSync } from 'node:fs'
  4. const source = JSON.parse(readFileSync('tools/city-massing/city/cad-bim/seated-plan.json', 'utf8'))
  5. const targets = new Map([[66, 1800], [65, 700], [130, 300], [126, 200]])
  6. const hash = (id) => {
  7. let value = 2166136261
  8. for (const ch of id) value = ((value ^ ch.charCodeAt(0)) * 16777619) >>> 0
  9. return value
  10. }
  11. const selected = []
  12. const details = {}
  13. for (const [maskId, target] of targets) {
  14. const group = source.buildings.filter((b) => Number(b.maskId) === maskId)
  15. const ordered = [...group].sort((a, b) => hash(a.id) - hash(b.id))
  16. const take = ordered.slice(0, Math.min(target, ordered.length))
  17. selected.push(...take)
  18. details[maskId] = { available: group.length, selected: take.length }
  19. }
  20. const out = {
  21. ...source,
  22. buildings: selected,
  23. pilot: {
  24. name: 'urban-mask-cad-bim-pilot-3000',
  25. selection: details,
  26. note: 'Bounded first CIM pass; full 48k seated buildings remain a later batched export.',
  27. },
  28. }
  29. writeFileSync('tools/city-massing/city/cad-bim/seated-pilot.json', JSON.stringify(out, null, 2))
  30. 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])) }))