Rotation About an Arbitrary Axis in 3 Dimensions Using Matrix - math

I come accross a math problem about Interactive Computer Graphics.
I summarize and abstract this problem as follows:
I'm going to rotation a 3d coordinate P(x1,y1,z1) around a point O(x0,y0,z0)
and there are 2 vectors u and v which we already know.
u is the direction to O before transformation.
v is the direction to O after transformation.
I want to know how to conduct the calculation and get the coordinate of Q
Thanks a lot.
Solution:
Rotation About an Arbitrary Axis in 3 Dimensions using the following matrix:
rotation axis vector (normalized): (u,v,w)
position coordinate of the rotation center: (a,b,c)
rotation angel: theta
Reference:
https://docs.google.com/viewer?a=v&pid=sites&srcid=ZGVmYXVsdGRvbWFpbnxnbGVubm11cnJheXxneDoyMTJiZTZlNzVlMjFiZTFi

for just single point no rotations is needed ... so knowns are:
u,v,O,P
so we now the distance is not changing:
|P-O| = |Q-O|
and directions are parallel to u,v so:
Q = O + v*(|P-O|/|v|)
But I suspect you want to construct rotation (transform matrix) such that more points (mesh perhaps) are transformed. If that is true then you need at least one known to get this right. Because there is infinite possible rotations transforming P -> Q but the rest of the mesh will be different for each ... so you need to know at least 2 non trivial points pair P0,P1 -> Q0,Q1 or axis of rotation or plane parallel to rotation or any other data known ...
Anyway in current state you can use as rotation axis vector perpendicular to u,v and angle obtained from dot product:
axis = cross (u,v)
ang = +/-acos(dot(u,v))
You just need to find out the sign of angle so try both and use the one for which the resultinq Q is where it should be so dot(Q-O,v) is max. To rotate around arbitrary axis and point use:
Rodrigues_rotation_formula
Also this might be helpfull:
Understanding 4x4 homogenous transform matrices

By computing dot product between v and u get the angle l between the vectors. Do a cross product of v and u (normalized) to produce axis of rotation vector a. Let w be a vector along vector u from O to P. To rotate point P into Q apply the following actions (in pseudo code) having axis a and angle l computed above:
float4 Rotate(float4 w, float l, float4 a)
{
float4x4 Mr = IDENTITY;
quat_t quat = IDENTITY;
float4 t = ZERO;
float xx, yy, zz, xy, xz, yz, wx, wy, wz;
quat[X] = a[X] * sin((-l / 2.0f));
quat[Y] = a[Y] * sin((-l / 2.0f));
quat[Z] = a[Z] * sin((-l / 2.0f));
quat[W] = cos((-l / 2.0f));
xx = quat[X] * quat[X];
yy = quat[Y] * quat[Y];
zz = quat[Z] * quat[Z];
xy = quat[X] * quat[Y];
xz = quat[X] * quat[Z];
yz = quat[Y] * quat[Z];
wx = quat[W] * quat[X];
wy = quat[W] * quat[Y];
wz = quat[W] * quat[Z];
Mr[0][0] = 1.0f - 2.0f * (yy + zz);
Mr[0][1] = 2.0f * (xy + wz);
Mr[0][2] = 2.0f * (xz - wy);
Mr[0][3] = 0.0f;
Mr[1][0] = 2.0f * (xy - wz);
Mr[1][1] = 1.0f - 2.0f * (xx + zz);
Mr[1][2] = 2.0f * (yz + wx);
Mr[1][3] = 0.0f;
Mr[2][0] = 2.0f * (xz + wy);
Mr[2][1] = 2.0f * (yz - wx);
Mr[2][2] = 1.0f - 2.0f * (xx + yy);
Mr[2][3] = 0.0f;
Mr[3][0] = 0.0f;
Mr[3][1] = 0.0f;
Mr[3][2] = 0.0f;
Mr[3][3] = 1.0f;
w = Mr * w;
return w;
}
Point Q is at the end of the rotated vector w. Algorithm used in the pseudo code is quaternion rotation.

