Im trying to find the components/head of a 3D vector with in java. I have a already got the x,y,z variables setup and the corresponding rotation variables. Using these variables and vector math, I want to find the components after they have been rotated. You can think the x,y,z variables as a vector being translated.
Using the math from this post:
Rotating a Vector in 3D Space
I wrote some code that was supposed to calculate position based on that last post:
//Rotate Z
x = (( x * Math.cos(radz)) - (y * Math.sin(radz)));
y = (( x * Math.sin(radz)) + (y * Math.cos(radz)));
//Ignore Z ###############################################
//Rotate Y
x = (( x * Math.cos(rady)) - (z * Math.sin(rady)));
//Ignore Y ###############################################
z = (( x * Math.sin(rady)) + (z * Math.cos(rady)));
//Rotate X
//Ignore X ###############################################
y = (( y * Math.cos(radx)) - (z * Math.sin(radx)));
z = (( y * Math.sin(radx)) + (z * Math.cos(radx)));
Where x, y and z are the positions that need to be changed and radx, rady and radz are the degrees of rotation in radians.
Using this code, if you set the variables like so:
double radx = Math.toRadians(0f);
double rady = Math.toRadians(90f);
double radz = Math.toRadians(0f);
double x = 1;
double y = 0;
double z = 0;
System.out.println(x + " " + y + " " + z);
It outputs:
6.123233995736766E-17 0.0 6.123233995736766E-17
Which im fairly sure isn't accurate. . .
What am I doing wrong with this code? Is there a easier way to find the head of a 3D vector java?
Also I do have the joml library, but it seems to have the same issue with the vec.rotateX method.
You are updating your variables early. Try to:
//Rotate Z
double newX = (( x * Math.cos(radz)) - (y * Math.sin(radz)));
y = (( x * Math.sin(radz)) + (y * Math.cos(radz)));
//Ignore Z ###############################################
x = newX;
//Rotate Y
newX = (( x * Math.cos(rady)) + (z * Math.sin(rady)));
//Ignore Y ###############################################
z = (( x * -Math.sin(rady)) + (z * Math.cos(rady)));
x = newX;
//Rotate X
//Ignore X ###############################################
double newY = (( y * Math.cos(radx)) - (z * Math.sin(radx)));
z = (( y * Math.sin(radx)) + (z * Math.cos(radx)));
y = newY;
Related
I'm trying to perform a Log-polar transform on an image for the purpose of image registration. In other words I'm trying to achieve this:
------>
I need to code this from scratch in Java because I'll be doing this on the GPU side with OpenCL Java bindings and can't use libraries. There are multiple threads on this but none that could really help me, mostly because they're all using in-built MATLAB functions that I cannot replicate.
I've been trying the Polar Transform instead of the Log-Polar Transform for the sake of getting this to work because most info online refers to the first. So far, the best result I've had is with this bit here (pseudocode), based on this thread:
w = input.width; // Width of the input image
h = input.height; // Height of the input image
// Copy input pixels into an array
for(y=0; y<h; y++){
for(x=0; x<w; x++){
input[y*w+x] = getPixel(x, y);
}
}
// Polar transform
maxRadius = sqrt(w*w + h*h);
radiusScale = w / maxRadius;
angleScale = h / (2 * PI);
for(y=0; y<h; y++){
dy = y - h/2; // Distance from the center in the y-axis
for(x=0; x<w; x++){
dx = x - w/2; // Distance from the center in the x-axis
angle = atan2(dy, dx) % (2*PI);
radius = sqrt(dx*dx + dy*dy);
newY = radius * radiusScale;
newX = radius * thetaScale;
output[y*w+x] = input[newY*w+newX];
}
}
What I get resembles some sort of polar transformation, despite not being the result that I'm looking for:
output image
Can someone give me any pointers on this?
Thanks
EDIT:
The log-polar transform goes like .
EDIT:
Implementing #matt suggestions I now have the following code:
w = input.width; // Width of the input image
h = input.height; // Height of the input image
maxRadius = sqrt(w*w/4 + h*h/4);
radiusScale = h / maxRadius;
angleScale = w /PI/2;
offset = PI;
for(y=0; y<h; y++){
dy = y - h/2; // Distance from center in the y-axis
for(x=0; x<w; x++){
dx = x - w/2; // Distance from the center in the x-axis
angle = atan2(dy, dx);
radius = sqrt(dx*dx + dy*dy);
newY = radius * radiusScale;
newX = (angle + offset) * angleScale;
output[newY*w+newX] = input.getPixel(x, y);
}
}
Plotting the new output gives me this, which is still not what I expect to get.
One issue with this transform is that each "pixel" in the transformed space takes up a different amount of space in the x,y space. So here is how I am defining the transform.
Our new image will have the same dimensions
The Y axis will be 0 to Max Rho
The X axis will be -PI to +PI
So we start by iterating over the i,j coordinates of the output image. The resulting rho and theta are as follows.
double rho = j*maxRho / height;
double theta = i*maxTheta / width + offset;
Now we need to grab the input pixels at the respective location.
int x = (int) ( Math.exp(rho)*Math.cos(theta) + width/2);
int y = (int) ( Math.exp(rho)*Math.sin(theta) + height/2);
Now we can get the pixel value.
int pixel = input[y*width + x];
Your input variable is a bit redundante since you could just use your getPixel(x, y)
Then we just set the corresponding output value.
output[j*width + i] = pixel;
Here is a compilable example.
import javax.imageio.ImageIO;
import java.net.URL;
import java.awt.image.BufferedImage;
import java.io.File;
public class ScannerJunk{
public static void main(String[] args) throws Exception{
BufferedImage img = ImageIO.read( new URL("https://i.stack.imgur.com/MvDQT.png") );
BufferedImage out = new BufferedImage( img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB );
double w = img.getWidth();
double h = img.getHeight();
double maxRho = 0.5*Math.log( w*w/4.0 + h*h/4.0 );
double maxTheta = 2 * Math.PI;
double offset = - Math.PI;
for(int i = 0; i< w; i++){
for(int j = 0; j< h; j++){
double rho = j*maxRho / h;
double theta = i*maxTheta / w + offset;
int x = (int) ( Math.exp(rho)*Math.cos(theta) + w/2);
int y = (int) ( Math.exp(rho)*Math.sin(theta) + h/2);
try{
out.setRGB( i, j, img.getRGB( x, y ) );
} catch(Exception e){
System.out.println( i + ", " + j + " :: " + rho + ", " + theta + " :: " + x + ", " + y );
}
}
}
ImageIO.write(out, "PNG", new File("transformed.png") );
}
}
Note that the max radius, does not map to the input image for all of the possible angles.
Also, the radius and theta axis appeat to be transposed from your example image.
is supposed to calculate the coordinates of a projectile launched with respect to time (steps of 100ms), with a linear equation, and it outputs linear numbers, but if i plot this equation with CalcMe.com (math tool) it makes a parabolic plot
InVel = Double.parseDouble(jTextField1.getText());
g = Double.parseDouble(jTextField8.getText());
y = 1;
while(y >= -1) {
t += 100;
x = InVel * TimeUnit.MILLISECONDS.toSeconds(t) * Math.cos(45);
y = InVel * TimeUnit.MILLISECONDS.toSeconds(t) * Math.sin(45) - (1 / 2) * g * Math.pow(TimeUnit.MILLISECONDS.toSeconds(t), 2);
//System.out.print(Double.toString(x));
//System.out.printf(" ");
System.out.print(Double.toString(y));
System.out.printf("%n");
}
jTextField6.setText(Double.toString(x));
the code is in java
g is constant (9.8)
and invel is given by user so its constant too
g is the gravity and invel the initial velocity of the projectile
the equation is:x=invel*time*cos(45) and y=invel*time*sin(45)-(1/2)*g*t^2
anyone can help me?
Your milisecond to second value conversion method TimeUnit.MILLISECONDS.toSeconds(t) is the main fact. Its returning long value which one you are wanted double. Please take a look on below code. Probably its your answer. Just replace hard-coded value with your jTextField
public static void main(String[] args) {
double InVel = Double.parseDouble("10.555");
double g = Double.parseDouble("9.8");
double y = 1;
double x=0;
double t=0;
while(y >= -1) {
t += 100;
double timeInSeconds = (t / (double)1000) % (double)60;
x = InVel * timeInSeconds * Math.cos(45);
y = InVel * timeInSeconds * Math.sin(45) - ((double) 1 / (double) 2) * g * Math.pow(timeInSeconds, 2);
//System.out.print(Double.toString(x));
//System.out.printf(" ");
System.out.println("X = " + x + " Y = " + Double.toString(y));
System.out.printf("%n");
}
}
I need to get an accurate value of my android device's angle of rotation around Z-axis while the device is inclined (not lying flat).
I reached this angle using accelerometer sensor and calculated the angle using this code:
float[] values = event.values;
double x = values[0];
double y = values[1];
double z = values[2];
double mag = Math.sqrt(x * x + y * y + z * z);
// Normalize the accelerometer vector
x = x / mag;
y = y / mag;
z = z / mag;
int inclination = (int) Math.round(Math.toDegrees(Math.acos(z)));
if (inclination < 25 || inclination > 155) {
return Orientation.Error;
} else {
double rotation = Math.toDegrees(Math.atan2(x, y));
but when the devices rotates in a high speed this value becomes unreliable.
How can I fix this problem?
Thanks in advance,
I am almost done of getting the coordinates of a diagonal circle.
Here is what I have so far.
// Center point
double centerX;
double centerY;
double centerZ;
for (double degree = 0D; degree < 360D; degree = degree + 8D) {
double angle = degree * Math.PI / 180D;
// Difference from the center
double x = 1.5D * Math.cos(angle);
double y;
if (degree >= 0D && degree < 90D) {
y = degree / 90D;
} else if (degree >= 90D && degree < 180D) {
y = 1D - ((degree - 90D) / 90D);
} else if (degree >= 180D && degree < 270D) {
y = -1D * ((degree - 180D) / 90D);
} else {
y = -1D * (1D - ((degree - 270D) / 90D));
}
double z = 1.5D * Math.sin(angle);
// New point
double pointX = centerX + x;
double pointY = centerY + y;
double pointZ = centerZ + z;
}
Here is the output in a game.
It is not perfect because it creates some edges and it looks inefficient to me.
How do I correct it?
Is there a better way to do this?
This should look similar to what you have already, but it's simpler and smoother:
double y = 1.0D * Math.sin(angle);
Now, with these dimensions, the result is not quite a circle, but a stretched ellipse. If you want a circle, make sure the coefficients on the cosine and sine obey the Pythagorean Theorem. For example:
double x = 1.5D * Math.cos(angle);
double y = 0.9D * Math.sin(angle);
double z = 1.2D * Math.sin(angle);
These coefficients will ensure that x^2 + y^2 + z^2 is a constant for every angle. You can verify that this is true, given the identity cos^2 + sin^2 = 1. (The coefficient representing the hypotenuse should be attached to the coordinate that uses a different trig function than the other two.)
For the most maintainable code, you might find it better to assign (x, y, z) = (cos, sin, 0) and then apply a rotation matrix, or a sequence of rotation matrices, to the vector (x, y, z). This will be easier to read and harder to mess up, if you want to fine-tune the amount of rotation later.
Here is a snippet of code that I have. I am trying to bound my object in a circle rather than a square, but there are things wrong with my code that I can't figure out. I have both the rectangle bounds which work and the circle bounds which don't work.
// get the pos
_touchingPoint.x = (int)event.getX();
_touchingPoint.y = (int)event.getY();
angle = Math.atan2(_touchingPoint.y , _touchingPoint.x);
// bound to a box
if( _touchingPoint.x < 75){
_touchingPoint.x = 75;
}
if ( _touchingPoint.x > 225){
_touchingPoint.x = 225;
}
if (_touchingPoint.y < 300){
_touchingPoint.y = 300;
}
if ( _touchingPoint.y > 450 ){
_touchingPoint.y = 450;
}
//bound to a circle
if( _touchingPoint.x < 75 * Math.cos(angle))
{
_touchingPoint.x = (int) (75 * Math.cos(angle));
}
if ( _touchingPoint.x > 225 * Math.cos(angle))
{
_touchingPoint.x = (int) (225 * Math.cos(angle));
}
if ( _touchingPoint.y < 300 * Math.sin(angle))
{
_touchingPoint.y = (int) (300 * Math.sin(angle));
}
if ( _touchingPoint.y > 450 * Math.sin(angle))
{
_touchingPoint.y = (int) (450 * Math.sin(angle));
}
_touchingPoint.x and _touchingPoint.y represent the object (Joystick) that I am trying to constrain. I figured I could try simple trig to constrain the Joystick to a circle, but I guess I was wrong.
What would be the best way to set up a circle constraint?
You seem to be trying to constrain the position to a circular disk, not a circle which is its boundary. I'd accomplish this by rescaling the offset vector from the center:
double dx = event.getX() - 150;
double dy = event.getY() - 375;
double len = Math.hypot(dx, dy);
if (len > 75) {
dx = dx*75/len;
dy = dy*75/len;
}
_touchingPoint.x = (int)dx + 150;
_touchingPoint.y = (int)dy + 375;
The code appears to have calculated the angle of your point from (0,0) then bounding it based on comparing its x with some function of that angle. For example, 75 * Math.cos(angle) varies between -75 and +75, whereas you want to be comparing the point with centre of a circle.
Set up variables for the centre of the circle (cx and cy) and the difference in the x and y ordinates (dx and dy).
You then want to test whether the distance from the centre exceeds your desired radius (usually this is done with the square of the distance as it avoids a sqrt operation - dx*dx+dy*dy>r*r).
If the distance is greater than the radius, project back to the circle, either using trig or by scaling the difference :
double dx = event.getX() - cx;
double dy = event.getY() - cy;
double d2 = dx*dx+dy*dy;
if(d2>r*r) {
double scale = r / Math.sqrt(d2);
dx*=scale;
dy*=scale;
}
then ( dx + cx, dy + cy ) will lie within the circle defined by cx,cy and r.
Unless I'm missing something, it would be along these lines:
===EDIT=== ONE THING I was missing, as pointed out by Pete, was how angle should be computed:
angle = atan2(y - 375, x - 150);
=== end of edit ===
a = _touchingPoint.x;
b = _touchingPoint.y;
if((a-150)*(a-150) + (b-375)*(b-375) > 75*75){
_touchingPoint.x = 150 + 75*cos(angle);
_touchingPoint.y = 375 + 75*sin(angle);
}