Related
What algorithms are used to find gaps between adjacent polygons (example pictures show 2 adjacent polygons and a shaded 'gap' between them), and is there a common name for this type of operation? Polygons in my input may have coincident vertices, segments, both, or neither. Polygons are represented as ordered lists of points. Adjacent polygons are defined as having at least one coincident point or segment.
I am developing in Go (and have access to the GEOS library), but any references to algorithm steps or implementations in common languages would be helpful.
This might not be what you were looking for, but something like this might get the job done.
Suppose you can calculate a list of all points of intersection p1, p2, …, pk between the perimeters of the two polygons. Let v1, v2, …, vn be the vertices of the first polygon, and w1, w2, …, wm be the vertices of the second polygon.
First, create two ordered collections c1 and c2, where c1 contains p1, p2, …, pk and v1, v2, …, vn, in order (so that if going around the perimeter of the polygon in the clockwise direction, the vertices appear in the list in the order visited), and c2 contains p1, p2, … pk and w1, v2, …, vm ordered in the same way.
Now, between every two adjacent p(i%k) and p((i+1)%k) there is some overlap or gap. This overlap or gap may be degenerate iff the vertices appearing in c1 and c2 between these two points of intersection are the same; in this case, the polygon traced out has area zero and may be discarded. Otherwise, we must see whether the vertices in c1 and c2 appearing between the points of intersection define a gap or an overlap.
If we have an easy/cheap way of testing whether a point is contained within the original polygon, simply choose a point in the space (e.g., the center of the triangle formed by one of the points of intersection and each of the adjacent points in c1 and c2 is guaranteed to be inside the space) and see whether the point is included in either c1 or c2 (it cannot be in one and not the other; why?). If the point is included, then you have an overlap; otherwise, you have a gap.
Indeed, we do have an easy way. If we are going around the first polygon in clockwise order, then if the point identified above (the middle of the triangle so described) is to the right of the line segment formed by the point of intersection and the vertex in c1 adjacent to it, then it's an overlap; otherwise, it's a gap. Alternatively, you can go clockwise around the points in c2 and use the same rule to tell.
To see whether a point is to the left or right of a vector:
take the vector (e.g., the point of intersection to the adjacent point in either c1 or c2)
take the vector to the candidate point (e.g., the center of the triangle described earlier)
Compute the 3-dimensional cross product
The sign of the z-coordinate of the resulting vector gives the answer.
In this example:
p1, p2, p3 ~ (3.1, 5.5), (3.3, 4), (3.8, 2)
v1, v2, v3, v4, v5 ~ (1, 0), (1, 8), (4, 4.5), (2, 3), (3.8, 2)
w1, w2, w3, w4 ~ (4, 1), (3, 5), (4, 9), (9, 5)
c1 ~ (v1, v2, p1, v3, p2, v4, p3=v5)
c2 ~ (w1, p3, p2, w2, p1, w3, w4)
pairs of points of intersection adjacent in c1:
x1 = (p1, p2), x2 = (p2, p3), x3 = (p3, p1)
pairs of points of intersection adjacent in c2:
y1 = (p3, p2), y2 = (p2, p1), y3 = (p1, p3)
triangle for x1 has vertices (p1, v3, w2), middle is
~ ((3.1+4+3)/3, (5.5+4.5+5)/3) = (3.3, 5)
vector from p1 to v3 ~ (0.9, -1)
vector from p1 to middle of triangle ~ (0.2, -0.5)
cross product of p1-v3 x middle of triangle vector:
+0.9 -1.0 +0.0
+0.2 -0.5 +0.0
i j k
=> -0.45k
this has a negative sign, so this is an overlap
triangle for x2 has vertices (p2, v4, p3=v5), middle is
~ ((3.3+2+3.8)/3, (4+3+2)/3) = (3, 3)
vector from p2 to v4: (-1.3, -1)
vector from p2 to middle of triangle: (-0.3, -1)
cross product of p2-v4 and middle of triangle vector:
-1.3 -1.0 +0.0
-0.3 -1.0 +0.0
i j k
=> 1.3k
this has a positive sign, so this must be a gap
I am having trouble forming an algorithm to determine if 12 vertices that was inputted by a user in any order, will form a cross shape in a 2D plane.
From the way I looked at it, it can be two rectangle intersecting.
Should I choose to brute force it by comparing the distances,
I will end up having 67 distances from the 12 vertices, which to compare all of them would not be feasible.
Is there any characteristic of a cross or shape that I could use?
What you want is a cross shape define by two intersecting rectilinear rectangles with protrusions greater than zero on all four sides. I believe the following algorithm will fully determine that for you.
Insure that none of the 12 points is identical.
There should only be 4 distinct X values among the 12 points. Put them in ascending order into an array that we’ll call your X-vector.
Do the same with Y values creating a Y-vector with 4 distinct values.
Make a 4x4 array, initializing all cells to zero.
Go through each of the 12 values using their X and Y values along with the X-vector and Y-vector to select a cell in the 4x4 array to increment. Thus if you had a point (12,9) and 12 was at the [0] entry of the X-vector and 9 was in the [2]entry of the Y-vector, you would increment the [0,2] cell of the 4x4 array.
Now your 4x4 Array should look exactly like this:
0, 1, 1, 0
1, 1, 1, 1
1, 1, 1, 1
0, 1, 1, 0
If so, then it is a cross as you have defined it. And if not, or if it fails at any previous step, the it is not a cross.
Something like the following should work:
collect the points in a set or list
iterate the points and find the distinct X and Y coordinates; there should be exactly four different values for X and Y, respectively; if there are more or fewer, it's not a cross-shape
sort the distinct X and Y coordinates and call them x1 through x4 and y1 through y4
check whether the original list of points contains exactly the points (x1, y2), (x1, y3), (x2, y1), (x2, y2), (x2, y3), (x2, y4), (x3, y1), (x3, y2), (x3, y3), (x3, y4), (x4, y2), and (x4, y3), in any order
if there are other properties to be met, e.g. the four arms having same lengths, check those, too, using the identified distinct X and Y values
Given a bounding box bbox1, I want to randomly generate a new bounding box bbox2, which overlaps bbox1 by at least 0.5.
The overlap ratio is defined as the area of intersection between bbox1 and bbox2, divided by the area of the union of the two.
The naive way I can think of is to randomly generate bounding boxes until I find one that satisfies the condition. But obviously, it will waste some time in generating and evaluating unsatisfied candidates.
If the bounding box is encoded by the upper left corner and the width and height bbox1 = (x1, y1, w1, h1), the pseudocode below shows how I generate the new bounding box.
do
x2 = random(x1 - w1, x1 + w1/2)
y2 = random(y1 - h1, y1 + h1/2)
w2 = random(0, 2 * w1)
h2 = random(0, 2 * w1 * h1 / w2)
bbox2 = (x2, y2, w2, h2)
while bboxOverlapRatio(bbox1, bbox2) < 0.5
Any better solutions? For example, can I further narrow down the random range?
One way to further narrow down the random range is to only generate new bounding boxes bbox2 with the center inside bbox1.
If the center of bbox2 is outside of bbox1 then it is impossible to have an overlap of at least 0.5 (note that this is a separate, interesting mathematical problem in itself).
This additional constraint can be expressed as x1 < x2 + w2/2 < x1 + w1 (with a similar relation for the vertical axis), and can be used to narrow the range for w2 and h2:
do
x2 = random(x1 - w1, x1 + w1/2)
y2 = random(y1 - h1, y1 + h1/2)
w2 = random(max(0, 2 * (x1 - x2)), min(2 * w1, 2 * (x1 + w1 - x2)))
h2 = random(max(0, 2 * (y1 - y2)), min(2 * w1 * h1 / w2, 2 * (y1 + h1 - y2)))
bbox2 = (x2, y2, w2, h2)
while bboxOverlapRatio(bbox1, bbox2) < 0.5
Lets take the case of equal size boxes:
There are four cases:
one where you start from the left at x1-w1/2, y1
one from the top x1, y1-h1/2
on from upper left to move in diagonal x1-c, y1-c
one from the lower left same diagonal up x1-c, y1+h1+c
where c is a number you can find that gives at least 1/2 overlap in the diagonal position (for a square (w-c)*(w-c)>=w^2/2 you solve this quadratic equation and find c).
The search space is limited within these areas:
so you do:
choice=random from 1 to 4
if choice==1: xnew=x1-w1/2+random from 0 to 2*w1; ynew=y1
if choice==2: xnew=x1; ynew=y1-h1/2+random from 0 to 2*h1
if choice==3: xnew=x1-c+random from 0 to w1+2*c; ynew=y1-c+random from 0 to h1+2*c
if choice==4: xnew=x1-c+random from 0 to w1+2*c; ynew=y1+h1+c+random from 0 to -(h1+2*c)
Its not a completely random selection since you dont have the seach space up front and then choose some point in it but effectively it covers the whole space randomly.
This cover the four main routes; but leaves the corner cases/spaces uncovered. You effectively have a circle search space: if you move your starting point up you have to move it right also to guarantee 1/2 overlap. That is a circle of radius w1 (if w1=h1) centered on the center of the initial rectangle. If you start on any point on the circle you are guaranteed to have 1/2 coverage. You can pick your point anywhere within the circle.
If the rectangles are not squares but general rectangles you have an ellipse as the search space.
--
Then lets go the the different size scenario:
within your loop you pick the size at random and perform the above search.
The calculations where you start from and how far you will go change but can be done.
[Correction: the starting points cannot be on the entire circle but certain part of the circle on the left side - symmetrical on the right side]
I'm implementing simple navigation, and I need to compute approximate location (GPS) on my route. Route is a list of points, so basically it looks like this:
(latX, longX)
(lat1, long1) o------o---------------o (lat2, long2)
|
|
o
(lat3, long3) - GPS My location
I have a two points (lat1, long1) and (lat2, long2) and my location (lat3, long3). How can I compute (latX, longX)?
Let me try to give you a sketch of how I would divide the problem into smaller steps.
Consider the Earth as a perfect 3D sphere of radius r.
Transform positions given by (lat, long) pairs into 3D points (x, y, z) on the surface of the sphere, i.e., with x^2 + y^2 + z^2 = r^2. You will also need the inverse transformation to get back to (lat, long) coordinates.
Lets put (using 2 above)
P1 := (x1, y1, z1) <-> (lat1, long1)
P2 := (x2, y2, z2) <-> (lat2, long2)
P3 := (x3, y3, z3) <-> (lat3, long3)
P := (x, y, z) <-> (latX, longX)
Let H be the plane containing the origin (at the center of the Earth) and the points P1 and P2. Note that H intersects the surface of the sphere in the path that joins P1 with P2 as in your illustration.
Let (a, b, c) perpendicular to H. You can find it by solving the matrix equation Mv = 0, where M is the matrix whose rows are (x1, y1, z1) and (x2, y2, z2) and v is the unknown column with coordinates (a, b, c).
Let Q = (x3, y3, z3) + u*(a, b, c), where u is the coefficient for which Q = (q1, q2, q3) lines in H. You can calculate u by solving the matrix equation Mv = P3, where M is the 3x3 matrix with columns (x1, y1, z1), (x2, y2, z2) and (-a, -b, -c), v is the unknown column (s, t, u) and P3 stands for the column (x3, y3, z3).
Let P = w*Q, where w is the coefficient for which P = (x, y, z) with x^2 + y^2 + z^2 = r^2.
Use the inverse of the transformation mentioned in step 2 above to compute (latX, longX) <-> (x, y, z).
Given a cartesian plane and rectangle on this plane where bottom-left corner has coordinates (x1, y1), the top-right one has coordinates (x2, y2).
Now I need to find the count of those rectangles that have the common area with the rectangle with a bottom-left corner coordinates (x1, y1) and a top-right corner coordinates (x2, y2).
How this can be done in an efficient way?
Their can be many such queries of the form x1 y1 x2 y2 and for given rectangle i need to find count of overlapping rectangles.Also even if the two rectangles only share a common point, they are still regarded as sharing common area.There can be a few same rectangles on the plane, they should be regarded as a few different rectangles.
The main point is rectangles can be added and deleted at any given instant.
Constraints :
Their can be total of 10^5 queries.And each coordinate can go from 1 to 10^9.
My approach : We know that Suppose we have two rectangles R1 and R2. Let (x1, y1) be the location of the bottom-left corner of R1 and (x2, y2) be the location of its top-right corner. Similarly, let (x3, y3) and (x4, y4) be the respective corner locations for R2. The intersection of R1 and R2 will be a rectangle R3 whose bottom-left corner is at (max(x1, x3), max(y1, y3)) and top-right corner at (min(x2, x4), min(y2, y4)).
If max(x1, x3) > min(x2, x4) or max(y1, y3) > min(y2, y4) then R3 does not exist, ie R1 and R2 do not intersect.
Now main problem with me that ma facing is say we have insert query of say (I X1 Y1 X2 Y2) and delete query of type(D index) which will delete rectangle inserted at index th query of insertion.How to handle them efficiently
An R-tree should work. See http://en.wikipedia.org/wiki/R-tree for more.
I wrote a solution in C# for a similar problem
https://github.com/ERufian/Overlap/blob/master/RectangleOverlap/Heap.cs
With minor modifications it would do what you need:
namespace RectangleOperations
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
public static class Heaped
{
public static int GetOverlap(double x1, double y1, double x2, double y2, Rect[] rects, int rectCount)
{
Rect startingArea = new Rect(new Point(x1, y1), new Point(x2, y2));
return Overlap(startingArea, 0, 0, rects, rectCount)
}
private static int Overlap(Rect currentArea, int currentIndex, int currentCount, Rect[] rects, int rectCount)
{
List<int> counts = new List<int>();
for (int i = currentIndex; rectCount > i; i++)
{
Rect newArea = currentArea;
newArea.Intersect(rects[i]);
// include point and edge (size 0) overlaps
if (0 <= newArea.Size.Height && 0 <= newArea.Size.Width)
{
counts.Add(Overlap(newArea, i + 1, currentCount + 1));
}
}
return (0 == counts.Count) ? currentCount : counts.Max();
}
}
}
Some help for translating this code if not using C#
Rect.Intersect calculates the intersection of the current rectangle with another rectangle and replaces the current rectangle.
List<> is a dynamic array (that grows as you add items), you can use regular arrays but then you'll need to calculate sizes, keep track of how many items were actually added and provide a way to calculate the Max.