1

With overpass, I use CSV to create individual formatted output.

All ways of a relation are determined. Here is the code:

[out:csv("print1";false)];

(
relation(id:15596842);
way(r);
) -> .set1;

for.set1 -> .set2 (id())  {
  make x
    print1 = "id: " + set2.val;
  out;
  
  foreach.set2 -> .set3 {      
    make x
      print1 = "coord: " + set3.u(lat()) + " " + set3.u(lon());
    out;
  }
};

Code on https://overpass-turbo.eu.

However, only the coordinates of the first nodes of these ways are output:

id: 15596842
coord: 44.6544826 -1.1932969
id: 40781706
coord: 44.6552341 -1.1936651
...

How must the code be modified so that all node coordinates of the respective way are output?

2 Answers 2

1

This is currently not supported by Overpass API. There's no way to iterate over nodes of a way in the exact sequence defined by the way. However, with a bit of regex post processing, it should be trivial to transform the output of the following query to the desired format:

relation(15596842);
way(r);

foreach {
  convert way ::id = id(), ::geom = geom();
  out geom;
};
0

Following my ideas and solutions to the question, including the special Overpass csv-output.

Variant 1

The following code outputs all coordinates of the relation, related to the respective ways:

[out:csv(print1;false)] [timeout:10];
relation(id:15596842);
way(r) -> .setWays;

for .setWays -> .setWay (id()) {
  .setWay; node(w) -> .setNodes;
  make x print1 = setWay.u(type()) + " " + setWay.u(id()); out;
  
  for .setNodes -> .setNode (id())  {
    make x print1 = setNode.u(type()) + " " + setNode.u(id()) + " " + setNode.u(lat()) + " " + setNode.u(lon());
    out;  
  };
  make x print1 = ""; out;
};

@ Overpass

However, Overpass sorts the nodes according to their ID, so the listing of nodes does not corresponds to their order in Openstreetmap. With the result, a way can not be created correctly.

way 40781706
node 368458761 44.6578979 -1.1938769
node 368458763 44.6577942 -1.1937059
node 368458764 44.6577924 -1.1935670
node 368458766 44.6577642 -1.1932297
...

Note: the notation of code can be made simpler, for example using the default-set _, or even without it. However, in order better to see which query results and are used also in the following variants, the notation here is not in short form.

Idea 2

The function per_member() processes all child elements of a parent element without changing their order. So, this can be used for the output:

[out:csv(print1;false)] [timeout:10];
relation(id:15596842);
way(r) -> .setWays;

for .setWays -> .setWay (per_member(mtype() + " " + ref() + "\n")) {
  make x print1 = setWay.u(type()) + " " + setWay.u(id()); out;
  make x print1 = setWay.val; out;
  make x print1 = ""; out;
};

@ Overpass

The output corresponds exactly to the order as it was realized in Openstreetmap:

way 40781706
"node 368458761
;node 6730586321
;node 368458763
;node 368458764
...

But there is no possibility to output the latitude or longitude of the nodes. E.g. node(ref()).u(lat()) or node(368458761).u(lat()) inside of per_member does not produce output. Another small point is that the special Overpass csv output cannot be configured absolutely freely, because output always includes ; and ".

Variant 3

With way(w:n) can be accessed a specific node within a way. n corresponds to the position as Openstreetmap. When continuously increased n, so all nodes of a way can be queried one after the other. However, n cannot be a variable. n must be hard-coded. This means that there must be a separate code for each node. With e.g. 35 nodes, therefore a corresponding instruction is needed at least 35 times:

[out:csv(print1;false)] [timeout:10];
relation(id:15596842);
way(r) -> .setWays;

