212 lines
6.6 KiB
JavaScript
212 lines
6.6 KiB
JavaScript
|
import { getProp, parseSequence, getColor, circleToPolygon } from './util'
|
||
|
import { point, lineString, polygon } from '@turf/helpers';
|
||
|
import transformTranslate from '@turf/transform-translate';
|
||
|
import clone from '@turf/clone';
|
||
|
import proj4 from 'proj4';
|
||
|
|
||
|
export const LANDXML_PIPE_NETWORK_PIPE = 'pipe_network_pipe';
|
||
|
export const LANDXML_PIPE_NETWORK_STRUCT = 'pipe_network_struct';
|
||
|
|
||
|
export function convertPipeNetworks(xmlObj, projection, opts) {
|
||
|
|
||
|
const features = [];
|
||
|
|
||
|
const pipeNetworksNodes = getProp(xmlObj, "LandXML", "PipeNetworks");
|
||
|
|
||
|
if (!pipeNetworksNodes) return features;
|
||
|
|
||
|
pipeNetworksNodes.forEach(pn => {
|
||
|
|
||
|
const pipeNetworkNodes = getProp(pn, "PipeNetwork");
|
||
|
|
||
|
if (!Array.isArray(pipeNetworkNodes)) return;
|
||
|
|
||
|
let structs = {};
|
||
|
|
||
|
pipeNetworkNodes.forEach(pn => {
|
||
|
|
||
|
const baseProps = {
|
||
|
name: pn.$.name,
|
||
|
description: pn.$.desc,
|
||
|
"stroke-width": 0.1,
|
||
|
"fill-opacity": 0.5,
|
||
|
};
|
||
|
|
||
|
const localStructs = convertStructs(pn, projection, baseProps, opts);
|
||
|
|
||
|
features.push(...Object.values(localStructs).map(s => s.geometry));
|
||
|
|
||
|
Object.assign(structs, localStructs);
|
||
|
|
||
|
});
|
||
|
|
||
|
pipeNetworkNodes.forEach(pn => {
|
||
|
|
||
|
const baseProps = {
|
||
|
name: pn.$.name,
|
||
|
description: pn.$.desc,
|
||
|
landxmlType: LANDXML_PIPE_NETWORK_PIPE,
|
||
|
"stroke-width": 1,
|
||
|
"fill-opacity": 1,
|
||
|
};
|
||
|
|
||
|
const pipes = convertPipes(pn, structs, projection, baseProps, opts);
|
||
|
|
||
|
features.push(...pipes);
|
||
|
|
||
|
});
|
||
|
|
||
|
});
|
||
|
|
||
|
|
||
|
return features;
|
||
|
|
||
|
}
|
||
|
|
||
|
function convertPipes(pipeNetwork, structs, projection, baseProps, opts) {
|
||
|
const pipes = [];
|
||
|
|
||
|
const pipeNodes = getProp(pipeNetwork, "Pipes", 0, "Pipe");
|
||
|
|
||
|
if (!Array.isArray(pipeNodes)) return;
|
||
|
|
||
|
pipeNodes.forEach(p => {
|
||
|
|
||
|
const circPipeNode = getProp(p, "CircPipe", 0);
|
||
|
|
||
|
const name = baseProps.name ? baseProps.name + ' - ' + p.$.name : p.$.name;
|
||
|
const featureProps = Object.assign({}, baseProps, {
|
||
|
name: name,
|
||
|
description: baseProps.description ? baseProps.description + ' - ' + p.$.desc : p.$.desc,
|
||
|
stroke: getColor(`pipe-network-pipe-${name}`, opts.colorOpts)
|
||
|
});
|
||
|
|
||
|
if (circPipeNode !== undefined) {
|
||
|
const attrs = circPipeNode.$;
|
||
|
if ('diameter' in attrs) featureProps.landxmlDiameter = parseFloat(attrs.diameter);
|
||
|
if ('thickness' in attrs) featureProps.landxmlThickness = parseFloat(attrs.thickness);
|
||
|
}
|
||
|
|
||
|
const refStart = structs[p.$.refStart];
|
||
|
const refEnd = structs[p.$.refEnd];
|
||
|
|
||
|
if (!refStart) throw new Error(`Cannot find pipe "${featureProps.name}" refStart "${p.$.refStart}" !`);
|
||
|
if (!refEnd) throw new Error(`Cannot find pipe "${featureProps.name}" refEnd "${p.$.refEnd}" !`);
|
||
|
|
||
|
const pipe = lineString([
|
||
|
refStart.center,
|
||
|
refEnd.center,
|
||
|
], featureProps);
|
||
|
|
||
|
pipes.push(pipe);
|
||
|
|
||
|
});
|
||
|
|
||
|
return pipes;
|
||
|
}
|
||
|
|
||
|
function convertStructs(pipeNetwork, projection, baseProps, opts) {
|
||
|
|
||
|
const structs = {};
|
||
|
|
||
|
const structNodes = getProp(pipeNetwork, "Structs", 0, "Struct");
|
||
|
|
||
|
if (!Array.isArray(structNodes)) return;
|
||
|
|
||
|
structNodes.forEach(s => {
|
||
|
|
||
|
const centerNode = getProp(s, "Center", 0);
|
||
|
const rectStructNode = getProp(s, "RectStruct", 0);
|
||
|
const circStructNode = getProp(s, "CircStruct", 0);
|
||
|
const inletStructNode = getProp(s, "InletStruct", 0);
|
||
|
const outletStructNode = getProp(s, "OutletStruct", 0);
|
||
|
const connectionNode = getProp(s, "Connection", 0);
|
||
|
|
||
|
const structType = rectStructNode !== undefined ? "rect" : (
|
||
|
( circStructNode !== undefined ? "circ" :
|
||
|
( inletStructNode !== undefined ? "inlet" :
|
||
|
( outletStructNode !== undefined ? "outlet" :
|
||
|
( connectionNode !== undefined ? "connection" :
|
||
|
( null )
|
||
|
)))));
|
||
|
|
||
|
const name = baseProps.name ? baseProps.name + ' - ' + s.$.name : s.$.name;
|
||
|
const featureProps = Object.assign({}, baseProps, {
|
||
|
name: name,
|
||
|
description: baseProps.description ? baseProps.description + ' - ' + s.$.desc : s.$.desc,
|
||
|
landxmlType: LANDXML_PIPE_NETWORK_STRUCT,
|
||
|
landxmlStruct: structType,
|
||
|
landxmlElevRim: 'elevRim' in s.$ ? parseFloat(s.$.elevRim) : undefined,
|
||
|
landxmlElevSump: 'elevSump' in s.$ ? parseFloat(s.$.elevSump) : undefined,
|
||
|
fill: getColor(`pipe-network-struct-${name}`, opts.colorOpts)
|
||
|
});
|
||
|
|
||
|
if (circStructNode !== undefined) {
|
||
|
const attrs = circStructNode.$;
|
||
|
if ('diameter' in attrs) featureProps.landxmlDiameter = parseFloat(attrs.diameter);
|
||
|
if ('thickness' in attrs) featureProps.landxmlThickness = parseFloat(attrs.thickness);
|
||
|
}
|
||
|
|
||
|
if (rectStructNode !== undefined) {
|
||
|
const attrs = rectStructNode.$;
|
||
|
if ('thickness' in attrs) featureProps.landxmlThickness = parseFloat(attrs.thickness);
|
||
|
if ('length' in attrs) featureProps.landxmlLength = parseFloat(attrs.length);
|
||
|
if ('width' in attrs) featureProps.landxmlWidth = parseFloat(attrs.width);
|
||
|
}
|
||
|
|
||
|
// Parse and convert center coordinates
|
||
|
const seq = parseSequence(centerNode).map(v => parseFloat(v));
|
||
|
let center = [seq[1], seq[0]];
|
||
|
center = proj4(projection, 'WGS84', center);
|
||
|
|
||
|
let geometry;
|
||
|
|
||
|
if (rectStructNode) {
|
||
|
const length = featureProps.length ? featureProps.length : 1;
|
||
|
const width = featureProps.width ? featureProps.width : 1;
|
||
|
geometry = squareAround(center, length, width, 'meters', featureProps);
|
||
|
} else {
|
||
|
const diameter = featureProps.landxmlDiameter ? featureProps.landxmlDiameter : 1;
|
||
|
geometry = circleToPolygon(center, diameter/2, 128, featureProps);
|
||
|
}
|
||
|
|
||
|
if (!geometry) {
|
||
|
throw new Error("Unsupported struct type")
|
||
|
};
|
||
|
|
||
|
structs[s.$.name] = { geometry, center };
|
||
|
|
||
|
});
|
||
|
|
||
|
return structs;
|
||
|
|
||
|
}
|
||
|
|
||
|
function squareAround(centerCoords, length, width, units, properties) {
|
||
|
const center = point(centerCoords);
|
||
|
|
||
|
const northEast = clone(center);
|
||
|
transformTranslate(northEast, width/2, 270, { units, mutate: true });
|
||
|
transformTranslate(northEast, length/2, 0, { units, mutate: true });
|
||
|
|
||
|
const northWest = clone(center);
|
||
|
transformTranslate(northWest, width/2, 90, { units, mutate: true });
|
||
|
transformTranslate(northWest, length/2, 0, { units, mutate: true });
|
||
|
|
||
|
const southWest = clone(center);
|
||
|
transformTranslate(southWest, width/2, 90, { units, mutate: true });
|
||
|
transformTranslate(southWest, length/2, 180, { units, mutate: true });
|
||
|
|
||
|
const southEast = clone(center);
|
||
|
transformTranslate(southEast, width/2, 270, { units, mutate: true });
|
||
|
transformTranslate(southEast, length/2, 180, { units, mutate: true });
|
||
|
|
||
|
const points = [
|
||
|
northEast.geometry.coordinates, northWest.geometry.coordinates,
|
||
|
southWest.geometry.coordinates, southEast.geometry.coordinates,
|
||
|
northEast.geometry.coordinates
|
||
|
];
|
||
|
|
||
|
return polygon([points], properties);
|
||
|
|
||
|
}
|