sorting vector of pointers by two parameters - c++

I am trying to sort a vector of pointers to a class A using std::sort, but am having some difficulties.
Imagine class A beings just a point, containing x and y coordinates. I want to sort the vector by y coordinates from biggest to lowest using some fixed offset value. And on top of this I want to sort it by x coordinatex, from lowest to biggest. I've had something like following in mind but as you can imagine its not working as wanted:
bool A::sortByCoordinates(const A *a, const A *b)
{
if ((b->y < a->y - offset) || (b->y > a->y + offset)) {
return false;
} else if (b->x < a->x) {
return true;
}
return false;
}
void A::recalculate(std::vector<A *> &test)
{
std::sort(test.begin(), test.end(), sortByCoordinates);
}
In short, if b->y < a->y - offset or b->y > a->y + offset treat it as b->y == a->y and then sort by their x coordinates from lowest to biggest. If the above is not true sort it as b->y < a->y.
How can I achieve this?
EDIT:
Imagine a xy plane such as this:
where black dots represent class A with x and y coordinates. I want to split this plane into finitely many sections which are represented by the red lines and are wide as offset. Now I want to treat points in these sections as tho they had the same y coordinate and sort them only by their x coordinate.

(b->y < a->y - offset) || (b->y > a->y + offset)
These are two different cases, which should have different results. I suppose that b is "less" then a in first case, and "greater" in the other case, but your code returns false for both cases. See #Jonathan's answer on how to fix this.
But also note a that your approach (considering all y's that differ by less than offset equal) has a major flaw: it will not generate a strict total order. Assume you have offset=3 and three points A(x=0,y=0), B(x=-2,y=2) and C(x=-4,y=4).
You will have A and B falling within offset by y coordinate so you will compare A.x and B.x and get A<B. Similarly you get B<C, but A and C do not fall within offset distance, so you get A>C, that is A<B<C<A, which should never be. (Tweak the coordinates if I get your ordering wrong). Therefore you first need to reconsider your ordering concept.
If (as you specify in the edit) you want to divide into horizontal stripes, and sort points within a stripe by x, then you should not check whether the ys differ by no more than offset, because two points can have their ys differ by less then offset, but still be located in different stripes. I would suggest to explicitly calculate the stripe number and compare them, something like
bool A::sortByCoordinates(const A& a, const A& b)
{
// get stripe numbers, assuming A::y to be positive int
int stripeA = a.y / offset; // be careful if a.y can be negative!
int stripeB = b.y / offset;
if (stripeA != stripeB)
return stripeA < stripeB;
return a.x < b.x;
}

Related

How to optimize the sorting of a vector with coordinates based on distance?

I need to sort a vector of coordinates (x, y >= 1) in a way that every next point from the vector is the closest one to the previous by calculating the distance with the formula from getDistance().
My current solution is too slow as I need the program to be able to finish in 5 seconds or less with vector length (N) equal to 100 000.
struct Point {
int ind;
int x;
int y;
double dist;
};
double getDist(int x1, int y1, int x2, int y2) {
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
vector<Point> cordSort(vector<Point> vect) {
vector<Point> finalDistVect;
finalDistVect.push_back(vect[0]);
Point firstPoint = vect[0];
vect.erase(vect.begin());
for (i = 0; i < pcVect.size() - 1; i++) {
sort(vect.begin(), vect.end(), [firstPoint](const Point & a, const Point & b) {
return getDist(firstPoint.x, firstPoint.y, a.x, a.y) < getDist(firstPoint.x, firstPoint.y, b.x, b.y);
});
finalDistVect.push_back(vect[0]);
finalDistVect[i].dist = getDist(firstPoint.x, firstPoint.y, vect[0].x, vect[0].y);
firstPoint = vect[0];
vect.erase(vect.begin());
}
return finalDistVect;
}
vect is the initial vector with coordinates sorted by:
sort(vect.begin(), vect.end(), [](const Point & a, const Point & b) {
if (a.x + a.y != b.x + b.y) {
return a.x + a.y < b.x + b.y;
}
return a.x < b.x;
});
I am thinking about implementing bucket sort but I don't know if it will work for my problem.
your implementation indeed increase inefficiency by repeatedly erase the first element from a vector. std::vector is not designed to be used to frequently erase elements from other the back.
Not sure if I read your algorithm correctly. The first element is predetermined as the first element of the input, then your program repeatedly find the points that has shortest distance from the last element (point) in the output point vector.
If that's the case, it has no benefit to sort at all.
A naive algorithm is like bubbling:
1. add first point to outputVector, add all rest to openSet;
2. if openSet is empty, we are done.
3. take the last point from output Vector, check with all points in `openSet`, to find the one with shortest distance from it, add it to outputVector, remove it from openSet;
4. goto 2
Basically I am recommending you do use a std::set to keep track of openset, or maybe even better, std::unordered_set.
Another way is to do it in place, just swap the chosen points with the one who is taking its place.
e.g. we have P0, P1, P2, P3, P4 as input in a vector
1. int pos = 1; // P0 is in right place, we are looking for
// the point that shall go to index 1;
2. check all points from index `pos` to `4`(which is the max index) and find the one with shortest distance from `P0`, let's say we get `P4`;
3. swap `P0` (the one at index `pos`) and `P4` (the chosen one);
4. ++ pos;
5. if pos!=4(max index), goto 2.
We are using pos to keep track of sorted and open and do it in place.
This is not a sorting problem, you have to come up with a different algorithm. For example, there may be no solution at all, which would not be the case for a sorting problem.
Consider four points on a single line: A=(1, 1), B=(100, 1), C=(101, 1), D=(1000, 1). Point D is not the closest point for any other point, so it should come first. Then we should put C, followed by B, and now we cannot put A because the closest point to B is actually C, not A.
And even if it was, you should come up with a faster algorithm. You have N iterations of the for loop, each iteration looks for the smallest element among N other elements, which is already at least O(N^2). Using sort instead of min_element makes it even worse: O(N^2 log N). This won't fly for N ~ 100'000 at all in competitive programming/home assignments.

What is wrong with my intersection checking algorithm?

I know there are many sites which explain how to check for an intersection of two lines, but I find it utterly boring to just copy and paste code for such a simple mathematical task. The more it frustrates me that I cannot get my code to work. I know questions with "What is wrong in my code?" are stupid, but I don't know what the hell is wrong with my mathematics / code, also my code is documented nicely (except of admittedly bad variable naming), so I guess there should be someone who is interested in the math behind it:
bool segment::checkforIntersection(QPointF a, QPointF b) { //line 1: a+bx, line 2: c+dx, note that a and c are called offset and bx and dx are called gradients in this code
QPointF bx = b-a;
double firstGradient = bx.y() / bx.x(); //gradient of line 1
//now we have to calculate the offset of line 1: we have b from a+bx. Since QPointF a is on that line, it is:
//a + b * a.x = a.y with a as free variable, which yields a = a.y - b*a.x.
//One could also use the second point b for this calculation.
double firstOffset = a.y() - firstGradient * a.x();
double secondGradient, secondOffset;
for (int i = 0; i < poscount-3; i++) { //we dont check with the last line, because that could be the same line, as the one that emited intersection checking
QPointF c = pos[i];
QPointF d = pos[i+1];
QPointF dx = d-c;
secondGradient = dx.y() / dx.x(); //same formula as above
secondOffset = c.y() - secondGradient * c.x();
//a+bx=c+dx <=> a-c = (d-b)x <=> (a-c)/(d-b) = x
double x = (firstOffset - secondOffset) / (secondGradient - firstGradient);
//we have to check, if those lines intersect with a x \in [a.x,b.x] and x \in [c.x,d.x]. If this is the case, we have a collision
if (x >= a.x() && x <= b.x() && x >= c.x() && x <= d.x()) {
return true;
}
}
return false;
}
So what this does, it has 4 points a, b, c, d (line 1: a--b, line 2: c--d) (ignore the for loop) which have an absolute x and y value. First it calculates the gradient of the lines by calculating deltay/deltax. Then it calculates the offset by using the fact that point a (or c respectively) are on the lines. This way we transformed the 4 points into mathematical representation of these lines as equation a+bx, whereas a x of 0 means that we are at the first point (a / c) and a x of 1 means that we are on the second point (b/d). Next we calculate the intersection of those two lines (basic algebra). After that we check if the intersection's x value is valid. To my understanding this is all correct. Does anyone see the error?
This was empirically checked to be incorrect. The code does not give any false Positives (says there is an intersection, when there isn't), but it gives false Negatives (says there is no intersection, when there actually is). So when it says there is an Intersection it is correct, however if it says there is no intersection, you cannot always believe my algorithm.
Again, I checked online, but the algorithms are different (with some orientation tricks and something), I just wanted to come up with my own algorithm, I would be so glad if someone could help. :)
Edit: Here is a minimal reproducable not working example, this time without Qt but with C++ only:
#include <iostream>
#include <math.h>
using namespace std;
class Point {
private:
double xval, yval;
public:
// Constructor uses default arguments to allow calling with zero, one,
// or two values.
Point(double x = 0.0, double y = 0.0) {
xval = x;
yval = y;
}
// Extractors.
double x() { return xval; }
double y() { return yval; }
Point sub(Point b)
{
return Point(xval - b.xval, yval - b.yval);
}
};
bool checkforIntersection(Point a, Point b, Point c, Point d) { //line 1: a+bx, line 2: c+dx, note that a and c are called offset and bx and dx are called gradients in this code
Point bx = b.sub(a);
double firstGradient = bx.y() / bx.x(); //gradient of line 1
//now we have to calculate the offset of line 1: we have b from a+bx. Since Point a is on that line, it is:
//a + b * a.x = a.y with a as free variable, which yields a = a.y - b*a.x.
//One could also use the second point b for this calculation.
double firstOffset = a.y() - firstGradient * a.x();
double secondGradient, secondOffset;
Point dx = d.sub(c);
secondGradient = dx.y() / dx.x(); //same formula as above
secondOffset = c.y() - secondGradient * c.x();
//a+bx=c+dx <=> a-c = (d-b)x <=> (a-c)/(d-b) = x
double x = (firstOffset - secondOffset) / (secondGradient - firstGradient);
//we have to check, if those lines intersect with a x \in [a.x,b.x] and x \in [c.x,d.x]. If this is the case, we have a collision
if (x >= a.x() && x <= b.x() && x >= c.x() && x <= d.x()) {
return true;
}
return false;
}
int main(int argc, char const *argv[]) {
if (checkforIntersection(Point(310.374,835.171),Point(290.434,802.354), Point(333.847,807.232), Point(301.03,827.172)) == true) {
cout << "These lines do intersect so I should be printed out\n";
} else {
cout << "The algorithm does not work, so instead I do get printed out\n";
}
return 0;
}
So as example I took the points ~ (310,835) -- (290,802), and (333,807) -- (301,827). These lines do intersect:
\documentclass[crop,tikz]{standalone}
\begin{document}
\begin{tikzpicture}[x=.1cm,y=.1cm]
\draw (310,835) -- (290,802);
\draw (333,807) -- (301,827);
\end{tikzpicture}
\end{document}
Proof of intersection
However when running the above C++ code, it says that they do not intersect
(you may call me a pedant, but the terminology is important)
If you want to see if the line segments intersect, then rely on the parametric representation of your two segments, solve the system in the two parameters and see if both of the solution for both of the parameters falls into [0,1] range.
Parametric representation for segment [a, b], component-wise
{x, y}(t) = {(1-t)*ax+t*bx, (1-t)*ay+t*by} with t in the [0,1] range
Quick check - at t=0 you get a, at t=1 you get b, the expression is linear in t, so there you have it.
So, your (a,b) (c,d) intersection problem becomes:
// for some t1 and t2, the x coordinate is the same
(1-t1)*ax+t*bx=(1-t2)*cx+t2*dx;
(1-t1)*ay+t*by=(1-t2)*cy+t2*dy; // and so is the y coordinate
Solve the system in t1 and t2. If t1 is in the [0,1] range, then the intersection lies between a and b, the same goes for t2 in respect with c and d.
It is left as an exercise for the reader the study of what effects will have on the system above the following conditions and what checks should be implemented for a robust algorithm:
segment degeneracy - coincident ends for one or both segments
collinear segments with non-void overlap. Particular case when there's a single point of overlap (necessary, that point will be one of the ends)
collinear segments with no overlap
parallel segments
First it calculates the gradient of the lines by calculating deltay/deltax.
And what happens when deltax is very close to zero?
Look, what you are doing is exposing yourself to ill-conditioned situations - always fear divisions and straight comparison with 0.0 when it comes to computational geometry.
Alternative:
two lines will intersect if they are not parallel
two distinct lines will be parallel if their definition vectors will have a zero cross-product.
Cross-product of your (a,b) x (c,d) = (ax-bx)*(cy-dy)-(ay-by)*(cx-dx) - if this is close enough to zero, for all practical purposes there's no intersection between your lines (the intersection is so far away it doesn't matter).
Now, what remains to be said:
there will need to be a "are those line distinct?" test before going into computing the cross-product. Even more, you will need to treat degenerate cases (one or both of the lines are reduced to a point by coincident ends - like a==b and/or c==d)
the "close enough to zero" test is ambiguous if you don't normalize your definition vectors - imagine a 1 lightsecond-length vector defining the first line and a 1 parsec-length vector for the other (What test for 'proximity to zero' should you use in this case?) To normalize the two vectors, just apply a division ... (a division you say? I'm already shaking with fear) ... mmm.. I was saying to divide the resulted cross-product with hypot(ax-bx, ay-by)*hypot(cx-dx,cy-dy) (do you see why the degeneracy cases need to be treated in advance?)
after the normalization, once again, what would be a good 'proximity to zero' test for the resulted cross-product? Well, I think I can go on with the analysis for another hour or so (e.g. how far the intersection would be when compared with the extent of your {a,b,c,d} polygon), but... since the cross-product of two unitary vectors (after normalization) is sin(angle-between-versors), you may use your common sense and say 'if the angle is less that 1 degree, will this be good enough to consider the two lines parallel? No? What about 1 arcsecond?"

