Finding the tangent on a given point of a polyline - coordinates

I have a list of X,Y coordinates that represents a road. For every 5 meters, I need to calculate the angle of the tangent on this road, as I have tried to illustrate in the image.
My problem is that this road is not represented by a mathematical function that I can simply derive, it is represented by a list of coordinates (UTM33N).
In my other similar projects we use ArcGIS/ESRI libraries to perform geographical functions such as this, but in this project I need to be independent of any software that require the end user to have a license, so I need to do the calculations myself (or find a free/open source library that can do it).
I am using a cubic spline function to make the line rounded between the coordinates, since all tangents on a line segment would just be parallell to the segment otherwise.
But now I am stuck. I am considering simply calculating the angle between any three points on the line (given enough points), and using this to find the tangents, but that doesn't sound like a good method. Any suggestions?

In the end, I concluded that the points were plentiful enough to give an accurate angle using simple geometry:
//Calculate delta values
var dx = next.X - curr.X;
var dy = next.Y - curr.Y;
var dz = next.Z - curr.Z;
//Calculate horizontal and 3D length of this segment.
var hLength = Math.Sqrt(dx * dx + dy * dy);
var length = Math.Sqrt(hLength * hLength + dz * dz);
//Calculate horizontal and vertical angles.
hAngle = Math.Atan(dy/dx);
vAngle = Math.Atan(dz/hLength);

Related

How to reposition a circle to be outside of circumference of two other circles?

