| 123456789 |
- import {readFileSync,writeFileSync} from 'node:fs'
- import {createHash} from 'node:crypto'
- const root='tools/city-massing/city/cad-bim',ids=['cad-25612','cad-25467','cad-25968','cad-25957'],plan=JSON.parse(readFileSync(root+'/plan.json')),seat=JSON.parse(readFileSync(root+'/seated-plan.json')),by=new Map(plan.buildings.map(b=>[b.id,b])),sb=new Map(seat.buildings.map(b=>[b.id,b])),results=[]
- function stats(json,bin){let tri=0,verts=0,prims=0,textures=0,images=0;for(const a of json.accessors||[])if(a.type==='VEC3')verts+=a.count;for(const m of json.meshes||[])for(const p of m.primitives||[]){prims++;if(p.indices!==undefined)tri+=(json.accessors[p.indices]?.count||0)/3}textures=json.textures?.length||0;images=json.images?.length||0;return{triangles:tri,vertices:verts,primitives:prims,materials:json.materials?.length||0,textures,images,nodes:json.nodes?.length||0,bytes:bin.length}}
- function firstLine(set,id){const m=JSON.parse(readFileSync(root+`/${set}/manifest.json`));for(const c of m.cells||[])if((c.buildingIds||[]).includes(id))return c}
- for(const id of ids){const b=by.get(id),s=sb.get(id),c=firstLine('lod-batch-rural1',id)||firstLine('lod-batch-rural3',id);results.push({id,kind:b.kind,archetype:b.archetype,floors:b.floors,heightM:s.heightM,terrainRelief:s.terrainRelief,cell:c?.id||null,cellBuildingCount:c?.buildingIds?.length||null,cellNote:'cell GLB is a group; per-building geometry attribution requires Blender/GLB metadata decode',sourceGraphHash:createHash('sha256').update(JSON.stringify(c?.buildingIds||[])).digest('hex')})}
- const pos=['cad-16575','cad-16576','cad-16503'];for(const id of pos){const c=firstLine('lod-batch-urban8000b',id)||firstLine('lod-batch-urban-tail',id)||firstLine('lod-batch-urban-final',id);results.push({id,kind:by.get(id)?.kind,archetype:by.get(id)?.archetype,floors:by.get(id)?.floors,cell:c?.id||null,cellBuildingCount:c?.buildingIds?.length||null})}
- const report={generatedAt:'2026-10-14',positiveSampleIds:pos,negativeCandidates:ids,results,modelChanged:false,qualityConclusion:'Source cell manifests establish lineage only; they do not attribute triangles to one building. Positive sample includes asset and massing kinds; negative candidates include one slab asset and three massing plans. A quality-unification change needs isolated GLB export or decoder attribution, neither run under no-build rule.'}
- writeFileSync('.scratch/cockpit-shell-panel-layout/verify/artifacts/t35/user-samples/glb-quality-lineage.json',JSON.stringify(report,null,2));console.log(JSON.stringify({passed:true,rows:results.length,modelChanged:false,attribution:'cell-level-only'}))
|