Algorithm to convert cell groups into a polygon - algorithm

Suppose i have currently a group of cells which can be considered "on" or "off", something like this picture (White means off, black means on)
Cells
The cells are basically squares with size = 1, and each corner can be calculated by:
p0 = p
p1 = p + (0, 1)
p2 = p + (1, 1)
p3 = p + (1, 0)
so each cell is actually a polygon in itself with 4 vertices
I want to generate an ordered list of vertices that creates a polygon in which all cells are grouped together, removing internal and redundant vertices, something like this:
Cells Grouped
So, the algorithm i came upon while trying to solve this only detects the verticies, and they detect correctly, and its quite simple code actually. It works like this:
foreach cell
foreach corner of the cell //each corner is a vertex of a square cell
if !vertex_list.contains(corner)
vertex_list.add(corner)
else
vertex_list.remove(corner)
endif
endfor
endfor
BUT, it doesnt sort them correctly, If i iterate over every vertex drawing a line from it to the previous one, it generates a mess
How can i create an algorithm that generates a SORTED list of vertices to create a polygon?

You can take this approach:
Create node objects for each vertex (corner). Each node will have (unique) x, y coordinates, and four references to neighbors: up, right, down, left. Each of those either references another node (pointer), or is null (when there is no edge in that direction). If for instance you have two adjacent cells, this step will create 6 nodes (not 8, because 2 vertices are shared by these cells and only one node should be created for each unique vertex). You would create a hashtable (dictionary/map) for these nodes, keyed by their x, y coordinates, so to avoid creating multiple nodes for the same vertex.
Find the north most node. This is the starting node. Name this also the current node.
Set the current direction to "right"
While the current node has a neighbor in the current direction, do:
Make that neighbor the current node
Add the (now) current node to the solution
Change the direction in counter-clockwise rotation, so that if it was right, make it up. If it was up, make it left, ...etc.
If the current node is the starting node, end the algorithm
As the current node has now no neighbor in the current direction, change the current direction in clockwise rotation, so that if it was right, make it down. If it was down, make it left, ...etc.
Repeat from step 4.
This assumes that all cells are connected, and the formed shape has no holes that are completely surrounded.

Related

Find unique loops in undirected graphs

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.

Algorithm for creating a polygon from a group of adjacent triangles

Suppose you have a set of triangles, like the one shown in the image below, where black is a triangle edge, red is a triangle point, green is the polygon that needs to be found, and blue is the polygon's points.
The polygon described may or may not be concave. The triangles in it will always be adjacent (share all three points with the other triangles in the set).
What sort of algorithms exist to generate the polygon that such a set of triangles describes? The polygon should be in the form of a list of points in clockwise or counter-clockwise order.
How About Following A simple GrahamScan Algo... That's should Do the Trick.
Assume you have N distinct points Pi and M triangles. We define each triangle by 3 indices i, j and k to the points. Each triangle will have 3 edges defined as E(i,j), E(j,k) and E(i,k). The way to find the "polygon" is as follows:
1) Loop thru all triangles. For each triangle, add the 3 edges into a set. Edges with two identical point indices should be considered as the same edge. Namely, E(i,j) = E(j,i). Once encounter such case, remove both E(i,j) and E(j,i) from the set as these are the interior edges.
2) The remaining edges in the set should be the edges forming the polygon.
3) Sort the edges in the set by the point indices as follows:
(3a) Pick any edge from the set, say E(i,j).
(3b) Add indices i and j into a std::vector, then remove E(i,j) from the set.
(3c) Find the edge from the set that shares the last point index in the std::vector (which is j now). Denote this edge as E(j,k). Add index k into the std::vector and remove E(j,k) from the set.
(3d) Repeat step (3c) until the set contains no edges. The point indices in the std::vector will be the points order for the polygon.
If you only have M triangles and 3*M (x, y) values for the triangle vertices, then you will need to do some pre-processing to remove identical points and re-define the triangles in terms of the point indices as stated above.

I need a way to construct a 2D-polygon with holes

