@dataforsyningen/saul 3.1.0 → 3.1.1

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.
@@ -5,8 +5,6 @@
5
5
  import { getDHM } from './api.js'
6
6
  import { getElevation } from './saul-elevation.js'
7
7
 
8
- let iterations
9
-
10
8
  /**
11
9
  * Converts x,y coordinates from an image to real world lat,lon coordinates
12
10
  * @param {object} image_data - skraafoto-stac-api image data
@@ -184,84 +182,11 @@ function iterate(image_data, col, row, auth, limit = 1) {
184
182
  */
185
183
  async function getWorldXYZ(options) {
186
184
 
187
- iterations = 1
188
-
189
185
  const world_xyz = image2world(options.image, options.xy[0], options.xy[1], 0)
190
- const better_world_xyz = await compareXYZ({
191
- xy: options.xy,
192
- image: options.image,
193
- terrain: options.terrain,
194
- world_xyz: Array.from(world_xyz),
195
- limit: 0.5
196
- })
197
- return better_world_xyz
198
- }
199
-
200
- /**
201
- * Adjusts elevation value if values are too far apart
202
- * @param {number} z - elevation
203
- * @param {number} delta_y - discrepancy value
204
- * @returns {number} Adjusted elevation number
205
- */
206
- function adjustZ(z, delta_y) {
207
- let new_z
208
- if (delta_y < 0) {
209
- new_z = z + 0.1
210
- } else {
211
- new_z = z - 0.1
212
- }
213
- console.log('z', new_z)
214
- return new_z
215
- }
216
-
217
- /**
218
- * Compares differences i x and y values
219
- * @param {number} delta_x - x difference
220
- * @param {number} delta_y - y difference
221
- * @param {number} limit - difference may be within this limit
222
- * @returns {boolean} Returns true if differences are within accepted limit
223
- */
224
- function compareXY(delta_x, delta_y, limit) {
225
- if (Math.abs(delta_x) > limit || Math.abs(delta_y) > limit) {
226
- return false
227
- } else {
228
- return true
229
- }
230
- }
231
-
232
- /**
233
- * Iterates world coordinate calculations in order to get a more precise result
234
- * @param {object} options
235
- * @param {array} options.xy - image coordinates
236
- * @param {object} options.image - STAC API item
237
- * @param {object} options.terrain - GeoTIFF object from getTerrainGeoTIFF() output
238
- * @param {array} options.world_xy - Array with (currently guessed) world coordinates (indexes 0 and 1) and elevation (index 2). Coordinates are EPSG:25832 format.
239
- * @param {number} options.limit - Return when two guesses are within this limit
240
- * @returns {array} Array with world coordinates (indexes 0 and 1) and elevation (index 2). Coordinates are EPSG:25832 format.
241
- */
242
- async function compareXYZ(options) {
243
-
244
- iterations++
245
- if (iterations > 50) {
246
- console.error('too many iterations')
247
- return false
248
- }
249
-
250
- const z = await getElevation(options.xy[0], options.xy[1], options.terrain)
251
- const world_xyz = image2world(options.image, options.xy[0], options.xy[1], z)
252
- const delta_x = world_xyz[0] - options.world_xyz[0]
253
- const delta_y = world_xyz[1] - options.world_xyz[1]
186
+ world_xyz[2] = await getElevation(world_xyz[0], world_xyz[1], options.terrain)
187
+ const better_world_xyz = image2world(options.image, options.xy[0], options.xy[1], world_xyz[2])
254
188
 
255
- if (!compareXY(delta_x, delta_y, options.limit)) {
256
-
257
- const new_options = Object.assign({},options)
258
- new_options.world_xyz = Array.from(world_xyz)
259
- new_options.world_xyz[2] = adjustZ(world_xyz[2], delta_x, delta_y)
260
- return await compareXYZ(new_options)
261
-
262
- } else {
263
- return world_xyz
264
- }
189
+ return better_world_xyz
265
190
  }
266
191
 
