Rotated rectangle rasterisation algorithm - algorithm

In a nutshell: I want to do a non-approximate version of Bresenham's line algorithm, but for a rectangle rather than a line, and whose points aren't necessarily aligned to the grid.
Given a square grid, and a rectangle comprising four non-grid-aligned points, I want to find a list of all grid squares that are covered, partially or completely, by the rectangle.
Bresenham's line algorithm is approximate – not all partially covered squares are identified. I'm looking for a "perfect" algorithm, that has no false positives or negatives.

It's an old question, but I have solved this issue (C++)
https://github.com/feelinfine/tracer
Maybe it will be usefull for someone
(sorry for my poor english)
Single line tracing
template <typename PointType>
std::set<V2i> trace_line(const PointType& _start_point, const PointType& _end_point, size_t _cell_size)
{
auto point_to_grid_fnc = [_cell_size](const auto& _point)
{
return V2i(std::floor((double)_point.x / _cell_size), std::floor((double)_point.y / _cell_size));
};
V2i start_cell = point_to_grid_fnc(_start_point);
V2i last_cell = point_to_grid_fnc(_end_point);
PointType direction = _end_point - _start_point;
//Moving direction (cells)
int step_x = (direction.x >= 0) ? 1 : -1;
int step_y = (direction.y >= 0) ? 1 : -1;
//Normalize vector
double hypot = std::hypot(direction.x, direction.y);
V2d norm_direction(direction.x / hypot, direction.y / hypot);
//Distance to the nearest square side
double near_x = (step_x >= 0) ? (start_cell.x + 1)*_cell_size - _start_point.x : _start_point.x - (start_cell.x*_cell_size);
double near_y = (step_y >= 0) ? (start_cell.y + 1)*_cell_size - _start_point.y : _start_point.y - (start_cell.y*_cell_size);
//How far along the ray we must move to cross the first vertical (ray_step_to_vside) / or horizontal (ray_step_to_hside) grid line
double ray_step_to_vside = (norm_direction.x != 0) ? near_x / norm_direction.x : std::numeric_limits<double>::max();
double ray_step_to_hside = (norm_direction.y != 0) ? near_y / norm_direction.y : std::numeric_limits<double>::max();
//How far along the ray we must move for horizontal (dx)/ or vertical (dy) component of such movement to equal the cell size
double dx = (norm_direction.x != 0) ? _cell_size / norm_direction.x : std::numeric_limits<double>::max();
double dy = (norm_direction.y != 0) ? _cell_size / norm_direction.y : std::numeric_limits<double>::max();
//Tracing loop
std::set<V2i> cells;
cells.insert(start_cell);
V2i current_cell = start_cell;
size_t grid_bound_x = std::abs(last_cell.x - start_cell.x);
size_t grid_bound_y = std::abs(last_cell.y - start_cell.y);
size_t counter = 0;
while (counter != (grid_bound_x + grid_bound_y))
{
if (std::abs(ray_step_to_vside) < std::abs(ray_step_to_hside))
{
ray_step_to_vside = ray_step_to_vside + dx; //to the next vertical grid line
current_cell.x = current_cell.x + step_x;
}
else
{
ray_step_to_hside = ray_step_to_hside + dy;//to the next horizontal grid line
current_cell.y = current_cell.y + step_y;
}
++counter;
cells.insert(current_cell);
};
return cells;
}
Get all cells
template <typename Container>
std::set<V2i> pick_cells(Container&& _points, size_t _cell_size)
{
if (_points.size() < 2 || _cell_size <= 0)
return std::set<V2i>();
Container points = std::forward<Container>(_points);
auto add_to_set = [](auto& _set, const auto& _to_append)
{
_set.insert(std::cbegin(_to_append), std::cend(_to_append));
};
//Outline
std::set<V2i> cells;
/*
for (auto it = std::begin(_points); it != std::prev(std::end(_points)); ++it)
add_to_set(cells, trace_line(*it, *std::next(it), _cell_size));
add_to_set(cells, trace_line(_points.back(), _points.front(), _cell_size));
*/
//Maybe this code works faster
std::vector<std::future<std::set<V2i> > > results;
using PointType = decltype(points.cbegin())::value_type;
for (auto it = points.cbegin(); it != std::prev(points.cend()); ++it)
results.push_back(std::async(trace_line<PointType>, *it, *std::next(it), _cell_size));
results.push_back(std::async(trace_line<PointType>, points.back(), points.front(), _cell_size));
for (auto& it : results)
add_to_set(cells, it.get());
//Inner
std::set<V2i> to_add;
int last_x = cells.begin()->x;
int counter = cells.begin()->y;
for (auto& it : cells)
{
if (last_x != it.x)
{
counter = it.y;
last_x = it.x;
}
if (it.y > counter)
{
for (int i = counter; i < it.y; ++i)
to_add.insert(V2i(it.x, i));
}
++counter;
}
add_to_set(cells, to_add);
return cells;
}
Types
template <typename _T>
struct V2
{
_T x, y;
V2(_T _x = 0, _T _y = 0) : x(_x), y(_y)
{
};
V2 operator-(const V2& _rhs) const
{
return V2(x - _rhs.x, y - _rhs.y);
}
bool operator==(const V2& _rhs) const
{
return (x == _rhs.x) && (y == _rhs.y);
}
//for std::set sorting
bool operator<(const V2& _rhs) const
{
return (x == _rhs.x) ? (y < _rhs.y) : (x < _rhs.x);
}
};
using V2d = V2<double>;
using V2i = V2<int>;
Usage
std::vector<V2d> points = { {200, 200}, {400, 400}, {500,100} };
size_t cell_size = 30;
auto cells = pick_cells(points, cell_size);
for (auto& it : cells)
... //do something with cells

