pythonopenstreetmapshapelyosmium

Plotting unsorted way/area's node reference from .osm file


So i am trying to define an exact shape (outter layer) of a building from .osm node references because I need to create more detail structure inside it (rooms, walls) based of some assumption.

Until now I've extracted the node's coordinate from its reference of 'building:part' using pyosmium, stored the node's coordinates to a list of tuples, reconstructed it using Polygon function from shapely and plotted it using mplleaflet. But somehow the nodes from the reference aren't sorted and when I try to plot it, there are a lot of intersections shown.

My current method to solve this sorting problem is following:

def distance(current_data, x_point):
        # find the shortest distance between x_point and all points in current data
        # check if it's perpendicular to the line built before
        return current_data[x] # which perpendicular and has shortest distance to x_point

def sort_nodes(nodes):
        temp = []
        for node in nodes:
               if len(temp) < 2: # adding first 2 points as a starting line 
                     temp.append(node)
               else:
                     n = distance(temp, node)
                     # find index of current_data[x] in temp
                     return temp.insert(min_index, node)

sorting the tuples of coordinates only by its distance (shortest) still doesn't solve the problem. And even sorting it based on its degree could lead to another problem which not all building is rectengular in shape.

so this is how I got so far by sorting based on distance.plotted image

Is there any better way to do this? Or did I do it wrongly? I've tried this for 2 days straight. I am sorry if it's to trivial but i am really new with coding and need to make this done. Thanks for the help.

edit: answer to scai

here's my following method extracting the nodes:

import osmium as osm
def way_filter():
    class WayFilter(osm.SimpleHandler):

        def __init__(self):
            super(WayFilter, self).__init__()
            self.nodes = []

        def way(self, w):
            if 'building:part' in w.tags and w.tags['building:part'] == 'hospital':
                temp = []
                for n in w.nodes:
                    temp.append(n.ref)
                self.nodes.append(temp)

     ways = WayFilter()
     ways.apply_file(map)
     return ways.nodes

def get_node(ref_node):
   class ObjectCounterHandler(osm.SimpleHandler):
       def __init__(self):
           osm.SimpleHandler.__init__(self)
           self.location = []
           self.ref = ref_node

       def write_object(self, lon, lat):
           self.location.append([lon, lat])

       def node(self, n):
            try:
               if any(n.id in sublist for sublist in self.ref):
                   self.write_object(n.location.lon, n.location.lat)
            except TypeError:
               if n.id in self.ref:
                   self.write_object(n.location.lon, n.location.lat)

   h = ObjectCounterHandler()
   h.apply_file(map)
   return h.location

Main Program

a = way_filter()
for ref in a:

    b = get_node(ref)
    c = next(colors)
    loc = []

    for x in b:
        loc.append(tuple(x))

    # plot the points
    polygons = Polygon(loc)
    x,y = polygons.exterior.xy
    plt.plot(x,y, zorder=1) 
mplleaflet.show()

and here is the result without sorting. plot image without sort


Solution

  • Nodes are referenced by ways in the correct order, i.e. so that they are adjacent to each other. You don't need to perform any manual sorting if you read the list of referenced node IDs correctly. Manual sorting is only required for relation elements.

    Unfortunately I'm not familiar with pyosmium so I can't tell you what's wrong with your code.