2

Sorry for bad English. It's somehow called Minimal Cycle Basis of graph algorithm. I'm currently working on some algorithm to seperate a graph into rooms. Like the example. I have a graph link like the one in left, I want to tell there are 2 rooms in the graph, like the red area and the orange area in the right.

So far, I've tried to walk the shortest path from an edge, which failed. Like, in the left image, I started from the edge marked red, the shortest path would be like the right image.

I've also tried to always take the turn with largest angle in clockwise. If it work in one graph, it would failed when starting with opposite direction.

Is there any cheap solution on this one? I'm currently quick trapped.

1
  • Do you only need to count the number of rooms? Commented Jul 9 at 14:19

4 Answers 4

1

Start at any edge, keeping track of which direction you're considering the edge in. Find the vertex at the end of the edge, then find the vertex coming out from the edge with a direction (out from that vertex) which makes the largest signed counterclockwise angle with the direction edge you started at. For instance, starting at the black edge, you could choose the blue edge or the green edge:

enter image description here

In this case, the angle formed to the blue edge is about 95 degrees, and the angle formed to the green edge is about 150 degrees. So you transition to the green edge. Keep following that rule, and eventually you'll get back to the starting edge. Those edges, taken in order, form a "room" (a face, in geometric terms).

Then, start with a new edge, one which you haven't yet visited in that direction. Each edge will be visited twice, once in each direction. That'll be a new room.

After you're all done, you'll have one edge loop for each room, plus an edge loop for the outside "room". Filter that one out if you like; it's the only one with a negative signed area.

2
  • I think it's the same as the last attempt of mine in the question - by taking largest signed clockwise or counterclockwise. In some scenarioes, it didn't work out well, like the example I've given in the last image. I'm currently trying something like taking the first turn with highest unsigned angle and then deciding clockwise or counterclockwise by the first turn - it's pretty hard to prove its stability.
    – Blastom
    Commented Jul 10 at 2:28
  • No, it’s not the same. You shouldn’t choose between clockwise and counter-clockwise. Always pick the largest signed angle, and the result will be going counter-clockwise.
    – Sneftel
    Commented Jul 10 at 6:51
1

With , you could make a Graph, get the cycle_basis, then polygonize its elements :

import networkx as nx
from shapely import Polygon, polygonize, unary_union

rooms = [
    poly
    for poly in polygonize(
        unary_union(
            list(
                x.exterior for x in map(Polygon, nx.cycle_basis(nx.Graph(edges)))
            )
        ).geoms
    ).geoms
]

# [
#     <POLYGON ((160 20, 10 100, 100 120, 160 20))>,
#     <POLYGON ((160 20, 100 120, 10 100, 30 180, 140 220, 180 140, 160 20))>
# ]

enter image description here

Used input :

edges = [
    ((10, 100), (30, 180)),
    ((30, 180), (140, 220)),
    ((140, 220), (180, 140)),
    ((180, 140), (160, 20)),
    ((160, 20), (10, 100)),
    ((10, 100), (100, 120)),
    ((100, 120), (160, 20)),
]
1
  • Thanks. Though I'm not using Python, I would consider the source of code of Shapely as the last resort.
    – Blastom
    Commented Jul 10 at 2:24
0

I would probably attempt an algorithm where:

  1. I mark every side of every edge as a potential room;
  2. Group these potential room into sets which are actually the same room (you could use the paths you've already drawn to do this)
  3. Discard the outside of the shape
  4. Treat each remaining set as a room enter image description here
4
  • 1
    Your step 2 is handwaving away the actual problem. What would shortest paths have to do with determining which half-edges belong to which room?
    – Sneftel
    Commented Jul 9 at 16:31
  • The step 2 requires the graph to be seperated before head, I think. And it's hard to tell if a side of an edge is outside the graph.
    – Blastom
    Commented Jul 10 at 1:38
  • You could see the last example, which I did it by clockwise (smallest signed angle). Starting from the edge at top-left, different starting directions would get different results.
    – Blastom
    Commented Jul 10 at 12:39
  • As you always take the rightmost turn (largest angle clockwise) then all the right sides of edges on your orientated path are in a common room (or they are all outside). Commented Jul 10 at 17:35
0

Finally, I've got the principles. For an edge inside the graph, which should be shared by 2 circle basises, priorizing the largest signed angle (counter-clockwise) would find one of them, whose edges going counter-clockwisely. And priorizing the smallest (clockwise) would find the other (edges go clockwisely). So both would be correct.

But for an edge on the 'edge' of the graph, who was only contained by 1 circle basis, one of the basises should not exist. So one of the priorizing ways would give the wrong result.

On this scenario, you could find the polygon, in the result, clockwisely doesn't match pathfinding priorizing. So you could change the priorizing and got the right result.

The way to determine if a polygon is clockwise could be found below. How to determine if a list of polygon points are in clockwise order?

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