This question already has answers here:
How to determine if a point is in a 2D triangle? [closed]
(25 answers)
Closed 9 years ago.
I am working on an assignment in which we are given a (my_x,my_y) coordinate and we have to tell whether this coordinate lies in the free space or inside an obstacle.
As you can see, from the picture, I have to tell whether a certain point lies among any of the obstacle.
Checking for out of boundary is easy and simple.
Similarly I check for circle as (pseudo code):
if sqrt((my_x-5)^2+(my_y-3.5)^2) <= 0.5
this means it is inside circle.
if ((my_x >= 3.5 || my_x <= 6.5) && ((my_y >= 5 || my_y <= 6)
this means it is inside rectangle.
However I am stuck for the triangle case. The main reason is that my_x and my_y are of decimal type and can take any value suppose up to 2 decimal figures. Now one was is to have several if conditions and then check each.
I want to know is there is some better algorithm to define the triangle may be using equations and what it might be.
You can you the concept of vector products to find if a point is inside a triangle or not :-
suppose point is (x,y) which you need to check. (x1,y1),(x2,y2),(x3,y3) are three vertices of the triangle. then each triple ((x1,y1),(x2,y2),(x,y)),((x2,y2),(x3,y3),(x,y)),((x3,y3),(x1,y1),(x,y)) are of same sign.
vector product of (x1,y1),(x2,y2),(x,y)
vp = (x-x2)*(y1-y2) - (y-y2)*(x1-x2)
Hence using same equation for all triples :-
sign1 = sign((x-x2)*(y1-y2) - (y-y2)*(x1-x2))
sign2 = sign((x-x3)*(y2-y3) - (y-y3)*(x2-x3))
sign3 = sign((x-x1)*(y3-y1) - (y-y1)*(x3-x1))
if(sign1==sign2==sign3) { //inside
return(true);
}
else return(false) // outside
Related
I'm given rectangle by it's height(h) and width(w), and it's center O(x0,y0). I need to calculate if given point A(x,y) is inside that rectangle. It is parallel to x and y axis. All values are real.
I came up with following test but for some reason website on which I'm testing the code is not working for all examples. Could someone point me in the right direction.
#include <iostream>
#include <cmath>
using namespace std;
int main(){
long x,y,x0,y0,r,h,w;
scanf("%ld",&x);
scanf("%ld",&y);
scanf("%ld",&x0);
scanf("%ld",&y0);
scanf("%ld",&h);
scanf("%ld",&w);
if((x0+w/2.0>=x)&&(x0-w/2.0<=x)&&(y0+h/2.0>=y)&&(y0-h/2.0<=y))
printf("inside a rectangle");
else
printf("outside a rectangle");
}
Thanks in advance.
After OP's Edit:
The rectangle's side are parallel to x axis and y-axis. Then also it is possible to get the co-ordinates and apply the below mentioned algorithm.
Centre -- (x0,y0)
A -- (x0-w/2,y0-h/2)
B -- (x0-w/2.y0+h/2)
C -- (x0+w/2,y0+h/2)
D -- (x0+w/2,y0-h/2)
So all you have to do is, Apply the algorithms provided below.
More simply we can do this,
if( 2*x <= 2*x0+w && 2*x >= 2*x0-w && 2*y <= 2*y0+h && 2*y >= 2*y0-h)
// it's inside
Before OP's edit
Your logic is wrong. It may say a point inside rectangle to be outside of it.
(For any rectangle this is wrong - OP didn't mention the condition of being sides parallel to x-y axes)
There is a simple way and cleaner way to do this for rectangle. Find the Area of the rectangle.
Suppose it's A.
Now if the point P lies inside ABCD then
area of PAB+PBC+PCD+PDA = A
For better thing do this with ,
AB.Bc+BC.CD+CD.DA+DA.AB = 2*AB*BC
or even better make a square of both side
LHS^2 = 4*AB^2*BC^2
Now you will just multiply and check it. One drawback of this solution is for large values of side length you have a chance of overflow.
Another method would be to consider the projections.
If point is inside of the rectangle then the projection of the corner of rectangle to point, on two of it's side must be less than the corresponding sides. You can check the projection length using dot products.
For example if P is the point and ABCD is rectangle check,
if AP's projection on AB has greater than zero length but less than the length of AB. Check the same with BC and BP and check if length is greater than zero and less than BC or not.
This two condition makes sure that your point lies inside the rectangle.
After reading several posts about getting the 2D transformation of 2D points from one image to another, estimateRigidTransform() seems to be the recommendation. I'm trying to use it. I modified the source code (to change the RANSAC parameters, because its hardcoded, and the hardcoded parameters are not very good)(the source code for this function is in lkpyramid.cpp). I have read up on how RANSAC works, and am trying to understand the steps in estimateRigidTransform().
// choose random 3 non-complanar points from A & B
...
// additional check for non-complanar vectors
a[0] = pA[idx[0]];
a[1] = pA[idx[1]];
a[2] = pA[idx[2]];
b[0] = pB[idx[0]];
b[1] = pB[idx[1]];
b[2] = pB[idx[2]];
double dax1 = a[1].x - a[0].x, day1 = a[1].y - a[0].y;
double dax2 = a[2].x - a[0].x, day2 = a[2].y - a[0].y;
double dbx1 = b[1].x - b[0].x, dby1 = b[1].y - b[0].y;
double dbx2 = b[2].x - b[0].x, dby2 = b[2].y - b[0].y;
const double eps = 0.01;
if( fabs(dax1*day2 - day1*dax2) < eps*std::sqrt(dax1*dax1+day1*day1)*std::sqrt(dax2*dax2+day2*day2) ||
fabs(dbx1*dby2 - dby1*dbx2) < eps*std::sqrt(dbx1*dbx1+dby1*dby1)*std::sqrt(dbx2*dbx2+dby2*dby2) )
continue;
Is it a typo that it uses non-coplanar vectors? I mean the 2D points are all on the same plane right?
My second question is what is that if condition doing? I know that the left hand side (gives the area of triangle times 2) would be zero or near zero if the points are collinear, and the right hand side is the multiplication of the lengths of 2 sides of the triangle.
Collinearity is preserved in affine transformations (such as the one you are probably estimating), but this transformations also calculate also changes in rotations in point of view (as if you rotated the object in a 3d world). However, these points will be collinear as well, so for the algorithm it may have not a unique solution. Look at the pictures:
imagine selecting 3 center points of each black square in the first row in the first image. Then map it to the same centers in the next image. It may generate a mapping to that solution, but also a mapping to a zoom version of the first one. The same may happen with the third one, just that this time may map to a zoom out version of the first one (without any other change). However if the points are not collinear, for example, 3 corner squares centers, it will find a unique mapping.
I hope this helps you to clarify your doubts. If not, leave a comment
I'm trying to work out the best way to determine whether a point is inside a frustum. I have something working, but not sure whether it is too cumbersome, and perhaps there is a more elegant / efficient way I should be doing this.
Suppose I want to find out whether point 'x' is inside a frustrum:
Once I have the locations of the 8 points of the frustrum (4 near points, four far points), I am calculating the normal for each plane of the frustum based on a triangle made from three of the points. For example (as in the diagram above), for the right side, I am making two vectors from three of the points:
Vector U = FBR - NBR
Vector V = FTR - NBR
Then I am making the cross product between these two vectors, ensuring that the winding order is correct for the normal to be pointing inside the frustum, in this case V x U will give the correct normal.
Right_normal = V x U
Once I have the normal for each plane, I am then checking whether point x is in front of or behind the plane by drawing a vector from x to one of the plane's points:
Vector xNBR = x - NBR
Then I am doing the dot product between this vector and the normal and testing whether the answer is positive, confirming whether point x is the correct side of that plane of the frustrum:
if ( xNBR . Right_normal < 0 )
{
return false;
}
else continue testing x against other planes...
If x is positive for all planes, then it is inside the frustum.
So this seems to work, but I'm just wondering whether I'm doing this in a stupid way. I didn't even know what 'cross product' meant until yesterday, so it's all rather new to me and I might be doing something rather silly.
To adapt the approach you have taken, rather than change it totally, you can make use of the fact that 2 of the pairs of planes are parallel. Create only one normal for that pair of planes. You already have the test for the point being "in front" of one of the planes, but assuming you know the depth of the frustum, you can use the same distance to test the point against the other parallel face.
double distancePastFrontPlane = xNBR . Right_normal;
if (distancePastFrontPlane < 0 )
{
// point is in front of front plane
return false;
if(distancePastFrontPlane > depthFaceRtoFaceL)
{
// point is behind back plane
return false;
}
}
If you have multiple points to test against the same frustum you can benefit because you only calculate the frustum depth once (per pair of parallel planes).
This is quite complicated to explain, so I will do my best, sorry if there is anything I missed out, let me know and I will rectify it.
My question is, I have been tasked to draw this shape,
(source: learnersdictionary.com)
This is to be done using C++ to write code that will calculate the points on this shape.
Important details.
User Input - Centre Point (X, Y), number of points to be shown, Font Size (influences radius)
Output - List of co-ordinates on the shape.
The overall aim once I have the points is to put them into a graph on Excel and it will hopefully draw it for me, at the user inputted size!
I know that the maximum Radius is 165mm and the minimum is 35mm. I have decided that my base Font Size shall be 20. I then did some thinking and came up with the equation.
Radius = (Chosen Font Size/20)*130. This is just an estimation, I realise it probably not right, but I thought it could work at least as a template.
I then decided that I should create two different circles, with two different centre points, then link them together to create the shape. I thought that the INSIDE line will have to have a larger Radius and a centre point further along the X-Axis (Y staying constant), as then it could cut into the outside line.
So I defined 2nd Centre point as (X+4, Y). (Again, just estimation, thought it doesn't really matter how far apart they are).
I then decided Radius 2 = (Chosen Font Size/20)*165 (max radius)
So, I have my 2 Radii, and two centre points.
Now to calculate the points on the circles, I am really struggling. I decided the best way to do it would be to create an increment (here is template)
for(int i=0; i<=n; i++) //where 'n' is users chosen number of points
{
//Equation for X point
//Equation for Y Point
cout<<"("<<X<<","<<Y<<")"<<endl;
}
Now, for the life of me, I cannot figure out an equation to calculate the points. I have found equations that involve angles, but as I do not have any, I'm struggling.
I am, in essence, trying to calculate Point 'P' here, except all the way round the circle.
(source: tutorvista.com)
Another point I am thinking may be a problem is imposing limits on the values calculated to only display the values that are on the shape.? Not sure how to chose limits exactly other than to make the outside line a full Half Circle so I have a maximum radius?
So. Does anyone have any hints/tips/links they can share with me on how to proceed exactly?
Thanks again, any problems with the question, sorry will do my best to rectify if you let me know.
Cheers
UPDATE;
R1 = (Font/20)*130;
R2 = (Font/20)*165;
for(X1=0; X1<=n; X1++)
{
Y1 = ((2*Y)+(pow(((4*((pow((X1-X), 2)))+(pow(R1, 2)))), 0.5)))/2;
Y2 = ((2*Y)-(pow(((4*((pow((X1-X), 2)))+(pow(R1, 2)))), 0.5)))/2;
cout<<"("<<X1<<","<<Y1<<")";
cout<<"("<<X1<<","<<Y2<<")";
}
Opinion?
As per Code-Guru's comments on the question, the inner circle looks more like a half circle than the outer. Use the equation in Code-Guru's answer to calculate the points for the inner circle. Then, have a look at this question for how to calculate the radius of a circle which intersects your circle, given the distance (which you can set arbitrarily) and the points of intersection (which you know, because it's a half circle). From this you can draw the outer arc for any given distance, and all you need to do is vary the distance until you produce a shape that you're happy with.
This question may help you to apply Code-Guru's equation.
The equation of a circle is
(x - h)^2 + (y - k)^2 = r^2
With a little bit of algebra, you can iterate x over the range from h to h+r incrementing by some appropriate delta and calculate the two corresponding values of y. This will draw a complete circle.
The next step is to find the x-coordinate for the intersection of the two circles (assuming that the moon shape is defined by two appropriate circles). Again, some algebra and a pencil and paper will help.
More details:
To draw a circle without using polar coordinates and trig, you can do something like this:
for x in h-r to h+r increment by delta
calculate both y coordinates
To calculate the y-coordinates, you need to solve the equation of a circle for y. The easiest way to do this is to transform it into a quadratic equation of the form A*y^2+B*y+C=0 and use the quadratic equation:
(x - h)^2 + (y - k)^2 = r^2
(x - h)^2 + (y - k)^2 - r^2 = 0
(y^2 - 2*k*y + k^2) + (x - h)^2 - r^2 = 0
y^2 - 2*k*y + (k^2 + (x - h)^2 - r^2) = 0
So we have
A = 1
B = -2*k
C = k^2 + (x - h)^2 - r^2
Now plug these into the quadratic equation and chug out the two y-values for each x value in the for loop. (Most likely, you will want to do the calculations in a separate function -- or functions.)
As you can see this is pretty messy. Doing this with trigonometry and angles will be much cleaner.
More thoughts:
Even though there are no angles in the user input described in the question, there is no intrinsic reason why you cannot use them during calculations (unless you have a specific requirement otherwise, say because your teacher told you not to). With that said, using polar coordinates makes this much easier. For a complete circle you can do something like this:
for theta = 0 to 2*PI increment by delta
x = r * cos(theta)
y = r * sin(theta)
To draw an arc, rather than a full circle, you simply change the limits for theta in the for loop. For example, the left-half of the circle goes from PI/2 to 3*PI/2.
This question already has answers here:
How do I efficiently determine if a polygon is convex, non-convex or complex?
(10 answers)
How to check if polygon is convex? [duplicate]
(1 answer)
Closed 9 years ago.
How can i test if a polygon is convex or not only by knowing the points of the polygon
with their coordonates in c++?
For each side of polygon, calculate line equation (Ax+By+C=0) and check (put x and y into equation and get sign of it), that all points are from one side of it.
EDIT:
If travel convex polygon, you will always rotate into one direction (left or right) on every point.
Using cross product, you can simply deduce, onto which side (negative or positive) you will rotate next turn. If all cross products of three consecutive points will have equal sign, then your polygon is convex.
Find the convex hull using any of the common algorithms. A polygon is convex if and only if all its vertices belong to its convex hull.
This is O(n log n) but does not rely on the assumption that the points are given in the proper order around the edges of the polygon. If the assumption is true then the answer from hate-engine is optimal (i.e. linear time.)
the gift wrapping algorithm is an algorithm for computing the convex
hull of a given set of points.
Pseudocode from wiki:
jarvis(S)
pointOnHull = leftmost point in S
i = 0
repeat
P[i] = pointOnHull
endpoint = S[0] // initial endpoint for a candidate edge on the hull
for j from 1 to |S|-1
if (endpoint == pointOnHull) or
(S[j] is on left of line from P[i] to endpoint)
endpoint = S[j] // found greater left turn, update endpoint
i = i+1
pointOnHull = endpoint
until endpoint == P[0] // wrapped around to first hull point
If your points match detected points of above algorithm then the polygon is convex.