Difference between osrm nearest and osrm match services - python

I want to match gps coordinates to osm nodes. The osrm document clearly states that match service is for that purpose. But I see most of them using nearest service for that purpose. Why so? Also any examples of Match service and what is the main difference between the two service for the matching operation.Which one is better?

As per the OSRM API Documentation,
the neareast service a query endpoint where the nearest number of waypoint objects to the snapped coordinates (single coordinate allowed) are returned.
GET http://{server}/nearest/v1/{profile}/{coordinates}.json?number={number}
On the other hand, as the name suggests match service does something quite different and as one can say more complex. It accepts multiple coordinates and matches these points in a plausible way to the route network. As it can be seen from the dummy and a bit manipulated response; matchings array defines the confidence (calculated by OSRM), geometry (provided in arguments), legs (defines the route details annotations and overview arguments provide flexibility) and tracepoints array that lists the waypoints with additional properties.
GET /match/v1/{profile}/{coordinates}?steps={true|false}&geometries={polyline|polyline6|geojson}&overview={simplified|full|false}&annotations={true|false}
coordinates: comma separated GPS points
steps: route steps for each route
geometries: 3 formats are supported for route geometry.
overview: adds the overview geometry according to the given value.
annotations: returns additional metadata for each coordinate.
Dummy Match service response overview as it is not very clearly provided:
{
"code": "Ok",
"matchings": [
{
"confidence": 0.980739,
"geometry": {
"coordinates": [
# coordinates here
],
"type": "LineString"
},
"legs": [
{
"annotation": {
# optional
},
"steps": [
{
"intersections": [
{
"out": 0,
"entry": [
true
],
"bearings": [
12
],
"location": [
28.98672,
41.041189
]
}
],
"driving_side": "right",
"geometry": {
"coordinates": [
# coordinates here
],
"type": "LineString"
},
"mode": "driving",
"duration": 95.6,
"maneuver": {
},
"weight": 95.6,
"distance": 796.3,
"name": "Cumhuriyet Caddesi"
},
],
"distance": 1250.9,
"duration": 150.2,
"summary": "Cumhuriyet Caddesi, Halaskargazi Caddesi",
"weight": 150.2
}
],
"distance": 1250.9,
"duration": 150.2,
"weight_name": "routability",
"weight": 150.2
}
],
"tracepoints": [
{
# waypoint object with additional fields
}
]
}

Related

Extracting coordinates (lat, lon) from MultiLineString GeoJSON in Python

