UNPKG

itowns

Version:

A JS/WebGL framework for 3D geospatial data visualization

457 lines (402 loc) 14.7 kB
"use strict"; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.FeatureCollection = exports["default"] = exports.FEATURE_TYPES = exports.FeatureGeometry = void 0; var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var THREE = _interopRequireWildcard(require("three")); var _Extent = _interopRequireDefault(require("./Geographic/Extent")); function defaultExtent(crs) { return new _Extent["default"](crs, Infinity, -Infinity, Infinity, -Infinity); } function _extendBuffer(feature, size) { feature.vertices.length += size * feature.size; if (feature.normals) { feature.normals.length = feature.vertices.length; } } var defaultNormal = new THREE.Vector3(0, 0, 1); /** * @property {Extent} extent - The 2D extent containing all the points * composing the geometry. * @property {Object[]} indices - Contains the indices that define the geometry. * Objects stored in this array have two properties, an `offset` and a `count`. * The offset is related to the overall number of vertices in the Feature. * * @property {Object} properties - Properties of the geometry. It can be * anything specified in the GeoJSON under the `properties` property. */ var FeatureGeometry = /*#__PURE__*/ function () { /** * @param {Feature} feature geometry */ function FeatureGeometry(feature) { (0, _classCallCheck2["default"])(this, FeatureGeometry); this.extent = feature.extent ? defaultExtent(feature.crs) : undefined; this.indices = []; this._feature = feature; this.properties = {}; this._currentExtent = feature.extent ? defaultExtent(feature.crs) : undefined; } /** * Add a new marker to indicate the starting of sub geometry and extends the vertices buffer. * Then you have to push new the coordinates of sub geometry. * The sub geometry stored in indices, see constructor for more information. * @param {number} count count of vertices */ (0, _createClass2["default"])(FeatureGeometry, [{ key: "startSubGeometry", value: function startSubGeometry(count) { var last = this.indices.length - 1; var extent = this.extent ? defaultExtent(this._feature.crs) : undefined; var offset = last > -1 ? this.indices[last].offset + this.indices[last].count : this._feature.vertices.length / this.size; this.indices.push({ offset: offset, count: count, extent: extent }); this._currentExtent = extent; _extendBuffer(this._feature, count); } /** * After you have pushed new the coordinates of sub geometry without * `startSubGeometry`, this function close sub geometry. The sub geometry * stored in indices, see constructor for more information. * @param {number} count count of vertices */ }, { key: "closeSubGeometry", value: function closeSubGeometry(count) { var last = this.indices.length - 1; var offset = last > -1 ? this.indices[last].offset + this.indices[last].count : this._feature.vertices.length / this.size - count; this.indices.push({ offset: offset, count: count, extent: this._currentExtent }); if (this.extent) { this.extent.union(this._currentExtent); this._currentExtent = defaultExtent(this._feature.crs); } } }, { key: "getLastSubGeometry", value: function getLastSubGeometry() { var last = this.indices.length - 1; return this.indices[last]; } /** * Push new coordinates in vertices buffer. * @param {Coordinates} coord The coordinates to push. */ }, { key: "pushCoordinates", value: function pushCoordinates(coord) { if (coord.crs !== this._feature.crs) { coord.as(this._feature.crs, coord); } if (this._feature.normals) { coord.geodesicNormal.toArray(this._feature.normals, this._feature._pos); } this._feature._pushValues(this._feature, coord.x, coord.y, coord.z); // expand extent if present if (this._currentExtent) { this._currentExtent.expandByCoordinates(coord); } } /** * Push new values coordinates in vertices buffer. * No geographical conversion is made or the normal doesn't stored. * * @param {number} long The longitude coordinate. * @param {number} lat The latitude coordinate. * @param {number} [alt=0] The altitude coordinate. * @param {THREE.Vector3} [normal=THREE.Vector3(0,0,1)] the normal on coordinates. */ }, { key: "pushCoordinatesValues", value: function pushCoordinatesValues(_long, lat) { var alt = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; var normal = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : defaultNormal; if (this._feature.normals) { normal.toArray(this._feature.normals, this._feature._pos); } this._feature._pushValues(this._feature, _long, lat, alt); // expand extent if present if (this._currentExtent) { this._currentExtent.expandByValuesCoordinates(_long, lat, alt); } } /** * @returns {number} the number of values of the array that should be associated with a coordinates. * The size is 3 with altitude and 2 without altitude. */ }, { key: "updateExtent", /** * update geometry extent with the last sub geometry extent. */ value: function updateExtent() { if (this.extent) { var last = this.indices[this.indices.length - 1]; if (last) { this.extent.union(last.extent); } } } }, { key: "size", get: function get() { return this._feature.size; } }]); return FeatureGeometry; }(); exports.FeatureGeometry = FeatureGeometry; function push2DValues(feature, value0, value1) { feature.vertices[feature._pos++] = value0; feature.vertices[feature._pos++] = value1; } function push3DValues(feature, value0, value1) { var value2 = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; feature.vertices[feature._pos++] = value0; feature.vertices[feature._pos++] = value1; feature.vertices[feature._pos++] = value2; } var FEATURE_TYPES = { POINT: 0, LINE: 1, POLYGON: 2 }; /** * * This class improves and simplifies the construction and conversion of geographic data structures. * It's an intermediary structure between geomatic formats and THREE objects. * * @property {string} type - Geometry type, can be `point`, `line`, or * `polygon`. * @property {number[]} vertices - All the vertices of the Feature. * @property {number[]} normals - All the normals of the Feature. * @property {number} size - the number of values of the array that should be associated with a coordinates. * The size is 3 with altitude and 2 without altitude. * @property {string} crs - Geographic or Geocentric coordinates system. * @property {Array.<FeatureGeometry>} geometry - The feature's geometry. * @property {Extent?} extent - The extent containing all the geometries * composing the feature. */ exports.FEATURE_TYPES = FEATURE_TYPES; var Feature = /*#__PURE__*/ function () { /** * * @param {string} type type of Feature. It can be 'point', 'line' or 'polygon'. * @param {string} crs Geographic or Geocentric coordinates system. * @param {Object} [options={}] options to build feature. * @param {boolean} [options.buildExtent] Build extent and update when adding new vertice. * @param {boolean} [options.withAltitude] Set vertice altitude when adding new vertice. * @param {boolean} [options.withNormal] Set vertice normal when adding new vertice. */ function Feature(type, crs) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; (0, _classCallCheck2["default"])(this, Feature); if (Object.keys(FEATURE_TYPES).find(function (t) { return FEATURE_TYPES[t] === type; })) { this.type = type; } else { throw new Error("Unsupported Feature type: ".concat(type)); } this.geometry = []; this.vertices = []; this.normals = options.withNormal ? [] : undefined; this.crs = crs; this.size = options.withAltitude ? 3 : 2; this.extent = options.buildExtent ? defaultExtent(crs) : undefined; this._pos = 0; this._pushValues = this.size === 3 ? push3DValues : push2DValues; } /** * Instance a new {@link FeatureGeometry} and push in {@link Feature}. * @returns {FeatureGeometry} the instancied geometry. */ (0, _createClass2["default"])(Feature, [{ key: "bindNewGeometry", value: function bindNewGeometry() { var geometry = new FeatureGeometry(this); this.geometry.push(geometry); return geometry; } /** * Update {@link Extent} feature with {@link Extent} geometry * @param {FeatureGeometry} geometry used to update Feature {@link Extent} */ }, { key: "updateExtent", value: function updateExtent(geometry) { if (this.extent) { this.extent.union(geometry.extent); } } /** * @returns {number} the count of geometry. */ }, { key: "geometryCount", get: function get() { return this.geometry.length; } }]); return Feature; }(); var _default = Feature; /** * @property {Feature[]} features - The array of features composing the * collection. * @property {Extent?} extent - The 2D extent containing all the features * composing the collection. * @property {string} crs - Geographic or Geocentric coordinates system. * @property {boolean} isFeatureCollection - Used to check whether this is FeatureCollection. * @property {THREE.Vector3} translation - Apply translation on vertices and extent to transform on coordinates system. * @property {THREE.Vector3} scale - Apply scale on vertices and extent to transform on coordinates system. * * An object regrouping a list of [features]{@link Feature} and the extent of this collection. */ exports["default"] = _default; var FeatureCollection = /*#__PURE__*/ function () { function FeatureCollection(crs, options) { (0, _classCallCheck2["default"])(this, FeatureCollection); this.isFeatureCollection = true; this.crs = crs; this.features = []; this.optionsFeature = options || {}; this.extent = this.optionsFeature.buildExtent ? defaultExtent(crs) : undefined; this.translation = new THREE.Vector3(); this.scale = new THREE.Vector3(1, 1, 1); } /** * Update FeatureCollection extent with `extent` or all features extent if * `extent` is `undefined`. * @param {Extent} extent */ (0, _createClass2["default"])(FeatureCollection, [{ key: "updateExtent", value: function updateExtent(extent) { if (this.extent) { var extents = extent ? [extent] : this.features.map(function (feature) { return feature.extent; }); var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = extents[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var ext = _step.value; this.extent.union(ext); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator["return"] != null) { _iterator["return"](); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } } /** * Remove features that don't have [FeatureGeometry]{@link FeatureGeometry}. */ }, { key: "removeEmptyFeature", value: function removeEmptyFeature() { this.features = this.features.filter(function (feature) { return feature.geometry.length; }); } /** * Push the `feature` in FeatureCollection. * @param {Feature} feature */ }, { key: "pushFeature", value: function pushFeature(feature) { this.features.push(feature); this.updateExtent(feature.extent); } }, { key: "requestFeature", value: function requestFeature(type, callback) { var feature = this.features.find(callback); if (feature && this.optionsFeature.mergeFeatures) { return feature; } else { var newFeature = new Feature(type, this.crs, this.optionsFeature); this.features.push(newFeature); return newFeature; } } /** * Returns the Feature by type if `mergeFeatures` is `true` or returns the * new instance of typed Feature. * * @param {string} type the type requested * @returns {Feature} */ }, { key: "requestFeatureByType", value: function requestFeatureByType(type) { return this.requestFeature(type, function (feature) { return feature.type === type; }); } /** * Returns the Feature by type if `mergeFeatures` is `true` or returns the * new instance of typed Feature. * * @param {string} id the id requested * @param {string} type the type requested * @returns {Feature} */ }, { key: "requestFeatureById", value: function requestFeatureById(id, type) { return this.requestFeature(type, function (feature) { return feature.id === id; }); } /** * Add a new feature with references to all properties. * It allows to have features with different styles * without having to duplicate the geometry. * @param {Feature} feature The feature to reference. * @return {Feature} The new referenced feature */ }, { key: "newFeatureByReference", value: function newFeatureByReference(feature) { var ref = new Feature(feature.type, this.crs, this.optionsFeature); ref.extent = feature.extent; ref.geometry = feature.geometry; ref.normals = feature.normals; ref.size = feature.size; ref.vertices = feature.vertices; ref._pos = feature._pos; this.features.push(ref); return ref; } }]); return FeatureCollection; }(); exports.FeatureCollection = FeatureCollection;