1 from pathlib import Path
 
   5     """ Provides functions to create geometries from scenes and data grids.
 
   9         defpath = Path(__file__) / '..' / '..' / '..' / 'scenes' / 'data'
 
  10         self.scene_path = os.environ.get('SCENE_PATH', defpath.resolve())
 
  14     def parse_geometry(self, geom, scene):
 
  15         """ Create a WKT SQL term for the given geometry.
 
  16             The function understands the following formats:
 
  19                  Geometry from a scene. If the scene is omitted, use the
 
  28            <P> may either be a coordinate of the form '<x> <y>' or a single
 
  29            number. In the latter case it must refer to a point in
 
  30            a previously defined grid.
 
  32         if geom.find(':') >= 0:
 
  33             return "ST_SetSRID({}, 4326)".format(self.get_scene_geometry(scene, geom))
 
  35         if geom.find(',') < 0:
 
  36             out = "POINT({})".format(self.mk_wkt_point(geom))
 
  37         elif geom.find('(') < 0:
 
  38             out = "LINESTRING({})".format(self.mk_wkt_points(geom))
 
  40             out = "POLYGON(({}))".format(self.mk_wkt_points(geom.strip('() ')))
 
  42         return "ST_SetSRID('{}'::geometry, 4326)".format(out)
 
  44     def mk_wkt_point(self, point):
 
  45         """ Parse a point description.
 
  46             The point may either consist of 'x y' cooordinates or a number
 
  47             that refers to a grid setup.
 
  50         if geom.find(' ') >= 0:
 
  54             pt = self.grid_node(int(geom))
 
  56             assert False, "Scenario error: Point '{}' is not a number".format(geom)
 
  58         assert pt is not None, "Scenario error: Point '{}' not found in grid".format(geom)
 
  59         return "{} {}".format(*pt)
 
  61     def mk_wkt_points(self, geom):
 
  62         """ Parse a list of points.
 
  63             The list must be a comma-separated list of points. Points
 
  64             in coordinate and grid format may be mixed.
 
  66         return ','.join([self.mk_wkt_point(x) for x in geom.split(',')])
 
  68     def get_scene_geometry(self, default_scene, name):
 
  69         """ Load the geometry from a scene.
 
  72         for obj in name.split('+'):
 
  74             if oname.startswith(':'):
 
  75                 assert default_scene is not None, "Scenario error: You need to set a scene"
 
  76                 defscene = self.load_scene(default_scene)
 
  77                 wkt = defscene[oname[1:]]
 
  79                 scene, obj = oname.split(':', 2)
 
  80                 scene_geoms = self.load_scene(scene)
 
  81                 wkt = scene_geoms[obj]
 
  83             geoms.append("'{}'::geometry".format(wkt))
 
  88         return 'ST_LineMerge(ST_Collect(ARRAY[{}]))'.format(','.join(geoms))
 
  90     def load_scene(self, name):
 
  91         """ Load a scene from a file.
 
  93         if name in self.scene_cache:
 
  94             return self.scene_cache[name]
 
  97         with open(Path(self.scene_path) / "{}.wkt".format(name), 'r') as fd:
 
 100                     obj, wkt = line.split('|', 2)
 
 101                     scene[obj.strip()] = wkt.strip()
 
 102             self.scene_cache[name] = scene
 
 106     def set_grid(self, lines, grid_step):
 
 107         """ Replace the grid with one from the given lines.
 
 115                     self.grid[int(pt_id)] = (x, y)
 
 119     def grid_node(self, nodeid):
 
 120         """ Get the coordinates for the given grid node.
 
 122         return self.grid.get(nodeid)