How to get vertexes of polyline from a list of its points? - algorithm

I have a list of points (pixels) QList<QPoint> that represent a curve looking like a orthogonal polyline.
My task is to split this one to small straight lines (an instance of QList<QLineF>). In order to know the end of a previous subline and beginning of a next subline, I got to know which points are vertexes of polyline, that is, the points where sublines are intersected.
What would be the best way to figure out that some point is a vertex?

I've found the answer by myself. It doesn't seem to be convenient and clear, nevertheless it works out.
QList<QPoint> vertexes;
for (int i = 2; i < points.size(); i++)
{
bool xChanged = points[i-2].x() != points[i].x();
bool yChanged = points[i-2].y() != points[i].y();
if (xChanged && yChanged)
vertexes.append(points[i-1]);
}
vertexes.prepend(points.first());
vertexes.append(points.last());
We check two points every loop iteration - the current point and the point two points ago. If their X and Y aren't equal, it means that curve change its direction and the point between them is a vertex.

Related

Cover a polygonal line using the least given rectangles while keeping her continuity

Given a list of points forming a polygonal line, and both height and width of a rectangle, how can I find the number and positions of all rectangles needed to cover all the points?
The rectangles should be rotated and may overlap, but must follow the path of the polyline (A rectangle may contain multiple segments of the line, but each rectangle must contain a segment that is contiguous with the previous one.)
Do the intersections on the smallest side of the rectangle, when it is possible, would be much appreciated.
All the solutions I found so far were not clean, here is the result I get:
You should see that it gives a good render in near-flat cases, but overlaps too much in big curbs. One rectangle could clearly be removed if the previous were offset.
Actually, I put a rectangle centered at width/2 along the line and rotate it using convex hull and modified rotating calipers algorithms, and reiterate starting at the intersection point of the previous rectangle and the line.
You may observe that I took inspiration from the minimum oriented rectangle bounding box algorithm, for the orientation, but it doesn't include the cutting aspect, nor the fixed size.
Thanks for your help!
I modified k-means to solve this. It's not fast, it's not optimal, it's not guaranteed, but (IMHO) it's a good start.
There are two important modifications:
1- The distance measure
I used a Chebyshev-distance-inspired measure to see how far points are from each rectangle. To find distance from points to each rectangle, first I transformed all points to a new coordinate system, shifted to center of rectangle and rotated to its direction:
Then I used these transformed points to calculate distance:
d = max(2*abs(X)/w, 2*abs(Y)/h);
It will give equal values for all points that have same distance from each side of rectangle. The result will be less than 1.0 for points that lie inside rectangle. Now we can classify points to their closest rectangle.
2- Strategy for updating cluster centers
Each cluster center is a combination of C, center of rectangle, and a, its rotation angle. At each iteration, new set of points are assigned to a cluster. Here we have to find C and a so that rectangle covers maximum possible number of points. I don’t now if there is an analytical solution for that, but I used a statistical approach. I updated the C using weighted average of points, and used direction of first principal component of points to update a. I used results of proposed distance, powered by 500, as weight of each point in weighted average. It moves rectangle towards points that are located outside of it.
How to Find K
Initiate it with 1 and increase it till all distances from points to their corresponding rectangles become less than 1.0, meaning all points are inside a rectangle.
The results
Iterations 0, 10, 20, 30, 40, and 50 of updating cluster centers (rectangles):
Solution for test case 1:
Trying Ks: 2, 4, 6, 8, 10, and 12 for complete coverage:
Solution for test case 2:
P.M: I used parts of Chalous Road as data. It was fun downloading it from Google Maps. The I used technique described here to sample a set of equally spaced points.
It’s a little late and you’ve probably figured this out. But, I was free today and worked on the constraint reflected in your last edit (continuity of segments). As I said before in the comments, I suggest using a greedy algorithm. It’s composed of two parts:
A search algorithm that looks for furthermost point from an initial point (I used binary search algorithm), so that all points between them lie inside a rectangle of given w and h.
A repeated loop that finds best rectangle at each step and advances the initial point.
The pseudo code of them are like these respectively:
function getBestMBR( P, iFirst, w, h )
nP = length(P);
iStart = iFirst;
iEnd = nP;
while iStart <= iEnd
m = floor((iStart + iEnd) / 2);
MBR = getMBR(P[iFirst->m]);
if (MBR.w < w) & (MBR.h < h) {*}
iStart = m + 1;
iLast = m;
bestMBR = MBR;
else
iEnd = m - 1;
end
end
return bestMBR, iLast;
end
function getRectList( P, w, h )
nP = length(P);
rects = [];
iFirst = 1;
iLast = iFirst;
while iLast < nP
[bestMBR, iLast] = getBestMBR(P, iFirst, w, h);
rects.add(bestMBR.x, bestMBR.y, bestMBR.a];
iFirst = iLast;
end
return rects;
Solution for test case 1:
Solution for test case 2:
Just keep in mind that it’s not meant to find the optimal solution, but finds a sub-optimal one in a reasonable time. It’s greedy after all.
Another point is that you can improve this a little in order to decrease number of rectangles. As you can see in the line marked with (*), I kept resulting rectangle in direction of MBR (Minimum Bounding Rectangle), even though you can cover larger MBRs with rectangles of same w and h if you rotate the rectangle. (1) (2)

