"""
Library for areas.
Basic usage is checking whether a point is inside an area.
-Supports GoogleEarth KML polylines.
+Supports GoogleEarth KML coordinates.
FIXME: It should works using polar coordinated, but now works in 2D.
"""
-__all__ = [ 'Area', 'load_area_from_kml_polygon' ]
+from __future__ import division
+
+__all__ = [ 'Area', 'load_area_from_kml_polygon', 'list_areas' ]
+
+import os
+import re
+
+AREA_DIR = u'/var/lib/ais/areas/'
class Area:
"""
#elif point[1] > self.max[1]:
# self.max = (self.max[0], point[1])
+ def reverse(self):
+ '''
+ Invert the area
+ From clockwise to counter-clockwise
+ Or from counter-clockwise to clockwise
+ '''
+ self.points.reverse()
+
def check(self):
"""
Area library self-test:
return False
return True
-def load_area_from_kml_polygon(filename):
+def load_area_from_kml_polygon(filename, reverse=False):
"""
Loads a kml file into an Area structure.
- The kml must contains exacly 1 polyline structure.
+ The kml must contains exacly one set of <coordinates>.
The first and last points must be the same.
It must also be counter-clockwise and convex.
-
- FIXME: This makes a lot of assumption about the way GoogleEarth output the
- XML file.
+ Actually, it may be clockwise, but then you need reverse=True.
"""
- kmlfile = open(filename)
- coordinates_lines = [ line for line in kmlfile.readlines() if '</coordinates>' in line ]
+ kml = open(filename).read()
+ coordinates_lines = re.findall('<coordinates>(.*)</coordinates>', kml, re.IGNORECASE|re.DOTALL)
assert len(coordinates_lines) == 1, \
- 'There should be exactly one line with coordinates in %s' % filename
- coordinates = coordinates_lines[0].replace('</coordinates>', '').replace('\n', '').replace('\r', '')
+ 'There should be exactly one set of <coordinates> %s' % filename
+ coordinates = coordinates_lines[0].replace('\n', ' ').replace('\r', ' ').replace('\t', ' ')
coordinates = [ xyz for xyz in coordinates.split(' ') if xyz ]
assert coordinates[0] == coordinates[-1], \
'First and last coordinates of %s should be the same: %s, %s' % \
assert len(coordinates)>3, 'polygon should have 3 edges minimum'
area = Area()
- for xyz in coordinates[0:-1]:
+ for xyz in coordinates[:-1]:
x, y, z = xyz.split(',')
area.addpoint((float(y), float(x)))
+ if reverse:
+ area.reverse()
assert area.check(), 'Polygon should be counter-clockwise and convex.'
return area
-#if __name__ == '__main__':
-# counter clock-wise : Positive
-#pelagos = Area([
-# (42.91, 12.5),
-# (45.3612930132714, 10.01843703552244),
-# (43.6,5.5),
-# (40.57,8.6)
-# ])
-#for p in [
-# (42,9),
-# (41,5),
-# (40,12),
-# (45,13),
-# (45,7),
-# ]:
-# print "testing", p
-# if pelagos.contains(p):
-# print "inside"
-# else:
-# print"outside"
-
+def list_areas():
+ """
+ return a list of areas as tupples:
+ [(nicename, fullpath), ...]
+ """
+ results = []
+ for filename in os.listdir(AREA_DIR):
+ if not filename.endswith(u'.kml'):
+ continue # ignore non-kml files
+ results.append((filename[:-4], AREA_DIR+filename))
+ return results
+
+if __name__ == '__main__':
+ print list_areas()
+ pelagos = load_area_from_kml_polygon('/var/lib/ais/areas/pelagos.kml')
+ # counter clock-wise : Positive
+ #pelagos = Area([
+ # (42.91, 12.5),
+ # (45.3612930132714, 10.01843703552244),
+ # (43.6,5.5),
+ # (40.57,8.6)
+ # ])
+ for p in [
+ (42,9),
+ (41,5),
+ (40,12),
+ (45,13),
+ (45,7),
+ ]:
+ print "testing", p
+ if pelagos.contains(p):
+ print "inside"
+ else:
+ print"outside"