draw arc on map with any projection - algorithm

I want minimize of usage of projection function to draw arc on plane.
As input of algorithm I have:
latitude and longitude of center C
radius R (orthodromic distance)
azimuth of begin of arc according to center A1
azimuth of end of arc according to center A2
projection function proj that take latitude longitude and give x and y on plane,
this function is continuous and has derivative, and its derivative is continuous
proj^-1 function that inverse proj
Output: array of points x, y on plane such is that their original lat, lon = proj^-1(x, y) has orthodromic distance ~ R and azimuth lay between A1 and A2.
In such algorithm I want reduce calls to proj.
At now I can only imagine such slow and not accurate algorithm:
P1 = direct geodetic problem(C, R, A1)
P1_plane = proj(P1)
P1_plane_shift = P1_plane.x + 1, P1_plane.y + 1
P1_shift = proj^-1(P1_plane_shift)
A1_shift = inverse geodetic problem(P1_shift)
dA = A - A1_shift
after that I run cycle from A1 to A2 with dA step using direct geodetic problem helper function.
Such algorithm have such disadvantages:
Not accurate, because of angle error of proj may change from area near P1 to area near P2 = direct geodetic problem(C, R, A2) [Never see this problem on real-life map projections and with R < 100 kilometer]
Call proj to often, so drawing works to slow for me
Any thoughts of improvements of this algorithm?
Update here is plot of possible input:

Related

Efficient method to check if point is within a diamond

I have an array of diamonds as shown in the image and I know the position of every diamond and the distance from the origin of the diamond to any vertex (They are all the same distance from the center). I am also given a point. Given that information what is the most efficient method to find which diamond the point is in.
I know that I can just check the distance of the point from the position of every diamond but that seems way too cpu intensive as I have to do this multiple times.
Also, this shouldn't matter, but I am using C# and Unity 3D to do this.
If your diamonds form a regular pattern as in your picture, then just perform coordinate transformation to rotate the whole thing 45 degrees CW or CCW with (0, 0) as the origin. After that the problem becomes trivial: locating a point in a regular orthogonal grid.
Diamonds border line have equations
x + y = a0 + u * Size
y - x = b0 + v * Size
where a0, b0 are coordinates of the some vertex of base diamond (that has cell coordinates 0, 0), u and v are cell coordinates, Size is edge length. So to find what diamond point (px, py) belongs to, you can calculate
u = Floor((px + py - a0) / Size))
v = Floor((py - px - b0) / Size))

Algorithm for deriving control points of a bezier curve from points along that curve?

