127 lines
3.5 KiB
JavaScript
127 lines
3.5 KiB
JavaScript
import { getProp, parseSequence, getColor } from './util'
|
|
import { polygon } from '@turf/helpers';
|
|
import union from '@turf/union';
|
|
import proj4 from 'proj4';
|
|
|
|
export const LANDXML_SURFACE = 'surface';
|
|
|
|
export function convertSurfaces(xmlObj, projection, opts) {
|
|
|
|
const features = [];
|
|
|
|
const surfacesContainerNodes = getProp(xmlObj, "LandXML", "Surfaces");
|
|
|
|
if (!surfacesContainerNodes) return features;
|
|
|
|
surfacesContainerNodes.forEach(sc => {
|
|
|
|
const attrs = (sc.$ || {});
|
|
|
|
const baseProps = {
|
|
name: attrs.name || "",
|
|
description: attrs.desc,
|
|
};
|
|
|
|
const surfaceNodes = getProp(sc, "Surface");
|
|
if (!Array.isArray(surfaceNodes)) return;
|
|
|
|
surfaceNodes.forEach(s => {
|
|
|
|
const name = baseProps.name ? ( baseProps.name + ' - ' + s.$.name ) : s.$.name;
|
|
const description = baseProps.description ? ( baseProps.description + ' - ' + s.$.desc ) : s.$.desc;
|
|
const featureProps = {
|
|
name: name,
|
|
description: description,
|
|
landxmlType: LANDXML_SURFACE,
|
|
landxmlColor: getColor(`surface-${name}`, opts.colorOpts),
|
|
};
|
|
|
|
let surfaceFeatures = convertBoundaries(s, projection, featureProps, opts);
|
|
|
|
if (surfaceFeatures.length !== 0) {
|
|
features.push(...surfaceFeatures);
|
|
} else {
|
|
surfaceFeatures = convertFaces(s, projection, featureProps, opts);
|
|
|
|
let merged = surfaceFeatures[0];
|
|
|
|
console.error("Applying union to %s faces (%d faces to merge)", merged.properties.name, surfaceFeatures.length);
|
|
|
|
for (let i = 1; i < surfaceFeatures.length-1; i++) {
|
|
const next = surfaceFeatures[i+1];
|
|
if (!next) return;
|
|
try {
|
|
merged = union(merged, next);
|
|
} catch(err) {
|
|
console.error("--> Could not apply union to %s (#%d)", next.properties.name, i+1);
|
|
// Ignore
|
|
}
|
|
}
|
|
|
|
merged.properties = featureProps;
|
|
|
|
features.push(merged);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
return features;
|
|
|
|
}
|
|
|
|
function convertFaces(surface, projection, featureProps, opts) {
|
|
|
|
const pointNodes = getProp(surface, "Definition", 0, "Pnts", 0, "P");
|
|
const faceNodes = getProp(surface, "Definition", 0, "Faces", 0, "F");
|
|
|
|
const points = {};
|
|
|
|
pointNodes.forEach(p => {
|
|
let pointCoords = parseSequence(p._).map(v => parseFloat(v));
|
|
pointCoords = [pointCoords[1], pointCoords[0], pointCoords[2]];
|
|
pointCoords = proj4(projection, 'WGS84', pointCoords);
|
|
const pointId = p.$.id;
|
|
points[pointId] = { name: p.$.name, coords: pointCoords };
|
|
});
|
|
|
|
const faces = [];
|
|
faceNodes.forEach(f => {
|
|
const pointIds = parseSequence(f);
|
|
const coords = [];
|
|
pointIds.forEach(id => {
|
|
const p = points[id];
|
|
coords.push(p.coords);
|
|
});
|
|
coords.push(points[pointIds[0]].coords);
|
|
faces.push(polygon([coords], featureProps));
|
|
});
|
|
|
|
return [...faces];
|
|
|
|
}
|
|
|
|
function convertBoundaries(surface, projection, featureProps, opts) {
|
|
const boundaryNodes = getProp(surface, "SourceData", 0, "Boundaries", 0, "Boundary");
|
|
|
|
if (!boundaryNodes) return [];
|
|
|
|
const polygons = [];
|
|
boundaryNodes.forEach(boundary => {
|
|
const pntList3DNode = getProp(boundary, 'PntList3D', 0);
|
|
const seq = parseSequence(pntList3DNode).map(p => parseFloat(p));
|
|
const coords = [];
|
|
for (let i = 0; i < seq.length; i += 3) {
|
|
let c = [seq[i+1], seq[i]];
|
|
c = proj4(projection, 'WGS84', c);
|
|
coords.push(c);
|
|
}
|
|
coords.push(coords[0]);
|
|
polygons.push(polygon([coords], featureProps));
|
|
});
|
|
|
|
return polygons;
|
|
|
|
} |