| 12345678910111213141516171819202122 |
- // Add local z19 TMS imagery coverage evidence to the large-building review queue.
- import assert from 'node:assert/strict'
- import {readFileSync,writeFileSync,mkdirSync,existsSync} from 'node:fs'
- import {resolve} from 'node:path'
- import {createHash} from 'node:crypto'
- const audit=JSON.parse(readFileSync(resolve('.scratch/cockpit-shell-panel-layout/verify/artifacts/t35/large-building-audit/audit.json')))
- const root='D:/GIS/GIS/yuanlingPic3',zoom=19,n=2**zoom
- const merc=(lon,lat)=>[(lon+180)/360*n,(1-Math.asinh(Math.tan(lat*Math.PI/180))/Math.PI)/2*n]
- const tilePath=(x,y)=>`${root}/${zoom}/${x}/${n-1-y}.png`
- const collectCoordinates=value=>{const out=[];const visit=v=>{if(Array.isArray(v)&&v.length>=2&&typeof v[0]==='number'&&typeof v[1]==='number'){out.push(v);return}if(Array.isArray(v))for(const child of v)visit(child)};visit(value);return out}
- const tileEvidence=(geometry)=>{
- const coords=collectCoordinates(geometry.coordinates),pixels=coords.map(([lon,lat])=>merc(lon,lat)),xs=pixels.map(p=>Math.floor(p[0])),ys=pixels.map(p=>Math.floor(p[1])),minX=Math.min(...xs),maxX=Math.max(...xs),minY=Math.min(...ys),maxY=Math.max(...ys),tiles=[]
- for(let x=minX;x<=maxX;x++)for(let y=minY;y<=maxY;y++){const path=tilePath(x,y);if(existsSync(path)){const bytes=readFileSync(path);tiles.push({x,y,path,sha256:createHash('sha256').update(bytes).digest('hex'),bytes:bytes.length})}else tiles.push({x,y,path,missing:true})}
- const existing=tiles.filter(t=>!t.missing).length
- assert.ok(tiles.length>0,'candidate geometry produced no imagery tiles')
- return {zoom,tms:true,bboxTiles:[minX,minY,maxX,maxY],tileCount:tiles.length,existingTiles:existing,missingTiles:tiles.length-existing,coverage:existing===tiles.length?'complete':existing?'partial':'missing',tiles}
- }
- const candidates=audit.candidates.filter(b=>b.tier==='urban').sort((a,b)=>b.areaSqm-a.areaSqm||a.id.localeCompare(b.id))
- const queue=candidates.map((b,index)=>{const imagery=tileEvidence(b.geometry),status=b.status;return {rank:index+1,id:b.id,areaSqm:b.areaSqm,width:b.width,depth:b.depth,center:b.center,maskId:b.maskId,status,terrainRelief:b.terrainRelief,source:b.source,imageryReviewed:b.imageryReviewed,imageryEvidence:imagery,action:status==='terrain relief exceeds the allowed plinth; needs stepped construction'?'Review satellite roof/footprint, then design stepped construction and re-run DEM seat check':status==='seated-outside-active-selection'?'Review satellite roof and explicitly decide whether this non-running-tier building belongs in the city runtime':'Repair survey/DEM evidence before any geometry decision'}})
- const summary={terrainReview:queue.filter(b=>b.status==='terrain relief exceeds the allowed plinth; needs stepped construction').length,seatedOutside:queue.filter(b=>b.status==='seated-outside-active-selection').length,invalidOutline:queue.filter(b=>b.status==='self-intersecting survey outline cannot be extruded').length,missingDem:queue.filter(b=>b.status==='missing or invalid DEM sample').length,imageryComplete:queue.filter(b=>b.imageryEvidence.coverage==='complete').length,imageryPartial:queue.filter(b=>b.imageryEvidence.coverage==='partial').length,imageryMissing:queue.filter(b=>b.imageryEvidence.coverage==='missing').length}
- const report={generatedAt:'2026-10-14',sourceAudit:'large-building-audit/audit.json',sourceLevel:'1:500 surveyed JMD polygon; height/facade estimated',imagerySource:`${root}/${zoom}/x/tms-y.png`,totalUrbanCandidates:queue.length,queue,summary,policy:'Queue only. Imagery coverage is evidence for human review, not proof of missing rendered geometry. Do not add geometry or restore rural assets until imagery and DEM/footprint review is explicitly accepted.'}
- const out=resolve('.scratch/cockpit-shell-panel-layout/verify/artifacts/t35/large-building-audit');mkdirSync(out,{recursive:true});writeFileSync(process.argv[2]||`${out}/review-queue-v7-imagery.json`,JSON.stringify(report,null,2));writeFileSync(process.argv[3]||`${out}/review-queue-v7-imagery.md`,['# Large building review queue v7 with imagery evidence','','Source: 1:500 surveyed JMD polygons plus local z19 TMS tiles. Candidates are not confirmed missing rendered buildings.','',`Urban candidates: ${queue.length}`,`Terrain/stepped review: ${summary.terrainReview}`,`Invalid outline: ${summary.invalidOutline}`,`Missing/invalid DEM: ${summary.missingDem}`,`Complete TMS bbox coverage: ${summary.imageryComplete}`,`Partial TMS bbox coverage: ${summary.imageryPartial}`,`Missing TMS bbox coverage: ${summary.imageryMissing}`,'','Each candidate includes tile paths and SHA-256 hashes. Imagery must still be visually reviewed before geometry changes.'].join('\n'));console.log(JSON.stringify({passed:true,urbanCandidates:queue.length,summary,top:queue.slice(0,10).map(({id,areaSqm,status,center,imageryEvidence})=>({id,areaSqm,status,center,coverage:imageryEvidence.coverage,tiles:imageryEvidence.existingTiles+'/'+imageryEvidence.tileCount}))}))
|