I have two arbitrary polygons that may or may not be the same shape, I'm looking for a advice on a simple algorithm that will rotate one of the polygons to minimize the difference between the two. Thanks.
If you are trying to make them more similar, you could try to minimize the area of the difference between the two polygons. That is, the area of the union of the two, minus, the area of the intersection between them.
An approximation would be to find the two points with maximum distance in each polygon (lets call them 'diameters'), and align those for the two polygons.
For example:
Polygon A = [(13, 12); (9, 14); (1,4); (5, 2)] (a rhombus)
Diameter = [(13, 12); (1,4)] (length 14.4)
Polygon B = [(14, 11); (8, 17); (3,24); (9, 18)] (another rhombus)
Diameter = [(14, 11); (3,24)] (length 17.0)
Polygon B shifted and rotated so diameters align:
[(14.08465297, 12.72310198); (7.439737081, 7.446257009);
(-0.084652970, 3.276898021); (6.560262919, 8.553742991)]
Related
I need to compute the No-Fit Polygon (NFP) of two polygons, A and B, for nesting purposes. The NFP of A and B can be defined as NFP(A,B) = A (+) -B, where (+) is the Minkowski sum. I'm using C++ and CGAL library, which provides functions to compute Minkowski sums. Well, after this small context description, let me introduce my problem. There are some well-known benchmark instances of the 2-D irregular nesting problems, and I intend to use them in my research. In the instance called jakobs2, there are some pairs of polygons that fit exactly together, as it is the case of those showed in the figure:
Exact fit case in jakobs2 instance
I've created those polygons in C++ with this code:
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/minkowski_sum_2.h>
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
typedef CGAL::Point_2<Kernel> Point_2;
typedef CGAL::Polygon_2<Kernel, std::vector<Point_2>> Polygon_2;
typedef CGAL::Polygon_with_holes_2<Kernel, std::vector<Point_2>> Polygon_with_holes_2;
(...)
Polygon_2 *A = new Polygon_2();
A->push_back(Point_2(0, 0));
A->push_back(Point_2(10, 0));
A->push_back(Point_2(10, 10));
A->push_back(Point_2(8, 10));
A->push_back(Point_2(8, 2));
A->push_back(Point_2(2, 2));
A->push_back(Point_2(2, 10));
A->push_back(Point_2(0, 10));
Polygon_2 *B = new Polygon_2();
B->push_back(Point_2(0, 0));
B->push_back(Point_2(6, 0));
B->push_back(Point_2(6, 6));
B->push_back(Point_2(4, 6));
B->push_back(Point_2(4, 2));
B->push_back(Point_2(2, 2));
B->push_back(Point_2(2, 6));
B->push_back(Point_2(0, 6));
Polygon_2 *minus_B = new Polygon_2();
minus_B->push_back(Point_2(0, 0));
minus_B->push_back(Point_2(-6, 0));
minus_B->push_back(Point_2(-6, -6));
minus_B->push_back(Point_2(-4, -6));
minus_B->push_back(Point_2(-4, -2));
minus_B->push_back(Point_2(-2, -2));
minus_B->push_back(Point_2(-2, -6));
minus_B->push_back(Point_2(0, -6));
And, to compute NFP(A,B), I used this:
Polygon_with_holes_2 nfp_A_B = CGAL::minkowski_sum_2(*A, *minus_B);
The variable nfp_A_B, computed by minkowski_sum_2, was described by these points:
(4, 10), (2, 10), (-4, 10), (-6, 10), (-6, 4), (-6, -6), (-4, -6),
(-2, -6), (0, -6), (6, -6), (10, -6), (10, 0), (10, 10)
This sequence of points forms a square. The line segment from (2, -6) to (2, 2) should be included in NFP(A,B), but it was not. I would appreciate any help provided to use CGAL::minkowski_sum_2 for NFP computation with exact fit in this case, or (better) in general case.
The output of the Minkowski sum operation is a regularized polygon (or polygon with holes). The manual of the 2D Regularized Boolean Set-Operations of CGAL contains the exact definition. In simple words, if P is a non-regularized polygon, then P* = closure(interior(P)) is regularized. It implies that the output cannot include degenerate features, such as isolated points and "antennas". (The segment that you claim is missing is sometimes referred to as an antenna.)
The feature that you were hoping to get is not available out-of-the-box. As a matter of fact, a different interface would be needed to support this feature. However, with some work, you should be able to get it. What you need to do is obtain the underlying 2D arrangement, and then traverse the arrangement to extract the degenerate polygon. You will have to dig into the code. Here is a hint to start with.
There are 3 functions that implement the 2D Minkowski sums: (i) by decomposition, (ii) by convolution, and by (iii) reduced convolution. I would start with (ii) (reduced convolution). Here, we compute the convolution cycles and insert them into a 2D arrangement. Then, we compute the winding numbers of the faces of the arrangement, to figure out which faces are part of the resulting polygon(s) and which are not. You need to intercept this arrangement, and process it yourself.
Given a coordinate and a movement vector. How can I get the list of all blocks will be infected?
I think it's a little bit like "object in view" or "object collision"?
For example, the original point O is (2, 2), the movement vector "→" is (0, 1) and the blocks B should be [(1, 3), (1, 4), (2, 4), (3, 3), (3, 4)]
0123 y→
0.......
1...BB..
2..O→B..
3...BB..
x.......
↓.......
If the movement vector is (-1, 1), the B should be [(0, 2), (0, 3), (0, 4), (1, 4), (2, 4)]
0123 y→
0..BBB..
1...↗B..
2..O.B..
3.......
x.......
↓.......
I'm currently considering
point P (x, y) vector V (v, u)
x' = x + v
y' = y + u
set S = ([x'-1, x'+1], [y'-1, y'+1])
calculate a line L "y=ax+b" perpendicular to V crossing (x', y').
split S into two groups by L
chose the one V is facing
but I cannot find a way to achieve last two steps.
Any suggestion will be helpful.
I think what you are looking for is something called time-until-impact or time-until-collision or something like that.
But in most game engines this is not the way to go. What a standard technique for collision handling is, is space partitioning. That means, if you have n rigid bodies in your simulation then a naive algorithm requires n^2 checks (each with another) to see if a collision happened. However, performance-wise this is a killer. Instead you should partition your space via (`uniform partitioning, Oct-Trees, Z-ordering, etc.), then you only check with neighboring rigid bodies that are neighbors with the cell in question.
Note, that the velocity vector (what you call movement) vector is not really needed here because in practice it brings no benefits.
I'm trying to make a "flashlight" effect in my game where the player can only see places that are in his line of sight.
I've got most of the effect done by raycasting to each vertex in the game world and added and extra raycasts +-0.0001 rad, then connecting them in clockwise order to form this shape in red. I'm trying to get the inverse of this polygon within the bounds of the rectangular level similar to the "Inverse Selection" option in programs like Photoshop (example)
Construct a set for both rectangle and polygon and calculate the symmetric difference (vertices in either rectangle or polygon but not in both), for example:
rectangle = [(0, 0), (13, 0), (13, 10), (0, 10)]
polygon = [(0, 5), (0, 10), (2, 6), (8, 6), (11, 0), (13, 0), (13, 10)]
# "^" is the symmetric difference operator in python
set(rectangle) ^ (set(polygon))
Returns:
set([(11, 0), (2, 6), (0, 5), (0, 0), (8, 6)])
Which corresponds to the green area (vertices A, I, E, H, J) in the following picture:
Beware that it will get the complement of the red polygon which does not include the intersection with the wall in your original image:
If you want your result to be the yellow polygon of the next figure instead:
Then you will have to do a rectangle-polygon intersection for every wall/block in the stage with the complement polygon using some method like the ones described in the following question:
Method to detect intersection between a rectangle and a polygon?
Given an array, I would like to be able to define some relationship between its elements so that each element "points to" a given number of elements, such that no element should share more than one target element with any other given element of the array.
I'm pretty sure this can be done easily with some solution from graph theory, but I embarrassingly don't know any graph theory and therefore don't know what I'm looking for. The best I can say is that the graph describing the links between elements is regular and directed.
The XY: what I actually have/want is two-dimensional grid (I don't think the dimension is relevant to the math but is very helpful with the visualization), where each cell points to around 16 (flexible on this) other cells with a minimum of duplication. The grid is a texture so it's anywhere in the 256*256 to 4096*4096 size range, which hopefully doesn't make a significant difference to the algorithm.
Once visualized as a 2D texture, there is an obvious "intuitive" solution based on image masks, but it's totally informal and relies on the implementation details (using fewer targets for the purposes of illustration):
Using a regular pattern for the pointed-to cells is inappropriate:
The next cell along will share seven targets with the origin cell (red, x). Duplication is guaranteed.
An irregular "broken circle" style arrangement intuitively seems like it should work:
If no pair of cells in the group (pointed-to and origin) have an equal difference in position to any other pair of cells in the group, then any given movement of the origin on the grid seems like it shouldn't result in more than one pointed-to cell overlapping with any of those highlighted in the original position, and none of the pointed-to (blue) cells should point back to the origin (red, x) directly (it would be nice if they didn't loop back too quickly, either).
("wrapping around" at the edges of the texture is assumed)
But this is totally informal and intuitive. I don't have any proof of this and don't know how to go about proving it. Is there an algorithm known from graph theory that can produce such a result, without wishy-washy handwaving involving image masks? Not least because the intuitive solution, even assuming it works, doesn't provide any guarantees about whether the target cells will loop back to the origin quickly or not, and whether the entire grid (or most of it, I don't mind a few unused cells) forms a single connected graph, which is absolutely essential.
Alternatively, if the "broken circle" model actually works, how would one go about formalizing this back down to an abstract algorithm operating on a sequence (I guess it's effectively just an integer sequence), rather than relying on a mask image, which is totally getting confused by implementation details? (The fact that I want to apply this to a texture should be irrelevant)
The mathematical description of what you want to do is to build a (strongly?) connected high-girth Cayley graph on the group Z/w × Z/h (where w is the width of the texture and h is the height) such that no two vertices have more than one out-neighbor in common.
Practically speaking, each vertex (i.e., pixel) points to the pixels at a fixed list of offsets. If a vertex at (0, 0) (w.l.o.g. by the vertex-transitivity of Cayley graphs) and a vertex at (x, y) have two out-neighbors in common, then there exist offsets (dx1, dy1), (dx2, dy2), (dx3, dy3), (dx4, dy4) such that (dx1, dy1) = (x + dx2, y + dy2) and (dx3, dy3) = (x + dx4, y + dy4), and (dx1, dy1) ≠ (dx3, dy3) (equivalently, (dx2, dy2) ≠ (dx4, dy4)). This condition can be verified programmatically, and for random sets of offsets within a close distance, it doesn't take long to find a suitable set. Here's some Python to generate and test them.
from random import randrange
# random pattern of offsets within the square [-k, k] x [-k, k]
def pattern(k, n):
return [(randrange(-k, k + 1), randrange(-k, k + 1)) for i in range(n)]
def valid(pat):
s = set()
for (x1, y1) in pat:
for (x2, y2) in pat:
if ((x1, y1) != (x2, y2)):
(dx, dy) = (x2 - x1, y2 - y1)
if (dx, dy) in s:
return False
s.add((dx, dy))
return True
if __name__ == '__main__':
while True:
pat = pattern(10, 16)
if valid(pat):
break
print(pat)
This code does not verify strong connectivity. I would conjecture that strong connectivity is very likely to be satisfied by random offset sets. You might want to write more code to check for short cycles, which can be found by breadth-first search.
The code above gives a list of offsets like
[(3, -4), (-8, -9), (2, 7), (-9, 3), (-4, 7), (-2, -7), (-6, 3), (-7, -2), (9, -10), (8, -2), (-6, -3), (2, -8), (-6, 6), (-9, -7), (-7, 10), (3, 10)]
(no idea if that one's any good). To figure out which vertices (x, y) points to, iterate (dx, dy) through the list above and yield the neighbor ((x + dx) & (w - 1), (y + dy) & (h - 1)), assuming that w and h are powers of two and that we're two's complement.
If you were given a set of pairs of lines, how would you find the amount of area which is contained by all pairs of lines (if it exists)? For example, if I had the pairs of lines:
((0, 0), (0, 10)) & ((10, 0), (10, 10))
and
((0, 0), (10, 0)) & ((0, 10), (10, 10))
how would you go about finding the area enclosed by all those lines (which in this simple case would be a square defined by points (0,0),(10,0),(10,10) & (0,10).
What algorithms might point me in the direction of solving such a problem?
EDIT: The lines won't always touch at the ends or intersect with each other. If there exists a pair of lines which doesn't intersect any of the other lines and doesn't touch at the edges, then it can be concluded that that set of pairs of lines does not have an area enclosed by all of them.
EDIT2:Take the following sets of lines:
pair 1: ((0, 0), (10, 0)) & ((0, 10), (10, 10))
pair 2: ((0, 0), (0, 10)) & ((10, 0), (10, 10))
pair 3: ((2, 0), (2, 10)) & ((8, 0),(8, 10))
The enclosed area by those three pairs of lines is the area defined by points (2,0),(2,10),(8,10) and (8,0). The convex hull algorithm however would return the values (0,0),(10,0),(10,10) and (0,10).
EDIT: it appears the convex hull is not the solution.
Just to make sure I understand your problem: is that the red area in this picture that you want?
Find all points of intersection which stay within the line segment for all pairs of lines. If no of points are less than 4 then no enclosed shape found.
If 4 points found then clip the lines with those points.Use flood fill to get the area of figure enclosed in the points.