UNPKG

isoxml

Version:

JavaScript library to parse and generate ISOXML (ISO11783-10) files

153 lines (152 loc) 7.45 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ExtendedPolygon = void 0; const turf_1 = require("@turf/turf"); const polygon_clipping_1 = __importDefault(require("polygon-clipping")); const baseEntities_1 = require("../baseEntities"); const constants_1 = require("../baseEntities/constants"); const classRegistry_1 = require("../classRegistry"); const LineString_1 = require("./LineString"); class ExtendedPolygon extends baseEntities_1.Polygon { constructor(attributes, isoxmlManager) { super(attributes, isoxmlManager); this.tag = constants_1.TAGS.Polygon; } static fromXML(xml, isoxmlManager, internalId) { return baseEntities_1.Polygon.fromXML(xml, isoxmlManager, internalId, ExtendedPolygon); } static fromGeoJSON(geoJSON, polygonType, isoxmlManager) { if (geoJSON.type === 'Polygon') { geoJSON = { type: 'MultiPolygon', coordinates: [geoJSON.coordinates] }; } if (isoxmlManager.options.version === 3) { const lineStrings = [].concat(...geoJSON.coordinates.map(component => component.map((ring, idx) => LineString_1.ExtendedLineString.fromGeoJSONCoordinates(ring, isoxmlManager, idx ? baseEntities_1.LineStringLineStringTypeEnum.PolygonInterior : baseEntities_1.LineStringLineStringTypeEnum.PolygonExterior)))); return [new ExtendedPolygon({ PolygonType: polygonType, LineString: lineStrings }, isoxmlManager)]; } else { return geoJSON.coordinates.map(component => new ExtendedPolygon({ PolygonType: polygonType, LineString: component.map((ring, idx) => LineString_1.ExtendedLineString.fromGeoJSONCoordinates(ring, isoxmlManager, idx ? baseEntities_1.LineStringLineStringTypeEnum.PolygonInterior : baseEntities_1.LineStringLineStringTypeEnum.PolygonExterior)) }, isoxmlManager)); } } // converts polygons to fits format of the target ISOXML version (taken from the first Polygon) static normalizePolygons(polygons) { if (!polygons || polygons.length === 0) { return []; } const isoxmlManager = polygons[0].isoxmlManager; if (isoxmlManager.options.version === 3) { if (polygons.length === 1) { return polygons; } const allLineStrings = [].concat(...polygons.map(poly => poly.attributes.LineString)); const combinedPolygon = new ExtendedPolygon(Object.assign(Object.assign({}, polygons[0].attributes), { LineString: allLineStrings }), isoxmlManager); delete combinedPolygon.attributes.PolygonArea; // area recalculation is not implemented return [combinedPolygon]; } else { const splittedPolygons = []; polygons.forEach(polygon => { const outerRings = polygon.attributes.LineString .filter((ring) => ring.attributes.LineStringType === baseEntities_1.LineStringLineStringTypeEnum.PolygonExterior); if (outerRings.length <= 1) { splittedPolygons.push(polygon); return; } const innerRings = polygon.attributes.LineString .filter((ring) => ring.attributes.LineStringType === baseEntities_1.LineStringLineStringTypeEnum.PolygonInterior); const outerRingIdxs = innerRings.map((ring) => { let maxArea = 0; let bestIdx = -1; outerRings.forEach((outerRing, idx) => { const intersectionRes = polygon_clipping_1.default.intersection([outerRing.toCoordinatesArray()], [ring.toCoordinatesArray()]); if (intersectionRes) { const areaRes = (0, turf_1.area)({ type: 'MultiPolygon', coordinates: intersectionRes }); if (areaRes > maxArea) { maxArea = areaRes; bestIdx = idx; } } }); return bestIdx; }); outerRings.forEach((outerRing, outerIdx) => { const splittedPolygon = new ExtendedPolygon(Object.assign(Object.assign({}, polygon.attributes), { LineString: [ outerRing, ...innerRings.filter((_, innerIdx) => outerRingIdxs[innerIdx] === outerIdx) ] }), isoxmlManager); delete splittedPolygon.attributes.PolygonArea; // area recalculation is not implemented splittedPolygons.push(splittedPolygon); }); }); return splittedPolygons; } } static toGeoJSON(polygons) { if (!polygons || polygons.length === 0) { return null; } const geoJSONCoordinates = []; polygons.forEach(polygon => { const outerRings = polygon.attributes.LineString .filter((ring) => ring.attributes.LineStringType === baseEntities_1.LineStringLineStringTypeEnum.PolygonExterior) .map((ring) => ring.toCoordinatesArray()); const innerRings = polygon.attributes.LineString .filter((ring) => ring.attributes.LineStringType === baseEntities_1.LineStringLineStringTypeEnum.PolygonInterior) .map((ring) => ring.toCoordinatesArray()); if (outerRings.length === 0) { return; } else if (outerRings.length === 1) { geoJSONCoordinates.push([ outerRings[0], ...innerRings ]); return; } const outerRingIdxs = innerRings.map((ring) => { let maxArea = 0; let bestIdx = -1; outerRings.forEach((outerRing, idx) => { const intersectionRes = polygon_clipping_1.default.intersection([outerRing], [ring]); if (intersectionRes) { const areaRes = (0, turf_1.area)({ type: 'MultiPolygon', coordinates: intersectionRes }); if (areaRes > maxArea) { maxArea = areaRes; bestIdx = idx; } } }); return bestIdx; }); outerRings.forEach((outerRing, outerIdx) => { geoJSONCoordinates.push([ outerRing, ...innerRings.filter((_, innerIdx) => outerRingIdxs[innerIdx] === outerIdx) ]); }); }); const geoJSON = { type: 'MultiPolygon', coordinates: geoJSONCoordinates }; geoJSON.bbox = (0, turf_1.bbox)(geoJSON); return geoJSON; } } exports.ExtendedPolygon = ExtendedPolygon; (0, classRegistry_1.registerEntityClass)('main', constants_1.TAGS.Polygon, ExtendedPolygon);