Skip to content

Commit

Permalink
Merge pull request #887 from geoadmin/feat_PB-583_use_backend_to_get_…
Browse files Browse the repository at this point in the history
…lv03

PB-583 : use backend service to get LV03 <> LV95 conversion right
  • Loading branch information
pakb authored Jun 10, 2024
2 parents 0a1f6e3 + 7088d98 commit 2f1ab9f
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 5 deletions.
49 changes: 49 additions & 0 deletions src/api/lv03Reframe.api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import axios from 'axios'
import proj4 from 'proj4'

import { LV03, LV95 } from '@/utils/coordinates/coordinateSystems'
import log from '@/utils/logging'

const REFRAME_BASE_URL = 'https://geodesy.geo.admin.ch/reframe/'

/**
* Re-frames LV95 coordinate taking all LV03 -> LV95 deformation into account (they are not stable,
* so using "simple" proj4 matrices isn't enough to get a very accurate result)
*
* @param {[Number, Number]} lv95coordinate LV95 coordinate that we want expressed in LV03
* @returns {Promise<[Number, Number]>} Input LV95 coordinate re-framed by the backend service into
* LV03 coordinate
* @see https://www.swisstopo.admin.ch/en/rest-api-geoservices-reframe-web
* @see https://github.com/geoadmin/mf-geoadmin3/blob/master/src/components/ReframeService.js
*/
export default function reframe(lv95coordinate) {
return new Promise((resolve, reject) => {
if (!Array.isArray(lv95coordinate) || lv95coordinate.length !== 2) {
reject(new Error('lv95coordinate must be an array with length of 2'))
}
axios({
method: 'GET',
url: `${REFRAME_BASE_URL}lv95tolv03`,
params: {
easting: lv95coordinate[0],
northing: lv95coordinate[1],
},
})
.then((response) => {
if (response.data?.coordinates) {
resolve(response.data.coordinates)
} else {
log.error(
'Error while re-framing coordinate',
lv95coordinate,
'fallback to proj4'
)
resolve(proj4(LV95.epsg, LV03.epsg, lv95coordinate))
}
})
.catch((error) => {
log.error('Error while re-framing coordinate', lv95coordinate, error)
reject(error)
})
})
}
20 changes: 18 additions & 2 deletions src/modules/map/components/LocationPopupPosition.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { computed, onMounted, ref, toRefs, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { requestHeight } from '@/api/height.api'
import reframe from '@/api/lv03Reframe.api'
import { registerWhat3WordsLocation } from '@/api/what3words.api'
import CoordinateCopySlot from '@/utils/components/CoordinateCopySlot.vue'
import {
Expand All @@ -15,7 +16,7 @@ import {
UTMFormat,
WGS84Format,
} from '@/utils/coordinates/coordinateFormat'
import { WGS84 } from '@/utils/coordinates/coordinateSystems'
import { LV03, LV95, WGS84 } from '@/utils/coordinates/coordinateSystems'
import log from '@/utils/logging'
const props = defineProps({
Expand All @@ -38,6 +39,7 @@ const props = defineProps({
})
const { coordinate, clickInfo, projection, currentLang } = toRefs(props)
const lv03Coordinate = ref(null)
const what3Words = ref(null)
const height = ref(null)
Expand Down Expand Up @@ -69,13 +71,15 @@ const heightInMeter = computed(() => {
onMounted(() => {
if (clickInfo.value) {
updateLV03Coordinate()
updateWhat3Word()
updateHeight()
}
})
watch(clickInfo, (newClickInfo) => {
if (newClickInfo) {
updateLV03Coordinate()
updateWhat3Word()
updateHeight()
}
Expand All @@ -84,6 +88,16 @@ watch(currentLang, () => {
updateWhat3Word()
})
async function updateLV03Coordinate() {
try {
const lv95coordinate = proj4(projection.value.epsg, LV95.epsg, coordinate.value)
lv03Coordinate.value = await reframe(lv95coordinate)
} catch (error) {
log.error('Failed to retrieve LV03 coordinate', error)
lv03Coordinate.value = null
}
}
async function updateWhat3Word() {
try {
what3Words.value = await registerWhat3WordsLocation(
Expand Down Expand Up @@ -119,9 +133,11 @@ async function updateHeight() {
</a>
</CoordinateCopySlot>
<CoordinateCopySlot
v-if="lv03Coordinate"
identifier="location-popup-lv03"
:value="coordinate"
:value="lv03Coordinate"
:coordinate-format="LV03Format"
:coordinate-projection="LV03"
>
<a :href="i18n.t('contextpopup_lv03_url')" target="_blank">
{{ LV03Format.label }}
Expand Down
10 changes: 8 additions & 2 deletions src/utils/components/CoordinateCopySlot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useI18n } from 'vue-i18n'
import { useStore } from 'vuex'
import { CoordinateFormat } from '@/utils/coordinates/coordinateFormat'
import CoordinateSystem from '@/utils/coordinates/CoordinateSystem.class'
import log from '@/utils/logging'
const props = defineProps({
Expand All @@ -28,16 +29,21 @@ const props = defineProps({
type: CoordinateFormat,
default: null,
},
coordinateProjection: {
type: CoordinateSystem,
default: null,
},
})
const { identifier, value, extraValue, resetDelay, coordinateFormat } = toRefs(props)
const { identifier, value, extraValue, resetDelay, coordinateFormat, coordinateProjection } =
toRefs(props)
const copyButton = ref(null)
const copied = ref(false)
const i18n = useI18n()
const store = useStore()
const projection = computed(() => store.state.position.projection)
const projection = computed(() => coordinateProjection.value ?? store.state.position.projection)
const lang = computed(() => store.state.i18n.lang)
const buttonIcon = computed(() => {
Expand Down
6 changes: 5 additions & 1 deletion tests/cypress/tests-e2e/mouseposition.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ describe('Test mouse position and interactions', () => {
})
it('shows the LocationPopUp when rightclick occurs on the map', () => {
let shortUrl = 'https://s.geo.admin.ch/0000000'

const fakeLV03Coordinate = [1234.56, 7890.12]
cy.intercept('**/lv95tolv03**', { coordinates: fakeLV03Coordinate }).as('reframe')
cy.intercept(/^http[s]?:\/\/(sys-s\.\w+\.bgdi\.ch|s\.geo\.admin\.ch)\//, {
body: { shorturl: shortUrl, success: true },
}).as('shortlink')
Expand Down Expand Up @@ -163,10 +166,11 @@ describe('Test mouse position and interactions', () => {
.then(checkXY(...centerLV95))
cy.log('it shows coordinates, correctly re-projected into LV95, in the popup')

cy.wait('@reframe')
cy.get('[data-cy="location-popup-lv03"]')
.invoke('text')
.then(parseLV)
.then(checkXY(...centerLV03))
.then(checkXY(...fakeLV03Coordinate))
cy.log('it shows coordinates, correctly re-projected into LV03, in the popup')

cy.get('[data-cy="location-popup-wgs84"]').contains(
Expand Down

0 comments on commit 2f1ab9f

Please sign in to comment.