This is a question for Unity people or Math geniuses.
I'm making a game where I have a circle object that I can move, but I don't want it to intersect or go into other (static) circles in the world (Physics system isn't good enough in Unity to simply use that, btw).
It's in 3D world, but the circles only ever move on 2 axis.
I was able to get this working perfectly if circle hits only 1 other circle, but not 2 or more.
FYI: All circles are the same size.
Here's my working formula for 1 circle to move it to the edge of the colliding circle if intersecting:
newPosition = PositionOfStaticCircleThatWasJustIntersected + ((positionCircleWasMovedTo - PositionOfStaticCircleThatWasJustIntersected).normalized * circleSize);
But I can't figure out a formula if the moving circle hits 2 (or more) static circles at the same time.
One of the things that confuse me the most is the direction issue depending on how all the circles are positioned and what direction the moving circle is coming from.
Here's an example image of what I'm trying to do.
Since we're operating in a 2D space, let's approach this with some geometry. Taking a close look at your desired outcome, a particular shape become apparent:
There's a triangle here! And since all circles are the same radius, we know even more: this is an isosceles triangle, where two sides are the same length. With that information in hand, the problem basically boils down to:
We know what d is, since it's the distance between the two circles being collided with. And we know what a is, since it's the radius of all the circles. With that information, we can figure out where to place the moved circle. We need to move it d/2 between the two circles (since the point will be equidistant between them), and h away from them.
Calculating the height h is straightforward, since this is a right-angle triangle. According to the Pythagorean theorem:
// a^2 + b^2 = c^2, or rewritten as:
// a = root(c^2 - b^2)
float h = Mathf.Sqrt(Mathf.Pow(2 * a, 2) - Mathf.Pow(d / 2, 2))
Now need to turn these scalar quantities into vectors within our game space. For the vector between the two circles, that's easy:
Vector3 betweenVector = circle2Position - circle1Position
But what about the height vector along the h direction? Well, since all movement is on 2D space, find a direction that your circles don't move along and use it to get the cross product (the perpendicular vector) with the betweenVector using Vector3.Cross(). For
example, if the circles only move laterally:
Vector3 heightVector = Vector3.Cross(betweenVector, Vector3.up)
Bringing this all together, you might have a method like:
Vector3 GetNewPosition(Vector3 movingCirclePosition, Vector3 circle1Position,
Vector3 circle2Position, float radius)
{
float halfDistance = Vector3.Distance(circle1Position, circle2Position) / 2;
float height = Mathf.Sqrt(Mathf.Pow(2 * radius, 2) - Mathf.Pow(halfDistance, 2));
Vector3 betweenVector = circle2Position - circle1Position;
Vector3 heightVector = Vector3.Cross(betweenVector, Vector3.up);
// Two possible positions, on either side of betweenVector
Vector3 candidatePosition1 = circle1Position
+ betweenVector.normalized * halfDistance
+ heightVector.normalized * height;
Vector3 candidatePosition2 = circle1Position
+ betweenVector.normalized * halfDistance
- heightVector.normalized * height;
// Absent any other information, the closer position will be assumed as correct
float distToCandidate1 = Vector3.Distance(movingCirclePosition, candidatePosition1);
float distToCandidate2 = Vector3.Distance(movingCirclePosition, candidatePosition2);
if (distToCandidate1 < distToCandidate2){
return candidatePosition1;
}
else{
return candidatePosition2;
}
}

Rotate a object in LatLng coordinate system

Hey there I am trying to rotate a line around its own center within the latlng system.
I got the angle and the two points. So I tried to append the rotation matrix, like this (following method takes the latitude and longitude of a point and the angle):
LatLng rotate(double lat, double long, double angle){
double rad = angle*pi/180;
double newLong = long*cos(rad)-lat*sin(rad);
double newLat = long* sin(rad) + lat*cos(rad);
return LatLng(newLat,newLong);
}
For example I got the point A (latitude:x,longitude:y) and the point B(latitude:x,longitude:y). Connecting these two points leads to a line. Now I want two rotate the line around it's own center with the above method, by calling:
LatLng newA = rotate(A.latitude,A.longitude);
LatLng newB = rotate(B.latitude,B.longitude);
But when I connect the two Points newA and NewB there is not the desired effect.
As #Abion47 clarified in his answer I need a rotation in 3-dimension, but how to do so? And is it possible with 2-dimension if it is a very small line?
So here's the rub. The problem I mentioned before is that a latitude-longitude pair are a pair of angles, not a 2D vector of a point on a graph, so trying to use them to rotate a point in 3D space on the surface of a sphere is going to run into its own problems. One thing that turns out, however, is that as long as you don't pick points that cross either the international date line or the poles, you can still use this trick by just pretending the angle pair is a 2D vector.
The real problem is that you are wanting to rotate the points around the midpoint, but your math is merely performing a straight rotation which will be rotating them around the origin instead (i.e. 0,0). You need to offset your "points" by the point you are using as a reference.
import 'dart:math';
LatLng rotate(LatLng coord, LatLng midpoint, double angle) {
// Make this constant so it doesn't have to be repeatedly recalculated
const piDiv180 = pi / 180;
// Convert the input angle to radians
final r = angle * piDiv180;
// Create local variables using appropriate nomenclature
final x = coord.longitude;
final y = coord.latitude;
final mx = midpoint.longitude;
final my = midpoint.latitude;
// Offset input point by the midpoint so the midpoint becomes the origin
final ox = x - mx;
final oy = y - my;
// Cache trig results because trig is expensive
final cosr = cos(r);
final sinr = sin(r);
// Perform rotation
final dx = ox * cosr - oy * sinr;
final dy = ox * sinr + oy * cosr;
// Undo the offset
return LatLng(dy + my, dx + mx);
}
Using this approach, I ended up with the following results:
The blue points are the input, the green point is the calculated midpoint, and the red points are each of the blue points passed through a 90 degree rotation.
(Note that the distance between the blue points appears to be farther than the distance between the red points. This is because I visualized the results in Google Maps which uses the Mercator projection, and that had the result of screwing with where the points appear to be relative to each other. If you were to visualize this on a globe, the points should appear the correct distance from each other.)

How to get coords between 2 points

I cannot find exactly what I'm looking for or reading google documentation I missed it, I just need a function or whatever to submit 2 point, start and end, and get X waypoint in between.
Is there some api like "www.somesite.com/api.php?start=43.12,12.23&end=44.12,12.23&number_of_waypoints=5" that return some json?
thank you!
First of all, this will require working with geodesics, which are the shortest lines passing through two points around the Earth, assuming the Earth is an ellipsoid. WGS84 is the standard coordinate system you will see most widely used for "latitude + longitude" coordinates, and this assumes the Earth is an ellipsoid.
To solve this problem, you first need to find the azimuth (bearing angle from north) and distance between two coordinates. The way to calculate this is by solving the inverse geodesic problem.
Once we have this distance (let's say in metres), we can divide it by n, where n - 1 is the number of waypoints we want in between the line. This gives us the distance d metres between each waypoint.
Now, we need to plot points at intervals of d metres along this line. To do this, we can solve the direct geodesic problem. This gives us a new set of coordinates after moving a given distance from a given point with a given azimuth. We can do this repeatedly to get new points moving d metres from the previous point each time. One thing to note with this is that the resultant azimuth to the end of the line from different points within the line will vary, so the destination azimuth must be obtained after each stage and used for calculating the next point.
Solving the direct and inverse geodesic problems requires mathematical formulas, of which multiple are available. However, for your PHP application, you are probably best not trying to implement these yourself, but instead use a library which can do this for you. One popular library for PHP which does this is called phpgeo.
Here's an example of how this might be implemented with phpgeo:
<?php
use Location\Coordinate;
use Location\Distance\Vincenty;
use Location\Bearing\BearingEllipsoidal;
$numPoints = 5;
$coordsA = new Coordinate(50.0, 0.0);
$coordsB = new Coordinate(51.0, 1.0);
$bearingCalculator = new BearingEllipsoidal();
$distanceCalculator = new Vincenty();
// Inverse geodesic problem
// Calculate total length of line between coords
$totalDistance = $distanceCalculator->getDistance($coordsA, $coordsB);
$intervalDistance = $totalDistance / ($numPoints + 1);
// Inverse geodesic problem
// Calculate angle to destination
$currentBearing = $bearingCalculator->calculateBearing($coordsA, $coordsB);
$currentCoords = $coordsA;
$points = [];
for ($i = 0; $i < $numPoints; $i++) {
// Direct geodesic problem
// Calculate new point along line
$currentCoords =
$bearingCalculator->calculateDestination($currentCoords,
$currentBearing,
$intervalDistance);
// Add these new coordinates to the list
array_push($points, $currentCoords);
// Inverse geodesic problem
// Recalculate angle to destination
$currentBearing =
$bearingCalculator->calculateBearing($currentCoords,
$coordsB);
}
// Print out the list of points
foreach ($points as $point) {
echo "{$point->getLat()}, {$point->getLng()}\n";
}

finding the intersection of a line with a non monotonic arbitrary surface?

I have a surface Z on a X-Y grid for which I want to find the intersection point with a line. I used so far this code for finding the intersection:
x_ray = x_source + t * x_dir
y_ray = y_source + t * y_dir
z_ray = z_source + t * z_dir
height_above_plane = #(t) z_source + t * z_dir - interp2(X, Y, Z, ...
x_source + t*x_dir, y_source + t*y_dir)
t_intercept = fzero(height_above_plane, 0);
my problem is that when my surface is "wiggly", the function has several zero crossing points, and I want to find the minimal out of them.
How can I do that?
Thanks
A possible approach is to project the ray onto the XY domain and draw the corresponding Bresenham line. As you go along this line, grid cell per grid cell, you will compute the Z altitudes along the ray and check if their range overlaps the range of altitudes of the surface (i.e. the min and max value in this cell).
If yes, you have to find the 3D intersection between the ray and the interpolating surface, an hyperbolic paraboloid. If the intersection does fall inside the grid cell considered, you are done. Otherwise, continue the march along the ray.
Convert the surface to matlab mesh, then use this code.

How can I correctly calculate the direction for a moving object?

I'm solving the following problem: I have an object and I know its position now and its position 300ms ago. I assume the object is moving. I have a point to which I want the object to get.
What I need is to get the angle from my current object to the destination point in such a format that I know whether to turn left or right.
The idea is to assume the current angle from the last known position and the current position.
I'm trying to solve this in MATLAB. I've tried using several variations with atan2 but either I get the wrong angle in some situations (like when my object is going in circles) or I get the wrong angle in all situations.
Examples of code that screws up:
a = new - old;
b = dest - new;
alpha = atan2(a(2) - b(2), a(1) - b(1);
where new is the current position (eg. x = 40; y = 60; new = [x y];), old is the 300ms old position and dest is the destination point.
Edit
Here's a picture to demonstrate the problem with a few examples:
In the above image there are a few points plotted and annotated. The black line indicates our estimated current facing of the object.
If the destination point is dest1 I would expect an angle of about 88°.
If the destination point is dest2 I would expect an angle of about 110°.
If the destination point is dest3 I would expect an angle of about -80°.
Firstly, you need to note the scale on the sample graph you show above. The x-axis ticks move in steps of 1, and the y-axis ticks move in steps of 20. The picture with the two axes appropriately scaled (like with the command axis equal) would be a lot narrower than you have, so the angles you expect to get are not right. The expected angles will be close to right angles, just a few degrees off from 90 degrees.
The equation Nathan derives is valid for column vector inputs a and b:
theta = acos(a'*b/(sqrt(a'*a) * sqrt(b'*b)));
If you want to change this equation to work with row vectors, you would have to switch the transpose operator in both the calculation of the dot product as well as the norms, like so:
theta = acos(a*b'/(sqrt(a*a') * sqrt(b*b')));
As an alternative, you could just use the functions DOT and NORM:
theta = acos(dot(a,b)/(norm(a)*norm(b)));
Finally, you have to account for the direction, i.e. whether the angle should be positive (turn clockwise) or negative (turn counter-clockwise). You can do this by computing the sign of the z component for the cross product of b and a. If it's positive, the angle should be positive. If it's negative, the angle should be negative. Using the function SIGN, our new equation becomes:
theta = sign(b(1)*a(2)-b(2)*a(1)) * acos(dot(a,b)/(norm(a)*norm(b)));
For your examples, the above equation gives an angle of 88.85, 92.15, and -88.57 for your three points dest1, dest2, and dest3.
NOTE: One special case you will need to be aware of is if your object is moving directly away from the destination point, i.e. if the angle between a and b is 180 degrees. In such a case you will have to pick an arbitrary turn direction (left or right) and a number of degrees to turn (180 would be ideal ;) ). Here's one way you could account for this condition using the function EPS:
theta = acos(dot(a,b)/(norm(a)*norm(b))); %# Compute theta
if abs(theta-pi) < eps %# Check if theta is within some tolerance of pi
%# Pick your own turn direction and amount here
else
theta = sign(b(1)*a(2)-b(2)*a(1))*theta; %# Find turn direction
end
You can try using the dot-product of the vectors.
Define the vectors 'a' and 'b' as:
a = new - old;
b = dest - new;
and use the fact that the dot product is:
a dot b = norm2(a) * norm2(b) * cos(theta)
where theta is the angle between two vectors, and you get:
cos(theta) = (a dot b)/ (norm2(a) * norm2(b))
The best way to calculate a dot b, assuming they are column vectors, is like this:
a_dot_b = a'*b;
and:
norm2(a) = sqrt(a'*a);
so you get:
cos(theta) = a'*b/(sqrt((a'*a)) * sqrt((b'*b)))
Depending on the sign of the cosine you either go left or right
Essentially you have a line defined by the points old and new and wish to determine if dest is on right or the left of that line? In which case have a look at this previous question.