Points on the same line

I was doing a practice question and it was something like this,We are given N pair of coordinates (x,y) and we are given a central point too which is (x0,y0).We were asked to find maximum number of points lying on a line passing from (x0,y0).
My approach:- I tried to maintain a hash map having slope as the key and I thought to get the maximum second value to get maximum number of points on the same line.Something like this
mp[(yi-y0)/(xi-x0))]++; //i from 0 to n
And iterating map and doing something line this
if(it->second >max) //it is the iterator
max=it->second;
and printing max at last;
Problem With my approach- Whenever I get (xi-x0) as 0 I get runtime error.I also tried atan(slope) so that i would get degrees instead of some not defined value but still its not working.
What i expect->How to remove this runtime error and is my approach correct for finding maximum points on a line passing from a point(x0,y0).
P.S -My native language is not english so please ignore if something goes wrong.I tried my best to make everything clear If i am not clear enough please tell me
I'm assuming no other points have the same coordinates as your "origin".
If all your coordinates happen to be integers, you can keep a rational number (i.e. a pair of integers, i.e. a numerator and a denominator) as the slope, instead of a single real number.
The slope is DeltaY / DeltaX, so all you have to do is keep the pair of numbers separate. You just need to take care to divide the pair by their greatest common divisor, and handle the case where DeltaX is zero. For example:
pair<int, int> CalcSlope (int x0, int y0, int x1, int y1)
{
int dx = abs(x1 - x0), dy = abs(y1 - y0);
int g = GCD(dx, dy);
return {dy / g, dx / g};
}
Now just use the return value of CalcSlope() as your map key.
In case you need it, here's one way to calculate the GCD:
int GCD (int a, int b)
{
if (0 == b) return a;
else return gcd(b, a % b);
}
You have already accepted an answer, but I would like to share my approach anyway. This method uses the fact that three points a, b, and c are covariant if and only if
(a.first-c.first)*(b.second-c.second) - (a.second-c.second)*(b.first-c.first) == 0
You can use this property to create a custom comparison object like this
struct comparePoints {
comparePoints(int x0 = 0, int y0 = 0) : _x0(x0), _y0(y0) {}
bool operator()(const point& a, const point& b) {
return (a.first-_x0)*(b.second-_y0) - (b.first-_x0)*(a.second-_y0) < 0;
}
private:
int _x0, _y0;
};
which you can then use as a comparison object of a map according to
comparePoints comparator(x0, y0);
map<pair<int, int>, int, comparePoints> counter(comparator);
You can then add points to this map similar to what you did before:
if (!(x == x0 && y == y0))
counter[{x,y}]++;
By using comparitor as a comparison object, two keys a, b in the map are considered equal if !comparator(a, b) && !comparator(b,a), which is true if and only if a, b and {x0,y0} are collinear.
The advantage of this method is that you don't need to divide the coordinates which avoids rounding errors and problems with dividing by zero, or calculate the atan which is a costly operation.
Move everything so that the zero point is at the origin:
(xi, yi) -= (x0, y0)
Then for each point (xi, yi), find the greatest common divisor of xi and yi and divide both numbers by it:
k = GCD(xi, yi)
(xi', yi`) = (yi/k, yi/k)
Now points that are on the same ray will map to equal points. If (xi, yi) is on the same ray as (xj, yj) then (xi', yi') = (xj', yj').
Now find the largest set of equal points (don't forget any (xi, yi) = (0, 0)) and you have your answer.
You've a very original approach here !
Nevertheless, a vertical line has a infinite slope and this is the problem here: dividing by 0 is not allowed.
Alternative built on your solution (slope):
...
int mpvertical=0; // a separate couner for verticals
if (xi-x0)
mp[(yi-y0)/(xi-x0))]++;
else if (yi-y0)
mpvertical++;
// else the point (xi,yi) is the point (x0,y0): it shall not be counted)
This is cumbersome, because you have everything in the map plus this extra counter. But it will be exact. A workaround could be to count such points in mp[std::numeric_limits<double>::max()], but this would be an approximation.
Remark: the case were xi==x0 AND yi==y0 corresponds to your origin point. These points have to be discarded as they belong to every line line.
Trigonomic alternative (angle):
This uses the general atan2 formula used to converting cartesian coordinates into polar coordinates, to get the angle:
if (xi!=x0 && yi!=y0) // the other case can be ignored
mp[ 2*atan((yi-y0)/((xi-x0)+sqrt(pow(xi-x0,2)+pow(yi-y0,2)))) ]++;
so your key for mp will be an angle between -pi and +pi. No more extra case, but slightly more calculations.
You can hide these extra details and use the slighltly more optimized build in function:
if (xi!=x0 && yi!=y0) // the other case can be ignored
mp[ atan2(yi-y0, xi-x0) ]++;
you can give this approach a try
struct vec2
{
vec2(float a,float b):x(a),y(b){}
float x,y;
};
bool isColinear(vec2 a, vec2 b, vec2 c)
{
return fabs((a.y-b.y)*(a.x-c.x) - (a.y-c.y)*(a.x-b.x)) <= 0.000001 ;
}

Determining if a set of points are inside or outside a square

I have two of these:
bool isPointOnShape(int a, int b)
{
}
bool isPointInShape(int a, int b)
{
}
Say I have a square, first point (bottom left corner) is x,y (0,0) second point (top left) is (0,2), third is (2,2) and fourth is (0,2).
The Points on shape would be (0,1) (1,2) (2,1) (1,0) and Points in shape is (1,1)
How do I find out the points on shape / in shape and return a true value so that I can store it somewhere?
I'll offer a general solution for any shape that can be divided in straight segments.
So, as you may have guessed, I'll start by consider your "shape" as a list of segments that completes a loop. Or simply put a circular list of points that represents a loop, for example, your square would be this list of points:
0, 0
0, 2
2, 2
2, 0
Note that we consider that there are segments from each point to the next and that the final point connects to the first. Also, we require that no consecutive points are equal, nor the first and last. If there are any, those must be removed before proceeding.
Now, for each segment we can determinate the bounding box. For example given this segment:
a = (0, 2)
b = (2, 2)
Then the range of values in x is [0, 2] and in y is [2, 2] and that is your bounding box for that segment.
The next thing you need is the director vector of the line of the segment. To get that, first calculate the length of the segment:
length = sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y))
And then:
director.x = (a.x - b.x)/length
director.y = (a.y - b.y)/length
Note 1: when then length is 0, then you have an invalid segment. That's why we don't want repeated points.
Note 2: Using the director vector instead of using the equation of the line will make things easier.
Now, given a point p, you can determinate if that point is in a segment (if it is one of the points in the list). For the rest of cases we start by looking if it is inside of the axis aligned bounding box. This is done simply by checking the range:
if
(
(p.x >= box.left && p.x <= box.right) &&
(p.y >= box.top && p.y <= box.bottom) // with origin at the top-left corner
)
{
//It is inside of the bounding box
}
And if it is, then we calculate the distance from the point to the line, if it is
0 then it is on the line. Now, because of floating point arithmetics, you could test if the distance is less or equal to epsilon, where epsilon is a very small number.
We use this formula:
distance vector = (a - p) - ((a - p) · director) * director
distance = the norm of distance vector
Where "·" denotes a dot product and "*" denotes an scalar product.
All that rests is to iterate over the segments, for each one calculate the distance and if for anyone the distance is less than epsilon then the point is "on the shape".
Ok, but what about "in the shape"?
Well, with a little help of a trick from topology we can determinate if a point is inside or not. This is the same algorithm Windows would use to fill a polygon or polyline (such as deciding what is inside a selected area with free hand in Microsoft Paint).
It goes like this:
Count the number of segments you have to cross to get to the point from outside. If the number is pair, then it is outside, if it is odd then inside.
You can choose from what direction to reach the point. I choose left.
Once more, you are going to iterate over the segments. For each one we need to decide if it is at the vertical range. For that use the bounding box:
if ((p.y >= box.top && p.y <= box.bottom))
{
//In the vertical range
}
Now, determinate if the segment is at left, or right:
if (p.x < box.left)
{
//The segment is at the left
}
else if (p.x > box.right)
{
//The segment is at the right
}
else
{
//The segment is close, need further calculation
}
In the case that the segment is close we need to calculate the vector distance to that segment and check it's direction.
The vector distance? Well, we already have it, we are taking its norm to determinate the distance. Now, instead of taking the norm, verify the sign of the x coordinate. If it is less than 0, it is right, if it is more than 0 then it is left. If it is 0... it means that the segment is horizontal (because the distance vector is always perpendicular to the segment), you can skip that segment*.
*: In fact, if the segment is horizontal and it is in vertical range, it means that it is at the segment. Are segments "in shape" or not?
Now, you need to count the number of segments at the left, and if it odd, the point is inside the shape. It is out otherwise. This can also be done with the segments that are up, or right, or below. I just picked left.
For large shapes where iterating over all the segments is expensive, you can store the segments in some space partitioning data structure. That is beyond the scope of this post.
If I suppose you have a Rectangle class and that this class has members bottomLeft and topRight, you can write something like this:
bool Rectangle::isPointOnShape(int x, int y) {
if (x == bottomLeft.x || x == topRight.x)
if (y > bottomLeft.y && y < topRight.y)
return true;
if (y == bottomLeft.y || y == topRight.y)
if (x > bottomLeft.x && x < topRight.x)
return true;
}
bool Rectangle::isPointInShape(int x, int y) {
bool inX = false;
bool inY = false;
if (x > bottomLeft.x && x < topRight.x)
inX = true;
if (y > bottomLeft.y && y < topRight.y)
inY = true;
return (inX && inY);
}
If your shape is not a rectangle, this functions will be different of course.

