Skip to content

Commit

Permalink
Merge pull request #7 from josteinl/feature/add_swedish_coordinates
Browse files Browse the repository at this point in the history
Add Swedish projections SWEREF99 with EPSG SRID 3006 to 3018
  • Loading branch information
josteinl committed Jan 18, 2024
2 parents 98e1fe2 + 530f92f commit 93daf05
Show file tree
Hide file tree
Showing 9 changed files with 715 additions and 437 deletions.
8 changes: 2 additions & 6 deletions .github/workflows/branch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,8 @@ jobs:
poetry-version: ${{ matrix.poetry-version }}
- name: Install dependencies
run: poetry install
- name: Run black
run: poetry run black . --check
# - name: Run isort
# run: poetry run isort . --check-only --profile black
# - name: Run flake8
# run: poetry run flake8 .
- name: Run ruff
run: poetry run ruff check .
- name: Run mypy
run: poetry run mypy .
- name: Run bandit
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
fail-fast: false
matrix:
python-version: ['3.11']
poetry-version: ['1.6.1']
poetry-version: ['1.7.1']
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
Expand Down
8 changes: 8 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# NGI Python Coordinate Projector Package

_2024-01-15_

Version 0.0.10

Add

- Swedish projections SWEREF99 with EPSG SRID 3006 to 3018.

_2023-08-24_

