Commit a2b94a48 authored by Christian Ledermann's avatar Christian Ledermann

add geometry processing

parent c9ef8d55
# -*- coding: utf-8 -*-
from shapely.geometry import Point, LineString, Polygon
from shapely.geometry import MultiPoint, MultiLineString, MultiPolygon
from shapely.geometry.polygon import LinearRing
import logging
logger = logging.getLogger('fastkml')
try:
from lxml import etree
LXML = True
except ImportError:
import xml.etree.ElementTree as etree
LXML = False
class KML(object):
""" represents a KML File """
......@@ -19,7 +29,9 @@ class KML(object):
self.from_string(f.read())
f.close()
def from_string(self, xml_string):
""" create a KML object from a xml string"""
element = etree.XML(xml_string)
if element.tag.endswith('kml'):
ns = element.tag.rstrip('kml')
......@@ -68,20 +80,36 @@ class _Feature(object):
subclasses are:
Container (Document, Folder),
Placemark,
NetworkLink,
GroundOverlay,
PhotoOverlay,
ScreenOverlay
#NetworkLink,
#GroundOverlay,
#PhotoOverlay,
#ScreenOverlay
"""
id = None
name = None
#User-defined text displayed in the 3D viewer as the label for the
#object (for example, for a Placemark, Folder, or NetworkLink).
description = None
#User-supplied content that appears in the description balloon.
visibility = 1
#Boolean value. Specifies whether the feature is drawn in the 3D
#viewer when it is initially loaded. In order for a feature to be
#visible, the <visibility> tag of all its ancestors must also be
#set to 1.
isopen = 0
#Boolean value. Specifies whether a Document or Folder appears
#closed or open when first loaded into the Places panel.
#0=collapsed (the default), 1=expanded.
styleUrl = None
#URL of a <Style> or <StyleMap> defined in a Document.
#If the style is in the same file, use a # reference.
#If the style is defined in an external file, use a full URL
#along with # referencing.
#atom_author = None
#atom_link = None
#styleUrl = None
def __init__(self, ns, id=None, name=None, description=None):
......@@ -155,7 +183,6 @@ class _Container(_Feature):
def etree_element(self):
element = super(_Container, self).etree_element()
for feature in self.features():
assert(feature != self)
element.append(feature.etree_element())
return element
......@@ -192,7 +219,7 @@ class Document(_Container):
class Folder(_Container):
"""
A Folder is used to arrange other Features hierarchically
(Folders, Placemarks, NetworkLinks, or Overlays).
(Folders, Placemarks, #NetworkLinks, or #Overlays).
"""
__name__ = "Folder"
......@@ -210,9 +237,175 @@ class Folder(_Container):
self.append(feature)
class Placemark(_Feature):
__name__ = "Placemark"
styleUrl = None
geometry = None
pass
def _get_coordinates(self, element):
coordinates = element.find('%scoordinates' % self.ns)
if coordinates is not None:
latlons = coordinates.text.strip().split()
coords = []
for latlon in latlons:
coords.append([float(c) for c in latlon.split(',')])
return coords
def _get_linear_ring(self, element):
# LinearRing
lr = element.find('%sLinearRing' % self.ns)
if lr is not None:
coords = self._get_coordinates(lr)
return LinearRing(coords)
def _get_geometry(self, element):
# Point, LineString,
# Polygon,
point = element.find('%sPoint' % self.ns)
if point is not None:
coords = self._get_coordinates(point)
return Point(coords[0])
line = element.find('%sLineString' % self.ns)
if line is not None:
coords = self._get_coordinates(line)
return LineString(coords)
polygon = element.find('%sPolygon' % self.ns)
if polygon is not None:
outer_boundary = polygon.find('%souterBoundaryIs' %self.ns)
ob = self._get_linear_ring(outer_boundary)
inner_boundaries = polygon.findall('%sinnerBoundaryIs' %self.ns)
ibs = []
for inner_boundary in inner_boundaries:
ibs.append(self._get_linear_ring(inner_boundary))
return Polygon(ob, ibs)
return self._get_linear_ring(element)
def _get_multigeometry(self, element):
# MultiGeometry
multigeometry = element.find('%sMultiGeometry' % self.ns)
geoms = []
if multigeometry is not None:
points = multigeometry.findall('%sPoint' % self.ns)
if points:
for point in points:
geoms.append(Point(self._get_coordinates(point)))
return MultiPoint(geoms)
linestrings = multigeometry.findall('%sLineString' % self.ns)
if linestrings:
for ls in linestrings:
geoms.append(LineString(self._get_coordinates(ls)))
return MultiLineString(geoms)
polygons = multigeometry.findall('%sPolygon' % self.ns)
if polygons:
for polygon in polygons:
outer_boundary = polygon.find('%souterBoundaryIs' %self.ns)
ob = self._get_linear_ring(outer_boundary)
inner_boundaries = polygon.findall('%sinnerBoundaryIs' %self.ns)
ibs = []
for inner_boundary in inner_boundaries:
ibs.append(self._get_linear_ring(inner_boundary))
geoms.append(Polygon(ob, ibs))
return MultiPolygon(geoms)
def from_element(self, element):
super(Placemark, self).from_element(element)
mgeom = self._get_multigeometry(element)
geom = self._get_geometry(element)
if mgeom is not None:
self.geometry = mgeom
elif geom is not None:
self.geometry = geom
else:
logger.warn('No geometries found')
def _etree_coordinates(self, coordinates):
element = etree.Element("coordinates")
if len(coordinates[0]) == 2:
tuples = ('%f,%f,0.0' % tuple(c) for c in coordinates)
elif len(coordinates[0]) == 3:
tuples = ('%f,%f,%f' % tuple(c) for c in coordinates)
else:
raise ValueError("Invalid dimensions")
element.text = ' '.join(tuples)
return element
def _etree_point(self, point):
element = etree.Element("Point")
coords = list(point.coords)
element.append(self._etree_coordinates(coords))
return element
def _etree_linestring(self, linestring):
element = etree.Element("LineString")
coords = list(linestring.coords)
element.append(self._etree_coordinates(coords))
return element
def _etree_linearring(self, linearring):
element = etree.Element("LinearRing")
coords = list(linearring.coords)
element.append(self._etree_coordinates(coords))
return element
def _etree_polygon(self, polygon):
element = etree.Element("Polygon")
outer_boundary = etree.SubElement(element, "outerBoundaryIs")
outer_boundary.append(self._etree_linearring(polygon.exterior))
for ib in polygon.interiors:
inner_boundary = etree.SubElement(element, "innerBoundaryIs")
inner_boundary.append(self._etree_linearring(ib))
return element
def _etree_multipoint(self, points):
element = etree.Element("MultiGeometry")
for point in points.geoms:
element.append(self._etree_point(point))
return element
def _etree_multilinestring(self, linestrings):
element = etree.Element("MultiGeometry")
for linestring in linestrings.geoms:
element.append(self._etree_linestring(linestring))
return element
def _etree_multipolygon(self, polygons):
element = etree.Element("MultiGeometry")
for polygon in polygons.geoms:
element.append(self._etree_polygon(polygon))
return element
def _etree_geometry(self):
if isinstance(self.geometry, Point):
return self._etree_point(self.geometry)
elif isinstance(self.geometry, LineString):
return self._etree_linestring(self.geometry)
elif isinstance(self.geometry, LinearRing):
return self._etree_linearring(self.geometry)
elif isinstance(self.geometry, Polygon):
return self._etree_polygon(self.geometry)
elif isinstance(self.geometry, MultiPoint):
return self._etree_multipoint(self.geometry)
elif isinstance(self.geometry, MultiLineString):
return self._etree_multilinestring(self.geometry)
elif isinstance(self.geometry, MultiPolygon):
return self._etree_multipolygon(self.geometry)
def etree_element(self):
element = super(Placemark, self).etree_element()
if self.geometry is not None:
element.append(self._etree_geometry())
else:
logger.warn('Object does not have a geometry')
return element
# -*- coding: utf-8 -*-
import unittest
import kml
from fastkml import kml
import xml.etree.ElementTree as etree
from shapely.geometry import Point, LineString, Polygon
from shapely.geometry import MultiPoint, MultiLineString, MultiPolygon
from shapely.geometry.polygon import LinearRing
class BuildKmlTestCase( unittest.TestCase ):
class BuildKmlTestCase(unittest.TestCase):
""" Build a simple KML File """
def test_kml(self):
""" kml file without contents """
k=None
k = kml.KML()
self.assertEqual(len(k.features()),0)
self.assertEqual( k.to_string(),
'<ns0:kml xmlns:ns0="http://www.opengis.net/kml/2.2" />')
'<ns0:kml xmlns:ns0="http://www.opengis.net/kml/2.2"/>')
k2 = kml.KML()
k2.from_string(k.to_string())
self.assertEqual(k.to_string(), k2.to_string())
print k.to_string()
def test_folder(self):
""" KML file with folders """
......@@ -26,15 +31,25 @@ class BuildKmlTestCase( unittest.TestCase ):
k.append(f2)
self.assertEqual(len(k.features()),2)
self.assertEqual(len( k.features()[0].features()),1)
print k.to_string()
k2 = kml.KML()
s = k.to_string()
k2.from_string(s)
self.assertEqual(s, k2.to_string())
print s
def test_placemark(self):
k = kml.KML()
p = kml.Placemark('', 'id', 'name', 'description')
p.geometry = Point(0.0, 0.0)
p2 = kml.Placemark('', 'id2', 'name2', 'description2')
p2.geometry = LineString([(0, 0), (1, 1)])
k.append(p)
k.append(p2)
self.assertEqual(len(k.features()),2)
k2 = kml.KML()
k2.from_string(k.to_string())
#self.assertEqual(k.to_string(), k2.to_string())
print k.to_string()
def test_document(self):
k = kml.KML()
......@@ -47,11 +62,19 @@ class BuildKmlTestCase( unittest.TestCase ):
f2 = kml.Folder('', 'id2', 'name2', 'description2')
d.append(f2)
p = kml.Placemark('', 'id', 'name', 'description')
p.geometry = Polygon([(0, 0), (1, 1), (1, 0)])
p2 = kml.Placemark('', 'id2', 'name2', 'description2')
#p2 does not have a geometry!
f2.append(p)
nf.append(p2)
self.assertEqual(len(k.features()),1)
self.assertEqual(len(k.features()[0].features()),2)
k2 = kml.KML()
k2.from_string(k.to_string())
#self.assertEqual(k.to_string(), k2.to_string())
print k.to_string()
class KmlFromStringTestCase( unittest.TestCase ):
......@@ -86,6 +109,9 @@ class KmlFromStringTestCase( unittest.TestCase ):
k.from_string(doc)
self.assertEqual(len(k.features()),1)
self.assertEqual(len(k.features()[0].features()),2)
k2 = kml.KML()
k2.from_string(k.to_string())
#self.assertEqual(k.to_string(), k2.to_string())
print k.to_string()
......@@ -134,6 +160,9 @@ class KmlFromStringTestCase( unittest.TestCase ):
k.from_string(doc)
self.assertEqual(len(k.features()),1)
self.assertEqual(len(k.features()[0].features()),3)
k2 = kml.KML()
k2.from_string(k.to_string())
#self.assertEqual(k.to_string(), k2.to_string())
print k.to_string()
def test_placemark(self):
......@@ -152,16 +181,71 @@ class KmlFromStringTestCase( unittest.TestCase ):
k.from_string(doc)
self.assertEqual(len(k.features()),1)
self.assertEqual(k.features()[0].name, "Simple placemark")
k2 = kml.KML()
k2.from_string(k.to_string())
#self.assertEqual(k.to_string(), k2.to_string())
print k.to_string()
def test_polygon(self):
doc= """<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Placemark>
<name>South Africa</name>
<Polygon><outerBoundaryIs><LinearRing><coordinates>31.521,-29.257,0 31.326,-29.402,0 30.902,-29.91,0 30.623,-30.424,0 30.056,-31.14,0 28.926,-32.172,0 28.22,-32.772,0 27.465,-33.227,0 26.419,-33.615,0 25.91,-33.667,0 25.781,-33.945,0 25.173,-33.797,0 24.678,-33.987,0 23.594,-33.794,0 22.988,-33.916,0 22.574,-33.864,0 21.543,-34.259,0 20.689,-34.417,0 20.071,-34.795,0 19.616,-34.819,0 19.193,-34.463,0 18.855,-34.444,0 18.425,-33.998,0 18.377,-34.137,0 18.244,-33.868,0 18.25,-33.281,0 17.925,-32.611,0 18.248,-32.429,0 18.222,-31.662,0 17.567,-30.726,0 17.064,-29.879,0 17.063,-29.876,0 16.345,-28.577,0 16.824,-28.082,0 17.219,-28.356,0 17.387,-28.784,0 17.836,-28.856,0 18.465,-29.045,0 19.002,-28.972,0 19.895,-28.461,0 19.896,-24.768,0 20.166,-24.918,0 20.759,-25.868,0 20.666,-26.477,0 20.89,-26.829,0 21.606,-26.727,0 22.106,-26.28,0 22.58,-25.979,0 22.824,-25.5,0 23.312,-25.269,0 23.734,-25.39,0 24.211,-25.67,0 25.025,-25.72,0 25.665,-25.487,0 25.766,-25.175,0 25.942,-24.696,0 26.486,-24.616,0 26.786,-24.241,0 27.119,-23.574,0 28.017,-22.828,0 29.432,-22.091,0 29.839,-22.102,0 30.323,-22.272,0 30.66,-22.152,0 31.191,-22.252,0 31.67,-23.659,0 31.931,-24.369,0 31.752,-25.484,0 31.838,-25.843,0 31.333,-25.66,0 31.044,-25.731,0 30.95,-26.023,0 30.677,-26.398,0 30.686,-26.744,0 31.283,-27.286,0 31.868,-27.178,0 32.072,-26.734,0 32.83,-26.742,0 32.58,-27.47,0 32.462,-28.301,0 32.203,-28.752,0 31.521,-29.257,0 </coordinates></LinearRing></outerBoundaryIs><innerBoundaryIs><LinearRing><coordinates>28.978,-28.956,0 28.542,-28.648,0 28.074,-28.851,0 27.533,-29.243,0 26.999,-29.876,0 27.749,-30.645,0 28.107,-30.546,0 28.291,-30.226,0 28.848,-30.07,0 29.018,-29.744,0 29.325,-29.257,0 28.978,-28.956,0 </coordinates></LinearRing></innerBoundaryIs></Polygon>
</Placemark> </kml>"""
k = kml.KML()
k.from_string(doc)
self.assertEqual(len(k.features()),1)
self.assertTrue(isinstance(
k.features()[0].geometry, Polygon))
k2 = kml.KML()
k2.from_string(k.to_string())
#self.assertEqual(k.to_string(), k2.to_string())
print k.to_string()
def test_multipoints(self):
pass
def test_multilinestrings(self):
doc="""<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Placemark>
<name>Dnipro (Dnieper)</name>
<MultiGeometry><LineString><coordinates>33.54,46.831,0 33.606,46.869,0 33.662,46.957,0 33.739,47.05,0 33.859,47.149,0 33.976,47.307,0 33.998,47.411,0 34.155,47.49,0 34.448,47.542,0 34.712,47.553,0 34.946,47.521,0 35.088,47.528,0 35.138,47.573,0 35.149,47.657,0 35.106,47.842,0 </coordinates></LineString><LineString><coordinates>33.194,49.094,0 32.884,49.225,0 32.603,49.302,0 31.886,49.555,0 </coordinates></LineString><LineString><coordinates>31.44,50,0 31.48,49.933,0 31.486,49.871,0 31.467,49.754,0 </coordinates></LineString><LineString><coordinates>30.508,51.217,0 30.478,50.904,0 30.479,50.749,0 30.515,50.597,0 </coordinates></LineString></MultiGeometry>
</Placemark> </kml>"""
k = kml.KML()
k.from_string(doc)
self.assertEqual(len(k.features()),1)
self.assertTrue(isinstance(
k.features()[0].geometry, MultiLineString))
k2 = kml.KML()
k2.from_string(k.to_string())
#self.assertEqual(k.to_string(), k2.to_string())
print k.to_string()
def test_multipolygon(self):
doc = """<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Placemark>
<name>Antartica</name>
<MultiGeometry><Polygon><outerBoundaryIs><LinearRing><coordinates>-59.572,-80.04,0 -59.866,-80.55,0 -60.16,-81,0 -62.255,-80.863,0 -64.488,-80.922,0 -65.742,-80.589,0 -65.742,-80.55,0 -66.29,-80.256,0 -64.038,-80.295,0 -61.883,-80.393,0 -61.139,-79.981,0 -60.61,-79.629,0 -59.572,-80.04,0 </coordinates></LinearRing></outerBoundaryIs></Polygon><Polygon><outerBoundaryIs><LinearRing><coordinates>-159.208,-79.497,0 -161.128,-79.634,0 -162.44,-79.281,0 -163.027,-78.929,0 -163.067,-78.87,0 -163.713,-78.596,0 -163.713,-78.596,0 -163.106,-78.223,0 -161.245,-78.38,0 -160.246,-78.694,0 -159.482,-79.046,0 -159.208,-79.497,0 </coordinates></LinearRing></outerBoundaryIs></Polygon><Polygon><outerBoundaryIs><LinearRing><coordinates>-45.155,-78.047,0 -43.921,-78.478,0 -43.49,-79.086,0 -43.372,-79.517,0 -43.333,-80.026,0 -44.881,-80.34,0 -46.506,-80.594,0 -48.386,-80.829,0 -50.482,-81.025,0 -52.852,-80.967,0 -54.164,-80.634,0 -53.988,-80.222,0 -51.853,-79.948,0 -50.991,-79.615,0 -50.365,-79.183,0 -49.914,-78.811,0 -49.307,-78.459,0 -48.661,-78.047,0 -48.661,-78.047,0 -48.151,-78.047,0 -46.663,-77.831,0 -45.155,-78.047,0 </coordinates></LinearRing></outerBoundaryIs></Polygon><Polygon><outerBoundaryIs><LinearRing><coordinates>-121.212,-73.501,0 -119.919,-73.658,0 -118.724,-73.481,0 -119.292,-73.834,0 -120.232,-74.089,0 -121.623,-74.01,0 -122.622,-73.658,0 -122.622,-73.658,0 -122.406,-73.325,0 -121.212,-73.501,0 </coordinates></LinearRing></outerBoundaryIs></Polygon><Polygon><outerBoundaryIs><LinearRing><coordinates>-125.56,-73.481,0 -124.032,-73.873,0 -124.619,-73.834,0 -125.912,-73.736,0 -127.283,-73.462,0 -127.283,-73.462,0 -126.558,-73.246,0 -125.56,-73.481,0 </coordinates></LinearRing></outerBoundaryIs></Polygon><Polygon><outerBoundaryIs><LinearRing><coordinates>-98.982,-71.933,0 -97.885,-72.071,0 -96.788,-71.953,0 -96.2,-72.521,0 -96.984,-72.443,0 -98.198,-72.482,0 -99.432,-72.443,0 -100.783,-72.502,0 -101.802,-72.306,0 -102.331,-71.894,0 -102.331,-71.894,0 -101.704,-71.718,0 -100.431,-71.855,0 -98.982,-71.933,0 </coordinates></LinearRing></outerBoundaryIs></Polygon><Polygon><outerBoundaryIs><LinearRing><coordinates>-68.451,-70.956,0 -68.334,-71.406,0 -68.51,-71.798,0 -68.784,-72.171,0 -69.959,-72.308,0 -71.076,-72.504,0 -72.388,-72.484,0 -71.898,-72.092,0 -73.074,-72.229,0 -74.19,-72.367,0 -74.954,-72.073,0 -75.013,-71.661,0 -73.916,-71.269,0 -73.916,-71.269,0 -73.23,-71.152,0 -72.075,-71.191,0 -71.781,-70.681,0 -71.722,-70.309,0 -71.742,-69.506,0 -71.174,-69.035,0 -70.253,-68.879,0 -69.724,-69.251,0 -69.489,-69.623,0 -69.059,-70.074,0 -68.726,-70.505,0 -68.451,-70.956,0 </coordinates></LinearRing></outerBoundaryIs></Polygon><Polygon><outerBoundaryIs><LinearRing><coordinates>-58.614,-64.152,0 -59.045,-64.368,0 -59.789,-64.211,0 -60.612,-64.309,0 -61.297,-64.544,0 -62.022,-64.799,0 -62.512,-65.093,0 -62.649,-65.485,0 -62.59,-65.857,0 -62.12,-66.19,0 -62.806,-66.426,0 -63.746,-66.504,0 -64.294,-66.837,0 -64.882,-67.15,0 -65.508,-67.582,0 -65.665,-67.954,0 -65.313,-68.365,0 -64.784,-68.679,0 -63.961,-68.914,0 -63.197,-69.228,0 -62.786,-69.619,0 -62.571,-69.992,0 -62.277,-70.384,0 -61.807,-70.717,0 -61.513,-71.089,0 -61.376,-72.01,0 -61.082,-72.382,0 -61.004,-72.774,0 -60.69,-73.166,0 -60.827,-73.695,0 -61.376,-74.107,0 -61.963,-74.44,0 -63.295,-74.577,0 -63.746,-74.93,0 -64.353,-75.263,0 -65.861,-75.635,0 -67.193,-75.792,0 -68.446,-76.007,0 -69.798,-76.223,0 -70.601,-76.634,0 -72.207,-76.674,0 -73.97,-76.634,0 -75.556,-76.713,0 -77.24,-76.713,0 -76.927,-77.105,0 -75.399,-77.281,0 -74.283,-77.555,0 -73.656,-77.908,0 -74.773,-78.222,0 -76.496,-78.124,0 -77.926,-78.378,0 -77.985,-78.79,0 -78.024,-79.182,0 -76.849,-79.515,0 -76.633,-79.887,0 -75.36,-80.26,0 -73.245,-80.416,0 -71.443,-80.691,0 -70.013,-81.004,0 -68.192,-81.318,0 -65.704,-81.474,0 -63.256,-81.749,0 -61.552,-82.043,0 -59.691,-82.376,0 -58.712,-82.846,0 -58.222,-83.218,0 -57.008,-82.866,0 -55.363,-82.572,0 -53.62,-82.258,0 -51.544,-82.004,0 -49.761,-81.729,0 -47.274,-81.71,0 -44.826,-81.847,0 -42.808,-82.082,0 -42.162,-81.651,0 -40.771,-81.357,0 -38.245,-81.337,0 -36.267,-81.122,0 -34.386,-80.906,0 -32.31,-80.769,0 -30.097,-80.593,0 -28.55,-80.338,0 -29.255,-79.985,0 -29.686,-79.633,0 -29.686,-79.26,0 -31.625,-79.299,0 -33.681,-79.456,0 -35.64,-79.456,0 -35.914,-79.084,0 -35.777,-78.339,0 -35.327,-78.124,0 -33.897,-77.889,0 -32.212,-77.653,0 -30.998,-77.36,0 -29.784,-77.066,0 -28.883,-76.674,0 -27.512,-76.497,0 -26.16,-76.36,0 -25.475,-76.282,0 -23.928,-76.243,0 -22.459,-76.105,0 -21.225,-75.909,0 -20.01,-75.674,0 -18.914,-75.439,0 -17.523,-75.126,0 -16.642,-74.793,0 -15.701,-74.499,0 -15.408,-74.107,0 -16.465,-73.872,0 -16.113,-73.46,0 -15.447,-73.147,0 -14.409,-72.951,0 -13.312,-72.715,0 -12.294,-72.402,0 -11.51,-72.01,0 -11.02,-71.54,0 -10.296,-71.265,0 -9.101,-71.324,0 -8.611,-71.657,0 -7.417,-71.697,0 -7.377,-71.324,0 -6.868,-70.932,0 -5.791,-71.03,0 -5.536,-71.403,0 -4.342,-71.461,0 -3.049,-71.285,0 -1.795,-71.167,0 -0.659,-71.226,0 -0.229,-71.638,0 0.868,-71.305,0 1.887,-71.128,0 3.023,-70.991,0 4.139,-70.854,0 5.158,-70.619,0 6.274,-70.462,0 7.136,-70.247,0 7.743,-69.894,0 8.487,-70.149,0 9.525,-70.011,0 10.25,-70.482,0 10.818,-70.834,0 11.954,-70.638,0 12.404,-70.247,0 13.423,-69.972,0 14.735,-70.031,0 15.127,-70.403,0 15.949,-70.031,0 17.027,-69.913,0 18.202,-69.874,0 19.259,-69.894,0 20.376,-70.011,0 21.453,-70.07,0 21.923,-70.403,0 22.569,-70.697,0 23.666,-70.521,0 24.841,-70.482,0 25.977,-70.482,0 27.094,-70.462,0 28.093,-70.325,0 29.15,-70.207,0 30.032,-69.933,0 30.972,-69.757,0 31.99,-69.659,0 32.754,-69.384,0 33.302,-68.836,0 33.87,-68.503,0 34.908,-68.659,0 35.3,-69.012,0 36.162,-69.247,0 37.2,-69.169,0 37.905,-69.521,0 38.649,-69.776,0 39.668,-69.541,0 40.02,-69.11,0 40.921,-68.934,0 41.959,-68.601,0 42.939,-68.463,0 44.114,-68.267,0 44.897,-68.052,0 45.72,-67.817,0 46.503,-67.601,0 47.443,-67.719,0 48.344,-67.366,0 48.991,-67.092,0 49.931,-67.111,0 50.753,-66.876,0 50.949,-66.523,0 51.792,-66.249,0 52.614,-66.053,0 53.613,-65.896,0 54.534,-65.818,0 55.415,-65.877,0 56.355,-65.975,0 57.158,-66.249,0 57.256,-66.68,0 58.137,-67.013,0 58.745,-67.288,0 59.939,-67.405,0 60.605,-67.68,0 61.428,-67.954,0 62.387,-68.013,0 63.19,-67.817,0 64.052,-67.405,0 64.992,-67.621,0 65.972,-67.738,0 66.912,-67.856,0 67.891,-67.934,0 68.89,-67.934,0 69.713,-68.973,0 69.673,-69.228,0 69.556,-69.678,0 68.596,-69.933,0 67.813,-70.305,0 67.95,-70.697,0 69.066,-70.678,0 68.929,-71.069,0 68.42,-71.442,0 67.95,-71.853,0 68.714,-72.167,0 69.869,-72.265,0 71.025,-72.088,0 71.573,-71.697,0 71.906,-71.324,0 72.455,-71.011,0 73.081,-70.717,0 73.336,-70.364,0 73.865,-69.874,0 74.492,-69.776,0 75.628,-69.737,0 76.626,-69.619,0 77.645,-69.463,0 78.135,-69.071,0 78.428,-68.698,0 79.114,-68.326,0 80.093,-68.072,0 80.935,-67.876,0 81.484,-67.542,0 82.052,-67.366,0 82.776,-67.209,0 83.775,-67.307,0 84.676,-67.209,0 85.656,-67.092,0 86.752,-67.15,0 87.477,-66.876,0 87.986,-66.21,0 88.358,-66.484,0 88.828,-66.955,0 89.671,-67.15,0 90.63,-67.229,0 91.59,-67.111,0 92.609,-67.19,0 93.549,-67.209,0 94.175,-67.111,0 95.018,-67.17,0 95.781,-67.386,0 96.682,-67.249,0 97.76,-67.249,0 98.68,-67.111,0 99.718,-67.249,0 100.384,-66.915,0 100.893,-66.582,0 101.579,-66.308,0 102.832,-65.563,0 103.479,-65.7,0 104.243,-65.975,0 104.908,-66.328,0 106.182,-66.935,0 107.161,-66.955,0 108.081,-66.955,0 109.159,-66.837,0 110.236,-66.7,0 111.058,-66.426,0 111.744,-66.132,0 112.86,-66.092,0 113.605,-65.877,0 114.388,-66.073,0 114.897,-66.386,0 115.602,-66.7,0 116.699,-66.661,0 117.385,-66.915,0 118.579,-67.17,0 119.833,-67.268,0 120.871,-67.19,0 121.654,-66.876,0 122.32,-66.563,0 123.221,-66.484,0 124.122,-66.621,0 125.16,-66.719,0 126.1,-66.563,0 127.001,-66.563,0 127.883,-66.661,0 128.803,-66.759,0 129.704,-66.582,0 130.781,-66.426,0 131.8,-66.386,0 132.936,-66.386,0 133.856,-66.288,0 134.757,-66.21,0 135.032,-65.72,0 135.071,-65.309,0 135.697,-65.583,0 135.874,-66.034,0 136.207,-66.445,0 136.618,-66.778,0 137.46,-66.955,0 138.596,-66.896,0 139.908,-66.876,0 140.809,-66.817,0 142.122,-66.817,0 143.062,-66.798,0 144.374,-66.837,0 145.49,-66.915,0 146.196,-67.229,0 146,-67.601,0 146.646,-67.895,0 147.723,-68.13,0 148.84,-68.385,0 150.132,-68.561,0 151.484,-68.718,0 152.502,-68.875,0 153.638,-68.895,0 154.285,-68.561,0 155.166,-68.836,0 155.93,-69.149,0 156.811,-69.384,0 158.026,-69.482,0 159.181,-69.6,0 159.671,-69.992,0 160.807,-70.227,0 161.57,-70.58,0 162.687,-70.736,0 163.842,-70.717,0 164.92,-70.776,0 166.114,-70.756,0 167.309,-70.834,0 168.426,-70.971,0 169.464,-71.207,0 170.502,-71.403,0 171.207,-71.697,0 171.089,-72.088,0 170.56,-72.441,0 170.11,-72.892,0 169.757,-73.245,0 169.287,-73.656,0 167.975,-73.813,0 167.387,-74.165,0 166.095,-74.381,0 165.644,-74.773,0 164.959,-75.145,0 164.234,-75.459,0 163.823,-75.87,0 163.568,-76.243,0 163.47,-76.693,0 163.49,-77.066,0 164.058,-77.457,0 164.273,-77.83,0 164.743,-78.183,0 166.604,-78.32,0 166.996,-78.751,0 165.194,-78.907,0 163.666,-79.123,0 161.766,-79.162,0 160.924,-79.73,0 160.748,-80.201,0 160.317,-80.573,0 159.788,-80.945,0 161.12,-81.279,0 161.629,-81.69,0 162.491,-82.062,0 163.705,-82.395,0 165.096,-82.709,0 166.604,-83.022,0 168.896,-83.336,0 169.405,-83.826,0 172.284,-84.041,0 172.477,-84.118,0 173.224,-84.414,0 175.986,-84.159,0 178.277,-84.473,0 180,-84.713,0 180,-90,0 -180,-90,0 -180,-84.713,0 -179.942,-84.721,0 -179.059,-84.139,0 -177.257,-84.453,0 -177.141,-84.418,0 -176.085,-84.099,0 -175.947,-84.11,0 -175.83,-84.118,0 -174.383,-84.534,0 -173.117,-84.118,0 -172.889,-84.061,0 -169.951,-83.885,0 -169,-84.118,0 -168.53,-84.237,0 -167.022,-84.57,0 -164.182,-84.825,0 -161.93,-85.139,0 -158.071,-85.374,0 -155.192,-85.1,0 -150.942,-85.296,0 -148.533,-85.609,0 -145.889,-85.315,0 -143.108,-85.041,0 -142.892,-84.57,0 -146.829,-84.531,0 -150.061,-84.296,0 -150.903,-83.904,0 -153.586,-83.689,0 -153.41,-83.238,0 -153.038,-82.827,0 -152.666,-82.454,0 -152.862,-82.043,0 -154.526,-81.768,0 -155.29,-81.416,0 -156.837,-81.102,0 -154.409,-81.161,0 -152.098,-81.004,0 -150.648,-81.337,0 -148.866,-81.043,0 -147.221,-80.671,0 -146.418,-80.338,0 -146.77,-79.926,0 -148.063,-79.652,0 -149.532,-79.358,0 -151.588,-79.299,0 -153.39,-79.162,0 -155.329,-79.064,0 -155.976,-78.692,0 -157.268,-78.378,0 -158.052,-78.026,0 -158.365,-76.889,0 -157.875,-76.987,0 -156.975,-77.301,0 -155.329,-77.203,0 -153.743,-77.066,0 -152.92,-77.497,0 -151.334,-77.399,0 -150.002,-77.183,0 -148.748,-76.909,0 -147.612,-76.576,0 -146.104,-76.478,0 -146.144,-76.105,0 -146.496,-75.733,0 -146.202,-75.38,0 -144.91,-75.204,0 -144.322,-75.537,0 -142.794,-75.341,0 -141.639,-75.086,0 -140.209,-75.067,0 -138.858,-74.969,0 -137.506,-74.734,0 -136.429,-74.518,0 -135.215,-74.303,0 -134.431,-74.361,0 -133.746,-74.44,0 -132.257,-74.303,0 -130.925,-74.479,0 -129.554,-74.459,0 -128.242,-74.322,0 -126.891,-74.42,0 -125.402,-74.518,0 -124.011,-74.479,0 -122.562,-74.499,0 -121.074,-74.518,0 -119.703,-74.479,0 -118.684,-74.185,0 -117.47,-74.028,0 -116.216,-74.244,0 -115.022,-74.068,0 -113.944,-73.715,0 -113.298,-74.028,0 -112.945,-74.381,0 -112.299,-74.714,0 -111.261,-74.42,0 -110.066,-74.793,0 -108.715,-74.91,0 -107.559,-75.184,0 -106.149,-75.126,0 -104.876,-74.949,0 -103.368,-74.988,0 -102.017,-75.126,0 -100.646,-75.302,0 -100.117,-74.871,0 -100.763,-74.538,0 -101.253,-74.185,0 -102.545,-74.107,0 -103.113,-73.734,0 -103.329,-73.362,0 -103.681,-72.618,0 -102.917,-72.755,0 -101.605,-72.813,0 -100.313,-72.755,0 -99.137,-72.911,0 -98.119,-73.205,0 -97.688,-73.558,0 -96.337,-73.617,0 -95.044,-73.48,0 -93.673,-73.284,0 -92.439,-73.166,0 -91.421,-73.401,0 -90.089,-73.323,0 -89.227,-72.559,0 -88.424,-73.009,0 -87.268,-73.186,0 -86.015,-73.088,0 -85.192,-73.48,0 -83.88,-73.519,0 -82.666,-73.636,0 -81.471,-73.852,0 -80.687,-73.48,0 -80.296,-73.127,0 -79.297,-73.519,0 -77.926,-73.421,0 -76.907,-73.636,0 -76.222,-73.97,0 -74.89,-73.872,0 -73.852,-73.656,0 -72.834,-73.401,0 -71.619,-73.264,0 -70.209,-73.147,0 -68.936,-73.009,0 -67.957,-72.794,0 -67.369,-72.48,0 -67.134,-72.049,0 -67.252,-71.638,0 -67.565,-71.246,0 -67.917,-70.854,0 -68.231,-70.462,0 -68.485,-70.109,0 -68.544,-69.717,0 -68.446,-69.326,0 -67.976,-68.953,0 -67.584,-68.542,0 -67.428,-68.15,0 -67.624,-67.719,0 -67.741,-67.327,0 -67.252,-66.876,0 -66.703,-66.582,0 -66.057,-66.21,0 -65.371,-65.896,0 -64.568,-65.603,0 -64.177,-65.171,0 -63.628,-64.897,0 -63.001,-64.642,0 -62.042,-64.584,0 -61.415,-64.27,0 -60.71,-64.074,0 -59.887,-63.957,0 -59.163,-63.702,0 -58.595,-63.388,0 -57.811,-63.271,0 -57.224,-63.525,0 -57.596,-63.859,0 -58.614,-64.152,0 </coordinates></LinearRing></outerBoundaryIs></Polygon></MultiGeometry>
</Placemark> </kml>"""
k = kml.KML()
k.from_string(doc)
self.assertEqual(len(k.features()),1)
self.assertTrue(isinstance(
k.features()[0].geometry, MultiPolygon))
k2 = kml.KML()
k2.from_string(k.to_string())
#self.assertEqual(k.to_string(), k2.to_string())
print k.to_string()
print
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite( KmlFromStringTestCase ))
suite.addTest(unittest.makeSuite( BuildKmlTestCase ))
return suite
if __name__ == '__main__':
......
......@@ -19,6 +19,7 @@ Create and read KML Files""",
zip_safe=False,
install_requires=[
# -*- Extra requirements: -*-
'shapely',
],
entry_points="""
# -*- Entry points: -*-
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment