There is already an answer for this question but for a 2D mesh:
Angles of triangles of a 3D mesh using #CGAL
I understand that the answer is different regarding 2D. So: how to compute the angles of triangles of a 2D mesh in CGAL? I can take the vertices and their respective Vector by making pairs, but I'm looking for a straight forward way of calculating the angles, without making a check if it's the outer or the inner angle.
If it makes any difference, this mesh has been produced by a CDT.
It was simple alright, but I thought it might help someone, since a comment by Laurent Rineauin in the initial 3D mesh question, proposed that the solution is different. So here it is:
// faces_iterator iterates through the triangles of l_cdt CDT triangulation
CGAL::Point_2<K> vertex1 = l_cdt.triangle(faces_iterator)[0];
CGAL::Point_2<K> vertex2 = l_cdt.triangle(faces_iterator)[1];
CGAL::Point_2<K> vertex3 = l_cdt.triangle(faces_iterator)[2];
double a = CGAL::sqrt((vertex2.x() - vertex3.x()) * (vertex2.x() - vertex3.x()) + (vertex2.y() - vertex3.y()) * (vertex2.y() - vertex3.y()));
double b = CGAL::sqrt((vertex1.x() - vertex3.x()) * (vertex1.x() - vertex3.x()) + (vertex1.y() - vertex3.y()) * (vertex1.y() - vertex3.y()));
double c = CGAL::sqrt((vertex2.x() - vertex1.x()) * (vertex2.x() - vertex1.x()) + (vertex2.y() - vertex1.y()) * (vertex2.y() - vertex1.y()));
// constants::PI is just π, for conversion to degrees instead of radians
double angle1 = ((std::acos((b*b + c*c - a*a) / (2*b*c))) * 180) / constants::PI;
double angle2 = ((std::acos((a*a + c*c - b*b) / (2*a*c))) * 180) / constants::PI;
double angle3 = ((std::acos((a*a + b*b - c*c) / (2*b*a))) * 180) / constants::PI;
Related
I am trying to implement this ear clipping algorithm (from the pseudocode) here Currently at the point in the algorithm where I am trying to calculate the angle of each vertex in a polygon. I also got the idea of how to calculate the angles with vectors here: here This way I can also determine convexity/concavity. Also my vertices are in counter clockwise order.
This is a helper function I wrote to help in calculating the angle of each vertex:
void calcConvexity(Node&* prev, Node&* curr, Node&* next) {
glm::vec2 u(0.0f), v(0.0f);
u.x = curr->x - prev->x;
u.y = curr->y - prev->y;
v.x = curr->x - next->x;
v.y = curr->y - next->y;
// Calculating angle (in radians)
curr->Angle =
((u.x * v.y) - (u.y * v.x))
/
std::sqrt((std::pow(u.x, 2.0f) + std::pow(u.y, 2.0f)) *
std::sqrt(std::pow(v.x, 2.0f) + std::pow(v.y, 2.0f));
// Convert to degrees
curr->Angle = (180 / 3.141592653589793238463) * curr->Angle;
if (curr->Angle < 180.0f)
curr->isConvex = true; // The vertex is convex
else
curr->isConvex = false;
}
I was expecting most of the angles to come out between 0 and 360 but they did not. I am not sure what further calculations or corrections I need to make. Also, in the node class I have a boolean attribute called isConvex. I know something wrong is happening because every vertex is having there isConvex attribute set to true even when there degree is greater than 180.0f (in the example below).
Here is an actual example output as well:
(The blue arrows are suppose to be facing in towards the nodes I just cant update the picture on here)
Polygon With vectors to each vertice
as well as the isConvex values for each node:
Node isConvex Values
and the angles:
Node angle values
I have tried facing the vectors in different directions as well as using the GLM library for vector operations.
I apologize if any of what I have supplied is confusing, this is my first time messing with computational geometry in general. So I am just wondering what am I doing wrong in my calcConvexity method?
UPDATED CODE:
void calcConvexity(Node&* prev, Node&* curr, Node&* next) {
glm::vec2 u(0.0f), v(0.0f);
u.x = curr->x - prev->x;
u.y = curr->y - prev->y;
v.x = curr->x - next->x;
v.y = curr->y - next->y;
float CrossProduct = ((u.x * v.y) - (u.y * v.x));
if (CrossProduct < 0)
curr->isConvex = true; // The vertex is convex
else
curr->isConvex = false; // Otherwise concave
curr->Angle =
(CrossProduct)
/
std::sqrt((std::pow(u.x, 2.0f) + std::pow(u.y, 2.0f)) *
std::sqrt(std::pow(v.x, 2.0f) + std::pow(v.y, 2.0f));
curr->Angle = glm::degrees(std::asin(curr->Angle));
}
So the solution I came up with is this:
I use the Cross product to determine convexity and then I use a slightly different angle formula: cos(curr->Angle) = (u.b) / (|u||v|)
My main problem was the the formula with sin was outputting between -90 and 90 while the formula with cos outputs between 0 and 180
Code that works:
void Graph::calcConvexity(Node*& prev, Node*& curr, Node*& next) {
glm::vec2 u(0.0f), v(0.0f);
u.x = curr->x - prev->x;
u.y = curr->y - prev->y;
v.x = curr->x - next->x;
v.y = curr->y - next->y;
float CrossProduct = ((u.x * v.y) - (u.y * v.x));
if (CrossProduct < 0)
curr->isConvex = true; // The vertex is convex
else
curr->isConvex = false; // Otherwise concave
float dotProduct = (u.x * v.x) + (u.y * v.y);
curr->Angle =
std::acos(dotProduct /
(std::sqrt(std::pow(u.x, 2.0f) + std::pow(u.y, 2.0f)) *
std::sqrt(std::pow(v.x, 2.0f) + std::pow(v.y, 2.0f))));
curr->Angle = glm::degrees(curr->Angle);
}
The safest way to obtain angles is by means of the function atan2, which returns a value on four quadrants (usually in (-π, π]).
Using the complex number notation, the angle formed by the vectors u to v is given by the argument of u*v where * denotes conjugation.
Anyway, I guess that to determine the concavity/convexity for triangulation, it is enough to consider the signed area of the triangles (cross product of two sides) rather than angles. That tells you if a triangle is clockwise or not.
curr->Angle appears to be set to sin(Angle) from u to v. Therefore concavity/convexity is determined by the sign of ((u.x * v.y) - (u.y * v.x)), since the denominator is always positive.
In particular, if the interior of the polygon is on the right as traversing the vector u from its tail to its head, the positive sign of ((u.x * v.y) - (u.y * v.x)) corresponds to a convex angle.
I'm currently working on a pice of software that interpolates data from existing measurements and makes estimates from this. The data is arranged in a 2D environment where we've got a wind speed on one axis and a wind angle on the other and each point represents a target speed.
For an example I've got three points:
p1: wind speed 6 knots, wind angle 90 degrees => target speed 5
p2: wind speed 6 knots, wind angle 70 degrees => target speed 6
p3: wind speed 8 knots, wind angle 70 degrees => target speed 7
Now I want to interpolate the point of wind speed 6 knots and wind angle 80 degrees. I would like an algorithm that uses all of these points and gives me an average of these three points.
Ages ago I made a 3D renderer and I think I used a technique there to color a polygon and I think this can be useful in this scenario. All the examples that I've found on the internet rely on OpenGL and such and that won't work for me as I want this solution to be pure c/c++ for an embedded environment. Since i run in an embedded environment I've got limited resources mainly in terms of program size.
Do any of you guys have any pointers to help me get past this problem? Thanks!
After diving into my old calculus i found a mathematical answer to this problem.
Given that I've got three points in the space I can form a plane:
P: (Px, Py, Pz)
Q: (Qx, Qy, Qz)
R: (Rx, Ry, Rz)
These points and the math described in here http://tutorial.math.lamar.edu/Classes/CalcIII/EqnsOfPlanes.aspx allowed me to move forward.
Vector(PQ) = (PQx, PQy, PQz)
Vector(PR) = (PRx, PRy, PRz)
Now I apply the cross product to these two vectors and this gives the normal vector of the plane
(Cross product math described here: http://tutorial.math.lamar.edu/Classes/CalcII/CrossProduct.aspx#Vectors_CrossProd_Ex2)
Vector(PQ) x Vector(PR) = Vector(PQy * PRz - PQz * PRy,
PQz * PRx - PQx * PRz,
PQx * PRy - PQy * PRx)
So, this is what I've got as a plane equation, without respect to that it has to pass trough one of the points:
x(PQy * PRz - PQz * PRy) + y(PQz * PRx - PQx * PRz) + z(PQx * PRy - PQy * PRx) = 0
To get the full equation of my plane that passes trough all of the points, I have to apply one point, as described in example 1 in the first link.
x(PQy * PRz - PQz * PRy) + y(PQz * PRx - PQx * PRz) + z(PQx * PRy - PQy * PRx) =
Px(PQy * PRz - PQz * PRy) + Py(PQz * PRx - PQx * PRz) + Pz(PQx * PRy - PQy * PRx)
To apply my example to this formula I get the following equation:
P: (90, 6, 5)
Q: (70, 6, 6)
R: (70, 8, 7)
Vector(PQ) = (20, 0, -1)
Vector(PR) = (20, -2, -2)
Cross product of these gives me this formula:
-2x + 20y - 40z = 0
If I now apply the point P to this I can get the full equatio of my plane:
-2x + 20y - 40z = -2 * 90 + 20 * 6 - 40 * 5
-2x + 20y - 40z = -260
z = (-2x + 20y + 260) / 40
As I seek the z value where x = 6 and y = 80 I put these values into the equation.
x = 80
y = 6
z = (-2 * 80 + 20 * 6 + 260) / 40
z = 5.5
5.5 is the expected answer for this example as it exactly in the middle of P and Q.
The final implementation of this algorithm:
float TargetSpeed::PlaneInterpolation(Point3D p, Point3D q, Point3D r, int x, int y)
{
Point3D pq = Point3D(p.X - q.X, p.Y - q.Y, p.Z - q.Z);
Point3D pr = Point3D(p.X - r.X, p.Y - r.Y, p.Z - r.Z);
Point3D n = Point3D(pq.Y * pr.Z - pq.Z * pr.Y,
pq.Z * pr.X - pq.X * pr.Z,
pq.X * pr.Y - pq.Y * pr.X);
float d = n.X * p.X + n.Y * p.Y + n.Z * p.Z;
float z = (d - n.X * (float)x - n.Y * (float)y) / n.Z;
return z;
}
Is the data on a regular grid? If so, I would just use something like linear interpolation. If not, then look at something like qhull.
For a game I'm making, I want 3 ships which will all race around the map following a collection of points. It works perfectly fine, except for one point in the map, where the ships decide to rotate almost 360 degrees counter clockwise even though only 10 degrees clockwise should be enough.
The code for calculating the rotation:
vec2 distance = *desiredPosition - position;
float rot = atan2(distance.y, distance.x);
rot = rot * 180.f / PI + 90.f;
if (rot < angle)
{
angle -= dAngle;
boat->RotateImage(-dAngle);
}
if (rot > angle)
{
angle += dAngle;
boat->RotateImage(dAngle);
}
velocity += vec2(acceleration * cos((angle - 90) * PI / 180.0), acceleration * sin((angle - 90) * PI / 180.0));
How do I ensure it won't rotate in the wrong direction there?
Thanks to Richard Byron (accepted answer below), the problem is fixed. Taking the dot product is better than using degrees.
The final code:
vec2 distance = desiredPosition - position;
normal = vec2(sin((angle - 90) * PI / 180.0), cos((angle - 90) * PI / 180.0) * -1);
float dir = normal.x * distance.x + normal.y * distance.y;
//turn
if (dir > 0)
{
angle -= dAngle;
boat->RotateImage(-dAngle);
}
if (dir < 0)
{
angle += dAngle;
boat->RotateImage(dAngle);
}
velocity += vec2(acceleration * cos((angle - 90) * PI / 180.0), acceleration * sin((angle - 90) * PI / 180.0));
The angle the boat turns should be less than 180 degrees either CW or CCW. If it turns more than 180 degrees in one direction it would have been better to turn the other way.
A more general solution would be calculate the distance vector with respect to the boat's frame of reference.
There are a couple of problems with your updated code. Firstly, it should be rot2 = 360 - rot1; (rot1 + 360 is exactly the same angle as rot1).
The second issue is that you are not taking into account that 1 and 359 degrees are almost the same angle. So if abs(rot1 - angle) > 180, then you really want to use 360 - abs(rot1 - angle) in that case. Your later comparisons with rot and angle are a problem for the same reason, and you need to handle angle incrementing above 360 and decrementing below 0.
I could write out code for this, but there's actually a much simpler and faster way to do this. If you take the dot product of the vector (desiredPosition - position) and a vector at right angles to the ships current heading, then you can turn based on the sign of that result. If it's not clear how to do this, let me know and I can expand on it in the comments.
i study OpenGL ES 2.0. But i think it's more C++ question rather then OpenGL. I'am stuck with rotation question. It is known, that rotation transformation can be applied using the following equations:
p'x = cos(theta) * (px-ox) - sin(theta) * (py-oy) + ox
p'y = sin(theta) * (px-ox) + cos(theta) * (py-oy) + oy
But it seems that when i perform this rotation operation several times the accuracy problem is occured. I guess, that the core of this problem is in uncertain results of cos function and floating point limitations. As a result i see that my rotating object is getting smaller and smaller and smaller. So:
1.) How do you think, does this issue really connected with floating point accuracy problem?
2.) If so, how can i handle this.
Suppose that float _points[] is array containing coordinates x1,y1,x2,y2...xn,yn. Then i recompute my coordinates after rotation in the following way:
/* For x */
float angle = .... ;
pair<float, float> orig_coordinates(0, 0);
for (; coors_ctr < _n_points * 2; coors_ctr += 2)
_points[coors_ctr] = cos(angle) * (_points[coors_ctr] - _orig_coordinates.first) -
sin(angle) * (_points[coors_ctr + 1] - _orig_coordinates.second) +
_orig_coordinates.first;
/* For y */
coors_ctr = 1;
for (; coors_ctr < _n_points * 2; coors_ctr += 2)
_points[coors_ctr] = sin(angle) * (_points[coors_ctr - 1] - _orig_coordinates.first) +
cos(angle) * (_points[coors_ctr] - _orig_coordinates.second) + _orig_coordinates.second;
I think the problem is that you're writing the rotated result back to the input array.
p'x = cos(theta) * (px-ox) - sin(theta) * (py-oy) + ox
p'y = sin(theta) * (p'x-ox) + cos(theta) * (py-oy) + oy
Try doing the rotation out of place, or use temporary variables and do one point (x,y) at a time.
I'm working on a (rather) simple 2D project in OpenGL. It's some sort of asteroids clone.
The ship is basically an isosceles triangle of height H, with the base have a length of H/2.
The way I've been doing it so far is simply storing the center point (CP) of the triangle and then calculating the final vertex positions on the fly. The 'point' of the ship is (vectors are x,y) the (CP.x, CP.y + H/2). The other two points are (CP.X - H/4, CP.Y - H/2) and (CP.X + H/4, CP.Y - H/2).
To get the ship facing the right direction, I first call glRotate on the current rotation angle.
This part is working fine however I'm running into issues with collision detection. Currently I'm trying to implement triangle-plane collision detection however to do that, I first need to figure out the actual points of the ship vertices after rotation. I've tried using trigonometry to calculate these points, however I've failed.
The way I've attempted is was to use the cosine rule to find the distance between the unrotated triangle and the triangle after rotation. To give an example, the following is how I've tried to calculate the 'pointy' vertex position after rotation:
//pA is a vector struct holding the position of the pointy vertex of the ship (centerPoint.x, centerPoint.y + height / 2)
//Distance between pA and the rotated pointy vertex - using the cosine rule
float distance = sqrt((2 * pow(size / 2, 2)) * (1 - cosf(rotAngle)));
//The angle to the calculated point
float newPointAngle = (M_PI / 2) - rotAngle;
float xDif = distance * cosf(newPointAngle);
float yDif = distance * sinf(newPointAngle);
//Actually drawing the new point
glVertex2f(pA.x - xDif, pA.y - yDif);
Any idea what I could be doing wrong?
Thanks for the help guys but I think those explanations were a bit too technical for me. Nonetheless you made it clear to me that there's no special case for a triangle (which, in hindsight, I should've known) so I tried my hand at searching and after trying a few methods, found one which worked for me.
The post from estain at the GameDev forums did the trick. To quote his post (sorry for the c&p but may be useful for someone else who runs into a similar issue):
Without getting to heavily into general solutions and maths (as the above posters and lots of articles have covered this already), I could give you an example on how to solve the problem "rotating a point A around point B by C degrees".
Now. First of all, as I described in the previous post, a point that is on the X axis, L distance from origo, is rotated C degrees around origo by
x = L * cos(C)
y = L * sin(C)
Similarly, the formula for a perpendicular vector is x = -y | y = x, which means that a point that is on the Y axis (again, L from origo) would be rotated by C using the formula
x = - L * sin(C)
y = L * cos(C)
As shown in the above image, the final solution is the sum of the rotations of the projected vectors, so we can derive the formula
x' = x * cos(C) - y * sin(C)
y' = y * cos(C) + x * sin(C)
... but you knew that already, right? problem is, this formula only rotates around origo. So what we need to do is move the coordinate system we're rotating around to origo, rotate and then move back. This can be done quickly with complex numbers or in general solutions with matrices, but we're gonna stick to vector math on this one to keep it simple.
first step; move the origin point.
x' = A.x - B.x
y' = A.y - B.y
second step, perform rotation
x'' = x' * cos(C) - y' * sin(C) = (A.x-B.x) * cos(C) - (A.y-B.y) * sin(C)
y'' = y' * cos(C) + x' * sin(C) = (A.y-B.y) * cos(C) + (A.x-B.x) * sin(C)
third and final step, move back the coordinate frame
x''' = x'' + B.x = (A.x-B.x) * cos(C) - (A.y-B.y) * sin(C) + B.x
y''' = y'' + B.y = (A.y-B.y) * cos(C) + (A.x-B.x) * sin(C) + B.y
And presto! we have our rotation formula. I'll give it to you without all those >calculations:
Rotating a point A around point B by angle C
A.x' = (A.x-B.x) * cos(C) - (A.y-B.y) * sin(C) + B.x
A.y' = (A.y-B.y) * cos(C) + (A.x-B.x) * sin(C) + B.y
If you've been following me here (and I'm a pretty lousy teacher, so sorry if you haven't), you can se that the ordering in which you perform these operations is very important. Try to mix step 3 and 1 and see the difference in the formulae you get.
Good luck and all!
Rotation calculations need to be centered at the origin, so you may need to first translate the coordinates so the center of rotation is aligned with the origin.
Then use the new points to get the rotated coordinates:
x1 = x cos f - y sin f
y1 = y cos f + x sin f
where f is the angle of rotation.
Then you translate the new coordinates back to where you started (the reverse of the first translation.
Check out this article for some diagrams and clarification.
Calculating the new points is relatively simple. Assume the x and y are the coordinates of a certain point on the triangle (i.e. the vertices) relative to the point of rotation (or center).
You must convert the coords to a square distance and angle component:
float dist, angle;
dist = (x*x) + (y*y);
angle = atan(abs(x)/abs(y));
// a little more code is required for the different quadrants that the angle could be in.
Then rotate:
angle+=rotation_angle;
Then convert back:
new_x = sqrt(dist)*sin(angle*pi/180);
new_y = sqrt(dist)*cos(angle*pi/180);