UNPKG

15.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
9exports.normalizeIndexSubsetConstraints = normalizeIndexSubsetConstraints;
10exports.subsetDomainByIndex = subsetDomainByIndex;
11exports.subsetCoverageByIndex = subsetCoverageByIndex;
12exports.subsetCoverageByValue = subsetCoverageByValue;
13
14var _referencing = require('./referencing.js');
15
16var _array = require('./array.js');
17
18var _constants = require('./constants.js');
19
20function _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); } }
21
22/**
23 * After normalization, all constraints are start,stop,step objects.
24 * It holds that stop > start, step > 0, start >= 0, stop >= 1.
25 * For each axis, a constraint exists.
26 */
27function normalizeIndexSubsetConstraints(domain, constraints) {
28 // check and normalize constraints to simplify code
29 var normalizedConstraints = {};
30 for (var axisName in constraints) {
31 if (!domain.axes.has(axisName)) {
32 // TODO clarify cov behaviour in the JS API spec
33 continue;
34 }
35 if (constraints[axisName] === undefined || constraints[axisName] === null) {
36 continue;
37 }
38 if (typeof constraints[axisName] === 'number') {
39 var constraint = constraints[axisName];
40 normalizedConstraints[axisName] = { start: constraint, stop: constraint + 1 };
41 } else {
42 normalizedConstraints[axisName] = constraints[axisName];
43 }
44
45 var _normalizedConstraint = normalizedConstraints[axisName];
46 var _normalizedConstraint2 = _normalizedConstraint.start;
47 var start = _normalizedConstraint2 === undefined ? 0 : _normalizedConstraint2;
48 var _normalizedConstraint3 = _normalizedConstraint.stop;
49 var stop = _normalizedConstraint3 === undefined ? domain.axes.get(axisName).values.length : _normalizedConstraint3;
50 var _normalizedConstraint4 = _normalizedConstraint.step;
51 var step = _normalizedConstraint4 === undefined ? 1 : _normalizedConstraint4;
52
53 if (step <= 0) {
54 throw new Error('Invalid constraint for ' + axisName + ': step=' + step + ' must be > 0');
55 }
56 if (start >= stop || start < 0) {
57 throw new Error('Invalid constraint for ' + axisName + ': stop=' + stop + ' must be > start=' + start + ' and both >= 0');
58 }
59 normalizedConstraints[axisName] = { start: start, stop: stop, step: step };
60 }
61 var _iteratorNormalCompletion = true;
62 var _didIteratorError = false;
63 var _iteratorError = undefined;
64
65 try {
66 for (var _iterator = domain.axes.keys()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
67 var _axisName = _step.value;
68
69 if (!(_axisName in normalizedConstraints)) {
70 var len = domain.axes.get(_axisName).values.length;
71 normalizedConstraints[_axisName] = { start: 0, stop: len, step: 1 };
72 }
73 }
74 } catch (err) {
75 _didIteratorError = true;
76 _iteratorError = err;
77 } finally {
78 try {
79 if (!_iteratorNormalCompletion && _iterator.return) {
80 _iterator.return();
81 }
82 } finally {
83 if (_didIteratorError) {
84 throw _iteratorError;
85 }
86 }
87 }
88
89 return normalizedConstraints;
90}
91
92function subsetDomainByIndex(domain, constraints) {
93 constraints = normalizeIndexSubsetConstraints(domain, constraints);
94
95 // subset the axis arrays of the domain (immediately + cached)
96 var newdomain = {
97 type: _constants.DOMAIN,
98 // TODO remove profiles in favour of domainType at some point
99 // TODO are the profiles still valid?
100 profiles: domain.profiles,
101 domainType: domain.domainType,
102 axes: new Map(domain.axes),
103 referencing: domain.referencing
104 };
105
106 var _iteratorNormalCompletion2 = true;
107 var _didIteratorError2 = false;
108 var _iteratorError2 = undefined;
109
110 try {
111 var _loop = function _loop() {
112 var axisName = _step2.value;
113
114 var axis = domain.axes.get(axisName);
115 var coords = axis.values;
116 var bounds = axis.bounds;
117 var constraint = constraints[axisName];
118 var newcoords = void 0;
119 var newbounds = void 0;
120
121 var start = constraint.start;
122 var stop = constraint.stop;
123 var step = constraint.step;
124
125 if (start === 0 && stop === coords.length && step === 1) {
126 newcoords = coords;
127 newbounds = bounds;
128 } else if (step === 1) {
129 // TypedArray has subarray which creates a view, while Array has slice which makes a copy
130 if (coords.subarray) {
131 newcoords = coords.subarray(start, stop);
132 } else {
133 newcoords = coords.slice(start, stop);
134 }
135 if (bounds) {
136 newbounds = {
137 get: function get(i) {
138 return bounds.get(start + i);
139 }
140 };
141 }
142 } else {
143 var q = Math.trunc((stop - start) / step);
144 var r = (stop - start) % step;
145 var len = q + r;
146 newcoords = new coords.constructor(len); // array or typed array
147 for (var i = start, j = 0; i < stop; i += step, j++) {
148 newcoords[j] = coords[i];
149 }
150 if (bounds) {
151 newbounds = {
152 get: function get(i) {
153 return bounds.get(start + i * step);
154 }
155 };
156 }
157 }
158
159 var newaxis = {
160 dataType: axis.dataType,
161 components: axis.components,
162 values: newcoords,
163 bounds: newbounds
164 };
165 newdomain.axes.set(axisName, newaxis);
166 };
167
168 for (var _iterator2 = Object.keys(constraints)[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
169 _loop();
170 }
171 } catch (err) {
172 _didIteratorError2 = true;
173 _iteratorError2 = err;
174 } finally {
175 try {
176 if (!_iteratorNormalCompletion2 && _iterator2.return) {
177 _iterator2.return();
178 }
179 } finally {
180 if (_didIteratorError2) {
181 throw _iteratorError2;
182 }
183 }
184 }
185
186 return newdomain;
187}
188
189/**
190 * Generic subsetByIndex function that can be used when building new Coverage objects.
191 *
192 * @example
193 * var cov = {
194 * type: 'Coverage',
195 * ...
196 * subsetByIndex: constraints => subsetCoverageByIndex(cov, constraints)
197 * }
198 */
199function subsetCoverageByIndex(cov, constraints) {
200 return cov.loadDomain().then(function (domain) {
201 constraints = normalizeIndexSubsetConstraints(domain, constraints);
202 var newdomain = subsetDomainByIndex(domain, constraints);
203
204 // subset ranges (on request)
205 var rangeWrapper = function rangeWrapper(range) {
206 var newrange = {
207 dataType: range.dataType,
208 get: function get(obj) {
209 // translate subsetted to original indices
210 var newobj = {};
211 var _iteratorNormalCompletion3 = true;
212 var _didIteratorError3 = false;
213 var _iteratorError3 = undefined;
214
215 try {
216 for (var _iterator3 = Object.keys(obj)[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
217 var axisName = _step3.value;
218 var _constraints$axisName = constraints[axisName];
219 var _start = _constraints$axisName.start;
220 var _step4 = _constraints$axisName.step;
221
222 newobj[axisName] = _start + obj[axisName] * _step4;
223 }
224 } catch (err) {
225 _didIteratorError3 = true;
226 _iteratorError3 = err;
227 } finally {
228 try {
229 if (!_iteratorNormalCompletion3 && _iterator3.return) {
230 _iterator3.return();
231 }
232 } finally {
233 if (_didIteratorError3) {
234 throw _iteratorError3;
235 }
236 }
237 }
238
239 return range.get(newobj);
240 }
241 };
242 newrange.shape = new Map();
243 var _iteratorNormalCompletion4 = true;
244 var _didIteratorError4 = false;
245 var _iteratorError4 = undefined;
246
247 try {
248 for (var _iterator4 = domain.axes.keys()[Symbol.iterator](), _step5; !(_iteratorNormalCompletion4 = (_step5 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
249 var axisName = _step5.value;
250
251 var size = newdomain.axes.get(axisName).values.length;
252 newrange.shape.set(axisName, size);
253 }
254 } catch (err) {
255 _didIteratorError4 = true;
256 _iteratorError4 = err;
257 } finally {
258 try {
259 if (!_iteratorNormalCompletion4 && _iterator4.return) {
260 _iterator4.return();
261 }
262 } finally {
263 if (_didIteratorError4) {
264 throw _iteratorError4;
265 }
266 }
267 }
268
269 return newrange;
270 };
271
272 var loadRange = function loadRange(key) {
273 return cov.loadRange(key).then(rangeWrapper);
274 };
275
276 var loadRanges = function loadRanges(keys) {
277 return cov.loadRanges(keys).then(function (ranges) {
278 return new Map([].concat(_toConsumableArray(ranges)).map(function (_ref) {
279 var _ref2 = _slicedToArray(_ref, 2);
280
281 var key = _ref2[0];
282 var range = _ref2[1];
283 return [key, rangeWrapper(range)];
284 }));
285 });
286 };
287
288 // assemble everything to a new coverage
289 var newcov = {
290 type: _constants.COVERAGE,
291 // TODO are the profiles still valid?
292 domainProfiles: cov.domainProfiles,
293 domainType: cov.domainType,
294 parameters: cov.parameters,
295 loadDomain: function loadDomain() {
296 return Promise.resolve(newdomain);
297 },
298 loadRange: loadRange,
299 loadRanges: loadRanges
300 };
301 newcov.subsetByIndex = subsetCoverageByIndex.bind(null, newcov);
302 newcov.subsetByValue = subsetCoverageByValue.bind(null, newcov);
303 return newcov;
304 });
305}
306
307/**
308 * Generic subsetByValue function that can be used when building new Coverage objects.
309 * Requires cov.subsetByIndex function.
310 *
311 * @example
312 * var cov = {
313 * type: 'Coverage',
314 * ...
315 * subsetByValue: constraints => subsetCoverageByValue(cov, constraints)
316 * }
317 */
318function subsetCoverageByValue(cov, constraints) {
319 return cov.loadDomain().then(function (domain) {
320 // calculate indices and use subsetByIndex
321 var indexConstraints = {};
322
323 var _iteratorNormalCompletion5 = true;
324 var _didIteratorError5 = false;
325 var _iteratorError5 = undefined;
326
327 try {
328 for (var _iterator5 = Object.keys(constraints)[Symbol.iterator](), _step6; !(_iteratorNormalCompletion5 = (_step6 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
329 var axisName = _step6.value;
330
331 var spec = constraints[axisName];
332 if (spec === undefined || spec === null || !domain.axes.has(axisName)) {
333 continue;
334 }
335 var axis = domain.axes.get(axisName);
336 var vals = axis.values;
337
338 // special-case handling
339 var isISODate = (0, _referencing.isISODateAxis)(domain, axisName);
340 var isLongitude = (0, _referencing.isLongitudeAxis)(domain, axisName);
341
342 // wrap input longitudes into longitude range of domain axis
343 var lonWrapper = isLongitude ? (0, _referencing.getLongitudeWrapper)(domain, axisName) : undefined;
344
345 if (typeof spec === 'number' || typeof spec === 'string' || spec instanceof Date) {
346 var match = spec;
347 if (isISODate) {
348 // convert times to numbers before searching
349 match = (0, _referencing.asTime)(match);
350 vals = vals.map(function (v) {
351 return new Date(v).getTime();
352 });
353 } else if (isLongitude) {
354 match = lonWrapper(match);
355 }
356 var i = void 0;
357 // older browsers don't have TypedArray.prototype.indexOf
358 if (vals.indexOf) {
359 i = vals.indexOf(match);
360 } else {
361 i = Array.prototype.indexOf.call(vals, match);
362 }
363 if (i === -1) {
364 throw new Error('Domain value not found: ' + spec);
365 }
366 indexConstraints[axisName] = i;
367 } else if ('target' in spec) {
368 // find index of value closest to target
369 var target = spec.target;
370 if (isISODate) {
371 // convert times to numbers before searching
372 target = (0, _referencing.asTime)(target);
373 vals = vals.map(function (v) {
374 return new Date(v).getTime();
375 });
376 } else if (isLongitude) {
377 target = lonWrapper(target);
378 } else if (typeof vals[0] !== 'number' || typeof target !== 'number') {
379 throw new Error('Invalid axis or constraint value type');
380 }
381 var _i = (0, _array.indexOfNearest)(vals, target);
382 indexConstraints[axisName] = _i;
383 } else if ('start' in spec && 'stop' in spec) {
384 // TODO what about bounds?
385
386 var _start2 = spec.start;
387 var _stop = spec.stop;
388
389 if (isISODate) {
390 var _ref3 = [(0, _referencing.asTime)(_start2), (0, _referencing.asTime)(_stop)];
391 // convert times to numbers before searching
392
393 _start2 = _ref3[0];
394 _stop = _ref3[1];
395
396 vals = vals.map(function (v) {
397 return new Date(v).getTime();
398 });
399 } else if (isLongitude) {
400 var _ref4 = [lonWrapper(_start2), lonWrapper(_stop)];
401 _start2 = _ref4[0];
402 _stop = _ref4[1];
403 } else if (typeof vals[0] !== 'number' || typeof _start2 !== 'number') {
404 throw new Error('Invalid axis or constraint value type');
405 }
406
407 var _indicesOfNearest = (0, _array.indicesOfNearest)(vals, _start2);
408
409 var _indicesOfNearest2 = _slicedToArray(_indicesOfNearest, 2);
410
411 var lo1 = _indicesOfNearest2[0];
412 var hi1 = _indicesOfNearest2[1];
413
414 var _indicesOfNearest3 = (0, _array.indicesOfNearest)(vals, _stop);
415
416 var _indicesOfNearest4 = _slicedToArray(_indicesOfNearest3, 2);
417
418 var lo2 = _indicesOfNearest4[0];
419 var hi2 = _indicesOfNearest4[1];
420
421 // cov is a bit arbitrary and may include one or two indices too much
422 // (but since we don't handle bounds it doesn't matter that much)
423
424 var imin = Math.min(lo1, hi1, lo2, hi2);
425 var imax = Math.max(lo1, hi1, lo2, hi2) + 1; // subsetByIndex is exclusive
426
427 indexConstraints[axisName] = { start: imin, stop: imax };
428 } else {
429 throw new Error('Invalid subset constraints');
430 }
431 }
432 } catch (err) {
433 _didIteratorError5 = true;
434 _iteratorError5 = err;
435 } finally {
436 try {
437 if (!_iteratorNormalCompletion5 && _iterator5.return) {
438 _iterator5.return();
439 }
440 } finally {
441 if (_didIteratorError5) {
442 throw _iteratorError5;
443 }
444 }
445 }
446
447 return cov.subsetByIndex(indexConstraints);
448 });
449}
\No newline at end of file