| 12345678910111213141516171819202122232425262728293031323334353637383940414243 |
- // Rejected prototype: historical coarse budgets and URI-only mapping are unsafe.
- // Kept as diagnostic history only; use build-far-shell-city.mjs for actual output.
- throw new Error('Rejected prototype; use build-far-shell-city.mjs')
- import assert from 'node:assert/strict'
- import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'
- import { resolve, join, relative } from 'node:path'
- const root=resolve('tools/city-massing/city/cad-bim'),source=join(root,'city-continuous-v8'),farDir=join(root,'far-roofed2'),out=join(root,process.argv[2]||'city-continuous-v9')
- assert.ok(!existsSync(out),'immutable generation')
- const farTree=JSON.parse(readFileSync(join(farDir,'tileset.json'))),sourceTree=JSON.parse(readFileSync(join(source,'tileset.json')))
- let transform=farTree.root.transform;assert.deepEqual(transform,sourceTree.root.transform)
- const byCell=new Map()
- function indexV8(t){
- const uri=t.content?.uri
- if(uri&&/-lod1\.glb$/.test(uri))byCell.set(uri.split('/').at(-1),t)
- for(const c of t.children||[])indexV8(c)
- }
- indexV8(sourceTree.root)
- const children=[],used=new Set(),records=[]
- function adaptLocal(tile){
- const t=structuredClone(tile)
- if(t.content)t.content.uri=relative(out,resolve(source,t.content.uri)).replaceAll('\\','/')
- if(t.children?.length){t.boundingVolume=t.boundingVolume.box?{sphere:[...t.boundingVolume.box.slice(0,3),Math.hypot(t.boundingVolume.box[3],t.boundingVolume.box[7],t.boundingVolume.box[11])]}:t.boundingVolume;t.geometricError=1000000;t.refine='REPLACE';delete t.viewerRequestVolume;t.children=t.children.map(adaptLocal)}
- return t
- }
- for(const farChild of farTree.root.children){
- const uri=farChild.content.uri, match=uri.match(/\.\.\/([^/]+)\/(.*)$/);assert.ok(match)
- const batchDir=join(root,match[1]),batchTree=JSON.parse(readFileSync(join(batchDir,'tileset.json'))),base=match[2].split('/').at(-1)
- const coarse=batchTree.root.children.find(t=>t.content?.uri?.split('/').at(-1)===base);assert.ok(coarse,base)
- const local=[]
- for(const child of coarse.children||[]){const cellUri=child.content?.uri?.split('/').at(-1);const branch=cellUri&&byCell.get(cellUri);if(!branch)continue;assert.ok(!used.has(cellUri),cellUri);used.add(cellUri);const cloned=adaptLocal(branch);cloned.geometricError=48;cloned.refine='REPLACE';delete cloned.viewerRequestVolume;local.push(cloned)}
- const center=farChild.boundingVolume.box.slice(0,3),radius=Math.hypot(farChild.boundingVolume.box[3],farChild.boundingVolume.box[7],farChild.boundingVolume.box[11])
- const parent={id:farChild.id,boundingVolume:{sphere:[...center,radius]},geometricError:128,refine:'REPLACE',viewerRequestVolume:{sphere:[...center,radius+14000]},content:{uri:relative(out,resolve(farDir,farChild.content.uri)).replaceAll('\\','/')},children:local}
- children.push(parent);records.push({id:farChild.id,localCells:local.length,farTriangles:farChild.geometricError})
- }
- // Near-estate has no historical far parent; append its already verified v8 branch.
- for(const t of sourceTree.root.children){const uri=t.content?.uri||'';if(uri.includes('lod-near-estate-pilot-v6'))children.push(adaptLocal(t))}
- assert.equal(used.size,3020,'legacy far ownership should cover the original city cells')
- assert.equal(children.filter(t=>t.content?.uri?.includes('far-roofed2')).length,74)
- mkdirSync(out,{recursive:true});writeFileSync(join(out,'root-anchor.glb'),readFileSync(join(farDir,'root-anchor.glb')))
- const box=farTree.root.boundingVolume
- writeFileSync(join(out,'tileset.json'),JSON.stringify({asset:{version:'1.1',generator:'74 coarse far parents with exact source-cell local branches'},geometricError:1000000,root:{transform,boundingVolume:box,geometricError:1000000,refine:'REPLACE',content:{uri:'root-anchor.glb'},children}},null,2)+'\n')
- writeFileSync(join(out,'manifest.json'),JSON.stringify({buildings:30172,farParents:74,legacyCells:used.size,nearEstate:true,records,geometryChanged:false,coarseBudgetException:'Legacy far coarse GLBs are retained only as distant parents; their historical triangles exceed the current local content budget. Local branches remain current bounded tiles.',policy:'Exact coarse-child URI to source-cell ownership; local branch GE48 under far parent GE128; fine v8 leaves preserve local ownership and parent fallback.',runtimeValidated:false},null,2)+'\n')
- console.log(JSON.stringify({out,farParents:74,legacyCells:used.size,nearEstate:true}))
|