Find transformation matrix between two matrices - math

I tried to find the transformation matrix between two matrices, so i can save it, and later apply it on an object so it will maintain its position and rotation relatively to another object. using this sugested solution:
3d (THREE.js) : difference matrix
I used this code:
var aInv1 = new THREE.Matrix4().getInverse(firstObject.matrix.clone());
var aMat2 = new THREE.Matrix4().copy(secondObject.matrix.clone());
var aTrans = new THREE.Matrix4().multiplyMatrices(aMat2, aInv1);
The values of the matrices elements are:
firstObject.matrix.elements = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, -358.483421667927, 1
]
secondObject.matrix.elements = [
0.5137532240102918, -0.844167465362402, 0.15309773101731067, 0,
0.8579380075617532, 0.5055071032079361, -0.091678480502733, 0,
-1.3877787807814457e-17, 0.1784484772418605, 0.983949257314655, 0,
94.64320536824728, 6.92473686011361, -372.0695450875709, 1
]
I would expect that the transformation Matrix aka variable aTrans elements would be 94.64320536824728, 6.92473686011361, 13.58 because those are the differences in the position, but I get 94.64320536824728, 70.89555757320696, -19.340048577797802, 1.
aTrans.matrix.elements = [
0.5137532240102918, -0.844167465362402, 0.15309773101731067, 0,
0.8579380075617532, 0.5055071032079361, -0.091678480502733, 0,
-1.3877787807814457e-17, 0.1784484772418605, 0.983949257314655, 0,
94.64320536824728, 70.89555757320696, -19.340048577797802, 1
]
I would appriciate any educated explanation for this difference, or another way to solve this problem.

You cannot simply add the translations because the second matrix might affect the effective translation of the first.
Let's consider a simple example - suppose both matrices only contain a rotation and translation:
M = R + T
R corresponds to the top-left 3x3 sub-matrix, and T is the first 3 elements of the last column. Multiplication rule with an arbitrary 3D point p:
M * p = R * p + T
Two of these give:
M2 * M1 * p = R2 * R1 * p + R2 * T1 + T2
The last column of M2 * M1 is R2 * T1 + T2 instead of simply T1 + T2, i.e. effective translation that M1 imposes on p is R2 * T1, and not simply T1.

Related

Delta operator in sympy

Is it possible to make a delta operator like this in sympy? Im not really sure how to code it. Should be really eazy if there exists a method.
I don't know if SymPy exposes something that could be useful to you. If not, we can create something raw.
Note: the following approach requires a bit of knowledge in Object Oriented Programming and the way SymPy treats things. This is a 5 minutes attempt, and it is not meant to be used in production (as a matter of fact, no test has been done over this code). There are many things that may not work as expected. But, for your case, it might work :)
One possible way is to define a "gradient" class, like this:
class Grad(Expr):
def __mul__(self, other):
return other.diff(*self.args)
def _latex(self, printer):
# create a latex representation to be visualize in Jupyter Notebook
return r"\frac{\partial}{%s}" % " ".join([r"\partial %s" % latex(t) for t in self.args])
We can create a gradient of something with respect to x by writing gx = Grad(x). Once gx is multiplied with some other thing, it returns the partial derivative of that thing with respect to x.
Then you would define your symbols/functions and matrices like this:
from sympy import *
init_printing()
var("x, y")
N1, N2, N3 = [s(x, y) for s in symbols("N1:4", cls=Function)]
A = Matrix(3, 2, [Grad(x), 0, 0, Grad(y), Grad(x), Grad(y)])
B = Matrix(2, 6, [N1, 0, N2, 0, N3, 0, 0, N1, 0, N2, 0, N3])
display(A, B)
Finally, you multiply the matrices together to obtain the symbolic results:
A * B
Eventually, you might want to create a function:
def delta_operator(x, y, N1, N2, N3):
A = Matrix(3, 2, [Grad(x), 0, 0, Grad(y), Grad(x), Grad(y)])
B = Matrix(2, 6, [N1, 0, N2, 0, N3, 0, 0, N1, 0, N2, 0, N3])
return A * B
So, whenever you have to apply that operator, you just execute delta_operator(x, y, N1, N2, N3) to obtain a result similar to above.

Threejs - How to offset all points on a 2d geometry by distance

