Kojo88
Kojo88

Reputation: 25

Find pattern in Openstreetmap using Python

I am working in python. My project's aim is to find a pattern on a network of streets. So for example, I define a "house" with edges and nodes like this

#Step 2: Define the house pattern
def create_house_graph():
    """Create a house-shaped graph."""
    H = nx.Graph()
    H.add_nodes_from([1, 2, 3, 4, 5])  # 5 nodes
    H.add_edges_from([(1, 2), (2, 3), (3, 4), (4, 1), (1, 5), (3, 5)])  # Square with triangle top
    return H

house_graph = create_house_graph()

My city graph is defined as

city = "Munich, Germany"
graph_file = "munich_bike_network.graphml"
try:
    G = ox.load_graphml(graph_file)
except FileNotFoundError:
    G = ox.graph_from_place(city, network_type="bike")
    ox.save_graphml(G, graph_file)

How can I perfom a fitting or snapping of my house pattern on my city map. Since networkx is only doing exact matching this approach doesn't work.

This is my try:

# Step 3: Generate more rotated, scaled, and translated variants of the house shape
def generate_house_variants(rotations=5, scales=[0.8, 1, 1.2], translations=[-0.0005, 0, 0.0005]):
    variants = []
    base_shape = create_house_shape()
    
    for scale in scales:
        for rotation in np.linspace(0, 360, rotations, endpoint=False):
            for dx in translations:
                for dy in translations:
                    # Create a variant with transformations
                    variant = nx.Graph()
                    for node in base_shape.nodes:
                        # Transform node positions (set default x, y if not present)
                        x, y = node % 2, node // 2  # Example positions to get x, y coordinates
                        x, y = scale * (x + dx), scale * (y + dy)
                        theta = np.radians(rotation)
                        x_rot = x * np.cos(theta) - y * np.sin(theta)  # Rotate
                        y_rot = x * np.sin(theta) + y * np.cos(theta)
                        variant.add_node(node, pos=(x_rot, y_rot))
                    variant.add_edges_from(base_shape.edges)
                    variants.append(variant)
    
    return variants

# Step 4: Try to find approximate matches with tolerance
house_variants = generate_house_variants()
matches = []
tolerance = 0.0002  # Latitude/longitude tolerance, adjust based on real-world distances

def node_within_tolerance(n1, n2, tolerance):
    pos1 = G.nodes[n1]['x'], G.nodes[n1]['y']
    pos2 = n2  # n2 is a tuple (x_rot, y_rot)
    return np.sqrt((pos1[0] - pos2[0])**2 + (pos1[1] - pos2[1])**2) < tolerance

for i, H_variant in enumerate(house_variants):
    match_found = False
    for g_node in G.nodes:
        variant_nodes = list(H_variant.nodes(data="pos"))
        match = []
        for _, pos in variant_nodes:
            nearby_nodes = [n for n in G.nodes if node_within_tolerance(n, pos, tolerance)]
            if nearby_nodes:
                match.extend(nearby_nodes)
            else:
                break
        if len(match) == len(H_variant.nodes):
            match_found = True
            matches.append((H_variant, match))
            break  # Stop after finding the first match for this variant

Can anyone advise?

BR Konstantin

Upvotes: 0

Views: 16

Answers (0)

Related Questions