UNPKG

13.6 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
8
9var _LongitudeAxisIndex;
10
11exports.getHorizontalCRSReferenceObject = getHorizontalCRSReferenceObject;
12exports.isEllipsoidalCRS = isEllipsoidalCRS;
13exports.getProjection = getProjection;
14exports.reproject = reproject;
15exports.getLongitudeWrapper = getLongitudeWrapper;
16exports.isLongitudeAxis = isLongitudeAxis;
17exports.isISODateAxis = isISODateAxis;
18exports.asTime = asTime;
19
20var _constants = require('./constants.js');
21
22function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
23
24function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
25
26var OPENGIS_CRS_PREFIX = 'http://www.opengis.net/def/crs/';
27
28/** 3D WGS84 in lat-lon-height order */
29var EPSG4979 = OPENGIS_CRS_PREFIX + 'EPSG/0/4979';
30
31/** 2D WGS84 in lat-lon order */
32var EPSG4326 = OPENGIS_CRS_PREFIX + 'EPSG/0/4326';
33
34/** 2D WGS84 in lon-lat order */
35var CRS84 = OPENGIS_CRS_PREFIX + 'OGC/1.3/CRS84';
36
37/** CRSs in which position is specified by geodetic latitude and longitude */
38var EllipsoidalCRSs = [EPSG4979, EPSG4326, CRS84];
39
40/** Position of longitude axis */
41var LongitudeAxisIndex = (_LongitudeAxisIndex = {}, _defineProperty(_LongitudeAxisIndex, EPSG4979, 1), _defineProperty(_LongitudeAxisIndex, EPSG4326, 1), _defineProperty(_LongitudeAxisIndex, CRS84, 0), _LongitudeAxisIndex);
42
43/**
44 * Return the reference system connection object for the given domain component,
45 * or undefined if none exists.
46 */
47function getReferenceObject(domain, component) {
48 var ref = domain.referencing.find(function (ref) {
49 return ref.components.indexOf(component) !== -1;
50 });
51 return ref;
52}
53
54/**
55 * Return the reference system connection object of the horizontal CRS of the domain,
56 * or ``undefined`` if none found.
57 * A horizontal CRS is either geodetic (typically ellipsoidal, meaning lat/lon)
58 * or projected and has exactly two axes.
59 */
60function getHorizontalCRSReferenceObject(domain) {
61 var isHorizontal = function isHorizontal(ref) {
62 return ['GeodeticCRS', 'ProjectedCRS'].indexOf(ref.system.type) !== -1 && ref.components.length === 2;
63 };
64 var ref = domain.referencing.find(isHorizontal);
65 return ref;
66}
67
68/**
69 * Return whether the reference system is a CRS in which
70 * horizontal position is specified by geodetic latitude and longitude.
71 */
72function isEllipsoidalCRS(rs) {
73 // TODO should support unknown CRSs with embedded axis information
74 // this also covers the case when there is no ID property
75 return EllipsoidalCRSs.indexOf(rs.id) !== -1;
76}
77
78/**
79 * Return a projection object based on the CRS found in the coverage domain.
80 * If no CRS is found or it is unsupported, then ``undefined`` is returned.
81 *
82 * A projection converts between geodetic lat/lon and projected x/y values.
83 *
84 * For lat/lon CRSs the projection is defined such that an input lat/lon
85 * position gets projected/wrapped to the longitude range used in the domain, for example
86 * [0,360]. The purpose of this is to make intercomparison between different coverages easier.
87 *
88 * The following limitations currently apply:
89 * - only ellipsoidal CRSs are supported (lat/lon)
90 * - only primitive axes and Tuple/Polygon composite axes are supported
91 *
92 * @param {Domain} domain A coverage domain object.
93 * @return {IProjection} A stripped-down leaflet IProjection object.
94 */
95function getProjection(domain) {
96 var ref = domain.referencing.find(function (ref) {
97 return isEllipsoidalCRS(ref.system);
98 });
99 if (!ref) {
100 // either no CRS found or not ellipsoidal
101 return;
102 }
103
104 var lonIdx = LongitudeAxisIndex[ref.system.id];
105 if (lonIdx > 1) {
106 // this should never happen as longitude is always the first or second axis
107 throw new Error();
108 }
109
110 var lonComponent = ref.components[lonIdx];
111
112 // we find the min and max longitude occuring in the domain by inspecting the axis values
113 // Note: this is inefficient for big composite axes.
114 // In that case, something like a domain extent might help which has the min/max values for each component.
115 // TODO handle bounds
116 var lonMin = void 0,
117 lonMax = void 0;
118 if (domain.axes.has(lonComponent)) {
119 // longitude is a grid axis
120 var lonAxisName = lonComponent;
121 var lonAxisVals = domain.axes.get(lonAxisName).values;
122 lonMin = lonAxisVals[0];
123 lonMax = lonAxisVals[lonAxisVals.length - 1];
124 if (lonMin > lonMax) {
125 var _ref = [lonMax, lonMin];
126 lonMin = _ref[0];
127 lonMax = _ref[1];
128 }
129 } else {
130 // TODO there should be no dependency to CovJSON
131
132 // longitude is not a primitive grid axis but a component of a composite axis
133
134 // find the composite axis containing the longitude component
135 var axes = [].concat(_toConsumableArray(domain.axes.values()));
136 var axis = axes.find(function (axis) {
137 return axis.components.indexOf(lonComponent) !== -1;
138 });
139 var lonCompIdx = axis.components.indexOf(lonComponent);
140
141 // scan the composite axis for min/max longitude values
142 lonMin = Infinity;
143 lonMax = -Infinity;
144 if (axis.dataType === _constants.COVJSON_DATATYPE_TUPLE) {
145 var _iteratorNormalCompletion = true;
146 var _didIteratorError = false;
147 var _iteratorError = undefined;
148
149 try {
150 for (var _iterator = axis.values[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
151 var tuple = _step.value;
152
153 var lon = tuple[lonCompIdx];
154 lonMin = Math.min(lon, lonMin);
155 lonMax = Math.max(lon, lonMax);
156 }
157 } catch (err) {
158 _didIteratorError = true;
159 _iteratorError = err;
160 } finally {
161 try {
162 if (!_iteratorNormalCompletion && _iterator.return) {
163 _iterator.return();
164 }
165 } finally {
166 if (_didIteratorError) {
167 throw _iteratorError;
168 }
169 }
170 }
171 } else if (axis.dataType === _constants.COVJSON_DATATYPE_POLYGON) {
172 var _iteratorNormalCompletion2 = true;
173 var _didIteratorError2 = false;
174 var _iteratorError2 = undefined;
175
176 try {
177 for (var _iterator2 = axis.values[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
178 var poly = _step2.value;
179 var _iteratorNormalCompletion3 = true;
180 var _didIteratorError3 = false;
181 var _iteratorError3 = undefined;
182
183 try {
184 for (var _iterator3 = poly[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
185 var ring = _step3.value;
186 var _iteratorNormalCompletion4 = true;
187 var _didIteratorError4 = false;
188 var _iteratorError4 = undefined;
189
190 try {
191 for (var _iterator4 = ring[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
192 var point = _step4.value;
193
194 var _lon = point[lonCompIdx];
195 lonMin = Math.min(_lon, lonMin);
196 lonMax = Math.max(_lon, lonMax);
197 }
198 } catch (err) {
199 _didIteratorError4 = true;
200 _iteratorError4 = err;
201 } finally {
202 try {
203 if (!_iteratorNormalCompletion4 && _iterator4.return) {
204 _iterator4.return();
205 }
206 } finally {
207 if (_didIteratorError4) {
208 throw _iteratorError4;
209 }
210 }
211 }
212 }
213 } catch (err) {
214 _didIteratorError3 = true;
215 _iteratorError3 = err;
216 } finally {
217 try {
218 if (!_iteratorNormalCompletion3 && _iterator3.return) {
219 _iterator3.return();
220 }
221 } finally {
222 if (_didIteratorError3) {
223 throw _iteratorError3;
224 }
225 }
226 }
227 }
228 } catch (err) {
229 _didIteratorError2 = true;
230 _iteratorError2 = err;
231 } finally {
232 try {
233 if (!_iteratorNormalCompletion2 && _iterator2.return) {
234 _iterator2.return();
235 }
236 } finally {
237 if (_didIteratorError2) {
238 throw _iteratorError2;
239 }
240 }
241 }
242 } else {
243 throw new Error('Unsupported data type: ' + axis.dataType);
244 }
245 }
246
247 var lonMid = (lonMax + lonMin) / 2;
248 var lonMinExtended = lonMid - 180;
249 var lonMaxExtended = lonMid + 180;
250
251 return {
252 project: function project(_ref2) {
253 var lon = _ref2.lon;
254 var lat = _ref2.lat;
255
256 var lonProjected = void 0;
257 if (lonMinExtended <= lon && lon <= lonMaxExtended) {
258 // use unchanged to avoid introducing rounding errors
259 lonProjected = lon;
260 } else {
261 lonProjected = ((lon - lonMinExtended) % 360 + 360) % 360 + lonMinExtended;
262 }
263
264 var _ref3 = lonIdx === 0 ? [lonProjected, lat] : [lat, lonProjected];
265
266 var _ref4 = _slicedToArray(_ref3, 2);
267
268 var x = _ref4[0];
269 var y = _ref4[1];
270
271 return { x: x, y: y };
272 },
273 unproject: function unproject(_ref5) {
274 var x = _ref5.x;
275 var y = _ref5.y;
276
277 var _ref6 = lonIdx === 0 ? [x, y] : [y, x];
278
279 var _ref7 = _slicedToArray(_ref6, 2);
280
281 var lon = _ref7[0];
282 var lat = _ref7[1];
283
284 return { lon: lon, lat: lat };
285 }
286 };
287}
288
289/**
290 * Reprojects coordinates from one projection to another.
291 */
292function reproject(pos, fromProjection, toProjection) {
293 return toProjection.project(fromProjection.unproject(pos));
294}
295
296/**
297 * Returns a function which converts an arbitrary longitude to the
298 * longitude extent used in the coverage domain.
299 * This only supports primitive axes since this is what subsetByValue supports.
300 * The longitude extent is extended to 360 degrees if the actual extent is smaller.
301 * The extension is done equally on both sides of the extent.
302 *
303 * For example, the domain may have longitudes within [0,360].
304 * An input longitude of -70 is converted to 290.
305 * All longitudes within [0,360] are returned unchanged.
306 *
307 * If the domain has longitudes within [10,50] then the
308 * extended longitude range is [-150,210] (-+180 from the middle point).
309 * An input longitude of -170 is converted to 190.
310 * All longitudes within [-150,210] are returned unchanged.
311 *
312 * @ignore
313 */
314function getLongitudeWrapper(domain, axisName) {
315 // TODO deprecate this in favour of getProjection, check leaflet-coverage
316
317 // for primitive axes, the axis identifier = component identifier
318 if (!isLongitudeAxis(domain, axisName)) {
319 throw new Error('\'' + axisName + '\' is not a longitude axis');
320 }
321
322 var vals = domain.axes.get(axisName).values;
323 var lon_min = vals[0];
324 var lon_max = vals[vals.length - 1];
325 if (lon_min > lon_max) {
326 var _ref8 = [lon_max, lon_min];
327 lon_min = _ref8[0];
328 lon_max = _ref8[1];
329 }
330
331 var x_mid = (lon_max + lon_min) / 2;
332 var x_min = x_mid - 180;
333 var x_max = x_mid + 180;
334
335 return function (lon) {
336 if (x_min <= lon && lon <= x_max) {
337 // directly return to avoid introducing rounding errors
338 return lon;
339 } else {
340 return ((lon - x_min) % 360 + 360) % 360 + x_min;
341 }
342 };
343}
344
345/**
346 * Return whether the given domain axis represents longitudes.
347 *
348 * @ignore
349 */
350function isLongitudeAxis(domain, axisName) {
351 var ref = getReferenceObject(domain, axisName);
352 if (!ref) {
353 return false;
354 }
355
356 var crsId = ref.system.id;
357 // TODO should support unknown CRSs with embedded axis information
358 if (EllipsoidalCRSs.indexOf(crsId) === -1) {
359 // this also covers the case when there is no ID property
360 return false;
361 }
362
363 var compIdx = ref.components.indexOf(axisName);
364 var isLongitude = LongitudeAxisIndex[crsId] === compIdx;
365 return isLongitude;
366}
367
368/**
369 * Returns true if the given axis has ISO8601 date strings
370 * as axis values.
371 */
372function isISODateAxis(domain, axisName) {
373 var val = domain.axes.get(axisName).values[0];
374 if (typeof val !== 'string') {
375 return false;
376 }
377 return !isNaN(new Date(val).getTime());
378}
379
380function asTime(inp) {
381 var res = void 0;
382 var err = false;
383 if (typeof inp === 'string') {
384 res = new Date(inp).getTime();
385 } else if (inp instanceof Date) {
386 res = inp.getTime();
387 } else {
388 err = true;
389 }
390 if (isNaN(res)) {
391 err = true;
392 }
393 if (err) {
394 throw new Error('Invalid date: ' + inp);
395 }
396 return res;
397}
\No newline at end of file