UNPKG

3.43 kBJavaScriptView Raw
1import { DOMAIN } from '../constants.js'
2
3/**
4 * After normalization, all constraints are start,stop,step objects.
5 * It holds that stop > start, step > 0, start >= 0, stop >= 1.
6 * For each axis, a constraint exists.
7 */
8export function normalizeIndexSubsetConstraints (domain, constraints) {
9 // check and normalize constraints to simplify code
10 let normalizedConstraints = {}
11 for (let axisName in constraints) {
12 if (!domain.axes.has(axisName)) {
13 // TODO clarify cov behaviour in the JS API spec
14 continue
15 }
16 if (constraints[axisName] === undefined || constraints[axisName] === null) {
17 continue
18 }
19 if (typeof constraints[axisName] === 'number') {
20 let constraint = constraints[axisName]
21 normalizedConstraints[axisName] = {start: constraint, stop: constraint + 1}
22 } else {
23 normalizedConstraints[axisName] = constraints[axisName]
24 }
25
26 let { start = 0, stop = domain.axes.get(axisName).values.length, step = 1 } = normalizedConstraints[axisName]
27 if (step <= 0) {
28 throw new Error(`Invalid constraint for ${axisName}: step=${step} must be > 0`)
29 }
30 if (start >= stop || start < 0) {
31 throw new Error(`Invalid constraint for ${axisName}: stop=${stop} must be > start=${start} and both >= 0`)
32 }
33 normalizedConstraints[axisName] = {start, stop, step}
34 }
35 for (let axisName of domain.axes.keys()) {
36 if (!(axisName in normalizedConstraints)) {
37 let len = domain.axes.get(axisName).values.length
38 normalizedConstraints[axisName] = {start: 0, stop: len, step: 1}
39 }
40 }
41 return normalizedConstraints
42}
43
44export function subsetDomainByIndex (domain, constraints) {
45 constraints = normalizeIndexSubsetConstraints(domain, constraints)
46
47 // subset the axis arrays of the domain (immediately + cached)
48 let newdomain = {
49 type: DOMAIN,
50 domainType: domain.domainType,
51 axes: new Map(domain.axes),
52 referencing: domain.referencing
53 }
54
55 for (let axisName of Object.keys(constraints)) {
56 let axis = domain.axes.get(axisName)
57 let coords = axis.values
58 let bounds = axis.bounds
59 let constraint = constraints[axisName]
60 let newcoords
61 let newbounds
62
63 let {start, stop, step} = constraint
64 if (start === 0 && stop === coords.length && step === 1) {
65 newcoords = coords
66 newbounds = bounds
67 } else if (step === 1) {
68 // TypedArray has subarray which creates a view, while Array has slice which makes a copy
69 if (coords.subarray) {
70 newcoords = coords.subarray(start, stop)
71 } else {
72 newcoords = coords.slice(start, stop)
73 }
74 if (bounds) {
75 newbounds = {
76 get: i => bounds.get(start + i)
77 }
78 }
79 } else {
80 let q = Math.trunc((stop - start) / step)
81 let r = (stop - start) % step
82 let len = q + r
83 newcoords = new coords.constructor(len) // array or typed array
84 for (let i = start, j = 0; i < stop; i += step, j++) {
85 newcoords[j] = coords[i]
86 }
87 if (bounds) {
88 newbounds = {
89 get: i => bounds.get(start + i * step)
90 }
91 }
92 }
93
94 let newaxis = {
95 dataType: axis.dataType,
96 coordinates: axis.coordinates,
97 values: newcoords,
98 bounds: newbounds
99 }
100 newdomain.axes.set(axisName, newaxis)
101 }
102
103 return newdomain
104}