I am studying the following code.
boolean convex(double x1, double y1, double x2, double y2,
double x3, double y3)
{
if (area(x1, y1, x2, y2, x3, y3) < 0)
return true;
else
return false;
}
/* area: determines area of triangle formed by three points
*/
double area(double x1, double y1, double x2, double y2,
double x3, double y3)
{
double areaSum = 0;
areaSum += x1 * (y3 - y2);
areaSum += x2 * (y1 - y3);
areaSum += x3 * (y2 - y1);
/* for actual area, we need to multiple areaSum * 0.5, but we are
* only interested in the sign of the area (+/-)
*/
return areaSum;
}
I do not understand the concept that area being negative.
Shouldn't area be always positive? maybe I am lacking some understanding of terms here.
I tried to contact the original writer but this code is about 8 years old and I have no way to contact the original writer.
This method of determining if the given vertex x2y2 is convex seems really mobile. I really want to understand it.
Any direction or reference to help me understand this piece of code will be appreciated greatly.
Source code : http://cgm.cs.mcgill.ca/~godfried/teaching/cg-projects/97/Ian/applets/BruteForceEarCut.java
The algorithm use a very simple formula with which you can compute twice the area of a triangle.
This formula has two advantages:
it doesn't require any division
it returns a negative area if the point are in the counterclockwise order.
In the code sample, the actual value of the area doesn't matter, only the sign of the result is needed.
The formula can also be used to check if three points are colinear.
You can find more information about this formula on this site : http://www.mathopenref.com/coordtrianglearea.html
This algorithm is basically using the dot product of two vectors and interpreting the results. This is the core of the Gift Wrapping Algorithm used to find convex hulls.
Since a dot b is also equal to |a|*|b|*cos(theta) then if the result is positive, cos of theta must be positive and thus convex. Per a wiki article on cross products...
Because the magnitude of the cross product goes by the sine of the
angle between its arguments, the cross product can be thought of as a
measure of ‘perpendicularity’ in the same way that the dot product is
a measure of ‘parallelism’. Given two unit vectors, their cross
product has a magnitude of 1 if the two are perpendicular and a
magnitude of zero if the two are parallel. The opposite is true for
the dot product of two unit vectors.
The use of "area" is slightly misleading on part of the original coder in my opinion.
You know about how integrals work, right? One way to think of integrals is in terms of the area under the integrated curve. For functions that are strictly positive, that definition works great, but when the function becomes negative at some point, there is a problem because then you have to take the absolute value, right?
That is not always so, actually, and it can be quite useful in some contexts to leave the curve negative. Think back to what was said earlier: the area under the curve. All that space between negative infinity and our function. Clearly, that is absurd, right? A better way to think of it is as the difference between the area under the curve, and the area under the x axis. That way, when the function is positive, our curve is gaining more area, and when it is negative, it is gaining less than the x axis.
The same thing applies to plane figures that are not strict functions. In order to really determine this, we have to define which direction our edge is going as it travels around the figure. We can define it so that all the area on the right of our curve is inside the region, and all the area to the left is outside (or we can define it the other way around, but I will use the first way).
So our figure includes all the area from there to the edge at infinity of the plane that is directly to our right. Regions enclosed clockwise really include their conventional interior twice. Regions enclosed counterclockwise don't include their conventional interior at all. The area, then, is the difference between our region and the whole plane.
The application of this to concavity is fairly simple, if you understand what it actually means to be concave or convex. The triangle you are given is concave if it is cutting an area out from the plane, and it is convex if you are adding extra area to it. That is the exact same thing we were doing to determine the our area, so positive area corresponds to a convex shape, and negative area corresponds to a concave shape.
You can also do other weird things with this conceptual model. For instance, you can turn a region 'inside out' by reversing the edge direction.
I'm sorry if this has been a little hard to follow, but this is the actual way I understand negative area.
Related
Given two triangles in 3D, defined by points [t1.v1, t1.v2, t1.v3] and [t2.v1, t2.v2, t2.v3], where vX are points with variables (x, y, z).
How can I calculate the force of gravity between them?
Formula for point masses:
force = constant*mass1*mass2/(distance^2);
For my application, the triangles will be close together, and approximating via point masses would not have the required precision.
I understand that this could be solved with a quadruple integral, but I don't have much mathematical know-how towards creating or solving such a complicated equation.
Edit:
My similar (related) question on math.stackexchange: https://math.stackexchange.com/questions/1082860/general-solution-for-the-gravity-between-two-3d-triangles/
Does anybody know how to find out if a set of coordinates are within a triangle for which you have the coordinates for. i know how to work out length of sides, area and perimeter, but i have no idea where to begin working out the whereabouts within the triangle of other points.
Any advice would be appreciated
You can create a Polygon object.
Polygon triangle = new Polygon();
Add the vertexes of your triangle with the addPoint(int x, int y) method.
And then, you just need to check if the set of coordinates is inside your triangle using contains(double x, double y) method.
Use the contains method of the Polygon class as documented here.
For a solution without using the Polygon-class:
Assume that you have giving three points A,B,C the vertices of your polygon. Let P be the point you want to check. First calculate the vectors representing the edges of your triangle. Let us call them AB, BC, CA. Also calculate the three vectors PA, PB, PC.
Now calculate the cross product between the first two of the vectors from above.
The cross product of the first pair gives you the sin(alpha), where alpha is the angle between AB and PA, multiplied with a vector pendenpicular to AB and PA. Ignore this vector because we are interested in the angle and take a look at the sine (in the case of 2D vectors you can imagine it as the vector standing perpendicular to your screen).
The sine can take values between (let's say for the ease) betwenn 0 and 2*Pi. It's 0 exactly at 0 and Pi. For every value in between the sine is positive and for every value between Pi and 2*Pi it's negative.
So let's say your Point p is on the left hand side of AB, so the sine would be positive.
By taking the cross product of each pair from above, you could easily guess that the point P is on the left hand side of each edge from the triangle. This just means that it has to be inside the triangle.
Of course this method can even be used from calculating whether a point P is in a polygon. Be aware of the fact, that this method only works if the sides of the polygon are directed.
I'm making a simple Vector class with a simple usage, so I don't want to import a whole library (like JScience...) for something that I can do myself.
Currently I have made this code so far:
public void add(Vector2D v){
double ang = this.angle*Math.PI/180;
double mag = this.magnitude;
double ang0 = v.angle*Math.PI/180;
double mag0 = v.magnitude;
//vector to coordinates
double x1 = mag*Math.cos(ang);
double y1 =-mag*Math.sin(ang);
//adding the other vector's coordinates
double x2 =x1+mag*Math.cos(ang0);
double y2 =y1-mag*Math.sin(ang0);
//back to vector form
double newMagnitude = Math.sqrt(x2*x2+y2*y2);
double newAngle = Math.atan2(y2,x2);
this.magnitude = newMagnitude;
this.angle = newAngle;
}
It's converting both vectors to coordinates and then back with the trigonometric functions, But those are extremely slow, and the method will be used very frequently.
Is there any better way?
First off, some terminology 101:
Point: a dimensionless entity that a space is made of.
Space: a set of points.
Euclidean space: a set of points, together with a set of lines and with the notion of closeness (topology). The set of lines is bound by the Euclid's axioms. It is uniquely defined by its dimension.
Vector: a translation-invariant relationship between two points in an Euclidean space.
Coordinate system: a mapping from tuples of real numbers to points or vectors in some space.
Cartesian coordinate system: A specific mapping, with the properties (in case of the Euclidean 2D space) that the set of points ax+by+c=0 is a line unless a,b are both zero, that the vectors [0,1] and [1,0] are perpendicular and unit length, and that points in space are close together iff they are close together in all coordinates. This is what you refer to as "coordinates".
Polar coordinate system: Another specific mapping, that can be defined from the cartesian coordinates: [arg,mag] in polar coordinates map to [cos(arg)*mag, sin(arg)*mag] in cartesian coordinates. This is what you refer to as "vector form".
The cartesian coordinate system has multiple benefits over the polar coordinate system. One of them is easier addition: [x1,y1]+[x2,y2]=[x1+x2,y1+y2] and scalar multiplication: [x1,y1].[x2,y2]=x1*x2+y1*y2. Additive inversion is slightly easier as well: -[x,y]=[-x,-y]
Another benefit is that while polar coordinates are strictly 2D (there is no unique extension - the spherical coordinate system is a candidate, though), cartesian coordinates extend naturally to any number of dimensions.
For this reason, it is beneficial - and usual - to always store vectors in their cartesian coordinate form.
If you ever need vectors in their polar form, then (and only then) convert, once and for all.
Polar coordinates not as useful. They can be used for input and output, but they are rarely useful for computation.
You keep storing your vectors in the polar form. You convert them to their cartesian form for computation, then convert back to polar - only to convert them to the cartesian again.
You should store your vectors in the cartesian form. The performance improvement should be clearly visible if you drop the redundant conversion.
Even if you want to rotate a vector, it's not beneficial to convert to polar and back. Rotation by a signed angle a is as easy as [x*cos(a)+y*sin(a), y*cos(a)-x*sin(a)]. That's two trigonometric functions (at most - you can cache these values) to rotate an entire array of vectors.
what I want to do is the following: I have an object (blue point) and I want to point it to other object no matter where it is located around it (green point). So I need to know the angle between these two objects to do what I want right?
http://s13.postimage.org/6jeuphcdj/android_angle.jpg
The problem is, I don't know what to do to achieve this. I've already used atan, math.tan and so many other functions but without any good results.
Could you help me? Thanks in advance.
Calculate a dot product of object vectors. Use Math.acos on the value you get. That will give you an angle in radians.
So, say your blue dot is at vec1 = (50, 100) and green one at vec2 = (100, 400).
A tuple (x, y) as a two dimensional vector describes object's position and distance from (0, 0) on your screen. To find the angle between these two vectors, you do a standard, binary dot product operation on them. This will get you a scalar (a value, cos(Theta)), but you want the inverse of it (acos) which is the angle you're looking for.
You can get a better understanding on the matter here
Suppose the coordinates of the blue and green points are (xblue, yblue) and (xgreen, ygreen) respectively.
The angle at which the blue point sees the green point is:
double angleRadians = Math.atan2(ygreen-yblue, xgreen-xblue);
If you want the angle in degrees:
double angleDegrees = Math.toDegrees(angleRadians);
I'm trying to write a 2D game in Java that uses the Separating Axis Theorem for collision detection. In order to resolve collisions between two polygons, I need to know the Minimum Translation Vector of the collision, and I need to know which direction it points relative to the polygons (so that I can give one polygon a penalty force along that direction and the other a penalty force in the opposite direction). For reference, I'm trying to implement the algorithm here.
I'd like to guarantee that if I call my collision detection function collide(Polygon polygon1, Polygon polygon2) and it detects a collision, the returned MTV will always point away from polygon1, toward polygon2. In order to do this, I need to guarantee that the separating axes that I generate, which are the normals of the polygon edges, always point away from the polygon that generated them. (That way, I know to negate any axis from polygon2 before using it as the MTV).
Unfortunately, it seems that whether or not the normal I generate for a polygon edge points towards the interior of the polygon or the exterior depends on whether the polygon's points are declared in clockwise or counterclockwise order. I'm using the algorithm described here to generate normals, and assuming that I pick (x, y) => (y, -x) for the "perpendicular" method, the resulting normals will only point away from the polygon if I iterate over the vertices in clockwise order.
Given that I can't force the client to declare the points of the polygon in clockwise order (I'm using java.awt.Polygon, which just exposes two arrays for x and y coordinates), is there a mathematical way to guarantee that the direction of the normal vectors I generate is toward the exterior of the polygon? I'm not very good at vector math, so there may be an obvious solution to this that I'm missing. Most Internet resources about the SAT just assume that you can always iterate over the vertices of a polygon in clockwise order.
You can just calculate which direction each polygon is ordered, using, for example, the answer to this question, and then multiply your normal by -1 if the two polygons have different orders.
You could also check each polygon passed to your algorithm to see if it is ordered incorrectly, again using the algorithm above, and reverse the vertex order if necessary.
Note that when calculating the vertex order, some algorithms will work for all polygons and some just for convex polygons.
I finally figured it out, but the one answer posted was not the complete solution so I'm not going to accept it. I was able to determine the ordering of the polygon using the basic algorithm described in this SO answer (also described less clearly in David Norman's link), which is:
for each edge in polygon:
sum += (x2 - x1) * (y2 + y1)
However, there's an important caveat which none of these answers mention. Normally, you can decide that the polygon's vertices are clockwise if this sum is positive, and counterclockwise if the sum is negative. But the comparison is inverted in Java's 2D graphics system, and in fact in many graphics systems, because the positive y axis points downward. So in a normal, mathematical coordinate system, you can say
if sum > 0 then polygon is clockwise
but in a graphics coordinate system with an inverted y-axis, it's actually
if sum < 0 then polygon is clockwise
My actual code, using Java's Polygon, looked something like this:
//First, find the normals as if the polygon was clockwise
int sum = 0;
for(int i = 0; i < polygon.npoints; i++) {
int nextI = (i + 1 == polygon.npoints ? 0 : i + 1);
sum += (polygon.xpoints[nextI] - polygon.xpoints[i]) *
(polygon.ypoints[nextI] + polygon.ypoints[i]);
}
if(sum > 0) {
//reverse all the normals (multiply them by -1)
}