@dataforsyningen/saul 3.1.3 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/config.js.example CHANGED
@@ -2,10 +2,11 @@ export default {
2
2
 
3
3
  // STAC TOKEN can be aquired from https://dataforsyningen.dk/
4
4
  API_STAC_TOKEN: "",
5
- API_STAC_BASEURL: "https://api.dataforsyningen.dk/skraafotoapi",
5
+ API_STAC_BASEURL: "https://api.dataforsyningen.dk/skraafoto_api_test/v1.0",
6
6
 
7
7
  // DHM URL and auth can be aquired from https://datafordeler.dk/dataoversigt/danmarks-hoejdemodel-dhm/koter/
8
+ API_DHM_WCS_BASEURL: "https://services.datafordeler.dk/DHMNedboer/dhm_wcs/1.0.0/WCS",
8
9
  API_DHM_BASEURL: "https://services.datafordeler.dk/DHMTerraen/DHMKoter/1.0.0/GEOREST/HentKoter",
9
- API_DHM_USERNAME: "",
10
- API_DHM_PASSWORD: ""
10
+ API_DHM_TOKENA: "", // DHM API service username
11
+ API_DHM_TOKENB: "" // DHM API service password
11
12
  }
package/example.html CHANGED
@@ -17,7 +17,7 @@
17
17
 
18
18
  <script type="module">
19
19
 
20
- // You should add your own config.js with proper tokens, passwords, etc.
20
+ // You should add your own config.js with proper tokens, etc.
21
21
  // Check config.js.example for info on how to set it up
22
22
  import auth from './config.js'
23
23
 
package/index.js CHANGED
@@ -2,9 +2,10 @@
2
2
 
3
3
  export {
4
4
  image2world,
5
- world2image,
5
+ world2image, // Deprecated. Use getImageXY
6
6
  getWorldXYZ,
7
- getZ, // Deprecated. Use getElevation
7
+ getImageXY,
8
+ getZ,
8
9
  iterate // Deprecated. Use getWorldXYZ
9
10
  } from './modules/saul-core.js'
10
11
 
@@ -12,6 +13,7 @@ export {
12
13
  postSTAC,
13
14
  getSTAC,
14
15
  getDHM,
16
+ getTerrainGeoTIFF,
15
17
  get,
16
18
  post
17
19
  } from './modules/api.js'
@@ -22,6 +24,5 @@ export {
22
24
  } from './modules/saul-projection.js'
23
25
 
24
26
  export {
25
- getTerrainGeoTIFF,
26
27
  getElevation
27
28
  } from './modules/saul-elevation.js'
package/modules/api.js CHANGED
@@ -2,6 +2,8 @@
2
2
  * SAUL API utilities
3
3
  */
4
4
 
5
+ import { fromArrayBuffer } from 'geotiff'
6
+
5
7
  let error_msg
6
8
  let load_stack = []
7
9
 