I've been looking for, but obviously not finding, an algorithm that will allow me to plug in a list of x,y coordinates that are known to be along a curve so as to get the 4 control points for a cubic bezier curve spit out.
To be more precise, I'm looking for an algorithm that will give me the two control points required to shape the curve while inputting a series of discrete points including the two control points which determine the start and end of the curve.
Thanks!
Edit: Okay, due to math, an old foe, I need to ask for the bezier curve of best fit to a polynomial function.
So I assume that the endpoints are fixed, and then you have a number of (x,y) sample points that you want to fit with a cubic Bezier.
The number of sample points that you have will determine what approach to take. Let's look through a few cases:
2 points
2 sample points is the simplest case. That gives you a total of 4 points, if you count the end points. This is the number of CVs in a cubic Bezier. To solve this, you need a parameter (t) value for both of the sample points. Then you have a system of 2 equations and 2 points that you need to solve, where the equation is the parametric equation of a Bezier curve at the t values you've chosen.
The t values can be whatever you like, but you will get better results by using either 1/3 and 2/3, or looking at relative distances, or relative distances along a baseline, depending on your data.
1 point
This is similar to 2 points, except that you have insufficient information to uniquely determine all your degrees of freedom. What I would suggest is to fit a quadratic Bezier, and then degree elevate. I wrote up a detailed example of quadratic fitting in this question.
More than 2 points
In this case, there isn't a unique solution. I have used least-squares approximation with good results. The steps are:
Pick t values for each sample
Build your system of equations as a matrix
Optionally add fairing or some other smoothing function
Solve the matrix with a least-squares solver
There is a good description of these steps in this free cagd textbook, chapter 11. It talks about fitting b-splines, but a cubic bezier is a type of b-spline (knot vector is 0,0,0,1,1,1 and has 4 points).
Let's say you have a curve y = f(x)
To define a bezier curve you need 4 points, like:
P1x, P1y, P2x, P2y, P3x, P3y and P4x and P4y
P1 and P4 you are the begin/end points of the curve. P2 and P3 are control points.
You already know where the beginning and end of the curve is. You have to calculate P2 and P3. The x coordinate P2x and P3x are easy, because you just pick them by selecting the curve's t to be eg 1/3 and 2/3. So you have P2x and P3x
Then, you end up with a system of two equations and two unknowns (the P2y and P3y).
After crunching some math you end up with something like this:
(My f(x) was a cubic polynomial, which also guaranteed that I would be able to fit one cubic Bezier curve to it exactly.)
/**
#params {Object} firstPoint = {x:...,y...}
#params {Object} lastPoint = {x:...,y...}
#params {Object} cubicPoly Definition of a cubic polynomial in the form y=ax^3+bx^2+c.
Has a method EvaluateAt, which calculates y for a particular x
*/
var CalcBezierControlPoints = function(firstPoint, lastPoint, cubicPoly) {
var xDiff = lastPoint.X - firstPoint.X;
var x1 = firstPoint.X + xDiff / 3.0;
var x2 = firstPoint.X + 2.0 * xDiff / 3.0;
var y1 = cubicPoly.EvaluateAt(x1);
var y2 = cubicPoly.EvaluateAt(x2);
var f1 = 0.296296296296296296296; // (1-1/3)^3
var f2 = 0.037037037037037037037; // (1-2/3)^3
var f3 = 0.296296296296296296296; // (2/3)^3
var b1 = y1 - firstPoint.Y * f1 - lastPoint.Y / 27.0;
var b2 = y2 - firstPoint.Y * f2 - f3 * lastPoint.Y;
var c1 = (-2 * b1 + b2) / -0.666666666666666666;
var c2 = (b2 - 0.2222222222222 * c1) / 0.44444444444444444;
var p2 = {};
var p3 = {};
p2.X = x1;
p2.Y = c1;
p3.X = x2;
p3.Y = c2;
return ([p2, p3]);
}

Calculating quaternion for transformation between 2 3D cartesian coordinate systems

