mirror of
https://github.com/osm-search/Nominatim.git
synced 2024-10-27 03:29:24 +03:00
Merge pull request #2981 from lonvia/add-point-wkb-decoder
Python frontend: add a WKB decoder for the Point class
This commit is contained in:
commit
3405dbf90e
@ -46,8 +46,7 @@ async def find_in_placex(conn: SearchConnection, place: ntyp.PlaceRef,
|
||||
t.c.importance, t.c.wikipedia, t.c.indexed_date,
|
||||
t.c.parent_place_id, t.c.rank_address, t.c.rank_search,
|
||||
t.c.linked_place_id,
|
||||
sa.func.ST_X(t.c.centroid).label('x'),
|
||||
sa.func.ST_Y(t.c.centroid).label('y'),
|
||||
t.c.centroid,
|
||||
_select_column_geometry(t.c.geometry, details.geometry_output))
|
||||
|
||||
if isinstance(place, ntyp.PlaceID):
|
||||
@ -76,8 +75,7 @@ async def find_in_osmline(conn: SearchConnection, place: ntyp.PlaceRef,
|
||||
sql = sa.select(t.c.place_id, t.c.osm_id, t.c.parent_place_id,
|
||||
t.c.indexed_date, t.c.startnumber, t.c.endnumber,
|
||||
t.c.step, t.c.address, t.c.postcode, t.c.country_code,
|
||||
sa.func.ST_X(sa.func.ST_Centroid(t.c.linegeo)).label('x'),
|
||||
sa.func.ST_Y(sa.func.ST_Centroid(t.c.linegeo)).label('y'),
|
||||
t.c.linegeo.ST_Centroid().label('centroid'),
|
||||
_select_column_geometry(t.c.linegeo, details.geometry_output))
|
||||
|
||||
if isinstance(place, ntyp.PlaceID):
|
||||
@ -106,8 +104,7 @@ async def find_in_tiger(conn: SearchConnection, place: ntyp.PlaceRef,
|
||||
sql = sa.select(t.c.place_id, t.c.parent_place_id,
|
||||
t.c.startnumber, t.c.endnumber, t.c.step,
|
||||
t.c.postcode,
|
||||
sa.func.ST_X(sa.func.ST_Centroid(t.c.linegeo)).label('x'),
|
||||
sa.func.ST_Y(sa.func.ST_Centroid(t.c.linegeo)).label('y'),
|
||||
t.c.linegeo.ST_Centroid().label('centroid'),
|
||||
_select_column_geometry(t.c.linegeo, details.geometry_output))
|
||||
|
||||
if isinstance(place, ntyp.PlaceID):
|
||||
@ -128,8 +125,7 @@ async def find_in_postcode(conn: SearchConnection, place: ntyp.PlaceRef,
|
||||
sql = sa.select(t.c.place_id, t.c.parent_place_id,
|
||||
t.c.rank_search, t.c.rank_address,
|
||||
t.c.indexed_date, t.c.postcode, t.c.country_code,
|
||||
sa.func.ST_X(t.c.geometry).label('x'),
|
||||
sa.func.ST_Y(t.c.geometry).label('y'),
|
||||
t.c.geometry.label('centroid'),
|
||||
_select_column_geometry(t.c.geometry, details.geometry_output))
|
||||
|
||||
if isinstance(place, ntyp.PlaceID):
|
||||
|
@ -132,13 +132,6 @@ class SearchResult:
|
||||
return self.importance or (0.7500001 - (self.rank_search/40.0))
|
||||
|
||||
|
||||
# pylint: disable=consider-using-f-string
|
||||
def centroid_as_geojson(self) -> str:
|
||||
""" Get the centroid in GeoJSON format.
|
||||
"""
|
||||
return '{"type": "Point","coordinates": [%f, %f]}' % self.centroid
|
||||
|
||||
|
||||
def _filter_geometries(row: SaRow) -> Dict[str, str]:
|
||||
return {k[9:]: v for k, v in row._mapping.items() # pylint: disable=W0212
|
||||
if k.startswith('geometry_')}
|
||||
@ -166,7 +159,7 @@ def create_from_placex_row(row: SaRow) -> SearchResult:
|
||||
importance=row.importance,
|
||||
country_code=row.country_code,
|
||||
indexed_date=getattr(row, 'indexed_date'),
|
||||
centroid=Point(row.x, row.y),
|
||||
centroid=Point.from_wkb(row.centroid.data),
|
||||
geometry=_filter_geometries(row))
|
||||
|
||||
|
||||
@ -186,7 +179,7 @@ def create_from_osmline_row(row: SaRow) -> SearchResult:
|
||||
'step': str(row.step)},
|
||||
country_code=row.country_code,
|
||||
indexed_date=getattr(row, 'indexed_date'),
|
||||
centroid=Point(row.x, row.y),
|
||||
centroid=Point.from_wkb(row.centroid.data),
|
||||
geometry=_filter_geometries(row))
|
||||
|
||||
|
||||
@ -203,7 +196,7 @@ def create_from_tiger_row(row: SaRow) -> SearchResult:
|
||||
'endnumber': str(row.endnumber),
|
||||
'step': str(row.step)},
|
||||
country_code='us',
|
||||
centroid=Point(row.x, row.y),
|
||||
centroid=Point.from_wkb(row.centroid.data),
|
||||
geometry=_filter_geometries(row))
|
||||
|
||||
|
||||
@ -219,7 +212,7 @@ def create_from_postcode_row(row: SaRow) -> SearchResult:
|
||||
rank_search=row.rank_search,
|
||||
rank_address=row.rank_address,
|
||||
country_code=row.country_code,
|
||||
centroid=Point(row.x, row.y),
|
||||
centroid=Point.from_wkb(row.centroid.data),
|
||||
indexed_date=row.indexed_date,
|
||||
geometry=_filter_geometries(row))
|
||||
|
||||
|
@ -10,6 +10,7 @@ Complex datatypes used by the Nominatim API.
|
||||
from typing import Optional, Union, NamedTuple
|
||||
import dataclasses
|
||||
import enum
|
||||
from struct import unpack
|
||||
|
||||
@dataclasses.dataclass
|
||||
class PlaceID:
|
||||
@ -55,6 +56,33 @@ class Point(NamedTuple):
|
||||
return self.x
|
||||
|
||||
|
||||
def to_geojson(self) -> str:
|
||||
""" Return the point in GeoJSON format.
|
||||
"""
|
||||
return f'{{"type": "Point","coordinates": [{self.x}, {self.y}]}}'
|
||||
|
||||
|
||||
@staticmethod
|
||||
def from_wkb(wkb: bytes) -> 'Point':
|
||||
""" Create a point from EWKB as returned from the database.
|
||||
"""
|
||||
if len(wkb) != 25:
|
||||
raise ValueError("Point wkb has unexpected length")
|
||||
if wkb[0] == 0:
|
||||
gtype, srid, x, y = unpack('>iidd', wkb[1:])
|
||||
elif wkb[0] == 1:
|
||||
gtype, srid, x, y = unpack('<iidd', wkb[1:])
|
||||
else:
|
||||
raise ValueError("WKB has unknown endian value.")
|
||||
|
||||
if gtype != 0x20000001:
|
||||
raise ValueError("WKB must be a point geometry.")
|
||||
if srid != 4326:
|
||||
raise ValueError("Only WGS84 WKB supported.")
|
||||
|
||||
return Point(x, y)
|
||||
|
||||
|
||||
class GeometryFormat(enum.Flag):
|
||||
""" Geometry output formats supported by Nominatim.
|
||||
"""
|
||||
|
@ -96,7 +96,7 @@ def _add_parent_rows_grouped(writer: JsonWriter, rows: napi.AddressLines,
|
||||
def _format_search_json(result: napi.SearchResult, options: Mapping[str, Any]) -> str:
|
||||
locales = options.get('locales', napi.Locales())
|
||||
geom = result.geometry.get('geojson')
|
||||
centroid = result.centroid_as_geojson()
|
||||
centroid = result.centroid.to_geojson()
|
||||
|
||||
out = JsonWriter()
|
||||
out.start_object()\
|
||||
|
@ -80,7 +80,7 @@ class TestCliDetailsCall:
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_status_mock(self, monkeypatch):
|
||||
result = napi.SearchResult(napi.SourceTable.PLACEX, ('place', 'thing'),
|
||||
(1.0, -3.0))
|
||||
napi.Point(1.0, -3.0))
|
||||
|
||||
monkeypatch.setattr(napi.NominatimAPI, 'lookup',
|
||||
lambda *args: result)
|
||||
@ -90,7 +90,7 @@ class TestCliDetailsCall:
|
||||
('--relation', '1'),
|
||||
('--place_id', '10001')])
|
||||
|
||||
def test_status_json_format(self, cli_call, tmp_path, capsys, params):
|
||||
def test_details_json_format(self, cli_call, tmp_path, capsys, params):
|
||||
result = cli_call('details', '--project-dir', str(tmp_path), *params)
|
||||
|
||||
assert result == 0
|
||||
|
Loading…
Reference in New Issue
Block a user