I'm making a compass that points to a user defined location. I'm using the rotateanimation to rotate the needle. When the needle points in the direction of the phone I know the phone is pointing in the direction I want. However, I wanted the needle to point in the correct direction irregardless of the phone's azimuth.
The problem is that it seems that rotateanimation does not rotate the needle according to the real world coordinates, and instead is relative to the phone's screen. So a 58 degree rotation of the needle does not match a 58 degree rotation in the real world. Is this true or am I making a mistake in my code?
The compass is meant to be used by placing the phone's back flat on a surface. I've also tried outputting the azimuth and it reads like this:
Azimuth Actual Phone angle
0 0
45 90
90 180
when it gets close to a full circle back it bounces between 120 and 340.
Here's the code:
direction = 360 - azimuth + rotate;
RotateAnimation animate = new RotateAnimation(rotateLast, direction, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animate.setFillAfter(true);
animate.setInterpolator(new LinearInterpolator());
animate.setDuration(10);
needle.startAnimation(animate);
rotateLast = direction;
azimuth is the phone's azimuth from the sensor, rotate is the user specified direction (in degrees from north), and direction is the required rotation of the needle.
rotateLast is the last position the needle was at, I'm using this because without it the needle reverts to zero degrees and flickers.
Thanks,
P.S. this has been driving me crazy
I figured it out, my math was all wrong and I misunderstood how azimuth affected the rotation.
I realized when I rotated the image to just azimuth and understood that it resulted in the needle pointing north. All I needed to do was just add the user direction. The math I was using caused the needle to rotate in unpredictable ways.
The answer is simply:
RotateAnimation animate = new RotateAnimation(-azimuth+rotation, -azimuth+rotation, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
the -azimuth is because of how rotateanimation rotates counter-clockwise.
Related
I am trying to create an arrow that points towards a specific coordinate, like a compass.
I am using Sensor.TYPE_ACCELEROMETER and Sensor.TYPE_MAGNETIC_FIELD from the phone to calculate the azimuth angle (I took reference from this question Using orientation sensor to point towards a specific location ):
//calculate RotationMatrix
if (gravity != null && geomag != null) {
boolean success = SensorManager.getRotationMatrix(inR, I,
gravity, geomag);
if (success) {
SensorManager.getOrientation(inR, orientVals);
azimuth = Math.toDegrees(orientVals[0]);
pitch = Math.toDegrees(orientVals[1]);
roll = Math.toDegrees(orientVals[2]);
}
}
azimuth += geomagneticField.getDeclination();
//azimuth = Math.round(sensorEvent.values[0]);
float bearing = lastLocation.bearingTo(targetLocation);
float angle = (float) azimuth + bearing;
I then use RotatateAnimation to create the Rotation of the arrow itself:
//the +90 below is because the ImageView arrow is pointing towards left by default
RotateAnimation animation = new RotateAnimation(
-(angle+90),
-(angle+90),
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF,
0.5f);
However, I tested four different targetLocations each in directions north east south and west, the arrow only correctly point towards the east west locations. In case of locations in direction north and south the arrow is rotated by 180 degrees, meaning that it will point completely towards the opposite direction. If I add 180 degrees to the rotation, the arrow will correctly point to the locations in north or south, but east and west locations will be wrong then.
It is really frustrating and this makes absolutely no sense to me.
I would be really really thankful if someone could help me out here! Thanks in advance!
I did some further tests and realized that the range from the bearing and the azimuth angles are each (0...180,-180...0) going clockwise and starting from 0, whereas the RotateAnimation takes angles from 0...360 clockwise. Therefore I just converted the azimuth and bearing angles by adding 360 if they were smaller than 0 before I proceeded in the calculations.
I want to set a 2D sprite's rotation so it faces the direction it's moving in. Currently I hooked the accelerometer to the sprite's linear velocity and when I tilt my device it doesn't rotate, only moves. I am running AndEngine on Android.
I want to calculate x+/x-/y+/y- to receive a value in rotation degrees.
atan2(y,x) should do the trick.
So if angle=0 is in positive x direction,
angle = Math.atan2(y_velocity, x_velocity);
gives you the angle you have to rotate.
Figured it out eventually, to achieve this I did the following:
float radians=(float)Math.atan2(-acceleration.x, acceleration.y); //No Idea why I had to invert x axiz but it wouldn't work without it being done
float degrees=(float)Math.toDegrees(radians)+90; //Had to rotate my sprite by 90 degrees
radians=(float)Math.toRadians(degrees);
sprite.setTransform(sprite.getWorldCenter(), radians);
I have a custom built compass that is used as part of a navigation app that I have written. I have also written an algorithm that that smooths out the compass (a type of low-pass filter). Everything works great and the compass is fluid. I pass in a current degrees and previous degrees arguments to the RotateAnimation. Problem is when you spin around quickly with the compass, after a certain point, the gap is so large between the current and previous degrees that the rotate switches direction to the path of least distance. It has to do with the sort of lag that happens from the low-pass filter - that it has to catch up wit the real-time direction. I was wondering if anyone has dealt with this (I have seen some compass apps from the store that handle this) or has some kind of algorithm/solution, to keep the orientation of the rotation. Here is some code:
RotateAnimation rotate = new RotateAnimation(startingPointer, pointerDeg, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotate.setInterpolator(new LinearInterpolator());
rotate.setDuration(ROTATION_INTERVAL);
rotate.setFillAfter(true);
pointer.setAnimation(rotate);
startingPointer = pointerDeg;
In my application, I am rotating a clock hand to the desired amount of minutes. This works good with RotateAnimation. Now what I want to do is to return the hand back to the starting position (0 minutes).
For example:
I first rotate the hand like this:
final RotateAnimation anim = new RotateAnimation(0f, ammountDegress, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 1f);
anim.setFillAfter(true);
anim.setFillEnabled(true)
Then I would like to move the hand back to it's starting position, so that means I should be calling a RotateAnimation after the first animation ends.
The problem is that the pivots have changed, how I can I set the pivot position to the exact position as previous? So that the rotating point is again at the same position of the clock hand.
Edit To make it more clearer - I would like to have something like a fixed point pivot that doesn't change with the rotation, so I am always rotating the hand around the same point.
I hope you can understand what I mean.
I want to rotate the cube when the user is touching it. To rotate it,is quite simple but actual problem is if the user is tilting it then always it should stop in particuler face(cube has 6 faces and i mean that only one face should be visible at one time). Please give your suggetion if anyone worked on that.
In the case of a cube this is simple: Face normals are the cartesian axes. So one looks straigt on a face if you constrain the rotations around the cartesian axes (X, Y, Z) and the rotation angles are multiple of pi/2 = 90°.
So in your code when the user stops interacting, set the rotation angles to the next multiple of 90°
fmod(round(angle/90) * 90, 360); // degrees
fmod(round(angle/(pi/2)) * pi/2, 2*pi); // radians
Either do it hard, or animate it.
If your object is not a cube, but arbitrary, you need to find the additional rotation for the face to get perpendicular to the view axis. This angle is determined by acos( scalar_product(normalize(face_normal), normalize(view_axis)) ) the axis of rotation is given by cross_product(normalize(face_normal), normalize(view_axis))