]> git.openstreetmap.org Git - nominatim.git/blob - test/bdd/steps/geometry_factory.py
Merge remote-tracking branch 'upstream/master'
[nominatim.git] / test / bdd / steps / geometry_factory.py
1 # SPDX-License-Identifier: GPL-2.0-only
2 #
3 # This file is part of Nominatim. (https://nominatim.org)
4 #
5 # Copyright (C) 2022 by the Nominatim developer community.
6 # For a full list of authors see the git log.
7 from pathlib import Path
8 import os
9
10 from steps.geometry_alias import ALIASES
11
12 class GeometryFactory:
13     """ Provides functions to create geometries from coordinates and data grids.
14     """
15
16     def __init__(self):
17         self.grid = {}
18
19     def parse_geometry(self, geom):
20         """ Create a WKT SQL term for the given geometry.
21             The function understands the following formats:
22
23               country:<country code>
24                  Point geometry guaranteed to be in the given country
25               <P>
26                  Point geometry
27               <P>,...,<P>
28                  Line geometry
29               (<P>,...,<P>)
30                  Polygon geometry
31
32            <P> may either be a coordinate of the form '<x> <y>' or a single
33            number. In the latter case it must refer to a point in
34            a previously defined grid.
35         """
36         if geom.startswith('country:'):
37             ccode = geom[8:].upper()
38             assert ccode in ALIASES, "Geometry error: unknown country " + ccode
39             return "ST_SetSRID('POINT({} {})'::geometry, 4326)".format(*ALIASES[ccode])
40
41         if geom.find(',') < 0:
42             out = "POINT({})".format(self.mk_wkt_point(geom))
43         elif geom.find('(') < 0:
44             out = "LINESTRING({})".format(self.mk_wkt_points(geom))
45         else:
46             out = "POLYGON(({}))".format(self.mk_wkt_points(geom.strip('() ')))
47
48         return "ST_SetSRID('{}'::geometry, 4326)".format(out)
49
50
51     def mk_wkt_point(self, point):
52         """ Parse a point description.
53             The point may either consist of 'x y' coordinates or a number
54             that refers to a grid setup.
55         """
56         geom = point.strip()
57         if geom.find(' ') >= 0:
58             return geom
59
60         try:
61             pt = self.grid_node(int(geom))
62         except ValueError:
63             assert False, "Scenario error: Point '{}' is not a number".format(geom)
64
65         assert pt is not None, "Scenario error: Point '{}' not found in grid".format(geom)
66         return "{} {}".format(*pt)
67
68
69     def mk_wkt_points(self, geom):
70         """ Parse a list of points.
71             The list must be a comma-separated list of points. Points
72             in coordinate and grid format may be mixed.
73         """
74         return ','.join([self.mk_wkt_point(x) for x in geom.split(',')])
75
76
77     def set_grid(self, lines, grid_step, origin=(0.0, 0.0)):
78         """ Replace the grid with one from the given lines.
79         """
80         self.grid = {}
81         y = origin[1]
82         for line in lines:
83             x = origin[0]
84             for pt_id in line:
85                 if pt_id.isdigit():
86                     self.grid[int(pt_id)] = (x, y)
87                 x += grid_step
88             y += grid_step
89
90
91     def grid_node(self, nodeid):
92         """ Get the coordinates for the given grid node.
93         """
94         return self.grid.get(nodeid)