I have an algorithm that can find if a point is inside a polygon.
int CGlEngineFunctions::PointInPoly(int npts, float *xp, float *yp, float x, float y)
{
int i, j, c = 0;
for (i = 0, j = npts-1; i < npts; 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;
}
My only issue with it is it assumes an odd winding rule. What I mean by this is that if the polygon is self intersecting, certain parts that it would considered to be 'empty' will return as false. What I'd need in even if it self intersects, anything inside the polygon will return true.
Thanks
Beware: this answer is wrong. I have no time to fix it right now, but see the comments.
This casts a ray from the point to infinity, and checks for intersections with each of the polygon's edges. Each time an intersection is found, the flag c is toggled:
c = !c;
So an even number of intersections means an even number of toggles, so c will be 0 at the end. An odd number of intersections means an odd number of toggles, so c will be 1.
What you want instead is to set the c flag if any intersection occurs:
c = 1;
And for good measure, you can then eliminate c entirely, and terminate early:
int CGlEngineFunctions::PointInPoly(int npts, float *xp, float *yp, float x, float y)
{
int i, j;
for (i = 0, j = npts-1; i < npts; 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]))
return 1;
}
return 0;
}
To translate your original algorithm to english: You're determining if the number of polygon segments to the right of your point are even or odd. If it's even (including zero) your point is outside, if it's odd your point is inside. This means if there are two segments to the right and also two segments to the left, the point is not considered inside the polygon.
What you need to do is change the algorithm so that it checks for segments on both sides; if there's a segment on both sides of the point, then the point is within the polygon.
int CGlEngineFunctions::PointInPoly(int npts, float *xp, float *yp, float x, float y)
{
int i, j;
bool hasSegmentLeft = false;
bool hasSegmentRight = false;
for (i = 0, j = npts-1; i < npts; j = i++) {
if ((((yp[i] <= y) && (y < yp[j])) ||
((yp[j] <= y) && (y < yp[i]))))
{
if (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i])
{
hasSegmentRight = true;
if (hasSegmentLeft) // short circuit early return
return true;
}
else
{
hasSegmentLeft = true;
if (hasSegmentRight) // short circuit early return
return true;
}
}
return hasSegmentLeft && hasSegmentRight;
}
P.S. that for statement construct is a very clever way of dealing with a circular list that wraps around to the beginning; I'd never seen it before.
Related
I have a vector<vector<double>> heightmap that is dynamically loaded from a CSV file of GPS data to be around 4000x4000. However, only provides 140,799 points.
It produces a greyscale map as shown bellow:
I wish to interpolate the heights between all the points to generate a height map of the area.
The below code finds all known points will look in a 10m radius of the point to find any other known points. If another point is found then it will linearly interpolate between the 2 points. Interpolated points are defined by - height and unset values are defined as -1337.
This approach is incredibly slow I am sure there are better ways to achieve this.
bool run_interp = true;
bool interp_interp = false;
int counter = 0;
while (run_interp)
{
for (auto x = 0; x < map.size(); x++)
{
for (auto y = 0; y < map.at(x).size(); y++)
{
const auto height = map.at(x).at(y);
if (height == -1337) continue;
if (!interp_interp && height < 0) continue;
//Look in a 10m radius of a known value to see if there
//Is another known value to linearly interp between
//Set height to a negative if it has been interped
const int radius = (1 / resolution) * 10;
for (auto rxi = 0; rxi < radius * 2; rxi++)
{
//since we want to expand outwards
const int rx = x + ((rxi % 2 == 0) ? rxi / 2 : -(rxi - 1) / 2);
if (rx < 0 || rx >= map.size()) continue;
for (auto ryi = 0; ryi < radius * 2; ryi++)
{
const int ry = y + ((rxi % 2 == 0) ? rxi / 2 : -(rxi - 1) / 2);
if (ry < 0 || ry >= map.at(x).size()) continue;
const auto new_height = map.at(rx).at(ry);
if (new_height == -1337) continue;
//First go around we don't want to interp
//Interps
if (!interp_interp && new_height < 0) continue;
//We have found a known point within 10m
const auto delta = new_height - height;
const auto distance = sqrt((rx- x) * (rx - x)
+ (ry - y) * (ry - y));
const auto angle = atan2(ry - y, rx - x);
const auto ratio = delta / distance;
//Backtrack from found point until we get to know point
for (auto radi = 0; radi < distance; radi++)
{
const auto new_x = static_cast<int>(x + radi * cos(angle));
const auto new_y = static_cast<int>(y + radi * sin(angle));
if (new_x < 0 || new_x >= map.size()) continue;
if (new_y < 0 || new_y >= map.at(new_x).size()) continue;
const auto interp_height = map.at(new_x).at(new_y);
//If it is a known height don't interp it
if (interp_height > 0)
continue;
counter++;
set_height(new_x, new_y, -interp_height);
}
}
}
}
std::cout << x << " " << counter << std::endl;;
}
if (interp_interp)
run_interp = false;
interp_interp = true;
}
set_height(const int x, const int y, const double height)
{
//First time data being set
if (map.at(x).at(y) == -1337)
{
map.at(x).at(y) = height;
}
else // Data set already so average it
{
//While this isn't technically correct and weights
//Later data significantly more favourablily
//It should be fine
//TODO: fix it.
map.at(x).at(y) += height;
map.at(x).at(y) /= 2;
}
}
If you put the points into a kd-tree, it will be much faster to find the closest point (O(nlogn)).
I'm not sure that will solve all your issues, but it is a start.
I am experiencing a rather strange thing. I am currently working on a function that calculates the shape factor of a shape. The perimeter and area functions work perfectly fine however I have discovered something.
The code that out puts the right answer
double Shapefactor (char line [50][50]){
double sfactor;
double perimeter1= (Perimeter(line));
printf("peri = %f", perimeter1);
double area1=((double)Area(line));
sfactor = ((perimeter1 * perimeter1) /area1);
printf("----------------------------------------------------*Therefore the shape factor for the given shape is* %f \n", sfactor);
return (sfactor);
}
This provides me the correct output. However if I was to remove this line from the code
printf("peri = %f", perimeter1);
Then it gives me the wrong number. Do you have any idea why this is?
Area code
int Area (char line [50][50]){
int x;
int y;
int sum;
for (x = 0; x <= 50; x++) {
for (y = 0; y <= 50; y++) {
if (line[x][y] == '1')
sum++;
}
}
return (sum);
}
Perimeter
int Perimeter (char line [50][50]){
int x;
int y;
int sumup;
FILE * f_ptr;
char filename[20];
for (x = 0; x < 50; x++) {
for (y = 0; y < 50; y++) {
if (line[x][y + 1] == '0' & line[x][y] == '1')
sumup++;
else if (line[x][y] == '1' & line[x][y - 1] == '0')
sumup++;
else if (line[x + 1][y] == '0' & line[x][y] == '1')
sumup++;
else if (line[x][y] == '1' & line[x - 1][y] == '0')
sumup++;
}
}
return (sumup);
}
Thank you
The variable sum in Area() (EDIT: and also sumup in Perimeter(), as noted by #agbinfo) is uninitialized:
int Area (char line [50][50]){
//...
int sum;
for (x = 0; x <= 50; x++) {
for (y = 0; y <= 50; y++) {
if (line[x][y] == '1')
sum++;
//...
This is undefined behavior; this being an automatic variable, it's likely what you're reading there is garbage left on the stack by a previous function call, i.e. whether you invoke printf() or not makes the difference you're seeing.
I recommend enabling compiler warnings and linters which would usually catch these sort of errors.
The game board is stored as a 2D char array. The Player moves his cursor around the board using the numpad, and chooses with the enter key- current position of the cursor is stored in two ints.
After each move, the board is evaluated for a win using the below method.
void checkwin()
{
//look along lines from current position
int x = cursorPosX;
int y = cursorPosY;
int c = playerTurn ? 1 : 2; //which mark to look for
for (int xAxis = 0; xAxis <= 2; xAxis++) //look along x axis
{
x = WrapValue(0, sizeof(squares[0]), x + 1);
if (CheckPos(x, y) != c) //if we don't find the same mark, must not be a horizontal line, otherwise, break out.
{
x = cursorPosX; //reset x
for (int yAxis = 0; yAxis <= 2; yAxis++) //look along y axis
{
y = WrapValue(0, sizeof(squares[0]), y + 1);
if (CheckPos(x, y) != c)
{
y = cursorPosY;
//look for diagonal
for (int i = 0; i <= 2; i++ )
{
x = WrapValue(0, sizeof(squares[0]), x + 1);
y = WrapValue(0, sizeof(squares[0]), y + 1);
if (CheckPos(x, y) != c)
{
//failed everything, return
winConditions = -1;
return;
}
}
break;
}
}
break;
}
}
//if we make it out of the loops, we have a winner.
winConditions = playerTurn ? 0 : 1;
}
I get wrong results- returning a draw or win when not appropriate. I'm almost certain x and y get wrong values at some point and start checking the wrong spots.
Visual Studio stops updating a watch on x and y after going into the yAxis loop- I'm not sure why, but it prevents me from keeping track of those values. Am I breaking a rule about scoping somewhere? This is the only place I use x and y as variable names.
Relevant wrap method below. My aim was to always be able to check the other 2 spaces by adding, no matter where I was on the board
int WrapValue(int min, int max, int value)
{
auto range = max - min;
while (value >= max)
{
value -= range;
}
while (value < min)
{
value += range;
}
return value;
}
I'd appreciate a trained eye to tell me what I did wrong here. Thanks so much for your time.
Nesting for loops was a terrible idea. I solved the problem by refactoring the code into multiple separate loops that each do 1 thing, rather than fall through each other into deeper levels of hell.
for (int xAxis = 0; xAxis <= 2; xAxis++) //look along x axis
{
x = WrapValue(0, sizeof(squares[0]), x + 1);
if (CheckPos(x, y) != c) //if we don't find the same mark, must not be a horizontal line, otherwise, break out.
{
x = cursorPosX; //reset x
break;
}
else if (xAxis == 2)
{
winConditions = playerTurn ? 0 : 1;
return;
}
}
for (int yAxis = 0; yAxis <= 2; yAxis++) //look along y axis
{
y = WrapValue(0, sizeof(squares[0]), y + 1);
if (CheckPos(x, y) != c)
{
y = cursorPosY;
break;
}
else if (yAxis == 2)
{
winConditions = playerTurn ? 0 : 1;
return;
}
}
...ect
This violates DRY, but it does work the way it's supposed to, I'm sure I can simplify it later.
While I'm not entirely sure why the previous way didn't work, I do realize that it was just bad design to start with.
I wrote the following code to find whether a point is inside a polygon or not -- the algorithm using crossing number and winding number tests. However, I find that these tests fail when my polygon is: (10,10),(10,20),(20,20) and (20,10) and the point which I want to find whether it is in the polygon is: (20,15). My points here represent the (latitude, longitude) of locations.
(20,15) lies on the boundary, therefore should be inside the polygon
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
typedef struct {int x, y;} Pt;
inline int
isLeft( Pt P0, Pt P1, Pt P2 )
{
return ( (P1.x - P0.x) * (P2.y - P0.y)
- (P2.x - P0.x) * (P1.y - P0.y) );
}
int crossingNumTest( Pt P, Pt* V, int n )
{
int cn = 0;
for (int i=0; i<n; i++) {
if (((V[i].y <= P.y) && (V[i+1].y > P.y))
|| ((V[i].y > P.y) && (V[i+1].y <= P.y))) {
float vt = (float)(P.y - V[i].y) / (V[i+1].y - V[i].y);
if (P.x < V[i].x + vt * (V[i+1].x - V[i].x))
++cn;
}
}
return (cn&1);
}
int windingNumTest( Pt P, Pt* V, int n )
{
int wn = 0;
for (int i=0; i<n; i++) {
if (V[i].y <= P.y) {
if (V[i+1].y > P.y)
if (isLeft( V[i], V[i+1], P) > 0)
++wn;
}
else {
if (V[i+1].y <= P.y)
if (isLeft( V[i], V[i+1], P) < 0)
--wn;
}
}
return wn;
}
//===================================================================
int main(int argc, char** argv) {
Pt arr[11];
arr[0].x=10;
arr[0].y=10;
arr[1].x=10;
arr[1].y=20;
arr[2].x=20;
arr[2].y=20;
arr[3].x=20;
arr[3].y=10;
Pt test;
test.x=20; test.y=15;
cout<<"1.polygon inside="<<crossingNumTest(test,arr,4)<<"\n";
cout<<"2.polygon inside="<<windingNumTest(test,arr,4)<<"\n";
return (EXIT_SUCCESS);
}
This is most likely a floating point accuracy issue.
The point you are checking is exactly on the line of the polygon, so it's quite possible that floating point is not able to represent that correctly and shows it as being outside when it is not.
You can either accept this behavior or add a small error tolerance on your checking. See What is the most effective way for float and double comparison? for a bigger picture. Effectively you need to identify the tolerance you will accept and expand your polygon a tiny amount when checking.
No need for float and incur potential rounding issues.
Stay with exact (likely faster) integer math. Reform test to mathematically equivalent.
(Note: no divide by 0 possible with this new approach as no division is done)
// float vt = (float)(P.y - V[i].y) / (V[i+1].y - V[i].y);
// if (P.x < V[i].x + vt * (V[i+1].x - V[i].x)) ++cn;
// Note: Use long long math if needed
int dy0 = P.y - V[i].y;
int dy1 = V[i+1].y - V[i].y;
int dx0 = P.x - V[i].x;
int dx1 = (V[i+1].x - V[i].x;
if (dy1*dx0 < dy0*dx1) ++cn;
[Edit] #user3629249 comment points out an array access violation. Suggest:
int crossingNumTest( Pt P, Pt* V, int n ) {
// for (int i=0; i<n; i++) {
for (int i=1; i<n; i++) {
// if (((V[i].y <= P.y) && (V[i+1].y > P.y))
if (((V[i-1].y <= P.y) && (V[i].y > P.y))
...
}
I have started to study algorithms and software development and, as a small self evaluation project I have decided to write the A* search algorithm in C++. It uses Qt and OpenGL for the visual part (but that is not important).
Using mostly this source:
A* Pathfinding for Beginners
I have write a small app, however I am have found a bug that I cant fix. It appears that for some reason the parent of a node close to the wall is set to the wall.(?) And the parent of the wall is set to the the start point(?) because of the way I am storing the info.
I have used a stateMatrix[][] where
1 = entrance green;
2 = exit;
3 = wall and;
4 = path;
I have also used matrix to represent openNodes and closedNode. The closedNodes matrix is bool matrix the openNode matrix also stores some info:
The openNodes instructions are:
openNodes[100][100][6];
0 - bool open or closed
1 - F
2 - G
3 - H
4 - parentX
5 - parentY
I know that there are better ways to code this but I have not yet got to this lesson ;)
Here is the code of the astar file:
#include <math.h>
#include "apath.h"
aPath::aPath()
{
gridSize = 100;
int i, j, k;
for(i = 0; i < gridSize; i++)
for(j = 0; j < gridSize; j++)
{
stateMatrix[i][j] = 0;
for(int k = 0; k < 6; k++) openNodes[i][j][k] = 0;
closedNodes[i][j] = 0;
}
targetX = targetY =
openX = openY = entranceX = entranceY = 0;
}
void aPath::start()
{
bool testOK = false;
int G = 0;
openNodes[entranceX][entranceY][0] = 1;
openNodes[entranceX][entranceY][2] = 14;
openNodes[entranceX][entranceY][3] = euclidean(entranceX,
entranceY);
openNodes[entranceX][entranceY][1] =
openNodes[entranceX][entranceY][2] +
openNodes[entranceX][entranceY][3];
openNodes[entranceX][entranceY][4] = entranceX;
openNodes[entranceX][entranceY][5] = entranceY;
int i, j, x, y;
while(closedNodes[targetX][targetY] == 0)
{
searchLessOpen();
closedNodes[openX][openY] = 1;
openNodes[openX][openY][0] = 0;
//Check the 8 squares around
for(i = openX - 1; i <= openX + 1; i++)
for(j = openY - 1; j <= openY + 1; j++)
{
//check if the square is in the limits,
//is not a wall and is not in the closed list
if((i >= 0) && (j >= 0) &&
(i < gridSize) && (j < gridSize) &&
(stateMatrix[i][j] != 3) &&
(closedNodes[i][j] == 0))
{
//G calculus. If it is in the edge it costs more
x = i - openX + 1;
y = j - openY + 1;
if((x == 0 && y == 0) ||
(x == 0 && y == 2) ||
(x == 2 && y == 0) ||
(x == 2 && y == 2))
{
G = 14;
}
else G = 10;
//check if node is already open
if(openNodes[i][j][0] == 0)
{
openNodes[i][j][0] = 1;
openNodes[i][j][2] = G;
openNodes[i][j][3] = euclidean(i,j);
openNodes[i][j][1] = openNodes[i][j][2] + openNodes[i][j][3];
openNodes[i][j][4] = openX;
openNodes[i][j][5] = openY;
}
else //if node is open, check if this path is better
{
if(G < openNodes[i][j][2])
{
openNodes[i][j][2] = G;
openNodes[i][j][1] = openNodes[i][j][2] + openNodes[i][j][3];
openNodes[i][j][4] = openX;
openNodes[i][j][5] = openY;
}
}
}
}
}
reconstruct();
}
void aPath::reconstruct()
{
bool test = false;
int x = openNodes[targetX][targetY][4];
int y = openNodes[targetX][targetY][5];
do
{
stateMatrix[x][y] = 4;
x = openNodes[x][y][4];
y = openNodes[x][y][5];
if(x == entranceX && y == entranceY) test = true;
} while(test == false);
}
int aPath::euclidean(int currentX, int currentY)
{
int dx = targetX - currentX;
int dy = targetY - currentY;
return 10*sqrt((dx*dx)+(dy*dy));
}
void aPath::searchLessOpen()
{
int F = 1000000;
int i, j;
for(i = 0; i < gridSize; i++)
for(j = 0; j < gridSize; j++)
{
if(openNodes[i][j][0] == 1)
{
if(openNodes[i][j][1] <= F)
{
F = openNodes[i][j][1];
openX = i;
openY = j;
}
}
}
}
Does anyone know what I am doing wrong?
Thanks.
Edit: Here are some pictures:
In aPath::start(), you have:
openNodes[entranceX][entranceY][0] = 1;
openNodes[entranceX][entranceY][2] = 14;
openNodes[entranceX][entranceY][3] = euclidean(entranceX,
entranceY);
openNodes[entranceX][entranceY][3] =
openNodes[entranceX][entranceY][2] +
openNodes[entranceX][entranceY][3];
openNodes[entranceX][entranceY][4] = entranceX;
openNodes[entranceX][entranceY][5] = entranceY;
Why is there no value for subscript [1]? And why do you assign two different values to subscript [3]? Also, to be honest, the entranceX and entranceY names are too long for the job they're doing; they make the code less readable (though I'm sure you were told to use good meaningful names). For these array indexes, I'd probably use just x and y.
At the code:
//Check the 8 squares around
for(i = openX - 1; i <= openX + 1; i++)
for(j = openY - 1; j <= openY + 1; j++)
{
I would probably ensure that neither i nor j took on invalid values with code such as:
//Check the 8 squares around (openX, openY)
int minX = max(openX - 1, 0);
int maxX = min(openX + 1, gridsize);
int minY = max(openY - 1, 0);
int maxY = min(openY + 1, gridsize);
for (i = minX; i <= maxX; i++)
for (j = minY; j <= maxY; j++)
{
I am not sure whether you need to explicitly check for the case where i == openX && j == openY (the current cell); it is not one of the 8 cells around the current cell (because it is the current cell), but the other conditions may already deal with that. If not:
if (i == openX && j == openY)
continue;
I note that we have no definitions of openX and openY or a number of other non-local variables. This makes it hard to work out whether they are class member variables or global variables of some sort. We also can't see how they're initialized, nor the documentation on what they represent.
Most plausible source of trouble
In aPath::SearchLessOpen(), you have:
if(openNodes[i][j][0] == 1)
{
if(openNodes[i][j][6] <= F)
{
F = openNodes[i][j][7];
You indicated in your description that the subscripts on openNodes in the last place ranged over 0..5; your code, though, is accessing subscripts 6 and 7. This could easily lead to the sort of confusion you describe - you are accessing data out of bounds. I think this might easily be the root of your trouble. When you access openNodes[i][j][6], this is technically undefined behaviour, but the most likely result is that it is reading the same data as if you'd written openNodes[i][j+1][0] (when j < gridsize - 1). Similarly, openNodes[i][j][7] is equivalent to accessing openNodes[i][j+1][1], with the same caveats.