Giter Site home page Giter Site logo

latlon's Introduction

Features

Methods for representing geographic coordinates (latitude and longitude) including the ability to:

  • Convert lat/lon strings from almost any format into a LatLon object (analogous to the datetime library’s stptime method)
  • Automatically store decimal degrees, decimal minutes, and degree, minute, second information in a LatLon object
  • Output lat/lon information into a formatted string (analogous to the datetime library’s strftime method)
  • Project lat/lon coordinates into some other proj projection
  • Calculate distance and heading between lat/lon pairs using either the FAI or WGS84 approximation
  • Create a new LatLon object by offsetting an initial coordinate by a distance and heading
  • Subtracting one LatLon object from another creates a GeoVector object with distance and heading attributes (analogous to the datetime library’s timedelta object)
  • Adding or subtracting a Latlon object and a GeoVector object creates a new LatLon object with the coordinates adjusted by the GeoVector object’s distance and heading
  • GeoVector objects can be added, subtracted, multiplied or divided

Installation

LatLon has only been tested in Python 2.7, 3.6, 3.7

Installation through pip:

$ pip install latlon3

Requires the following non-standard libraries:

  • pyproj

Module import

import latlon

Subclasses described in README can be found under the latlon module.

Usage Notes

Usage of LatLon is primarily through the class LatLon, which is designed to hold a single pair of Latitude and Longitude objects. Strings can be converted to LatLon objects using the method string2latlon, and to Latitude or Longitude objects using string2geocoord. Alternatively, a LatLon object can be constructed by subtracting two LatLon objects, or adding or subtracting a Latlon object and a GeoVector object.

Latitude or Longitude Construction

Latitude of longitude construction is through the classes Latitude and Longitude, respectively. You can pass a latitude or longitude coordinate in any combination of decimal degrees, degrees and minutes, or degrees minutes and seconds. Alternatively, you can pass a formatted string using the function string2geocoord for a string containing a single latitude or longitude, or string2latlon for a pair of strings representing the latitude and longitude.

String formatting:

string2latlon and string2geocoord both take a formatter string which is loosely modeled on the format keyword used in datetime’s strftime function. Indicator characters (e.g. H or D) are placed between a specific separator character (%) to specify the way in which a coordinate string is formatted. Possible values are as follows:

  • H is a hemisphere identifier (e.g. N, S, E or W)
  • D is a coordinate in decimal degrees notation (e.g. 5.833)
  • d is a coordinate in degrees notation (e.g. 5)
  • M is a coordinate in decimal minutes notation (e.g. 54.35)
  • m is a coordinate in minutes notation (e.g. 54)
  • S is a coordinate in seconds notation (e.g. 28.93)
  • Any other characters (e.g. ‘ ‘ or ‘, ‘) will be treated as a separator between the above components.
  • All components should be separated by the % character. For example, if the coord_str is ‘5, 52, 59.88_N’, the format_str would be ‘d%, %m%, %S%_%H’
Important

One format that will not currently work is one where the hemisphere identifier and a degree or decimal degree are not separated by any characters. For example ‘5 52 59.88 N’ is valid whereas ‘5 52 59.88N’ is not.

String output:

Both LatLon and Latitude and Longitude objects include a to_string() method for outputting a formatted coordinate.

Projection:

Use LatLon.project to transform geographical coordinates into a chosen projection. Requires that you pass it a pyproj or basemap projection.

Distance and Heading Calculation:

LatLon objects have a distance() method which accepts a 2nd LatLon object as an argument. distance() will calculate the great-circle distance between the two coordinates using the WGS84 ellipsoid by default. To use the more approximate FAI sphere, set ellipse to ‘sphere’. Initial and reverse headings (in degrees) can be calculated in a similar way using the heading_initial() and heading_reverse() methods. Alternatively, subtracting one LatLon object from another will return a GeoVector object with the attributes heading and distance.

Creating a New LatLon Object by Offset from Another One:

Use the offset() method of LatLon objects, which takes an initial heading (in degrees) and distance (in km) to return a new LatLon object at the offset coordinates. Also, you can perform the same operation by adding or subtracting a LatLon object with a GeoVector object.

Examples

Create a LatLon object from coordinates:

