Skip to content

PB-1383: layers module #1258

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 10 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 12 additions & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,18 @@ export default defineConfigWithVueTs(
// on unused param from abstract function arguments
rules: {
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-unused-vars': [
'error',
{
// as we are adding dispatcher reference in all our store action, but won't be using
// them directly in the action, we must ignore these unused variables too
argsIgnorePattern: '^(_|dispatcher)',
caughtErrorsIgnorePattern: '^_',
destructuredArrayIgnorePattern: '^_',
},
],
'@typescript-eslint/consistent-type-exports': 'error',
'@typescript-eslint/no-import-type-side-effects': 'error',
},
},
{
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@
"@types/geojson": "catalog:",
"@types/jsdom": "catalog:",
"@types/node": "catalog:",
"@types/proj4": "catalog:",
"@vue/eslint-config-prettier": "catalog:",
"@vue/eslint-config-typescript": "catalog:",
"@vue/language-core": "catalog:",
"@vue/tsconfig": "catalog:",
"eslint": "catalog:",
"eslint-plugin-cypress": "catalog:",
Expand All @@ -61,8 +61,8 @@
"stylelint-scss": "catalog:",
"typescript": "catalog:",
"typescript-eslint": "catalog:",
"unplugin-dts": "catalog:",
"vite": "catalog:",
"vite-plugin-dts": "catalog:",
"vitest": "catalog:",
"vue-tsc": "catalog:"
},
Expand All @@ -73,7 +73,8 @@
"pnpm": {
"onlyBuiltDependencies": [
"cypress",
"sharp"
"sharp",
"vue-demi"
],
"ignoredBuiltDependencies": [
"core-js",
Expand Down
16 changes: 11 additions & 5 deletions packages/geoadmin-coordinates/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
],
"scripts": {
"build": "pnpm run type-check && pnpm run generate-types && vite build",
"build:dev": "pnpm run build -- --mode development",
"build:dev:watch": "pnpm run build --watch -- --mode development",
"build:int": "pnpm run build -- --mode integration",
"build:prod": "pnpm run build -- --mode production",
"build:dev": "pnpm run build --mode development",
"build:dev:watch": "pnpm run build --watch --mode development",
"build:int": "pnpm run build --mode integration",
"build:prod": "pnpm run build --mode production",
"dev": "vite",
"generate-types": "vue-tsc --declaration",
"preview": "vite preview",
Expand All @@ -32,11 +32,17 @@
"lodash": "catalog:"
},
"devDependencies": {
"@microsoft/api-extractor": "catalog:",
"@turf/turf": "catalog:",
"@types/chai": "catalog:",
"@types/lodash": "catalog:",
"chai": "catalog:"
"chai": "catalog:",
"unplugin-dts": "catalog:",
"vite": "catalog:",
"vitest": "catalog:"
},
"peerDependencies": {
"ol": "catalog:",
"proj4": "catalog:"
}
}
167 changes: 167 additions & 0 deletions packages/geoadmin-coordinates/src/__test__/coordinatesUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import { expect } from 'chai'
import { describe, it } from 'vitest'

import type { Single3DCoordinate, SingleCoordinate } from '@/coordinatesUtils'

import coordinatesUtils from '@/coordinatesUtils'
import { CoordinateSystem, LV95, WEBMERCATOR, WGS84 } from '@/proj'

