// Per-building north-up ENU roof imagery for Blender UVs, local-only provenance. import assert from 'node:assert/strict' import {readFileSync,writeFileSync} from 'node:fs' import {resolve,join} from 'node:path' import {createHash} from 'node:crypto' import jpeg from 'jpeg-js' import {PNG} from 'pngjs' import {enuToGeodetic} from './roof-geodesy.mjs' import {roofRasterSize,sharpenRoofRgba} from './roof-raster-quality.mjs' const dir=resolve('.scratch/cockpit-shell-panel-layout/verify/artifacts/t35/negative-estate-pilot/input-v2'),plan=JSON.parse(readFileSync(join(dir,'seated-plan.json'))) const tiles=new Map(),zoom=19,n=2**zoom,textures={},sha=b=>createHash('sha256').update(b).digest('hex') function tile(x,y){const path=`D:/GIS/GIS/yuanlingPic3/${zoom}/${x}/${n-1-y}.png`;if(!tiles.has(path)){const bytes=readFileSync(path),image=bytes[0]===255?jpeg.decode(bytes):PNG.sync.read(bytes);assert.equal(image.width,256);assert.equal(image.height,256);tiles.set(path,{image,path,sha256:sha(bytes)})}return tiles.get(path)} for(const b of plan.buildings){ const low=[0,1].map(a=>Math.min(...b.footprintENU.map(p=>p[a]))),high=[0,1].map(a=>Math.max(...b.footprintENU.map(p=>p[a]))),span=high.map((v,a)=>v-low[a]) const [width,height]=roofRasterSize(span,{maxDimension:512,metresPerPixel:.263}),rgba=Buffer.alloc(width*height*4),used=new Set() for(let y=0;y({path:p,sha256:tiles.get(p).sha256})),caveat:'roof texture from undated satellite; facade/height estimates; no source pixels claimed as surveyed facade'} } writeFileSync(join(dir,'roof-textures.json'),JSON.stringify(textures,null,2));console.log(JSON.stringify({passed:true,textures:Object.entries(textures).map(([id,r])=>({id,size:r.size,tiles:r.sourceTiles.length})),modelConfigured:false}))