Using Three.js, (although I believe this is more math related) I have a set of 2D points that can create a 2D geometry. such as square, rectangle, pentagon, or custom 2D shape. Based of the original 2D shape, I would like to create a method to offset the points inward or outward uniformly in such a way like the attached image.
I don't know if there is a simple way to offset/grow/shrink all the points (vector3) uniformly on the 2D shape inward or outward. And if so, it'll be cool if I can offset the points by X distance? Kinda of like saying offset the points on the 2D shape outward or inward by X distance.
And no, I'm not referring to scaling from a center point. While scaling may work for symmetrical shapes, it won't work when it comes to non-symmetrical shapes.
see image for example
Thanks in advance.
You can read that forum thread.
I've made some changes with ProfiledContourGeometry and got OffsetContour, so I leave it here, just in case, what if it helps :)
function OffsetContour(offset, contour) {
let result = [];
offset = new THREE.BufferAttribute(new Float32Array([offset, 0, 0]), 3);
console.log("offset", offset);
for (let i = 0; i < contour.length; i++) {
let v1 = new THREE.Vector2().subVectors(contour[i - 1 < 0 ? contour.length - 1 : i - 1], contour[i]);
let v2 = new THREE.Vector2().subVectors(contour[i + 1 == contour.length ? 0 : i + 1], contour[i]);
let angle = v2.angle() - v1.angle();
let halfAngle = angle * 0.5;
let hA = halfAngle;
let tA = v2.angle() + Math.PI * 0.5;
let shift = Math.tan(hA - Math.PI * 0.5);
let shiftMatrix = new THREE.Matrix4().set(
1, 0, 0, 0,
-shift, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
let tempAngle = tA;
let rotationMatrix = new THREE.Matrix4().set(
Math.cos(tempAngle), -Math.sin(tempAngle), 0, 0,
Math.sin(tempAngle), Math.cos(tempAngle), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
let translationMatrix = new THREE.Matrix4().set(
1, 0, 0, contour[i].x,
0, 1, 0, contour[i].y,
0, 0, 1, 0,
0, 0, 0, 1,
);
let cloneOffset = offset.clone();
console.log("cloneOffset", cloneOffset);
shiftMatrix.applyToBufferAttribute(cloneOffset);
rotationMatrix.applyToBufferAttribute(cloneOffset);
translationMatrix.applyToBufferAttribute(cloneOffset);
result.push(new THREE.Vector2(cloneOffset.getX(0), cloneOffset.getY(0)));
}
return result;
}
Feel free to modify it :)
I have some doubts about solutions that do not include number of edges modification.
I faced the same issue in this project where I wanted to ensure a known distance between voronoi cells, and I quickly figured out that scale does not fulfill the use case. But one complication I faced was the disappearance of some edges that I had to handle in a while loop. It was so difficult to debug that I had to create a debug mode that helps see the points and lines, that I also left available. It's possible to activate this debug mode with a checkbox:
Note for the images, I have them as links not embedded as I'm still new contributor (might improve that later).
The edges that shall disappear are shown in red
retraction snapshot1
retraction with edges discard 1
retraction with edges discard 2
Here a link to the function in action, you might have to modify it to have another points format though :
https://github.com/WebSVG/voronoi/blob/8893768e3929ea713a47dba2c4d273b775e0bd82/src/voronoi_diag.js#L278
And here a link to the complete project integrating this function, it has link to a live demo too
https://github.com/WebSVG/voronoi

How to calculate the expression

Given the equation-> (index+rotation)%rot=f; if i konw the values of f , rotation , rot
what is the formula to calculate index.I am not so good in mathematics but i want to know to calculate index in my programming.
(index + rotation)%rot = f
means
index + rotation = rot*k + f, k is an integer (.., -2, -1, 0, 1, 2,..)
therefore
index = rot*k + f - rotation, k: integer
If you want to have index > 0, make sure to choose k > (rotation - f) / rot

How does alpha blending work, mathematically, pixel-by-pixel?

Seems like it's not as simple as RGB1*A1 + RGB2*A2...how are values clipped? Weighted? Etc.
And is this a context-dependent question? Are there different algorithms, that produce different results? Or one standard implementation?
I'm particularly interested in OpenGL-specific answers, but context from other environments is useful too.
I don't know about OpenGL, but one pixel of opacity A is usually drawn on another pixel like so:
result.r = background.r * (1 - A) + foreground.r * A
result.g = background.g * (1 - A) + foreground.g * A
result.b = background.b * (1 - A) + foreground.b * A
Repeat this operation for multiple pixels.
The above answer works if the image isn't premultiplied alpha. However if you use that type of blending with a premultiplied alpha image, there will be a black border.
Premultiplied Alpha:
When the image is created, the color values are multiplied by the alpha channel. Take a look at this one pixel example:
Pixel: r = 1, g = 0, b = 0, a = 0.5
When it's saved, the rgb vales will be multiplied by the alpha value giving:
Pixel: r = 0.5, g = 0, b = 0, a = 0.5
To blend this kind of image you need to use the following formula:
result.r = background.r * (1 - A) + foreground.r
result.g = background.g * (1 - A) + foreground.g
result.b = background.b * (1 - A) + foreground.b
Non-premultiplied Alpha
In this example, the alpha channel is completely separate to the color channels.
Pixel: r = 1, g = 0, b = 0, a = 0.5
When it's saved:
Pixel: r = 1, g = 0, b = 0, a = 0.5
It's the same. In this case the answer provided by minitech is correct.
More details can be found here: Premultiplied alpha

Problem with Euler angles from YZX Rotation Matrix

I've gotten stuck getting my euler angles out my rotation matrix.
My conventions are:
Left-handed (x right, z back, y up)
YZX
Left handed angle rotation
My rotation matrix is built up from Euler angles like (from my code):
var xRotationMatrix = $M([
[1, 0, 0, 0],
[0, cx, -sx, 0],
[0, sx, cx, 0],
[0, 0, 0, 1]
]);
var yRotationMatrix = $M([
[ cy, 0, sy, 0],
[ 0, 1, 0, 0],
[-sy, 0, cy, 0],
[ 0, 0, 0, 1]
]);
var zRotationMatrix = $M([
[cz, -sz, 0, 0],
[sz, cz, 0, 0],
[ 0, 0, 1, 0],
[ 0, 0, 0, 1]
]);
Which results in a final rotation matrix as:
R(YZX) = | cy.cz, -cy.sz.cx + sy.sx, cy.sz.sx + sy.cx, 0|
| sz, cz.cx, -cz.sx, 0|
|-sy.cz, sy.sz.cx + cy.sx, -sy.sz.sx + cy.cx, 0|
| 0, 0, 0, 1|
I'm calculating my euler angles back from this matrix using this code:
this.anglesFromMatrix = function(m) {
var y = 0, x = 0, z = 0;
if (m.e(2, 1) > 0.999) {
y = Math.atan2(m.e(1, 3), m.e(3, 3));
z = Math.PI / 2;
x = 0;
} else if (m.e(2, 1) < -0.999) {
y = Math.atan2(m.e(1, 3), m.e(3, 3));
z = -Math.PI / 2;
x = 0;
} else {
y = Math.atan2(-m.e(3, 1), -m.e(1, 1));
x = Math.atan2(-m.e(2, 3), m.e(2, 2));
z = Math.asin(m.e(2, 1));
}
return {theta: this.deg(x), phi: this.deg(y), psi: this.deg(z)};
};
I've done the maths backwards and forwards a few times, but I can't see what's wrong. Any help would hugely appreciated.
Your matrix and euler angles aren't consistent. It looks like you should be using
y = Math.atan2(-m.e(3, 1), m.e(1, 1));
instead of
y = Math.atan2(-m.e(3, 1), -m.e(1, 1));
for the general case (the else branch).
I said "looks like" because -- what language is this? I'm assuming you have the indexing correct for this language. Are you sure about atan2? There is no single convention for atan2. In some programming languages the sine term is the first argument, in others, the cosine term is the first argument.
The last and most important branch of the anglesFromMatrix function has a small sign error but otherwise works correctly. Use
y = Math.atan2(-m.e(3, 1), m.e(1, 1))
since only m.e(3, 1) of m.e(1, 1) = cy.cz and m.e(3, 1) = -sy.cz should be inverted. I haven't checked the other branches for errors.
Beware that since sz = m.e(2, 1) has two solutions, the angles (x, y, z) used to construct the matrix m might not be the same as the angles (rx, ry, rz) returned by anglesFromMatrix(m). Instead we can test that the matrix rm constructed from (rx, ry, rz) does indeed equal m.
I worked on this problem extensively to come up with the correct angles for a given matrix. The problem in the math comes from the inability to determine a precise value for the SIN since -SIN(x) = SIN(-x) and this will affect the other values of the matrix. The solution I came up with comes up with two equally valid solutions out of eight possible solutions. I used a standard Z . Y . X matrix form but it should be adaptable to any matrix. Start by findng the three angles from: X = atan(m32,m33): Y = -asin(m31) : Z = atan(m21,m11) : Then create angles X' = -sign(X)*PI+X : Y'= sign(Y)*PI-Y : Z = -sign(Z)*pi+Z . Using these angles create eight set of angle groups : XYZ : X'YZ : XYZ' : X'YZ' : X'Y'Z' : XY'Z' : X'Y'Z : XY'Z
Use these set to create the eight corresponding matrixes. Then do a sum of the difference between the unknown matrix and each matrix. This is a sum of each element of the unknown minus the same element of the test matrix. After doing this, two of the sums will be zero and those matrixes will represent the solution angles to the original matrix. This works for all possible angle combinations including 0's. As 0's are introduced, more of the eight test matrixes become valid. At 0,0,0 they all become idenity matrixes!
Hope this helps, it worked very well for my application.
Bruce
update
After finding problems with Y = -90 or 90 degrees in the solution above. I came up with this solution that seems to reproduce the matrix at all values!
X = if(or(m31=1,m31=-1),0,atan(m33+1e-24,m32))
Y = -asin(m31)
Z = if(or(m31=1,m31=-1),-atan2(m22,m12),atan2(m11+1e-24,m21))
I went the long way around to find this solution, but it wa very enlightening :o)
Hope this helps!
Bruce

Resources