How can I find two adjacent power towers in Overpass-Turbo that are at a maximum distance of, say, 10 m apart?
My first, naive approach finds all the towers because it apparently compares a power tower to itself.
Then I tried using AI, but all of those solutions were wrong as well. Does anyone have a solution that works?
Overpass is not good a spatial queries beyond simple bounding box queries. Use Postpass instead. It is the better tool for that purpose. It is a thin API wrapper around a PostGIS database where you can access all spatial function. You can access it from the Overpass Turbo graphical user interface.
{{data:sql,server=https://postpass.geofabrik.de/api/}}
SELECT
a.osm_id AS osm_id,
a.osm_type AS osm_type,
a.tags AS tags,
a.geom AS geom
FROM postpass_point AS a
JOIN postpass_point AS b
ON a.geom && {{bbox}}
-- spatial condition for table b in order to boost up the query and making use of the spatial index
AND b.geom && {{bbox}}
AND a.tags @> '{"power": "tower"}'::JSONB
AND b.tags @> '{"power": "tower"}'::JSONB
-- removing duplicates and pairs where a.osm_id = b.osm_id
AND a.osm_id < b.osm_id
-- casting to geography because the database is in EPSG:4326
AND ST_DWithin(a.geom::geography, b.geom::geography, 10, FALSE)
-- necessary for lager bounding boxes: rough filter to make more use of indexes; distance in degrees!
AND ST_DWithin(a.geom, b.geom, 0.001)
With PostGIS you can do all kinds of spatial queries. Requests which are either slow or impossible with Overpass. In addition, it is much easier to run those requests later on your own database, if you need to make these requests in production or need to make more requests than acceptable for a free service.
Overpass can do this as well, but extremely slow overpass turbo
You have to iterate over each tower, searching for towers nearby, minus the tower itself.
It can be performed using Overpass (assuming you can find a working server), but at just 10m you’ll have to be pretty specific with your search area. This example sets it at 400m
Note the difference to @mueschel’s routine is it uses ‘Towers’ to search within rather than another call to the server for the same data.
nwr[power=tower]({{bbox}})->.Towers;
foreach.Towers->.Tower(
(
nwr.Towers(around.Tower:400);
-
.Tower;
);
out geom;
);
If you happen to be interested in a planet-wide query of adjacent power towers, qlever might be an apt tool as well:
Clicking “Map view” will give you a fast visualisation of the results. Note, however, that it will only show the geometry of the second power tower since the tool can only handle one wkt geometry per result row as of yet.
world = geodesk.Features("world.gol")
towers = world("n[power=tower]")
for tower in towers:
nearby = list(towers.around(tower, meters=10))
other_count = len(nearby) - 1
if other_count:
print(f"{tower} is near {other_count} "
f"other tower{'s' if other_count > 1 else ''}:")
for other in nearby:
if other != tower:
print(f"- {other}")
This prints:
node/1336841279 is near 2 other towers:
- node/1336841280
- node/1336841271
node/10614444222 is near 1 other tower:
- node/10614444229
node/10614444223 is near 1 other tower:
- node/10614444227
This looks for any other power tower within 10 meters. If you meant “towers on the same line that are less than 10 meters apart,” let me know and I’ll show you how to adjust the script.
If you’re doing power-line QA, this checks for any towers on the same line that are less than min_distance meters apart:
import geodesk
world = geodesk.Features("world.gol")
lines = world("w[power=line]")
towers = world("n[power=tower]")
min_distance = 10
for line in lines:
warned = False
prev = None
for tower in towers.nodes_of(line):
if prev:
d = tower.distance(prev)
if d < min_distance:
if not warned:
print(f"{line} has closely-placed towers:")
warned = True
print(f"- {prev} and {tower} ({d:.2f} meters apart)")
prev = tower
(This script avoids flagging closely-placed towers of unrelated lines; it’s also more efficient, since it just walks the nodes of each power-line way.)
way/361936470 has closely-placed towers:
- node/1623811830 and node/1623811852 (9.67 meters apart)
way/202830461 has closely-placed towers:
- node/2127666543 and node/2127666546 (7.39 meters apart)
- node/2127666558 and node/2127666563 (5.19 meters apart)
Thank you very much! I got your code to work. Unfortunately, I’m not very familiar with GeoDesk and Python. How do I get the coordinates instead of the nodes?