I need to measure angle between two vectors. I have .kml file that is filled with Latitutes and longitutes
54.90627884784906, 23.98023512082725
54.90568158443394, 23.98021489919758
54.9055211876991, 23.97995622451836
...
So here how I made my vectors:
Vector3 firstVec = new Vector3(new Point3((float)54.90627884784906, (float)23.98023512082725, 0),
new Point3((float)54.90568158443394, (float)23.98021489919758, 0));
Vector3 secondVec = new Vector3(new Point3((float)54.90568158443394, (float)23.98021489919758, 0),
new Point3((float)54.9055211876991, (float)23.97995622451836, 0));
here how I measure angle between two vectors
double angle = firstVec.angle(secondVec);
and here's my result:
0.9824845194816589
Here's image image on my phone representing these coordinates.
Obviously my angle is not correct. How to calculate it?
Your vectors are wrong.
Lat and lon are spherical angle coordinates. I'd recommend that you convert them to rectangular coordinates in 3D before you begin. Once you have those it's easy to calculate the angle in radians using the dot product.
You should also know that lat and lon are expressed in degrees - convert them to radians before you start using them in trig functions.
angle between two vector is Math.acos(Dot Product) result is in radiants, thus you'd multiply by Math.Pi/180
Related
I have two set's of longitude and latitude, i am desperately trying to figure out how many meters point A is displaced from point B, horizontally and vertically.
My goal would be have to +/-X and +/-Y values - I already have the shortest distance between the two points via Location.distanceBetween()....i thought i could use this with the Location.bearingTo() to find the values im looking for via basic trigonometry.
My thinking was i could use the bearing as angle A, 90 degrees as angle C and legnth of Side C (distanceBetween) to calculate the legnth of side A (x axis) and B (y axis) but the results were underwhelming to say the least lol
//CALCULATE ANGLES
double ANGLE_A;
ANGLE_A = current_Bearing; //Location.bearingTo()
ANGLE_A = ANGLE_A*Math.PI/180; //CONVERT DEGREES TO RADIANS
double ANGLE_C;
ANGLE_C = 90; // Always Right Angle
ANGLE_C = ANGLE_C*Math.PI/180; //CONVERT DEGREES TO RADIANS
double ANGLE_B;
ANGLE_B = 180 - ANGLE_A - ANGLE_C; // 3 sides of triangle must add up to 180, if 2 sides known 3rd can be calced
ANGLE_B = ANGLE_B*Math.PI/180; //CONVERT DEGREES TO RADIANS
//CALCULATE DISTANCES
double SIDE_C = calculatedDistance; //Location.distanceTo()
double SIDE_A = Math.sin(ANGLE_A) * SIDE_C /Math.sin(ANGLE_C);
double SIDE_B = Math.sin(ANGLE_B)*SIDE_C/Math.sin(ANGLE_C);
What im noticing is that my bearing changes very little between the two points regardless of how we move, though mind you im testing this at 10 - 100m distance, its always at 64.xxxxxxx and only the last few decimals really change.
All the online references i can find always look at computing the shortest path, and although this awesome site references x and y positions it always ends up combining them into shortest distance again
Would SUPER appreciate any pointers in the right direction!
Since the earth is not flat, your idea with 90 degree angles will not work properly.
What might be better, is this.
Lets say your 2 known points A and B have latitude and longitude latA, longA and latB, longB.
Now you could introduce two additional points C and D with latC = latA, longC = longB, and latD = latB, longD = longA, so the points A, B, C, D form a rectangle on the earth's surface.
Now you can simply use distanceBetween(A, C) and distanceBerween(A, D) to get the required distances.
It may be possible to utilize Location.distanceBetween(), if following conditions meet,
the points are located far apart from polar regions and
distance is short enough (compared to radius of the Earth).
The way is very simple. Just fix either longitude or latitude and vary only the other. Then calculate distance.
Location location1 = new Location("");
Location location2 = new Location("");
location1.setLatitude(37.4184359437);
location1.setLongitude(-122.088038921);
location2.setLatitude(37.3800232707);
location2.setLongitude(-122.073230422);
float[] distance = new float[3];
Location.distanceBetween(
location1.getLatitude(), location1.getLongitude(),
location2.getLatitude(), location2.getLongitude(),
distance
);
double lat_mid = (location1.getLatitude() + location2.getLatitude()) * 0.5;
double long_mid = (location1.getLongitude() + location2.getLongitude()) * 0.5;
float[] distanceLat = new float[3];
Location.distanceBetween(
location1.getLatitude(), long_mid,
location2.getLatitude(), long_mid,
distanceLat
);
float[] distanceLong = new float[3];
Location.distanceBetween(
lat_mid, location1.getLongitude(),
lat_mid, location2.getLongitude(),
distanceLong
);
double distance_approx = Math.sqrt(
Math.pow(distanceLong[0], 2.0) + Math.pow(distanceLat[0], 2.0)
);
Compare distance[0] and distance_approx, check whether accuracy meets your requiement.
If your points are close enough, you may easily calculate x-y distances from latitude / longitude once you know that 1 degree of latitude is 111km, and one degree of longitude is 111km * cos(latitude):
y_dist = abs(a.lat - b.lat) * 111000;
x_dist = abs(a.lon - b.lon) * 111000 * cos(a.lat);
For short distances we could easily ignore that earth is not exactly a sphere, the error is approximately 0.1-0.2% depending on your exact location.
There is no valid answer to this question until you define what projection.
The azimuth of a "straight" line varies along the route unless you are travelling exactly due south or due north. You can only calculate the angles at each node, or azimuth at a specific point along the route. Angles at the nodes will not add up to 180° because you're referring to an ellipsoidal triangle, and calculating an ellipsoidal triangle is a multiple-step process that in all honesty, is better left to the libraries out there such as OSGEO.
If you want to fit the geometry to a plane Cartesian, it is usually using the Lambert projection for areas mostly long on east and west directions, and Transverse Mercator on longer north to south projections. The entire Earth is mapped in the UTM (Universal Transverse Mercator) that will give you Cartesian coordinates anywhere, but in no case will you get perfect Eucldian geometry when dealing with geodetics. For instance, if you go south 10 miles, turn left 90° and go east for 10 miles, turn left 90° again, you can be anywhere from 10 miles from your starting point, to exactly back to where you started, if that point happened to be the North pole. So you may have a mathematically beautiful bearing on the UTM coordinate plane, but on the ground, you cannot turn the same angles as the UTM geometry indicates and follow that same path on ground. You will either follow a straight line on the ground and a curved line on a cartesian plane, or vice-versa.
You could do a distance between two points on the same northings and separately, the same eastings, and derive a north distance and an east distance. However, in reality the angles of this triangle will make sense only on paper, and not on the globe. If a plane took off at the bearing calculated by such a triangle, it would arrive in the wrong continent.
Given an existing point in lat/long, distance(inches) and bearing (in degrees converted to radians), I'm trying to calculate the new lat/long. But the resulting is some times inaccurate because I'm trying to measure a small area for the new lat/long. Currently, I'm trying to get the next foot lat/long but some times it has a 1-inch error. I used the following algorithm for this implementation. Referred this thread for the algorithm Get lat/long given current point, distance and bearing.
public LatLng calculateLatLangFromDistance(double brng, double distance, LatLng latLng){
double lat1 = Math.toRadians(latLng.getLatitude());
double long1 = Math.toRadians(latLng.getLongitude());
double br = Math.toRadians(brng);
double lat2 = Math.asin(Math.sin(lat1)*Math.cos(distance/r) +
Math.cos(lat1)* Math.sin(distance/r)* Math.cos(br));
double long2 = long1 + Math.atan2(Math.sin(br)*Math.sin(distance/r)*Math.cos(lat1),
Math.cos(distance/r)-Math.sin(lat1)*Math.sin(lat2));
lat2 = Math.toDegrees(lat2);
long2 = Math.toDegrees(long2);
LatLng latLng1 = new LatLng();
latLng1.setLongitude(long2);
latLng1.setLatitude(lat2);
return latLng1;
}
r is defined as 250826771.6535433 // //Radius of the Earth from inches
I'm using the above implementation to generate a 1-foot grid to mapbox map layer but resulting grid's some lines are 1-inch inaccurate. Is there any way to improve this implementation for better results or is there another way to get accurate lat/long for this?
this is the generated grid and I did a line drawing to get the idea about line length of the some lines in the grid.
You can use the spherical geometry utilities of the Google Maps SDK for Android utility library.
The specific method that you can use will be the computeOffset method. You can see it when you search the SphericalUtil in this link.
ComputeOffset returns the LatLng resulting from moving a distance from an origin in the specified heading (expressed in degrees clockwise from north). Here are the parameters that you need to specify:
from - The LatLng from which to start.
distance - The distance to travel.
heading - The heading in degrees clockwise from north.
To use this, add the utility library to your dependencies:
implementation 'com.google.maps.android:android-maps-utils:0.5'
This is the sample of a line of code that I use:
LatLng newCoordinates = SphericalUtil.computeOffset(new LatLng(-25.363, 131.044),30000, 90);
Hope this helps!
alright so im making a ai for a zombie in one of my games, but when i try to rotate the zombie so that he is facing the player everything goes out of wack. they rotate the wrong way, spin around when i get close even though the angle shouldn't change.
here is some of my code: ps ignore the z, this game is 3d but im only rotating on on axis so i can code this as though it was xy.
//get camera/player yx
float PlayerYPosition = Player.getPosition().y;
float PlayerXPosition = Player.getPosition().z;
//get zombie yx
float ZombieYPosition = Zombie.getPosition().y;
float ZombieXPosition = Zombie.getPosition().z;
//get side lengths
float sideY = (CameraYPosition - ZombieYPosition);
float sideX = (CameraXPosition - ZombieXPosition);
//get angle
float angle = (float)Math.atan2(sideX,sideY);
//move decimal place out so ex: 0.90f is 90.0f
float ans = angle * 100;
//set rotation of zombie
super.setRotY(ans);
Math.atan2 returns its value in radians, not degrees. To convert to degrees, multiply by either 180/pi or 360/(2 pi):
float ans = angle * 180 / Math.PI;
Java even has a builtin function for this, Math.toDegrees: (thanks #yshavit)
float ans = Math.toDegrees(angle);
Also, what #yshavit says in the comments: you should be using radians throughout the code. But that's perhaps too much work, or you might rely on 3rd party libraries which work with degrees.
I am trying to make a circle (actually a flat cylinder) rotate so that the edge crosses two points in world position. These two points can be anywhere on a sphere. The sphere has the same radius and position as the cylinder. the origin of both is [0,0,0].
It's a little bit hard to explain, so I included three pictures that I hope illustrates what I am trying to accomplish.
Here you see what I am trying to accomplish. The yellow circle represents one of the points along the sphere, while the red circle represents the other point. The blue line is actually a flat cylinder going through the sphere, and is rotated so that it goes through both points.
Here is another similar picture, but with the points at different locations.
In this picture one can see the cylinder in full, as the sphere has been hidden.
Now, I am really terrible at math, so I would really love an answer made up of pseudo code or a programming language. And if I should be so lucky, java.
The circles rotation can be represented with either a quaternion or a matrix
So far, what I have tried, is rotating the cylinder with an up vector towards one of the points, and a forward vector towards the other point. But I can't seem to make it work. I have also tried other solutions, most of them involving two rotations (one for each point), but I end up having trouble when combining the rotations.
Here is my current non-working code:
This code makes the circle go through the first point, and then rotates it with an "up vector" towards the same point, this second rotation varies depending on the first point position, and is kind off all over the place.
//calculate direction vector between the two points
point1point2dir.set(point1Pos);
//subtract point two position
point1point2dir.sub(point2Pos);
//normalize
point1point2dir.nor();
//make two quaternions for rotation
Quaternion rot1=new Quaternion();
Quaternion rot2=new Quaternion();
//set first rotation two a rotation between X-axis and point1 position. Vector3.X = (1,0,0)
rot1.set(m.quatUtils.getRot(Vector3.X, point1Pos));
//crossmuliply direction vector between the two points with X-axis
point1point2dir.crs(Vector3.X);
//set the second rotation to a rotation between Z-Axis and the crossmultiplied direction vector
rot2.set(m.quatUtils.getRot(Vector3.Z, point1point2dir));
//multiply the two rotations
rot1.mul(rot2);
//apply the rotation to the cylinders matrix
cylinderMatrix.rotate(rot1);
//the function that gets the quaternion rotation between two vectors
Quaternion getRot(Vector3 pStart, Vector3 pDest) {
start.set(pStart);
dest.set(pDest);
start.nor();
dest.nor();
cosTheta = Vector3.dot(start.x, start.y, start.z, dest.x, dest.y,
dest.z);
rotationAxis.set(0.0f, 0.0f, 0.0f);
if (cosTheta < -1.0f + 0.001f) {
rotationAxis.set(Z_AXIS);
rotationAxis.crs(start);
if (rotationAxis.len2() < 0.01f) {
rotationAxis.set(X_AXIS);
rotationAxis.crs(start);
}
rotationAxis.nor();
resultQuat.set(rotationAxis, 180.0f);
return resultQuat;
}
rotationAxis.set(start);
rotationAxis.crs(dest);
s = (float) Math.sqrt((1 + cosTheta) * 2);
invs = 1.0f / s;
resultQuat.set(rotationAxis.x * invs, rotationAxis.y * invs,
rotationAxis.z * invs, s * 0.5f);
return resultQuat;
}
I would suggest this solution:
Calculate v1 and v2 as the vectors from the center of the sphere to each point that you want the cylinder to pass trough.
Cross product v1 and v2 to get the vector up of the cylinder, let's call it n.
Position the center of the cylinder in the center of the sphere.
Rotate the cylinder using n as vector up.
I figured out the solution! It was actually really simple. I don't know how I managed to bungle the math as much as I did earlier. I actually did spend alot of time on this >:)
Sorry if I wasted anybodys time!
The solution:
find direction vector from point1 (A) to point2 (B).
crossmultiply direction vector with point2 to get (C)
Find the quaternion which represents the rotation from Z-axis to the crossmultiplied direction vector (C), function for doing this included in the code attached to the question.
apply rotation.
Here is the working code (yay):
//the rotation
Quaternion rot=new Quaternion();
//the direction from point1 to point 2 (the point positions are in this case also the direction vectors from center)
point1point2dir.set(point1Pos);
point1point2dir.sub(point2Pos);
point1point2dir.nor();
//crossmultiplied with point2
point1point2dir.crs(point2Pos);
//set the rotation to the rotation between Z-axis and the crossmultiplied direction between point 1 and 2
rot.set(m.quatUtils.getRot(Vector3.Z, point1point2dir));
//apply rotation
ekvatorMatrix.rotate(rot);
And here is the code for the function that returns the quaternion between two vectors:
Quaternion getRot(Vector3 pStart, Vector3 pDest) {
start.set(pStart);
dest.set(pDest);
start.nor();
dest.nor();
cosTheta = Vector3.dot(start.x, start.y, start.z, dest.x, dest.y,
dest.z);
rotationAxis.set(0.0f, 0.0f, 0.0f);
if (cosTheta < -1.0f + 0.001f) {
rotationAxis.set(Z_AXIS);
rotationAxis.crs(start);
if (rotationAxis.len2() < 0.01f) {
rotationAxis.set(X_AXIS);
rotationAxis.crs(start);
}
rotationAxis.nor();
resultQuat.set(rotationAxis, 180.0f);
return resultQuat;
}
rotationAxis.set(start);
rotationAxis.crs(dest);
s = (float) Math.sqrt((1 + cosTheta) * 2);
invs = 1.0f / s;
resultQuat.set(rotationAxis.x * invs, rotationAxis.y * invs,
rotationAxis.z * invs, s * 0.5f);
return resultQuat;
}
Assuming that the initial cylinder is axis aligned with the "circle" ends in positive and negative X direction, and assuming cylinder and sphere is initially unit size (radius=1.0) I would do the following:
Convert the world coordinate representation of the Red and "Yellow" points (let's just for fun call them A and B shall we) to normalized vectors pointing from centre [0,0,0] (from now on called C)
Calculate the angle between CA and CB (which is really just between A and B). Let's call this angle W
Calculate the vector perpendicular to both A and B by doing a cross product. Lets call this new vector D.
Find the rotation matrix that rotates from [0,0,1] to B. Lets call this M1. This can be done in the same way as in point 3 (create a perpendicular vector and rotate identity matrix around it with the angle between the normalized vectors).
Find the rotation matrix that rotates W around D. Let's call this M2
Combine M1 + M2 into M3
You result is M3
This was not tested and so I don't know if it works.
Okay, so I'm trying to get the angle of two quaternions, and it almost works perfectly, but then it jumps from
evec angle: 237.44999653311922
evec angle: 119.60001380112993
and I can't figure out why for the life of me. (Note: evec was a old variable name that just stayed in the print)
Anyway, here's my code:
FloatBuffer fb = BufferUtils.createFloatBuffer(16);
// get the current modelview matrix
GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, fb);
Matrix4f mvm = new Matrix4f();
mvm.load(fb);
Quaternion qmv2 = new Quaternion();
Matrix4f imvm = new Matrix4f();
Matrix4f.invert(mvm, imvm);
qmv2.setFromMatrix(imvm);
qmv2.normalise();
Matrix3f nil = new Matrix3f();
nil.setIdentity();
Quaternion qnil = new Quaternion();
qnil.setFromMatrix(nil);
qnil.normalise();
float radAngle = (float)(2.0 * Math.acos(Quaternion.dot(qmv2, qnil)));
System.out.println("evec angle: " + Math.toDegrees(radAngle));
How do I make it stop jumping from 237 to 119 and keep going up to the full 360?
First, what does an angle between two four dimensional vectors (=quaternions) mean to you geometrically? You can calculate it but the result might not make sense. Maybe you are looking for the angle between the axis of the rotations that the two quaternions represent?
Second, you have an error here:
float radAngle = (float)(2.0 * Math.acos(Quaternion.dot(qmv2, qnil)));
^^^^^
The result from acos is the angle. Don't multiply by 2.
Third, the angle between two vectors in a 3D or 4D space can never be greater than 180°. On a plane it can because the plane imposes an orientation. In a 3D space you would have to define an arbitrary direction as "up" to get angles higher than 180°.