From 38b5d9ac031a6411511304ad27775384788c6922 Mon Sep 17 00:00:00 2001 From: FABallemand Date: Sun, 3 Sep 2023 16:19:15 +0200 Subject: [PATCH] #9 Work in progress: -GPX to KML conversion [ci skip] --- ezgpx/gpx/gpx.py | 103 +++-- ezgpx/gpx_elements/gpx.py | 89 +++- ezgpx/gpx_writer/__init__.py | 2 +- ezgpx/gpx_writer/{writer.py => gpx_writer.py} | 11 +- ezgpx/kml_writer/__init__.py | 1 + ezgpx/kml_writer/kml_writer.py | 434 ++++++++++++++++++ notes.md | 2 +- setup.py | 2 +- tests/test_files/files/river_run.kml | 44 ++ tests/test_files/files/strava_run_1_test.kml | 356 ++++++++++++++ 10 files changed, 979 insertions(+), 65 deletions(-) rename ezgpx/gpx_writer/{writer.py => gpx_writer.py} (99%) create mode 100644 ezgpx/kml_writer/__init__.py create mode 100644 ezgpx/kml_writer/kml_writer.py create mode 100644 tests/test_files/files/river_run.kml create mode 100644 tests/test_files/files/strava_run_1_test.kml diff --git a/ezgpx/gpx/gpx.py b/ezgpx/gpx/gpx.py index 34fff1f..78b3ec5 100644 --- a/ezgpx/gpx/gpx.py +++ b/ezgpx/gpx/gpx.py @@ -1,5 +1,5 @@ import os -from typing import Optional, Union, Tuple, NewType +from typing import Optional, Union, List, Tuple, Dict, NewType import logging import webbrowser from datetime import datetime @@ -20,7 +20,8 @@ from ..gpx_elements import Gpx, WayPoint from ..gpx_parser import Parser -from ..gpx_writer import Writer +from ..gpx_writer import GPXWriter +from ..kml_writer import KMLWriter from ..utils import EARTH_RADIUS GPX = NewType("GPX", object) # GPX forward declaration for type hint @@ -47,14 +48,16 @@ def __init__(self, file_path: Optional[str] = None, check_schemas: bool = True, self.file_path: str = file_path self.parser: Parser = Parser(file_path, check_schemas, extensions_schemas) self.gpx: Gpx = self.parser.gpx - self.writer: Writer = Writer( + self.gpx_writer: GPXWriter = GPXWriter( + self.gpx, precisions=self.parser.precisions, time_format=self.parser.time_format) + self.kml_writer: KMLWriter = KMLWriter( self.gpx, precisions=self.parser.precisions, time_format=self.parser.time_format) else: logging.warning("File path does not exist") pass def __str__(self) -> str: - return f"file_path = {self.file_path}\nparser = {self.parser}\ngpx = {self.gpx}\nwriter = {self.writer}" + return f"file_path = {self.file_path}\nparser = {self.parser}\ngpx = {self.gpx}\nwriter = {self.gpx_writer}" def check_schemas(self, extensions_schemas: bool = False) -> bool: """ @@ -408,19 +411,19 @@ def remove_metadata(self): """ Remove metadata (ie: metadata will not be written when saving the GPX object as a .gpx file). """ - self.writer.metadata = False + self.gpx_writer.metadata = False def remove_elevation(self): """ Remove elevation data (ie: elevation data will not be written when saving the GPX object as a .gpx file). """ - self.writer.ele = False + self.gpx_writer.ele = False def remove_time(self): """ Remove time data (ie: time data will not be written when saving the GPX object as a .gpx file). """ - self.writer.time = False + self.gpx_writer.time = False def remove_gps_errors(self): """ @@ -500,7 +503,7 @@ def to_string(self) -> str: str String representingth GPX object. """ - return self.writer.gpx_to_string(self.gpx) + return self.gpx_writer.gpx_to_string(self.gpx) def to_dataframe( self, @@ -535,6 +538,36 @@ def to_dataframe( """ return self.gpx.to_dataframe(projection, elevation, speed, pace, ascent_rate, ascent_speed) + def to_csv( + self, + path: str = None, + sep: str = ",", + columns: List[str] = None, + header: bool = True, + index: bool = False) -> Union[str, None]: + """ + Write the GPX object track coordinates to a .csv file. + + Parameters + ---------- + path : str, optional + Path to the .csv file, by default None + sep : str, optional + Separator, by default "," + columns : List[str], optional + List of columns to write, by default None + header : bool, optional + Toggle header, by default True + index : bool, optional + Toggle index, by default False + + Returns + ------- + str + CSV like string if path is set to None. + """ + return self.gpx.to_csv(columns, path, sep, header, index) + def to_gpx(self, path: str, check_schemas: bool = True, extensions_schemas: bool = False) -> bool: """ Write the GPX object to a .gpx file. @@ -553,47 +586,29 @@ def to_gpx(self, path: str, check_schemas: bool = True, extensions_schemas: bool bool Return False if written file does not follow checked schemas. Return True otherwise. """ - return self.writer.write(path, check_schemas, extensions_schemas) - - def to_csv( - self, - projection: bool = False, - elevation: bool = True, - speed: bool = False, - pace: bool = False, - ascent_rate: bool = False, - ascent_speed: bool = False, - path: str = "unnamed.csv", - sep: str = ",", - header: bool = True, - index: bool = False): + return self.gpx_writer.write(path, check_schemas, extensions_schemas) + + def to_kml(self, path: str, styles: Optional[List[Tuple[str, Dict]]] = None, check_schemas: bool = True, extensions_schemas: bool = False) -> bool: """ - Write the GPX object track coordinates to a .csv file. + Write the GPX object to a .kml file. Parameters ---------- - projection : bool, optional - Toggle projected coordinates, by default False - elevation : bool, optional - Toggle elevation, by default True - speed : bool, optional - Toggle speed, by default False - pace : bool, optional - Toggle pace, by default False - ascent_rate : bool, optional - Toggle ascent rate, by default False - ascent_speed : bool, optional - Toggle ascent speed, by default False - path : str, optional - Path to the .csv file, by default "unnamed.csv" - sep : str, optional - Separator, by default "," - header : bool, optional - Toggle header, by default True - index : bool, optional - Toggle index, by default False + path : str + Path to the .gpx file. + styles : List[Tuple[str, Dict]], optional + List of (style_id, style) tuples, by default None + check_schemas : bool, optional + Toggle schema verification after writting, by default True + extensions_schemas : bool, optional + Toggle extensions schema verificaton after writing. Requires internet connection and is not guaranted to work, by default False + + Returns + ------- + bool + Return False if written file does not follow checked schemas. Return True otherwise. """ - self.to_dataframe(projection, elevation, speed, pace, ascent_rate, ascent_speed).to_csv(path, sep=sep, header=header, index=index) + return self.kml_writer.write(path, styles, check_schemas, extensions_schemas) def _matplotlib_plot_text( self, diff --git a/ezgpx/gpx_elements/gpx.py b/ezgpx/gpx_elements/gpx.py index 78c9d06..d278ebc 100644 --- a/ezgpx/gpx_elements/gpx.py +++ b/ezgpx/gpx_elements/gpx.py @@ -1,4 +1,4 @@ -from typing import List, Tuple +from typing import Union, List, Tuple import logging import xmlschema import pandas as pd @@ -609,16 +609,25 @@ def to_dataframe( """ Convert GPX object to Pandas Dataframe. - Args: - projection (bool, optional): Toggle projection. Defaults to False. - elevation (bool, optional): Toggle elevation. Defaults to True. - speed (bool, optional): Toggle speed. Defaults to False. - pace (bool, optional): Toggle pace. Defaults to False. - ascent_rate (bool, optional): Toggle ascent rate. Defaults to False. - ascent_speed (bool, optional): Toggle ascent speed. Defaults to False. - - Returns: - pd.DataFrame: Dataframe containing data from GPX. + Parameters + ---------- + projection : bool, optional + Toggle projection, by default False + elevation : bool, optional + Toggle elevation, by default True + speed : bool, optional + Toggle speed, by default False + pace : bool, optional + Toggle pace, by default False + ascent_rate : bool, optional + Toggle ascent rate, by default False + ascent_speed : bool, optional + Toggle ascent speed, by default False + + Returns + ------- + pd.DataFrame + Dataframe containing data from GPX. """ test_point = self.first_point() if projection and test_point._x is None: @@ -641,7 +650,10 @@ def to_dataframe( "lon": track_point.lon } if elevation: - track_point_dict["ele"] = track_point.ele + if track_point.ele is not None: + track_point_dict["ele"] = track_point.ele + else: + track_point_dict["ele"] = 0 if projection: track_point_dict["x"] = track_point._x track_point_dict["y"] = track_point._y @@ -657,6 +669,59 @@ def to_dataframe( df = pd.DataFrame(route_info) return df + def to_csv( + self, + path: str = None, + sep: str = ",", + columns: List[str] = None, + header: bool = True, + index: bool = False) -> Union[str, None]: + """ + Write the GPX object track coordinates to a .csv file. + + Parameters + ---------- + path : str, optional + Path to the .csv file, by default None + sep : str, optional + Separator, by default "," + columns : List[str], optional + List of columns to write, by default None + header : bool, optional + Toggle header, by default True + index : bool, optional + Toggle index, by default False + + Returns + ------- + str + CSV like string if path is set to None. + """ + if columns is None: + columns = ["lat", "lon"] + + elevation = False + projection = False + speed = False + pace = False + ascent_rate = False + ascent_speed = False + + if "ele" in columns: + elevation = True + if "x" in columns or "y" in columns: + projection = True + if "speed" in columns: + speed = True + if "pace" in columns: + pace = True + if "ascent_rate" in columns: + ascent_rate = True + if "ascent_speed" in columns: + ascent_speed = True + + return self.to_dataframe(projection, elevation, speed, pace, ascent_rate, ascent_speed).to_csv(path, sep=sep, columns=columns, header=header, index=index) + def project(self, projection: str): """ Project tracks. diff --git a/ezgpx/gpx_writer/__init__.py b/ezgpx/gpx_writer/__init__.py index 9a35e8e..7107615 100644 --- a/ezgpx/gpx_writer/__init__.py +++ b/ezgpx/gpx_writer/__init__.py @@ -1 +1 @@ -from .writer import * \ No newline at end of file +from .gpx_writer import * \ No newline at end of file diff --git a/ezgpx/gpx_writer/writer.py b/ezgpx/gpx_writer/gpx_writer.py similarity index 99% rename from ezgpx/gpx_writer/writer.py rename to ezgpx/gpx_writer/gpx_writer.py index 6bbc206..5d467c9 100644 --- a/ezgpx/gpx_writer/writer.py +++ b/ezgpx/gpx_writer/gpx_writer.py @@ -7,7 +7,7 @@ from ..gpx_elements import Bounds, Copyright, Email, Extensions, Gpx, Link, Metadata, Person, PointSegment, Point, Route, TrackSegment, Track, WayPoint from ..gpx_parser import Parser, DEFAULT_PRECISION, DEFAULT_TIME_FORMAT -class Writer(): +class GPXWriter(): """ GPX file writer. """ @@ -26,7 +26,7 @@ def __init__( precisions: dict = None, time_format: str = None) -> None: """ - Initialize Writer instance. + Initialize GPXWriter instance. Args: gpx (Gpx, optional): Gpx instance to write. Defaults to None. @@ -241,7 +241,7 @@ def add_metadata(self, element: ET.Element, metadata: Metadata) -> ET.Element: xml.etree.ElementTree.Element: GPX element. """ if metadata is not None: - metadata_ = ET.SubElement(self.gpx_root, metadata.tag) + metadata_ = ET.SubElement(element, metadata.tag) metadata_, _ = self.add_subelement(metadata_, "name", metadata.name) metadata_, _ = self.add_subelement(metadata_, "desc", metadata.desc) metadata_ = self.add_person(metadata_, metadata.author) @@ -492,7 +492,7 @@ def add_root_extensions(self) -> None: def gpx_to_string(self) -> str: """ - Convert Gpx instance to string. + Convert Gpx instance to a string (the content of a .gpx file). Returns: str: String corresponding to the Gpx instance. @@ -578,5 +578,4 @@ def write(self, path: str, check_schemas: bool = False, extensions_schemas: bool if not verification_gpx.check_schemas(self.path, extensions_schemas=extensions_schemas): logging.error("Invalid written file (does not follow schema)") return False - return True - + return True \ No newline at end of file diff --git a/ezgpx/kml_writer/__init__.py b/ezgpx/kml_writer/__init__.py new file mode 100644 index 0000000..a2e7246 --- /dev/null +++ b/ezgpx/kml_writer/__init__.py @@ -0,0 +1 @@ +from .kml_writer import * \ No newline at end of file diff --git a/ezgpx/kml_writer/kml_writer.py b/ezgpx/kml_writer/kml_writer.py new file mode 100644 index 0000000..8b083b0 --- /dev/null +++ b/ezgpx/kml_writer/kml_writer.py @@ -0,0 +1,434 @@ +import os +from typing import Optional, Union, List, Tuple, Dict +import logging +import xml.etree.ElementTree as ET +from datetime import datetime + +from ..gpx_elements import Bounds, Copyright, Email, Extensions, Gpx, Link, Metadata, Person, PointSegment, Point, Route, TrackSegment, Track, WayPoint +from ..gpx_parser import Parser, DEFAULT_PRECISION, DEFAULT_TIME_FORMAT + +DEFAULT_NORMAL_STYLE = {"color": "ff0000ff", + "width": 2, + "fill": 0 + } + +DEFAULT_HIGHLIGHT_STYLE = {"color": "ff0000ff", + "width": 2, + "fill": 0 + } + +DEFAULT_STYLES = [("normal", DEFAULT_NORMAL_STYLE), + ("highlight", DEFAULT_HIGHLIGHT_STYLE) + ] + +class KMLWriter(): + """ + KML file writer. + """ + + def __init__( + self, + gpx: Gpx = None, + path: str = None, + properties: bool = True, + metadata: bool = True, # unused + way_points: bool = True, + routes: bool = True, + extensions: bool = True, + ele: bool = True, + time: bool = True, + precisions: dict = None, + time_format: str = None, + styles: List[Tuple[str, Dict]] = DEFAULT_STYLES) -> None: + """ + Initialize GPXWriter instance. + """ + self.gpx: Gpx = gpx + self.path: str = path + self.file_name: str = "" + self.kml_string: str = "" + + # Parameters + self.properties: bool = properties + self.metadata: bool = metadata + self.way_points: bool = way_points + self.routes: bool = routes + self.extensions: bool = extensions + self.ele: bool = ele + self.time: bool = time + + self.precisions: Dict = precisions + self.time_format = time_format + + self.styles = styles + + self.kml_root = None + + def add_subelement(self, element: ET.Element, sub_element: str, text: str) -> Tuple[ET.Element, Union[ET.Element, None]]: + """ + Add sub-element to GPX element. + + Args: + element (xml.etree.ElementTree.Element): GPX element. + sub_element (str): GPX sub-element. + text (str): GPX sub-element text. + + Returns: + Tuple[xml.etree.ElementTree.Element, Union[xml.etree.ElementTree.Element, None]]: GPX element and GPX sub-element (if not None). + """ + sub_element_ = None + if text is not None: + sub_element_ = ET.SubElement(element, sub_element) + sub_element_.text = text + return element, sub_element_ + + def add_subelement_number(self, element: ET.Element, sub_element: str, number: Union[int, float], precision: int = DEFAULT_PRECISION) -> Tuple[ET.Element, Union[ET.Element, None]]: + """ + Add sub-element to GPX element. + + Args: + element (xml.etree.ElementTree.Element): GPX element. + sub_element (str): GPX sub-element. + number (Union[int, float], optional): GPX sub-element value. + precision (int, optional): Precision. Defaults to DEFAULT_PRECISION. + + Returns: + Tuple[xml.etree.ElementTree.Element, Union[xml.etree.ElementTree.Element, None]]: GPX element and GPX sub-element (if not None). + """ + sub_element_ = None + if number is not None: + sub_element_ = ET.SubElement(element, sub_element) + if type(number) is int: + sub_element_.text = str(number) + elif type(number) is float: + sub_element_.text = "{:.{}f}".format(number, precision) + else: + logging.error("Invalid number type.") + return element, sub_element_ + + def add_subelement_time(self, element: ET.Element, sub_element: str, time: datetime, format: str = DEFAULT_TIME_FORMAT) -> ET.Element: + """ + Add sub-element to GPX element. + + Args: + element (xml.etree.ElementTree.Element): GPX element. + sub_element (str): GPX sub-element. + time (datetime, optional): GPX sub-element value. + format (str, optional): Format. Defaults to DEFAULT_TIME_FORMAT. + + Returns: + Tuple[xml.etree.ElementTree.Element, Union[xml.etree.ElementTree.Element, None]]: GPX element and GPX sub-element (if not None). + """ + sub_element_ = None + if time is not None: + sub_element_ = ET.SubElement(element, sub_element) + try: + sub_element_.text = time.strftime(format) + except: + logging.error("Invalid time format.") + return element, sub_element_ + + def add_pair(self, element: ET.Element, key: str, style_url: str) -> ET.Element: + """ + Add StyleMap to KML element. + + Parameters + ---------- + element : ET.Element + KML element. + key : str + Key. + style_url : str + Style URL. + + Returns + ------- + ET.Element + KML element. + """ + pair_ = ET.SubElement(element, "Pair") + pair_, _ = self.add_subelement(pair_, "key", key) + pair_, _ = self.add_subelement(pair_, "styleUrl", style_url) + return element + + def add_stylemap(self, element: ET.Element, id: str) -> ET.Element: + """ + Add StyleMap to KML element. + + Parameters + ---------- + element : ET.Element + KML element. + id : str + StyleMap element id. + + Returns + ------- + ET.Element + KML element. + """ + stylemap_ = ET.SubElement(element, "StyleMap") + stylemap_.set("id", id) + style_id = 1 + for style_key, style in self.styles: + stylemap_ = self.add_pair(stylemap_, style_key, "#style" + str(style_id)) + style_id += 1 + return element + + def add_polystyle(self, element: ET.Element, style: Dict) -> ET.Element: + """ + Add PolyStyle to KML element. + + Parameters + ---------- + element : ET.Element + KML element. + style : Dict + Style. + + Returns + ------- + ET.Element + KML element. + """ + polystyle_ = ET.SubElement(element, "PolyStyle") + try: + polystyle_, _ = self.add_subelement_number(polystyle_, "fill", style["fill"]) + except: + logging.warning("No fill attribute in style") + polystyle_, _ = self.add_subelement_number(polystyle_, "fill", 0) + return element + + def add_linestyle(self, element: ET.Element, style: Dict) -> ET.Element: + """ + Add LineStyle to KML element. + + Parameters + ---------- + element : ET.Element + KML element. + style : Dict + Style. + + Returns + ------- + ET.Element + KML element. + """ + linestyle_ = ET.SubElement(element, "LineStyle") + try: + linestyle_, _ = self.add_subelement(linestyle_, "color", style["color"]) + except: + logging.warning("No color attribute in style") + linestyle_, _ = self.add_subelement(linestyle_, "color", "ff0000ff") + try: + linestyle_, _ = self.add_subelement_number(linestyle_, "width", style["width"]) + except: + logging.warning("No width attribute in style") + linestyle_, _ = self.add_subelement_number(linestyle_, "width", 2) + return element + + def add_style(self, element: ET.Element, id: str, style: Dict) -> ET.Element: + """ + Add Style to KML element. + + Parameters + ---------- + element : ET.Element + KML element. + id : str + Style element id. + style : Dict + Line style. + + Returns + ------- + ET.Element + KML element. + """ + style_ = ET.SubElement(element, "Style") + style_.set("id", id) + style_ = self.add_linestyle(style_, style) + style_ = self.add_polystyle(style_, style) + return element + + def add_linestring(self, element: ET.Element) -> ET.Element: + """ + Add LineString to KML element. + + Parameters + ---------- + element : ET.Element + KML element. + + Returns + ------- + ET.Element + KML element. + """ + linestring_ = ET.SubElement(element, "LineString") + linestring_, _ = self.add_subelement_number(linestring_, "tessellate", 1) + coordinates = self.gpx.to_csv(path=None, columns=["lon", "lat", "ele"], header=False).replace("\n", " ") + linestring_, _ = self.add_subelement(linestring_, "coordinates", coordinates) + return element + + def add_placemark(self, element: ET.Element) -> ET.Element: + """ + Add Placemark to KML element. + + Parameters + ---------- + element : ET.Element + KML element. + + Returns + ------- + ET.Element + KML element. + """ + placemark_ = ET.SubElement(element, "Placemark") + placemark_, _ = self.add_subelement(placemark_, "name", self.gpx.name()) + placemark_, _ = self.add_subelement(placemark_, "styleUrl", "#stylemap") + placemark_ = self.add_linestring(placemark_) + return element + + def add_document(self, element: ET.Element) -> ET.Element: + """ + Add Document to KML element. + + Parameters + ---------- + element : ET.Element + KML element. + + Returns + ------- + ET.Element + KML element. + """ + document_ = ET.SubElement(element, "Document") + document_, _ = self.add_subelement(document_, "name", self.file_name) + id = 1 + for style_key, style in self.styles: + document_ = self.add_style(document_, "style" + str(id), style) + id += 1 + document_ = self.add_stylemap(document_, "stylemap") + document_ = self.add_placemark(document_) + return element + + def add_root_document(self) -> None: + """ + Add Document element to the KML root element. + """ + logging.info("Preparing Document...") + + self.kml_root = self.add_document(self.kml_root) + + def add_root_properties(self) -> None: + """ + Add properties to the GPX root element. + """ + logging.info("Preparing properties...") + + # According to .kml file from Google Earth Pro + self.kml_root.set("xmlns", "http://www.opengis.net/kml/2.2") + self.kml_root.set("xmlns:gx", "http://www.google.com/kml/ext/2.2") + self.kml_root.set("xmlns:kml", "http://www.opengis.net/kml/2.2") + self.kml_root.set("xmlns:atom", "http://www.w3.org/2005/Atom") + + def gpx_to_string(self) -> str: + """ + Convert Gpx instance to a string (the content of a .kml file). + + Returns: + str: String corresponding to the Gpx instance. + """ + if self.gpx is not None: + logging.info("Start convertion from GPX to string") + # Reset string + self.kml_string = "" + + # Root + self.kml_root = ET.Element("kml") + + # Properties + if self.properties: + self.add_root_properties() + + # Document + self.add_root_document() + + # Convert data to string + logging.info("Converting GPX to string...") + self.gpx_string = ET.tostring(self.kml_root, encoding="unicode") + # self.gpx_string = ET.tostring(kml_root, encoding="utf-8") + + logging.info(f"GPX successfully converted to string:\n{self.gpx_string}") + + return self.gpx_string + + def write_gpx(self): + """ + Convert Gpx instance to string and write to file. + """ + # Open/create GPX file + try: + f = open(self.path, "w") + except OSError: + logging.exception(f"Could not open/read file: {self.path}") + raise + # Write GPX file + with f: + f.write("") + f.write(self.gpx_string) + + def write( + self, + path: str, + styles: Optional[List[Tuple[str, Dict]]] = None, + check_schemas: bool = False, + extensions_schemas: bool = False) -> bool: + """ + Handle writing. + + Parameters + ---------- + path : str + Path to write the KML file. + styles : Optional[List[Tuple[str, Dict]]], optional + List of (style_id, style) tuples, by default None + check_schemas : bool, optional + Toggle schema verification after writting, by default False + extensions_schemas : bool, optional + Toggle extensions schema verificaton after writing. + Requires internet connection and is not guaranted to work, + by default False + + Returns + ------- + bool + bool: Return False if written file does not follow checked schemas. Return True otherwise. + """ + # Handle path + directory_path = os.path.dirname(os.path.realpath(path)) + if not os.path.exists(directory_path): + logging.error("Provided path does not exist") + return + self.path = path + self.file_name = os.path.basename(self.path) + + # Update style + if styles is not None: + self.styles = styles + + # Write .kml file + self.gpx_to_string() + self.write_gpx() + + # Check schema + if check_schemas: + verification_gpx = Parser(path, check_schemas=False, extensions_schemas=False).gpx + if not verification_gpx.check_schemas(self.path, extensions_schemas=extensions_schemas): + logging.error("Invalid written file (does not follow schema)") + return False + return True \ No newline at end of file diff --git a/notes.md b/notes.md index 3908914..2745cca 100644 --- a/notes.md +++ b/notes.md @@ -37,7 +37,7 @@ - [gpxpy](https://github.com/tkrajina/gpxpy) ## 📝 TO DO LIST !! -- Update doc +- Sub classes for GPX & KML writers - Merge method - Garmin extensions - Compute length properly (improve haversine distance precision, 2D, 3D) \ No newline at end of file diff --git a/setup.py b/setup.py index c3d1cec..9c77cc7 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ setup( name='ezgpx', - version='0.1.6', + version='0.1.7', description='Easy to use Python GPX library', long_description=long_description, long_description_content_type='text/markdown', diff --git a/tests/test_files/files/river_run.kml b/tests/test_files/files/river_run.kml new file mode 100644 index 0000000..cc2f801 --- /dev/null +++ b/tests/test_files/files/river_run.kml @@ -0,0 +1,44 @@ + + + + river_run.kmz + + + + + normal + #inline0 + + + highlight + #inline + + + + river_run + #inline1 + + 1 + + 4.481370525731916,43.95650026952033,0 4.481485367625671,43.95640402998316,0 4.48217105951252,43.95634375687478,0 4.482625246024401,43.95603451023627,0 4.4831328235635,43.95565312845113,0 4.483248677881459,43.95548113778926,0 4.483228264220678,43.95528241086905,0 4.482661660883509,43.95478945244211,0 4.481919341209759,43.95404851985435,0 4.481540255722058,43.95343948757471,0 4.481313859363598,43.95299569700544,0 4.480934729912864,43.95259637047558,0 4.480575541322994,43.95234276353923,0 4.480200336166629,43.95182937136925,0 4.479806014310361,43.95168669707343,0 4.479494222073153,43.951612498898,0 4.479134685242006,43.95169274282107,0 4.478726214959467,43.95166299785402,0 4.478475801453216,43.95158766614033,0 4.478051640165024,43.95155606873482,0 4.477610752630943,43.95141668347881,0 4.477166515248623,43.95132656247834,0 4.476363091770916,43.95111390195405,0 4.475542915866724,43.95096436935327,0 4.474738177568025,43.95074609475913,0 4.474187956899178,43.95047016036906,0 4.473591480221748,43.95014278603475,0 4.473045769240125,43.94986439544564,0 4.472646984510846,43.94944414399873,0 4.472453791841843,43.94918740301012,0 4.472208994365355,43.94888654851936,0 4.471919373274504,43.94831467188851,0 4.471746705698967,43.94780155119306,0 4.471568035181946,43.94738449319705,0 4.471408888830608,43.9470374344354,0 4.471065491013366,43.94687554627505,0 4.470688199687944,43.94668107136336,0 4.470397428728495,43.94649446752341,0 4.470145638031163,43.94635754187824,0 4.469623434312475,43.9457342737384,0 4.468751637525134,43.94535709422169,0 4.468064704520016,43.94511850465413,0 4.467289417334166,43.94487121314351,0 4.466493647114187,43.94461048998615,0 4.465939729738999,43.94443244107807,0 4.464718384970958,43.9442473015324,0 4.464351616584317,43.94421278036327,0 4.463969160406829,43.94405564315364,0 4.463476306934416,43.94389447104449,0 4.463090024138285,43.94373262158786,0 4.462879409646819,43.94372226400765,0 4.462255865217548,43.94355561844627,0 4.461571925045831,43.943468200407,0 4.461385092965584,43.94348209737127,0 4.460986811050535,43.94347625175961,0 4.460474141571367,43.94348143925352,0 4.460031215207221,43.94345881916114,0 4.459655853774165,43.94353758962629,0 4.459261570238844,43.94355323275558,0 4.459056751429631,43.94351630011722,0 4.458576445799503,43.94360834518996,0 4.458134803833785,43.9437876434818,0 4.457952592088372,43.94392125684793,0 4.457842682598483,43.94397165295425,0 4.457777110257646,43.94400921119423,0 4.457435101456886,43.94397026260703,0 4.456951628392622,43.94400445926086,0 4.456646729230965,43.94389488416176,0 4.456329040845746,43.94402974667912,0 4.456614670882828,43.94388131589383,0 4.45625903831923,43.94378303045221,0 4.455973856504247,43.943679881332,0 4.455362549013799,43.94352987856555,0 4.454912258018409,43.94337134567873,0 4.454569790700324,43.94318611203386,0 4.454261671334983,43.94302205852491,0 4.453747066032532,43.9428011896551,0 4.452895895373416,43.94255237122753,0 4.452234448721066,43.94236817309751,0 4.451786499329067,43.94235751611421,0 4.451228988282079,43.94224232098738,0 4.450895988415777,43.94223345059486,0 4.450859413008914,43.94227132546244,0 4.450464104704164,43.94227258122023,0 4.450182012762918,43.94219119049276,0 4.450137845864079,43.94221059827503,0 4.449645520944168,43.94213517698861,0 4.449555029205825,43.94219373973657,0 4.449202324919468,43.94214339230722,0 4.448362657080089,43.94250541287927,0 4.447508720407556,43.94234414312373,0 4.44674444115511,43.94219225841487,0 4.444017876663287,43.94112577388795,0 4.440731833830527,43.93984632689045,0 4.43929712449857,43.93941089389966,0 4.438480155652675,43.93908983506951,0 4.437548085415863,43.93880264247446,0 4.436713505467433,43.93847554120214,0 4.436174871782159,43.93811744603194,0 4.435987559514802,43.93776245217295,0 4.435721728674342,43.93762143292568,0 4.435133618949722,43.9373719092289,0 4.434508758239268,43.93668581681998,0 4.433723231196776,43.9367140606182,0 4.433156015115012,43.93719108812454,0 4.432780383880834,43.93787333163846,0 4.432568834935033,43.93821521109963,0 4.432293222751998,43.93858812830476,0 4.431685013885767,43.93911030453158,0 4.431185387504,43.93939669588573,0 4.430083616979665,43.93922077016635,0 4.4296269893463,43.93920270814799,0 4.428323190978871,43.93856087537944,0 4.427584247689214,43.9382753149994,0 4.426161273953251,43.93793277560601,0 4.42641789317856,43.93847746796891,0 4.425323885387183,43.93812746283394,0 4.425762561853035,43.9385030374483,0 4.425958119677249,43.93890784352498,0 4.425956254429773,43.93943043933185,0 4.426136395199133,43.93968518602857,0 4.426730391666167,43.93962465981021,0 4.427084421276815,43.94010473060811,0 4.427502537207692,43.9402752450284,0 4.427677046547771,43.94067448693493,0 4.427817926952454,43.94117558192269,0 4.427527415590607,43.94173885225171,0 4.427365594416067,43.9421798278071,0 4.427133554582598,43.94194222722953,0 4.427211116979024,43.94140012738487,0 4.427188019865302,43.94104261709195,0 4.426983391618375,43.94080950125932,0 4.426783241986428,43.94086594480683,0 4.426557558873389,43.94153710085218,0 4.426265146476894,43.94204212506139,0 4.426652958804524,43.94359284119581,0 4.426292124463997,43.94543150745258,0 4.426813838190058,43.94522813614635,0 4.42806393948346,43.94480264937894,0 4.42952712018386,43.9446829039924,0 4.430545762229694,43.94499762735681,0 4.431442682814877,43.94541910472979,0 4.431836469026735,43.94522447194187,0 4.432520506709432,43.94498468524046,0 4.43357139371267,43.94507827124344,0 4.43462335321086,43.94494841624475,0 4.435365017761795,43.94492408869366,0 4.436191051753521,43.94525700663278,0 4.43689473530603,43.9451788102384,0 4.437290550099111,43.94546524927863,0 4.437637681284148,43.94572954955036,0 4.43824472872798,43.94572681781147,0 4.438595512684302,43.94570021394119,0 4.439050847342001,43.94570173724839,0 4.43941283106188,43.94531585482527,0 4.439644030707328,43.94523012228829,0 4.440700632976366,43.94507696348783,0 4.441132159085512,43.94474459738824,0 4.441636685316945,43.94489917971361,0 4.442258843194122,43.9450110464891,0 4.442876630333828,43.94489558416983,0 4.44337934876711,43.94476133319761,0 4.444329090513657,43.94466174977025,0 4.445278706111832,43.94476489282206,0 4.446063549305109,43.94498290034392,0 4.447193453972398,43.94497521394299,0 4.447783435692177,43.94470902998202,0 4.448421960977502,43.94473453411275,0 4.449155426659592,43.94479123672536,0 4.449694523207874,43.9447314865907,0 4.450545115398277,43.94420687701015,0 4.450344521671408,43.94508133362543,0 4.452092260990696,43.94626890623253,0 4.452837783556118,43.94709971646544,0 4.454008145947899,43.94785781894775,0 4.454981241383029,43.94798710340307,0 4.456086323919868,43.94806074915915,0 4.45668370915131,43.94771260025827,0 4.457895879572069,43.94791270839947,0 4.458370206875264,43.94666921235233,0 4.459056875045928,43.94630681879157,0 4.459848533644164,43.94633984741924,0 4.460677890923037,43.94594480960369,0 4.461305796660742,43.94606523395046,0 4.461755136370602,43.94663814810184,0 4.462370511561387,43.94601729922905,0 4.466322215364871,43.94715529316555,0 4.469040014751632,43.9487389292463,0 4.469032461492654,43.94944280917152,0 4.46906485470053,43.95030323676922,0 4.469224139871784,43.95074899446532,0 4.468838875067485,43.95093815102982,0 4.468687260058257,43.95165230551246,0 4.468905934420615,43.95247716424414,0 4.46920735087587,43.95332774849614,0 4.470059838286053,43.95369370863435,0 4.470170646991905,43.95412551525474,0 4.474563850474185,43.95437239622024,0 4.475634234502877,43.95439511533763,0 4.476732513830219,43.95489463743861,0 4.477790651084337,43.95428159907738,0 4.478987584279615,43.95384123854528,0 4.481285926392142,43.95638766191445,0 + + + + + diff --git a/tests/test_files/files/strava_run_1_test.kml b/tests/test_files/files/strava_run_1_test.kml new file mode 100644 index 0000000..7920e93 --- /dev/null +++ b/tests/test_files/files/strava_run_1_test.kml @@ -0,0 +1,356 @@ + + + + strava_run_1_test.kml + + + + + normal + #style1 + + + highlight + #style2 + + + + Dérouillage habituel 💥 + #stylemap + + 1 + 4.453089,44.043332,110.7 4.453113,44.043353,111.0 + 4.453133,44.0434,111.3 4.453129,44.04353,111.8 4.453114,44.043605,112.0 + 4.453109,44.043631,112.0 4.453108,44.043667,112.1 4.453098,44.043735,112.4 + 4.453163,44.043909,113.3 4.453212,44.044106,115.0 4.453219,44.044292,117.0 + 4.45322,44.044311,117.2 4.45317,44.04446,118.4 4.453061,44.044596,119.7 + 4.453037,44.044613,119.9 4.452855,44.044707,121.3 4.452821,44.044719,121.6 + 4.45261,44.044785,123.2 4.452382,44.044853,124.6 4.452144,44.044923,125.7 + 4.452106,44.044939,125.9 4.451934,44.045037,126.4 4.451692,44.045141,126.7 + 4.45155,44.045292,126.8 4.451434,44.045437,126.9 4.451188,44.045415,126.4 + 4.450978,44.045405,125.6 4.450933,44.045407,125.4 4.450696,44.045407,124.4 + 4.450649,44.045406,124.2 4.45038,44.045384,122.6 4.450104,44.04538,121.5 + 4.449997,44.045384,121.4 4.449743,44.045388,122.0 4.449666,44.045394,122.5 + 4.449516,44.045432,123.4 4.449498,44.045458,123.3 4.449469,44.045613,123.2 + 4.449432,44.045773,123.2 4.449462,44.045962,123.1 4.449464,44.045989,123.1 + 4.449446,44.046103,123.2 4.449441,44.046162,123.3 4.449389,44.04627,123.6 + 4.449359,44.046289,123.7 4.449187,44.046323,124.0 4.448991,44.046325,124.4 + 4.44871,44.046309,125.0 4.448669,44.046305,125.1 4.448381,44.046318,126.0 + 4.448353,44.046317,126.1 4.448161,44.046322,127.0 4.448133,44.046323,127.1 + 4.448025,44.046337,127.6 4.447816,44.046362,128.7 4.447535,44.046404,130.0 + 4.447291,44.046439,131.1 4.44727,44.046438,131.2 4.447132,44.046429,131.9 + 4.446872,44.046458,133.0 4.446837,44.046458,133.1 4.446631,44.046511,134.3 + 4.446527,44.046627,136.1 4.446454,44.04674,138.0 4.446446,44.046755,138.1 + 4.446432,44.04676,138.2 4.446381,44.046746,138.5 4.446347,44.046715,138.8 + 4.446325,44.04666,139.2 4.446271,44.046551,139.8 4.446239,44.046491,140.1 + 4.446209,44.046435,140.5 4.446143,44.046364,141.0 4.446116,44.046345,141.2 + 4.445958,44.046311,142.0 4.445725,44.046298,142.8 4.445622,44.046275,142.9 + 4.445577,44.046263,143.0 4.445455,44.046261,143.0 4.44519,44.046323,143.0 + 4.445146,44.046326,143.0 4.445109,44.046327,142.9 4.444849,44.046288,142.5 + 4.444641,44.046282,142.4 4.444431,44.046287,142.7 4.444306,44.046281,142.9 + 4.444228,44.046296,143.1 4.444165,44.046327,143.3 4.44414,44.046349,143.3 + 4.444134,44.046495,144.0 4.444167,44.046582,144.5 4.444192,44.046673,145.0 + 4.4442,44.046697,145.2 4.444284,44.046884,146.4 4.444384,44.047029,148.0 + 4.44442,44.047033,148.3 4.444517,44.047035,149.0 4.44468,44.047033,150.0 + 4.444791,44.04703,150.6 4.444857,44.047032,150.9 4.444952,44.047065,151.4 + 4.444943,44.047086,151.6 4.4449,44.047221,152.0 4.444909,44.04728,152.0 + 4.444965,44.047363,152.0 4.445029,44.047401,151.8 4.445183,44.047463,151.5 + 4.445386,44.047558,151.1 4.445425,44.047573,151.1 4.445542,44.047608,151.1 + 4.445614,44.04764,151.2 4.445788,44.047666,151.4 4.445823,44.047682,151.5 + 4.446023,44.047709,151.3 4.446244,44.047734,150.7 4.446351,44.047762,150.5 + 4.446473,44.047742,150.3 4.446622,44.04773,150.4 4.446692,44.047742,150.4 + 4.446788,44.04776,150.2 4.446907,44.047778,149.9 4.447045,44.047739,149.5 + 4.44708,44.047738,149.3 4.447311,44.047706,148.5 4.447586,44.047704,147.7 + 4.447688,44.047713,147.5 4.44795,44.047691,146.9 4.447988,44.047681,146.8 + 4.448029,44.047661,146.6 4.448077,44.047626,146.3 4.448148,44.047589,145.9 + 4.44819,44.047585,145.7 4.448262,44.047573,145.4 4.44839,44.047556,145.0 + 4.448543,44.047531,144.6 4.448613,44.047511,144.5 4.448673,44.047502,144.4 + 4.448843,44.047495,144.2 4.448925,44.047491,144.1 4.449119,44.047468,143.8 + 4.449195,44.047446,143.5 4.449387,44.04742,142.9 4.449415,44.047421,142.8 + 4.449475,44.047434,142.6 4.44951,44.047446,142.5 4.44954,44.047446,142.4 + 4.449585,44.047417,142.2 4.449688,44.047301,141.4 4.449725,44.047289,141.2 + 4.449839,44.047285,140.8 4.450027,44.047296,140.3 4.450203,44.0473,140.0 + 4.45024,44.04729,140.0 4.450439,44.047234,139.6 4.450497,44.047207,139.5 + 4.450524,44.047187,139.4 4.450563,44.047169,139.3 4.450634,44.047159,139.1 + 4.450745,44.047164,138.7 4.45088,44.047177,138.3 4.45095,44.047187,138.0 + 4.451066,44.047191,137.6 4.451166,44.047148,137.3 4.451286,44.047117,137.1 + 4.451319,44.047121,137.1 4.451449,44.047141,137.0 4.451479,44.047139,137.0 + 4.451509,44.04714,137.0 4.451547,44.047142,136.9 4.451571,44.047145,136.8 + 4.451738,44.047136,136.6 4.451946,44.047122,136.2 4.452104,44.047073,135.9 + 4.452237,44.047021,135.5 4.45245,44.046962,135.0 4.452681,44.04695,134.5 + 4.452947,44.046896,133.6 4.453138,44.046824,133.0 4.453286,44.046801,132.4 + 4.453451,44.046779,131.9 4.453533,44.046768,131.5 4.453807,44.046717,130.4 + 4.453896,44.046706,130.2 4.454034,44.046716,129.7 4.454281,44.046704,128.9 + 4.454317,44.046697,128.8 4.454351,44.046691,128.8 4.454593,44.04665,128.0 + 4.454855,44.046609,127.3 4.455038,44.046577,126.7 4.455287,44.046544,126.1 + 4.455328,44.046519,125.9 4.45538,44.046437,125.3 4.455386,44.046253,124.1 + 4.455387,44.046216,123.9 4.455424,44.046158,123.5 4.455496,44.04614,123.1 + 4.455782,44.046158,121.8 4.456042,44.046131,120.6 4.456263,44.046088,119.6 + 4.456492,44.046046,118.5 4.45675,44.04598,117.2 4.456796,44.045964,117.0 + 4.457064,44.045865,115.6 4.457096,44.045851,115.4 4.457352,44.045763,114.1 + 4.4574,44.045748,113.9 4.457674,44.045678,112.6 4.457932,44.045614,111.3 + 4.45804,44.045517,110.5 4.458016,44.045327,109.8 4.458005,44.045299,109.8 + 4.457926,44.045117,109.4 4.457874,44.044993,109.2 4.45781,44.044831,109.0 + 4.457765,44.044691,108.8 4.45771,44.0445,108.7 4.457673,44.044334,108.6 + 4.457618,44.044153,108.5 4.457604,44.044089,108.4 4.457539,44.043909,108.3 + 4.457512,44.043854,108.1 4.457424,44.043683,107.5 4.457408,44.04365,107.4 + 4.457323,44.043465,106.4 4.457278,44.043366,105.8 4.457252,44.043302,105.5 + 4.457208,44.043202,105.2 4.457135,44.043056,104.7 4.457191,44.042935,103.9 + 4.457388,44.04286,103.5 4.457534,44.042815,103.4 4.457617,44.042797,103.4 + 4.457822,44.042742,103.4 4.457876,44.042732,103.5 4.458123,44.042683,103.7 + 4.458394,44.042644,103.7 4.458485,44.042637,103.7 4.458558,44.042626,103.6 + 4.458782,44.042618,103.6 4.458996,44.042602,103.6 4.459169,44.042586,103.6 + 4.459293,44.042572,103.6 4.459554,44.042564,103.6 4.4596,44.042561,103.6 + 4.459842,44.042536,103.7 4.460097,44.042512,103.7 4.460341,44.042502,103.6 + 4.460623,44.042475,103.5 4.460804,44.042457,103.5 4.460974,44.04243,103.4 + 4.461222,44.042407,103.4 4.461321,44.042397,103.5 4.461445,44.042385,103.6 + 4.46168,44.042366,103.8 4.461891,44.042348,103.9 4.46204,44.042337,103.9 + 4.462316,44.042349,104.0 4.46261,44.042376,104.2 4.462683,44.042384,104.2 + 4.462936,44.042416,104.5 4.463216,44.042459,104.9 4.463384,44.042504,105.1 + 4.463457,44.042541,105.2 4.463703,44.042601,105.7 4.463935,44.042655,106.2 + 4.464202,44.042717,106.9 4.46445,44.042762,107.6 4.46469,44.042804,108.2 + 4.464959,44.042834,109.0 4.465004,44.042836,109.1 4.465259,44.042825,109.7 + 4.465353,44.042819,109.9 4.465572,44.042804,110.4 4.465847,44.042747,111.0 + 4.466103,44.042703,111.7 4.466143,44.042697,111.8 4.466422,44.042648,112.4 + 4.466456,44.042645,112.4 4.466721,44.042599,113.1 4.46698,44.042593,114.2 + 4.467219,44.042629,115.1 4.467471,44.042662,116.2 4.467508,44.042672,116.4 + 4.467635,44.042728,117.1 4.467679,44.042735,117.2 4.467922,44.042745,118.2 + 4.468114,44.042752,118.8 4.468351,44.042764,119.5 4.468586,44.042783,120.2 + 4.468788,44.042806,120.9 4.468989,44.042827,121.5 4.469254,44.042837,122.3 + 4.469294,44.042846,122.4 4.469489,44.042881,123.0 4.469746,44.042923,124.0 + 4.469974,44.042959,124.9 4.470232,44.042992,126.0 4.470357,44.043009,126.5 + 4.470602,44.043047,127.4 4.470642,44.043054,127.6 4.470908,44.04309,128.2 + 4.471157,44.043108,128.7 4.471237,44.043118,128.7 4.471517,44.043162,129.0 + 4.471631,44.043171,129.1 4.4719,44.043195,129.1 4.472155,44.043204,129.2 + 4.47228,44.043197,129.1 4.47253,44.043184,129.0 4.472587,44.043173,128.9 + 4.472664,44.04316,128.9 4.472928,44.043125,128.7 4.47297,44.043122,128.7 + 4.473229,44.043159,128.3 4.473482,44.0432,127.7 4.473646,44.043224,127.3 + 4.47373,44.043226,127.1 4.473932,44.043163,126.9 4.474082,44.043114,127.1 + 4.474235,44.04304,127.5 4.474366,44.042968,128.0 4.47447,44.042889,128.5 + 4.474574,44.042712,129.5 4.474586,44.042685,129.6 4.474647,44.042488,130.5 + 4.474652,44.042465,130.7 4.474723,44.04227,131.7 4.474741,44.042241,131.8 + 4.474887,44.042102,132.7 4.47512,44.042028,133.6 4.475371,44.041969,134.5 + 4.475436,44.041948,134.7 4.475636,44.041845,135.6 4.47577,44.041693,136.5 + 4.475803,44.04165,136.7 4.475938,44.04148,137.5 4.47596,44.041455,137.7 + 4.476108,44.041281,138.7 4.476129,44.041259,138.9 4.47627,44.041166,139.7 + 4.476449,44.04107,140.7 4.476527,44.041018,141.2 4.476586,44.040982,141.5 + 4.476784,44.040867,142.7 4.476812,44.040852,142.8 4.477018,44.040738,143.9 + 4.477242,44.040643,145.0 4.477316,44.040617,145.3 4.477424,44.040581,145.8 + 4.477513,44.040572,146.2 4.477724,44.04057,147.0 4.477941,44.04061,147.9 + 4.478134,44.040623,148.5 4.478335,44.040681,149.3 4.478533,44.0408,150.2 + 4.478546,44.040833,150.3 4.478592,44.040911,150.8 4.478611,44.040937,150.9 + 4.478715,44.04105,151.6 4.478868,44.041194,152.5 4.478976,44.041264,153.0 + 4.479037,44.041291,153.3 4.479152,44.041375,153.8 4.479189,44.041384,154.0 + 4.479338,44.041443,154.6 4.479416,44.041467,154.9 4.479441,44.041487,155.0 + 4.479546,44.041541,155.6 4.479747,44.04167,156.6 4.47988,44.041769,157.4 + 4.48008,44.041864,158.4 4.480318,44.041928,159.6 4.480481,44.04197,160.3 + 4.480521,44.041968,160.5 4.480711,44.041991,161.3 4.480746,44.04199,161.5 + 4.480855,44.041965,161.9 4.481109,44.041869,163.0 4.481209,44.041806,163.4 + 4.481376,44.041729,164.2 4.481617,44.04161,165.4 4.481718,44.041564,165.9 + 4.481841,44.041512,166.6 4.482048,44.041385,167.9 4.482072,44.041367,168.0 + 4.482204,44.041257,168.8 4.482255,44.041156,169.2 4.482253,44.041133,169.2 + 4.482261,44.041107,169.3 4.482266,44.040956,169.3 4.482274,44.040778,169.2 + 4.482348,44.040633,169.1 4.482462,44.040642,169.6 4.482498,44.040641,169.8 + 4.482681,44.040597,170.7 4.482851,44.04058,171.5 4.482883,44.040577,171.7 + 4.483114,44.040523,173.0 4.483142,44.040523,173.1 4.48327,44.040528,173.9 + 4.483522,44.040539,175.3 4.483555,44.040539,175.4 4.483723,44.040542,176.3 + 4.483866,44.040531,177.0 4.483939,44.040523,177.4 4.484163,44.040501,178.7 + 4.484198,44.040501,178.9 4.484401,44.040485,180.1 4.484499,44.040399,181.0 + 4.484527,44.040254,182.7 4.484531,44.040091,183.4 4.484634,44.039948,184.2 + 4.484809,44.039917,184.8 4.484967,44.039988,185.5 4.485065,44.040081,186.2 + 4.485132,44.04004,186.1 4.485205,44.039928,185.9 4.485304,44.039763,185.5 + 4.485414,44.039586,185.7 4.485483,44.039468,186.1 4.485508,44.039406,186.3 + 4.48555,44.039304,186.8 4.48558,44.039184,187.7 4.485605,44.039086,188.7 + 4.485639,44.038991,190.0 4.485697,44.03887,191.8 4.485775,44.038745,194.1 + 4.485831,44.038683,195.6 4.485862,44.038659,196.3 4.485866,44.038638,196.8 + 4.485861,44.038639,196.8 4.485863,44.038633,197.0 4.485872,44.038624,197.2 + 4.48589,44.038594,198.0 4.485898,44.038557,198.8 4.485894,44.038555,198.9 + 4.485916,44.038528,199.7 4.485926,44.038509,200.2 4.485974,44.038441,202.0 + 4.485994,44.038432,202.4 4.486055,44.038385,204.0 4.486088,44.038361,204.9 + 4.486171,44.038298,207.2 4.486249,44.038224,209.5 4.48627,44.03819,210.4 + 4.486312,44.038134,211.8 4.486324,44.038085,212.8 4.486337,44.038074,213.1 + 4.486394,44.038018,214.6 4.486409,44.037994,215.2 4.486424,44.037977,215.7 + 4.486456,44.037926,216.9 4.486466,44.037912,217.3 4.486498,44.037843,219.0 + 4.486517,44.037819,219.6 4.486526,44.037802,220.0 4.486538,44.037742,221.2 + 4.486575,44.037705,221.9 4.486598,44.037635,222.8 4.486607,44.037536,223.0 + 4.486597,44.037469,222.4 4.486543,44.037425,221.9 4.486368,44.03733,220.8 + 4.486258,44.037275,220.4 4.486202,44.037259,220.2 4.486001,44.037212,219.9 + 4.485935,44.037195,219.8 4.485776,44.037156,219.5 4.485597,44.037071,218.9 + 4.485564,44.037057,218.8 4.485529,44.037047,218.7 4.485329,44.037026,218.1 + 4.485249,44.037022,217.9 4.485113,44.037045,217.7 4.485014,44.037079,217.6 + 4.484979,44.037083,217.6 4.484943,44.037082,217.6 4.484716,44.037046,217.8 + 4.484558,44.036924,217.8 4.484519,44.036883,217.8 4.484477,44.036835,217.8 + 4.484438,44.036779,217.8 4.484416,44.036758,217.8 4.484395,44.036737,217.9 + 4.48429,44.036658,218.1 4.484147,44.036595,218.3 4.484047,44.036573,218.5 + 4.483928,44.036529,218.7 4.483893,44.036495,219.1 4.483846,44.036401,220.1 + 4.483773,44.036287,221.6 4.483673,44.036227,222.6 4.483651,44.036191,223.2 + 4.483607,44.036068,224.1 4.483528,44.03594,225.2 4.483426,44.035848,225.9 + 4.483395,44.035798,226.1 4.483348,44.03578,226.7 4.483331,44.035796,226.7 + 4.48325,44.035917,228.0 4.483198,44.035988,228.4 4.483143,44.036027,228.8 + 4.483089,44.03603,229.1 4.483063,44.036007,229.7 4.483057,44.035838,230.5 + 4.483051,44.035809,230.7 4.482993,44.035756,231.2 4.48297,44.035752,231.6 + 4.482944,44.03575,231.7 4.48288,44.03577,232.4 4.482861,44.035778,232.4 + 4.482807,44.035811,233.0 4.482765,44.035835,233.3 4.482735,44.035848,233.1 + 4.482688,44.035837,233.6 4.482646,44.03581,233.8 4.482618,44.035782,234.1 + 4.482567,44.035756,234.2 4.482557,44.035746,234.3 4.482495,44.035688,234.4 + 4.482452,44.035692,234.4 4.482375,44.035701,234.3 4.482325,44.035688,234.2 + 4.482277,44.035667,234.0 4.482218,44.035675,233.8 4.482235,44.03568,233.8 + 4.482264,44.035676,234.1 4.482281,44.03568,234.1 4.482383,44.035711,234.6 + 4.482425,44.035714,234.7 4.482459,44.035703,234.7 4.482506,44.035706,234.7 + 4.482535,44.035678,234.6 4.482536,44.035665,234.7 4.482495,44.035636,234.6 + 4.482488,44.035603,234.4 4.482485,44.035601,234.4 4.482508,44.0356,234.4 + 4.482518,44.035596,234.5 4.482557,44.035608,234.4 4.482607,44.035634,234.5 + 4.482626,44.035639,234.6 4.482682,44.03564,234.3 4.482689,44.035641,234.3 + 4.482641,44.035622,234.5 4.48262,44.035618,234.5 4.482578,44.035614,234.6 + 4.482524,44.03558,234.4 4.482517,44.035579,234.5 4.482516,44.035579,234.5 + 4.482504,44.035583,234.6 4.482461,44.035587,234.6 4.482459,44.035586,234.7 + 4.482459,44.035586,234.7 4.482466,44.035586,234.7 4.4825,44.035651,235.3 + 4.482495,44.035717,235.6 4.482526,44.035753,235.6 4.482585,44.035789,235.5 + 4.482594,44.035798,235.4 4.482606,44.035811,235.3 4.482628,44.035847,235.2 + 4.482575,44.035875,235.0 4.482545,44.035875,235.1 4.482442,44.035873,235.1 + 4.482407,44.035873,234.9 4.482374,44.035878,234.8 4.482242,44.035865,234.6 + 4.482004,44.035884,233.0 4.481971,44.035892,232.7 4.481831,44.035882,231.4 + 4.481796,44.035874,231.0 4.481656,44.035844,229.5 4.48159,44.035807,228.5 + 4.481464,44.035706,226.1 4.481439,44.03569,226.1 4.481374,44.035639,224.0 + 4.481283,44.035582,221.8 4.481252,44.035581,221.0 4.481063,44.035606,218.1 + 4.481047,44.035624,217.5 4.481013,44.035653,217.6 4.480972,44.035664,216.8 + 4.480843,44.035656,214.5 4.480785,44.03564,213.1 4.480672,44.035639,211.9 + 4.480555,44.035618,209.7 4.480522,44.035621,209.0 4.480461,44.035647,208.4 + 4.480415,44.035694,207.9 4.480395,44.035718,207.2 4.480376,44.035734,207.2 + 4.480292,44.035768,205.7 4.480215,44.035796,204.0 4.48018,44.035816,203.1 + 4.48016,44.03582,203.1 4.480054,44.035846,200.2 4.480023,44.035862,200.2 + 4.47993,44.035879,197.4 4.479659,44.035873,192.3 4.479553,44.035841,190.6 + 4.479525,44.035805,189.8 4.479481,44.035779,189.0 4.479408,44.035764,187.5 + 4.479306,44.035761,186.0 4.479236,44.035769,184.5 4.479096,44.035779,182.0 + 4.479036,44.035777,181.3 4.478815,44.035794,177.1 4.478699,44.035841,175.6 + 4.478673,44.035833,175.0 4.478446,44.035757,172.0 4.478269,44.035695,169.7 + 4.478239,44.035671,169.0 4.478097,44.035575,166.9 4.477926,44.035577,164.9 + 4.477864,44.035592,164.0 4.477799,44.035573,163.3 4.477719,44.035561,162.1 + 4.477591,44.035571,160.5 4.477539,44.035551,159.8 4.477501,44.0355,159.0 + 4.477476,44.035487,158.2 4.477421,44.035488,157.6 4.477393,44.035489,156.9 + 4.477193,44.035451,154.1 4.477076,44.03545,152.4 4.477015,44.035482,151.9 + 4.476883,44.035586,149.6 4.476866,44.0356,149.7 4.476685,44.035725,147.0 + 4.476509,44.035866,144.4 4.476491,44.035893,143.7 4.476481,44.035918,143.8 + 4.476484,44.035947,143.8 4.476476,44.036097,143.4 4.476464,44.036198,143.1 + 4.476445,44.036195,142.5 4.476332,44.03614,141.4 4.476266,44.03612,140.2 + 4.476143,44.036134,138.5 4.476107,44.036127,137.9 4.475996,44.036102,136.8 + 4.475875,44.036104,135.1 4.475858,44.036114,135.2 4.475803,44.036124,134.2 + 4.475709,44.036089,133.5 4.4757,44.036063,133.4 4.475681,44.035991,133.4 + 4.475675,44.035908,133.2 4.475654,44.035714,132.8 4.475657,44.035645,132.7 + 4.475628,44.03546,132.2 4.475604,44.035371,132.0 4.475584,44.035185,131.6 + 4.475572,44.035061,131.3 4.475553,44.034874,130.9 4.475551,44.034839,130.8 + 4.475538,44.034777,130.7 4.475518,44.034583,130.3 4.475506,44.034497,130.1 + 4.475518,44.034294,129.7 4.475534,44.034242,129.6 4.475669,44.034076,129.3 + 4.475795,44.033919,128.9 4.475856,44.033835,128.7 4.475948,44.033655,128.2 + 4.47597,44.033532,127.9 4.475992,44.03334,127.5 4.476002,44.033218,127.2 + 4.476109,44.033053,126.8 4.476137,44.033035,126.7 4.476164,44.032987,126.6 + 4.476129,44.032965,126.0 4.475974,44.032992,125.3 4.475711,44.033036,124.3 + 4.47563,44.033056,124.0 4.475379,44.033114,123.2 4.475337,44.033121,123.0 + 4.475072,44.033173,122.3 4.474865,44.033208,121.8 4.474609,44.033246,121.0 + 4.474531,44.033255,120.8 4.474281,44.03328,120.2 4.474239,44.033284,120.1 + 4.473984,44.033314,119.5 4.473767,44.033324,118.9 4.473508,44.033336,118.2 + 4.473338,44.033348,117.7 4.473076,44.033366,116.9 4.472989,44.033373,116.7 + 4.472723,44.033385,115.9 4.472592,44.033391,115.5 4.472469,44.033401,115.2 + 4.472217,44.033427,114.5 4.472091,44.033425,114.3 4.471841,44.033404,113.8 + 4.471803,44.033402,113.7 4.471517,44.03337,113.2 4.471484,44.033366,113.2 + 4.471233,44.033348,112.8 4.471199,44.033341,112.7 4.470951,44.033312,112.4 + 4.470831,44.033312,112.2 4.470549,44.033314,111.8 4.470292,44.033319,111.6 + 4.470247,44.03332,111.6 4.469983,44.033347,111.2 4.469934,44.033359,111.1 + 4.469696,44.033428,110.8 4.469656,44.033441,110.7 4.469394,44.033518,110.4 + 4.469145,44.0336,110.0 4.469093,44.033618,109.9 4.468907,44.033666,109.5 + 4.468871,44.033679,109.4 4.468713,44.033799,108.9 4.468532,44.033942,108.3 + 4.468311,44.034045,107.6 4.468163,44.034124,107.0 4.468044,44.034175,106.6 + 4.467964,44.034209,106.4 4.467768,44.034276,106.0 4.467729,44.034288,105.9 + 4.467492,44.03436,105.5 4.467344,44.034418,105.3 4.467166,44.034488,105.2 + 4.467003,44.034554,105.0 4.466967,44.034568,105.0 4.46675,44.034657,104.7 + 4.466686,44.034686,104.6 4.466472,44.034781,104.2 4.466367,44.034826,104.0 + 4.466122,44.034925,103.9 4.466061,44.034946,103.9 4.465805,44.035029,103.9 + 4.465778,44.035038,103.9 4.465556,44.03513,103.9 4.465441,44.035184,103.8 + 4.465336,44.03524,103.8 4.465295,44.035253,103.8 4.465163,44.035298,103.8 + 4.46493,44.035401,103.7 4.464815,44.035464,103.6 4.464592,44.035555,103.5 + 4.464523,44.035583,103.4 4.46438,44.035646,103.3 4.464209,44.035744,103.2 + 4.464015,44.035835,103.1 4.463785,44.035964,102.9 4.46376,44.03598,102.9 + 4.463512,44.036075,102.6 4.463268,44.036117,102.4 4.463116,44.036141,102.3 + 4.46303,44.036151,102.3 4.462751,44.03619,102.2 4.46247,44.036218,102.0 + 4.462195,44.036263,102.0 4.461966,44.036359,102.0 4.461931,44.036376,102.0 + 4.461733,44.036491,102.1 4.461637,44.036553,102.1 4.461467,44.036688,102.0 + 4.461382,44.036752,101.9 4.461206,44.036888,101.7 4.46112,44.036955,101.6 + 4.46093,44.037082,101.5 4.460814,44.03716,101.4 4.460616,44.0373,101.2 + 4.460589,44.03732,101.2 4.460403,44.037445,101.0 4.460304,44.037499,100.9 + 4.46009,44.037604,100.8 4.459944,44.03766,100.7 4.459769,44.037721,100.6 + 4.459699,44.037743,100.6 4.459459,44.037798,100.4 4.459322,44.037807,100.4 + 4.459037,44.037821,100.3 4.458953,44.037828,100.3 4.458702,44.037866,100.2 + 4.458622,44.037873,100.1 4.458371,44.037897,100.1 4.458166,44.037915,100.1 + 4.457918,44.037944,100.1 4.457795,44.037956,100.1 4.457545,44.037977,100.0 + 4.457389,44.038002,99.9 4.45712,44.038052,99.9 4.457006,44.03808,99.8 + 4.456734,44.038152,99.8 4.456584,44.038207,99.8 4.456371,44.038306,99.6 + 4.45627,44.03835,99.4 4.456048,44.038407,99.0 4.455972,44.038418,98.9 + 4.455722,44.038441,98.7 4.455647,44.038447,98.7 4.455384,44.038476,98.6 + 4.455136,44.038501,98.6 4.454854,44.038528,98.6 4.454814,44.038532,98.6 + 4.454653,44.038559,98.6 4.45449,44.038579,98.6 4.454415,44.038591,98.6 + 4.454252,44.038624,98.7 4.453979,44.038692,98.8 4.45394,44.038704,98.8 + 4.453675,44.038774,98.7 4.453406,44.038853,98.6 4.453249,44.038902,98.6 + 4.452982,44.038968,98.6 4.452726,44.039069,98.6 4.452685,44.039082,98.6 + 4.452454,44.039155,98.7 4.452421,44.039169,98.7 4.452328,44.039227,98.8 + 4.452154,44.039304,98.7 4.451965,44.039364,98.5 4.451751,44.039471,98.5 + 4.451546,44.039579,98.5 4.451483,44.039613,98.6 4.451305,44.03968,98.6 + 4.451097,44.039804,98.8 4.451006,44.039876,98.9 4.450854,44.039979,99.0 + 4.450791,44.039998,99.1 4.450725,44.040019,99.1 4.450526,44.040089,99.4 + 4.4503,44.040204,99.5 4.450212,44.040267,99.6 4.450013,44.040396,99.8 + 4.449894,44.040468,100.0 4.449687,44.040602,100.3 4.449613,44.040648,100.4 + 4.449393,44.04075,100.6 4.449332,44.040784,100.7 4.449303,44.040799,100.7 + 4.449146,44.040948,100.9 4.449088,44.040996,101.0 4.448929,44.041154,101.3 + 4.448872,44.041198,101.4 4.44872,44.041369,101.7 4.448534,44.041515,101.9 + 4.448482,44.041554,102.0 4.448281,44.041704,102.4 4.448225,44.041736,102.5 + 4.448004,44.041858,102.7 4.447795,44.041962,102.9 4.44766,44.042031,103.1 + 4.447456,44.042137,103.5 4.447399,44.042167,103.6 4.447184,44.042288,104.0 + 4.44711,44.042351,104.1 4.44695,44.042503,104.4 4.446925,44.042524,104.5 + 4.446776,44.042681,105.1 4.446754,44.042703,105.1 4.446619,44.042862,105.7 + 4.446484,44.042997,106.3 4.44634,44.043145,107.0 4.446176,44.043297,107.6 + 4.44615,44.043318,107.7 4.446122,44.043338,107.8 4.446049,44.043457,108.3 + 4.445954,44.043532,108.6 4.445767,44.043649,108.8 4.445713,44.043774,109.1 + 4.445752,44.043922,110.2 4.44582,44.044118,111.8 4.44584,44.044167,112.2 + 4.445928,44.044337,113.5 4.445991,44.044407,114.1 4.446141,44.044469,115.0 + 4.446173,44.04447,115.2 4.446458,44.044425,116.3 4.446501,44.044426,116.5 + 4.446694,44.044435,116.9 4.446835,44.04449,117.1 4.447054,44.044569,117.5 + 4.447288,44.04464,117.8 4.447326,44.044646,117.9 4.447583,44.044671,118.6 + 4.447616,44.044679,118.7 4.447817,44.044718,119.3 4.448025,44.044814,120.1 + 4.448204,44.044913,121.0 4.448261,44.044943,121.4 4.448485,44.045059,122.8 + 4.448712,44.045169,124.4 4.448901,44.04523,125.4 4.448936,44.045234,125.6 + 4.449208,44.045294,125.9 4.44924,44.045305,125.8 4.449347,44.045371,125.4 + 4.449376,44.045423,125.1 4.449408,44.045609,123.9 4.449427,44.045654,123.5 + 4.44948,44.045654,123.2 4.4495,44.045635,123.2 4.449534,44.045556,123.1 + 4.449539,44.045497,123.2 4.449607,44.045413,123.4 4.449812,44.045403,121.7 + 4.450077,44.045411,121.5 4.450109,44.045414,121.5 4.450177,44.045419,121.7 + 4.450208,44.045419,121.8 4.45033,44.045419,122.3 4.450428,44.045419,122.9 + 4.450523,44.045429,123.6 4.450554,44.045427,123.7 4.450659,44.045444,124.3 + 4.450766,44.045457,124.8 4.450805,44.045455,124.9 4.451035,44.045456,125.8 + 4.451262,44.045451,126.6 4.451508,44.045445,126.9 4.45158,44.045314,126.8 + 4.451677,44.045173,126.7 4.451868,44.045094,126.6 4.452089,44.044981,126.1 + 4.452191,44.044936,125.7 4.452273,44.044906,125.3 4.452547,44.044845,123.9 + 4.452629,44.044824,123.4 4.452848,44.044741,121.7 4.453064,44.044647,120.1 + 4.453128,44.044583,119.4 4.453235,44.04441,117.8 4.453242,44.044372,117.6 + 4.453228,44.044189,115.8 4.453215,44.044082,114.6 4.453187,44.043898,113.2 + 4.453148,44.043789,112.6 4.453117,44.043606,111.9 4.453122,44.043535,111.8 + 4.453165,44.043391,111.2 + + + + \ No newline at end of file