upatde: json + models
🔍 Lint / 🪄 Check lint (pull_request) Has been cancelled
🔍 Lint / 🎨 Check format (pull_request) Has been cancelled
🔍 Lint / 🔎 Typecheck (pull_request) Has been cancelled
📊 Quality / 🔒 Security Audit (pull_request) Has been cancelled
📊 Quality / 📋 Dependency Freshness (pull_request) Has been cancelled
📊 Quality / 📦 Bundle Size (pull_request) Has been cancelled
🔍 Lint / 🏗 Build (pull_request) Has been cancelled
🔍 Lint / 🪄 Check lint (pull_request) Has been cancelled
🔍 Lint / 🎨 Check format (pull_request) Has been cancelled
🔍 Lint / 🔎 Typecheck (pull_request) Has been cancelled
📊 Quality / 🔒 Security Audit (pull_request) Has been cancelled
📊 Quality / 📋 Dependency Freshness (pull_request) Has been cancelled
📊 Quality / 📦 Bundle Size (pull_request) Has been cancelled
🔍 Lint / 🏗 Build (pull_request) Has been cancelled
This commit is contained in:
+213
-62
@@ -13,7 +13,11 @@ const MESH_NAME_MAPPINGS = {
|
||||
panneauxquartier: "panneauaffichage",
|
||||
};
|
||||
|
||||
const REMOVED_NODE_NAMES = new Set(["ROOT", "mc"]);
|
||||
const IDENTITY_NODE = {
|
||||
position: [0, 0, 0],
|
||||
rotation: [0, 0, 0],
|
||||
scale: [1, 1, 1],
|
||||
};
|
||||
|
||||
function cloneNode(node) {
|
||||
return {
|
||||
@@ -25,32 +29,147 @@ function cloneNode(node) {
|
||||
};
|
||||
}
|
||||
|
||||
function mapMeshName(node) {
|
||||
if (node.type !== "Mesh") {
|
||||
return cloneNode(node);
|
||||
}
|
||||
function createGroup(name, sourceNode) {
|
||||
return {
|
||||
name,
|
||||
type: "Object3D",
|
||||
role: "group",
|
||||
position: sourceNode?.position ?? IDENTITY_NODE.position,
|
||||
rotation: sourceNode?.rotation ?? IDENTITY_NODE.rotation,
|
||||
scale: sourceNode?.scale ?? IDENTITY_NODE.scale,
|
||||
children: [],
|
||||
};
|
||||
}
|
||||
|
||||
function mapMeshNode(node) {
|
||||
return {
|
||||
...cloneNode(node),
|
||||
name: MESH_NAME_MAPPINGS[node.name] ?? node.name,
|
||||
};
|
||||
}
|
||||
|
||||
function createGroup(node, children = []) {
|
||||
function getOrCreateModelGroup(parent, modelName) {
|
||||
let group = parent.children.find(
|
||||
(child) => child.name === modelName && child.type === "Object3D",
|
||||
);
|
||||
|
||||
if (!group) {
|
||||
group = createGroup(modelName);
|
||||
parent.children.push(group);
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
function createRenderableObject(objectNode, meshNode) {
|
||||
const mappedMesh = mapMeshNode(meshNode);
|
||||
|
||||
return {
|
||||
...cloneNode(node),
|
||||
name: node.name === "Neutre" ? "blocking" : node.name,
|
||||
children,
|
||||
...cloneNode(objectNode ?? meshNode),
|
||||
name: mappedMesh.name,
|
||||
type: "Object3D",
|
||||
children: [mappedMesh],
|
||||
};
|
||||
}
|
||||
|
||||
function addRenderable(parent, objectNode, meshNode) {
|
||||
const renderable = createRenderableObject(objectNode, meshNode);
|
||||
getOrCreateModelGroup(parent, renderable.name).children.push(renderable);
|
||||
}
|
||||
|
||||
function addObjectsByRange(rawData, parent, start, end, allowedNames) {
|
||||
let currentObject = null;
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
const node = rawData[i];
|
||||
|
||||
if (node?.type === "Object3D") {
|
||||
currentObject = node;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (node?.type !== "Mesh") continue;
|
||||
if (allowedNames && !allowedNames.has(node.name)) continue;
|
||||
|
||||
addRenderable(parent, currentObject, node);
|
||||
}
|
||||
}
|
||||
|
||||
function getNearestGroup(groups, node) {
|
||||
const [x, , z] = node.position;
|
||||
|
||||
return groups.reduce((nearest, group) => {
|
||||
const [gx, , gz] = group.position;
|
||||
const distance = Math.hypot(x - gx, z - gz);
|
||||
if (!nearest || distance < nearest.distance) {
|
||||
return { group, distance };
|
||||
}
|
||||
return nearest;
|
||||
}, null).group;
|
||||
}
|
||||
|
||||
function createResidenceZones(rawData, residence) {
|
||||
const zoneSources = [rawData[830], rawData[874], rawData[892]];
|
||||
const zones = zoneSources.map((sourceNode, index) => {
|
||||
const zone = createGroup(`zone${index + 1}_residence`, sourceNode);
|
||||
residence.children.push(zone);
|
||||
return zone;
|
||||
});
|
||||
|
||||
addObjectsByRange(rawData, zones[0], 831, 873, RESIDENCE_MESH_NAMES);
|
||||
addObjectsByRange(rawData, zones[1], 875, 891, RESIDENCE_MESH_NAMES);
|
||||
addObjectsByRange(rawData, zones[2], 893, 942, RESIDENCE_MESH_NAMES);
|
||||
|
||||
for (let i = 14; i <= 23; i++) {
|
||||
const node = rawData[i];
|
||||
if (node?.type === "Mesh" && node.name === "parcebike") {
|
||||
addRenderable(getNearestGroup(zones, node), null, node);
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 25; i <= 58; i++) {
|
||||
const node = rawData[i];
|
||||
if (node?.type === "Mesh" && node.name === "boitesauxlettres") {
|
||||
addRenderable(getNearestGroup(zones, node), null, node);
|
||||
}
|
||||
}
|
||||
|
||||
return zones;
|
||||
}
|
||||
|
||||
const VEGETATION_MESH_NAMES = new Set(["arbre", "sapin", "buissons"]);
|
||||
const CHAMP_MESH_NAMES = new Set([
|
||||
"champdeble",
|
||||
"champdesoja",
|
||||
"champsdetournesol",
|
||||
]);
|
||||
const FERME_MESH_NAMES = new Set(["buissons", "buisson", "fermeverticale"]);
|
||||
const RESIDENCE_MESH_NAMES = new Set(["immeuble_1", "immeuble_2", "maison1"]);
|
||||
const ENERGIE_MESH_NAMES = new Set([
|
||||
"pyloneelectrique",
|
||||
"eoliennes",
|
||||
"panneausolaire",
|
||||
"generateur",
|
||||
]);
|
||||
const DIRECTION_MESH_NAMES = new Set([
|
||||
"panneauxcentre",
|
||||
"panneauxdomaine",
|
||||
"panneaudircentre",
|
||||
"panneaudirdomaine",
|
||||
"panneaudirfabrik",
|
||||
"panneaudirresidences1",
|
||||
"panneaudirresidences2",
|
||||
"panneauxquartier",
|
||||
]);
|
||||
const LAFABRIK_MESH_NAMES = new Set([
|
||||
"lafabrik",
|
||||
"immeuble_1",
|
||||
"immeuble_2",
|
||||
"maison1",
|
||||
]);
|
||||
function transformMap() {
|
||||
console.log("Reading map_raw.json...");
|
||||
const rawData = JSON.parse(fs.readFileSync(INPUT_PATH, "utf-8"));
|
||||
console.log(`Found ${rawData.length} nodes in raw file`);
|
||||
|
||||
let removedCount = 0;
|
||||
let renamedCount = 0;
|
||||
|
||||
const sceneRaw = rawData.find(
|
||||
(node) => node.name === "Scene" && node.type === "Object3D",
|
||||
@@ -58,67 +177,99 @@ function transformMap() {
|
||||
const terrainRaw = rawData.find(
|
||||
(node) => node.name === "terrain" && node.type === "Object3D",
|
||||
);
|
||||
const terrainMesh = rawData.find(
|
||||
(node) => node.name === "terrain" && node.type === "Mesh",
|
||||
);
|
||||
const blockingRaw = rawData.find(
|
||||
(node) => node.name === "Neutre" && node.type === "Object3D",
|
||||
);
|
||||
|
||||
if (!sceneRaw || !terrainRaw || !blockingRaw) {
|
||||
throw new Error("Missing required Scene, terrain, or Neutre node");
|
||||
if (!sceneRaw || !terrainRaw || !terrainMesh || !blockingRaw) {
|
||||
throw new Error("Missing required Scene, terrain, or Neutre nodes");
|
||||
}
|
||||
|
||||
const scene = createGroup(sceneRaw);
|
||||
const terrain = createGroup(terrainRaw);
|
||||
const blocking = createGroup(blockingRaw);
|
||||
let currentGroup = null;
|
||||
const scene = createGroup("Scene", sceneRaw);
|
||||
const terrain = createGroup("terrain", terrainRaw);
|
||||
const blocking = createGroup("blocking", blockingRaw);
|
||||
const vegetation = createGroup("vegetation");
|
||||
const agriculture = createGroup("agriculture");
|
||||
const champs = createGroup("champs");
|
||||
const ferme = createGroup("ferme", rawData[4798]);
|
||||
const residence = createGroup("residence");
|
||||
const energie = createGroup("energie", rawData[4800]);
|
||||
const direction = createGroup("direction", rawData[5]);
|
||||
const lafabrik = createGroup("lafabrik", rawData[4873]);
|
||||
const ecole = createGroup("ecole", rawData[4895]);
|
||||
delete ecole.role;
|
||||
const unclassified = createGroup("unclassified");
|
||||
|
||||
for (const rawNode of rawData) {
|
||||
if (REMOVED_NODE_NAMES.has(rawNode.name)) {
|
||||
removedCount++;
|
||||
continue;
|
||||
terrain.children.push(createRenderableObject(terrainRaw, terrainMesh));
|
||||
scene.children.push(terrain, blocking);
|
||||
blocking.children.push(
|
||||
vegetation,
|
||||
agriculture,
|
||||
residence,
|
||||
energie,
|
||||
direction,
|
||||
lafabrik,
|
||||
ecole,
|
||||
);
|
||||
agriculture.children.push(champs, ferme);
|
||||
|
||||
addObjectsByRange(rawData, direction, 6, 12, DIRECTION_MESH_NAMES);
|
||||
createResidenceZones(rawData, residence);
|
||||
addObjectsByRange(rawData, energie, 61, 96, new Set(["pyloneelectrique"]));
|
||||
addObjectsByRange(rawData, vegetation, 98, 829, VEGETATION_MESH_NAMES);
|
||||
addObjectsByRange(rawData, agriculture, 944, 944, new Set(["tuyauxlac"]));
|
||||
addObjectsByRange(rawData, champs, 946, 4594, CHAMP_MESH_NAMES);
|
||||
addObjectsByRange(rawData, ferme, 4595, 4799, FERME_MESH_NAMES);
|
||||
addObjectsByRange(rawData, vegetation, 4750, 4797, VEGETATION_MESH_NAMES);
|
||||
addObjectsByRange(rawData, energie, 4801, 4872, ENERGIE_MESH_NAMES);
|
||||
addObjectsByRange(rawData, lafabrik, 4874, 4894, LAFABRIK_MESH_NAMES);
|
||||
addObjectsByRange(rawData, direction, 4896, 4897, DIRECTION_MESH_NAMES);
|
||||
addObjectsByRange(rawData, vegetation, 4898, 4997, VEGETATION_MESH_NAMES);
|
||||
|
||||
for (let i = 0; i < rawData.length; i++) {
|
||||
const node = rawData[i];
|
||||
if (node.type !== "Mesh") continue;
|
||||
if (node.name === "mc") continue;
|
||||
if (node.name === "bati-ecole") continue;
|
||||
|
||||
const alreadyClassified = isMeshClassified(scene, node);
|
||||
if (!alreadyClassified) {
|
||||
addRenderable(unclassified, null, node);
|
||||
}
|
||||
|
||||
if (rawNode.name === "Scene" || rawNode.name === "Neutre") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rawNode.name === "terrain" && rawNode.type === "Object3D") {
|
||||
currentGroup = terrain;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rawNode.type === "Object3D") {
|
||||
currentGroup = createGroup(rawNode);
|
||||
blocking.children.push(currentGroup);
|
||||
continue;
|
||||
}
|
||||
|
||||
const mappedNode = mapMeshName(rawNode);
|
||||
if (mappedNode.name !== rawNode.name) {
|
||||
renamedCount++;
|
||||
}
|
||||
|
||||
if (rawNode.name === "terrain" && currentGroup === terrain) {
|
||||
terrain.children.push(mappedNode);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentGroup) {
|
||||
currentGroup.children.push(mappedNode);
|
||||
continue;
|
||||
}
|
||||
|
||||
blocking.children.push(mappedNode);
|
||||
}
|
||||
|
||||
scene.children = [terrain, blocking];
|
||||
|
||||
console.log(`\nTransformation complete:`);
|
||||
console.log(` - Removed ${removedCount} mc/ROOT nodes`);
|
||||
console.log(` - Renamed ${renamedCount} mesh nodes`);
|
||||
console.log(` - Output: hierarchical Scene root`);
|
||||
if (unclassified.children.length > 0) {
|
||||
blocking.children.push(unclassified);
|
||||
}
|
||||
|
||||
fs.writeFileSync(OUTPUT_PATH, JSON.stringify(scene, null, 2));
|
||||
console.log(`\nWritten to ${OUTPUT_PATH}`);
|
||||
console.log(`Written hierarchical map to ${OUTPUT_PATH}`);
|
||||
}
|
||||
|
||||
function isSameTransform(a, b) {
|
||||
return (
|
||||
a.name === (MESH_NAME_MAPPINGS[b.name] ?? b.name) &&
|
||||
JSON.stringify(a.position) === JSON.stringify(b.position) &&
|
||||
JSON.stringify(a.rotation) === JSON.stringify(b.rotation) &&
|
||||
JSON.stringify(a.scale) === JSON.stringify(b.scale)
|
||||
);
|
||||
}
|
||||
|
||||
function isMeshClassified(root, rawMeshNode) {
|
||||
const stack = [...(root.children ?? [])];
|
||||
|
||||
while (stack.length > 0) {
|
||||
const node = stack.pop();
|
||||
if (node.type === "Mesh" && isSameTransform(node, rawMeshNode)) {
|
||||
return true;
|
||||
}
|
||||
stack.push(...(node.children ?? []));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
transformMap();
|
||||
|
||||
Reference in New Issue
Block a user