Find unique loops in undirected graphs - algorithm

I am currently working on a node-based house-builder for Unity. The system is pretty simple in its workflow: users can create nodes, which are simply cubes, and connect them with each other to create walls. The mesh processing is already done and it works nice and smooth.
What I am trying to do now is to detect how many closed rooms have been created and what vertices are involved in each one of them. The possible inputs can be seen in the following images:
In the first picture, the loops would be
(1,5,3,4), (1,2,6,8,7,5), (6,9,12,11,10,8), (8,10,14,13) and (10,11,17,16,15,14).
In the second one they'd be
(1,2,5,6,8,7), (2,3,4,14,13,6,5), (6,13,12,11,10) and (8,6,10,9).
Each node can be connected to up to four other nodes, one per cardinal side, and every link is stored on both sides. I do not need the nodes to come in any particular order.
I thought I could use a generic loop-detection algorithm and recursively search for sub-loops until the loop I find has has no internal connections, but this would be extremely resource-consuming. There must be some properties I can use to detect loops with no internal connections without iterating over the graph so many times, but I haven't been able to find it.
Do you have any suggestion?

For the following algorithm to work, you need the following:
A unique direction of the edge (which you probably already have)
Two flags for every edge that specify if the edge has been used in the forward and the backward direction
A list of vertices with unused edges
Then the idea is the following. Take any node with unused edges and go along any of the unused edges to the neighbor (keep the direction in mind). Doing so, immediately mark the edge in the according direction as used. At this neighbor, you know the direction from which you came. Look in counter-clockwise order until you find the first unused edge (again watch out for the edge direction). You can also search in clockwise order, this will define the order of all your output faces. E.g. if you came from the left edge, then check the bottom, right, top edges, respectively. Go across this edge (mark as used) and repeat until you arrive at the start vertex. All visited vertices form your room.
Doing so, you should update the list of vertices with unused edges accordingly.
Eventually, you will also create a face for the border. You can detect this e.g. by calculating its orientation:
v1 x v2 + v2 x v3 + v3 x v4 + ... + vn x v1
, where v are the positions of the vertices and x represents the z-component of the cross product (which represents the face orientation):
(x1, y1) x (x2, y2) = (x1 * y2) - (x2 * y1)
The boundary face will have a different sign for this orientation than all other faces. The actual sign depends on whether you used counter-clockwise or clockwise order during the edge traversal.

This is an answer only to the first question, but it might help you with the second one. The number of closed rooms actually has a closed formula:
1 - V + E where V is the number of vertices and E is the number of edges. In your second example, there are 14 vertices, 17 edges and 4 rooms.
The mathematics are a bit complicated, but the key word is Euler characteristic.

Related

Convert voronoi edges into polygons

Currently I am trying to get Voronoi polygons dividing a plane of a certain size (e.g. 1000x1000 with 500 random points).
For this purpose, I used Delaunay's triangulation - Bowyer Watson's algorithm. Thanks to this, I am able to generate points and properly connect the edges included in the Voronoi diagram. Unfortunately, in my case, I need a list of polygons (of which each polygon contains a list of its edges).
I tried to create a naive algorithm that would take the edges one by one and look for the next ones to create a final polygon and so on - unfortunately without success. I was also thinking about taking the vertices of the triangles and creating a circle until the polygon is formed (from the existing edges), but I am not sure if this is a good solution?
Is there any way to do it? Or should I use a different algorithm to get the Voronoi polygon list?
I have not found a suitable solution to this problem on the Internet, if there is one, I will be grateful for the link
Select E an arbitrary edge
Add vertices in E to polygon
Select point P slightly to one side of E
If point inside plane
Select one vertex of selected edge
Select E2 new edge from vertex with smallest angle on side with point P
Add second vertex in E2 to polygon
Repeat last two steps until reach other vertex in E
Add polygon to solution, if not already included
Repeat with point on other side of edge
Repeat until all edges processed

Connecting a set of points with horizontally aligned polylines without them crossing

