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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user