My object is constructed in a honeycomb grid. All objects are connected. The red lines represents the connection between each node. I heard Binary Space Partitioning (BSP) Trees is good with this type of problem, but not sure what is front and back in my case.
I've implemented the lookup using the honeycomb grid system as shown (x , y)
class Node {
Point position; //center position
Point grid; //honeycomb grid system
}
class MyObject {
Node lookup(Point grid);
}
I need a data structure that represent the graph as user add more nodes onto the scene and a way to quickly determine if a grid point is (against MyObject):
1. outside
2. inside
3. inside a hole
How big is the space you're working in?
Simulate the whole thing with a simple rectangular grid assuming even-rows are staggered right.
Any node has coordinates [x,y]
For (y%2 == 0) neighbor nodes are [x-1,y][x+1,y][x,y+1][x,y-1][x-1,y-1][x-1,y+1]
For (y%2 == 1) neighbor nodes are [x-1,y][x+1,y][x,y+1][x,y-1][x+1,y-1][x+1,y+1]
Each node can be full or empty and empty nodes can be checked or not checked. Originally all empty nodes are not checked.
Check if a node belongs to a hole by:
if node is full - it does not belong to hole, it belongs to the shape.
if a node is empty mark node as checked.
Iterate over all neighbor nodes:
Skip nodes marked as checked or full
recursively repeat the search for all nodes not checked.
If the recursion brings you into any x<0, y<0, x>MAX_X, y>MAX_Y, abort. The node is outside the shape
If the recursion ends without finding edges of the playfield, the node belongs to a hole.
Additionally, you may now repeat the procedure turning all checked nodes into outside or hole for later reference.
If you want to index all holes at start, it may be easier to find all not checked empty nodes at borders of the playfield (x==0, y==0, x==MAX_X, y==MAX_Y) and use the above algorithm to mark them as outside. All remaining empty nodes are holes.
Depending on your grid size, you may implement it as 2D array of structs/objects containing object state (or even chars, with status as bits of the number), sized [MAX_X+1][MAX_Y+1] if it's reasonably sized, or as a list (vector) of full nodes, each containing its coords, status and if you want this to be more speed-optimal, neighbors. In this case, search the shape, finding all empty neighbor nodes for potential holes. Edge nodes with extreme coords (lowest/highest x/y) belong to "outside". Follow their empty neighbors that have full neighbors, to find the outer edge of the shape. All remaining are inner edges and after following the algorithm starting with them you'll have all your "holes".
My suggestion:
Assign each tile a center position in a 2d cartesian space.
Build a binary search tree (BST) containing all center positions.
For a query point find the relative position to the nearest occupied tile using that BST.
Determine whether that position is inside or outside the tile using some geometric formula, e.g., as in here:
Is a point inside regular hexagon
Alternatively, work with an approximation using squares, e.g., as seen here:
Hexagonal Grids, how do you find which hexagon a point is in?

marching cubes efficiency- you can reduce 3/4rs of the edge calculations?