Should point on the edge of polygon be inside polygon?

Recently I've faced with one little but majour problem: is point on the edge of polygon be inside polygon?
What I mean - currently I am trying to implement 2D geometry library in JS for custom needs and there is method, lets say polygon.contains(point).
So my question is - when point is situated on one of the polygon's edges - as result the point is inside or outside of the polygon? Additional question for vertices: if point is right on top of polygon's vertex - is it inside or outside?
Algo that I've used is taken from here and looks like:
int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy)
{
int i, j, c = 0;
for (i = 0, j = nvert-1; i < nvert; j = i++) {
if ( ((verty[i]>testy) != (verty[j]>testy)) &&
(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j] - verty[i]) + vertx[i]) )
c = !c;
}
return c;
}
Also, there is a quote from the site:
PNPOLY partitions the plane into points inside the polygon and points outside the polygon. Points that are on the boundary are classified as either inside or outside.
And it is total true, in some situations it returns TRUE, and in some FALSE.
Actually, this is not what I'm needed. So my question is beginning to expand - which behaviour is correct when point is on the edge of polygon - is it inside or outside. And do you have a better algo with predictable behaviour?
UPDATE:
Okay, I'm found another algo, which is called "winding number" and to test this I'm using only polygons and points with integer values:
function isLeft(p0, p1, p2){
return ( Math.round((p1.x - p0.x) * (p2.y - p0.y)) - Math.round((p2.x - p0.x) * (p1.y - p0.y)) );
}
function polygonContainsPoint(polygon, point){
var i, j, pointi, pointj;
var count = 0;
var vertices = polygon.vertices;
var length = vertices.length;
for (i = 0; i < length; i++){
j = (i + 1) % length;
pointi = vertices[i];
pointj = vertices[j];
if (pointi.y > point.y){
if (pointj.y <= point.y && (isLeft(pointi, pointj, point) < 0)){
--count;
}
} else if (pointj.y > point.y && (isLeft(pointi, pointj, point) > 0)){
++count;
}
}
return 0 !== count;
}
As you can see there is no division; multiplication is wrapped into round() method, so there is no way for floating point errors. Anyway, I'm getting same result as with even-odd algo.
And I think I started to see the "pattern" in this strange behaviour: the left and top edges may tell that point is inside of polygon, but when you're tryed to put point on one of the right or bottom edges - it may return false.
This is not good for me. Maybe some of you know some algo with more predictable behaviour?
The simple answer to the question is that a point on the edge is neither inside, nor outside of polygon, it is on the boundary of the polygon - the third option. But typically it does not matter (as supported by your quotations), and what matters is to avoid the errors in classification of points, which are really deep inside or outside.
Point-in-polygon problem is sometimes called the Parity Algorithm:
Let r be the horizontal half-line whose left endpoint is the test point.
Count the number of intersections between r and the edges of the polygon. If that number is odd, then the test point lies within the polygon, and if the number is even, then it lies outside the polygon.
Here are some examples:
(a), (b) - not-degenerate cases, where half-line either does not intersect the edge or crosses it.
(c), (d), (e), (f) - four degenerate cases that have to be taken into account.
A correct answer is obtained if cases (c) and (e) are counted as one crossing and cases (d) and (f) are not counted at all. If we write the code for the above algorithm, we realize that a substantial amount of the efforts is required to cover the four degenerated cases.
With more complex algorithms and especially in 3D, the amount of efforts to support degenerate cases increases dramatically.
The above problem and explanation appear in the introduction to Simulation of Simplicity article by Herbert Edelsbrunner and Ernst Peter Mucke. And proposed solution is to get rid of all degenerations by virtual minimal perturbation of input points. After that a tested point will never be on the edge, but only inside or outside of polygon.

