Java/JavaME: Quicker geometric vector addition - java

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.

Related

Determine if vertex is convex. Help understanding

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.

how to discover an angle between two objects?

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);

Example of how to interpolate a Z value for a point using the Delaunay Triangulation in JTS

This is a fairly remedial question. I have been looking at the documentation for the JTS DelaunayTriangulationBuilder and I am at a loss as to how to do what seems like it should be a simple thing. I wish to take a series of points, triangulate them, and then interpolate the Z value of a random point within that mesh. It's non-obvious from a cursory reading how to do this. Any ideas?
After you've loaded up the triangulation object, call getSubdivision() on it to get the triangulation. It uses a quad-edge data structure, which you'll need later. (It's easier to understand if you know what a half-edge or winged-edge representation is.) The resulting QuadEdgeSubdivision has a method locate that, given a coordinate, returns one of the edges of the enclosing triangle (as a quad-edge). Get its origin vertex with orig() and its destination vertex with dest(). Get another edge with oNext() Its destination vertex is the third vertex (also dPrev().origin() is the same vertex). Now that you have the three vertices, represent your test point as a Vertex and call interpolateZValue.
For example:
public static double
interpolateZ(DelaunayTriangulationBuilder triangulation,
Coordinate coordinate) {
QuadEdgeSubdivision quadEdgeSubdivision = triangulation.getSubdivision();
QuadEdge edge = quadEdgeSubdivision.locate(coordinate);
return new Vertex(coordinate.x, coordinate.y)
.interpolateZValue(edge.orig(), edge.dest(), edge.oNext().dest());
}
You're right, though. It's not obvious how to do this from reading their API.
I'm not familiar with JTS DelauneyTriangulationBuilder, but it sounds like you have a collection of points (x,y,z), and you are submitting the 2D (x,y) pairs to the triangulator. This gives you a planar triangulation of the (x,y) points, but also a mesh who's vertices are the original (x,y,z) points.
Once you have a triangulation, you wish to find the point (p,q,r) on the mesh that corresponds to the planar point (p,q). To do so, find the triangle T of the Delauney triangulation that contains (p,q). Find the barycentric coordinates of (p,q) relative to T, and use these to compute a weighted average r of the z values corresponding to the vertices of T. That weighted average is the Z value you're looking for. In other words, (p,q,r) is on the mesh.

Guarantee outward direction of polygon normals

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)
}

Bilinear Interpolation on large arrays in Java

I am using Java's InterpolationBilinear class to help me resample an array. My current (and relatively small) test case is transforming a 10x10 array into a 20x20 array. My issue is that the interpolate(double[][], float x, float y) method in this class is only resampling the upper-left corner of the 2D array I send it (0x0, 0x1, 1x0, 1x1).
Currently, it looks like I'll have to write some code to send the interpolate method a bunch of 2x2 arrays instead of the whole array. There just seems to be a better way, any tips?
I am not interested in using 3rd party libraries, only standard Java and code I can write myself.
Thanks!
That's what the InterpolationBilinear class is supposed to do. See the documentation. The only thing it does is implement bilinear interpolation between four points arranged in a rectangle. The formula is explained here, and you can also implement it yourself pretty easily.
The question is: what are float x and float y in your example? For InterpolationBilinear.interpolate they're supposed to represent the fractional position between the four corners of the sample rectangle.
Or do you want float x and float y to represent element numbers in your array? e.g. (4.3,7.1) would mean interpolating between elements (4,7), (4,8), (5,7), and (5,8)? Then yes, you just have to plug those four values into interpolate (or your own implementation of that simple formula) along with the fractional positions 0.3 in x and 0.1 in y.
EDIT You have now clarified that x and y should represent the fractional position in the array, let's call it raw[][], and assume it's 10 x 10 i.e. indices go from 0 to 9 in both dimensions.
To interpolate at (x,y) you just need to find what square (x,y) falls into, and interpolate between the four corners. In the x direction, the indices will be the integers immediately above and below x*9, i.e. Math.floor(x*9) and Math.floor(x*9) + 1 -- same idea in y but with y*9. Now you have your four corners. Plug them into the formula. The fractional position will be something like xfrac = x*9 - Math.floor(x*9) and yfrac = y*9 - Math.floor(y*9). Plug those in the formula as well.
This has to be repeated for each point in your target array. Note that the x in the paragraph above will be equal to i/19 and the y equal to j/19 where i and j are the indices of your target array.

Categories