Normal marching cubes finds 12 edges per cube, but you can do 3 edges per cube, save the edges inside an array, and then go through the cubes again, referencing the edges from the cubes adjacent rather than calculating them.
The process to reference adjacent cubes isn't clearly discussed on the Internet so anyone using marching cubes would be welcome to help find the details of the solution. do you know an implementation already?
here is a picture showing the 3 edges in yellow that you need for each cube, instead of 12.
EDIT- I just found this solution, although it's just a part of it:
Imagine 3 edges coming from the corner of the cube with lowerest coordinates. Then all other edges just belong to other cubes. If our cube has coordinates (x,y,z), the neiboring cubes have coordinates (x+1,y,z), (x,y+1,z), (x,y,z+1), (x+1,y+1,z), (x+1,y,z+1), (x,y+1,z+1). You can imagine the edge as a vector. Then the corner of the cube have edges (1,0,0), (0,1,0), (0,0,1). The cube with coordinates (x+1,y,z) have edges (0,1,0) and (0,0,1) that belong to our cube. The cube (x+1,y+1,z) has only one edge (0,0,1) that belongs to our cube. So if you store 4 elements for the cube you can access them like that:
edge1 = cube[x][y][z][0];
edge2 = cube[x][y][z][1];
edge3 = cube[x][y][z][2];
edge4 = cube[x+1][y][z][1];
edge5 = cube[x+1][y][z][2];
edge6 = cube[x][y+1][z][0];
edge7 = cube[x][y+1][z][2];
edge8 = cube[x][y][z+1][0];
edge9 = cube[x][y][z+1][1];
edge10 = cube[x+1][y+1][z][2];
edge11 = cube[x+1][y][z+1][1];
edge12 = cube[x][y+1][z+1][0];
Now which points edge7 connect? The answer is (x,y+1,z) and (x,y+1,z)+(0,0,1)=(x,y+1,z+1).
Now which cubes edge7 connect? It is more harder. We see that coordinate z is changes along the edge this means that neibour cube has the same z coordinate. Now all others coordinates change. Where we have +1, the cube has large coordinate. Where we have +0, the cube has smaller coordinates. So the edge connects cubes (x,y,z) and (x-1,y+1,z). Other 2 cubes that has the same edge are (x,y+1,z) and (x-1,y,z).
-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=--=-=
EDIT2-
So I am doing this, and it isn't so simple. I have a loop which simultaneously calculate 8 points, 12 edges, the interpolation of edges, the bit values and a vertex the values for the edges, all in one loop.
so I am doing a new loop previous to it to calculate as much as possible and place it in arrays to used in the complicated loop.
I can recycle the interpolated values of the intersection points along edges, in an array, although I will have to recalculate all the points again in the complicated loop, because the values of the points I used to decide bit numbers that reference values in the vertex table. That confuses me! I thought that once I have the edge intersection values, I could use those directly to get the triangle tables, without having to calculate the points all over again!
in fact no.
anyway, here is another bit of information with someone that already did it, if only it was readable!
http://www.new-npac.org/projects/sv2all/sv2/vtk/patented/vtkImageMarchingCubes.cxx
scroll to this line: Cubes are responsible for edges on their min faces.
A simple way to reduce edge calculations in the way you are suggesting is to compute cubes one axis aligned plane at a time.
If you kept all of the cubes, with their edges, in memory, it would be easy to compute each edge only once and to find adjacent edges by indexing. However, you usually don't want to keep all the cubes in memory at once because of the space requirements.
A solution to this is to compute one plane of cubes at a time. i.e. an axis aligned cross-section, starting from one side and progressing to the opposite side. You then only need to keep at most two full planes of cubes in memory at a time. As you move through each plane you can reference shared edges in the previous plane and previously computed cubes in the current plane. As you move to the next plane you can deallocate the plane you will no longer need.
Edit: This article discusses doing just what I suggest:
http://alphanew.net/index.php?section=articles&site=marchoptim&lang=eng
Funny, because when I implemented my own MCs I came up with similar solution.
When you start working with MCs you treat them as a distinct cubes but if you want to go for high performance you'll need to create entire mesh as a whole, and creating vertex indices etc. is not so easy here. It gets even more interesting when you want to add smooth per-vertex normals :).
To solve this I created a simple index cache mechanism to store vertex indices for each edge.
Then, for each computed edge I have cube position x,y,z and edge index and I do as follows:
For each axis:
if the edge is on '+' side of axis:
replace edge index with its '-' side sibling
increment cube position along axis
This simple operation gives me the correct cube position, and edge index of 0,1,2. Then I compute a total cache index from x,y,z,edgeIndex values with simple bit rotations.
When I have cache index I check if it's bigger than -1. If it is then there was an already computed vertex at this edge and I can reuse it. If it's -1 I need to create a new vertex and store its index in the cache. This way you'll compute each vertex only once, and you can even add a normal value shared between every triangle containing your vertex.
Yes, I think I do it similar to kolenda. I have a struct with 5 ints: (cube)index and 4 vertexindices (A, B, C, D).
for the most inner loop (x), I have just lastXCache and nextXCache. On the 4 edges pointing in the -x direction, i ask if lastXCache.A != -1 and if so, assign the previously calculated value, etc.
In the +x direction I store calculated vertices in nextXCache. when cube is done: lastXCache = nextXCache;
For y and z direction it needs to be a list (unity term for mutable array), next y is next row (so sizex) and next z is the next plane (so sizex * sizey)
only diadvantage is that this way it has to run cube after cube, so serially. But you can calculate different chunks in parallel.
Another way I thought of that could be more parallel would need 2 passes: 1. calculate 3 edges every cube, when 1 is done -> 2. draw the triangles.
Don't really know what is better, but the way it actually works seems to be fast enough. even better with unity jobs. Create one IJob for 1 chunk/mesh.

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