| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849 |
- import assert from 'node:assert/strict'
- import {readFileSync,writeFileSync} from 'node:fs'
- import {resolve,join} from 'node:path'
- import {parseGlb} from './instance-repeated-meshes.mjs'
- import {unpackInstanceBuffers} from './instance-buffer-codec.mjs'
- import {selectDetailRegions} from '../../src/modules/cockpit/services/regionLoading.js'
- import {decodePrimitive} from './instance-safe-primitives.mjs'
- import {createHash} from 'node:crypto'
- const out=resolve(process.argv[2]),m=JSON.parse(readFileSync(join(out,'manifest.json'))),base=resolve(out,'../'+m.source),tree=JSON.parse(readFileSync(join(base,'tileset.json'))),source=JSON.parse(readFileSync(join(base,'manifest.json')))
- assert.equal(m.regions.length,tree.root.children.length);assert.equal(m.regions.length,113)
- const seenFine=new Set(),seenCoarse=new Set()
- let coarseBytes=0,maxRegionBytes=0
- const signature=(json,bin,p)=>{const g=decodePrimitive(json,bin,p);return createHash('sha256').update(JSON.stringify({positions:g.positions,normals:g.normals,indices:g.indices,material:json.materials[p.material]})).digest('hex')}
- for(const r of m.regions){
- const path=join(out,r.url),rt=JSON.parse(readFileSync(path)),expected=[]
- function fine(t){if(t.content?.uri.endsWith('-lod0.glb'))expected.push(resolve(base,t.content.uri));for(const c of t.children||[])fine(c)}
- fine(tree.root.children[r.id]);assert.deepEqual(rt.root.transform,tree.root.transform);assert.deepEqual(rt.root.boundingVolume,r.bounds)
- assert.equal(r.contentCount,rt.root.children.length);assert.ok(r.contentCount<=128)
- const actual=rt.root.children.map(t=>resolve(path,'../'+t.content.uri))
- assert.deepEqual(actual.sort(),expected.sort());for(const p of actual){assert.ok(!seenFine.has(p));seenFine.add(p)}
- maxRegionBytes=Math.max(maxRegionBytes,r.decodedGeometryBytes)
- }
- for(const r of m.coarseRecords){const target=unpackInstanceBuffers(readFileSync(join(out,r.uri))),old=parseGlb(readFileSync(resolve(base,r.sourceUri)));assert.ok(!seenCoarse.has(r.uri));seenCoarse.add(r.uri);coarseBytes+=readFileSync(join(out,r.uri)).length
- assert.deepEqual(target.json.nodes,old.json.nodes,'coarse transforms changed')
- const ext=target.json.extensions.EXT_structural_metadata,table=ext.propertyTables[0],regionView=target.json.bufferViews[table.properties.region.values]
- assert.equal(target.bin.readUInt16LE(regionView.byteOffset),r.region)
- assert.equal(table.count,1);assert.equal(table.class,'BuildingRegion')
- assert.equal(target.json.meshes[0].primitives.length,old.json.meshes[0].primitives.length)
- for(let i=0;i<target.json.meshes[0].primitives.length;i++){const p=target.json.meshes[0].primitives[i],prev=old.json.meshes[0].primitives[i]
- assert.equal(signature(target.json,target.bin,p),signature(old.json,old.bin,prev),'geometry/material changed')
- const f=p.extensions.EXT_mesh_features.featureIds[0],a=target.json.accessors[p.attributes._FEATURE_ID_0],view=target.json.bufferViews[a.bufferView]
- assert.equal(f.attribute,0);assert.equal(f.featureCount,1);assert.equal(f.propertyTable,0);assert.equal(a.count,target.json.accessors[p.attributes.POSITION].count);assert.equal(a.type,'SCALAR')
- assert.equal(a.componentType,5125);assert.ok(target.bin.subarray(view.byteOffset,view.byteOffset+view.byteLength).every(b=>b===0),'feature ID not constant zero')
- }
- }
- assert.equal(seenFine.size,3023);assert.equal(seenCoarse.size,113)
- const samples=[]
- for(const pose of [[0,-1000,350],[0,-1000,50],[2000,1000,180],[0,-1000,10000]]){
- const regions=m.regions.map(r=>{const s=r.bounds.sphere;return{...r,retryAt:0,active:false,distance:Math.max(0,Math.hypot(...s.slice(0,3).map((v,a)=>v-pose[a]))-s[3])}})
- const ids=selectDetailRegions(regions),chosen=regions.filter(r=>ids.includes(r.id)),contents=chosen.reduce((s,r)=>s+r.contentCount,0),memory=chosen.reduce((s,r)=>s+r.decodedGeometryBytes,0)
- assert.ok(ids.length<=2&&contents<=180&&memory<=96*1024*1024)
- assert.deepEqual(selectDetailRegions(regions,{pipeline:true}),[])
- samples.push({cameraENU:pose,regions:ids,detailContentCap:contents,decodedGeometryEstimate:memory,pipelineRegions:0})
- }
- const coarseTree=JSON.parse(readFileSync(join(out,'coarse-tileset.json')))
- assert.ok(coarseTree.root.children.every(t=>t.geometricError===0&&!t.children),'coarse-only dataset must have no detail descendants')
- const result={passed:true,regions:m.regions.length,fineFiles:seenFine.size,coarseFiles:seenCoarse.size,maxRegionContents:m.maxRegionContents,maxRegionDecodedGeometryEstimate:maxRegionBytes,coarseBytes,
- indexedCoarseGeometryUnchanged:true,everyCoarseVertexFeatureZero:true,allFineUrisUnchanged:true,pipelineDetailAdmission:0,samples,renderingValidated:false,fpsValidated:false}
- if(process.argv[3])writeFileSync(process.argv[3],JSON.stringify(result,null,2));console.log(JSON.stringify(result))
|