You can use a scanline approach. The rectangle is a closed convex polygon, so it is sufficient to store the leftmost and rightmost pixel for each horizontal scanline. (And the top and bottom scanlines, too.)
The Bresenham algorithm tries to draw a thin, visually pleasing line without adjacent cells in the smaller dimension. We need an algorithm that visits each cell that the edges of the polygon pass through. The basic idea is to find the starting cell (x, y) for each edge and then to adjust x whenever the edge intersects a vertical border and to adjust y when it intersects a horizontal border.
We can represent the intersections by means of a normalised coordinate s that travels along the edge and that is 0.0 at the first node n1 and 1.0 at the second node n2.
var x = Math.floor(n1.x / cellsize);
var y = Math.floor(n1.y / cellsize);
var s = 0;
The vertical insersections can the be represented as equidistant steps of with dsx from an initial sx.
var dx = n2.x - n1.x;
var sx = 10; // default value > 1.0
// first intersection
if (dx < 0) sx = (cellsize * x - n1.x) / dx;
if (dx > 0) sx = (cellsize * (x + 1) - n1.x) / dx;
var dsx = (dx != 0) ? grid / Math.abs(dx) : 0;
Likewise for the horizontal intersecions. A default value greater than 1.0 catches the cases of horizontal and vertical lines. Add the first point to the scanline data:
add(scan, x, y);
Then we can visit the next adjacent cell by looking at the next intersection with the smallest s.
while (sx <= 1 || sy <= 1) {
if (sx < sy) {
sx += dsx;
if (dx > 0) x++; else x--;
} else {
sy += dsy;
if (dy > 0) y++; else y--;
}
add(scan, x, y);
}
Do this for all four edges and with the same scanline data. Then fill all cells:
for (var y in scan) {
var x = scan[y].min;
var xend = scan[y].max + 1;
while (x < xend) {
// do something with cell (x, y)
x++;
}
}
(I have only skimmed the links MBo provided. It seems that the approach presented in that paper is essentially the same as mine. If so, please excuse the redundant answer, but after working this out I thought I could as well post it.)

This is sub-optimal but might give a general idea.
First off treat the special case of the rectangle being aligned horizontally or vertically separately. This is pretty easy to test for and make the rest simpler.
You can represent the rectangle as a set of 4 inequalities a1 x + b1 y >= c1 a1 x + b1 y <= c2 a3 x + b3 y >= c3 a3 x + b3 y <= c4 as the edges of the rectangles are parallel some of the constants are the same. You also have (up to a multiple) a3=b1 and b3=-a1. You can multiply each inequality by a common factor so you are working with integers.
Now consider each scan line with a fixed value of y.
For each value of y find the four points where the lines intersect the scan line. That is find the solution with each line above. A little bit of logic will find the minimum and maximum values of x. Plot all pixels between these values.
You condition that you want all partially covered squares makes things a little trickier. You can solve this by considering two adjacent scan lines. You want to plot the points between the minimum x for both lines and the maximum for the both lines. If say
a1 x+b1 y>=c is the inequality for the bottom left line in the figure. You want the find the largest x such that a1 x + b1 y < c this will be floor((c-b1 y)/a1) call this minx(y) also find minx(y+1) and the left hand point will be the minimum of these two values.
There is many easy optimisation you can find the y-values of the top and bottom corners reducing the range of y-values to test. You should only need to test two side. For each end point of each line there is one multiplication, one subtraction and one division. The division is the slowest part I think about 4 time slower than other ops. You might be able to remove this with a Bresenham or DDA algorithms others have mentioned.

There is method of Amanatides and Woo to enumerate all intersected cells
A Fast Voxel Traversal Algorithm for Ray Tracing.
Here is practical implementation.
As side effect for you - you'll get points of intersection with grid lines - it may be useful if you need areas of partially covered cells (for antialiasing etc).

Related

Drawing Geometrical and Mathematical Algorithm

I have a certain requirement which becomes an interesting Mathematical problem.
Given a number n and fixed distance d and Point p(x,y) inside rectangle R of fixed width and height (which is screen).
I want to draw n squares inside rectangle with maximum size possible (all squares same size) and squares not intersect each other and are separate from each other by minimum distance d (Distance from perimeter of square).
These squares should also be at least at distance d from a given point P (which is basically mouse's last recorded position).
Please let me know if there is a solution to this.
Solution should give size of square and coordinates for all squares.
The reverse interesting problem could be given size of square how many such squares can be drawn.
Simple (probably not optimal) approach: with binary search find maximal value of a that
Floor((Width + d) / a) * Floor((Height + d) / a) >= n+1
and make regular grid of n squares with edge (a - d), excluding place with point
You've asked for it, you've got it
I've got a fiddle here that probably does a near-optimal tiling.
It's godawful ugly, though.
It reminds me of some customers of mine insisting on dabbling in detailed specifications instead of remaining at functional requirement level :).
The heart of the algorithm is here:
compute: function ()
{
function try_size (x1, x2, y1, y2, w, h, y)
{
var d = Math.sqrt((this.w+this.h)/this.n);
var delta = 10*d;
var n = 0;
while ((delta > 1e-12) || (n < this.n))
{
var res = {};
if (y < (d/2-this.d))
{
res.x1 = res.x2 = res.y1 = 0;
res.y2 = Math.floor ((h-y-this.d)/d);
res.c1 = true;
}
else if (y > (h-d+2*this.d))
{
res.x1 = res.x2 = res.y2 = 0;
res.y1 = Math.floor ((y-this.d)/d);
res.c2 = true;
}
else
{
res.y1 = Math.floor((y1-d/2)/d);
res.y2 = Math.floor((y2-d/2)/d);
res.x1 = Math.floor ((x1-this.d/2)/d);
res.x2 = Math.floor ((x2-this.d/2)/d);
}
res.w = Math.floor ((w+this.d)/d);
n = res.x1+res.x2+res.w*(res.y1+res.y2);
d += n > this.n ? delta : -delta;
if (delta > 1e-12) delta /=2;
}
res.d = d;
res.s = d-2*this.d;
return res;
}
The idea is to tile the rectangle regularily, except for the band around the center point. Horizontal and vertical variants of this band are tried to retain the highest square size.
I guess an optimal solution would not center the band around the center point, but given the awful looks of the result, I don't think it's worth the effort :)
A better-looking but less optimal solution:
(just a proof of concept; some edge cases are handled wrongly).
compute: function ()
{
var d = Math.sqrt((this.w+this.h)/this.n);
var delta = 100*d;
while ((delta > 1e-12) || (res.n < this.n))
{
var res = {};
res.x = Math.floor ((this.w-this.x%d)/d);
res.y = Math.floor ((this.h-this.y%d)/d);
res.n = res.x * res.y;
d += res.n > this.n ? delta : -delta;
if (delta > 1e-12) delta /=2;
}
res.d = d;
res.s = d-2*this.d;
res.a = 0;
this.res = res;
},
Moving the reference point still causes the square size to wobble.
Might be fun as a graphic effect, though.