If you know u, v, P, and O then I would suggest that you compute |OP| which should be preserved under rotations. Then multiply this length by the unit vector -v (I assumed u, v are unit vectors: if not - normalize them) and translate the origin by this -|OP|v vector. The negative sign in front of v comes from the description given in your question:"v is the direction to O after transformation".

P and Q are at the same distance R to O
R = sqrt( (x1-x0)^2 + (y1-y0)^2 + (z1-z0)^2 )
and OQ is collinear to v, so OQ = v * R / ||v|| where ||v|| is the norm of v
||v|| = sqrt( xv^2 + yv^2 + zv^2 )
So the coordinates of Q(xq,yq,zq) are:
xq= xo + xv * R / ||v||
yq= yo + yv * R / ||v||
zq= zo + zv * R / ||v||

Related

Orientation Matrix from Heading, Pitch and Roll

I have a problem converting Heading, Pitch and Roll to an Orientation Matrix
How would I go about improving this to ensure Y and Z and are correctly calculated.
--[[
get_orientation - Returns the orientation matrix of an object based on its heading, pitch, and roll in degrees.
#param heading number - The heading of the object in degrees.
#param pitch number - The pitch of the object in degrees.
#param roll number - The roll of the object in degrees.
#returns orientation table - The orientation matrix of the object, represented as a table with three unit vectors: x, y, and z.
]]
local function get_orientation(heading, pitch, roll)
local orientation = {}
-- Convert the heading, pitch, and roll from degrees to radians using math.rad
heading = math.rad(heading)
pitch = math.rad(pitch)
roll = math.rad(roll)
-- Calculate the x unit vector
-- x is the Vec3 unit vector that points in the direction of the object's front
orientation.x = {}
orientation.x.x = math.cos(heading) * math.cos(pitch)
orientation.x.y = math.sin(pitch)
orientation.x.z = math.sin(heading) * math.cos(pitch)
-- Calculate the y unit vector
-- y is the Vec3 unit vector that points in the direction of the object's top
orientation.y = {}
orientation.y.x = -math.cos(heading) * math.sin(pitch)
orientation.y.y = math.cos(pitch)
orientation.y.z = -math.sin(heading) * math.sin(pitch)
-- Calculate the z unit vector
-- z is the Vec3 unit vector that points in the direction of the object's right side
orientation.z = {}
orientation.z.x = -math.sin(heading)
orientation.z.z = -math.cos(heading) * math.cos(roll)
orientation.z.y = math.sin(roll)
-- Return the orientation matrix of the object
return orientation
end
---------------------------------------------------
---------------------------------------------------
local lat = 41.610278
local lon = 41.599444
local heading = 90
local pitch = 25
local roll = 0
local alt = 100
local x, y = terrain.convertLatLonToMeters(lat, lon)
local orientation = get_orientation(heading, pitch, roll)
local position = {
x=orientation.x,
y=orientation.y,
z=orientation.z,
p={x=x,y=alt,z=y}
}
Export.LoSetCameraPosition(position)
local actual = Export.LoGetCameraPosition()
return {position=position, actual=actual}
There is a little more information about the Orientation here
https://www.digitalcombatsimulator.com/en/support/faq/1256/#:~:text=level%2010%20m-,Orientation,-Object%20orientation%20is
I am attempting to build a function that takes lat, lon, alt, heading, pitch and roll and produce the Position matrix.
I have the example function so far, which does work but everything goes funky after -81 pitch and the roll does not work as intended.
Formulas for 3D rotation are not simple, but they can be simply deduced from three consecutive 2D rotations.
local function apply_rotation(a, b, angle)
local ax, ay, az, bx, by, bz = a.x, a.y, a.z, b.x, b.y, b.z
a.x = math.cos(angle) * ax + math.sin(angle) * bx
a.y = math.cos(angle) * ay + math.sin(angle) * by
a.z = math.cos(angle) * az + math.sin(angle) * bz
b.x = math.cos(angle) * bx - math.sin(angle) * ax
b.y = math.cos(angle) * by - math.sin(angle) * ay
b.z = math.cos(angle) * bz - math.sin(angle) * az
end
local function get_orientation(heading, pitch, roll)
-- Convert the heading, pitch, and roll from degrees to radians using math.rad
heading = math.rad(heading)
pitch = math.rad(pitch)
roll = math.rad(roll)
-- x is the Vec3 unit vector that points in the direction of the object's front
-- y is the Vec3 unit vector that points in the direction of the object's top
-- z is the Vec3 unit vector that points in the direction of the object's right side
local o = {
x = { x=1, y=0, z=0 },
y = { x=0, y=1, z=0 },
z = { x=0, y=0, z=1 },
}
apply_rotation(o.x, o.z, heading)
apply_rotation(o.x, o.y, pitch)
apply_rotation(o.z, o.y, roll)
-- Return the orientation matrix of the object
return o
end

