Skip to content

Commit

Permalink
Merge pull request #70 from semuconsulting/RC-1.0.44
Browse files Browse the repository at this point in the history
RC 1.0.44
semuadmin authored Jan 4, 2025
2 parents f596ad1 + 1aa5374 commit 82cbdb5
Showing 5 changed files with 83 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -298,6 +298,7 @@ b'$EIGNQ,RMC*24\r\n'

- `latlon2dms` - converts decimal lat/lon to degrees, minutes, decimal seconds format e.g. "53°20′45.6″N", "2°32′46.68″W"
- `latlon2dmm` - converts decimal lat/lon to degrees, decimal minutes format e.g. "53°20.76′N", "2°32.778′W"
- `dms2deg` - converts lat/lon in d.m(.s) string format to signed decimal degrees e.g. "51°20′45.6″S" -> -51.346
- `llh2iso6709` - converts lat/lon and altitude (hMSL) to ISO6709 format e.g. "+27.5916+086.5640+8850CRSWGS_84/"
- `ecef2llh` - converts ECEF (X, Y, Z) coordinates to geodetic (lat, lon, ellipsoidal height) coordinates
- `llh2ecef` - converts geodetic (lat, lon, ellipsoidal height) coordinates to ECEF (X, Y, Z) coordinates
6 changes: 6 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# pynmeagps Release Notes

### RELEASE 1.0.44

ENHANCEMENTS:

1. dms2deg helper method added to convert d.m.s or d.m to d.dd format.

### RELEASE 1.0.43

ENHANCEMENTS:
2 changes: 1 addition & 1 deletion src/pynmeagps/_version.py
Original file line number Diff line number Diff line change
@@ -8,4 +8,4 @@
:license: BSD 3-Clause
"""

__version__ = "1.0.43"
__version__ = "1.0.44"
38 changes: 38 additions & 0 deletions src/pynmeagps/nmeahelpers.py
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@

# pylint: disable=invalid-name

import re
from datetime import datetime
from math import acos, asin, atan2, cos, pi, sin, sqrt

@@ -346,6 +347,43 @@ def deg2dmm(degrees: float, att: str) -> str:
return ""


def dms2deg(
dmsstr: str,
rnd: int = 7,
) -> float:
"""
Convert degrees, minutes, seconds string to decimal degrees.
Expects degrees and (optional) minutes and seconds to be delimited by
non-numeric char, e.g.
'51°20′45.6″N' -> 51.346
'51°30.0′' -> 51.5
:param str dmsstr: d,m,s string
:param int rnd: decimal places (7)
:return: degrees as d.dd
:rtype: float
:raises: ValueError if invalid dms string format
"""

if (
re.match(
r"^([\d.]+[^\d.]{1}){1}([\d.]+[^\d.]{1})?([\d.]+[^\d.]{1})?[NSEW]?$", dmsstr
)
is None
):
raise ValueError(f"Invalid dms string format {dmsstr}")

sign = -1 if dmsstr.find("S") >= 0 or dmsstr.find("W") >= 0 else 1
dms = re.split(r"[^\d.]", dmsstr, maxsplit=3)
ddd = 0.0
for x in range(len(dms) - 1):
ddd += 0.0 if dms[x] == "" else float(dms[x]) / pow(60, x)
return round(ddd * sign, rnd)


def llh2iso6709(lat: float, lon: float, alt: float, crs: str = WGS84) -> str:
"""
Convert decimal degrees and alt to ISO6709 format
37 changes: 37 additions & 0 deletions tests/test_static.py
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@
deg2dmm,
deg2dms,
dmm2ddd,
dms2deg,
ecef2llh,
generate_checksum,
get_gpswnotow,
@@ -161,6 +162,42 @@ def testDDD2DMM_HPMode(self): # high precision mode
res = ddd2dmm("", "LN", True)
self.assertEqual(res, "")

def testDMS2DEG(self):
res = dms2deg("51°20′45.6″N")
self.assertEqual(res, 51.346)
self.assertEqual(deg2dms(res, "LA"), "51°20′45.6″N")
res = dms2deg("51°30′0.0″N")
self.assertEqual(res, 51.5)
self.assertEqual(deg2dms(res, "LA"), "51°30′0.0″N")
res = dms2deg("51°30.00′")
self.assertEqual(res, 51.5)
self.assertEqual(deg2dms(res, "LA"), "51°30′0.0″N")
res = dms2deg("2°20′45.6″W")
self.assertEqual(res, -2.346)
self.assertEqual(deg2dms(res, "LN"), "2°20′45.6″W")
res = dms2deg("33°45′0.0″S")
self.assertEqual(res, -33.75)
self.assertEqual(deg2dms(res, "LA"), "33°45′0.0″S")
res = dms2deg("33°45′N")
self.assertEqual(res, 33.75)
self.assertEqual(deg2dms(res, "LN"), "33°45′0.0″E")
res = dms2deg("33°45.3564′N")
self.assertEqual(res, 33.75594)
self.assertEqual(deg2dms(res, "LA"), "33°45′21.384″N")
res = dms2deg("28°S")
self.assertEqual(res, -28.0)
self.assertEqual(deg2dms(res, "LA"), "28°0′0.0″S")
res = dms2deg("45.1234°")
self.assertEqual(res, 45.1234)
with self.assertRaises(ValueError) as context:
res = dms2deg("51°°20′45.6″")
with self.assertRaises(ValueError) as context:
res = dms2deg("51°20′45.6″Z")
with self.assertRaises(ValueError) as context:
res = dms2deg("51°20′45.6″34.25`N")
with self.assertRaises(ValueError) as context:
res = dms2deg("xx°yy′zz.6″N")

def testDate2UTC(self):
res = date2utc("")
self.assertEqual(res, "")

0 comments on commit 82cbdb5

Please sign in to comment.