Bresenham line algorithm - where does the decision parameter come from?

void line()
{
int x1 = 10, y1 = 10, x2 = 300, y2 = 500 , x, y;
int dx, dy, //deltas
e; // decision parameter
glClear(GL_COLOR_BUFFER_BIT);
glColor3f( 1 ,0, 0);
setPixel(x1, y1); //plot first point
// difference between starting and ending points
dx = x2 - x1;
dy = y2 - y1;
e = 2 * dy - dx;
x = x1; y = y1;
for(int k = 0; k < dx - 1; ++k)
{
if(e < 0)
{
//next pixel: (x+1, y)
e = e + 2*dy;
}
else
{
//next pixel: (x+1, y+1)
e = e + 2*dy - 2*dx;
++y;
}
++x;
setPixel(x, y);
}
glFlush();
}
Where does the e = 2*dy - dx come from? Why do we increase it by 2*dy or 2*dy - 2*dx?
Bresenham's algorithm uses only integer arithmetic. The key idea is to minimize the calculations for incremental evaluation of the line equation.
The algorithm is really simple. Let's start with the line equation
f(x) = y = a*x +b
(and assume 0 <= a < 1 for now).
When we go one pixel to the right, we get:
f(x+1) = a * (x+1) + b = f(x) + a
But both a and y will not be integers for the typical line.
So let's just introduce an "error". We always go to the right neighbor. In doing so, we make an error of a by not going up. If our error is above half a pixel (0.5), we go up (and hence decrease the error value by a pixel again)
float e=a;
float y=y1;
int x=x1;
while(x<=x2) {
SetPixel(x,y);
x++;
if (e > 0.5) {
y++;
e=e+a-1;
} else {
e=e+a;
}
}
(Note that we already set the error e to a initially and not to zero, because we always make the decision after the pixel is drawn, and we don't need to check the condition before drawing the very first pixel because that one is always exactly on the line.)
Now, we have come close. But there are two things which prevent us from using integers: the 0.5 and a which is dy/dx. But: we can scale the error value (and the condition) by an arbitray factor, without changing anything. Think about it: we've measured the error in pixels so far (because that seems intuitive at first), but this algorithm could use any arbitrary unit for the error value - half pixels, double pixels, pi pixels.
So let's just scale it by 2*dx to get rid of both fractions in the formula above! (In a way, they key trick here is that the "unit" in which we measure the error value is just not constant in the algorithm, but a function of the line).
int e=2*dy;
int y=y1;
int x=x1;
while(x<=x2) {
SetPixel(x,y);
x++;
if (e > dx) {
y++;
e=e+2*dy - 2*dx;
} else {
e=e+2*dy;
}
}
Now, we have what we want: only integers.
(One thing to note here, though: by going from float to int, we automatically "snap-in" the line's endpoints to integer coordinates - having integer endpoints is some precondition for (and limitation of) the Bresenham algorithm).
There is one additional trick: the condition contains a variable. It would be even more efficient, if we would test against a constant, and ideally against zero (since branching depending just on the sign or zero flags saves us a compare operation). And we can achive this, by just shifiting our error values. In the same way as before, not only the scale of the error value cane be chosen arbitrarily, but also origin.
Since we test for e > dx currently, shifting the error by -dx will allow us to test against 0 (and 0 now means what dx meant before, namely 0.5 pixels). This shift only affects the initial value of e, and the condition, all the increments stay the same as before:
int e=2*dy-dx;
int y=y1;
int x=x1;
while(x<=x2) {
SetPixel(x,y);
x++;
if (e > 0) {
y++;
e=e+2*dy - 2*dx;
} else {
e=e+2*dy;
}
}
Voila, the 2*dy-dx term has suddenly emerged... ;)
The term 2dy-dx comes after we fill xk =yk=0 in the formula (2dy•xk-2dx•yk+2dy+(2b-1)) because for the first parameter we assume the starting point of line lies at origin i.e (0,0).
And b is constant so it is ignored.
Try it by yourself.

Improve the solution to monkey grid puzzle

I was trying to solve the following problem:
There is a monkey which can walk around on a planar grid. The monkey
can move one space at a time left, right, up or down. That is, from
(x, y) the monkey can go to (x+1, y), (x-1, y), (x, y+1), and (x,
y-1). Points where the sum of the digits of the absolute value of the
x coordinate plus the sum of the digits of the absolute value of the y
coordinate are lesser than or equal to 19 are accessible to the
monkey. For example, the point (59, 79) is inaccessible because 5 + 9
+ 7 + 9 = 30, which is greater than 19. Another example: the point (-5, -7) is accessible because abs(-5) + abs(-7) = 5 + 7 = 12, which
is less than 19. How many points can the monkey access if it starts at
(0, 0), including (0, 0) itself?
I came up with the following brute force solution (pseudo code):
/*
legitPoints = {}; // all the allowed points that monkey can goto
list.push( Point(0,0) ); // start exploring from origin
while(!list.empty()){
Point p = list.pop_front(); // remove point
// if p has been seen before; ignore p => continue;
// else mark it and proceed further
if(legit(p){
// since we are only exploring points in one quadrant,
// we don't need to check for -x direction and -y direction
// hence explore the following: this is like Breadth First Search
list.push(Point(p.x+1, p.y)); // explore x+1, y
list.push(Point(p.x, p.y+1)); // explore x, y+1
legitPoints.insert(p); // during insertion, ignore duplicates
// (although no duplicates should come through after above check)
// count properly using multipliers
// Origin => count once x = 0 && y == 0 => mul : 1
// X axis => count twice x = 0 && y != 0 => mul : 2
// Y axis => count twice x != 0 && y = 0 => mul : 2
// All others => mul : 4
}
return legitPoints.count();
}
*/
This is a very brute force solution. One of the optimizations I used was to one scan one quadrant instead of looking at four. Another one was to ignore the points that we've already seen before.
However, looking at the final points, I was trying to find a pattern, perhaps a mathematical solution or a different approach that would be better than what I came up.
Any thoughts ?
PS: If you want, I can post the data somewhere. It is interesting to look at it with any one of the axis sorted.
First quadrant visual:
Here's what the whole grid looks like as an image:
The black squares are inaccessible, white accessible, gray accessible and reachable by movement from the center. There's a 600x600 bounding box of black because the digits of 299 add to 20, so we only have to consider that.
This exercise is basically a "flood fill", with a shape which is just about the worst case possible for a flood fill. You can do the symmetry speedup if you like, though that's not really where the meat of the issue is--my solution runs in 160 ms without it (under 50ms with it).
The big speed wins are (1) do a line-filling flood so you don't have to put every point on the stack, and (2) manage your own stack instead of doing recursion. I built my stack as two dynamically-allocated vectors of ints (for x and y), and they grow to about 16k, so building whole stack frames that deep would definitely be a huge loss.
Without looking for the ideal solution I had something similar. For each point the monkey is, I added the next 4 possibilities to a list and did the same for the next four recursively only if they had not been visited. This can be also done with multiprocessing to speed up the process.
Here is my solution, more like a BFS:
int DigitSum(int num)
{
int sum = 0;
num = (num >= 0) ? num : -num;
while(num) {
sum += num % 10;
num /= 10;
}
return sum;
}
struct Point {
int x,y;
Point(): x(0), y(0) {}
Point(int x1, int y1): x(x1), y(y1) {}
friend bool operator<(const Point& p1, const Point& p2)
{
if (p1.x < p2.x) {
return true;
} else if (p1.x == p2.x) {
return (p1.y < p2.y);
} else {
return false;
}
}
};
void neighbor(vector<Point>& n, const Point& p)
{
if (n.size() < 4) n.resize(4);
n[0] = Point(p.x-1, p.y);
n[1] = Point(p.x+1, p.y);
n[2] = Point(p.x, p.y-1);
n[3] = Point(p.x, p.y+1);
}
int numMoves(const Point& start)
{
map<Point, bool> m;
queue<Point> q;
int count = 0;
vector<Point> neigh;
q.push(start);
m[start] = true;
while (! q.empty()) {
Point c = q.front();
neighbor(neigh, c);
for (auto p: neigh) {
if ((!m[p]) && (DigitSum(p.x) + DigitSum(p.y) <= 19)) {
count++;
m[p] = true;
q.push(p);
}
}
q.pop();
}
return count;
}
I'm not sure how different this may be from brainydexter's idea... roaming the one quadrant, I instituted a single array hash (index = 299 * y + x) and built the result with another array, each index storing only the points that expand from its previous index, for example:
first iteration, result = [[(0,0)]]
second iteration, result = [[(0,0)],[(0,1),(1,0)]]
...
On an old IBM Thinkpad in JavaScript, the speed seemed to vary from 35-120 milliseconds (fiddle here).

Polygon triangulation into triangle strips for OpenGL ES

I am looking for a fast polygon triangulation algorithm that can triangulate not very complex 2D concave polygons (without holes) into triangle strips ready to be sent to OpenGL ES for drawing using GL_TRIANGLE_STRIP.
I am aware of some algorithms but I couldn't find one that will fit my needs:
http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
this algorithm works ok but the problem is it returns simple triangles which you can't draw with GL_TRIANGLE_STRIP, you need to use GL_TRIANGLES which isn't very efficient on a large number of vertices.
http://code.google.com/p/iphone-glu/
it doesn't have any example associated and I couldn't find anyone that has successfully used it on iOS with OpenGL ES 2.0
I don't know what it returns and it seems like it also calls the corresponding OpenGL commands which I don't want - I only need the triangles back
it leaks memory
The platform I am developing for is: iOS, OpenGL ES 2.0, cocos2d 2.0.
Can anyone help me with such an algorithm? Or any other advice will be greatly appreciated.
In 2D and without holes, this is fairly easy. First, you need to break your polygon to one or more monotone polygons.
The monotone polygons are pretty simple to turn into tristrips, just sort the values by y, find the top-most and bottom-most vertex, and then you have lists of vertices to the right and to the left (because vertices come in some defined, say clockwise, order). Then you start with top-most vertex and add vertices from the left and from the right sides in alternating manner.
This technique will work for any 2D polygons without self-intersecting edges, which includes some cases of polygons with holes (the holes must be correctly wound though).
You can try and play with this code:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(-.5f, -.5f, 0);
std::vector<Vector2f> my_polygon;
my_polygon.push_back(Vector2f(-0.300475f, 0.862924f));
my_polygon.push_back(Vector2f(0.302850f, 1.265013f));
my_polygon.push_back(Vector2f(0.811164f, 1.437337f));
my_polygon.push_back(Vector2f(1.001188f, 1.071802f));
my_polygon.push_back(Vector2f(0.692399f, 0.936031f));
my_polygon.push_back(Vector2f(0.934679f, 0.622715f));
my_polygon.push_back(Vector2f(0.644893f, 0.408616f));
my_polygon.push_back(Vector2f(0.592637f, 0.753264f));
my_polygon.push_back(Vector2f(0.269596f, 0.278068f));
my_polygon.push_back(Vector2f(0.996437f, -0.092689f));
my_polygon.push_back(Vector2f(0.735154f, -0.338120f));
my_polygon.push_back(Vector2f(0.112827f, 0.079634f));
my_polygon.push_back(Vector2f(-0.167458f, 0.330287f));
my_polygon.push_back(Vector2f(0.008314f, 0.664491f));
my_polygon.push_back(Vector2f(0.393112f, 1.040470f));
// from wiki (http://en.wikipedia.org/wiki/File:Polygon-to-monotone.png)
glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLineWidth(6);
glColor3f(1, 1, 1);
glBegin(GL_LINE_LOOP);
for(size_t i = 0, n = my_polygon.size(); i < n; ++ i)
glVertex2f(my_polygon[i].x, my_polygon[i].y);
glEnd();
glPointSize(6);
glBegin(GL_POINTS);
for(size_t i = 0, n = my_polygon.size(); i < n; ++ i)
glVertex2f(my_polygon[i].x, my_polygon[i].y);
glEnd();
// draw the original polygon
std::vector<int> working_set;
for(size_t i = 0, n = my_polygon.size(); i < n; ++ i)
working_set.push_back(i);
_ASSERTE(working_set.size() == my_polygon.size());
// add vertex indices to the list (could be done using iota)
std::list<std::vector<int> > monotone_poly_list;
// list of monotone polygons (the output)
glPointSize(14);
glLineWidth(4);
// prepare to draw split points and slice lines
for(;;) {
std::vector<int> sorted_vertex_list;
{
for(size_t i = 0, n = working_set.size(); i < n; ++ i)
sorted_vertex_list.push_back(i);
_ASSERTE(working_set.size() == working_set.size());
// add vertex indices to the list (could be done using iota)
for(;;) {
bool b_change = false;
for(size_t i = 1, n = sorted_vertex_list.size(); i < n; ++ i) {
int a = sorted_vertex_list[i - 1];
int b = sorted_vertex_list[i];
if(my_polygon[working_set[a]].y < my_polygon[working_set[b]].y) {
std::swap(sorted_vertex_list[i - 1], sorted_vertex_list[i]);
b_change = true;
}
}
if(!b_change)
break;
}
// sort vertex indices by the y coordinate
// (note this is using bubblesort to maintain portability
// but it should be done using a better sorting method)
}
// build sorted vertex list
bool b_change = false;
for(size_t i = 0, n = sorted_vertex_list.size(), m = working_set.size(); i < n; ++ i) {
int n_ith = sorted_vertex_list[i];
Vector2f ith = my_polygon[working_set[n_ith]];
Vector2f prev = my_polygon[working_set[(n_ith + m - 1) % m]];
Vector2f next = my_polygon[working_set[(n_ith + 1) % m]];
// get point in the list, and get it's neighbours
// (neighbours are not in sorted list ordering
// but in the original polygon order)
float sidePrev = sign(ith.y - prev.y);
float sideNext = sign(ith.y - next.y);
// calculate which side they lie on
// (sign function gives -1 for negative and 1 for positive argument)
if(sidePrev * sideNext >= 0) { // if they are both on the same side
glColor3f(1, 0, 0);
glBegin(GL_POINTS);
glVertex2f(ith.x, ith.y);
glEnd();
// marks points whose neighbours are both on the same side (split points)
int n_next = -1;
if(sidePrev + sideNext > 0) {
if(i > 0)
n_next = sorted_vertex_list[i - 1];
// get the next vertex above it
} else {
if(i + 1 < n)
n_next = sorted_vertex_list[i + 1];
// get the next vertex below it
}
// this is kind of simplistic, one needs to check if
// a line between n_ith and n_next doesn't exit the polygon
// (but that doesn't happen in the example)
if(n_next != -1) {
glColor3f(0, 1, 0);
glBegin(GL_POINTS);
glVertex2f(my_polygon[working_set[n_next]].x, my_polygon[working_set[n_next]].y);
glEnd();
glBegin(GL_LINES);
glVertex2f(ith.x, ith.y);
glVertex2f(my_polygon[working_set[n_next]].x, my_polygon[working_set[n_next]].y);
glEnd();
std::vector<int> poly, remove_list;
int n_last = n_ith;
if(n_last > n_next)
std::swap(n_last, n_next);
int idx = n_next;
poly.push_back(working_set[idx]); // add n_next
for(idx = (idx + 1) % m; idx != n_last; idx = (idx + 1) % m) {
poly.push_back(working_set[idx]);
// add it to the polygon
remove_list.push_back(idx);
// mark this vertex to be erased from the working set
}
poly.push_back(working_set[idx]); // add n_ith
// build a new monotone polygon by cutting the original one
std::sort(remove_list.begin(), remove_list.end());
for(size_t i = remove_list.size(); i > 0; -- i) {
int n_which = remove_list[i - 1];
working_set.erase(working_set.begin() + n_which);
}
// sort indices of vertices to be removed and remove them
// from the working set (have to do it in reverse order)
monotone_poly_list.push_back(poly);
// add it to the list
b_change = true;
break;
// the polygon was sliced, restart the algorithm, regenerate sorted list and slice again
}
}
}
if(!b_change)
break;
// no moves
}
if(!working_set.empty())
monotone_poly_list.push_back(working_set);
// use the remaining vertices (which the algorithm was unable to slice) as the last polygon
std::list<std::vector<int> >::const_iterator p_mono_poly = monotone_poly_list.begin();
for(; p_mono_poly != monotone_poly_list.end(); ++ p_mono_poly) {
const std::vector<int> &r_mono_poly = *p_mono_poly;
glLineWidth(2);
glColor3f(0, 0, 1);
glBegin(GL_LINE_LOOP);
for(size_t i = 0, n = r_mono_poly.size(); i < n; ++ i)
glVertex2f(my_polygon[r_mono_poly[i]].x, my_polygon[r_mono_poly[i]].y);
glEnd();
glPointSize(2);
glBegin(GL_POINTS);
for(size_t i = 0, n = r_mono_poly.size(); i < n; ++ i)
glVertex2f(my_polygon[r_mono_poly[i]].x, my_polygon[r_mono_poly[i]].y);
glEnd();
// draw the sliced part of the polygon
int n_top = 0;
for(size_t i = 0, n = r_mono_poly.size(); i < n; ++ i) {
if(my_polygon[r_mono_poly[i]].y < my_polygon[r_mono_poly[n_top]].y)
n_top = i;
}
// find the top-most point
glLineWidth(1);
glColor3f(0, 1, 0);
glBegin(GL_LINE_STRIP);
glVertex2f(my_polygon[r_mono_poly[n_top]].x, my_polygon[r_mono_poly[n_top]].y);
for(size_t i = 1, n = r_mono_poly.size(); i <= n; ++ i) {
int n_which = (n_top + ((i & 1)? n - i / 2 : i / 2)) % n;
glVertex2f(my_polygon[r_mono_poly[n_which]].x, my_polygon[r_mono_poly[n_which]].y);
}
glEnd();
// draw as if triangle strip
}
This code is not optimal, but it should be easy to understand. At the beginnig, a concave polygon is created. Then a "working set" of vertices is created. On that working set, a permutation is calculated which sorts the vertices by their y coordinate. That permutation is then looped through, looking for split points. Once a split point is found, a new monotone polygon is created. Then, the vertices used in the new polygon are removed from the working set and the whole process repeats. Finally, the working set contains the last polygon which could not be split. At the end, the monotone polygons are rendered, along with triangle strip ordering. It is a little bit messy, but I'm sure you will figure it out (this is C++ code, just put it inside a GLUT window and see what it does).
Hope this helps ...
You can extract tesselation algorithm from OpenGL Sample Implementation, like described in this post http://choruscode.blogspot.de/2013/03/extracting-tesselation-from-opengl.html , it also has an example.

Geo Fencing - point inside/outside polygon

I would like to determine a polygon and implement an algorithm which would check if a point is inside or outside the polygon.
Does anyone know if there is any example available of any similar algorithm?
If i remember correctly, the algorithm is to draw a horizontal line through your test point. Count how many lines of of the polygon you intersect to reach your point.
If the answer is odd, you're inside. If the answer is even, you're outside.
Edit: Yeah, what he said (Wikipedia):
C# code
bool IsPointInPolygon(List<Loc> poly, Loc point)
{
int i, j;
bool c = false;
for (i = 0, j = poly.Count - 1; i < poly.Count; j = i++)
{
if ((((poly[i].Lt <= point.Lt) && (point.Lt < poly[j].Lt))
|| ((poly[j].Lt <= point.Lt) && (point.Lt < poly[i].Lt)))
&& (point.Lg < (poly[j].Lg - poly[i].Lg) * (point.Lt - poly[i].Lt)
/ (poly[j].Lt - poly[i].Lt) + poly[i].Lg))
{
c = !c;
}
}
return c;
}
Location class
public class Loc
{
private double lt;
private double lg;
public double Lg
{
get { return lg; }
set { lg = value; }
}
public double Lt
{
get { return lt; }
set { lt = value; }
}
public Loc(double lt, double lg)
{
this.lt = lt;
this.lg = lg;
}
}
After searching the web and trying various implementations and porting them from C++ to C# I finally got my code straight:
public static bool PointInPolygon(LatLong p, List<LatLong> poly)
{
int n = poly.Count();
poly.Add(new LatLong { Lat = poly[0].Lat, Lon = poly[0].Lon });
LatLong[] v = poly.ToArray();
int wn = 0; // the winding number counter
// loop through all edges of the polygon
for (int i = 0; i < n; i++)
{ // edge from V[i] to V[i+1]
if (v[i].Lat <= p.Lat)
{ // start y <= P.y
if (v[i + 1].Lat > p.Lat) // an upward crossing
if (isLeft(v[i], v[i + 1], p) > 0) // P left of edge
++wn; // have a valid up intersect
}
else
{ // start y > P.y (no test needed)
if (v[i + 1].Lat <= p.Lat) // a downward crossing
if (isLeft(v[i], v[i + 1], p) < 0) // P right of edge
--wn; // have a valid down intersect
}
}
if (wn != 0)
return true;
else
return false;
}
private static int isLeft(LatLong P0, LatLong P1, LatLong P2)
{
double calc = ((P1.Lon - P0.Lon) * (P2.Lat - P0.Lat)
- (P2.Lon - P0.Lon) * (P1.Lat - P0.Lat));
if (calc > 0)
return 1;
else if (calc < 0)
return -1;
else
return 0;
}
The isLeft function was giving me rounding problems and I spent hours without realizing that I was doing the conversion wrong, so forgive me for the lame if block at the end of that function.
BTW, this is the original code and article:
http://softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm
By far the best explanation and implementation can be found at
Point In Polygon Winding Number Inclusion
There is even a C++ implementation at the end of the well explained article. This site also contains some great algorithms/solutions for other geometry based problems.
I have modified and used the C++ implementation and also created a C# implementation. You definitely want to use the Winding Number algorithm as it is more accurate than the edge crossing algorithm and it is very fast.
I think there is a simpler and more efficient solution.
Here is the code in C++. I should be simple to convert it to C#.
int pnpoly(int npol, float *xp, float *yp, float x, float y)
{
int i, j, c = 0;
for (i = 0, j = npol-1; i < npol; j = i++) {
if ((((yp[i] <= y) && (y < yp[j])) ||
((yp[j] <= y) && (y < yp[i]))) &&
(x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
c = !c;
}
return c;
}
The complete solution in asp.Net C#, you can see the complete detail here, you can see how to find point(lat,lon) whether its inside or Outside the Polygon using the latitude and longitudes ?
Article Reference Link
private static bool checkPointExistsInGeofencePolygon(string latlnglist, string lat, string lng)
{
List<Loc> objList = new List<Loc>();
// sample string should be like this strlatlng = "39.11495,-76.873259|39.114588,-76.872808|39.112921,-76.870373|";
string[] arr = latlnglist.Split('|');
for (int i = 0; i <= arr.Length - 1; i++)
{
string latlng = arr[i];
string[] arrlatlng = latlng.Split(',');
Loc er = new Loc(Convert.ToDouble(arrlatlng[0]), Convert.ToDouble(arrlatlng[1]));
objList.Add(er);
}
Loc pt = new Loc(Convert.ToDouble(lat), Convert.ToDouble(lng));
if (IsPointInPolygon(objList, pt) == true)
{
return true;
}
else
{
return false;
}
}
private static bool IsPointInPolygon(List<Loc> poly, Loc point)
{
int i, j;
bool c = false;
for (i = 0, j = poly.Count - 1; i < poly.Count; j = i++)
{
if ((((poly[i].Lt <= point.Lt) && (point.Lt < poly[j].Lt)) |
((poly[j].Lt <= point.Lt) && (point.Lt < poly[i].Lt))) &&
(point.Lg < (poly[j].Lg - poly[i].Lg) * (point.Lt - poly[i].Lt) / (poly[j].Lt - poly[i].Lt) + poly[i].Lg))
c = !c;
}
return c;
}
Just a heads up (using answer as I can't comment), if you want to use point-in-polygon for geo fencing, then you need to change your algorithm to work with spherical coordinates. -180 longitude is the same as 180 longitude and point-in-polygon will break in such situation.
Relating to kobers answer I worked it out with more readable clean code and changed the longitudes that crosses the date border:
public bool IsPointInPolygon(List<PointPosition> polygon, double latitude, double longitude)
{
bool isInIntersection = false;
int actualPointIndex = 0;
int pointIndexBeforeActual = polygon.Count - 1;
var offset = calculateLonOffsetFromDateLine(polygon);
longitude = longitude < 0.0 ? longitude + offset : longitude;
foreach (var actualPointPosition in polygon)
{
var p1Lat = actualPointPosition.Latitude;
var p1Lon = actualPointPosition.Longitude;
var p0Lat = polygon[pointIndexBeforeActual].Latitude;
var p0Lon = polygon[pointIndexBeforeActual].Longitude;
if (p1Lon < 0.0) p1Lon += offset;
if (p0Lon < 0.0) p0Lon += offset;
// Jordan curve theorem - odd even rule algorithm
if (isPointLatitudeBetweenPolyLine(p0Lat, p1Lat, latitude)
&& isPointRightFromPolyLine(p0Lat, p0Lon, p1Lat, p1Lon, latitude, longitude))
{
isInIntersection = !isInIntersection;
}
pointIndexBeforeActual = actualPointIndex;
actualPointIndex++;
}
return isInIntersection;
}
private double calculateLonOffsetFromDateLine(List<PointPosition> polygon)
{
double offset = 0.0;
var maxLonPoly = polygon.Max(x => x.Longitude);
var minLonPoly = polygon.Min(x => x.Longitude);
if (Math.Abs(minLonPoly - maxLonPoly) > 180)
{
offset = 360.0;
}
return offset;
}
private bool isPointLatitudeBetweenPolyLine(double polyLinePoint1Lat, double polyLinePoint2Lat, double poiLat)
{
return polyLinePoint2Lat <= poiLat && poiLat < polyLinePoint1Lat || polyLinePoint1Lat <= poiLat && poiLat < polyLinePoint2Lat;
}
private bool isPointRightFromPolyLine(double polyLinePoint1Lat, double polyLinePoint1Lon, double polyLinePoint2Lat, double polyLinePoint2Lon, double poiLat, double poiLon)
{
// lon <(lon1-lon2)*(latp-lat2)/(lat1-lat2)+lon2
return poiLon < (polyLinePoint1Lon - polyLinePoint2Lon) * (poiLat - polyLinePoint2Lat) / (polyLinePoint1Lat - polyLinePoint2Lat) + polyLinePoint2Lon;
}
I add one detail to help people who live in the... south of earth!!
If you're in Brazil (that's my case), our GPS coord are all negatives.
And all these algo give wrong results.
The easiest way if to use the absolute values of the Lat and Long of all point. And in that case Jan Kobersky's algo is perfect.
Check if a point is inside a polygon or not -
Consider the polygon which has vertices a1,a2,a3,a4,a5. The following set of steps should help in ascertaining whether point P lies inside the polygon or outside.
Compute the vector area of the triangle formed by edge a1->a2 and the vectors connecting a2 to P and P to a1. Similarly, compute the vector area of the each of the possible triangles having one side as the side of the polygon and the other two connecting P to that side.
For a point to be inside a polygon, each of the triangles need to have positive area. Even if one of the triangles have a negative area then the point P stands out of the polygon.
In order to compute the area of a triangle given vectors representing its 3 edges, refer to http://www.jtaylor1142001.net/calcjat/Solutions/VCrossProduct/VCPATriangle.htm
The problem is easier if your polygon is convex. If so, you can do a simple test for each line to see if the point is on the inside or outside of that line (extending to infinity in both directions). Otherwise, for concave polygons, draw an imaginary ray from your point out to infinity (in any direction). Count how many times it crosses a boundary line. Odd means the point is inside, even means the point is outside.
This last algorithm is trickier than it looks. You will have to be very careful about what happens when your imaginary ray exactly hits one of the polygon's vertices.
If your imaginary ray goes in the -x direction, you can choose only to count lines that include at least one point whose y coordinate is strictly less than the y coordinate of your point. This is how you get most of the weird edge cases to work correctly.
If you have a simple polygon (none of the lines cross) and you don't have holes you can also triangulate the polygon, which you are probably going to do anyway in a GIS app to draw a TIN, then test for points in each triangle. If you have a small number of edges to the polygon but a large number of points this is fast.
For an interesting point in triangle see link text
Otherwise definately use the winding rule rather than edge crossing, edge crossing has real problems with points on edges, which if your data is generated form a GPS with limited precision is very likely.
the polygon is defined as a sequential list of point pairs A, B, C .... A.
no side A-B, B-C ... crosses any other side
Determine box Xmin, Xmax, Ymin, Ymax
case 1 the test point P lies outside the box
case 2 the test point P lies inside the box:
Determine the 'diameter' D of the box {[Xmin,Ymin] - [Xmax, Ymax]} ( and add a little extra to avoid possible confusion with D being on a side)
Determine the gradients M of all sides
Find a gradient Mt most different from all gradients M
The test line runs from P at gradient Mt a distance D.
Set the count of intersections to zero
For each of the sides A-B, B-C test for the intersection of P-D with a side
from its start up to but NOT INCLUDING its end. Increment the count of intersections
if required. Note that a zero distance from P to the intersection indicates that P is ON a side
An odd count indicates P is inside the polygon
I translated c# method in Php and I added many comments to understand code.Description of PolygonHelps:
Check if a point is inside or outside of a polygon. This procedure uses gps coordinates and it works when polygon has a little geographic area.
INPUT:$poly: array of Point: polygon vertices list; [{Point}, {Point}, ...];$point: point to check; Point: {"lat" => "x.xxx", "lng" => "y.yyy"}
When $c is false, the number of intersections with polygon is even, so the point is outside of polygon;When $c is true, the number of intersections with polygon is odd, so the point is inside of polygon;$n is the number of vertices in polygon;For each vertex in polygon, method calculates line through current vertex and previous vertex and check if the two lines have an intersection point.$c changes when intersection point exists.
So, method can return true if point is inside the polygon, else return false.
class PolygonHelps {
public static function isPointInPolygon(&$poly, $point){
$c = false;
$n = $j = count($poly);
for ($i = 0, $j = $n - 1; $i < $n; $j = $i++){
if ( ( ( ( $poly[$i]->lat <= $point->lat ) && ( $point->lat < $poly[$j]->lat ) )
|| ( ( $poly[$j]->lat <= $point->lat ) && ( $point->lat < $poly[$i]->lat ) ) )
&& ( $point->lng < ( $poly[$j]->lng - $poly[$i]->lng )
* ( $point->lat - $poly[$i]->lat )
/ ( $poly[$j]->lat - $poly[$i]->lat )
+ $poly[$i]->lng ) ){
$c = !$c;
}
}
return $c;
}
}
Jan's answer is great.
Here is the same code using the GeoCoordinate class instead.
using System.Device.Location;
...
public static bool IsPointInPolygon(List<GeoCoordinate> poly, GeoCoordinate point)
{
int i, j;
bool c = false;
for (i = 0, j = poly.Count - 1; i < poly.Count; j = i++)
{
if ((((poly[i].Latitude <= point.Latitude) && (point.Latitude < poly[j].Latitude))
|| ((poly[j].Latitude <= point.Latitude) && (point.Latitude < poly[i].Latitude)))
&& (point.Longitude < (poly[j].Longitude - poly[i].Longitude) * (point.Latitude - poly[i].Latitude)
/ (poly[j].Latitude - poly[i].Latitude) + poly[i].Longitude))
c = !c;
}
return c;
}
You can try this simple class https://github.com/xopbatgh/sb-polygon-pointer
It is easy to deal with it
You just insert polygon coordinates into array
Ask library is desired point with lat/lng inside the polygon
$polygonBox = [
[55.761515, 37.600375],
[55.759428, 37.651156],
[55.737112, 37.649566],
[55.737649, 37.597301],
];
$sbPolygonEngine = new sbPolygonEngine($polygonBox);
$isCrosses = $sbPolygonEngine->isCrossesWith(55.746768, 37.625605);
// $isCrosses is boolean
(answer was returned from deleted by myself because initially it was formatted wrong)

Resources