Point positioning inside rectangle with only two known vertexes

I'm working on a js widget, and I've come across a positioning problem, which I can't seem to solve with my limited geometry knowledge or by help of Wikipedia/google.
I have a quadrilateral rectangle, which is positioned at an angle. I know its two opposite vertexes and width/height ratio. And there's a point on it, which coordinates I also know.
I need to find how far (in %s of width/height) is that point from rectangle's sides. Is it possible to do so?
Having two corners P1 = (x1,y1) and P2 = (x2,y2) and point Q, you can find diagonal length
dx = (x2 - x1)
dy = (y2 - y1)
dlen = sqrt(dx^2 + dy^2)
and unit direction vector
dx = dx / dlen
dy = dy / dlen
and center of rectangle
cx = x1 + dx/2
cy = y1 + dy/2
Width and height (with known r = w/h ratio)
w = dlen / sqrt(1 + r^2)
h = w / r
Now we need direction of side of length w. Note that given information does not allow to choose exact rectangle orientation from two possible cases.
Angle between diagonal and side
sina = r / sqrt(1 + r^2)
cosa = 1 / sqrt(1 + r^2)
Side direction vector
wx = dx * cosa - dy * sina
wy = dx * sina + dy * cosa
and for the second orientation
wx' = dx * cosa + dy * sina
wy' = -dx * sina + dy * cosa
The second side vector
hx = -wy
hy = wx
Now we can find length of projection of point p onto sides W and H using dot product
qx = q.x - x1
qy = q.y - y1
qw = qx * wx + qy * wy
qh = qx * hx + qy * hy
The last values are coordinates in W-H basis, so value qw varies from 0 for points at the "left" to w for points at the "right" side. You can divide these values by w and h to get percent values.
Note again - there are two possible rectangles and correspondingly two positions of point Q

Calculate Angle from direction vector

I have direction vector (0.000000, 0.707107, 0.707107) like this, i want to convert this vector to an angle between X, Y and Z direction planes and Direction vectors (0,45 deg,45 deg). Please provide the mathematical equations or VBA functions to get an angle.
To get angle between vector D = (dx, dy, dz) and coordinate planes, you can use scalar product of vector and its projection onto corresponding plane.
For example, to get projection on OYZ plane, you can just make x-component zero.
P(0yz) = (0, dy, dz)
S = D.dot.P = 0 + dy * dy + dz * dz
Fi(D, 0yz) = ArcCosine(S / (length(P) * length(D)) =
ArcCosine((dy*dy + dz*dz) / Sqrt((dx*dx + dy*dy + dz*dz)*(dy*dy + dz*dz)))=
ArcCosine(Sqrt((dy*dy + dz*dz) /(dx*dx + dy*dy + dz*dz))))=
ArcCosine(length(P) / length(D))
You can build similar formulas for OXY and OXZ planes

