[Python-modules-commits] [gpxpy] 01/07: Initial import.

Dominik George natureshadow-guest at moszumanska.debian.org
Fri Nov 4 12:37:19 UTC 2016


This is an automated email from the git hooks/post-receive script.

natureshadow-guest pushed a commit to branch master
in repository gpxpy.

commit 871e030c94a3c22f56ca58114de0258f0dadc61e
Author: Dominik George <nik at naturalnet.de>
Date:   Fri Nov 4 12:42:21 2016 +0100

    Initial import.
---
 PKG-INFO          |   13 +
 gpxinfo           |  102 +++
 gpxpy/__init__.py |   34 +
 gpxpy/geo.py      |  384 ++++++++
 gpxpy/gpx.py      | 2643 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 gpxpy/gpxfield.py |  406 ++++++++
 gpxpy/gpxxml.py   |   67 ++
 gpxpy/parser.py   |  221 +++++
 gpxpy/utils.py    |  116 +++
 setup.py          |   34 +
 10 files changed, 4020 insertions(+)

diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..672265f
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,13 @@
+Metadata-Version: 1.1
+Name: gpxpy
+Version: 1.1.1
+Summary: GPX file parser and GPS track manipulation library
+Home-page: http://www.trackprofiler.com/gpxpy/index.html
+Author: Tomo Krajina
+Author-email: tkrajina at gmail.com
+License: Apache License, Version 2.0
+Description: UNKNOWN
+Platform: UNKNOWN
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
diff --git a/gpxinfo b/gpxinfo
new file mode 100644
index 0000000..2a4b2ab
--- /dev/null
+++ b/gpxinfo
@@ -0,0 +1,102 @@
+#!/bin/env python
+
+"""
+Command line utility to extract basic statistics from a gpx file
+"""
+
+import pdb
+
+import sys as mod_sys
+import logging as mod_logging
+import math as mod_math
+
+import gpxpy as mod_gpxpy
+
+#mod_logging.basicConfig(level=mod_logging.DEBUG,
+#                        format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
+
+
+
+
+def format_time(time_s):
+    if not time_s:
+        return 'n/a'
+    minutes = mod_math.floor(time_s / 60.)
+    hours = mod_math.floor(minutes / 60.)
+
+    return '%s:%s:%s' % (str(int(hours)).zfill(2), str(int(minutes % 60)).zfill(2), str(int(time_s % 60)).zfill(2))
+
+
+def print_gpx_part_info(gpx_part, indentation='    '):
+    """
+    gpx_part may be a track or segment.
+    """
+    length_2d = gpx_part.length_2d()
+    length_3d = gpx_part.length_3d()
+    print('{}Length 2D: {:.3f}km'.format(indentation, length_2d / 1000.))
+    print('{}Length 3D: {:.3f}km'.format(indentation, length_3d / 1000.))
+
+    moving_time, stopped_time, moving_distance, stopped_distance, max_speed = gpx_part.get_moving_data()
+    print('%sMoving time: %s' % (indentation, format_time(moving_time)))
+    print('%sStopped time: %s' % (indentation, format_time(stopped_time)))
+    #print('%sStopped distance: %sm' % stopped_distance)
+    print('{}Max speed: {:.2f}m/s = {:.2f}km/h'.format(indentation, max_speed if max_speed else 0, max_speed * 60. ** 2 / 1000. if max_speed else 0))
+
+    uphill, downhill = gpx_part.get_uphill_downhill()
+    print('{}Total uphill: {:.2f}m'.format(indentation, uphill))
+    print('{}Total downhill: {:.2f}m'.format(indentation, downhill))
+
+    start_time, end_time = gpx_part.get_time_bounds()
+    print('%sStarted: %s' % (indentation, start_time))
+    print('%sEnded: %s' % (indentation, end_time))
+
+    points_no = len(list(gpx_part.walk(only_points=True)))
+    print('%sPoints: %s' % (indentation, points_no))
+
+    distances = []
+    previous_point = None
+    for point in gpx_part.walk(only_points=True):
+        if previous_point:
+            distance = point.distance_2d(previous_point)
+            distances.append(distance)
+        previous_point = point
+    print('{}Avg distance between points: {:.2f}m'.format(indentation, sum(distances) / len(list(gpx_part.walk()))))
+
+    print('')
+
+
+def print_gpx_info(gpx, gpx_file):
+    print('File: %s' % gpx_file)
+
+    if gpx.name:
+        print('  GPX name: %s' % gpx.name)
+    if gpx.description:
+        print('  GPX description: %s' % gpx.description)
+    if gpx.author_name:
+        print('  Author: %s' % gpx.author_name)
+    if gpx.author_email:
+        print('  Email: %s' % gpx.author_email)
+
+    print_gpx_part_info(gpx)
+
+    for track_no, track in enumerate(gpx.tracks):
+        for segment_no, segment in enumerate(track.segments):
+            print('    Track #%s, Segment #%s' % (track_no, segment_no))
+            print_gpx_part_info(segment, indentation='        ')
+
+def run(gpx_files):
+    if not gpx_files:
+        print('No GPX files given')
+        mod_sys.exit(1)
+
+    for gpx_file in gpx_files:
+        try:
+            gpx = mod_gpxpy.parse(open(gpx_file))
+            print_gpx_info(gpx, gpx_file)
+        except Exception as e:
+            mod_logging.exception(e)
+            print('Error processing %s' % gpx_file)
+            mod_sys.exit(1)
+
+if __name__ == '__main__':
+    run(mod_sys.argv[1:])
diff --git a/gpxpy/__init__.py b/gpxpy/__init__.py
new file mode 100644
index 0000000..996f229
--- /dev/null
+++ b/gpxpy/__init__.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2011 Tomo Krajina
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+def parse(xml_or_file, parser=None):
+    """
+    Parse xml (string) or file object. This is just an wrapper for
+    GPXParser.parse() function.
+
+    parser may be 'lxml', 'minidom' or None (then it will be automatically
+    detected, lxml if possible).
+
+    xml_or_file must be the xml to parse or a file-object with the XML.
+    """
+
+    from . import gpx as mod_gpx
+    from . import parser as mod_parser
+
+    parser = mod_parser.GPXParser(xml_or_file, parser=parser)
+
+    return parser.parse()
diff --git a/gpxpy/geo.py b/gpxpy/geo.py
new file mode 100644
index 0000000..ac55805
--- /dev/null
+++ b/gpxpy/geo.py
@@ -0,0 +1,384 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2011 Tomo Krajina
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import pdb
+
+import logging as mod_logging
+import math as mod_math
+
+from . import utils as mod_utils
+
+# Generic geo related function and class(es)
+
+# One degree in meters:
+ONE_DEGREE = 1000. * 10000.8 / 90.
+
+EARTH_RADIUS = 6371 * 1000
+
+
+def to_rad(x):
+    return x / 180. * mod_math.pi
+
+
+def haversine_distance(latitude_1, longitude_1, latitude_2, longitude_2):
+    """
+    Haversine distance between two points, expressed in meters.
+
+    Implemented from http://www.movable-type.co.uk/scripts/latlong.html
+    """
+    d_lat = to_rad(latitude_1 - latitude_2)
+    d_lon = to_rad(longitude_1 - longitude_2)
+    lat1 = to_rad(latitude_1)
+    lat2 = to_rad(latitude_2)
+
+    a = mod_math.sin(d_lat/2) * mod_math.sin(d_lat/2) + \
+        mod_math.sin(d_lon/2) * mod_math.sin(d_lon/2) * mod_math.cos(lat1) * mod_math.cos(lat2)
+    c = 2 * mod_math.atan2(mod_math.sqrt(a), mod_math.sqrt(1-a))
+    d = EARTH_RADIUS * c
+
+    return d
+
+
+def length(locations=None, _3d=None):
+    locations = locations or []
+    if not locations:
+        return 0
+    length = 0
+    for i in range(len(locations)):
+        if i > 0:
+            previous_location = locations[i - 1]
+            location = locations[i]
+
+            if _3d:
+                d = location.distance_3d(previous_location)
+            else:
+                d = location.distance_2d(previous_location)
+            if d != 0 and not d:
+                pass
+            else:
+                length += d
+    return length
+
+
+def length_2d(locations=None):
+    """ 2-dimensional length (meters) of locations (only latitude and longitude, no elevation). """
+    locations = locations or []
+    return length(locations, False)
+
+
+def length_3d(locations=None):
+    """ 3-dimensional length (meters) of locations (it uses latitude, longitude, and elevation). """
+    locations = locations or []
+    return length(locations, True)
+
+
+def calculate_max_speed(speeds_and_distances):
+    """
+    Compute average distance and standard deviation for distance. Extremes
+    in distances are usually extremes in speeds, so we will ignore them,
+    here.
+
+    speeds_and_distances must be a list containing pairs of (speed, distance)
+    for every point in a track segment.
+    """
+    assert speeds_and_distances
+    if len(speeds_and_distances) > 0:
+        assert len(speeds_and_distances[0]) == 2
+        # ...
+        assert len(speeds_and_distances[-1]) == 2
+
+    size = float(len(speeds_and_distances))
+
+    if size < 20:
+        mod_logging.debug('Segment too small to compute speed, size=%s', size)
+        return None
+
+    distances = list(map(lambda x: x[1], speeds_and_distances))
+    average_distance = sum(distances) / float(size)
+    standard_distance_deviation = mod_math.sqrt(sum(map(lambda distance: (distance-average_distance)**2, distances))/size)
+
+    # Ignore items where the distance is too big:
+    filtered_speeds_and_distances = filter(lambda speed_and_distance: abs(speed_and_distance[1] - average_distance) <= standard_distance_deviation * 1.5, speeds_and_distances)
+
+    # sort by speed:
+    speeds = list(map(lambda speed_and_distance: speed_and_distance[0], filtered_speeds_and_distances))
+    if not isinstance(speeds, list):  # python3
+        speeds = list(speeds)
+    if not speeds:
+        return None
+    speeds.sort()
+
+    # Even here there may be some extremes => ignore the last 5%:
+    index = int(len(speeds) * 0.95)
+    if index >= len(speeds):
+        index = -1
+
+    return speeds[index]
+
+
+def calculate_uphill_downhill(elevations):
+    if not elevations:
+        return 0, 0
+
+    size = len(elevations)
+
+    def __filter(n):
+        current_ele = elevations[n]
+        if current_ele is None:
+            return False
+        if 0 < n < size - 1:
+            previous_ele = elevations[n-1]
+            next_ele = elevations[n+1]
+            if previous_ele is not None and current_ele is not None and next_ele is not None:
+                return previous_ele*.3 + current_ele*.4 + next_ele*.3
+        return current_ele
+
+    smoothed_elevations = list(map(__filter, range(size)))
+
+    uphill, downhill = 0., 0.
+
+    for n, elevation in enumerate(smoothed_elevations):
+        if n > 0 and elevation is not None and smoothed_elevations is not None:
+            d = elevation - smoothed_elevations[n-1]
+            if d > 0:
+                uphill += d
+            else:
+                downhill -= d
+
+    return uphill, downhill
+
+
+def distance(latitude_1, longitude_1, elevation_1, latitude_2, longitude_2, elevation_2,
+             haversine=None):
+    """
+    Distance between two points. If elevation is None compute a 2d distance
+
+    if haversine==True -- haversine will be used for every computations,
+    otherwise...
+
+    Haversine distance will be used for distant points where elevation makes a
+    small difference, so it is ignored. That's because haversine is 5-6 times
+    slower than the dummy distance algorithm (which is OK for most GPS tracks).
+    """
+
+    # If points too distant -- compute haversine distance:
+    if haversine or (abs(latitude_1 - latitude_2) > .2 or abs(longitude_1 - longitude_2) > .2):
+        return haversine_distance(latitude_1, longitude_1, latitude_2, longitude_2)
+
+    coef = mod_math.cos(latitude_1 / 180. * mod_math.pi)
+    x = latitude_1 - latitude_2
+    y = (longitude_1 - longitude_2) * coef
+
+    distance_2d = mod_math.sqrt(x * x + y * y) * ONE_DEGREE
+
+    if elevation_1 is None or elevation_2 is None or elevation_1 == elevation_2:
+        return distance_2d
+
+    return mod_math.sqrt(distance_2d ** 2 + (elevation_1 - elevation_2) ** 2)
+
+
+def elevation_angle(location1, location2, radians=False):
+    """ Uphill/downhill angle between two locations. """
+    if location1.elevation is None or location2.elevation is None:
+        return None
+
+    b = float(location2.elevation - location1.elevation)
+    a = location2.distance_2d(location1)
+
+    if a == 0:
+        return 0
+
+    angle = mod_math.atan(b / a)
+
+    if radians:
+        return angle
+
+    return 180 * angle / mod_math.pi
+
+
+def distance_from_line(point, line_point_1, line_point_2):
+    """ Distance of point from a line given with two points. """
+    assert point, point
+    assert line_point_1, line_point_1
+    assert line_point_2, line_point_2
+
+    a = line_point_1.distance_2d(line_point_2)
+
+    if a == 0:
+        return line_point_1.distance_2d(point)
+
+    b = line_point_1.distance_2d(point)
+    c = line_point_2.distance_2d(point)
+
+    s = (a + b + c) / 2.
+
+    return 2. * mod_math.sqrt(abs(s * (s - a) * (s - b) * (s - c))) / a
+
+
+def get_line_equation_coefficients(location1, location2):
+    """
+    Get line equation coefficients for:
+        latitude * a + longitude * b + c = 0
+
+    This is a normal cartesian line (not spherical!)
+    """
+    if location1.longitude == location2.longitude:
+        # Vertical line:
+        return float(0), float(1), float(-location1.longitude)
+    else:
+        a = float(location1.latitude - location2.latitude) / (location1.longitude - location2.longitude)
+        b = location1.latitude - location1.longitude * a
+        return float(1), float(-a), float(-b)
+
+
+def simplify_polyline(points, max_distance):
+    """Does Ramer-Douglas-Peucker algorithm for simplification of polyline """
+
+    if len(points) < 3:
+        return points
+
+    begin, end = points[0], points[-1]
+
+    # Use a "normal" line just to detect the most distant point (not its real distance)
+    # this is because this is faster to compute than calling distance_from_line() for
+    # every point.
+    #
+    # This is an approximation and may have some errors near the poles and if
+    # the points are too distant, but it should be good enough for most use
+    # cases...
+    a, b, c = get_line_equation_coefficients(begin, end)
+
+    tmp_max_distance = -1000000
+    tmp_max_distance_position = None
+    for point_no in range(len(points[1:-1])):
+        point = points[point_no]
+        d = abs(a * point.latitude + b * point.longitude + c)
+        if d > tmp_max_distance:
+            tmp_max_distance = d
+            tmp_max_distance_position = point_no
+
+    # Now that we have the most distance point, compute its real distance:
+    real_max_distance = distance_from_line(points[tmp_max_distance_position], begin, end)
+
+    if real_max_distance < max_distance:
+        return [begin, end]
+
+    return (simplify_polyline(points[:tmp_max_distance_position + 2], max_distance) +
+            simplify_polyline(points[tmp_max_distance_position + 1:], max_distance)[1:])
+
+
+class Location:
+    """ Generic geographical location """
+
+    latitude = None
+    longitude = None
+    elevation = None
+
+    def __init__(self, latitude, longitude, elevation=None):
+        self.latitude = latitude
+        self.longitude = longitude
+        self.elevation = elevation
+
+    def has_elevation(self):
+        return self.elevation or self.elevation == 0
+
+    def remove_elevation(self):
+        self.elevation = None
+
+    def distance_2d(self, location):
+        if not location:
+            return None
+
+        return distance(self.latitude, self.longitude, None, location.latitude, location.longitude, None)
+
+    def distance_3d(self, location):
+        if not location:
+            return None
+
+        return distance(self.latitude, self.longitude, self.elevation, location.latitude, location.longitude, location.elevation)
+
+    def elevation_angle(self, location, radians=False):
+        return elevation_angle(self, location, radians)
+
+    def move(self, location_delta):
+        self.latitude, self.longitude = location_delta.move(self)
+
+    def __add__(self, location_delta):
+        latitude, longitude = location_delta.move(self)
+        return Location(latitude, longitude)
+
+    def __str__(self):
+        return '[loc:%s,%s@%s]' % (self.latitude, self.longitude, self.elevation)
+
+    def __repr__(self):
+        if self.elevation is None:
+            return 'Location(%s, %s)' % (self.latitude, self.longitude)
+        else:
+            return 'Location(%s, %s, %s)' % (self.latitude, self.longitude, self.elevation)
+
+    def __hash__(self):
+        return mod_utils.hash_object(self, ('latitude', 'longitude', 'elevation'))
+
+
+class LocationDelta:
+    """
+    Intended to use similar to timestamp.timedelta, but for Locations.
+    """
+
+    NORTH = 0
+    EAST = 90
+    SOUTH = 180
+    WEST = 270
+
+    def __init__(self, distance=None, angle=None, latitude_diff=None, longitude_diff=None):
+        """
+        Version 1:
+            Distance (in meters).
+            angle_from_north *clockwise*. 
+            ...must be given
+        Version 2:
+            latitude_diff and longitude_diff
+            ...must be given
+        """
+        if (distance is not None) and (angle is not None):
+            if (latitude_diff is not None) or (longitude_diff is not None):
+                raise Exception('No lat/lon diff if using distance and angle!')
+            self.distance = distance
+            self.angle_from_north = angle
+            self.move_function = self.move_by_angle_and_distance
+        elif (latitude_diff is not None) and (longitude_diff is not None):
+            if (distance is not None) or (angle is not None):
+                raise Exception('No distance/angle if using lat/lon diff!')
+            this.latitude_diff  = latitude_diff
+            this.longitude_diff = longitude_diff
+            self.move_function = self.move_by_lat_lon_diff
+
+    def move(self, location):
+        """
+        Move location by this timedelta.
+        """
+        return self.move_function(location)
+
+    def move_by_angle_and_distance(self, location):
+        coef = mod_math.cos(location.latitude / 180. * mod_math.pi)
+        vertical_distance_diff   = mod_math.sin((90 - self.angle_from_north) / 180. * mod_math.pi) / ONE_DEGREE
+        horizontal_distance_diff = mod_math.cos((90 - self.angle_from_north) / 180. * mod_math.pi) / ONE_DEGREE
+        lat_diff = self.distance * vertical_distance_diff
+        lon_diff = self.distance * horizontal_distance_diff / coef
+        return location.latitude + lat_diff, location.longitude + lon_diff
+
+    def move_by_lat_lon_diff(self, location):
+        return location.latitude  + self.latitude_diff, location.longitude + self.longitude_diff
diff --git a/gpxpy/gpx.py b/gpxpy/gpx.py
new file mode 100644
index 0000000..a148cc1
--- /dev/null
+++ b/gpxpy/gpx.py
@@ -0,0 +1,2643 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2011 Tomo Krajina
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+GPX related stuff
+"""
+
+import pdb
+
+import logging as mod_logging
+import math as mod_math
+import collections as mod_collections
+import copy as mod_copy
+import datetime as mod_datetime
+
+from . import utils as mod_utils
+from . import geo as mod_geo
+from . import gpxfield as mod_gpxfield
+
+# GPX date format to be used when writing the GPX output:
+DATE_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
+
+# GPX date format(s) used for parsing. The T between date and time and Z after
+# time are allowed, too:
+DATE_FORMATS = [
+    '%Y-%m-%d %H:%M:%S',
+    '%Y-%m-%d %H:%M:%S.%f',
+    #'%Y-%m-%d %H:%M:%S%z',
+    #'%Y-%m-%d %H:%M:%S.%f%z',
+]
+# Used in smoothing, sum must be 1:
+SMOOTHING_RATIO = (0.4, 0.2, 0.4)
+
+# When computing stopped time -- this is the minimum speed between two points,
+# if speed is less than this value -- we'll assume it is zero
+DEFAULT_STOPPED_SPEED_THRESHOLD = 1
+
+# Fields used for all point elements (route point, track point, waypoint):
+GPX_10_POINT_FIELDS = [
+        mod_gpxfield.GPXField('latitude', attribute='lat', type=mod_gpxfield.FLOAT_TYPE, mandatory=True),
+        mod_gpxfield.GPXField('longitude', attribute='lon', type=mod_gpxfield.FLOAT_TYPE, mandatory=True),
+        mod_gpxfield.GPXField('elevation', 'ele', type=mod_gpxfield.FLOAT_TYPE),
+        mod_gpxfield.GPXField('time', type=mod_gpxfield.TIME_TYPE),
+        mod_gpxfield.GPXField('magnetic_variation', 'magvar', type=mod_gpxfield.FLOAT_TYPE),
+        mod_gpxfield.GPXField('geoid_height', 'geoidheight', type=mod_gpxfield.FLOAT_TYPE),
+        mod_gpxfield.GPXField('name'),
+        mod_gpxfield.GPXField('comment', 'cmt'),
+        mod_gpxfield.GPXField('description', 'desc'),
+        mod_gpxfield.GPXField('source', 'src'),
+        mod_gpxfield.GPXField('link', 'url'),
+        mod_gpxfield.GPXField('link_text', 'urlname'),
+        mod_gpxfield.GPXField('symbol', 'sym'),
+        mod_gpxfield.GPXField('type'),
+        mod_gpxfield.GPXField('type_of_gpx_fix', 'fix', possible=('none', '2d', '3d', 'dgps', 'pps',)),
+        mod_gpxfield.GPXField('satellites', 'sat', type=mod_gpxfield.INT_TYPE),
+        mod_gpxfield.GPXField('horizontal_dilution', 'hdop', type=mod_gpxfield.FLOAT_TYPE),
+        mod_gpxfield.GPXField('vertical_dilution', 'vdop', type=mod_gpxfield.FLOAT_TYPE),
+        mod_gpxfield.GPXField('position_dilution', 'pdop', type=mod_gpxfield.FLOAT_TYPE),
+        mod_gpxfield.GPXField('age_of_dgps_data', 'ageofdgpsdata', type=mod_gpxfield.FLOAT_TYPE),
+        mod_gpxfield.GPXField('dgps_id', 'dgpsid'),
+]
+GPX_11_POINT_FIELDS = [
+        mod_gpxfield.GPXField('latitude', attribute='lat', type=mod_gpxfield.FLOAT_TYPE, mandatory=True),
+        mod_gpxfield.GPXField('longitude', attribute='lon', type=mod_gpxfield.FLOAT_TYPE, mandatory=True),
+        mod_gpxfield.GPXField('elevation', 'ele', type=mod_gpxfield.FLOAT_TYPE),
+        mod_gpxfield.GPXField('time', type=mod_gpxfield.TIME_TYPE),
+        mod_gpxfield.GPXField('magnetic_variation', 'magvar', type=mod_gpxfield.FLOAT_TYPE),
+        mod_gpxfield.GPXField('geoid_height', 'geoidheight', type=mod_gpxfield.FLOAT_TYPE),
+        mod_gpxfield.GPXField('name'),
+        mod_gpxfield.GPXField('comment', 'cmt'),
+        mod_gpxfield.GPXField('description', 'desc'),
+        mod_gpxfield.GPXField('source', 'src'),
+        'link',
+            mod_gpxfield.GPXField('link', attribute='href'),
+            mod_gpxfield.GPXField('link_text', tag='text'),
+            mod_gpxfield.GPXField('link_type', tag='type'),
+        '/link',
+        mod_gpxfield.GPXField('symbol', 'sym'),
+        mod_gpxfield.GPXField('type'),
+        mod_gpxfield.GPXField('type_of_gpx_fix', 'fix', possible=('none', '2d', '3d', 'dgps', 'pps',)),
+        mod_gpxfield.GPXField('satellites', 'sat', type=mod_gpxfield.INT_TYPE),
+        mod_gpxfield.GPXField('horizontal_dilution', 'hdop', type=mod_gpxfield.FLOAT_TYPE),
+        mod_gpxfield.GPXField('vertical_dilution', 'vdop', type=mod_gpxfield.FLOAT_TYPE),
+        mod_gpxfield.GPXField('position_dilution', 'pdop', type=mod_gpxfield.FLOAT_TYPE),
+        mod_gpxfield.GPXField('age_of_dgps_data', 'ageofdgpsdata', type=mod_gpxfield.FLOAT_TYPE),
+        mod_gpxfield.GPXField('dgps_id', 'dgpsid'),
+        mod_gpxfield.GPXExtensionsField('extensions'),
+]
+
+# GPX1.0 track points have two more fields after time
+# Note that this is not true for GPX1.1
+GPX_TRACK_POINT_FIELDS = GPX_10_POINT_FIELDS[:4] \
+        + [ \
+                mod_gpxfield.GPXField('course', type=mod_gpxfield.FLOAT_TYPE), \
+                mod_gpxfield.GPXField('speed', type=mod_gpxfield.FLOAT_TYPE) \
+          ] \
+        + GPX_10_POINT_FIELDS[4:]
+
+# When possible, the result of various methods are named tuples defined here:
+TimeBounds = mod_collections.namedtuple(
+    'TimeBounds',
+    ('start_time', 'end_time'))
+MovingData = mod_collections.namedtuple(
+    'MovingData',
+    ('moving_time', 'stopped_time', 'moving_distance', 'stopped_distance', 'max_speed'))
+UphillDownhill = mod_collections.namedtuple(
+    'UphillDownhill',
+    ('uphill', 'downhill'))
+MinimumMaximum = mod_collections.namedtuple(
+    'MinimumMaximum',
+    ('minimum', 'maximum'))
+NearestLocationData = mod_collections.namedtuple(
+    'NearestLocationData',
+    ('location', 'track_no', 'segment_no', 'point_no'))
+PointData = mod_collections.namedtuple(
+    'PointData',
+    ('point', 'distance_from_start', 'track_no', 'segment_no', 'point_no'))
+
+
+class GPXException(Exception):
+    """
+    Exception used for invalid GPX files. Is is used when the XML file is
+    valid but something is wrong with the GPX data.
+    """
+    pass
+
+
+class GPXBounds:
+    gpx_10_fields = gpx_11_fields = [
+            mod_gpxfield.GPXField('min_latitude', attribute='minlat', type=mod_gpxfield.FLOAT_TYPE),
+            mod_gpxfield.GPXField('max_latitude', attribute='maxlat', type=mod_gpxfield.FLOAT_TYPE),
+            mod_gpxfield.GPXField('min_longitude', attribute='minlon', type=mod_gpxfield.FLOAT_TYPE),
+            mod_gpxfield.GPXField('max_longitude', attribute='maxlon', type=mod_gpxfield.FLOAT_TYPE),
+    ]
+
+    __slots__ = ('min_latitude', 'max_latitude', 'min_longitude', 'max_longitude')
+
+    def __init__(self, min_latitude=None, max_latitude=None, min_longitude=None, max_longitude=None):
+        self.min_latitude = min_latitude
+        self.max_latitude = max_latitude
+        self.min_longitude = min_longitude
+        self.max_longitude = max_longitude
+
+    def __iter__(self):
+        return (self.min_latitude, self.max_latitude, self.min_longitude, self.max_longitude,).__iter__()
+
+    def __hash__(self):
+        return mod_utils.hash_object(self, self.__slots__)
+
+
+class GPXXMLSyntaxException(GPXException):
+    """
+    Exception used when the the XML syntax is invalid.
+
+    The __cause__ can be a minidom or lxml exception (See http://www.python.org/dev/peps/pep-3134/).
+    """
+    def __init__(self, message, original_exception):
+        GPXException.__init__(self, message)
+        self.__cause__ = original_exception
+
+
+class GPXWaypoint(mod_geo.Location):
+    gpx_10_fields = GPX_10_POINT_FIELDS
+    gpx_11_fields = GPX_11_POINT_FIELDS
+
+    __slots__ = ('latitude', 'longitude', 'elevation', 'time', 
+                 'magnetic_variation', 'geoid_height', 'name', 'comment', 
+                 'description', 'source', 'link', 'link_text', 'symbol', 
+                 'type', 'type_of_gpx_fix', 'satellites', 
+                 'horizontal_dilution', 'vertical_dilution', 
+                 'position_dilution', 'age_of_dgps_data', 'dgps_id', 
+                 'link_type', 'extensions')
+
+    def __init__(self, latitude=None, longitude=None, elevation=None, time=None,
+                 name=None, description=None, symbol=None, type=None,
+                 comment=None, horizontal_dilution=None, vertical_dilution=None,
+                 position_dilution=None):
+        mod_geo.Location.__init__(self, latitude, longitude, elevation)
+
+        self.latitude = latitude
+        self.longitude = longitude
+        self.elevation = elevation
+        self.time = time
+        self.magnetic_variation = None
+        self.geoid_height = None
+        self.name = name
+        self.comment = comment
+        self.description = description
+        self.source = None
+        self.link = None
+        self.link_text = None
+        self.link_type = None
+        self.symbol = symbol
+        self.type = type
+        self.type_of_gpx_fix = None
+        self.satellites = None
+        self.horizontal_dilution = horizontal_dilution
+        self.vertical_dilution = vertical_dilution
+        self.position_dilution = position_dilution
+        self.age_of_dgps_data = None
+        self.dgps_id = None
+        self.extensions = None
+
+    def __str__(self):
+        return '[wpt{%s}:%s,%s@%s]' % (self.name, self.latitude, self.longitude, self.elevation)
+
+    def __repr__(self):
+        representation = '%s, %s' % (self.latitude, self.longitude)
+        for attribute in 'elevation', 'time', 'name', 'description', 'symbol', 'type', 'comment', \
+                'horizontal_dilution', 'vertical_dilution', 'position_dilution':
+            value = getattr(self, attribute)
+            if value is not None:
+                representation += ', %s=%s' % (attribute, repr(value))
+        return 'GPXWaypoint(%s)' % representation
+
+    def get_max_dilution_of_precision(self):
+        """
+        Only care about the max dop for filtering, no need to go into too much detail
+        """
+        return max(self.horizontal_dilution, self.vertical_dilution, self.position_dilution)
+
+    def __hash__(self):
+        return mod_utils.hash_object(self, self.__slots__)
+
+
+class GPXRoutePoint(mod_geo.Location):
+    gpx_10_fields = GPX_10_POINT_FIELDS
+    gpx_11_fields = GPX_11_POINT_FIELDS
+
+    __slots__ = ('latitude', 'longitude', 'elevation', 'time', 
+                 'magnetic_variation', 'geoid_height', 'name', 'comment', 
+                 'description', 'source', 'link', 'link_text', 'symbol', 
+                 'type', 'type_of_gpx_fix', 'satellites', 
+                 'horizontal_dilution', 'vertical_dilution', 
+                 'position_dilution', 'age_of_dgps_data', 'dgps_id', 
+                 'link_type', 'extensions')
+
+    def __init__(self, latitude=None, longitude=None, elevation=None, time=None, name=None,
+                 description=None, symbol=None, type=None, comment=None,
+                 horizontal_dilution=None, vertical_dilution=None,
+                 position_dilution=None):
+
+        mod_geo.Location.__init__(self, latitude, longitude, elevation)
+        self.latitude = latitude
+        self.longitude = longitude
+        self.elevation = elevation
+        self.time = time
+        self.magnetic_variation = None
+        self.geoid_height = None
+        self.name = name
+        self.comment = comment
+        self.description = description
+        self.source = None
+        self.link = None
+        self.link_text = None
+        self.symbol = symbol
+        self.type = type
+        self.type_of_gpx_fix = None
+        self.satellites = None
+        self.horizontal_dilution = horizontal_dilution
+        self.vertical_dilution = vertical_dilution
+        self.position_dilution = position_dilution
+        self.age_of_dgps_data = None
+        self.dgps_id = None
+        self.link_type = None
+        self.extensions = None
+
+    def __str__(self):
+        return '[rtept{%s}:%s,%s@%s]' % (self.name, self.latitude, self.longitude, self.elevation)
+
+    def __repr__(self):
+        representation = '%s, %s' % (self.latitude, self.longitude)
+        for attribute in 'elevation', 'time', 'name', 'description', 'symbol', 'type', 'comment', \
+                'horizontal_dilution', 'vertical_dilution', 'position_dilution':
+            value = getattr(self, attribute)
+            if value is not None:
+                representation += ', %s=%s' % (attribute, repr(value))
+        return 'GPXRoutePoint(%s)' % representation
+
+    def __hash__(self):
+        return mod_utils.hash_object(self, self.__slots__)
+
+
+class GPXRoute:
+    gpx_10_fields = [
+            mod_gpxfield.GPXField('name'),
+            mod_gpxfield.GPXField('comment', 'cmt'),
+            mod_gpxfield.GPXField('description', 'desc'),
+            mod_gpxfield.GPXField('source', 'src'),
+            mod_gpxfield.GPXField('link', 'url'),
+            mod_gpxfield.GPXField('link_text', 'urlname'),
+            mod_gpxfield.GPXField('number', type=mod_gpxfield.INT_TYPE),
+            mod_gpxfield.GPXComplexField('points', tag='rtept', classs=GPXRoutePoint, is_list=True),
+    ]
+    gpx_11_fields = [
+            mod_gpxfield.GPXField('name'),
+            mod_gpxfield.GPXField('comment', 'cmt'),
+            mod_gpxfield.GPXField('description', 'desc'),
+            mod_gpxfield.GPXField('source', 'src'),
+            'link',
+                mod_gpxfield.GPXField('link', attribute='href'),
+                mod_gpxfield.GPXField('link_text', tag='text'),
+                mod_gpxfield.GPXField('link_type', tag='type'),
+            '/link',
+            mod_gpxfield.GPXField('number', type=mod_gpxfield.INT_TYPE),
+            mod_gpxfield.GPXField('type'),
+            mod_gpxfield.GPXExtensionsField('extensions'),
+            mod_gpxfield.GPXComplexField('points', tag='rtept', classs=GPXRoutePoint, is_list=True),
+    ]
+
+    __slots__ = ('name', 'comment', 'description', 'source', 'link', 
+                 'link_text', 'number', 'points', 'link_type', 'type', 
+                 'extensions')
+
+    def __init__(self, name=None, description=None, number=None):
+        self.name = name
+        self.comment = None
+        self.description = description
+        self.source = None
+        self.link = None
+        self.link_text = None
+        self.number = number
+        self.points = []
+        self.link_type = None
+        self.type = None
+        self.extensions = None
+
+    def remove_elevation(self):
+        """ Removes elevation data from route """
+        for point in self.points:
+            point.remove_elevation()
+
+    def length(self):
+        """ 
+        Computes length (2-dimensional) of route. 
+         
+        Returns:
+        -----------
+        length: float
+            Length returned in meters
+        """
+        return mod_geo.length_2d(self.points)
+
+    def get_center(self):
+        """
+        Get the center of the route.
+
+        Returns
+        -------
+        center: Location
+            latitude: latitude of center in degrees
+            longitude: longitude of center in degrees
+            elevation: not calculated here
+        """
+        if not self.points:
+            return None
+
+        if not self.points:
+            return None
+
+        sum_lat = 0.
+        sum_lon = 0.
+        n = 0.
+
+        for point in self.points:
+            n += 1.
+            sum_lat += point.latitude
+            sum_lon += point.longitude
+
+        if not n:
+            return mod_geo.Location(float(0), float(0))
+
+        return mod_geo.Location(latitude=sum_lat / n, longitude=sum_lon / n)
+
+    def walk(self, only_points=False):
+        """
+        Generator for iterating over route points
+
+        Parameters
+        ----------
+        only_points: boolean
+            Only yield points (no index yielded)
+
+        Yields
+        ------
+        point: GPXRoutePoint
+            A point in the GPXRoute
+        point_no: int 
+            Not included in yield if only_points is true
+        """
+        for point_no, point in enumerate(self.points):
+            if only_points:
+                yield point
+            else:
+                yield point, point_no
+
+    def get_points_no(self):
+        """
+        Get the number of points in route.
+
+        Returns
+        ----------
+        num_points : integer
+            Number of points in route
+        """
+        return len(self.points)
... 3098 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/gpxpy.git



More information about the Python-modules-commits mailing list