@csi-foxbyte/cityjson-to-3d-tiles
Version:
A Node.js library that converts CityJSON files into Cesium 3D Tiles—complete with automatic texture atlas packing, Basis compression, three LOD levels, and customizable threading.
2 lines • 4.19 kB
JavaScript
import {Logger}from'@gltf-transform/core';import {PromisePool}from'@supercharge/promise-pool/dist/index.js';import {readFile}from'fs/promises';import {glob}from'glob';import J,{join}from'path';import {Worker}from'worker_threads';import {getIO}from'../3dtiles/io.js';import {createDatabase}from'../database/index.js';import {buildGeometry}from'./buildGeometry.js';import {convertEPSGFromCityJSONToProj4}from'./helpers.js';import {queue}from'async';import {WorkerPool}from'./workerPool.js';import {existsSync}from'fs';Logger.DEFAULT_INSTANCE=new Logger(Logger.Verbosity.SILENT);async function fr(y,f,T,O,w={}){const{threadCount:P=4}=w;if(!existsSync(y))throw new Error(`FATAL: no such directory: ${y}`);if(!existsSync(f))throw new Error(`FATAL: no such directory: ${f}`);const N=await glob("**/*.json",{absolute:true,cwd:y}),A=N.map(t=>({folderPath:J.dirname(t),inputFile:t})),u=J.join(f,"tmp-db.bin"),n=await createDatabase(u,true),m=new WorkerPool(()=>new Worker(new URL("./worker.js",import.meta.url)),P),R=await getIO(),k=new Set,l=new Set;let W=null,E=0;const h=await n.prepare("INSERT INTO instancedData (arrayIndex, srcSRS, doc, id, filePath) VALUES (?, ?, ?, ?, ?)"),g=await n.prepare("INSERT INTO data (name, childrenIds, parentIds, address, attributes, type, bbMinX, bbMinY, bbMinZ, bbMaxX, bbMaxY, bbMaxZ, doc, isInstanced, refId, transformationMatrix) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"),s=await n.prepare("INSERT INTO textures (img, path) VALUES (?, ?)");for(const{inputFile:t,folderPath:S}of A){const U=(await readFile(t)).toString(),c=JSON.parse(U);let i=W??w.srcSRS??null;try{i??(i=convertEPSGFromCityJSONToProj4(c.metadata?.referenceSystem));}catch(e){console.error(e);}if(W??(W=i),!i)throw new Error("No valid src srs found please provide one!");const C=Object.entries(c.CityObjects),M=c["geometry-templates"]?.templates??[],L=c["geometry-templates"]?.["vertices-templates"]??[];try{for(let e=0;e<M.length;e++){const a=await buildGeometry({geometry:[M[e]],vertices:L,id:e.toString(),cityJson:c,src:i,dest:"+proj=geocent +datum=WGS84 +units=m +no_defs +type=crs",folderPath:S,appearance:T,noTransform:!0,dbInstance:n});if(a.length!==1)throw new Error("Unexpected!");const I=await R.readBinary(a[0].serializedDoc);await h.bind({1:e.toString(),2:i,3:await R.writeBinary(I),4:[crypto.randomUUID(),crypto.randomUUID()].join("-"),5:t}),await h.run();}}catch(e){console.error("ERROR in INSTANCING:",e);}await m.messageWorkers({type:"init",data:{cityJsonRaw:U,src:i,dbFile:u,filePath:t}});const b=queue(async e=>{await e();},1);await PromisePool.withConcurrency(P).for(C).process(async([e,a])=>{const I=await m.run({type:"work",data:{id:e,folderPath:S,appearance:T,dest:w.destSRS}});try{try{for(const r of I){let p=r.id??crypto.randomUUID();k.has(p)&&(p=crypto.randomUUID()),k.add(p),await b.push(async()=>{await g.bind({1:p,2:a.children?.join("_#,#_"),3:a.parents?.join("_#,#_"),4:JSON.stringify(a.address??{}),5:JSON.stringify(a.attributes??{}),6:a.type,7:r.cartographicBoxMinX,8:r.cartographicBoxMinY,9:r.cartographicBoxMinZ,10:r.cartographicBoxMaxX,11:r.cartographicBoxMaxY,12:r.cartographicBoxMaxZ,13:r.serializedDoc,14:r.isInstanced?1:0,15:r.refId,16:r.transformationMatrix?.join("@")}),await g.run();});try{for(const o of r.texturePaths){if(l.has(o)||o==="UNTEXTURED")continue;const d=await readFile(join(S,o));await b.push(async()=>{await s.bind({1:d,2:o}),await s.run();}),l.add(o);}for(const{buffer:o,name:d}of r.collectedTextures)l.has(d)||(await b.push(async()=>{await s.bind({1:o,2:d}),await s.run();}),l.add(d));}catch(o){console.error(o,r.texturePaths);}}}catch(r){console.error("a",r);}}catch(r){console.error("b",r);}}),E++,O(E/N.length);}try{await g.finalize();}catch(t){console.error("prepared geometry insert failed",t);}try{await h.finalize();}catch(t){console.error("prepared geometry template insert failed",t);}try{await s.finalize();}catch(t){console.error("prepared texture insert failed",t);}await m.messageWorkers({type:"terminate"}),m.terminate();try{await n.close();}catch(t){console.error(t);}return {dbFilePath:u}}export{fr as generateTileDatabaseFromCityJSON};//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map