I want to make a ScatterMapbox map based on the information contained in this GeoJSON file: https://cdn.buenosaires.gob.ar/datosabiertos/datasets/metrobus/recorrido-de-metrobus.geojson .
However, I am facing the following problem: the geometry in the GeoJSON is a MultiLineString. I provide a written example of the problem here:
{
"type": "FeatureCollection",
"name": "callejero_badata_WGS84",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "id": 28686, "codigo": 17138, "nomoficial": "PUNTA ARENAS", "alt_izqini": 0, "alt_izqfin": 0, "alt_derini": 0, "alt_derfin": 0, "nomanter": null, "nom_mapa": "TÚNEL PUNTA ARENAS", "tipo_c": "TÚNEL", "long": 334.60341680080836, "sentido": "DOBLE", "cod_sent": 2, "observa": "Viaducto - Túnel inaugurado en Abril de 2009", "bicisenda": "-", "lado_ciclo": null, "recorrid_x": null, "ciclo_obse": null, "tooltip_bi": null, "red_jerarq": "VÍA DISTRIBUIDORA COMPLEMENTARIA", "red_tp": null, "ffcc": "SI", "tipo_ffcc": "Túnel", "COMUNA": 15, "COM_PAR": 15, "COM_IMPAR": 15, "BARRIO": "PATERNAL", "BARRIO_PAR": "PATERNAL", "BARRIO_IMP": "PATERNAL" },
"geometry": { "type": "MultiLineString", "coordinates":
[ [ [ -58.46939502613111, -34.590823162817173 ],
[ -58.469462454508552, -34.59098118466796 ],
[ -58.469669480276444, -34.591727559343369 ],
[ -58.469869735691702, -34.592625455739224 ],
[ -58.470073382303283, -34.593447590597258 ],
[ -58.470121607819273, -34.593775790374316 ] ] ] } }, ...
]
}
As you may see, the coordinates are composed by an array of lists (i.e. [ [ [ -58.46939502613111, -34.590823162817173 ], [ -58.469462454508552, -34.59098118466796 ] ] ]).
In order to plot the map, I need to extract from that file ALL the coordinates separately: all the latitudes must be on one list, and all the longitudes must be on another one. I would need something like this (following the example previously provided):
lats = [ -34.590823162817173,
-34.59098118466796,
-34.591727559343369,
...
]
lons = [ -58.46939502613111,
-58.469462454508552,
-58.469669480276444,
...
]
I tried several things, but got nothing close. Everything I did resulted in various errors and/or obtaining just one value/pair of values (coordinates) instead of the wanted list (above).
Everything I have now is the code where I load the GeoJSON, which I provide below.
metrobus = json.load(open("recorrido-de-metrobus.geojson"))
Is there any way to do something like this?
I really appreciate any advice, workaround or solution you might share with me. Thank you, in advance.
EDIT 2
Finally solved after following solution in this link: https://community.plotly.com/t/possible-bug-plotting-multipolygons-in-scattermapbox/33479 .
Thank you Yuri and fusion for your help.
# read your data:
metrobus = json.load(open("recorrido-de-metrobus.geojson"))
lats = []
lons = []
for i in data['features']:
cord = i['geometry']['coordinates']
for j in cord:
for k in j:
lats.append(k[1])
lons.append(k[0])

Delete polygons that have one or more side parts in common