Polygon in rectangle algorithm?

I have an algorithm which can find if a point is in a given 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;
}
given this, how could I make it check if its within a rectangle defind by Ptopleft and Pbottomright instead of a single point?
Thanks
Basically you know how in Adobe Illustrator you can drag to select all objects that fall within the selection rectangle? well I mean that. –
Can't you just find the minimum and maximum x and y values among the points of the polygon and check to see if any of the values are outside the rectangle's dimensions?
EDIT: duh, I misinterpreted the question. If you want to ensure that the polygon is encosed by a rectangle, do a check for each polygon point. You can do that more cheaply with the minimum/maximum x and y coordinates and checking if that rectangle is within the query rectangle.
EDIT2: Oops, meant horizontal, not vertical edges.
EDIT3: Oops #2, it does handle horizontal edges by avoiding checking edges that are horizontal. If you cross multiply however, you can avoid the special casing as well.
int isPointInRect( Point point, Point ptopleft, Point pbottomright) {
float xp[2] ;
xp[0] = ptopleft.x,
xp[1] = pbottomright.x;
float yp[2] ;
yp[0] = ptopleft.y ;
yp[1] = pbottomright.y ;
return CGlEngineFunctions::PointInPoly(2, xp, yp, point.x, point.y);
}
As mentioned before, for that specific problem, this function is an overkill. However, if you are required to use it, note that:
1. It works only for convex polygons,
2. The arrays holding the polygon's vertices must be sorted such that consecutive points in the array relate to adjacent vertices of your polygon.
3. To work properly, the vertices must be ordered in the "right hand rule" order. That means that when you start "walking" along the edges, you only make left turns.
That said, I think there is an error in the implementation. Instead of:
// c initialized to 0 (false), then...
c = !c;
you should have something like:
// c initialized to 1 (true), then...
// negate your condition:
if ( ! (....))
c = 0;