Closes gh-31 Fix decimal to degree, minute, second conversion by making seconds more precice and supporting negative values
This commit is contained in:
parent
c4e817bde8
commit
f1787d5a16
|
@ -12,13 +12,11 @@ from elodie import constants
|
||||||
|
|
||||||
class Fraction(fractions.Fraction):
|
class Fraction(fractions.Fraction):
|
||||||
"""Only create Fractions from floats.
|
"""Only create Fractions from floats.
|
||||||
|
|
||||||
>>> Fraction(0.3)
|
>>> Fraction(0.3)
|
||||||
Fraction(3, 10)
|
Fraction(3, 10)
|
||||||
>>> Fraction(1.1)
|
>>> Fraction(1.1)
|
||||||
Fraction(11, 10)
|
Fraction(11, 10)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __new__(cls, value, ignore=None):
|
def __new__(cls, value, ignore=None):
|
||||||
"""Should be compatible with Python 2.6, though untested."""
|
"""Should be compatible with Python 2.6, though untested."""
|
||||||
return fractions.Fraction.from_float(value).limit_denominator(99999)
|
return fractions.Fraction.from_float(value).limit_denominator(99999)
|
||||||
|
@ -47,28 +45,20 @@ def coordinates_by_name(name):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def decimal_to_dms(decimal):
|
def decimal_to_dms(decimal):
|
||||||
"""Convert decimal degrees into degrees, minutes, seconds.
|
# if decimal is negative we need to make the degrees and minutes negative also
|
||||||
|
sign = 1
|
||||||
|
if(decimal < 0):
|
||||||
|
sign = -1
|
||||||
|
|
||||||
|
|
||||||
>>> decimal_to_dms(50.445891)
|
|
||||||
[Fraction(50, 1), Fraction(26, 1), Fraction(113019, 2500)]
|
|
||||||
>>> decimal_to_dms(-125.976893)
|
|
||||||
[Fraction(125, 1), Fraction(58, 1), Fraction(92037, 2500)]
|
|
||||||
"""
|
|
||||||
# @TODO figure out a better and more proper way to do seconds
|
|
||||||
degrees = int(decimal)
|
degrees = int(decimal)
|
||||||
subminutes = abs((decimal - int(decimal)) * 60)
|
subminutes = abs((decimal - int(decimal)) * 60)
|
||||||
minutes = int(subminutes)
|
minutes = int(subminutes) * sign
|
||||||
subseconds = abs((subminutes - int(subminutes)) * 60)
|
subseconds = abs((subminutes - int(subminutes)) * 60) * sign
|
||||||
return (pyexiv2.Rational(degrees, 1), pyexiv2.Rational(minutes, 1), pyexiv2.Rational(subseconds, 1))
|
subseconds_fraction = Fraction(subseconds)
|
||||||
|
return (pyexiv2.Rational(degrees, 1), pyexiv2.Rational(minutes, 1), pyexiv2.Rational(subseconds_fraction.numerator, subseconds_fraction.denominator))
|
||||||
|
|
||||||
def dms_to_decimal(degrees, minutes, seconds, sign=' '):
|
def dms_to_decimal(degrees, minutes, seconds, sign=' '):
|
||||||
"""Convert degrees, minutes, seconds into decimal degrees.
|
|
||||||
|
|
||||||
>>> dms_to_decimal(10, 10, 10)
|
|
||||||
10.169444444444444
|
|
||||||
>>> dms_to_decimal(8, 9, 10, 'S')
|
|
||||||
-8.152777777777779
|
|
||||||
"""
|
|
||||||
return (-1 if sign[0] in 'SWsw' else 1) * (
|
return (-1 if sign[0] in 'SWsw' else 1) * (
|
||||||
float(degrees) +
|
float(degrees) +
|
||||||
float(minutes) / 60 +
|
float(minutes) / 60 +
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# Project imports
|
# Project imports
|
||||||
import os
|
import os
|
||||||
import sys
|
import random
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))))
|
sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))))
|
||||||
|
|
||||||
|
@ -12,9 +12,16 @@ from elodie import geolocation
|
||||||
os.environ['TZ'] = 'GMT'
|
os.environ['TZ'] = 'GMT'
|
||||||
|
|
||||||
def test_decimal_to_dms():
|
def test_decimal_to_dms():
|
||||||
target_decimal_value = 37.383336725
|
|
||||||
|
|
||||||
dms = geolocation.decimal_to_dms(target_decimal_value)
|
for x in range(0, 1000):
|
||||||
check_value = dms[0].to_float() + dms[1].to_float() / 60 + dms[2].to_float() / 3600
|
target_decimal_value = random.uniform(0.0, 180.0)
|
||||||
|
if(x % 2 == 1):
|
||||||
|
target_decimal_value = target_decimal_value * -1
|
||||||
|
|
||||||
assert target_decimal_value == check_value, '%s does not match %s' % (check_value, target_decimal_value)
|
dms = geolocation.decimal_to_dms(target_decimal_value)
|
||||||
|
check_value = dms[0].to_float() + dms[1].to_float() / 60 + dms[2].to_float() / 3600
|
||||||
|
|
||||||
|
target_decimal_value = round(target_decimal_value, 8)
|
||||||
|
check_value = round(check_value, 8)
|
||||||
|
|
||||||
|
assert target_decimal_value == check_value, '%s does not match %s' % (check_value, target_decimal_value)
|
||||||
|
|
Loading…
Reference in New Issue