I am trying to solve a particular case of comparison of polygons to others. I have five polygons distributed as in the figure below. The black polygon is the one with the largest area.
There may be other similar cases, the main rule is to remove the smallest polygons among all those that have one or more side portions in common.
The data for this case are in a GeoJson file as follows:
{"type":"FeatureCollection","features":[
{"type":"Feature","properties":{"id":1},"geometry":{"type":"Polygon","coordinates":[[[3.4545135498046875,45.533288879467456],[3.4960556030273433,45.533288879467456],[3.4960556030273433,45.57055337226086],[3.4545135498046875,45.57055337226086],[3.4545135498046875,45.533288879467456]]]}},
{"type":"Feature","properties":{"id":2},"geometry":{"type":"Polygon","coordinates":[[[3.4545135498046875,45.52917023833511],[3.4960556030273433,45.52917023833511],[3.4960556030273433,45.53891018749409],[3.4545135498046875,45.53891018749409],[3.4545135498046875,45.52917023833511]]]}},
{"type":"Feature","properties":{"id":3},"geometry":{"type":"Polygon","coordinates":[[[3.4845542907714844,45.5298015824607],[3.5159683227539062,45.5298015824607],[3.5159683227539062,45.543388795387294],[3.4845542907714844,45.543388795387294],[3.4845542907714844,45.5298015824607]]]}},
{"type":"Feature","properties":{"id":4},"geometry":{"type":"Polygon","coordinates":[[[3.465328216552734,45.542667432984864],[3.4735679626464844,45.542667432984864],[3.4735679626464844,45.5478369923404],[3.465328216552734,45.5478369923404],[3.465328216552734,45.542667432984864]]]}},
{"type":"Feature","properties":{"id":5},"geometry":{"type":"Polygon","coordinates":[[[3.4545138850808144,45.56799974017372],[3.4588050842285156,45.56799974017372],[3.4588050842285156,45.57055290285386],[3.4545138850808144,45.57055290285386],[3.4545138850808144,45.56799974017372]]]}}]}
Is there a solution to delete only the two blue polygons(id 2 and 5)? In python.
By transforming the Polygons into LineString one could look if a Linestring is a portion of another Linestring ? But I don't see how to do it. Or maybe looking to see if the LineString of the black and blue polygons have more than two points in common ? But we can't convert a LineString into more than two points.
The following approach may work for you using shared_paths which correctly calls out the path overlap between polygons 1, 2 and 5:
import json
import shapely as sh
import shapely.ops as ops
import shapely.geometry as geo
with open('./test.json') as f:
features = json.load(f)['features']
for f1 in features:
for f2 in features:
id1 = f1['properties']['id']
id2 = f2['properties']['id']
if int(id1) > int(id2):
s1 = geo.shape(f1['geometry'])
s2 = geo.shape(f2['geometry'])
coll = ops.shared_paths(s1.boundary, s2.boundary)
if not coll.is_empty:
print(f"{id1} and {id2} have shared path")
# update your feature collection etc
I had to reduce the precision to 5 decimal places in your feature geometry for this to work as initially it only detects the overlap between polygon 1 and 2. The shared corner between polygon 1 and 5 is slightly out in your input FeatureCollection:
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"id": 1
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[3.45451, 45.53328],
[3.49605, 45.53328],
[3.49605, 45.57055],
[3.45451, 45.57055],
[3.45451, 45.53328]
]
]
}
},
{
"type": "Feature",
"properties": {
"id": 2
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[3.45451, 45.52917],
[3.49605, 45.52917],
[3.49605, 45.53891],
[3.45451, 45.53891],
[3.45451, 45.52917]
]
]
}
},
{
"type": "Feature",
"properties": {
"id": 3
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[3.48455, 45.52980],
[3.51596, 45.52980],
[3.51596, 45.54338],
[3.48455, 45.54338],
[3.48455, 45.52980]
]
]
}
},
{
"type": "Feature",
"properties": {
"id": 4
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[3.465328, 45.54266],
[3.473567, 45.54266],
[3.473567, 45.54783],
[3.465328, 45.54783],
[3.465328, 45.54266]
]
]
}
},
{
"type": "Feature",
"properties": {
"id": 5
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[3.454513, 45.56799],
[3.458805, 45.56799],
[3.458805, 45.57055],
[3.454513, 45.57055],
[3.454513, 45.56799]
]
]
}
}
]
}

Python seems to only read one item per top-level arrays

I have a JSON file that I read in Python. The JSON (see below) contains two top-level items, both are arrays, containing complex structure, including other arrays at lower levels. For some reason, Python seems to only read one item from both top level arrays.
This is the JSON:
{
"deliverables": [
{
"name": "<uvCode>gadget1",
"objects": [
{ "name": "handler-plate" },
{ "name": "Cone" }
]
},
{
"name": "<uvCode>gadget2",
"objects": [
{ "name": "handler-plate" },
{ "name": "Cone" }
]
}
],
"uvCombinations": [
{
"name": "st01",
"uvMapping": [
{
"objectNameContains": "handler-plate",
"uvLayer": "UVMap1"
},
{
"objectNameContains": "Cone",
"uvLayer": "UVMap1"
}
]
},
{
"name": "st02",
"uvMapping": [
{
"objectNameContains": "handler-plate",
"uvLayer": "UVMap3"
},
{
"objectNameContains": "Cone",
"uvLayer": "UVMap2"
}
]
}
]
}
This is my code to read and dump the JSON file:
with open("file.json") as configFile:
configuration = json.load(configFile)
logging.debug("CONFIG: %s", json.dumps(configuration, indent=4))
And this is the output:
CONFIG: {
"deliverables": [
{
"name": "<uvCode>gadget1",
"objects": [
{
"name": "handler-plate"
},
{
"name": "Cone"
}
]
}
],
"uvCombinations": [
{
"name": "st02",
"uvMapping": [
{
"objectNameContains": "handler-plate",
"uvLayer": "UVMap3"
},
{
"objectNameContains": "Cone",
"uvLayer": "UVMap2"
}
]
}
]
}
The second item of array deliverables (with name <uvCode>gadget2) and the first item of array uvCombination (the one with name st01) is somehow missing.
I'm not a Python expert, but I think this should work like charm, and it's strange that the missing items are not even of the same index. It get even more interesting if you observe that arrays called objects and uvMapping are read properly.
What am I doing wrong?, the poor guy asks
Oh guys, you saved my life! As two of you reported very quickly you can't repro it and as Jordan suggested that maybe my file does not contain what I think it does, I first started ROTL, then I took a look at the files, and found that the file name was not updated... I was editing another file for hours... :D
Thanks, guys, really. If you don't say you can't repro it, I never realize this since I completely forgot about the other copy of the file.

