landxml/lib/pipe-network.js

212 lines
6.8 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,
};
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,
};
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,
landxmlColor: 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);
if ('material' in attrs) featureProps.landxmlMaterial = attrs.material;
}
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,
landxmlColor: 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], seq[2]];
center = proj4(projection, 'WGS84', center);
featureProps.landxmlCenterLongitude = center[0];
featureProps.landxmlCenterLatitude = center[1];
featureProps.landxmlCenterAltitude = center[2];
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);
}