New list_areas function
[ais.git] / bin / area.py
index eafd2b708b912701d312ccf5b18d05d5e6918564..fc5324c9ec3801d6cc46095dcef77e3b9b35e1e1 100644 (file)
@@ -3,11 +3,18 @@
 """
 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:
     """
@@ -38,6 +45,14 @@ 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: 
@@ -73,21 +88,19 @@ class Area:
                 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' % \
@@ -95,32 +108,47 @@ def load_area_from_kml_polygon(filename):
     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"