| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950 |
- import assert from 'node:assert/strict'
- import { readFileSync, writeFileSync, existsSync } from 'node:fs'
- import { resolve, join } from 'node:path'
- import { parseGlb } from './instance-repeated-meshes.mjs'
- import { normalizeConfig } from '../../src/modules/cockpit/services/cockpitConfig.js'
- import { planTilesets } from '../../src/modules/cockpit/domain/mapLayers.js'
- import { tilesetOptions } from '../../src/modules/cockpit/services/tilesetOptions.js'
- const dir = resolve(process.argv[2]),tree=JSON.parse(readFileSync(join(dir,'tileset.json'))),report=JSON.parse(readFileSync(join(dir,'manifest.json')))
- assert.equal(tree.root.content,undefined,'empty root must not wait for entire city')
- assert.equal(tree.root.viewerRequestVolume,undefined)
- const sourceDir=resolve(dir,'../'+report.source),source=JSON.parse(readFileSync(join(sourceDir,'manifest.json')))
- const expected=new Map(source.records.map(r=>[resolve(sourceDir,r.uri),r])),seen=new Set(),ids=new Set()
- let maxTriangles=0,maxVertices=0,coarseBytes=0,far=0,near=0,fine=0
- for(const c of report.decisions)for(const id of c.buildingIds){assert.ok(!ids.has(id));ids.add(id)}
- function visit(t){
- if(t.content){const path=resolve(dir,t.content.uri),r=expected.get(path);assert.ok(r&&existsSync(path));assert.ok(!seen.has(path));seen.add(path)
- const bytes=readFileSync(path),{json}=parseGlb(bytes)
- let triangles=0,vertices=0
- for(const n of json.nodes)if(n.mesh!==undefined)for(const p of json.meshes[n.mesh].primitives){triangles+=json.accessors[p.indices].count/3;vertices+=json.accessors[p.attributes.POSITION].count}
- assert.ok(triangles<=20000&&vertices<=60000,path+' budget');maxTriangles=Math.max(maxTriangles,triangles);maxVertices=Math.max(maxVertices,vertices)
- if(r.level==='far'){far++;coarseBytes+=bytes.length;assert.equal(t.geometricError,report.errors.far);assert.deepEqual(t.viewerRequestVolume.sphere,[...t.boundingVolume.sphere.slice(0,3),t.boundingVolume.sphere[3]+report.coarseRequestMargin])}
- else{assert.equal(t.viewerRequestVolume,undefined);if(r.level==='near'){near++;assert.equal(t.geometricError,report.errors.near)}else{fine++;assert.equal(t.geometricError,0)}}
- }else assert.equal(t.viewerRequestVolume,undefined)
- if(t.children?.length){
- assert.equal(t.refine,'REPLACE');assert.ok(t===tree.root||t.boundingVolume.sphere)
- if(t.content){
- assert.ok(t.geometricError>0&&t.geometricError<1000000,'finite content error required')
- assert.ok(t.children.every(c=>c.content),'content parent must wait on renderable children, not empty wrappers')
- }
- }
- for(const c of t.children||[])visit(c)
- }
- visit(tree.root)
- assert.equal(ids.size,30172);assert.equal(seen.size,expected.size);assert.equal(far,report.far);assert.equal(near,report.near);assert.equal(fine,report.fine)
- const config=normalizeConfig({map:{tilesets:[{url:'/gis/example',progressiveRefinement:true,maximumScreenSpaceError:96}]}})
- assert.deepEqual(config.issues,[])
- const planned=planTilesets(config.config.map)[0],options=tilesetOptions(planned)
- assert.equal(planned.progressiveRefinement,true);assert.equal(options.skipLevelOfDetail,false);assert.equal(options.maximumScreenSpaceError,96)
- assert.equal(options.preloadWhenHidden,false);assert.equal(options.preloadFlightDestinations,false)
- assert.equal(options.cacheBytes,64*1024*1024);assert.equal(options.maximumCacheOverflowBytes,32*1024*1024)
- assert.equal(tilesetOptions(planTilesets(normalizeConfig({map:{tilesets:[{url:'old'}]}}).config.map)[0]).skipLevelOfDetail,true,'old deployments unchanged')
- const bad=normalizeConfig({map:{tilesets:[{url:'x',progressiveRefinement:'yes'}]}})
- assert.ok(bad.issues.some(s=>s.includes('progressiveRefinement')));assert.equal(planTilesets(bad.config.map)[0].progressiveRefinement,false)
- // Nominal SSE examples (actual viewport/FOV/cache may change the distance).
- const height=1080,denominator=2*Math.tan(Math.PI/6),sse=options.maximumScreenSpaceError
- const result={passed:true,buildings:ids.size,content:seen.size,far,near,fine,maxTriangles,maxVertices,farBytes:coarseBytes,
- geometryChanged:false,allContentUrisMatchSource:true,finiteErrorPolicy:report.errors,
- nominal1080p60degFineDistanceM:report.errors.near*height/(denominator*sse),coarseRequestMargin:report.coarseRequestMargin,
- configPipelineValidated:true,renderingValidated:false,fpsValidated:false}
- if(process.argv[3])writeFileSync(process.argv[3],JSON.stringify(result,null,2));console.log(JSON.stringify(result))
|