Version 0.0.9
Expand Down
847 changes: 430 additions & 417 deletions poetry.lock

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ exclude = '''

[tool.poetry]
name = "coordinate-projector"
version = "0.0.9"
version = "0.0.10"
description = "Project points from one projection to another using pyproj"
license = "MIT"
authors = ["Helge Smebye", "Jostein Leira <jostein@leira.net>"]
Expand All @@ -38,10 +38,12 @@ packages = [
line-length = 120
src = ["src", "tests"]

[tool.ruff.per-file-ignores]
"__init__.py" = ["F401"]

[tool.poetry.dependencies]
python = ">=3.9,<4"
pyproj = "^3.5.0"
pyproj = "^3.6.1"
python-dateutil = "^2.8.2"
types-python-dateutil = "^2.8.19"
timezonefinder = "*"
Expand Down
25 changes: 15 additions & 10 deletions src/coordinate_projector/datetime_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@
from dateutil import tz
from timezonefinder import TimezoneFinder

from coordinate_projector import Projector
from coordinate_projector.projector import Projector

projector = Projector()

_time_zone_finder = TimezoneFinder()
_time_zone_finder: TimezoneFinder | None = None


def ensure_tz(
dt: Optional[datetime],
longitude: Optional[float] = None,
latitude: Optional[float] = None,
srid: int = 4326,
dt: Optional[datetime],
longitude: Optional[float] = None,
latitude: Optional[float] = None,
srid: int = 4326,
) -> Optional[datetime]:
"""
Return passed datetime dt enriched with timezone.
Expand All @@ -31,6 +31,8 @@ def ensure_tz(
If no location or timezone is provided, then assume the passed datetime is
recorded in the norwegian timezone.
"""
global _time_zone_finder

if not dt:
return dt

Expand All @@ -46,6 +48,9 @@ def ensure_tz(
longitude, latitude = projector.transform(from_srid=srid, to_srid=4326, east=longitude, north=latitude)

# find timezone from position
if not _time_zone_finder:
_time_zone_finder = TimezoneFinder()

input_timezone = tz.gettz(_time_zone_finder.timezone_at(lng=longitude, lat=latitude))
else:
# Assume Norway
Expand All @@ -57,10 +62,10 @@ def ensure_tz(


def datetime_to_json(
dt: Optional[datetime],
longitude: Optional[float] = None,
latitude: Optional[float] = None,
srid: int = 4326,
dt: Optional[datetime],
longitude: Optional[float] = None,
latitude: Optional[float] = None,
srid: int = 4326,
) -> Optional[str]:
"""
Return passed datetime.datetime as json-formatted (iso-8601) string with UTC timezone. Sub-second time information
Expand Down
117 changes: 117 additions & 0 deletions src/coordinate_projector/projections.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,123 @@
"data": "+proj=utm +zone=36 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"
}
},
"3006": {
"srid": 3006,
"name": "SWEREF99 TM",
"shortname": "SWEREF99 TM",
"definition": {
"name": "EPSG:3006",
"data": "+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"
}
},
"3007": {
"srid": 3007,
"name": "SWEREF99 12 00",
"shortname": "SWEREF99 12 00",
"definition": {
"name": "EPSG:3007",
"data": "+proj=tmerc +lat_0=0 +lon_0=12 +k=1 +x_0=150000 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"
}
},
"3008": {
"srid": 3008,
"name": "SWEREF99 13 30",
"shortname": "SWEREF99 13 30",
"definition": {
"name": "EPSG:3008",
"data": "+proj=tmerc +lat_0=0 +lon_0=13.5 +k=1 +x_0=150000 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"
}
},
"3009": {
"srid": 3009,
"name": "SWEREF99 15 00",
"shortname": "SWEREF99 15 00",
"definition": {
"name": "EPSG:3009",
"data": "+proj=tmerc +lat_0=0 +lon_0=15 +k=1 +x_0=150000 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"
}
},
"3010":{
"srid": 3010,
"name": "SWEREF99 16 30",
"shortname": "SWEREF99 16 30",
"definition": {
"name": "EPSG:3010",
"data": "+proj=tmerc +lat_0=0 +lon_0=16.5 +k=1 +x_0=150000 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"
}
},
"3011": {
"srid": 3011,
"name": "SWEREF99 18 00",
"shortname": "SWEREF99 18 00",
"definition": {
"name": "EPSG:3011",
"data": "+proj=tmerc +lat_0=0 +lon_0=18 +k=1 +x_0=150000 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"
}
},
"3012": {
"srid": 3012,
"name": "SWEREF99 14 15",
"shortname": "SWEREF99 14 15",
"definition": {
"name": "EPSG:3012",
"data": "+proj=tmerc +lat_0=0 +lon_0=14.25 +k=1 +x_0=150000 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"
}
},
"3013": {
"srid": 3013,
"name": "SWEREF99 15 45",
"shortname": "SWEREF99 15 45",
"definition": {
"name": "EPSG:3013",
"data": "+proj=tmerc +lat_0=0 +lon_0=15.75 +k=1 +x_0=150000 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"
}
},
"3014": {
"srid": 3014,
"name": "SWEREF99 17 15",
"shortname": "SWEREF99 17 15",
"definition": {
"name": "EPSG:3014",
"data": "+proj=tmerc +lat_0=0 +lon_0=17.25 +k=1 +x_0=150000 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"
}
},
"3015": {
"srid": 3015,
"name": "SWEREF99 18 45",
"shortname": "SWEREF99 18 45",
"definition": {
"name": "EPSG:3015",
"data": "+proj=tmerc +lat_0=0 +lon_0=18.75 +k=1 +x_0=150000 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"
}
},
"3016": {
"srid": 3016,
"name": "SWEREF99 20 15",
"shortname": "SWEREF99 20 15",
"definition": {
"name": "EPSG:3016",
"data": "+proj=tmerc +lat_0=0 +lon_0=20.25 +k=1 +x_0=150000 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"
}
},
"3017": {
"srid": 3017,
"name": "SWEREF99 21 45",
"shortname": "SWEREF99 21 45",
"definition": {
"name": "EPSG:3017",
"data": "+proj=tmerc +lat_0=0 +lon_0=21.75 +k=1 +x_0=150000 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"
}
},
"3018": {
"srid": 3018,
"name": "SWEREF99 23 15",
"shortname": "SWEREF99 23 15",
"definition": {
"name": "EPSG:3018",
"data": "+proj=tmerc +lat_0=0 +lon_0=23.25 +k=1 +x_0=150000 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"
}
},
"3857": {
"srid": 3857,
"name": "WGS 84 / Pseudo-Mercator",
Expand Down
5 changes: 4 additions & 1 deletion tests/test_projector.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from coordinate_projector import Projector
from coordinate_projector.projector import Projector
from data.coords import Coords
from data.coords import ProjSets

Expand Down Expand Up @@ -90,3 +90,6 @@ def test_get_supported_projections(self):
assert "4326" in supported_projections
assert "5130" in supported_projections
assert "5105" in supported_projections
assert "3006" in supported_projections
assert "3010" in supported_projections
assert "3018" in supported_projections
134 changes: 134 additions & 0 deletions tests/test_sweref99.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import pytest

from coordinate_projector.projector import Projector


# Assumption that the SWEREF99 is the same as WGS84
WGS84 = 4326
SWEREF99TM = 3006
SWEREF99_12_00 = 3007
SWEREF99_13_30 = 3008
SWEREF99_15_00 = 3009
SWEREF99_16_30 = 3010
SWEREF99_18_00 = 3011
SWEREF99_14_15 = 3012
SWEREF99_15_45 = 3013
SWEREF99_17_15 = 3014
SWEREF99_18_45 = 3015
SWEREF99_20_15 = 3016
SWEREF99_21_45 = 3017
SWEREF99_23_15 = 3018


@pytest.mark.parametrize(
"latitude, longitude, to_srid, expected_northing, expected_easting",
(
(55, 12.75, SWEREF99TM, 6097106.672, 356083.438),
(55, 14.25, SWEREF99TM, 6095048.642, 452024.069),
(57, 12.75, SWEREF99TM, 6319636.937, 363331.554),
(57, 19.5, SWEREF99TM, 6326392.707, 773251.054),
(59, 11.25, SWEREF99TM, 6546096.724, 284626.066),
(59, 19.5, SWEREF99TM, 6548757.206, 758410.519),
(61, 12.75, SWEREF99TM, 6764877.311, 378323.440),
(61, 18.75, SWEREF99TM, 6768593.345, 702745.127),
(63, 12, SWEREF99TM, 6989134.048, 348083.148),
(63, 19.5, SWEREF99TM, 6993565.630, 727798.671),
(65, 13.5, SWEREF99TM, 7209293.753, 429270.201),
(65, 21.75, SWEREF99TM, 7225449.115, 817833.405),
(67, 16.5, SWEREF99TM, 7432168.174, 565398.458),
(67, 24, SWEREF99TM, 7459745.672, 891298.142),
(69, 21, SWEREF99TM, 7666089.698, 739639.195),
(57, 11.25, SWEREF99_12_00, 6320164.077, 104421.390),
(59, 11.25, SWEREF99_12_00, 6542910.921, 106894.103),
(57, 12.75, SWEREF99_12_00, 6320164.077, 195578.610),
(59, 12.75, SWEREF99_12_00, 6542910.921, 193105.897),
(55, 12.75, SWEREF99_13_30, 6097487.637, 102004.871),
(57, 12.75, SWEREF99_13_30, 6320164.077, 104421.390),
(59, 12.75, SWEREF99_13_30, 6542910.921, 106894.103),
(61, 12.75, SWEREF99_13_30, 6765725.847, 109420.005),
(63, 12.75, SWEREF99_13_30, 6988606.198, 111996.020),
(55, 14.25, SWEREF99_13_30, 6097487.637, 197995.129),
(57, 14.25, SWEREF99_13_30, 6320164.077, 195578.610),
(59, 14.25, SWEREF99_13_30, 6542910.921, 193105.897),
(61, 14.25, SWEREF99_13_30, 6765725.847, 190579.995),
(63, 12, SWEREF99_14_15, 6990379.288, 36003.367),
(65, 13.5, SWEREF99_14_15, 7211548.993, 114619.001),
(63, 15, SWEREF99_14_15, 6988606.198, 188003.980),
(65, 15, SWEREF99_14_15, 7211548.993, 185380.999),
# SWEREF 99 SWEREF 99 15 00
(55, 14.25, SWEREF99_15_00, 6097487.637, 102004.871),
(57, 14.25, SWEREF99_15_00, 6320164.077, 104421.390),
(59, 14.25, SWEREF99_15_00, 6542910.921, 106894.103),
(61, 14.25, SWEREF99_15_00, 6765725.847, 109420.005),
(57, 15.75, SWEREF99_15_00, 6320164.077, 195578.610),
(59, 15.75, SWEREF99_15_00, 6542910.921, 193105.897),
(61, 15.75, SWEREF99_15_00, 6765725.847, 190579.995),
# SWEREF 99 SWEREF 99 15 45
(63, 15.00, SWEREF99_15_45, 6988606.198, 111996.020),
(65, 15.00, SWEREF99_15_45, 7211548.993, 114619.001),
(67, 15.00, SWEREF99_15_45, 7434550.943, 117285.739),
(63, 16.50, SWEREF99_15_45, 6988606.198, 188003.980),
(65, 16.50, SWEREF99_15_45, 7211548.993, 185380.999),
(67, 16.50, SWEREF99_15_45, 7434550.943, 182714.261),
# SWEREF 99 SWEREF 99 16 30
(57, 15.75, SWEREF99_16_30, 6320164.077, 104421.390),
(59, 15.75, SWEREF99_16_30, 6542910.921, 106894.103),
(61, 15.75, SWEREF99_16_30, 6765725.847, 109420.005),
(63, 15.75, SWEREF99_16_30, 6988606.198, 111996.020),
(57, 17.25, SWEREF99_16_30, 6320164.077, 195578.610),
(59, 17.25, SWEREF99_16_30, 6542910.921, 193105.897),
(61, 17.25, SWEREF99_16_30, 6765725.847, 190579.995),
(63, 17.25, SWEREF99_16_30, 6988606.198, 188003.980),
# SWEREF 99 SWEREF 99 17 15
(63, 16.50, SWEREF99_17_15, 6988606.198, 111996.020),
(65, 16.50, SWEREF99_17_15, 7211548.993, 114619.001),
(67, 16.50, SWEREF99_17_15, 7434550.943, 117285.739),
(63, 18.00, SWEREF99_17_15, 6988606.198, 188003.980),
(65, 18.00, SWEREF99_17_15, 7211548.993, 185380.999),
(67, 18.00, SWEREF99_17_15, 7434550.943, 182714.261),
# SWEREF 99 SWEREF 99 18 00
(59, 17.25, SWEREF99_18_00, 6542910.921, 106894.103),
(61, 17.25, SWEREF99_18_00, 6765725.847, 109420.005),
(59, 18.75, SWEREF99_18_00, 6542910.921, 193105.897),
(61, 18.75, SWEREF99_18_00, 6765725.847, 190579.995),
# SWEREF 99 SWEREF 99 18 45
(57, 18, SWEREF99_18_45, 6320164.077, 104421.390),
(59, 18, SWEREF99_18_45, 6542910.921, 106894.103),
(63, 18, SWEREF99_18_45, 6988606.198, 111996.020),
(65, 18, SWEREF99_18_45, 7211548.993, 114619.001),
(67, 18, SWEREF99_18_45, 7434550.943, 117285.739),
(57, 19.5, SWEREF99_18_45, 6320164.077, 195578.610),
(59, 19.5, SWEREF99_18_45, 6542910.921, 193105.897),
(63, 19.5, SWEREF99_18_45, 6988606.198, 188003.980),
(65, 19.5, SWEREF99_18_45, 7211548.993, 185380.999),
(67, 19.5, SWEREF99_18_45, 7434550.943, 182714.261),
# SWEREF 99 SWEREF 99 20 15
(63, 19.5, SWEREF99_20_15, 6988606.198, 111996.020),
(65, 19.5, SWEREF99_20_15, 7211548.993, 114619.001),
(67, 19.5, SWEREF99_20_15, 7434550.943, 117285.739),
(69, 19.5, SWEREF99_20_15, 7657608.465, 119992.964),
(65, 21, SWEREF99_20_15, 7211548.993, 185380.999),
(67, 21, SWEREF99_20_15, 7434550.943, 182714.261),
(69, 21, SWEREF99_20_15, 7657608.465, 180007.036),
# SWEREF 99 SWEREF 99 21 45
(65, 21, SWEREF99_21_45, 7211548.993, 114619.001),
(67, 21, SWEREF99_21_45, 7434550.943, 117285.739),
(65, 22.5, SWEREF99_21_45, 7211548.993, 185380.999),
(67, 22.5, SWEREF99_21_45, 7434550.943, 182714.261),
# SWEREF 99 SWEREF 99 23 15
(65, 22.5, SWEREF99_23_15, 7211548.993, 114619.001),
(67, 22.5, SWEREF99_23_15, 7434550.943, 117285.739),
(65, 24, SWEREF99_23_15, 7211548.993, 185380.999),
(67, 24, SWEREF99_23_15, 7434550.943, 182714.261),
),
)
def test_sweref99(latitude, longitude, to_srid, expected_northing, expected_easting):
"""
Test data above taken from:
https://www.lantmateriet.se/contentassets/a7ddfc3b7821498da8b55cd3f71b5150/kontrollpunkter_sweref99tm.pdf
https://www.lantmateriet.se/contentassets/a7ddfc3b7821498da8b55cd3f71b5150/kontrollpunkter_sweref99proj.pdf
"""
projector = Projector()
easting, northing = projector.transform(from_srid=WGS84, to_srid=to_srid, east=longitude, north=latitude)
assert easting == pytest.approx(expected_easting)
assert northing == pytest.approx(expected_northing)

0 comments on commit 93daf05

Please sign in to comment.