Bilinear Interpolation on large arrays in Java - 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.

Related

How to draw a line by coloring one pixel at a time in Java?

My objective is to draw lines and store the x and y coordinates of all the pixels that have been colored so far. I am achieving this by maintaining a 2D array
int graph[][] = new int[1000][1000] //assuming that the applet
//window is limited to 1000px X 1000px
Say I want to draw a line from (x1,y1) to (x2,y2). I achieve that by using the drawLine() method as
g.drawLine(x1,y1,x2,y2); //g is a Graphics object
This will result in a line between the given coordinates. I want to mark every pixel colored as a result of this in my graph matrix. So if (xk,yk) is colored, I would do
graph[xk][yk] = 1;
Using the fact that for every one pixel increment in x, I can get the correspoding change in y (by using the slope of the line), I did
int d = (y2-y1)/(x2-x1);
for(int i=x1;i<x2;i++)
{
graph[x1][y1]=1;
g.drawLine(x1,y1,x1++,y1+=d);
}
The obvious problem that I encountered was when dealing with floating point slopes. Every time the slope has a fractional part, it simply truncates the number and draws a line with an integral value slope. The result is that it draws lines that are not smooth with breaks in between.
I cannot make d to be double/float because I cannot increment y1 by floating point values as it is a pixel number.
I am very new to Graphics and Applets, so this^ is the best that I could think of to get what I wanted. I'd be happy to provide any further explanations if needed.

How to generate some identically distributed pseudo-random vectors with a fixed length r in a programming language?

For example, for the dimension d=2, it means that we could generate a random angle 0<=a<2*pi, and then we could just use
(x_1,x_2)=(r*cos(a),r*sin(a)) as the random vector.
However, for the dimension d>=3, we could not just generate an angle and use it to represent the vector. Then how could we generate such a vector (x_1,...,x_d), which is identically distributed on x_1^2+x_2^2+...+x_d^2=r^2?
I have just come up with a new idea, that we could generate a vector (x_1,...,x_d) such that -r<=x_i<r for all i, normalize it if x_1^2+x_2^2+...+x_d^2<=r^2 and abondon it if x_1^2+x_2^2+...+x_d^2>r^2.
However, there is a drawback that the probability that x_1^2+x_2^2+...+x_d^2<=r^2 would become very small if d is very large. Does there exist some better solutions?
Generate random variables (X_1, X_2, ... X_d) that are independent and have standard normal distributions, and then normalize by dividing by sqrt(X_1^2+...+X_d^2)/r.
That the joint distribution of independent normal distributions is rotationally symmetric is not just true, it characterizes normal distributions.
You can generate pairs of independent variables with a standard normal distribution efficiently from uniform random variables using the Box-Muller transform.
I see two ways around it.
The straightforward way is, in pseudo-code:
1. build n-dimensional vector x[0] through x[n-1] with random components
2. find radius
3. go to step 1 if radius > r; otherwise, normalize to radius r
This is non-deterministic, because there is no way to know how many times you will need to cycle before you find an acceptable sphere. Additionally, the probability of finding a bad point goes up with the number of dimensions.
To understand why (thanks commenters!), imagine a 1x1 square. Add a r=1 circle inside. Fill the square with random points. All the points between the center and the circle are evenly distributed when projected on the circle. All the points between the circle and the square's border are not - because there's too many at, say, 45º; and none at, say, 90º.
The non-straightforward version is a generalization of your 2-dimensional approach:
1. assume that we are on an n-sphere; generate angles phi[0], ...phi[n-2]
for a polar-coordinates point
2. convert to cartesian coordinates x[0] through x[n-1]
According to the n-sphere page in wikipedia, the formula is
x[0] = r*cos(phi[0]);
x[1] = r*sin(phi[0])*cos(phi[1]);
x[2] = r*sin(phi[0])*sin(phi[1]);
...
x[n-2] = r*sin(phi[0])*sin(phi[1])* /*...*/ sin(phi[n-3])*sin(phi[n-2])
x[n-1] = r*sin(phi[0])*cos(phi[1])* /*...*/ sin(phi[n-3])*cos(phi[n-2])
The actual algorithm can be implemented a lot more efficiently (sin(phi[0]) is getting calculated a lot, for example)
To avoid non-determinism, I recommend the second approach.
Edit
The recommended approach, not listed above, is in Douglas's answer and many reference sites:
https://mathoverflow.net/questions/136314/what-is-a-good-method-to-find-random-points-on-the-n-sphere-when-n-is-large
http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
http://mathworld.wolfram.com/HyperspherePointPicking.html

How do i find if a set of coordinates are inside a 2D triangle?

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.

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

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

Categories