find all inner grid points of a polygon made up from neighbouring grid points

I have list of Points (int x, int y).
together they form areas, I check if this area is closed and then I need to get inner area formed by all positions that are inside this area.
example area:
Only idea I had is to convert this area to vector and check every point if it is inside polygon or not, counting intersections of polygon a axis's of point.
But I don't think it would be the most efficient way to do it.
other idea was to first get all points that are outside, I start from corners (if corner is not part of list of points, then is 100% empty), add all neighbor points that are empty and repeat.
then all points that aren't outside and aren't in highlighted list are inside.
but again, it feels somehow cumbersome...
To find all inner grid points of grid polygon, one can exploit these observations:
for each inner grid point (x,y) also (x,y+0.5) and (x,y-0.5) are inner points.
the lines defined by y=n+0.5 have simple intersections with the grid polygon
This leads to the following algorithm:
As a prerequisite one needs all non-horizontal (i.e. vertical and diagonal) polygon edges, actually only the x-coords of the centers in ascending order for each (second) mid-row.
The grid is scanned at each second horizontal "mid-line", i.e. y=2n+0.5, where n is from a sufficient range of integers s.t. the polygon is "covered", see the blue lines in the scetch.
Starting from the left all intersections with the polygon (i.e. the non-horizontal edges) and all inner points of the form (m,2n+0.5) are to be detected, see the red and green circles (this is done by iterating over the x-coors of the edges' centers)
Now the vertical grid neighbours (m,2n) and (m,2n+1) of inner points (m,2n+0.5) are inner points, if they are not on the boundary, see the green points in the scetch.
Here is some pseudo code (C++/python inspired :-) ):
list<Point> polygon; // given polygon as list of neighbouring grid points
// get centers of non-horizontal edges organized by line
map<int, set<float> > edgeCentersX; // for each scan line the x-coords of edges in ascending order
p_i = polygon[0]
yMin, yMax = 999999, -999999
for (i=1; i<polygon.size(); ++i)
p_i1 = polygon[i] // next point after p_i
if (p_i.x == p_i1.x)
continue // horizontal edges can be ignored
yMin_i = min(p_i.y, p_i1.y)
if (yMin_i % 2 == 1)
continue // we only need to look at each second mid-row
if (yMin_i < yMin)
yMin = yMin_i
if (yMin_i > yMax)
yMax = yMin_i
cx = 0.5*(p_i.x+p_i1.x)
edgeCentersX[yMin_i].insert(cx) // store edge center (yMin_i+0.5, cx)
p_i = p_i1
list<Point> innerPoints
for (y=yMin; y<= yMax; y+=2)
inside = false
cx_i = edgeCentersX[y][0]
for (i=1; i<edgeCentersX[y].size(); ++i)
cx_i1 = edgeCentersX[y][i]
inside = !inside
if (!inside)
continue
for (x=floor(cx_i)+1; x<cx_i1; ++x)
pLower = Point(y,x)
if (!polygon.contains(pLower))
innerPoints.append(pLower)
pUpper = Point(y+1,x)
if (!polygon.contains(pUpper))
innerPoints.append(pUpper)
Pick's theorem might be the formula you are looking for. It allows rather simple computation of the area for a polygon whose corners are grid points (i.e. have integer coordinates).