267
192
  export {
@@ -36,6 +36,22 @@ async function consumeGeoTIFF(raw_data) {
36
36
  return image
37
37
  }
38
38
 
39
+ function constrainToBbox(bbox, x, y) {
40
+ let new_x = x
41
+ let new_y = y
42
+ if (x < bbox[0]) {
43
+ new_x = bbox[0] + 1
44
+ } else if (bbox[2] < x) {
45
+ new_x = bbox[2] - 1
46
+ }
47
+ if (y < bbox[1]) {
48
+ new_y = bbox[1] + 1
49
+ } else if (bbox[3] < y) {
50
+ new_y = bbox[3] - 1
51
+ }
52
+ return [new_x, new_y]
53
+ }
54
+
39
55
  /** Calculates nearest elevation for given coordinate using geoTIFF terrain data
40
56
  * Heavily inspired by https://towardsdatascience.com/geotiff-coordinate-querying-with-javascript-5e6caaaf88cf
41
57
  * @param {number} x - EPSG:25832 X coordinate
@@ -51,8 +67,10 @@ async function getElevation(x, y, geoTiff) {
51
67
  const bboxWidth = bbox[2] - bbox[0]
52
68
  const bboxHeight = bbox[3] - bbox[1]
53
69
 
54
- const widthPct = ( x - bbox[0] ) / bboxWidth
55
- const heightPct = ( y - bbox[1] ) / bboxHeight
70
+ const xy = constrainToBbox(bbox, x, y)
71
+
72
+ const widthPct = ( xy[0] - bbox[0] ) / bboxWidth
73
+ const heightPct = ( xy[1] - bbox[1] ) / bboxHeight
56
74
  const xPx = Math.floor( width * widthPct )
57
75
  const yPx = Math.floor( height * ( 1 - heightPct ) )
58
76
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dataforsyningen/saul",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
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",
@@ -5,7 +5,7 @@ import auth from '../config.js'
5
5
  import assert from 'assert'
6
6
  import { getTerrainGeoTIFF, getElevation } from '../modules/saul-elevation.js'
7
7
  import { get } from '../modules/api.js'
8
- import { getZ, getWorldXYZ } from '../modules/saul-core.js'
8
+ import { getZ, getWorldXYZ, world2image } from '../modules/saul-core.js'
9
9
 
10
10
  // Vars
11
11
  const stac_item = '2021_83_29_2_0019_00003995'
@@ -16,8 +16,8 @@ const max_deviation = 0.5
16
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'
17
17
  url_stac += `&ids=${ stac_item }`
18
18
 
19
- function is_equalIsh(num1, num2) {
20
- if (Math.abs(num1 - num2) > max_deviation) {
19
+ function is_equalIsh(num1, num2, deviation = max_deviation) {
20
+ if (Math.abs(num1 - num2) > deviation) {
21
21
  return false
22
22
  } else {
23
23
  return true
@@ -30,13 +30,38 @@ function getRandomCoordinate(bbox) {
30
30
  return [x,y]
31
31
  }
32
32
 
33
- function testDataAnumberOfTimes(data, bbox, times) {
33
+ function testGetElevationAnumberOfTimes(data, bbox, times) {
34
34
  for (let i = 1; i <= times; i++) {
35
35
  const world1 = getRandomCoordinate(bbox)
36
36
  compareElevations(world1[0], world1[1], data)
37
37
  }
38
38
  }
39
39
 
40
+ function getRandomImageXY(image) {
41
+ const shapex = image.properties['proj:shape'][0]
42
+ const shapey = image.properties['proj:shape'][1]
43
+ const x = Math.floor(shapex - Math.random() * shapex)
44
+ const y = Math.floor(shapey - Math.random() * shapey)
45
+ return [x,y]
46
+ }
47
+
48
+ function testGetWorldXYZAnumberOfTimes(item, terrain, times) {
49
+ for (let i = 1; i <= times; i++) {
50
+ const xy = getRandomImageXY(item)
51
+ getWorldXYZ({
52
+ xy: xy,
53
+ image: item,
54
+ terrain: terrain
55
+ }).then(world_xy => {
56
+ compareElevations(world_xy[0], world_xy[1], terrain) // lower left corner of image
57
+ 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`)
60
+ console.log('getWorldXYZ => world2image OK')
61
+ })
62
+ }
63
+ }
64
+
40
65
  function compareElevations(x,y,geotiff) {
41
66
  getElevation(x, y, geotiff)
42
67
  .then(elevation => {
@@ -52,8 +77,6 @@ function compareElevations(x,y,geotiff) {
52
77
  get(url_stac)
53
78
  .then((json) => {
54
79
 
55
- console.log('Testing getTerrainGeoTIFF and getElevation')
56
-
57
80
  const width = Math.round( json.features[0].properties['proj:shape'][0] * fidelity )
58
81
  const height = Math.round( json.features[0].properties['proj:shape'][1] * fidelity )
59
82
 
@@ -62,15 +85,19 @@ get(url_stac)
62
85
  getTerrainGeoTIFF(json.features[0], auth, fidelity)
63
86
  .then(data => {
64
87
 
65
- testDataAnumberOfTimes(data, json.features[0].bbox, 5)
66
-
67
- getWorldXYZ({
68
- xy: [1,1],
69
- image: json.features[0],
70
- terrain: data
71
- }).then(world_xy => {
72
- compareElevations(world_xy[0], world_xy[1], data) // lower left corner of image
73
- })
88
+ // Testing getElevation
89
+ try {
90
+ testGetElevationAnumberOfTimes(data, json.features[0].bbox, 5)
91
+ } catch(error) {
92
+ console.error(error)
93
+ }
94
+
95
+ // Testing getWorldXYZ
96
+ try {
97
+ testGetWorldXYZAnumberOfTimes(json.features[0], data, 10)
98
+ } catch(error) {
99
+ console.error(error)
100
+ }
74
101
 
75
102
  })
76
103