I was looking at some code in python skimage toolkit regarding representing affine transformations in 2D and there is an AffineTransform class which is defined as:
Parameters
----------
matrix : (3, 3) array, optional
Homogeneous transformation matrix.
scale : (sx, sy) as array, list or tuple, optional
Scale factors.
rotation : float, optional
Rotation angle in counter-clockwise direction as radians.
shear : float, optional
Shear angle in counter-clockwise direction as radians.
translation : (tx, ty) as array, list or tuple, optional
Translation parameters.
I notice that the shearing only takes one parameter (shearing angle in counter-clockwise direction). However, why should this not be two parameters? I can shear in x AND in y direction. How come these two operations map into one free parameter in 2D?
Currently in the code we have, for the transformation matrix:
[sx * math.cos(rotation), -sy * math.sin(rotation + shear), 0],
[sx * math.sin(rotation), sy * math.cos(rotation + shear), 0],
[ 0, 0, 1]
I wonder if this is indeed the most intuitive way to specify shear. I have opened an issue: https://github.com/scikit-image/scikit-image/issues/1779
Related
I have a path output as shown in the image below, in a coordinate system 1 wherein the start point and the end point are (40,40) and (10,20) respectively.
I want to scale this path to a new coordinate system (coordinate system 2) with a known start and end point, the path has to scale and adjust between the new points.
I believe Affine transforms might help / linear algebra.
How do I achieve this ? and will this be accurate or will it distort ?
To find appropriate affine tranformation (there are many ways to transform two points into two another ones, but we choose the simplest way), you can apply these elementary steps:
Shift coordinates by (-startx, -starty)
Scale along X-axis with coefficient (newendx-newstartx)/(endx-startx) (here -80/3)
Scale along Y-axis with coefficient (newendy-newstarty)/(endy-starty) (here -35)
Shift coordinates by (newstartx, newstarty)
Resulting affine tranformation is product of these four matrices
Using Wolfram alpha to get matrix
M == {{c, 0, 0},
{0, d, 0},
{a*c + e, b*d + f, 1}}
where a,b,c,d,e,f are values from decription above (a = -startx and so on)
Now transform coordinates with multiplication of point coordinates and matrix M
(x, y, 1) * M = (newx, newy, 1)
I'm trying to implement a simple 3d render. I have implemented a perspective projection matrix similar to glm::perspective. I have read that a perspective projection matrix transforms vertices such that after the perspective division, visible region, i.e., objects that lie inside the specified frustum fall in the range [-1,1], but when I tested some values with a matrix returned by glm::perspective results are not similar to my understanding.
float nearPlane = 0.1f;
float farPlane = 100.0f;
auto per =
glm::perspective(45.0f, (float)(window_width * 1.0 / window_height),
nearPlane, farPlane);
// z=nearplane
print(per * glm::vec4(1, -1, -0.1, 1));
// z=farplane
print(per * glm::vec4(1, -1, -100, 1));
// z between nearplane and farplane
print(per * glm::vec4(1, -1, -5, 1));
// z beyond far plane
print(per * glm::vec4(1, -1, -200, 1));
// z behind the camera
print(per * glm::vec4(1, -1, 0.1, 1));
// z between camera and near plane
print(per * glm::vec4(1, -1, -0.09, 1));
As per my understanding, if vertices have a z coordinate which lies towards positive z-direction from nearPlane then after perspective divide z/w value should be <-1 but as shown in the picture below it is not the case. what am I missing?
as per my understanding if vertices has z coordinate which is lies towards positive z direction from nearPlane then after perspective divide z/w value should be <-1 but as shown in picture below it is not the case. what am i missing?
That's simply not the case. There is a singularity at z=0 (camera plane), and the sign of the function flips (camera is looking to the left; blue vertical line is the near clipping plane):
Those values are still outside the [-1,1] range, telling us that they are outside the camera frustum and should be clipped accordingly.
You might be confused because you're thinking that "smaller z/w values mean that the point is closer to the camera". But that's true only in-front of the camera. In fact the depth buffer values matter only if the fragment isn't clipped -- i.e. in the [-1,1] range, where that relation happens to be correct.
So, I have ellipses given - they are defined by their midpoint, an horizontal radius(rh) and an vertical radius(rv). I'm drawing them using sin/cos and the result looks fairly good to me(just making sure this isn't an error source).
Now say I have an angle(or a direction vector) given and I want to have the point on the ellipse's outline with that angle/direction. My intuitive approach was to simply use the direction vector, normalise it and multiply its x-component with rh, its y-component with rv. Now both my written program AND all the calculations I did on a paper give me not the point I want but another one, though it's still on the ellipse's outline. However, this method works just fine if the direction is one of (1,0), (0, 1), (-1, 0), (0, -1), (so it works for 0°, 90°, 180°, 270°).
Although there is a farily big amount of data about ellipses themselves on the internet, I couldn't find any information about my particular problem - and I couldn't come up with any better solution than the above one.
So, any idea how to achieve this?
If I understand what you are asking then I think that what you need is polar form of an ellipse where the angle is measured from the ellipse centre. Using this form of the ellipse, you will be able to evaulate your elliptic radius value for a given choice of theta and then plot your point.
If you take a look at this gif image you will see why using the parametric angle give you the correct result only at theta = 90, 180, 270 and 360 degrees http://en.wikipedia.org/wiki/File:Parametric_ellipse.gif . Use the polar form for an ellipse and you should get the points that you want.
You are correct - the parametric angle is not the same as the angle between the desired point and the X axis. However, their tangents are proportional (with a factor of rh/rv) so you can use this approach:
Get the tangent of the desired angle
Multiply this tangent by rh/rv
Use trigonometric identities to compute the sine and cosine from the tangent
Scale/position the point according to the parameters (midpoint, rh, rv)
In Python:
from math import copysign, cos, sin, sqrt
class Ellipse:
def __init__(self, mx, my, rh, rv):
self.mx = mx
self.my = my
self.rh = rh
self.rv = rv
def pointFromAngle(self, a):
c = cos(a)
s = sin(a)
ta = s / c ## tan(a)
tt = ta * self.rh / self.rv ## tan(t)
d = 1. / sqrt(1. + tt * tt)
x = self.mx + copysign(self.rh * d, c)
y = self.my + copysign(self.rv * tt * d, s)
return x, y
I have a shape made out of several triangles which is positioned somewhere in world space with scale, rotate, translate. I also have a plane on which I would like to project (orthogonal) the shape.
I could multiply every vertex of every triangle in the shape with the objects transformation matrix to find out where it is located in world coordinates, and then project this point onto the plane.
But I don't need to draw the projection, and instead I would like to transform the plane with the inverse transformation matrix of the shape, and then project all the vertices onto the (inverse transformed) plane. Since it only requires me to transform the plane once and not every vertex.
My plane has a normal (xyz) and a distance (d). How do I multiply it with a 4x4 transformation matrix so that it turns out ok?
Can you create a vec4 as xyzd and multiply that? Or maybe create a vector xyz1 and then what to do with d?
You need to convert your plane to a different representation. One where N is the normal, and O is any point on the plane. The normal you already know, it's your (xyz). A point on the plane is also easy, it's your normal N times your distance d.
Transform O by the 4x4 matrix in the normal way, this becomes your new O. You will need a Vector4 to multiply with a 4x4 matrix, set the W component to 1 (x, y, z, 1).
Also transform N by the 4x4 matrix, but set the W component to 0 (x, y, z, 0). Setting the W component to 0 means that your normals won't get translated. If your matrix is composed of more that just translating and rotating, then this step isn't so simple. Instead of multiplying by your transformation matrix, you have to multiply by the transpose of the inverse of the matrix i.e. Matrix4.Transpose(Matrix4.Invert(Transform)), there's a good explanation on why here.
You now have a new normal vector N and a new position vector O. However I suppose you want it in xyzd form again? No problem. As before, xyz is your normal N all that's left is to calculate d. d is the distance of the plane from the origin, along the normal vector. Hence, it is simply the dot product of O and N.
There you have it! If you tell me what language you're doing this in, I'd happily type it up in code as well.
EDIT, In pseudocode:
The plane is vector3 xyz and number d, the matrix is a matrix4x4 M
vector4 O = (xyz * d, 1)
vector4 N = (xyz, 0)
O = M * O
N = transpose(invert(M)) * N
xyz = N.xyz
d = dot(O.xyz, N.xyz)
xyz and d represent the new plane
This question is a bit old but I would like to correct the accepted answer.
You do not need to convert your plane representation.
Any point lies on the plane if
It can be written as dot product :
You are looking for the plane transformed by your 4x4 matrix .
For the same reason, you must have
So and with some arrangements
TLDR : if p=(a,b,c,d), p' = transpose(inverse(M))*p
Notation:
n is a normal represented as a (1x3) row-vector
n' is the transformed normal of n according to transform matrix T
(n|d) is a plane represented as a (1x4) row-vector (with n the plane's normal and d the plane's distance to the origin)
(n'|d') is the transformed plane of (n|d) according to transform matrix T
T is a (4x4) (affine) column-major transformation matrix (i.e. transforming a column-vector t is defined as t' = T t).
Transforming a normal n:
n' = n adj(T)
Transforming a plane (n|d):
(n'|d') = (n|d) adj(T)
Here, adj is the adjugate of a matrix which is defined as follows in terms of the inverse and determinant of a matrix:
T^-1 = adj(T)/det(T)
Note:
The adjugate is generally not equal to the inverse of a transformation matrix T. If T includes a reflection, det(T) = -1, reversing the winding order!
Re-normalizing n' is mathematically not required (but maybe numerically depending on the implementation) since scaling is taken care off by the determinant. Thanks to Adrian Leonhard.
You can directly transform the plane without first decomposing and recomposing a plane (normal and point).
I am trying to do inverse kinematics for a serial chain of arbitrarily many links.
In the following paper, I have found an example for how to calculate the Jacobian matrix.
Entry (i, j) = v[j] * (s[i] - p[j])
where:
v[j] is the unit vector of the axis of
rotation for joint j
s[i] is the position (int world
coords?) of joint i
p[j] is the position (in world
coords?) of joint j
The paper says that this works if j is a rotational joint with a single degree of freedom. But my rotational joints have no constraints on their rotation. What formula do I then want? (Or am I possibly misunderstanding the term "degree of freedom"?)
This question is old, but I'll answer anyway, as it is something I have thought about but never really gotten around to implement.
Rotational joints with no constraints are called ball joints or spherical joints; they have 3 degrees of freedom. You can use the formula in the tutorial for spherical joints also, if you parameterize each spherical joint in terms of 3 rotational (revolute) joints of one degree of freedom each.
For example: Let N be the number of spherical joints. Suppose each joint has a local transformation T_local[i] and a world transformation
T_world[i] = T_local[0] * ... * T_local[i]
Let R_world[i][k], k = 0, 1, 2, be the k-th column of the rotation matrix of T_world[i]. Define the 3 * N joint axes as
v[3 * j + 0] = R_world[i][0]
v[3 * j + 1] = R_world[i][1]
v[3 * j + 2] = R_world[i][2]
Compute the Jacobian J for some end-effector s[i], using the formula of the tutorial. All coordinates are in the world frame.
Using for example the pseudo-inverse method gives a displacement dq that moves the end-effector in a given direction dx.
The length of dq is 3 * N. Define
R_dq[j] =
R_x[dq[3 * j + 0]] *
R_y[dq[3 * j + 1]] *
R_z[dq[3 * j + 2]]
for j = 0, 1, ..., N-1, where R_x, R_y, R_z are the transformation matrices for rotation about the x-, y-, and z-axes.
Update the local transformations:
T_local[j] := T_local[j] * R_dq[j]
and repeat from the top to move the end-effector in other directions dx.
Let me suggest a simpler approach to Jacobians in the context of arbitrary many DOFs: Basically, the Jacobian tells you, how far each joint moves, if you move the end effector frame in some arbitrarily chosen direction. Let f(θ) be the forward kinematics, where θ=[θ1,...,θn] are the joints. Then you can obtain the Jacobian by differentiating the forward kinematics with respect to the joint variables:
Jij = dfi/dθj
is your manipulator's Jacobian. Inverting it would give you the inverse kinematics with respect to velocities. It can still be useful though, if you want to know how far each joint has to move if you want to move your end effector by some small amount Δx in any direction (because on position level, this would effectively be a linearization):
Δθ=J-1Δx
Hope that this helps.