/* eslint-disable */ let textureValues = []; let materialValues = []; let metaData = {}; let imgValues = []; let textureVertices = []; let appearanceMaterials = []; let imgList = []; var global = self; importScripts("../comlink.min.js"); importScripts("./Cartesian3.js"); importScripts("../sqljs/sql-wasm.js"); importScripts("../earcut.js"); const defaultSemanticsColors = { GroundSurface: 0x999999ff, WallSurface: 0xffffffff, RoofSurface: 0xff0000ff, TrafficArea: 0x6e6e6eff, AuxiliaryTrafficArea: 0x2c8200ff, Window: 0x0059ffff, Door: 0x640000ff, }; const workerFunctions = { async processData(url, callback) { const fetchConfig = { method: "GET", headers: { Accept: "application/octet-stream", }, }; const response = await fetch(url, fetchConfig); const data = await response.arrayBuffer(); const uInt8Array = new Uint8Array(data); const SQL = await initSqlJs({ locateFile: (file) => `../sqljs/sql-wasm.wasm`, }); const db = new SQL.Database(uInt8Array); const textureContent = db.exec("SELECT * FROM TEXTUREVERTICE"); const imageContent = db.exec("SELECT * FROM IMAGE"); const materialContnet = db.exec("SELECT * FROM MATERIAL"); const metaDataContnet = db.exec("SELECT * FROM METADATA"); textureValues = textureContent.length ? textureContent[0].values : []; materialValues = materialContnet.length ? materialContnet[0].values : []; imgValues = imageContent.length ? imageContent[0].values : []; metaData = JSON.parse(metaDataContnet[0].values[0][0]); // 查询总的记录数量 const totalRecords = await getTotalRecords(db); let batchSize = 10; for (let offset = 0; offset < totalRecords; offset += batchSize) { try { const query = `SELECT * FROM ENTITY LIMIT ${batchSize} OFFSET ${offset}`; const result = await db.exec(query); parseCityData(result[0].values, callback); } catch (error) { console.error("error", error); } } callback({ type: "success" }); db.close(); }, }; function parseCityData(entityValues, callback) { if (textureValues.length) { textureVertices = textureValues.map((texture) => { const textureCopy = texture.slice(1); return textureCopy.map((item) => parseFloat(item)); }); } if (materialValues.length) { appearanceMaterials = materialValues.map((item) => { return JSON.parse(item[1]); }); } if (imgValues.length) { imgList = imgValues.map((item) => item[1]); } // 拿最后一次的rtcCenter, 临时作为中心点 let modelCenter = null; for (i = 0; i < entityValues.length; i++) { const cityjson = JSON.parse(entityValues[i][1]); const cityObjects = cityjson.CityObjects; for (const key in cityObjects) { if (Object.hasOwnProperty.call(cityObjects, key)) { const geometry = cityObjects[key].geometry; const attributes = cityObjects[key].attributes; const rtcCenter = [attributes.lon, attributes.lat, 0]; modelCenter = rtcCenter; const vertices = cityjson.vertices; parseGeometry(key, geometry, vertices, attributes, rtcCenter, callback); } } } callback({ type: "done", modelCenter }); } function parseGeometry( key, geometry, vertices, attributes, rtcCenter, callback ) { if (!geometry.length) { return; } for (let i = 0; i < geometry.length; i++) { parseShell(key, geometry[i], vertices, attributes, rtcCenter, callback); } } function parseShell(key, geometry, vertices, attributes, rtcCenter, callback) { const boundaries = geometry.boundaries; const lod = geometry.lod; const semantics = geometry.semantics ? geometry.semantics.values : []; const surfaces = geometry.semantics ? geometry.semantics.surfaces : []; const material = geometry.material ? geometry.material : {}; const texture = geometry.texture ? geometry.texture : {}; const vertexIds = []; let textures = {}; let textureArray = []; let surfaceType = -1; for (let i = 0; i < boundaries.length; i++) { let boundary = []; let pList = []; let holes = []; surfaceType = getSurfaceTypeIdx(i, semantics, surfaces); const boundaryContent = boundaries[i]; if (boundaryContent instanceof Array) { for (let j = 0; j < boundaryContent.length; j++) { if (boundaryContent[j] instanceof Array) { if (boundary.length > 0) { holes.push(boundary.length); } boundary.push(...boundaryContent[j]); } else { boundary.push(...boundaryContent); } } } else { boundary.push(...boundaries); } if (boundary.length === 3 && lod > 1) { for (let n = 0; n < 3; n++) { const vertext = boundary[n]; const textureData = getTextureData(i, n, holes, texture, vertext); vertexIds.push(vertext); appendTexture(textures, textureData, vertext); } } else if (boundary.length > 3 && lod > 1) { for (let k = 0; k < boundary.length; k++) { pList.push({ x: vertices[boundary[k]][0], y: vertices[boundary[k]][1], z: vertices[boundary[k]][2], }); } const normal = getNewellsNormal(pList); let pv = []; for (let k = 0; k < pList.length; k++) { const re = to_2d(pList[k], normal); pv.push(re.x); pv.push(re.y); } const tr = earcut(pv, holes, 2); for (let k = 0; k < tr.length; k += 3) { for (let n = 0; n < 3; n++) { const vertext = boundary[tr[k + n]]; const textureData = getTextureData( i, tr[k + n], holes, texture, vertext ); vertexIds.push(vertext); appendTexture(textures, textureData, vertext); } } } else if (lod < 1) { for (let n = 0; n < boundary.length; n++) { const vertext = boundary[n]; vertexIds.push(vertext); } } } textureArray = textures.index; // 找出纹理用到的所有图片,并去除图片索引为-1的项 const imageIds = [...new Set(textureArray)]; const imgIndex = imageIds.indexOf(-1); if (~imgIndex) imageIds.splice(imgIndex, 1); const newVertices = vertexIds.map((id) => { return vertices[id]; }); const newFaceIds = vertexIds.map((id, index) => { return index; }); const data = { type: "parse", key, rtcCenter, newVertices, newFaceIds, imageIds, textures, imgList, attributes, surfaceType, lod, metaData, }; callback(data); return vertexIds; } async function getTotalRecords(db) { try { const result = db.exec("SELECT COUNT(*) AS total FROM ENTITY"); const totalRecords = result[0].values[0][0]; return totalRecords; } catch (error) { console.error("Error fetching total records: ", error); return 0; } } function appendTexture(textures, textureData) { Object.entries(textureData).forEach((entry) => { const [theme, value] = entry; if (!textures["index"]) { textures["index"] = []; textures["uvs"] = []; textures["data"] = []; } textures.index.push(value.index); textures.uvs.push(value.uvs); textures.data.push({ index: value.index, uvs: value.uvs, }); }); } function getTextureData(surfaceIndex, vertexIndex, holes, texture, vertext) { const pairs = Object.entries(texture).map((tex) => { const [theme, obj] = tex; if (obj.values) { const activeHoles = holes.filter((v) => v <= vertexIndex); const ringId = activeHoles.length; const vId = ringId ? vertexIndex - activeHoles[activeHoles.length - 1] : vertexIndex; const data = obj.values[surfaceIndex]; if (data[0][0] !== null) { const uvs = textureVertices[data[ringId][vId + 1]]; if (uvs[0] < 0 || uvs[0] > 1) { uvs[0] = 0; } if (uvs[1] < 0 || uvs[0] > 1) { uvs[1] = 0; } return [theme, { index: data[0][0], uvs }]; } return [theme, { index: -1, uvs: [0, 0] }]; } else { return [theme, { index: -1, uvs: [0, 0] }]; } }); return Object.fromEntries(pairs); } function getNewellsNormal(indices) { // find normal with Newell's method const n = [0.0, 0.0, 0.0]; for (let i = 0; i < indices.length; i++) { let nex = i + 1; if (nex === indices.length) { nex = 0; } n[0] = n[0] + (indices[i].y - indices[nex].y) * (indices[i].z + indices[nex].z); n[1] = n[1] + (indices[i].z - indices[nex].z) * (indices[i].x + indices[nex].x); n[2] = n[2] + (indices[i].x - indices[nex].x) * (indices[i].y + indices[nex].y); } const b = new Cartesian3(n[0], n[1], n[2]); Cartesian3.normalize(b, b); return b; } function to_2d(p, n) { p = new Cartesian3(p.x, p.y, p.z); const x3 = new Cartesian3(1.1, 1.1, 1.1); if (Cartesian3.distance(x3, n) < 0.01) { const offset = new Cartesian3(1.0, 2.0, 3.0); Cartesian3.add(x3, offset, x3); } const tmp = Cartesian3.dot(x3, n); const tmp2 = new Cartesian3(); Cartesian3.multiplyByScalar(n, tmp, tmp2); Cartesian3.subtract(x3, tmp2, x3); Cartesian3.normalize(x3, x3); const y3 = new Cartesian3(); Cartesian3.cross(x3, n, y3); const x = Cartesian3.dot(p, x3); const y = Cartesian3.dot(p, y3); const re = { x: x, y: y }; return re; } function getSurfaceTypeIdx(idx, semantics, surfaces) { let surfaceType = -1; if (semantics.length > 0) { const surface = surfaces[semantics[idx]]; if (surface) { surfaceType = Object.keys(defaultSemanticsColors).indexOf(surface.type); if (surfaceType < 0) { surfaceType = Object.keys(defaultSemanticsColors).length; defaultSemanticsColors[surface.type] = Math.floor( Math.random() * 0xffffff ); } } } return surfaceType; } Comlink.expose(workerFunctions);