describe('Unit test for coordinatesUtils', () => {
describe('toRoundedString', () => {
it('rounds without decimal if 0 is given as digits', () => {
expect(coordinatesUtils.toRoundedString([1.49, 2.49], 0)).to.eq(
'1, 2',
'it should floor any number lower than .5'
)
expect(coordinatesUtils.toRoundedString([1.5, 2.5], 0)).to.eq(
'2, 3',
'it should raise any number greater or equal to .5'
)
})
it('rounds with decimal if a number is given as digits', () => {
expect(coordinatesUtils.toRoundedString([1.44, 2.44], 1)).to.eq('1.4, 2.4')
expect(coordinatesUtils.toRoundedString([1.45, 2.45], 1)).to.eq('1.5, 2.5')
})
it('correctly enforcers digits when asked for', () => {
expect(coordinatesUtils.toRoundedString([1.44, 2.44], 5, false, true)).to.eq(
'1.44000, 2.44000'
)
expect(coordinatesUtils.toRoundedString([1, 2], 3, false, true)).to.eq('1.000, 2.000')
expect(coordinatesUtils.toRoundedString([1234.5678, 1234.5678], 6, true, true)).to.eq(
"1'234.567800, 1'234.567800"
)
})
})

describe('wrapXCoordinates()', () => {
it('can wrap a single coordinate', () => {
function testLowerWrap(projection: CoordinateSystem): void {
const bounds = projection.bounds
expect(bounds).to.be.an('Object')
expect(
coordinatesUtils.wrapXCoordinates(
[bounds!.lowerX - 1, bounds!.center[1]],
projection
)
).to.deep.equal([bounds!.upperX - 1, bounds!.center[1]])
}
testLowerWrap(WGS84)
testLowerWrap(WEBMERCATOR)

function testUpperWrap(projection: CoordinateSystem) {
const bounds = projection.bounds
expect(bounds).to.be.an('Object')
expect(
coordinatesUtils.wrapXCoordinates(
[bounds!.upperX + 1, bounds!.center[1]],
projection
)
).to.deep.equal([bounds!.lowerX + 1, bounds!.center[1]])
}
testUpperWrap(WGS84)
testUpperWrap(WEBMERCATOR)
})
it('do not wrap if projection is not global (world-wide)', () => {
const justOffBoundCoordinate: SingleCoordinate = [
LV95.bounds.lowerX - 1,
LV95.bounds.center[1],
]
expect(coordinatesUtils.wrapXCoordinates(justOffBoundCoordinate, LV95)).to.deep.equal(
justOffBoundCoordinate
)
})
it('can wrap every coordinates of an array of coordinates', () => {
function testMultipleWrap(projection: CoordinateSystem) {
const bounds = projection.bounds
expect(bounds).to.be.an('Object')
const lowOutOfBoundCoordinate: SingleCoordinate = [
bounds!.lowerX - 1,
bounds!.center[1],
]
const inBoundCoordinate: SingleCoordinate = [bounds!.lowerX, bounds!.center[1]]
const inBoundCoordinate2: SingleCoordinate = [bounds!.center[0], bounds!.center[1]]
const inBoundCoordinate3: SingleCoordinate = [bounds!.upperX, bounds!.center[1]]
const upOutOfBoundCoordinate: SingleCoordinate = [
bounds!.upperX + 1,
bounds!.center[1],
]
const original = [
lowOutOfBoundCoordinate,
inBoundCoordinate,
inBoundCoordinate2,
inBoundCoordinate3,
upOutOfBoundCoordinate,
]
const result = coordinatesUtils.wrapXCoordinates(original, projection)
expect(result).to.be.an('Array').lengthOf(original.length)
const [first, second, third, fourth, fifth] = result
expect(first).to.deep.equal([bounds!.upperX - 1, lowOutOfBoundCoordinate[1]])
expect(second).to.deep.equal(inBoundCoordinate, 'wrong lowerX handling')
expect(third).to.deep.equal(inBoundCoordinate2, 'wrong center handling')
expect(fourth).to.deep.equal(inBoundCoordinate3, 'wrong upperX handling')
expect(fifth).to.deep.equal([bounds!.lowerX + 1, upOutOfBoundCoordinate[1]])
}
testMultipleWrap(WGS84)
testMultipleWrap(WEBMERCATOR)
})
})

describe('unwrapGeometryCoordinates(coordinates)', () => {
it('returns the input if nothing is required', () => {
expect(coordinatesUtils.unwrapGeometryCoordinates([])).to.be.an('Array').lengthOf(0)
const alreadyUnwrappedCoordinates: SingleCoordinate[] = [
[1, 2],
[3, 4],
[5, 6],
]
expect(coordinatesUtils.unwrapGeometryCoordinates(alreadyUnwrappedCoordinates)).to.eql(
alreadyUnwrappedCoordinates
)
})
it('unwraps when required', () => {
const expectedOutcome: SingleCoordinate[] = [
[1, 2],
[3, 4],
[5, 6],
]
const wrappedCoordinates = [expectedOutcome]
expect(coordinatesUtils.unwrapGeometryCoordinates(wrappedCoordinates)).to.eql(
expectedOutcome
)
})
})

describe('removeZValues', () => {
it('returns the input if an empty array is given', () => {
expect(coordinatesUtils.removeZValues([])).to.eql([])
})
it('returns coordinate untouched if they have no Z values', () => {
const coordinates: SingleCoordinate[] = [
[1, 2],
[3, 4],
[5, 6],
]
expect(coordinatesUtils.removeZValues(coordinates)).to.eql(coordinates)
})
it('removes Z values when needed', () => {
const coordinateWithoutZValues: SingleCoordinate[] = [
[1, 2],
[3, 4],
[5, 6],
]
expect(
coordinatesUtils.removeZValues(
coordinateWithoutZValues.map(
(coordinate): Single3DCoordinate => [
coordinate[0],
coordinate[1],
Math.floor(1 + 10 * Math.random()),
]
)
)
).to.eql(coordinateWithoutZValues)
// testing with only one coordinate
expect(coordinatesUtils.removeZValues([[1, 2, 3]])).to.eql([[1, 2]])
})
})
})
81 changes: 81 additions & 0 deletions packages/geoadmin-coordinates/src/__test__/extentUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { expect } from 'chai'
import { describe, it } from 'vitest'