for .setWays -> .setWay (id()) {  // ways in id order
//foreach .setWays ->.setWay {    // ways not in id order
  make x print1= "way " + setWay.u(id()); out;  

  .setWay;node (w:1); if(u(id())) {make x print1=u(id()+" "+lat()+" "+lon());out;};
  .setWay;node (w:2); if(u(id())) {make x print1=u(id()+" "+lat()+" "+lon());out;};
  .setWay;node (w:3); if(u(id())) {make x print1=u(id()+" "+lat()+" "+lon());out;};
  .setWay;node (w:4); if(u(id())) {make x print1=u(id()+" "+lat()+" "+lon());out;};
  .setWay;node (w:5); if(u(id())) {make x print1=u(id()+" "+lat()+" "+lon());out;};
  .setWay;node (w:6); if(u(id())) {make x print1=u(id()+" "+lat()+" "+lon());out;};
  .setWay;node (w:7); if(u(id())) {make x print1=u(id()+" "+lat()+" "+lon());out;};
  // ... and so on
  .setWay;node (w:8) -> .setLastNode; .setLastNode; if(u(id())) {make x print1=set(id()+" "+lat()+" "+lon());out;};
  .setWay;node (w:-1) -> ._; ._; if(setLastNode.u(id()) && (u(id()) != setLastNode.u(id()))) {make x print1
  =u(id()+" "+lat()+" "+lon());out;};
  make x print1="";out;
};

@ Overpass

The last two lines are programmed differently so that, even if a way has more nodes, the very last node is still output with its data and at least the last node of the way can be visible.

This will output the nodes with their values ​​and in the correct order:

way 40781706
368458761 44.6578979 -1.1938769
6730586321 44.6578304 -1.1938244
368458763 44.6577942 -1.1937059
368458764 44.6577924 -1.1935670
...

Variant 4

In the previous variant, the code may be very long and it can still happen that there are more nodes than the output was programmed for. The best way would be if a variable number of nodes could be taken into account. The first problem is that Overpass does not support to use variables, that can e.g. be used as running variable. Well, there are still a trick and tricks to make the whole thing possible nevertheless. This is the code:

[out:csv(print1; false)] [timeout:10];
relation(id:15596842);
way(r) -> .setWays;

for .setWays -> .setWay (id()) {
  make x print1 = setWay.u(type()) + " " + setWay.u(id()); out;
  .setWay; node(w) -> .setNodes;              // all nodes, but in Overpass ID ascending order
  .setNodes -> .setCounter;                   // setCounter as i
  
  foreach .setNodes {                         // loop over all (OSM-) positions with setCounter as i
    foreach .setNodes -> .setNode {           // loop over all node ID's
      for .setWay -> .setMember (per_member(pos() + "_" + ref())) {  // comparison with origin OSM-order database as [pos_id]: "1_6735630372;2_6735630371;..."
        if (lrs_in ((setNodes.count(nodes)-setCounter.count(nodes)+1) + "_" + setNode.u(id()), setMember.val)) {   // compose loops [pos_id], pos=max-i+1; element at appropriate (OSM-) position found
          make x print1 = setNode.u(id()) + " " + setNode.u(lat()) + " " + setNode.u(lon()); out; // customizable output
          (.setCounter; - .setNode;) -> .setCounter;  // decrease number of elements for counter: i=i-1
        }
      }
    } 
  };
  make x print1 = ""; out;
};

@ Overpass

Explanation:

The per_member method in Overpass generate the result in the same order as the Openstreetmap database. But due some limitations of Overpass, it is not sufficient simply to determine the IDs of the nodes in the correct order. Therefore a special ID is generated with the internal position number and the node ID. Data sets with all possible variants of position and node ID are then generated and compared with the correct special position ID from per_member. If there is a match, the output is displayed.

Since variables are not possible in Overpass, a counter is simulated by using of [number of nodes]-[number reduced by one node per run]

Compared to the variants before, this code requires the greatest computing capacity, so that this code should be used with caution when dealing with large amounts of data.

The result corresponds to that of Variant 3:

way 40781706
368458761 44.6578979 -1.1938769
6730586321 44.6578304 -1.1938244
368458763 44.6577942 -1.1937059
368458764 44.6577924 -1.1935670
...

Not the answer you're looking for? Browse other questions tagged or ask your own question.