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