An algorithm to randomly place circles at least D distance apart

I'm trying to work out how to write an algorithm to randomly place circles of R radius, in a 2d rectangle of arbitrary dimensions, such that each placed circle is at least D distance away from other circles in the rectangle,
The rectangle doesn't need to be filled, to be more specific older circles may be destroyed, so I need to be able to place a new circle that respects the positions of the last N circles I've already placed (say 5 for eg), if it can't satisfy these conditions then I could handle it seperately.
Can anyone help me how to deduce such an algorithm, or perhaps point to some research that may cover this?
1 Place circle at random location
2 Loop over previous circles
3 if too close
4 delete new circle
5 goto 1
6 if need more circles
7 goto 1
To determine if there is room
Choose resolution required, say delta = D/100
for( x = 0; x < rectangle_size x += delta )
for( y = 0; y < rectangle_size y += delta )
unset failed
loop over circles
if x,y less than 2D from circle
set failed
break from circle loop
if not failed
return 'yes there is room'
return 'no, there is no room'
If you expect to have so many circles that there only a few holes left with room for new circles, then you could do this
clear candidates
Choose resolution required, say delta = D/100
for( x = 0; x < rectangle_size x += delta )
for( y = 0; y < rectangle_size y += delta )
unset failed
loop over circles
if x,y less than 2D from circle
set failed
break from circle loop
if not failed
add x,y to candidates
if no candidates
return 'there is no room'
randomly choose location for new circle from candidates
1. Pick random startingspot.
2. Place circle
3. Move in random direction at least D
4. Goto 2 until distance to edge is < D or the distance to another circles center is < 2D
The first algorithm to come to mind is simulated annealing. Basically, you start out with the easiest solution, probably just a grid, then you "shake the box" in random ways to see if you get better answers. First you do large shakes, then gradually make them smaller. It sounds a little chaotic, and doesn't always produce the absolute best solution, but when something is computationally intensive it usually comes pretty close in a lot shorter time.
It really depends on what you mean by "random". Assuming that you want as close to a uniform distribution as possible, you will probably have to use an iterative solution like the one ravenspoint suggested. It may be slightly faster to place all of the circles randomly and then start replacing circles that don't meet your distance condition.
If the randomness isn't that important - i.e. if it just has to "look" random (which is probably fine if you're not doing something scientific), then grid your space up and place your N circles by choosing N indices in the grid. You could make it slightly more "random" by adding some noise to the location that you place the circle inside the grid. This would work really well for sparse placement.

How to identify the boundary points of area overlapped between 2 rectangles in 2D?