@@ -152,11 +154,11 @@ function post(url, requestbody, token) {
152
154
  /**
153
155
  * API method to fetch data from DHM
154
156
  * @param {string} query - DHM API query. Find details at https://datafordeler.dk/dataoversigt/danmarks-hoejdemodel-dhm/koter/
155
- * @param {{API_DHM_BASEURL: string, API_DHM_USERNAME: string, API_DHM_PASSWORD: string}} auth - API autentication data. See ../config.js.example for reference.
157
+ * @param {{API_DHM_BASEURL: string, API_DHM_TOKENA: string, API_DHM_TOKENB: string}} auth - API autentication data. See ../config.js.example for reference.
156
158
  * @returns {object} Response data
157
159
  */
158
160
  function getDHM(query, auth) {
159
- const auth_params = `&username=${auth.API_DHM_USERNAME}&password=${auth.API_DHM_PASSWORD}`
161
+ const auth_params = `&username=${auth.API_DHM_TOKENA}&password=${auth.API_DHM_TOKENB}`
160
162
  return get(encodeURI(auth.API_DHM_BASEURL + query + auth_params))
161
163
  .then((data) => data)
162
164
  }
@@ -184,10 +186,50 @@ function postSTAC(endpoint, data, auth) {
184
186
  .then((data) => data)
185
187
  }
186
188
 
189
+
190
+ /** Converts raw GeoTIFF arrayBuffer to image */
191
+ async function consumeGeoTIFF(raw_data) {
192
+ const tiff = await fromArrayBuffer(raw_data)
193
+ const image = await tiff.getImage()
194
+ return image
195
+ }
196
+
197
+
198
+ /** Fetches a GeoTIFF with elevation data matching the bounding box of a STAC API item (image)
199
+ * @param {object} stac_item - STAC API item from a featureCollection request
200
+ * @param {{API_DHM_WCS_BASEURL: string, API_DHM_TOKENA: string, API_DHM_TOKENB: string}} auth - API autentication data. See ../config.js.example for reference.
201
+ * @param {number} [resolution] - Resolution (1 - 0.01). Higher number means more pixels and better precision.
202
+ * @returns {object} GeoTiff data
203
+ */
204
+ function getTerrainGeoTIFF(stac_item, auth, resolution = 0.05) {
205
+
206
+ const bbox = stac_item.bbox
207
+ const width = Math.round( stac_item.properties['proj:shape'][0] * resolution )
208
+ const height = Math.round( stac_item.properties['proj:shape'][1] * resolution )
209
+
210
+ // GET request for DHM WCS data
211
+ let url = auth.API_DHM_WCS_BASEURL
212
+ url += '?SERVICE=WCS&COVERAGE=dhm_terraen&RESPONSE_CRS=epsg:25832&CRS=epsg:25832&FORMAT=GTiff&REQUEST=GetCoverage&VERSION=1.0.0'
213
+ url += `&username=${ auth.API_DHM_TOKENA }&password=${ auth.API_DHM_TOKENB }`
214
+ url += `&height=${ height }`
215
+ url += `&width=${ width }`
216
+ url += `&bbox=${ bbox[0]},${ bbox[1]},${ bbox[2]},${ bbox[3]}`
217
+
218
+ return get(url, {}, false)
219
+ .then((response) => {
220
+ return response.arrayBuffer()
221
+ })
222
+ .then((arrayBuffer) => {
223
+ return consumeGeoTIFF(arrayBuffer)
224
+ })
225
+ }
226
+
227
+
187
228
  export {
188
229
  get,
189
230
  post,
190
231
  getSTAC,
191
232
  postSTAC,
192
- getDHM
233
+ getDHM,
234
+ getTerrainGeoTIFF
193
235
  }
@@ -57,18 +57,22 @@ function image2world(image_data, col, row, Z = 0) {
57
57
  var X = (Z-Z0)*kx + X0
58
58
  var Y = (Z-Z0)*ky + Y0
59
59
 
60
- return[X,Y,Z]
60
+ return[
61
+ Math.round(X * 100) / 100,
62
+ Math.round(Y * 100) / 100,
63
+ Z
64
+ ]
61
65
  }
62
66
 
63
67
  /**
64
- * Converts lat,lon coordinates to x,y coordinates within a specific image
68
+ * Converts world lat,lon coordinates to x,y coordinates within a specific image
65
69
  * @param {Object} image_data - skraafoto-stac-api image data
66
70
  * @param {Number} Y - northing
67
71
  * @param {Number} X - easting
68
72
  * @param {Number} [Z] - elevation (geoide)
69
73
  * @returns {array} [x,y] Column/row image coordinate
70
74
  */
71
- function world2image(image_data, X, Y, Z = 0) {
75
+ function getImageXY(image_data, X, Y, Z = 0) {
72
76
 
73
77
  // constants pulled from image_data
74
78
  const xx0 = image_data.properties['pers:interior_orientation'].principal_point_offset[0]
@@ -109,7 +113,22 @@ function world2image(image_data, X, Y, Z = 0) {
109
113
  var col = ((x_dot-xx0)+(dimX))*(-1)/pix
110
114
  var row = ((y_dot-yy0)+(dimY))*(-1)/pix
111
115
 
112
- return [col, row]
116
+ return [
117
+ Math.round(col),
118
+ Math.round(row)
119
+ ]
120
+ }
121
+
122
+ /**
123
+ * (DEPRECATED - Use getImageXY) Converts lat,lon coordinates to x,y coordinates within a specific image
124
+ * @param {Object} image_data - skraafoto-stac-api image data
125
+ * @param {Number} Y - northing
126
+ * @param {Number} X - easting
127
+ * @param {Number} [Z] - elevation (geoide)
128
+ * @returns {array} [x,y] Column/row image coordinate
129
+ */
130
+ function world2image(image_data, X, Y, Z = 0) {
131
+ return getImageXY(image_data, X, Y, Z)
113
132
  }
114
133
 
115
134
  /** Converts degress to radians */
@@ -198,16 +217,17 @@ async function compareZ(options) {
198
217
  * @param {array} options.xy - image coordinates
199
218
  * @param {object} options.image - STAC API item
200
219
  * @param {object} options.terrain - GeoTIFF object from getTerrainGeoTIFF() output
220
+ * @param {number} precision - Precision in meters for "good enough"
201
221
  * @returns {array} Array with world coordinates (indexes 0 and 1) and elevation (index 2). Coordinates are EPSG:25832 format.
202
222
  */
203
- async function getWorldXYZ(options) {
223
+ async function getWorldXYZ(options, precision = 0.3) {
204
224
 
205
225
  const best_world_xyz = compareZ({
206
226
  image: options.image,
207
227
  terrain: options.terrain,
208
228
  xy: options.xy,
209
229
  z: 0,
210
- limit: 0.5,
230
+ limit: precision,
211
231
  iteration: 1
212
232
  })
213
233
 
@@ -216,8 +236,9 @@ async function getWorldXYZ(options) {
216
236
 
217
237
  export {
218
238
  image2world,
219
- getWorldXYZ,
220
239
  world2image,
240
+ getWorldXYZ,
241
+ getImageXY,
221
242
  getZ,
222
243
  iterate
223
244
  }
@@ -1,41 +1,7 @@
1
- import { fromArrayBuffer } from 'geotiff'
2
- import { get } from './api.js'
1
+ import { getTerrainGeoTIFF } from './api.js'
3
2
 
4
- /** Fetches a GeoTIFF with elevation data matching the bounding box of a STAC API item (image)
5
- * @param {object} stac_item - STAC API item from a featureCollection request
6
- * @param {{API_DHM_WCS_BASEURL: string, API_DHM_USERNAME: string, API_DHM_PASSWORD: string}} auth - API autentication data. See ../config.js.example for reference.
7
- * @param {number} [fidelity] - Resolution fidelity. Higher number means more pixels and better precision. Between 1 and 0.01.
8
- * @returns {object} GeoTiff data
9
- */
10
- function getTerrainGeoTIFF(stac_item, auth, fidelity = 0.05) {
11
-
12
- const bbox = stac_item.bbox
13
- const width = Math.round( stac_item.properties['proj:shape'][0] * fidelity )
14
- const height = Math.round( stac_item.properties['proj:shape'][1] * fidelity )
15
-
16
- // GET request for DHM WCS data
17
- let url = auth.API_DHM_WCS_BASEURL
18
- url += '?SERVICE=WCS&COVERAGE=dhm_terraen&RESPONSE_CRS=epsg:25832&CRS=epsg:25832&FORMAT=GTiff&REQUEST=GetCoverage&VERSION=1.0.0'
19
- url += `&username=${ auth.API_DHM_USERNAME }&password=${ auth.API_DHM_PASSWORD }` // TODO: Should be auth stuff
20
- url += `&height=${ height }`
21
- url += `&width=${ width }`
22
- url += `&bbox=${ bbox[0]},${ bbox[1]},${ bbox[2]},${ bbox[3]}`
23
-
24
- return get(url, {}, false)
25
- .then((response) => {
26
- return response.arrayBuffer()
27
- })
28
- .then((arrayBuffer) => {
29
- return consumeGeoTIFF(arrayBuffer)
30
- })
31
- }
32
-
33
- async function consumeGeoTIFF(raw_data) {
34
- const tiff = await fromArrayBuffer(raw_data)
35
- const image = await tiff.getImage()
36
- return image
37
- }
38
3
 
4
+ /** Constrain coordinates to be within a bounding box */
39
5
  function constrainToBbox(bbox, x, y) {
40
6
  let new_x = x
41
7
  let new_y = y
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@dataforsyningen/saul",
3
- "version": "3.1.3",
3
+ "version": "3.3.0",
4
4
  "description": "This is a collection of stand-alone methods for photogrammetry calculations and API interactions for 'Danske Skråfotos'.",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
7
  "scripts": {
8
- "test": "echo 'TESTS WILL ONLY RUN UNDER NODE v18' && node ./test/saul-projection.test.js && node ./test/saul-core.test.js && node ./test/saul-elevation.test.js",
8
+ "test": "echo 'TESTS WILL ONLY RUN UNDER NODE v18' && node ./test/saul-projection.test.js && node ./test/saul-core.test.js && node ./test/saul-combined.test.js && node ./test/saul-elevation.test.js",
9
9
  "docs": "jsdoc ./modules/*.js --destination docs"
10
10
  },
11
11
  "repository": {
@@ -17,7 +17,11 @@
17
17
  "SDFI",
18
18
  "saul"
19
19
  ],
20
- "author": "Styrelsen for Dataforsyning og Infrastruktur (https://sdfi.dk/)",
20
+ "author": {
21
+ "name": "Styrelsen for Dataforsyning og Infrastruktur",
22
+ "email": "support@sdfi.dk",
23
+ "url": "https://sdfi.dk/"
24
+ },
21
25
  "license": "MIT",
22
26
  "bugs": {
23
27
  "url": "https://github.com/SDFIdk/saul/issues"
@@ -0,0 +1,147 @@
1
+ // You should add your own config.js with proper tokens, etc.
2
+ // Check config.js.example for info on how to set it up
3
+ import auth from '../config.js'
4
+ import { getSTAC, getTerrainGeoTIFF,getZ, getWorldXYZ, getImageXY } from '../index.js'
5
+
6
+
7
+ // Vars
8
+ const resolution = 0.005 // Higher number means more points and better precision
9
+ const max_deviation = 0.5
10
+
11
+ /*
12
+ // North
13
+ let item_1 = {
14
+ id: '2021_83_29_2_0019_00003995',
15
+ xy: [1000,1000]
16
+ }
17
+ // East
18
+ let item_2 = {
19
+ id: '2021_83_29_4_0016_00002877'
20
+ }
21
+ // West
22
+ let item_3 = {
23
+ id: '2021_83_29_5_0022_00003276'
24
+ }
25
+ // South
26
+ let item_4 = {
27
+ id: '2021_83_29_3_0019_00003975'
28
+ }
29
+ // Nadir
30
+ let item_5 = {
31
+ id: '2021_83_29_1_0019_00003985'
32
+ }
33
+ */
34
+
35
+ /*
36
+ // North
37
+ let item_1 = {
38
+ id: '2021_83_33_2_0003_00002821',
39
+ xy: [8000,5000]
40
+ }
41
+ // East
42
+ let item_2 = {
43
+ id: '2021_83_33_4_0002_00000845'
44
+ }
45
+ // West
46
+ let item_3 = {
47
+ id: '2021_83_33_5_0005_00003192'
48
+ }
49
+ // South
50
+ let item_4 = {
51
+ id: '2021_83_33_3_0004_00002970'
52
+ }
53
+ // Nadir
54
+ let item_5 = {
55
+ id: '2021_83_33_1_0004_00002965'
56
+ }
57
+ */
58
+
59
+ // North
60
+ let item_1 = {
61
+ id: '2021_83_29_2_0019_00003995',
62
+ xy: [1000,1000]
63
+ }
64
+ // East
65
+ let item_2 = {
66
+ id: '2021_83_29_4_0016_00002877'
67
+ }
68
+ // West
69
+ let item_3 = {
70
+ id: '2021_83_29_5_0022_00003276'
71
+ }
72
+ // South
73
+ let item_4 = {
74
+ id: '2021_83_29_3_0019_00003975'
75
+ }
76
+ // Nadir
77
+ let item_5 = {
78
+ id: '2021_83_29_1_0019_00003985'
79
+ }
80
+
81
+ // Helper functions
82
+ function is_equalIsh(num1, num2, deviation = max_deviation) {
83
+ if (Math.abs(num1 - num2) > deviation) {
84
+ return false
85
+ } else {
86
+ return true
87
+ }
88
+ }
89
+ function generateSTACurl(stac_item_id) {
90
+ return `/search?limit=1&crs=http://www.opengis.net/def/crs/EPSG/0/25832&ids=${ stac_item_id }`
91
+ }
92
+ async function enrichData(item) {
93
+ let new_item = Object.assign({}, item)
94
+ // add STAC item
95
+ new_item.item = await getSTAC(generateSTACurl(new_item.id), auth)
96
+ new_item.item = new_item.item.features[0]
97
+ // add terrain GeoTIFF
98
+ new_item.terrain = await getTerrainGeoTIFF(new_item.item, auth, resolution)
99
+ // Add imageXY
100
+ new_item.xy = getImageXY(new_item.item, item_1.xyz[0], item_1.xyz[1], item_1.xyz[2])
101
+ // Add world XYZ (from imageYX)
102
+ new_item.xyz = await getWorldXYZ({
103
+ xy: new_item.xy,
104
+ image: new_item.item,
105
+ terrain: new_item.terrain
106
+ })
107
+ // add kote
108
+ new_item.kote = await getZ(new_item.xyz[0], new_item.xyz[1], auth)
109
+ // add resolution info
110
+ new_item.ext_x = Math.round((new_item.item.bbox[2] - new_item.item.bbox[0]) * 100) / 100
111
+ new_item.ext_y = Math.round((new_item.item.bbox[3] - new_item.item.bbox[1]) * 100) / 100
112
+ new_item.z_pr_m_x = Math.round((new_item.item.properties['proj:shape'][0] / new_item.ext_x) * 100 * resolution) / 100
113
+ new_item.z_pr_m_y = Math.round((new_item.item.properties['proj:shape'][1] / new_item.ext_y) * 100 * resolution) / 100
114
+ const width = Math.round( new_item.item.properties['proj:shape'][0] * resolution )
115
+ const height = Math.round( new_item.item.properties['proj:shape'][1] * resolution )
116
+ new_item.z_points = width * height
117
+ return new_item
118
+ }
119
+
120
+ // Fetch image data and terrain
121
+ item_1.item = await getSTAC(generateSTACurl(item_1.id), auth)
122
+ item_1.item = item_1.item.features[0]
123
+ item_1.terrain = await getTerrainGeoTIFF(item_1.item, auth, resolution)
124
+
125
+ // Given image XY for one image, get world XYZ
126
+ item_1.xyz = await getWorldXYZ({
127
+ xy: item_1.xy,
128
+ image: item_1.item,
129
+ terrain: item_1.terrain
130
+ })
131
+
132
+ item_1.kote = await getZ(item_1.xyz[0], item_1.xyz[1], auth)
133
+
134
+ // Get image and corresponding world coordinates for other images (amongst other things)
135
+ item_2 = await enrichData(item_2)
136
+ item_3 = await enrichData(item_3)
137
+ item_4 = await enrichData(item_4)
138
+ item_5 = await enrichData(item_5)
139
+
140
+ // Compare items
141
+ console.table({
142
+ north: item_1,
143
+ east: item_2,
144
+ west: item_3,
145
+ south: item_4,
146
+ nadir: item_5
147
+ })
@@ -1,12 +1,11 @@
1
1
  // Testing saul-core methods
2
2
 
3
- // You should add your own config.js with proper tokens, passwords, etc.
3
+ // You should add your own config.js with proper tokens, etc.
4
4
  // Check config.js.example for info on how to set it up
5
5
  import auth from '../config.js'
6
6
 
7
7
  import assert from 'assert'
8
- import {getSTAC} from '../modules/api.js'
9
- import {world2image, image2world, getZ, iterate} from '../modules/saul-core.js'
8
+ import {getSTAC, world2image, image2world, getZ, iterate} from '../index.js'
10
9
 
11
10
  /*
12
11
  const item = await getSTAC('/collections/skraafotos2019/items/2019_83_37_2_0046_00001113', auth)
@@ -24,8 +23,7 @@ const image_x = 41839.698939
24
23
  const image_y = 3204.326930
25
24
  const world_elevation = 38.874336
26
25
 
27
- function is_equalIsh(num1, num2) {
28
- const deviation = 0.05
26
+ function is_equalIsh(num1, num2, deviation = 0.05) {
29
27
  if (Math.abs(num1 - num2) > deviation) {
30
28
  return false
31
29
  } else {
@@ -65,7 +63,7 @@ try {
65
63
 
66
64
  let xy = world2image(item, world_x, world_y, world_elevation)
67
65
 
68
- assert(is_equalIsh(xy[0], image_x), "world2image fail: The x coordinate values are not equal")
66
+ assert(is_equalIsh(xy[0], image_x, 1), `world2image fail: The x coordinate values ${xy[0]} ${image_x} are not equal`)
69
67
  assert(is_equalIsh(xy[1], image_y), "world2image fail: The y coordinate values are not equal")
70
68
 
71
69
  console.log("Test world2image OK")
@@ -1,19 +1,17 @@
1
- // You should add your own config.js with proper tokens, passwords, etc.
1
+ // You should add your own config.js with proper tokens, etc.
2
2
  // Check config.js.example for info on how to set it up
3
3
  import auth from '../config.js'
4
4
 
5
5
  import assert from 'assert'
6
- import { getTerrainGeoTIFF, getElevation } from '../modules/saul-elevation.js'
7
- import { get } from '../modules/api.js'
8
- import { getZ, getWorldXYZ, world2image } from '../modules/saul-core.js'
6
+ import { getElevation, get, getTerrainGeoTIFF, getZ, getWorldXYZ, world2image } from '../index.js'
9
7
 
10
8
  // Vars
11
9
  const stac_item = '2021_83_29_2_0019_00003995'
12
- const fidelity = 0.05 // Higher number means more points and better precision
10
+ const fidelity = 0.03 // Higher number means more points and better precision
13
11
  const max_deviation = 0.5
14
12
 
15
13
  // STAC API endpoint
16
- let url_stac = 'https://api.dataforsyningen.dk/skraafotoapi_test/search?limit=1&crs=http://www.opengis.net/def/crs/EPSG/0/25832&token=9b554b6c854184c3b0f377ffc7481585'
14
+ let url_stac = auth.API_STAC_BASEURL + '/search?limit=1&crs=http://www.opengis.net/def/crs/EPSG/0/25832&token=9b554b6c854184c3b0f377ffc7481585'
17
15
  url_stac += `&ids=${ stac_item }`
18
16
 
19
17
  function is_equalIsh(num1, num2, deviation = max_deviation) {
@@ -53,10 +51,10 @@ function testGetWorldXYZAnumberOfTimes(item, terrain, times) {
53
51
  image: item,
54
52
  terrain: terrain
55
53
  }).then(world_xy => {
56
- compareElevations(world_xy[0], world_xy[1], terrain) // lower left corner of image
54
+ compareElevations(world_xy[0], world_xy[1], terrain)
57
55
  const image_coords = world2image(item, world_xy[0], world_xy[1], world_xy[2])
58
- assert(is_equalIsh(image_coords[0], xy[0], 0.75), `Image x coordinates ${image_coords[0]} / ${xy[0]} do not match`)
59
- assert(is_equalIsh(image_coords[1], xy[1], 0.75), `Image y coordinates ${image_coords[1]} / ${xy[1]} do not match`)
56
+ assert(is_equalIsh(image_coords[0], xy[0], 2), `Image x coordinates ${image_coords[0]} / ${xy[0]} do not match`)
57
+ assert(is_equalIsh(image_coords[1], xy[1], 2), `Image y coordinates ${image_coords[1]} / ${xy[1]} do not match`)
60
58
  console.log('getWorldXYZ => world2image OK')
61
59
  })
62
60
  }
@@ -67,7 +65,7 @@ function compareElevations(x,y,geotiff) {
67
65
  .then(elevation => {
68
66
  getZ(x, y, auth)
69
67
  .then(getz_e => {
70
- assert(is_equalIsh(getz_e, elevation), `Elevations ${elevation} / ${getz_e} at ${x} ${y} do not match`)
68
+ assert(is_equalIsh(getz_e, elevation, 0.5), `Elevations ${elevation} / ${getz_e} at ${x} ${y} do not match`)
71
69
  console.log(`Elevation at ${ x } ${ y } with delta ${Math.abs(elevation - getz_e).toFixed(2)} OK`)
72
70
  })
73
71
  })
@@ -2,7 +2,7 @@
2
2
 
3
3
  import assert from 'assert'
4
4
  import proj4 from 'proj4'
5
- import {epsg25832proj, createTranslator} from '../modules/saul-projection.js'
5
+ import {epsg25832proj, createTranslator} from '../index.js'
6
6
 
7
7
  // Test epsg25832proj
8
8
  try {