Tesselation of the circle in OpenGL

I'm having trouble understanding the math behind this function. I would like to hear the logic behind the formulas (especially what is this tangential and radial factor) written here to create points which later (when it send the vec3 array to a function) form a circle in OpenGL.
void doTesselate(const Arc& arc, int slices, std::vector<glm::vec3>& vertices)
{
double dang = (arc.endAngle() - arc.startAngle()) * Deg2Rad;
double radius = arc.radius();
double angIncr = dang / slices;
double tangetial_factor = tan(angIncr);
double radial_factor = 1 - cos(angIncr);
double startAngle = arc.startAngle() * Deg2Rad;
const glm::vec3& center = arc.center();
double x = center.x - radius * cos(startAngle);
double y = center.y - radius * sin(startAngle);
++slices;
for (int ii = 0; ii < slices; ii++) {
vertices.push_back(glm::vec3(x, y, center.z));
double tx = center.y - y;
double ty = x - center.x;
x += tx * tangetial_factor;
y += ty * tangetial_factor;
double rx = center.x - x;
double ry = center.y - y;
x += rx * radial_factor;
y += ry * radial_factor;
}
}
The idea is the following:
Starting from the current point, you go a bit in tangential direction and then back towards the center.
The vector (tx, ty) is the tangent at the current point with length equal to the radius. In order to get to the new angle, you have to move tan(angle) * radius along the tangent. radius is already incorporated in the tangent vector and tan(angle) is the tangetial_factor (you get that directly from tangent's definition).
After that, (rx, ry) is the vector towards the center. This vector has the length l:
cos(angle) = radius / l
l = radius / cos(angle)
We need to find a multiple m of this vector, such that the corrected point lies on the circle with the given radius again. If we just inspect the lengths, then we want to find:
target distance = current distance - m * length of (rx, ry)
radius = radius / cos(angle) - m * radius / cos(angle)
1 = (1 - m) / cos(angle)
cos(angle) = 1 - m
1 - cos(angle) = m
And this multiple is exactly the radial_factor (the amount which you need to move towards the center to get onto the circle).

Rotate all points to align with a vector

I have a vector v = (x,y,z), and I want to rotate all points such that the point (x,y,z) = (0,0,sqrt(x^2 + y^2 + z^2). In other words, I want to make the direction of the vector v be the z axis, and rotate all points such that this is true.
I want the point (1,1,0) to go to (0,0,sqrt(2)), and the point (0,0,1) to go to (-1/(sqrt(2)),-1/sqrt(2),0) given a v of (1,1,0).
I am working in unity3d's left handed axis system, where y is vertical.
My current method is this, using with v = (vx,vy,vz) and x,y,z being the point to be rotated.
float vx = 1;
float vy = 1;
float vz = 0;
float c1 = -vz/(sqrt(vx*vx + vz*vz));
float c2 = -sqrt(vx*vx + vz*vz)/sqrt(vx*vx + vy*vy + vz*vz);
float s1 = -vx/(sqrt(vx*vx + vz*vz));
float s2 = -vy/sqrt(vx*vx + vy*vy + vz*vz);
float rx = x * c1 + y*s1*s2 - z*s1*c2;
float ry = x * 0 + y*c2 + z * s2;
float rz = x * s1 - y*s2*c1 + z*c1*c2;
You are looking for a 3x3 Matrix f with fv=(0,0,1), |x|=|fx|; this needs
( t1 t2 t3 )
f = ( u1 u2 u3 )
( w1 w2 w3 )
where w := v / |v|, and t, u, w are pairwise orthogonal and |t|=|u|=|w|=1.
Chosing t and u depends on what you want to do, but if you just need any t and u, get some via the 3d cross product.
I found the answer, find axis of rotation by taking cross product of (0,0,1) then use this as the axis of rotation with the angle being the angle between the vector (0,0,1) and (vx,vy,vz).
http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle

Resources