I'm looking to return the coordinates of the points bounding the area of overlap between 2 arbitrary rectangles in 2D. Whats the best way to approach this that would take care of all the special cases eg:
Rectangles intersecting only on a single vertex ? (the program would have to return the lone vertex)
Rectangles which share whole or part of a side ? (the program would have to return the endpoints of the common line segment)
To add to the complexity, it has to order the points in either clockwise/anticlockwise order. As such, I can use a convex hull algorithm to order them before reporting, but if there's an algorithm that can figure out the bounding points in order directly, that'll be the best !!
Any ideas of what avenues I should be looking at ? I'm not looking for code projects etc, only a general idea of a generic algorithm for which I don't have to keep a lot of
if "special case" then "do this" kind of code.
EDIT: The rectangles are arbitrary - i.e. they may/may not be parallel to X/Y axis...
Just use the general convex polygon intersection method. Look up intersect convex polygons rotating calipers.
Alright, we'll try this again...
Consider a union of the two, made up of areas defined by drawing a line from every vertex in ABCD (in black) to EFGH (in red):
The hard part here is coming up with all of the shapes defined by these lines (both the gray lines and the original lines coming from the ABCD and EFGH rectangles.)
Once you figure that out, create a linked list of these shapes, and assume every one of these shapes exists within the intersection.
Step 1. Translate & rotate everything so that ABCD has one vertex on 0,0 and its lines are parallel/perpendicular to the x and y axes.
Step 1A. Find the lowest y-value vertex in ABCD, and then subtract it from all other verts in the scene. Let's assume for the purposes of demonstration that that vertex is C. By subtracting C from every vertex in the scene, we will effectively move the origin (0,0) to C, making rotation around C easy.
for all shapes in linked list {
for all vertices in shape {
vertex -= C;
}
}
Step 1B. Rotate everything about the origin by an angle equal to the angle between the C->B vector and the x-axis, so that B lands on the x-axis:
// see http://en.wikipedia.org/wiki/Atan2
float rotRadians = atan2(B.x, B.y); // assuming ABCD vertices are labelled clockwise
for all shapes in linked list {
for all vertices in shape {
rot(thisVert, rotRadians);
}
}
// ...
// function declaration
void rot(theVertex, theta) {
tempX = theVertex.x;
tempY = theVertex.y;
theVertex.x = cos(theta) * tempX + sin(theta) * tempY;
theVertex.y = cos(theta) * tempY - sin(theta) * tempX;
}
If ABCD vertices were labelled clockwise, the ABCD vertices should now look like this:
A = ABCDx , ABCDy
B = ABCDx , 0
C = 0 , 0
D = 0 , ABCDy
(If they were not labeled clockwise, then the "lies within" check in Step 2 won't work, so make sure the vert used in the atan2(...) call is the vertex counterclockwise from the lowest vertex.)
Step 2. Now we can easily analyze whether or not a shape lies within the ABCD rectangle, e.g. if (thisVert.x >= 0 && thisVert.y >= 0 && thisVert.x <= ABCDx && thisVert.y <= ABCDy). Traverse the linked list of shapes, and check to make sure each vertex of each shape lies within ABCD. If one vertex of a shape does not lie within ABCD, then that shape is not part of the ABCD/EFGH intersection. Mark it as not part of the intersection and skip to the next shape.
Step 3. Undo the rotation from Step 1B, then undo the translation from Step 1A.
Step 4. Repeat Steps 1-3 with EFGH instead of ABCD, and you will have your intersection set.
If the only intersection between the two sets is a line, then the above will return nothing as an intersection. If the intersection == NULL, then check for lines that intersect.
If the intersection is still NULL, then check for intersecting points.
This is probably really rough but:
object rectangle {
pos { x, y } // top-left position
size { height, width } // rectangle-size
}
collision::check (rectangle rect) {
// collision-detection logic
collision->order_coords(coords); // order-coords clockwise;
return collision_result_object; // return collided vertices, ordered clockwise, or 0 if rect hit nothing
}
collision::order_rects (rectangle *rect, opt angle) {
return clockwise_rects; // returns rectangles ordered clockwise
}
collision::order_coords (coordinate *coord, opt angle) {
return ordered_coords; // recieves coordinates and returns ordered clockwise
}
rectangle rects; // bunch of rectangles
ordered_rects = collision->order_rects (rects); // order rects starting at 12PM
loop {
foreach ordered_rects as i {
if (collision->check(i)) {
array_of_collision_result_objects[i] = collision->check(i); // start checking rects starting at 12PM, if collision found, return ordered vertexes
}
}
}
Find all the intersections of segments of rectangles. The result consists of some of them and some of initial vertices. To find them just check for every point it lies in both rectangles. Remove unnecessary points (if there are 3 or more on one line). The result is convex and no point you get is strictly inside it, so (if there are at least 3 of them) sort points from some inner point by angle and enjoy the result.
I've come up with a reasonable method that should cover all possible cases:
All we need is basically 3 steps :
Step 1:
for each side Si of R1
for each side Sj of R2
Check if Si and Sj intersect. If they do, push the point in results array
(This also has to take care of the case in case Si and Sj overlap, which is
basically checking if they have the same equation or not - if so, push in
the points of overlap. This also takes care of the case where a vertex of
R2 lies on Si).
next
next
Step 2:
for each vertex Vi of R1
Check if Vi lies inside R2, If so, push it in the results array.
next
Step 3:
for each vertex Vi of R2
Check if Vi lies inside R1, If so, push it in the results array.
next
Now, order the results array, and return
For step 2 & 3 (how to find if a point lies inside a rectangle) - I'd use this excellent article (the last algorithm stated there).

Resources