Elasticsearch Shape query to find the bounding polygon and background color from Nested JSON (Google OCR response)

I have a response from an OCR application which is a JSON similar to Google Vision OCR response. I want to put this in Elasticsearch in order to perform a shape query. Although I am able to put the JSON in Elasticsearch, I am not able to come up with a perfect schema and mapping to perform a search on the basis of the shape or the boundingPoly and the bgColor.
I am pretty new to Elasticsearch and I have few questions.
(1) How can I perform search on the basis of the boundingPoly and bgColor?
(2) Do I need to change the schema for performing the search or can I keep it as it is? What the best schema and mapping that suits my purpose?
(3) Also, I would like to perform a search on the basis of bgColor. How can I achieve this?
I tried with Geo-shape query but failed to implement it with the proper result. Also, there is a restriction in Geo-shape query that the values must lie between 90 - 180. I think that part we can handle by normalizing the values.
Sample JSON:
{
"responses": [{
"textAnnotations": [{
"description": "were",
"boundingPoly": {
"vertices": [{
"x": 112,
"y": 5
},
{
"x": 333,
"y": 5
},
{
"x": 333,
"y": 93
},
{
"x": 112,
"y": 93
}
],
"confidence": 99
},
"wordInfo": {
"length": 4,
"width": 221,
"height": 88,
"bgColor": [
255,
255,
251
]
}
},
{
"description": "gonna",
"boundingPoly": {
"vertices": [{
"x": 338,
"y": 5
},
{
"x": 589,
"y": 5
},
{
"x": 589,
"y": 93
},
{
"x": 338,
"y": 93
}
],
"confidence": 99
},
"wordInfo": {
"length": 5,
"width": 251,
"height": 88,
"bgColor": [
255,
255,
255
]
}
}
]
}]
}
Thanks in advance!
As you're using bounding box coordinates of words over an image i would suggest you to use shape datatype as there is not limitation of coordinate values.
"vertices": {
"type": "shape"
}
Also make sure to manipulate the bounding box coordinates in below format.
[[x1,y1],[x2,y2],[x3,y3],[x4,y4],[x1,y1]]
You might want to change the schema in elasticsearch as it will be easier for you to search different fields in a document.
Post data into document like:
POST /example/_doc
{
"vertices" : {
"type" : "polygon",
"coordinates" : [
[ [1000.0, -1001.0], [1001.0, -1001.0], [1001.0, -1000.0], [1000.0, -1000.0], [1000.0, -1001.0] ]
]
}
}
For Searching you can use make use of envelope type query so you wouldn't have to write all the coordinates of bounding box, you can set a envelope(rectangle) to be searched in and it will give you all the documents that are contained in the envelope.
Note : coordinate input for envelope type searching in a bit different it takes [[minX,maxY],[maxX,minY]] this type of format.
Example:
{
"query":{
"bool": {
"must": {
"match_all": {}
},
"filter": {
"shape": {
"prefix.vertices": {
"shape": {
"type": "envelope",
"coordinates": [
[40,60],
[100,40]
]
}
}
}
}
}
}
}
As each field in elasticsearch can have single or multiple(in form of array) values, bgColor can be searched using must-match query for matching all the values to bgColor elements.
Example:
{
"query": {
"bool": {
"must": [
{"match": {"prefix.wordInfo.bgColor": 1}},
{"match": {"prefix.wordInfo.bgColor": 2}},
{"match": {"prefix.wordInfo.bgColor": 3}}
]
}
}
}
I hope this helps.
geo_shape is intended for ... geographic shapes. So you'll have to either
normalize your coordinates so that they fit into the lat/long spec limits and only then sync them as such
or you can treat them as being in the, say, Mercator (EPSG:900913) projection which supports values like [589, 93] and then convert them to actual lat/longs. Though you should keep in mind that, say, the geopoint [0 (lon), 1 (lat)] converted to mercator coords is [0, ~111325]. So you'll also need some scaling factor in order to not make your geopolygon too small. In other words, a difference of 1 mercator coordinate is 0.000009° in WGS 84 which means that your polygons could be too small to index and/or too high-res to effectively store.
Step-by-step guide:
Convert and/or normalize your coordinates
Convert your [x,y] pairs into [lon, lat] pairs
Convert your [r,g,b] colors into rgb strings ([0,0,0] => "#000000") -- unless you intend to query by the actual r,g,b channels
Create an index w/ a geoshape mapping:
PUT /example
{
"mappings": {
"properties": {
"location": {
"type": "geo_shape"
},
"bgColor": {
"type": "keyword"
}
}
}
}
Make sure your polygon coordinates start and end with the same geopoint & wrap them in 2 more empty arrays to comply with the geojson standard.
Sync your polygons + bgColors
POST /example/_doc
{
"location" : {
"type" : "polygon",
"coordinates" : [
[ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ]
]
},
"bgColor": "#000000"
}
After that there's plenty of resources already answered elsewhere as to how polygons are searched and how to search (color) strings.

