What exactly is the output quaternion of slerp? - c

I'm trying to implement SLERP (described by Ken Shoemake in "Animating Rotation with Quaternion Curves)
I've read up on the topic on wikipedia (topic: quaternions, 1 and 2) and other sites and also searched stackoverflow about this problem. It seems like I understand the theory behind it, but oversee one small detail. I will use w for the scalar value of the quaternion
So initially I have two 3D vectors. Each vector has a representation in two coordinate systems (C and C'). My goal is to find a third representation of these vectors in the system "halfway" the initial two.
So what I do is I find the rotation matrix, which transform the vectors from C to C', which seems to work out quite fine.
My next step is to transform this matrix into a quaternion, which also works.
Now my issue is with the formula of slerp, which is:
slerp(q1, q2; u) = ((sin(1-u) * t)/ (sin t)) * q1 + (sin(ut)/sin t) * q2
(sorry can't upload images yet for a better representation: see source 1)
so I guess here u = 0.5, q1 is the vector I would like to rotate (with w=0) and q2 equals the quaternion I calculated previously. Theta is calculated from the dotproduct of the normalized vector and the (already) normalized quaternion.
So what I expect is that I get back a vector, rotated either from C to the third coordinate system or from C' to the third coordinate system.
My issue now is, that I don't see, how I will get a vector and not a quaternion. Meaning, how is it possible, that I will get a quaternion with (w=0), as by simply multiplying q2 with this factor won't set w to 0. Or is it something else I will get from this function?
What am I overseeing here?
Thanks for your help!

Seems like I figured it out. For someone with the same understanding problem:
slerp simply interpolates between two orientations, meaning between two actual rotations. So in my case, q1 is the quaternion corresponding to the identity matrix (so [1, 0, 0, 0]). q2 is the rotation. theta is still 0.5.
With the quaternion I get from this, I have to calculate the rotation with q^-1 v q. Where v is my vector I want to rotate. This can be calculated using the Hamilton product.

Related

Resampling two vectors with interp1 or spline

Situation:
I was trying to compare two signal vectors (y1 & y2 with time vectors x1 & x2) with different lengths (len(y1)=1000>len(y2)=800). For this, I followed the main piece of advice given hardly everywhere: to use interp1 or spline. In order to 'expand' y2 towards y1 in number of samples through an interpolation.
So I want:
length(y1)=length(y2_interp)
However, in these functions you have to give the points 'x' where to interpolate (xq), so I generate a vector with the resampled points I want to compute:
xq = x2(1):(length(x2))/length(x1):x2(length(x2));
y2_interp = interp1(x2,y2,xq,'spline'); % or spline method directly
RMS = rms(y1-y2_interp)
The problem:
When I resample the x vector in 'xq' variable, as the faction of lengths is not an integer it gives me not the same length for 'y2_interp' as 'y1'. I cannot round it for the same problem.
I tried interpolate using the 'resample' function:
y2_interp=resample(y2,length(y1),length(y2),n);
But I get an aliasing problem and I want to avoid filters if possible. And if n=0 (no filters) I get some sampling problems and more RMS.
The two vectors are quite long, so my misalignment is just of 2 or 3 points.
What I'm looking for:
I would like to find a way of interpolating one vector but having as a reference the length of another one, and not the points where I want to interpolate.
I hope I have explained it well... Maybe I have some misconception. It's more than i'm curious about any possible idea.
Thanks!!
The function you are looking for here is linspace
To get an evenly spaced vector xq with the same endpoints as x2 but the same length as x1:
xq = (x2(1),x2(end),length(x1));
It is not sufficient to interpolate y2 to get the right number of samples, the samples should be at locations corresponding to samples of y1.
Thus, you want to interpolate y2 at the x-coordinates where you have samples for y1, which is given by x1:
y2_interp = interp1(x2,y2,x1,'spline');
RMS = rms(y1-y2_interp)

How to efficiently evaluate or approximate a road Clothoid?

I'm facing the problem of computing values of a clothoid in C in real-time.
First I tried using the Matlab coder to obtain auto-generated C code for the quadgk-integrator for the Fresnel formulas. This essentially works great in my test scnearios. The only issue is that it runs incredibly slow (in Matlab as well as the auto-generated code).
Another option was interpolating a data-table of the unit clothoid connecting the sample points via straight lines (linear interpolation). I gave up after I found out that for only small changes in curvature (tiny steps along the clothoid) the results were obviously degrading to lines. What a surprise...
I know that circles may be plotted using a different formula but low changes in curvature are often encountered in real-world-scenarios and 30k sampling points in between the headings 0° and 360° didn't provide enough angular resolution for my problems.
Then I tried a Taylor approximation around the R = inf point hoping that there would be significant curvatures everywhere I wanted them to be. I soon realized I couldn't use more than 4 terms (power of 15) as the polynom otherwise quickly becomes unstable (probably due to numerical inaccuracies in double precision fp-computation). Thus obviously accuracy quickly degrades for large t values. And by "large t values" I'm talking about every point on the clothoid that represents a curve of more than 90° w.r.t. the zero curvature point.
For instance when evaluating a road that goes from R=150m to R=125m while making a 90° turn I'm way outside the region of valid approximation. Instead I'm in the range of 204.5° - 294.5° whereas my Taylor limit would be at around 90° of the unit clothoid.
I'm kinda done randomly trying out things now. I mean I could just try to spend time on the dozens of papers one finds on that topic. Or I could try to improve or combine some of the methods described above. Maybe there even exists an integrate function in Matlab that is compatible with the Coder and fast enough.
This problem is so fundamental it feels to me I shouldn't have that much trouble solving it. any suggetions?
about the 4 terms in Taylor series - you should be able to use much more. total theta of 2pi is certainly doable, with doubles.
you're probably calculating each term in isolation, according to the full formula, calculating full factorial and power values. that is the reason for losing precision extremely fast.
instead, calculate the terms progressively, the next one from the previous one. Find the formula for the ratio of the next term over the previous one in the series, and use it.
For increased precision, do not calculate in theta by rather in the distance, s (to not lose the precision on scaling).
your example is an extremely flat clothoid. if I made no mistake, it goes from (25/22) pi =~ 204.545° to (36/22) pi =~ 294.545° (why not include these details in your question?). Nevertheless it should be OK. Even 2 pi = 360°, the full circle (and twice that), should pose no problem.
given: r = 150 -> 125, 90 degrees turn :
r s = A^2 = 150 s = 125 (s+x)
=> 1+(x/s) = 150/125 = 1 + 25/125 x/s = 1/5
theta = s^2/2A^2 = s^2 / (300 s) = s / 300 ; = (pi/2) * (25/11) = 204.545°
theta2 = (s+x)^2/(300 s) = (6/5)^2 s / 300 ; = (pi/2) * (36/11) = 294.545°
theta2 - theta = ( 36/25 - 1 ) s / 300 == pi/2
=> s = 300 * (pi/2) * (25/11) = 1070.99749554 x = s/5 = 214.1994991
A^2 = 150 s = 150 * 300 * (pi/2) * (25/11)
a = sqrt (2 A^2) = 300 sqrt ( (pi/2) * (25/11) ) = 566.83264608
The reference point is at r = Infinity, where theta = 0.
we have x = a INT[u=0..(s/a)] cos(u^2) d(u) where a = sqrt(2 r s) and theta = (s/a)^2. write out the Taylor series for cos, and integrate it, term-by-term, to get your Taylor approximation for x as function of distance, s, along the curve, from the 0-point. that's all.
next you have to decide with what density to calculate your points along the clothoid. you can find it from a desired tolerance value above the chord, for your minimal radius of 125. these points will thus define the approximation of the curve by line segments, drawn between the consecutive points.
I am doing my thesis in the same area right now.
My approach is the following.
at each point on your clothoid, calculate the following (change in heading / distance traveled along your clothoid), by this formula you can calculate the curvature at each point by this simple equation.
you are going to plot each curvature value, your x-axis will be the distance along the clothoid, the y axis will be the curvature. By plotting this and applying very easy linear regression algorithm (search for Peuker algorithm implementation in your language of choice)
you can easily identify where are the curve sections with value of zero (Line has no curvature), or linearly increasing or decreasing (Euler spiral CCW/CW), or constant value != 0 (arc has constant curvature across all points on it).
I hope this will help you a little bit.
You can find my code on github. I implemented some algorithms for such problems like Peuker Algorithm.

Linear interpolation: calculate correction based on 2D table

I try to do a thing that should be nothing more than a two-dimensional, linear interpolation but currently I fail finding the correct approach. To describe the problem a bit simplified: there is a drawing area with a size of 3000x3000 pixels where I have to draw e.g. a horizontal line. To do that I'm drawing dots or short lines from every pixel position to the next pixel position which then forms a line.
Now a correction has to be applied to the whole thing where correction information can be found in a (for this example simplified) 4 by 4 array, where every element contains a pair of coordinates describing the values after correction. So a neutral array (with no correction) would look like this:
0,0 1000,0 2000,0 3000,0
0,1000 1000,1000 2000,1000 3000,1000
0,2000 1000,2000 2000,2000 3000,2000
0,3000 1000,3000 2000,3000 3000,3000
A real correction table would contain other coordinates describing the correction to be done:
So as input data I have the coordinates of points on the line without correction, the fields values without correction and the correction data. But how can I calculate the lines points now applying the correction values to it so that a distorted line is drawn like shown in right side if the image? My current approach with two separate linear interpolations for X and Y does not work, there the Y-position jumps on a cells border but does not change smoothly within a cell.
So...any ideas how this could be done?
You have to agree on an interpolation method first. I would suggest either bilinear or barycentric interpolation. In one of my previous posts I visualized the difference between both methods.
I'll concentrate on the bilinear interpolation. We want to transform any point within a cell to its corrected point. Therefore, all points could be transformed separately.
We need the interpolation parameters u and v for the point (x, y). Because we have an axis-aligned grid, this is pretty simple:
u = (x - leftCellEdge) / (rightCellEdge - leftCellEdge)
v = (y - bottomCellEdge) / (topCellEdge - bottomCellEdge)
We could reconstruct the point by bilinear interpolation:
p2 p4
x----x
| o |
x----x
p1 p3
o = (1 - u) * ((1 - v) * p1 + v * p2) + u * ((1 - v) * p3 + v * p4)
Now, the same formula can be used for the corrected points. If you use the original points p1 through p4, you'll get the uncorrected line point. If you use the corrected cell points for p1 through p4, you'll get the corrected line point.

I need to translate 3d points relative to a triangle as if the triangle was somewhere else

I posted this on twitter a while ago but seeing how none of my followers appears to be a math/programming genius, I'll try my luck here as well. I got here because I found this which might contain part of my solution.
I described my problem in the following pdf document, containing a picture of what I'm trying to achieve.
To give some more details, I divided the pentagon's of a dodecahedron (12 pentagons) into triangles (5/pentagon, 60 triangles in total), then collected a set of data points relative to each of these triangles.
The idea is to generate terrain meshes for each individual triangle.
To do so, the data must be represented flat, in a 32K x 32K square (idTech4 Megatexture)
I have vaguely heard of transformation matrices, which when set up properly, could do the trick of passing all the data points trough them to have them show up in the right place.
I looked at this source code here but I don't understand how I'm supposed to get the points in and/or out of there, not to mention how to do the setup so I can present each point in turn and get the result point back.
I got as fas as identifying the point that belongs in the back right corner. All my 3D points are originally stored in latitude / longitude pairs. I retrieve the 3D vectors this way:
coord getcoord(point* p)
{
coord c;
c.x=cos(p->lat*pi/180.l) * cos(p->lon*pi/180.l);
c.y=cos(p->lat*pi/180.l) * sin(p->lon*pi/180.l);
c.z=sin(p->lat*pi/180.l);
return c;
};
My thought is that if I can find the center of my triangle, and discover how to offset my angles so the vector from the center of my sphere to the middle of the triangle moves to 90N then my points would already be in the right plane if I rotated them all along the same angles. If I then convert them all to 3d and subtracti the radius from y, they'll be at the correct y position as well.
Then all I'd need to do is the rotation, the scaling, and the moving to the final position.
There are several kinds of 'centers' for a triangle, I think the one I need is the one that is equidistant to the corners of the triangle (Circumcenter?)
But then there might be an easier approach to the whole problem so while I continue my own research, perhaps some of you can help pointing me in the right direction.
It appears as if some sample data is in order, here are a few of these triangles in obj file format:
v 0.000000 0.000000 3396.000000
v 2061.582356 0.000000 2698.646733
v 637.063983 1960.681333 2698.646733
f 1 2 3
And another:
v -938.631230 2888.810129 1518.737455
v 637.063983 1960.681333 2698.646733
v 1030.791271 3172.449325 637.064076
f 1 2 3
You will notice that each point is at a distance of 3396 from 0,0,0
I mentioned 'on the sphere' meaning that the face away from the center of the sphere is the face that needs to become the 'top' when translated into the square.
Theoretically all these triangles should in fact have identical sizes, but due to rounding errors in the math that generated them, this might not be entirely true.
If I'm not mistaken I already took measures to ensure that the first point you see here is always the one opposite the longest border, so it's the one that should go in the far left corner (testing the above 2 samples confirms this, but I'm measuring anyway just to be sure)
Both legs leading away from this point should theoretically have the same length as well, but again rounding errors might slightly offset that.
If I've done it correctly then the longer side is 1,113587 times longer than the 2 shorter sides. Assuming those are identical, then doing some goal seeking in excel, I can deduct that the final points, assuming I was just translating this triangle, should look like:
v 16384.000000 0.000000 16384.000000
v -16384.000000 0.000000 9916.165306
v 9916.165306 0.000000 -16384.000000
f 1 2 3
So I need to setup the matrix to do this transformation, preferably using the 4x4 matrix as explained below.
I would recommend using transform matrices. The 3d transform matrix is a 4x4 data structure which describes a translation and rotation (and possibly a scale). Once you have a matrix you can transform a point like so
result.x = (tmp->pt.x * m->element[0][0]) +
(tmp->pt.y * m->element[1][0]) +
(tmp->pt.z * m->element[2][0]) +
m->element[3][0];
result.y = (tmp->pt.x * m->element[0][1]) +
(tmp->pt.y * m->element[1][1]) +
(tmp->pt.z * m->element[2][1]) +
m->element[3][1];
result.z = (tmp->pt.x * m->element[0][2]) +
(tmp->pt.y * m->element[1][2]) +
(tmp->pt.z * m->element[2][2]) +
m->element[3][2];
int w = (tmp->pt.x * m->element[0][3]) + (tmp->pt.y * m->element[1][3])
+ (tmp->pt.z * m->element[2][3]) + m->element[3][3];
if (w!=0 || w!=1)
result.x/=w; result.y/=w; result.z/=w;
This will transform the 3D point pt by the matrix m. If you now a little matrix math you'll see i'm just multiplying my origin point as a vector against the matrix (and doing a little normalization if it is a skew matrix.) Matrices can be multiplied together to form complicated transformations so they are very useful.
For details on making matrices suggest reading this link.
http://en.wikipedia.org/wiki/Transformation_matrix

Checking Triangle Similarity in C

The problem set asks me to create two triangles, defining them using points, and then checking if they're similar.
I did first part: created a struct point and a struct triangle, as the profesor told us to. To solve the problem of checking similarity, I thought I could use the points to define vectors, and them use the law of cosines to calculate its angles, together with some if sentences to check if the triangles are similar.
Which codes could help me achieve that? I could not find anything that I'd be able to turn into a partial solution.
What you said does the trick!
For the first triangle, take some measures, like as you said: an angle (or its cosine - easy to calculate with a dot product) on any vertex and the lengths of the sides next to it.
For another triangle, use if-conditions to see if the angle (or its cosine) is the same, and if the ratios of the lengths are also the same. You'd have to do this check from all 3 vertices in this way (if at least one fits, then the triangles are similar).
A faster way would be to always start with (for instnace) the vertex with the smallest angle, then you'd need to only compare once.
Now go code it! :-)
You are given coordinates of all three points of each triangle. Let us consider two triangles T1 A(a1,a2) B(b1,b2) C(c1, c2), T2 P(p1,p2) Q(q1,q2) R(r1,r2).
a = length of opposite side of vertex A
b = length of opposite side of vertex B
c = length of opposite side of vertex C
similarly p,q,r of triangle T2
So, for the two triangles to be similar, it has to follow the following conditions
1. AB = PQ; BC = QR; CA = RP
(We don't need their directions, So I am considering only magnitudes)
2. angle (A) = angle(B) i.e angle(BAC) = angle(QPR);
angle(B) = angle(Q) i.e angle(CBA) = angle (RQP) and
angle(C) = angle(R).
Now, you got to use coordinate geometry/ spherical geometry here.
COS (A) = ( b^2 + c^2 - a^2 )/2bc
COS (B) = ( c^2 + a^2 - b^2 )/2ac
COS (C) = (a^2 + b^2 - c^2)/2ab
Note:: As cosine is periodic with 2*pi, please make sure that you have exact angle. So, why don't you think of using inverse cosine functions where you get principle angles.(I am not sure of them, as how they work. please do check)
(Similarly for P,Q,R of triangle T2).
Actually there is another rule by which its easy to do.
law: a/sin(A) = b/sin(B) = c/sin(C).
I think you have to go through Spherical Geometry
I hope this helps you to do the program.
How to do the program:
Actually, its fine if you want to use structures. Create a structure with fields of 3 sides and 3 angles. Thus you need to take two variables under structure type and compare those quantities mentioned above.
If they satisfy, they are similar triangles.
I hope this helps you.

Resources