UNPKG

4.02 kBJavaScriptView Raw
1import { shallowcopy } from '../util.js'
2import { COVJSON_DATATYPE_TUPLE, COVERAGE, DOMAIN } from '../constants.js'
3import { getHorizontalCRSReferenceObject, getProjection } from '../domain/referencing.js'
4
5/**
6 * Reproject a coverage.
7 *
8 * Reprojecting means returning a new coverage where the horizontal CRS is replaced
9 * and the horizontal domain coordinates are reprojected.
10 *
11 * Current limitations:
12 * - only point-type coverage domains are supported (Tuple only)
13 * - only horizontal CRSs (2-dimensional) are supported
14 * - non-lat/lon CRSs have to be pre-cached with loadProjection()
15 *
16 * @param {Coverage} cov The Coverage object to reproject.
17 * @param {Domain} refDomain The reference domain from which the horizontal CRS is used.
18 * @returns {Promise<Coverage>} A promise with the reprojected Coverage object as result.
19 */
20export function reproject (cov, refDomain) {
21 return cov.loadDomain().then(sourceDomain => {
22 let sourceRef = getHorizontalCRSReferenceObject(sourceDomain)
23 if (sourceRef.coordinates.length > 2) {
24 throw new Error('Reprojection not supported for >2D CRSs')
25 }
26 // check that the CRS coordinate IDs don't refer to grid axes
27 if (sourceRef.coordinates.some(sourceDomain.axes.has)) {
28 throw new Error('Grid reprojection not supported yet')
29 }
30 let [xComp, yComp] = sourceRef.coordinates
31
32 // TODO reproject bounds
33
34 // find the composite axis that contains the horizontal coordinates
35 let axes = [...sourceDomain.axes.values()]
36 let axis = axes.find(axis => sourceRef.coordinates.every(comp => axis.coordinates.indexOf(comp) !== -1))
37 let [xCompIdx, yCompIdx] = [axis.coordinates.indexOf(xComp), axis.coordinates.indexOf(yComp)]
38
39 // find the target CRS and get the projection
40 let sourceProjection = getProjection(sourceDomain)
41 let targetProjection = getProjection(refDomain)
42
43 // reproject the x/y part of every axis value
44 // this is done by unprojecting to lon/lat, followed by projecting to the target x/y
45 let values
46 if (axis.dataType === COVJSON_DATATYPE_TUPLE) {
47 // make a deep copy of the axis values and replace x,y values by the reprojected ones
48 values = axis.values.map(tuple => tuple.slice())
49 for (let tuple of values) {
50 let [sourceX, sourceY] = [tuple[xCompIdx], tuple[yCompIdx]]
51 let latlon = sourceProjection.unproject({x: sourceX, y: sourceY})
52 let {x, y} = targetProjection.project(latlon)
53 tuple[xCompIdx] = x
54 tuple[yCompIdx] = y
55 }
56 } else {
57 throw new Error('Unsupported data type: ' + axis.dataType)
58 }
59
60 // assemble reprojected coverage
61 let newAxes = new Map(sourceDomain.axes)
62 let newAxis = shallowcopy(axis)
63 delete newAxis.bounds
64 newAxis.values = values
65 newAxes.set(axis.key, newAxis)
66
67 let targetRef = getHorizontalCRSReferenceObject(refDomain)
68 if (targetRef.coordinates.length > 2) {
69 throw new Error('Reprojection not supported for >2D CRSs')
70 }
71 let newReferencing = sourceDomain.referencing.map(ref => {
72 if (ref === sourceRef) {
73 return {
74 coordinates: sourceRef.coordinates,
75 system: targetRef.system
76 }
77 } else {
78 return ref
79 }
80 })
81
82 let newDomain = {
83 type: DOMAIN,
84 domainType: sourceDomain.domainType,
85 axes: newAxes,
86 referencing: newReferencing
87 }
88
89 let newCoverage = {
90 type: COVERAGE,
91 domainType: cov.domainType,
92 parameters: cov.parameters,
93 loadDomain: () => Promise.resolve(newDomain),
94 loadRange: paramKey => cov.loadRange(paramKey),
95 loadRanges: paramKeys => cov.loadRanges(paramKeys),
96 subsetByIndex: constraints => cov.subsetByIndex(constraints).then(sub => reproject(sub, refDomain)),
97 subsetByValue: constraints => cov.subsetByValue(constraints).then(sub => reproject(sub, refDomain))
98 }
99 return newCoverage
100 })
101}