/* 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);
|
}
|
}
|
}
|
|
// const cityjson = JSON.parse(entityValues[3][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;
|
// parseShell(geometry[1], vertices, attributes, rtcCenter, 3, attributes);
|
// }
|
// }
|
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,
|
attributes,
|
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);
|