Accessing nested python Dict of coordinates in GeoJSON

I'm making a get request from a REST service and returning a GeoJSON but it recognized as a dict by Python. I'm trying to access the nested list value from the coordinates key and the string value from the Zone_ key. Here is a sample of the data:
data = {
"type": "FeatureCollection",
"crs": {
"type": "name",
"properties": {
"name": "EPSG:4326"
}
},
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-80.1135430232235,
33.49892053365546
],
[
-80.1165139377003,
33.499835530094444
],
[
-80.1170369402652,
33.49992051898103
],
[
-80.11707393820328,
33.49992653060032
]
]
]
},
"properties": {
"Zone_": "H"
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-79.62281482439842,
33.289964520159124
],
[
-79.62376378105404,
33.29028749972797
],
[
-79.6247927817771,
33.29068750016911
],
[
-79.62604278223982,
33.29121650014533
]
]
]
},
"properties": {
"Zone_": "I"
}
}
]
}
The problem I am having is I'm stumped with trying to access the coordinates from the geometry key. I'm getting strings back and I don't know how to get to the nested list in coordinates. Here is what I have so far:
for x in data['features']:
for y in x['geometry']:
print(y)
Can someone please help me with this please?
The coordinates are nested inside the geometry of the features. So, you need to access it accordingly.
Try:
for feature in data['features']:
print("Feature coods:")
for cood in feature['geometry']['coordinates']:
print(cood)
This will give you the nested coordinate list:
Feature coods:
[[-80.1135430232235, 33.49892053365546], [-80.1165139377003, 33.499835530094444], [-80.1170369402652, 33.49992051898103], [-80.11707393820328, 33.49992653060032]]
Feature coods:
[[-79.62281482439842, 33.289964520159124], [-79.62376378105404, 33.29028749972797], [-79.6247927817771, 33.29068750016911], [-79.62604278223982, 33.29121650014533]]
features is a list so you have to reference that by integer index [0]
for x in data['features'][0]['geometry']['coordinates']:
print(x)
for x in data['features'][0]['properties']:
print(x)

Categories

Resources