I have a set of 2D points where all values are integers. No points are identical. I want to draw polylines/paths/whatever through all the points with a few restrictions:
1: A line should always move in the positive x-direction. p1.x < p2.x < ...
2: Lines may never cross each other.
3: All polylines needs to begin at x = 0 and end at x-max.
4: It should use as few polylines as possible (or a number defined by me).
I have attached an image of a sample set of points. And a hand made solution I drew with a pencil and ruler.
It's trivial to find a solution by hand, but I have no idea how to describe my process in logical terms. I don't need an optimal solution (whatever that means). It doesn't need to be fast.
Point set (Disregard colors)
Connected Points
My current solution is to step through the set along the x-axis and then try all viable combinations and choosing the one with the lowest total vertical movement. This works in some cases but not all. And it seems to over-complicate the problem.
My next idea is to do a brute force approach with backtracking when collisions occour. But that also seems a bit much.
For anyone wondering the points are actually notes on sheet music. The x-axis is time and the y-axis is pitch. The polylines represent the movement of robotic fingers playing a piano.
We will find a solution which uses the minimum number of robotic fingers (least number of polylines). The trick is to consider your input as a Partially ordered set (or poset). Each point in your input is an element of the poset, and with the relation (p1.x, p1.y) < (p2.x , p2.y) if and only if p1.x < p2.x. This basically means that two points which have the same x-coordinate are incomparable with each other.
For now, let us forget this constraint: "Lines may never cross each other". We'll get back to it at the end.
What you are looking for, is a partition of this poset into chains. This is done using Dilworth's Theorem. It should be clear that if there are 5 points with the same x-coordinate, then we need at least 5 different polylines. What Dilworth's says is that if there is no x-coordinate with more than 5 points on it, then we can get 5 polylines (chains) which cover all the points. And it also gives us a way to find these polylines, which I'm summarizing here:
You just create a bipartite graph G = (U,V,E) where U = V = Set of all input points and where (u,v) is an edge in G if u.x < v.x. Then find a maximum matching, M, in this graph, and consider the set of polylines formed by including u and v in the same polyline whenever there is an edge (u,v) in M.
The only issue now, is that some of these polylines could cross each other. We'll see how to fix that:
First, let us assume that there are only two polylines, L1 and L2. You find the first instance (minimum x-coordinate) of their crossing. Suppose the two line segments which cross each other are AB and CD:
We delete AB and CD and instead add AD and CB:
The polylines still cross each other, but their point of crossing has been delayed. So we can keep repeating this process until there is no crossing left. This takes at most n iterations. Thus we know how to 'untangle' two polylines.
[The edge case of B lying on the segment CD is also handled in the exact same way]
Now, suppose we have k different polylines which the maximum matching has given us: L1, L2, ..., Lk. WLOG, let us assume that at x = 0, L1's y-coordinate is lower than L2's y-coordinate, which is lower than L3's and so on.
Take L1 and find the first time that it crosses with any other polyline. At that crossing, applying the swapping operation as above. Keep repeating this, until L1 does not cross with any other polyline. Now, L1 is at the 'bottom', and doesn't cross with any other line. We now output L1 as one of the final polylines, and delete it from our algo. We then repeat the same process with L2, and after outputting it, delete it, and repeat with L3, and so on.

Adding edges dynamically in a DCEL/half-edge based graph?