I have two cartesian coordinate systems with known unit vectors:
System A(x_A,y_A,z_A)
and
System B(x_B,y_B,z_B)
Both systems share the same origin (0,0,0). I'm trying to calculate a quaternion, so that vectors in system B can be expressed in system A.
I am familiar with the mathematical concept of quaternions. I have already implemented the required math from here: http://content.gpwiki.org/index.php/OpenGL%3aTutorials%3aUsing_Quaternions_to_represent_rotation
One possible solution could be to calculate Euler angles and use them for 3 quaternions. Multiplying them would lead to a final one, so that I could transform my vectors:
v(A) = q*v(B)*q_conj
But this would incorporate Gimbal Lock again, which was the reason NOT to use Euler angles in the beginning.
Any idead how to solve this?
You can calculate the quaternion representing the best possible transformation from one coordinate system to another by the method described in this paper:
Paul J. Besl and Neil D. McKay
"Method for registration of 3-D shapes", Sensor Fusion IV: Control Paradigms and Data Structures, 586 (April 30, 1992); http://dx.doi.org/10.1117/12.57955
The paper is not open access but I can show you the Python implementation:
def get_quaternion(lst1,lst2,matchlist=None):
if not matchlist:
matchlist=range(len(lst1))
M=np.matrix([[0,0,0],[0,0,0],[0,0,0]])
for i,coord1 in enumerate(lst1):
x=np.matrix(np.outer(coord1,lst2[matchlist[i]]))
M=M+x
N11=float(M[0][:,0]+M[1][:,1]+M[2][:,2])
N22=float(M[0][:,0]-M[1][:,1]-M[2][:,2])
N33=float(-M[0][:,0]+M[1][:,1]-M[2][:,2])
N44=float(-M[0][:,0]-M[1][:,1]+M[2][:,2])
N12=float(M[1][:,2]-M[2][:,1])
N13=float(M[2][:,0]-M[0][:,2])
N14=float(M[0][:,1]-M[1][:,0])
N21=float(N12)
N23=float(M[0][:,1]+M[1][:,0])
N24=float(M[2][:,0]+M[0][:,2])
N31=float(N13)
N32=float(N23)
N34=float(M[1][:,2]+M[2][:,1])
N41=float(N14)
N42=float(N24)
N43=float(N34)
N=np.matrix([[N11,N12,N13,N14],\
[N21,N22,N23,N24],\
[N31,N32,N33,N34],\
[N41,N42,N43,N44]])
values,vectors=np.linalg.eig(N)
w=list(values)
mw=max(w)
quat= vectors[:,w.index(mw)]
quat=np.array(quat).reshape(-1,).tolist()
return quat
This function returns the quaternion that you were looking for. The arguments lst1 and lst2 are lists of numpy.arrays where every array represents a 3D vector. If both lists are of length 3 (and contain orthogonal unit vectors), the quaternion should be the exact transformation. If you provide longer lists, you get the quaternion that is minimizing the difference between both point sets.
The optional matchlist argument is used to tell the function which point of lst2 should be transformed to which point in lst1. If no matchlist is provided, the function assumes that the first point in lst1 should match the first point in lst2 and so forth...
A similar function for sets of 3 Points in C++ is the following:
#include <Eigen/Dense>
#include <Eigen/Geometry>
using namespace Eigen;
/// Determine rotation quaternion from coordinate system 1 (vectors
/// x1, y1, z1) to coordinate system 2 (vectors x2, y2, z2)
Quaterniond QuaternionRot(Vector3d x1, Vector3d y1, Vector3d z1,
Vector3d x2, Vector3d y2, Vector3d z2) {
Matrix3d M = x1*x2.transpose() + y1*y2.transpose() + z1*z2.transpose();
Matrix4d N;
N << M(0,0)+M(1,1)+M(2,2) ,M(1,2)-M(2,1) , M(2,0)-M(0,2) , M(0,1)-M(1,0),
M(1,2)-M(2,1) ,M(0,0)-M(1,1)-M(2,2) , M(0,1)+M(1,0) , M(2,0)+M(0,2),
M(2,0)-M(0,2) ,M(0,1)+M(1,0) ,-M(0,0)+M(1,1)-M(2,2) , M(1,2)+M(2,1),
M(0,1)-M(1,0) ,M(2,0)+M(0,2) , M(1,2)+M(2,1) ,-M(0,0)-M(1,1)+M(2,2);
EigenSolver<Matrix4d> N_es(N);
Vector4d::Index maxIndex;
N_es.eigenvalues().real().maxCoeff(&maxIndex);
Vector4d ev_max = N_es.eigenvectors().col(maxIndex).real();
Quaterniond quat(ev_max(0), ev_max(1), ev_max(2), ev_max(3));
quat.normalize();
return quat;
}
What language are you using? If c++, feel free to use my open source library:
http://sourceforge.net/p/transengine/code/HEAD/tree/transQuaternion/
The short of it is, you'll need to convert your vectors to quaternions, do your calculations, and then convert your quaternion to a transformation matrix.
Here's a code snippet:
Quaternion from vector:
cQuat nTrans::quatFromVec( Vec vec ) {
float angle = vec.v[3];
float s_angle = sin( angle / 2);
float c_angle = cos( angle / 2);
return (cQuat( c_angle, vec.v[0]*s_angle, vec.v[1]*s_angle,
vec.v[2]*s_angle )).normalized();
}
And for the matrix from quaternion:
Matrix nTrans::matFromQuat( cQuat q ) {
Matrix t;
q = q.normalized();
t.M[0][0] = ( 1 - (2*q.y*q.y + 2*q.z*q.z) );
t.M[0][1] = ( 2*q.x*q.y + 2*q.w*q.z);
t.M[0][2] = ( 2*q.x*q.z - 2*q.w*q.y);
t.M[0][3] = 0;
t.M[1][0] = ( 2*q.x*q.y - 2*q.w*q.z);
t.M[1][1] = ( 1 - (2*q.x*q.x + 2*q.z*q.z) );
t.M[1][2] = ( 2*q.y*q.z + 2*q.w*q.x);
t.M[1][3] = 0;
t.M[2][0] = ( 2*q.x*q.z + 2*q.w*q.y);
t.M[2][1] = ( 2*q.y*q.z - 2*q.w*q.x);
t.M[2][2] = ( 1 - (2*q.x*q.x + 2*q.y*q.y) );
t.M[2][3] = 0;
t.M[3][0] = 0;
t.M[3][1] = 0;
t.M[3][2] = 0;
t.M[3][3] = 1;
return t;
}
I just ran into this same problem. I was on the track to a solution, but I got stuck.
So, you'll need TWO vectors which are known in both coordinate systems. In my case, I have 2 orthonormal vectors in the coordinate system of a device (gravity and magnetic field), and I want to find the quaternion to rotate from device coordinates to global orientation (where North is positive Y, and "up" is positive Z). So, in my case, I've measured the vectors in the device coordinate space, and I'm defining the vectors themselves to form the orthonormal basis for the global system.
With that said, consider the axis-angle interpretation of quaternions, there is some vector V about which the device's coordinates can be rotated by some angle to match the global coordinates. I'll call my (negative) gravity vector G, and magnetic field M (both are normalized).
V, G and M all describe points on the unit sphere.
So do Z_dev and Y_dev (the Z and Y bases for my device's coordinate system).
The goal is to find a rotation which maps G onto Z_dev and M onto Y_dev.
For V to rotate G onto Z_dev the distance between the points defined by G and V must be the same as the distance between the points defined by V and Z_dev. In equations:
|V - G| = |V - Z_dev|
The solution to this equation forms a plane (all points equidistant to G and Z_dev). But, V is constrained to be unit-length, which means the solution is a ring centered on the origin -- still an infinite number of points.
But, the same situation is true of Y_dev, M and V:
|V - M| = |V - Y_dev|
The solution to this is also a ring centered on the origin. These rings have two intersection points, where one is the negative of the other. Either is a valid axis of rotation (the angle of rotation will just be negative in one case).
Using the two equations above, and the fact that each of these vectors is unit length you should be able to solve for V.
Then you just have to find the angle to rotate by, which you should be able to do using the vectors going from V to your corresponding bases (G and Z_dev for me).
Ultimately, I got gummed up towards the end of the algebra in solving for V.. but either way, I think everything you need is here -- maybe you'll have better luck than I did.
Define 3x3 matrices A and B as you gave them, so the columns of A are x_A,x_B, and x_C and the columns of B are similarly defined. Then the transformation T taking coordinate system A to B is the solution TA = B, so T = BA^{-1}. From the rotation matrix T of the transformation you can calculate the quaternion using standard methods.
You need to express the orientation of B, with respect to A as a quaternion Q. Then any vector in B can be transformed to a vector in A e.g. by using a rotation matrix R derived from Q. vectorInA = R*vectorInB.
There is a demo script for doing this (including a nice visualization) in the Matlab/Octave library available on this site: http://simonbox.info/index.php/blog/86-rocket-news/92-quaternions-to-model-rotations
You can compute what you want using only quaternion algebra.
Given two unit vectors v1 and v2 you can directly embed them into quaternion algebra and get the corresponding pure quaternions q1 and q2. The rotation quaternion Q that align the two vectors such that:
Q q1 Q* = q2
is given by:
Q = q1 (q1 + q2)/(||q1 + q2||)
The above product is the quaternion product.

computational geometry - projecting a 2D point onto a plane to determine its 3D location

The following is what I am trying to figure out.
Question - Explain how you can project a 2D point onto a plane to create a 3D point.
I want to know how I would go about figuring this out. I have looked through a computational geometry book and looked for anything that may relate to what I'm trying to figure out. There was no information given along with the question about the computational geometry problem. The thing is I don't know anything about computational geometry< so figuring this out is beyond my knowledge.
Can anyone point me in the right direction?
If I understood this correctly you want to project points on the 2D plane onto a plane with a different orientation. I’m also going to assume that you are looking for the orthogonal projection (i.e. all points from the xy-plane are to be projected onto the closest point on the target plane).
So we have the equations of the two planes and the point we want to project:
The original 2D plane: z = 0, with the normal vector n1 = (0, 0, 1)
The target plane: ax + by + cz + d = 0 with the normal vector n2 = (a, b, c)
Point P: (e, f, 0) which obviously lies in the xy-plane
Now, we want to travel from point P in the direction of the normal of the target plane (because this will give us the closest point on the target plane). Hence we form an equation for the line which starts at point P, and which is parallel to the normal vector of the target plane.
Line L: (x,y,z) = (e,f,0) + t(a,b,c) = (e+ta, f+tb, tc) , where t is a real valued parameter
Next, we want to find a point on the line L which also lies on the target plane. Hence, we plug the line equation into the equation for the target plane and receive:
a(e+ta) + b(f+tb) + c * tc + d= 0
ae + bf + d + t(a2 + b2 + c 2) = 0
t = - (ae + bf + d) / (a2 + b2 + c 2)
hence the projected point will be:
Pprojected = (e + ka, f + kb, kc), where k = - (ae + bf + d) / (a2 + b2 + c 2)
With all the variables in the solution about, it might be a bit hard to grasp if you are new to the area. But really, it is rather simple. The things you have to learn are:
The standard equation for a plane: ax + by + cz + d = 0
How to extract the normal vector from the equation of the plane
What the normal vector is (a vector which is perpendicular to all position vectors in the plane)
The parametric representation of a line: (x, y, z) = u + t*v* , where u is a point which lies on the line, t is a real valued parameter and v is a vector parallel to the line.
The understanding that the closest path between a point and a plane will be parallel to the normal of the plane
If you grasped the above concepts, computing the projection is simple:
Compute the normal vector of the target plane. Starting from the point that you want to project, travel parallel to the computed normal vector until you reach the plane.

Finding the spin of a sphere given X, Y, and Z vectors relative to sphere

I'm using Electro in Lua for some 3D simulations, and I'm running in to something of a mathematical/algorithmic/physics snag.
I'm trying to figure out how I would find the "spin" of a sphere of a sphere that is spinning on some axis. By "spin" I mean a vector along the axis that the sphere is spinning on with a magnitude relative to the speed at which it is spinning. The reason I need this information is to be able to slow down the spin of the sphere by applying reverse torque to the sphere until it stops spinning.
The only information I have access to is the X, Y, and Z unit vectors relative to the sphere. That is, each frame, I can call three different functions, each of which returns a unit vector pointing in the direction of the sphere model's local X, Y and Z axes, respectively. I can keep track of how each of these change by essentially keeping the "previous" value of each vector and comparing it to the "new" value each frame. The question, then, is how would I use this information to determine the sphere's spin? I'm stumped.
Any help would be great. Thanks!
My first answer was wrong. This is my edited answer.
Your unit vectors X,Y,Z can be put together to form a 3x3 matrix:
A = [[x1 y1 z1],
[x2 y2 z2],
[x3 y3 z3]]
Since X,Y,Z change with time, A also changes with time.
A is a rotation matrix!
After all, if you let i=(1,0,0) be the unit vector along the x-axis, then
A i = X so A rotates i into X. Similarly, it rotates the y-axis into Y and the
z-axis into Z.
A is called the direction cosine matrix (DCM).
So using the DCM to Euler axis formula
Compute
theta = arccos((A_11 + A_22 + A_33 - 1)/2)
theta is the Euler angle of rotation.
The magnitude of the angular velocity, |w|, equals
w = d(theta)/dt ~= (theta(t+dt)-theta(t)) / dt
The axis of rotation is given by e = (e1,e2,e3) where
e1 = (A_32 - A_23)/(2 sin(theta))
e2 = (A_13 - A_31)/(2 sin(theta))
e3 = (A_21 - A_12)/(2 sin(theta))
I applaud ~unutbu's, answer, but I think there's a simpler approach that will suffice for this problem.
Take the X unit vector at three successive frames, and compare them to get two deltas:
deltaX1 = X2 - X1
deltaX2 = X3 - X2
(These are vector equations. X1 is a vector, the X vector at time 1, not a number.)
Now take the cross-product of the deltas and you'll get a vector in the direction of the rotation vector.
Now for the magnitude. The angle between the two deltas is the angle swept out in one time interval, so use the dot product:
dx1 = deltaX1/|deltaX1|
dx2 = deltax2/|deltaX2|
costheta = dx1.dx2
theta = acos(costheta)
w = theta/dt
For the sake of precision you should choose the unit vector (X, Y or Z) that changes the most.

Resources