>> palmyra = LatLon(Latitude(5.8833), Longitude(-162.0833)) # Location of Palmyra Atoll in decimal degrees
>> palmyra = LatLon(5.8833, -162.0833) # Same thing but simpler!
>> palmyra = LatLon(Latitude(degree = 5, minute = 52, second = 59.88),
>>                  Longitude(degree = -162, minute = -4.998) # or more complicated!
>> print(palmyra.to_string('d% %m% %S% %H')) # Print coordinates to degree minute second
('5 52 59.88 N', '162 4 59.88 W')

Create a Latlon object from a formatted string:

>> palmyra = string2latlon('5 52 59.88 N', '162 4 59.88 W', 'd% %m% %S% %H')
>> print(palmyra.to_string('d%_%M')) # Print coordinates as degree minutes separated by underscore
('5_52.998', '-162_4.998')

Perform some calculations:

>> palmyra = LatLon(Latitude(5.8833), Longitude(-162.0833)) # Location of Palmyra Atoll
>> honolulu = LatLon(Latitude(21.3), Longitude(-157.8167)) # Location of Honolulu, HI
>> distance = palmyra.distance(honolulu) # WGS84 distance in km
>> print distance
1766.69130376
>> print(palmyra.distance(honolulu, ellipse = 'sphere')) # FAI distance in km
1774.77188181
>> initial_heading = palmyra.heading_initial(honolulu) # Heading from Palmyra to Honolulu on WGS84 ellipsoid
>> print(initial_heading)
14.6907922022
>> hnl = palmyra.offset(initial_heading, distance) # Reconstruct Honolulu based on offset from Palmyra
>> print(hnl.to_string('D')) # Coordinates of Honolulu
('21.3', '-157.8167')

Manipulate LatLon objects using GeoVectors:

>> vector = (honolulu - palmyra) * 2 # A GeoVector with 2x the magnitude of a vector from palmyra to honolulu
>> print(vector) # Print heading and magnitude
14.6907922022 3533.38260751
print(palmyra + (vector/2.0)) # Recreate the coordinates of Honolulu by adding half of vector to palmyra
21.3, -157.8167

Version

1.0.4 - Tested on Python 3.7 with Eclipse IDLE. Please let me know of any issues.

Changelog

1.0.4 (August/10/2021)
  • Replaced with setuptools in distutils during python packaging.
  • The angle information was initialized when the GeoCord class was initialized.
  • The function removed from Python 3 was added separately for compatibility with Python 2.
  • In addition, we renamed the modules being imported from lat_lon to latlon and improved the test program to work with both Pythons 2 and 3.
1.0.3 (June/16/2019)
  • Support for Python 2.7 and Python 3
1.0.2 (OCTOBER/14/2014)
  • Class GeoVector is now an abstract class to ensure that any subclasses use the correct API
  • Added methods range180 and range360 to class Longitude to interconvert between longitudes reported -180 to 180 format and those reported in 0 to 360 format. To ensure that all operations such as hemisphere assignment work as expected, longitudes reported in 0 to 360 format are automatically converted into -180 to 180 format when the Longitude object is initialized.
1.0.1 (SEPTEMBER/2/2014)
  • Fixed issue with where attribute theta in GeoVector was treated in some cases like a heading (i.e. starting with due north and continuing clockwise) even though it was in fact an angle (i.e. starting with (1, 0) and continuing anti-clockwise). The attribute name has now been changed to heading to eliminate confusion. The local variable theta is used for computations involving angle.
  • Added testing functions with pytest for class LatLon and GeoVector
  • Added almost_equal methods to class LatLon and GeoVector to deal with float errors in decimal degree specification
  • LatLon.project now returns (x, y) instead of (y, x) to be more consistent with the accepted convention.
0.91 (AUGUST/28/2014)
  • degree, minute and second attributes for GeoCoord class are now coerced to type float
0.90 (AUGUST/28/2014)
  • Updated magic methods for GeoCoord class
  • Added option for instantiating LatLon from scalars
0.80 (AUGUST/27/2014)
  • Added GeoVector class to handle vectors between two LatLon objects
  • Cleaned up str and repr methods for LatLon, Latitude, Longitude, GeoCoord, and GeoVector classes
0.70 (AUGUST/27/2014)
  • Deprecated LatLon.distance_sphere method. From now on use distance(other, ellipse = ‘sphere’) instead
  • Added LatLon.bearing method to return the initial bearing between two LatLon objects
  • Added LatLon.offset method to return a new LatLon object that is computed from an initial LatLon object plus a bearing and distance
0.60 (AUGUST/27/2014)
  • Added compatibility with comparison, negation, addition and multiplication magic methods
0.50 (AUGUST/20/2014)
  • First release

latlon's People

Contributors

search5 avatar swidch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

latlon's Issues

README.md - can't copy-paste the examples

Make it so that all the examples will run after being copy-pasted:

  1. Add the required import, e.g. from latlon import LatLon, Latitude, Longitude.
  2. Remove >> from the beginning of the code.
  3. Add the occasional missing bracket.
  4. Separate the program from the expected output.

Limit decimal digits

I'm working with latitudes and longitudes in SeeYou CUP format. This is a simple CSV format, but with a somewhat specific DDMM.MMM latitude and longitude format.

For example:

name,code,country,lat,lon,elev,style,rwdir,rwlen,rwwidth,freq,desc,userdata,pics
"Wycombe Air Park - Booker","EGTB",GB,5136.684N,00048.479W,156m,5,,,,

Within this, the lat field is encoded:

Latitude is a field of length 9, where 1-2 characters are degrees, 3-4 characters are minutes, 5 decimal point,
6-8 characters are decimal minutes and 9th character is either N or S. The ellipsoid used is WGS-1984

Char 0 Char 1 Char 2 Char 3 Char 4 Char 5 Char 6 Char 7 Char 8
5 1 0 7 . 8 3 0 N | S
$10^1$ Degrees $10^0$ Degrees $10^1$ Minutes $10^0$ Minutes . $10^{-1}$ Minutes $10^{-2}$ Minutes $10^{-3}$ Minutes N | S

I can get very close to what I want, but end up with excessive decimal digits:

>>> latlon.LatLon(51.61140,-0.80798).to_string('%d%%M%%H%')
('5136.6840000000002N', '048.47879999999918W')

Even the example in latlon.py#L123 gives me similar behaviour:

>>> palmyra = LatLon(5.8833, -162.0833)
>>> palmyra.to_string('D')
('5.8833', '-162.0833')
>>> palmyra.to_string('H% %D')
('N 5.8833', 'W 162.0833')
>>> palmyra.to_string('d%_%M')
('5_52.99800000000001', '-162_4.998000000000502')

It would be great if there were a way to specify the number of digits in the format string, and also leading zeros.

Test for equality fails.

from latlon import LatLon, Latitude, Longitude

palmyra_1 = LatLon(Latitude(5.8833), Longitude(-162.0833))
palmyra_2 = LatLon(5.8833, -162.0833)
assert palmyra_1 == palmyra_2
palmyra_3 = LatLon(Latitude(degree=5, minute=52, second=59.88), Longitude(degree=-162, minute=-4.998)) 
assert palmyra_2 == palmyra_3

AssertionError

Data not stored correctly in python 3.9

There seems to be a problem in python 3.9 (tested on mac)

palmyra = LatLon(Latitude(degree = 5, minute = 52, second = 59.88),
Longitude(degree = -162, minute = -4.998))
print(palmyra.to_string('d% %m% %S% %H'))

Output:
('5 52 59.880000000000706 N', '162 4 59.88000000003012 W')

Installation Error

FileNotFoundError: [Errno 2] No such file or directory: 'README.md'

Unable to intall

NameError: name 'cmp' is not defined

In this library's GeoCoord class definition, specifically in method _calc_degreeminutes(decimal_degree) the Python 2.7.15 cmp() method is used. cmp() has been removed in Python 3:

The cmp() function should be treated as gone, and the cmp() special method is no longer supported. Use lt() for sorting, eq() with hash(), and other rich comparisons as needed. (If you really need the cmp() functionality, you could use the expression (a > b) - (a < b) as the equivalent for cmp(a, b).)

Note that cmp() is used in this library in the _calc_decimaldegree and _calc_decimalminute methods in GeoCoord

AttributeError: 'Latitude' object has no attribute 'degree'

This looks like a bug since the GeoCoord class in LatLon from Gen Del Ray for Python 2.7.x initializes the degree attribute but your version does not:

LatLon from Gen Del Ray

class GeoCoord:
    '''
    Abstract class representing geographic coordinates (i.e. latitude or longitude)
    Not meant to be used directly - access through Subclasses Latitude() and Longitude() 
    '''
    __metaclass__ = abc.ABCMeta
    
    def __init__(self, degree = 0, minute = 0, second = 0):
        '''
        Initialize a GeoCoord object
        Inputs:
            degree (scalar) - integer or decimal degrees. If decimal degrees are given (e.g. 5.83),
              the fractional values (0.83) will be added to the minute and second variables.
            minute (scalar) - integer or decimal minutes. If decimal minutes are given (e.g. 49.17),
              the fractional values (0.17) will be added to the second variable.
            second (scalar) - decimal minutes.
        '''
        self.degree = float(degree)
        self.minute = float(minute)
        self.second = float(second)
        self._update() # Clean up each variable and make them consistent

This library's init method

class GeoCoord:
    '''
    Abstract class representing geographic coordinates (i.e. latitude or longitude)
    Not meant to be used directly - access through Subclasses Latitude() and Longitude() 
    '''
    __metaclass__ = abc.ABCMeta
    
    def __init__(self, degree = 0, minute = 0, second = 0):
        '''
        Initialize a GeoCoord object
        Inputs:
            degree (scalar) - integer or decimal degrees. If decimal degrees are given (e.g. 5.83),
              the fractional values (0.83) will be added to the minute and second variables.
            minute (scalar) - integer or decimal minutes. If decimal minutes are given (e.g. 49.17),
              the fractional values (0.17) will be added to the second variable.
            second (scalar) - decimal minutes.
        '''
        self.minute = float(minute)
        self.second = float(second)
        self._update() # Clean up each variable and make them consistent

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.