itowns
Version:
A JS/WebGL framework for 3D geospatial data visualization
457 lines (402 loc) • 14.7 kB
JavaScript
"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;