I'm trying to implement a vector graphics "drafting" system, where, in essence, users can draw lines on the screen and interact with the regions created by intersecting lines. I'm struggling with determining/evaluating what these regions are.
I've tried a few different solutions to this problem, chiefly keeping a list of edges and running a BFS to find shortest cycles, but this brought up a myriad of issues where the BFS would shortcut in illegal ways, and holes and degenerate edges caused more problems than I could count, so I moved on to a DCEL, half-edge system.
I've read seemingly everything I can on this topic, including two articles referenced frequently on here: http://kaba.hilvi.org/homepage/blog/halfedge/halfedge.htm and http://www.flipcode.com/archives/The_Half-Edge_Data_Structure.shtml. However, neither of these seem to answer this problem that I have when it comes to dynamically adding edges to the graph.
Let's say I start out with this single edge. Image
The half-edges connect with each other in a cycle, and the global, unbounded "outside face" is connected to one of the half edges. Easy, got that.
Then we add another edge, attached to the center vertex: Image
The new half-edges work fine, and we update the edges that flow into v1's next pointers to be the only other edges available that aren't their twins. Again, makes sense to me.
What confuses me to no end is what happens here, when we add a third edge to the center vertex: Image
I know that's what it's supposed to look like and link up to be, but I am so bewildered on how to achieve that programmatically, because I'm not sure how I can determine whether the edge (4,1) should point to edge (1,2), or edge (1,3) (similarly for what edge should point to (1,4)).
The answer seems obvious when looking at the image, but when you try to rationalize it in a robust, airtight algorithmic way, my brain melts and I can't figure it out. The textbook I'm reading (Computational Geometry, Mark de Berg et al., pg 35), just says
"[to test where the edge] should be in the cyclic order of the edges
around vertex v".
The algorithm given in the hilvi.org article for finding the outgoing and incoming edges to link up with doesn't even seem to work, as it will take vertex 1, and follow its outgoing edge's twin until it finds a "free" edge, which in this case, is (2,1) which is wrong. (Unless I'm understanding it incorrectly, I could be understanding this whole problem wrong.)
So I'm absolutely stumped. My only idea now is to create some sort of heading attribute for each half edge, where I measure the angle created by the edge, and choose the edges that way, and maybe that's right, but that seems so against what the half-edge structure seems to support, at least in the articles I'm reading about it, nothing seems to mention anything like that. Any help would be extremely appreciated. I've been on this problem for over a week now and just can't seem to get unstuck.
Right, so I've spent a lot of time thinking about this problem, and to be honest I'm kinda surprised that I can't find a direct answer to this issue. So, in case anyone in the future runs into a similar problem of wanting to populate a half-edge graph from the ground up, here's a solution that works. I don't have a blog, so I'm writing it here.
I have no idea if it's the best answer, but it works in linear time and seems simple to me.
I'll be dealing with the following objects/classes, that vary slightly from the conventional DCEL:
class Vertex {
x;
y;
edges = []; //A list of all Half Edges with their origin at this vertex.
//Technically speaking this could be calculated as needed,
and you could just keep a single outgoing edge, but I'm not
in crucial need of space in my application so I'm just
using an array of all of them.
}
class HalfEdge {
origin; //The Vertex which this half-edge emanates from
twin; // The half-edge pair to this half-edge
face; // The region/face this half-edge is incident to
next; // The half-edge that this half-edge points to
prev; // The half-edge that points to this half-edge
angle; //The number of degrees this hedge is CW from the segment (0, 0) -> (inf, 0)
}
class Face {
outer_edge; //An arbitrary half-edge on the outer boundary defining this face.
inner_edges = []; //A collection of arbitrary half-edges, each defining
//A hole in the face.
global; //A boolean describing if the face is the global face or not.
//This could also be done by having a single "global face" Face instance.
//This is simply how I did it.
}
For initializing a vertex at(x,y):
Verify that a vertex with the given (x,y) coordinates does not already exist. If it does, you don't have to do anything (except maybe return this existing vertex if you're using it immediately).
If it doesn't, allocate space for and create a new vertex with the corresponding x,y values, and with its incident edge null.
For initializing an edge from vertex A to vertex B:
Similarly to many of the articles about this topic, we create two new instances of HalfEdge, one from vertex A to B, one from B to A. They link to each other in that we set their twin, prev, and next pointers all to the other half-edge (hedge).
We also set the angle of the hedge. The angle is calculated clockwise from the positive x-axis. The function I implemented is below. This is super important to making this data structure work properly, and that fact that I haven't read anything in the literature about this being important makes me think there has to be a better way, but I digress.
setAngle(){
const dx = this.destination().x - this.origin.x;
const dy = this.destination().y - this.origin.y;
const l = Math.sqrt(dx * dx + dy * dy);
if (dy > 0) {
this.angle = toDeg(Math.acos(dx / l));
} else {
this.angle = toDeg(Math.PI * 2 - Math.acos(dx / l));
}
function toDeg(rads) {
return 180 * rads / Math.PI;
}
}
Next, we pair the vertices with their new edges by adding them to their Vertex's edge list, and then we sort the edge list by the hedge's angles from smallest (0) to largest (359).
Then and this is the crucial step, in order to link everything up properly, we grab the closest hedge to the new hedge we're trying to link up in CCW order. Basically, wherever our new hedge ends up in the edge list, it's that index - 1 (if index = 0, we return edges[edges.length - 1]). Take that edge's twin, and that becomes our AIn described in the hivli article above. BOut = AIn.next.
We set AIn.next = hedgeAB and similarly, hedgeAB.prev = AIn, then hedgeBA.next = AOut, AOut.prev = hedgeBA. Perform steps 3-5 for the hedgeBA as well, except running the CCW search on vertex B.
Then, if both vertex A and B were "old" vertices, meaning their edge lists now have at least 2 elements each, a new face has potentially been added, and we need to find it (the edge case is having two isolated edges and connecting them to create an unbounded bucket or cap shape)
For initializing a Face:
We need to find all the cycles in a graph. For my first implementation of this, I recalculated all of the cycles every single time, resetting all the faces. This isn't necessary, but it also isn't too expensive, since we're not running a search, everything is in linear time with respect to the number of cycles and number of vertices in each cycle.
To do this, we get a list of all the hedges in the graph. It doesn't really matter how you do this, I decided to keep an array of every hedge that I passed into my cycle-finder function each time.
Then we look through that list, while the list isn't empty, we take the first item and run its cycle, removing every hedge we find along the way from the list, and adding it into a new cycle, which we add to another list
With this new list of cycles, we need to determine whether the cycle is an inside/outside cycle. There are a lot of ways to do this, and the Computational Geometry book mentioned above has a great section about it. The one that I used is to calculate the area defined by each cycle. If the area is >= 0, the cycle is defined by "inside" hedges. Otherwise, it's defined by "outside" hedges.
The last step is to set all the face records, again, the aforementioned textbook has a lot of great details about this, but the basic idea is to basically create a virtual "graph" of these cycles, and connect outside cycles (which are holes in faces), to their corresponding inside cycles, which are the outer boundaries of faces. To do this, you look at the leftmost vertex of the cycle and extend a ray out infinitely to the left, and "connect" the cycle with the first downward-facing hedge of a cycle the ray hits (I'll leave the implementation up to you, I have no idea if my way is the best, in short, I checked every cycle with a leftmost vertex left of the current cycle and calculated the rightmost intersection with the y value of the leftmost vertex of the current cycle, and then checked if that was facing downward).
With this graph of cycles, run a BFS/DFS starting from each "inside-hedge" cycle (not the holes), and create a face with an arbitrary hedge from the inside-hedge cycle as the outer edge, (or null if it's the global face), and an arbitrary hedge from each found hole-cycle to the face's inner components.
Hey presto, that's it. If you check everything every time, that handles everything. It handles face splitting like a charm and is very robust and quick. I don't know if it's right, but it works.

Point inside arbitrary polygon with partitions

Say I have a polygon. It can be a convex one or not, it doesn't matter, but it doesn't have holes. It also has "inner" vertices and edges, meaning that it is partitioned.
Is there any kind of popular/known algorithm or standard procedures for when I want to check if a point is inside that kind of polygon?
I'm asking because Winding Number and Ray Casting aren't accurate in this case
Thanks in advance
You need to clarify what you mean by 'inner vertices and edges'. Let's take a very general case and hope that you find relevance.
The ray casting (point in polygon) algorithm shoots off a ray counting the intersections with the sides of the POLYGON (Odd intersections = inside, Even = outside).
Hence it accurately gives the correct result regardless of whether you start from inside the disjoint trapezoidal hole or the triangular hole (inner edges?) or even if a part of the polygon is completely seperated and/or self intersecting.
However, in what order do you feed the vertices of the polygon such that all the points are evaluated correctly?
Though this is code specific, if you're using an implementation that is counting every intersection with the sides of the polygon then this approach will work -
- Break the master polygon into polygonal components. eg - trapezoidal hole is a polygonal component.
- Start with (0,0) vertex (doesn't matter whether (0,0) actually lies wrt your polygon) followed by the first component' vertices, repeating its first vertex after the last vertex.
- Include another (0,0) vertex.
- Include the next component , repeating its first vertex after the last vertex.
- Repeat the above two steps for each component.
- End with a final (0,0) vertex.
2 component eg- Let the vertices of the two components be (1x,1y), (2x,2y), (3x,3y) and (Ax,Ay), (Bx,By), (Cx,Cy). Where (Ax,Ay), (Bx,By), (Cx,Cy) could be anything from a disjoint triangular hole, intersecting triangle or separated triangle.
Hence , the vertices of a singular continous polygon which is mathematically equivalent to the 2 components is -
(0,0),(1x,1y),(2x,2y),(3x,3y),(1x,1y),(0,0),(Ax,Ay),(Bx,By),(Cx,Cy),(Ax,Ay),(0,0)
To understand how it works, try drawing this mathematically equivalent polygon on a scratch pad.-
1. Mark all the vertices but don't join them yet.
2. Mark the repeated vertices separately also. Do this by marking them close to the original points, but not on them. (at a distance e, where e->0 (tends to/approaches) ) (to help visualize)
3. Now join all the vertices in the right order (as in the example above)
You will notice that this forms a continuous polygon and only becomes disjoint at the e=0 limit.
You can now send this mathematically equivalent polygon to your ray casting function (and maybe even winding number function?) without any issues.

Four-way navigation algorithm

Consider a rectangular shaped canvas, containing rectangles of random sizes and positions. To navigate between these rectangles, a user can use four arrows: up, down, left, right.
Are you familiar with any algorithm of navigation that would produce a fairly straightforward user experience?
I came across a few solutions but none of them seemed suitable. I am aware that no solution will be "ideal". However, the kind of algorithm I am looking for is the sort used to navigate between icons on a desktop using only the arrow keys.
[EDIT 21/5/2013: As pointed out by Gene in a comment, my weighting scheme actually does not guarantee that every rectangle will be reachable from every other rectangle -- only that every rectangle will be connected to some other rectangle in each direction.]
A nice way to do this is using maximum weighted bipartite matching.
What we want to do is build a table defining a function f(r, d) that returns the rectangle that the user will be moved to if they are currently at rectangle r and hit direction d (up, down, left or right). We would like this function to have some nice properties, such as:
It must be possible to reach every rectangle from every other rectangle
Pressing left then right or vice versa, or up then down or vice versa, should leave the user in the same place
Pressing e.g. left should take the user to a rectangle to the left (this is a bit more difficult to state precisely, but we can use a scoring system to measure the quality)
For each rectangle, create 4 vertices in a graph: one for each possible key that could be pressed while at that rectangle. For a particular rectangle r, call them rU, rD, rL and rR. For every pair of rectangles r and s, create 4 edges:
(rU, sD)
(rD, sU)
(rL, sR)
(rR, sL)
This graph has 2 connected components: one contains all U and D vertices, and the other contains all L and R vertices. Each component is bipartite, because e.g. no U vertex is ever connected to another U vertex. We could in fact run maximum weighted bipartite matching on each component separately, although it's easier just to talk about running it once on the entire graph after grouping, say, U vertices with L vertices and D vertices with R vertices.
Assign each of these edges a nonnegative weight according to how much sense it makes for that pair of rectangles to be connected by that pair of keys. You are free to choose the form for this scoring function, but it should probably be:
inversely proportional to the distances between the rectangles (you could use the distance between their centres), and
inversely proportional to how far the angle between the centres of the rectangles differs from the desired horizontal or vertical line, and
zero whenever the rectangles are oriented the wrong way (e.g. if for the edge (rU, sD) if the centre of r is actually above the centre of s). Alternatively, you can just delete these zero-weight edges.
This function attempts to satisfy requirement 3 at the top.
[EDIT #2 24/5/2013: Added an example function below.]
Here is C-ish pseudocode for an example function satisfying these properties. It takes the centre points of 2 rectangles and the direction from rectangle 1 (the direction from rectangle 2 is always the opposite of this direction):
const double MAXDISTSQUARED = /* The maximum possible squared distance */;
const double Z = /* A +ve number. Z > 1 => distance more important than angle */
// Return a weight in the range [0, 1], with higher indicating a better fit.
double getWeight(enum direction d, int x1, int y1, int x2, int y2) {
if (d == LEFT && x1 < x2 ||
d == RIGHT && x1 > x2 ||
d == UP && y1 < y2 ||
d == DOWN && y1 > y2) return 0;
// Don't need to take sqrt(); in fact it's probably better not to
double distSquared = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
double angle = abs(atan2(x1 - x2, y1 - y2)); // 0 => horiz; PI/2 => vert
if (d == UP || d == DOWN) angle = PI / 2 - angle;
return 1 - pow(distSquared / MAXDISTSQUARED, Z) * (2 * angle / PI);
}
Now run maximum weighted bipartite matching. This will attempt to find the set of edges having highest total weight such that every vertex (or at least as many as possible) are adjacent to a selected edge, but no vertex is adjacent to more than one edge. (If we allowed a vertex to be adjacent to more than one edge, it would mean that pressing that key while at that rectangle would take you to more than one destination rectangle, which doesn't make sense.) Each edge in this matching corresponds to a bidirectional pair of keypresses, so that pressing e.g. up and then down will take to back to where you were, automatically satisfying requirement 2 at the top.
The only requirement not automatically satisfied by this approach so far is the important one, number 1: it does not necessarily guarantee that every rectangle will be reachable. If we just use the "raw" quality scores as edge weights, then this can actually occur for certain configurations, e.g. when there is one rectangle in each of the 4 corners of the screen, plus one at the centre, the centre one might be unreachable.
[EDIT 21/5/2013: As Gene says, my claim below that property 1 is satisfied by the new weighting scheme I propose is wrong. In many cases every rectangle will be reachable, but in general, you need to solve the NP-hard Hamiltonian Cycle problem to guarantee this. I'll leave the explanation in as it gets us some of the way there. In any case it can be hacked around by adjusting weights between connected components upward whenever subcycles are detected.]
In order to guarantee that the matching algorithm always returns a matching in which every rectangle is reachable, we need to adjust the edge weights so that it is never possible for a matching to score higher than a matching with more edges. This can be achieved by scaling the scoring function to between 0 and 1, and adding the number of rectangles, n, to each edge's weight. This works because a full matching then has score at least 4n^2 (i.e. even if the quality score is 0, the edge itself has a weight of n and there are 4n of them), while any matching with fewer edges has score at most 4(n-1)(n+1) = 4n^2 - 4, which is strictly less.
It's a truism that to a person with a hammer everything looks like a nail. Shortest path algorithms are an obvious tool here because shortest distance seems intuitive.
However we are designing a UI where logical distance is much more important than physical distance.
So let's try thinking differently.
One constraint is that repeatedly hitting the up (right, down or left) arrow ought to eventually cycle through all the rectangles. Otherwise some unreachable "orphans" are likely. Achieving this with an algorithm based on physical (2d) distance is difficult because the closest item in 2d might be in the wrong direction in the 1d projection corresponding to the arrow pair being used. I.e. hitting the up arrow could easily select a box below the current. Ouch.
So let's adopt an extremely simple solution. Just sort all the rectangles on the x-coordinate of their centroids. Hitting the right and left arrow cycles through rectangles in this order: right to the next highest x and left to the next lowest x. Wrap at the screen edges.
Also do the same with y-coordinates. Using up and down cycles in this order.
The key (pun intended) to success is adding dynamic information to the screen while cycling to show the user the logic of what is occurring. Here is a proposal. Others are possible.
At first vertical (up or down) key, a pale translucent overlay appears over the rectangles. They are shaded pale red or blue in a pattern that alternates by y coordinate of centroid. There are also horizontal hash marks of matching color across the entire window. The only reason for two colors is to provide a visual indicator of correspondence between lines and rectangles. The currently selected rectangle is non-translucent and the hash mark is brighter than all the others. When you continue to hit the up or down key, the highlighted box changes in the centroid y-order as described above. The overlay disappears when no arrow key has been struck for a half second or so.
A very similar overlay appears if a horizontal key is hit, only it's vertical hash marks and x-order.
As a user I'd really like this scheme. But YMMV.
The algorithm and data structures needed to implement this are obvious, trivial, and scale very well. The effort will go into making the overlays look good.
NB Now that I have done all the drawings I realize it would be a good idea to place a correctly colored dot at the centroid of each box to show which of the lines is intersecting it. Some illustrative diagrams follow.
Bare Boxes
Selection with up or down arrow in progress
Selection with left or right arrow in progress
What about building a movement graph as follows:
for any direction, try to go to the nearest rectangle, in the given direction, whose center point is the middle of the current rectangle's side.
try to eliminate loops, e.g. moving 'right' from A should try to yield a different rectangle than moving 'up-right' from A. For example in this drawing, the 'right' from green should be orange, even though pink would be the nearest mid-point
(Thanks to biziclop): if any rectangles aren't reachable in the graph, then re-map one of the adjoining rectangles to get to it, likely the one with the least error. Repeat until all rectangles are reachable (I think that algorithm would terminate...)
Then store the graph and only use that to navigate. You don't want to change the directions in the middle of the session.
This problem can be modeled as a graph problem and algorithm of navigation can be used as a shortest path routing.
Here is the modelling.
Each rectangle is a vertex in the graph. From each vertex (aka rectangle) you have four options - up, down, left, right. So, you can reach four different rectangles, i.e this vertex will have four neighbors and you add these edges to graph.
I am not sure if this is part of the problem -- "multiple rectangles can be reached from a rectangle using a particular action (e.g. up)". If not, the above modelling is good enough. If yes, then add all such vertices as the neighbor for this vertex. Therefore, you may not end up with a 4-regular graph. Otherwise, you will model your problem into a 4-regular graph.
Now, the question is how do you define your "navigation" algorithm. If you do not want to distinguish between your actions, i.e. if up, down, left, and right are all equal, then you can add weight of 1 to all edges.
If you decide to give a particular action more precedence than other, say up is better than the rest, then you can give weight for edges resulted from up movement as 1, and the remaining edges as 2. The idea is by assigning different weights you can distinguish between the edges you will travel.
If you decide that all up edges are not equal, i.e. the up distance between A and B, is shorter than the up distance between C and D, then you can accordingly assign weights to the edges during the graph construction process.
Here is the routing
Now how to find the route -- You can use dijkstra's algorithm to find a shortest path between a given pair of vertices. If you are interested in multiple shortest paths, you can use k-shortest path algorithm to find k shortest paths between a pair of node, and then pick your best path.
Note that the graph you end up with does not have to be a directed graph. If you prefer a directed graph, you can assign directions to the edges when you are constructing them. Otherwise you should be good using an undirected graph, as all you care is to use an edge to reach a vertex from another. Moreover, if rectangle A can be reached using up from rectangle B, then rectangle B can be reached using down from rectangle A. Thus, directions really do not matter, if you do not need them for other reasons. If you do not like the assumption I just made, then you need to construct a directed graph.
Hope this helps.

Resources