import coordinatesUtils, { type SingleCoordinate } from '@/coordinatesUtils'
import { type FlatExtent, getExtentIntersectionWithCurrentProjection } from '@/extentUtils'
import { LV95, WGS84 } from '@/proj'

describe('Test extent utils', () => {
describe('reproject and cut extent within projection bounds', () => {
function expectExtentIs(
toBeTested: FlatExtent,
expected: FlatExtent,
acceptableDelta = 0.5
) {
expect(toBeTested).to.be.an('Array').lengthOf(4)
expected.forEach((value, index) => {
expect(toBeTested[index]).to.be.approximately(value, acceptableDelta)
})
}

it('reproject extent of a single coordinate inside the bounds of the projection', () => {
const singleCoordinate: SingleCoordinate = [8.2, 47.5]
const singleCoordinateInLV95 = coordinatesUtils.reprojectAndRound(
WGS84,
LV95,
singleCoordinate
)
const extent = [singleCoordinate, singleCoordinate].flat() as FlatExtent
const result = getExtentIntersectionWithCurrentProjection(extent, WGS84, LV95)
expect(result).to.be.an('Array').lengthOf(4)
expectExtentIs(result!, [...singleCoordinateInLV95, ...singleCoordinateInLV95])
})
it('returns undefined if a single coordinate outside of bounds is given', () => {
const singleCoordinateOutOfLV95Bounds = [8.2, 40]
const extent = [
singleCoordinateOutOfLV95Bounds,
singleCoordinateOutOfLV95Bounds,
].flat() as FlatExtent
expect(getExtentIntersectionWithCurrentProjection(extent, WGS84, LV95)).to.be.undefined
})
it('returns undefined if the extent given is completely outside of the projection bounds', () => {
const extent: FlatExtent = [-25.0, -20.0, -5.0, -45.0]
expect(getExtentIntersectionWithCurrentProjection(extent, WGS84, LV95)).to.be.undefined
})
it('reproject and cut an extent that is greater than LV95 extent on all sides', () => {
const result = getExtentIntersectionWithCurrentProjection(
[-2.4, 35, 21.3, 51.7],
WGS84,
LV95
)
expect(result).to.be.an('Array').lengthOf(4)
expectExtentIs(result!, [...LV95.bounds.bottomLeft, ...LV95.bounds.topRight])
})
it('reproject and cut an extent that is partially bigger than LV95 bounds', () => {
const result = getExtentIntersectionWithCurrentProjection(
// extent of file linked to PB-1221
[-122.08, -33.85, 151.21, 51.5],
WGS84,
LV95
)
expect(result).to.be.an('Array').lengthOf(4)
expectExtentIs(result!, [...LV95.bounds.bottomLeft, ...LV95.bounds.topRight])
})
it('only gives back the portion of an extent that is within LV95 bounds', () => {
const singleCoordinateInsideLV95: SingleCoordinate = [7.54, 48.12]
const singleCoordinateInLV95 = coordinatesUtils.reprojectAndRound(
WGS84,
LV95,
singleCoordinateInsideLV95
)
const overlappingExtent: FlatExtent = [0, 0, ...singleCoordinateInsideLV95]
const result = getExtentIntersectionWithCurrentProjection(
overlappingExtent,
WGS84,
LV95
)
expect(result).to.be.an('Array').lengthOf(4)
expectExtentIs(result!, [...LV95.bounds.bottomLeft, ...singleCoordinateInLV95])
})
})
})
Loading
Loading