I notice that multmatrix() takes matrices in the traditional format where,
for example, translation terms are the in the last column. However, matrix
maths in OpenSCAD user land is done with transposed matrices, where
translation terms are on the last row.
I understand this is because vectors are treated as rows instead of columns
when doing the multiply. It is inconvenient when at the end of calculating
some transformation I want to pass the result to multmatrix and have to
transpose it.
Experimentally it seems that if I reverse the order of multiplication, so
that instead of row vector times transformation matrix I have matrix times
row vector then I can use traditional format transformation matrices and
pass them directly to multmatrix. Is this correct? It seems too simple.
m = translate([1,2,3]);
m2 = transpose(m);
echo(m);
echo(m2);
echo([4,5,6, 1] * m);
echo(m2 * [4,5,6,1]);
ECHO: [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [1, 2, 3, 1]]
ECHO: [[1, 0, 0, 1], [0, 1, 0, 2], [0, 0, 1, 3], [0, 0, 0, 1]]
ECHO: [5, 7, 9, 1]
ECHO: [5, 7, 9, 1]
If I just rewrite all my transformations in conventional order and swap
just the multiplication order with row vectors, will everything work out?
This statement seems to imply the answer is yes:
https://en.wikipedia.org/wiki/Matrix_multiplication#Transpose
On Mon, 1 Apr 2019 at 14:28, nop head nop.head@gmail.com wrote:
I notice that multmatrix() takes matrices in the traditional format where,
for example, translation terms are the in the last column. However, matrix
maths in OpenSCAD user land is done with transposed matrices, where
translation terms are on the last row.
I understand this is because vectors are treated as rows instead of
columns when doing the multiply. It is inconvenient when at the end of
calculating some transformation I want to pass the result to multmatrix and
have to transpose it.
Experimentally it seems that if I reverse the order of multiplication, so
that instead of row vector times transformation matrix I have matrix times
row vector then I can use traditional format transformation matrices and
pass them directly to multmatrix. Is this correct? It seems too simple.
m = translate([1,2,3]);
m2 = transpose(m);
echo(m);
echo(m2);
echo([4,5,6, 1] * m);
echo(m2 * [4,5,6,1]);
ECHO: [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [1, 2, 3, 1]]
ECHO: [[1, 0, 0, 1], [0, 1, 0, 2], [0, 0, 1, 3], [0, 0, 0, 1]]
ECHO: [5, 7, 9, 1]
ECHO: [5, 7, 9, 1]
If I just rewrite all my transformations in conventional order and swap
just the multiplication order with row vectors, will everything work out?
Mathematically, the product of a matrix by a row matrix is undefined
(except if the matrix has just one column) but in OpenSCAD, the vector is
considered a column vector instead of a row vector in the product of a
matrix by a vector. On the other hand, the product of a vector by a matrix
in OpenSCAD has the same meaning it has in Mathematics. So, in Mathematics,
the following holds for a row vector v and matrix M :
v * M = transpose(M)*transpose(v)
but in OpenSCAD we get an undefined vector in the evaluation of the right
expression.
Em seg, 1 de abr de 2019 às 14:33, nop head nop.head@gmail.com escreveu:
This statement seems to imply the answer is yes:
https://en.wikipedia.org/wiki/Matrix_multiplication#Transpose
On Mon, 1 Apr 2019 at 14:28, nop head nop.head@gmail.com wrote:
I notice that multmatrix() takes matrices in the traditional format
where, for example, translation terms are the in the last column. However,
matrix maths in OpenSCAD user land is done with transposed matrices, where
translation terms are on the last row.
I understand this is because vectors are treated as rows instead of
columns when doing the multiply. It is inconvenient when at the end of
calculating some transformation I want to pass the result to multmatrix and
have to transpose it.
Experimentally it seems that if I reverse the order of multiplication, so
that instead of row vector times transformation matrix I have matrix times
row vector then I can use traditional format transformation matrices and
pass them directly to multmatrix. Is this correct? It seems too simple.
m = translate([1,2,3]);
m2 = transpose(m);
echo(m);
echo(m2);
echo([4,5,6, 1] * m);
echo(m2 * [4,5,6,1]);
ECHO: [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [1, 2, 3, 1]]
ECHO: [[1, 0, 0, 1], [0, 1, 0, 2], [0, 0, 1, 3], [0, 0, 0, 1]]
ECHO: [5, 7, 9, 1]
ECHO: [5, 7, 9, 1]
If I just rewrite all my transformations in conventional order and swap
just the multiplication order with row vectors, will everything work out?
Yes OpenSCAD seems unable to handle single column vectors but the transpose
of a column vector is a row vector, so I think that is why it works when I
swap the order. The order has been swapped and both operands have been
transposed, so the result is the same but now the matrix is in conventional
format.
So now I have conventional transformation matrices that can be passed
directly to multmatrix simply by swapping the multiplication order.
The other thing that changed is the order that I have to multiply
transformation matrices with each other is reversed. This seems more
natural because translate () rotate() in modules becomes translate() *
rotate() in functions, whereas before I had do it in reverse, which seemed
wrong.
I used it to speed up the preview of this box from 63 seconds to 5 seconds.
[image: image.png]
All the time was taken making the holes in the sheets. In 3D it is slow
because of CGAL hates lots of holes. When I made the sheets 2D I had to
project the holes and that was not much faster as projection() is very
slow. Now I represent the holes positions and orientation with matrices and
project the holes with matrix multiplication and filter the ones that lie
on the sheet like this.
module drill_holes(type, t)
for(list = [corner_holes(type), side_holes(type)], p = list)
let(q = t * p)
if(abs(transform([0, 0, 0], q).z) < eps)
multmatrix(q)
drill(screw_clearance_radius(bbox_screw(type)), 0);
t is the transformation that maps the holes for each sheet to the X plane.
On Mon, 1 Apr 2019 at 16:15, Ronaldo Persiano rcmpersiano@gmail.com wrote:
Mathematically, the product of a matrix by a row matrix is undefined
(except if the matrix has just one column) but in OpenSCAD, the vector is
considered a column vector instead of a row vector in the product of a
matrix by a vector. On the other hand, the product of a vector by a matrix
in OpenSCAD has the same meaning it has in Mathematics. So, in Mathematics,
the following holds for a row vector v and matrix M :
v * M = transpose(M)*transpose(v)
but in OpenSCAD we get an undefined vector in the evaluation of the right
expression.
Em seg, 1 de abr de 2019 às 14:33, nop head nop.head@gmail.com escreveu:
This statement seems to imply the answer is yes:
https://en.wikipedia.org/wiki/Matrix_multiplication#Transpose
On Mon, 1 Apr 2019 at 14:28, nop head nop.head@gmail.com wrote:
I notice that multmatrix() takes matrices in the traditional format
where, for example, translation terms are the in the last column. However,
matrix maths in OpenSCAD user land is done with transposed matrices, where
translation terms are on the last row.
I understand this is because vectors are treated as rows instead of
columns when doing the multiply. It is inconvenient when at the end of
calculating some transformation I want to pass the result to multmatrix and
have to transpose it.
Experimentally it seems that if I reverse the order of multiplication,
so that instead of row vector times transformation matrix I have matrix
times row vector then I can use traditional format transformation matrices
and pass them directly to multmatrix. Is this correct? It seems too simple.
m = translate([1,2,3]);
m2 = transpose(m);
echo(m);
echo(m2);
echo([4,5,6, 1] * m);
echo(m2 * [4,5,6,1]);
ECHO: [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [1, 2, 3, 1]]
ECHO: [[1, 0, 0, 1], [0, 1, 0, 2], [0, 0, 1, 3], [0, 0, 0, 1]]
ECHO: [5, 7, 9, 1]
ECHO: [5, 7, 9, 1]
If I just rewrite all my transformations in conventional order and swap
just the multiplication order with row vectors, will everything work out?
I experimented a bit with these operations and then I also read the manual.
:) Matrix*matrix products work exactly as expected, when both matrices are
lists of lists. What is perhaps a bit trickier is the handling of vectors,
where a vector is a list of scalars.
Note that there is no meaningful notion of "row vector" vs "column vector"
for a list of scalars, nor is there any meaningful notion of
transpose---these objects are just vectors. So I can't make sense of
"transpose(v)" as an OpenSCAD operation on a vector, v. How would it
change?
Simply put, when you do matrixvector or vectormatrix operations, OpenSCAD
treats the vector as either a column or row as needed to make the operation
possible.
So in OpenSCAD, Mv = vtranspose(M). But if you want to transform a list
of points, then you have to pay attention to the orientation of the data, so
M*[v1,v2,v3,v4,...] will fail because you have now organized the data as a
matrix of row vectors, whereas multiplying on the right (by the transpose)
will work: [v1,v2,v3,v4,...]transpose(M). And of course it would also
work to do Mtranspose([v1,v2,v3,v4,...]) but then the result would need to
be transposed again to get a list of points.
Ronaldo wrote
Mathematically, the product of a matrix by a row matrix is undefined
(except if the matrix has just one column) but in OpenSCAD, the vector is
considered a column vector instead of a row vector in the product of a
matrix by a vector. On the other hand, the product of a vector by a matrix
in OpenSCAD has the same meaning it has in Mathematics. So, in
Mathematics,
the following holds for a row vector v and matrix M :
v * M = transpose(M)*transpose(v)
but in OpenSCAD we get an undefined vector in the evaluation of the right
expression.
--
Sent from: http://forum.openscad.org/
Simply put, when you do matrixvector or vectormatrix operations,
OpenSCAD treats the vector as either a column or row as needed to make the
operation possible.
No it doesn't. In conventional maths vector * transformation matrix the
vector is a column. When you do it in OpenSCAD the result you get is what
it would be for a column vector if the matrix was transposed. That makes
the transformation matrix wrong for multmatrix, which expects it in
conventional format as you would see in Wikipedia, for example.
All the user land matrix maths I have seen for OpenSCAD works with
transposed transformations. I found that simply by post multiplying by the
vector you get the correct answer without having to transpose the matrix.
So I have rewritten my maths utilities with conventional transformation
matrices.
function sqr(x) = x * x;
function translate(v) = let(u = is_list(v) ? len(v) == 2 ? [v.x, v.y, 0]
: v
: [0, 0, v])
[ [1, 0, 0, u.x],
[0, 1, 0, u.y],
[0, 0, 1, u.z],
[0, 0, 0, 1] ];
function rotate(a, v) =
is_undef(v) ? let(av = is_list(a) ? a : [0, 0, a],
cx = cos(av[0]),
cy = cos(av[1]),
cz = cos(av[2]),
sx = sin(av[0]),
sy = sin(av[1]),
sz = sin(av[2]))
[
[ cy * cz, cz * sx * sy - cx * sz, cx * cz *
sy + sx * sz, 0],
[ cy * sz, cx * cz + sx * sy * sz,-cz * sx +
cx * sy * sz, 0],
[-sy, cy * sx, cx * cy,
0],
[ 0, 0, 0,
1]
]
: let(s = sin(a),
c = cos(a),
C = 1 - c,
m = sqr(v.x) + sqr(v.y) + sqr(v.z), // m used instead
of norm to avoid irrational roots as much as possible
u = v / sqrt(m))
[
[ C * v.x * v.x / m + c, C * v.x * v.y
/ m - u.z * s, C * v.x * v.z / m + u.y * s, 0],
[ C * v.y * v.x / m + u.z * s, C * v.y * v.y
/ m + c, C * v.y * v.z / m - u.x * s, 0],
[ C * v.z * v.x / m - u.y * s, C * v.z * v.y
/ m + u.x * s, C * v.z * v.z / m + c, 0],
[ 0, 0,
0, 1]
];
function scale(v) = let(s = len(v) ? v : [v, v, v])
[
[s.x, 0, 0, 0],
[0, s.y, 0, 0],
[0, 0, s.z, 0],
[0, 0, 0, 1]
];
function vec3(v) = [v.x, v.y, v.z];
function transform(v, m) = vec3(m * [v.x, v.y, v.z, 1]);
function transform_points(path, m) = [for(p = path) transform(p, m)];
This makes far more sense to me as I can pass my matrices to multmatrix
without transposing them. Note that in my transform(v, m) I post multiply
by v whereas if OpenSCAD treated v as a column it should be pre-multiplied.
I think if you transpose a row vector you would get a column vector.
On Tue, 2 Apr 2019 at 18:25, adrianv avm4@cornell.edu wrote:
I experimented a bit with these operations and then I also read the manual.
:) Matrix*matrix products work exactly as expected, when both matrices are
lists of lists. What is perhaps a bit trickier is the handling of
vectors,
where a vector is a list of scalars.
Note that there is no meaningful notion of "row vector" vs "column vector"
for a list of scalars, nor is there any meaningful notion of
transpose---these objects are just vectors. So I can't make sense of
"transpose(v)" as an OpenSCAD operation on a vector, v. How would it
change?
Simply put, when you do matrixvector or vectormatrix operations, OpenSCAD
treats the vector as either a column or row as needed to make the operation
possible.
So in OpenSCAD, Mv = vtranspose(M). But if you want to transform a list
of points, then you have to pay attention to the orientation of the data,
so
M*[v1,v2,v3,v4,...] will fail because you have now organized the data as a
matrix of row vectors, whereas multiplying on the right (by the transpose)
will work: [v1,v2,v3,v4,...]transpose(M). And of course it would also
work to do Mtranspose([v1,v2,v3,v4,...]) but then the result would need to
be transposed again to get a list of points.
Ronaldo wrote
Mathematically, the product of a matrix by a row matrix is undefined
(except if the matrix has just one column) but in OpenSCAD, the vector is
considered a column vector instead of a row vector in the product of a
matrix by a vector. On the other hand, the product of a vector by a
matrix
in OpenSCAD has the same meaning it has in Mathematics. So, in
Mathematics,
the following holds for a row vector v and matrix M :
v * M = transpose(M)*transpose(v)
but in OpenSCAD we get an undefined vector in the evaluation of the right
expression.
--
Sent from: http://forum.openscad.org/
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
In conventional maths vector * transformation matrix the vector is a column.
This is not a convention I am familiar with. All the references I have consulted say that the vector is a row, and that's the convention I use in my own code.
Here's what I use as a reference for "conventional maths":
http://mathworld.wolfram.com/MatrixMultiplication.html
quote: "(a×b) denotes a matrix with a rows and b columns".
In OpenSCAD, an a×b matrix is written in row-major order. Here's a 2×3 matrix:
[ [11,12,13],
[21,22,23] ]
In matrix multiplication, "the dimensions of the matrices must satisfy (n×m)(m×p) = (n×p)".
For example, (1×3)(3×3) = (1×3).
Therefore, in the maths convention that I know, as defined by MathWorld, vector*matrix, the vector is a row vector.
OpenSCAD conforms to this convention. And for what it's worth, the OpenSCAD matrix multiply is consistent with the behaviour of the Mathematica matrix multiply (both use nested lists to represent matrices).
The wikipedia article Matrix Multiplication defines the same conventions. Also, https://en.wikipedia.org/wiki/Row_and_column_vectors says that in 'vector*matrix', the vector is a row vector.
However, in conventional maths, if you write matrix*vector, then in that case, the vector is a column vector.
Also, when you transform a vector using a transformation matrix, the convention is to perform the multiplication in this order:
transformation_matrix * vector
This convention is mentioned in both Mathworld and in the Wikipedia article "Transformation_matrix".
Doug Moen.
On Tue, Apr 2, 2019, at 3:40 PM, nop head wrote:
Simply put, when you do matrixvector or vectormatrix operations, OpenSCAD treats the vector as either a column or row as needed to make the operation possible.
No it doesn't. In conventional maths vector * transformation matrix the vector is a column. When you do it in OpenSCAD the result you get is what it would be for a column vector if the matrix was transposed. That makes the transformation matrix wrong for multmatrix, which expects it in conventional format as you would see in Wikipedia, for example.
All the user land matrix maths I have seen for OpenSCAD works with transposed transformations. I found that simply by post multiplying by the vector you get the correct answer without having to transpose the matrix. So I have rewritten my maths utilities with conventional transformation matrices.
function sqr(x) = x * x;
function translate(v) = let(u = is_list(v) ? len(v) == 2 ? [v.x, v.y, 0]
: v
: [0, 0, v])
[ [1, 0, 0, u.x],
[0, 1, 0, u.y],
[0, 0, 1, u.z],
[0, 0, 0, 1] ];
function rotate(a, v) =
is_undef(v) ? let(av = is_list(a) ? a : [0, 0, a],
cx = cos(av[0]),
cy = cos(av[1]),
cz = cos(av[2]),
sx = sin(av[0]),
sy = sin(av[1]),
sz = sin(av[2]))
[
[ cy * cz, cz * sx * sy - cx * sz, cx * cz * sy + sx * sz, 0],
[ cy * sz, cx * cz + sx * sy * sz,-cz * sx + cx * sy * sz, 0],
[-sy, cy * sx, cx * cy, 0],
[ 0, 0, 0, 1]
]
: let(s = sin(a),
c = cos(a),
C = 1 - c,
m = sqr(v.x) + sqr(v.y) + sqr(v.z), // m used instead of norm to avoid irrational roots as much as possible
u = v / sqrt(m))
[
[ C * v.x * v.x / m + c, C * v.x * v.y / m - u.z * s, C * v.x * v.z / m + u.y * s, 0],
[ C * v.y * v.x / m + u.z * s, C * v.y * v.y / m + c, C * v.y * v.z / m - u.x * s, 0],
[ C * v.z * v.x / m - u.y * s, C * v.z * v.y / m + u.x * s, C * v.z * v.z / m + c, 0],
[ 0, 0, 0, 1]
];
function scale(v) = let(s = len(v) ? v : [v, v, v])
[
[s.x, 0, 0, 0],
[0, s.y, 0, 0],
[0, 0, s.z, 0],
[0, 0, 0, 1]
];
function vec3(v) = [v.x, v.y, v.z];
function transform(v, m) = vec3(m * [v.x, v.y, v.z, 1]);
function transform_points(path, m) = [for(p = path) transform(p, m)];
This makes far more sense to me as I can pass my matrices to multmatrix without transposing them. Note that in my transform(v, m) I post multiply by v whereas if OpenSCAD treated v as a column it should be pre-multiplied.
I think if you transpose a row vector you would get a column vector.
On Tue, 2 Apr 2019 at 18:25, adrianv avm4@cornell.edu wrote:
I experimented a bit with these operations and then I also read the manual.
:) Matrix*matrix products work exactly as expected, when both matrices are
lists of lists. What is perhaps a bit trickier is the handling of vectors,
where a vector is a list of scalars.
Note that there is no meaningful notion of "row vector" vs "column vector"
for a list of scalars, nor is there any meaningful notion of
transpose---these objects are just vectors. So I can't make sense of
"transpose(v)" as an OpenSCAD operation on a vector, v. How would it
change?
Simply put, when you do matrixvector or vectormatrix operations, OpenSCAD
treats the vector as either a column or row as needed to make the operation
possible.
So in OpenSCAD, Mv = vtranspose(M). But if you want to transform a list
of points, then you have to pay attention to the orientation of the data, so
M*[v1,v2,v3,v4,...] will fail because you have now organized the data as a
matrix of row vectors, whereas multiplying on the right (by the transpose)
will work: [v1,v2,v3,v4,...]transpose(M). And of course it would also
work to do Mtranspose([v1,v2,v3,v4,...]) but then the result would need to
be transposed again to get a list of points.
Ronaldo wrote
Mathematically, the product of a matrix by a row matrix is undefined
(except if the matrix has just one column) but in OpenSCAD, the vector is
considered a column vector instead of a row vector in the product of a
matrix by a vector. On the other hand, the product of a vector by a matrix
in OpenSCAD has the same meaning it has in Mathematics. So, in
Mathematics,
the following holds for a row vector v and matrix M :
v * M = transpose(M)*transpose(v)
but in OpenSCAD we get an undefined vector in the evaluation of the right
expression.
--
Sent from: http://forum.openscad.org/
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
OK so OpenSCAD is correct and we need to post multiply with the vector to
have it treated as a column. Somehow I had it all transposed. I was sure
it came from looking at other people's code but perhaps it was just me
getting confused.
On Tue, 2 Apr 2019 at 22:30, Doug Moen doug@moens.org wrote:
In conventional maths vector * transformation matrix the vector is a
column.
This is not a convention I am familiar with. All the references I have
consulted say that the vector is a row, and that's the convention I use in
my own code.
Here's what I use as a reference for "conventional maths":
http://mathworld.wolfram.com/MatrixMultiplication.html
quote: "(a×b) denotes a matrix with a rows and b columns".
In OpenSCAD, an a×b matrix is written in row-major order. Here's a 2×3
matrix:
[ [11,12,13],
[21,22,23] ]
In matrix multiplication, "the dimensions of the matrices must satisfy
(n×m)(m×p) = (n×p)".
For example, (1×3)(3×3) = (1×3).
Therefore, in the maths convention that I know, as defined by MathWorld,
vector*matrix, the vector is a row vector.
OpenSCAD conforms to this convention. And for what it's worth, the
OpenSCAD matrix multiply is consistent with the behaviour of the
Mathematica matrix multiply (both use nested lists to represent matrices).
The wikipedia article Matrix Multiplication defines the same conventions.
Also, https://en.wikipedia.org/wiki/Row_and_column_vectors says that in
'vector*matrix', the vector is a row vector.
However, in conventional maths, if you write matrix*vector, then in that
case, the vector is a column vector.
Also, when you transform a vector using a transformation matrix, the
convention is to perform the multiplication in this order:
transformation_matrix * vector
This convention is mentioned in both Mathworld and in the Wikipedia
article "Transformation_matrix".
Doug Moen.
On Tue, Apr 2, 2019, at 3:40 PM, nop head wrote:
Simply put, when you do matrixvector or vectormatrix operations,
OpenSCAD treats the vector as either a column or row as needed to make the
operation possible.
No it doesn't. In conventional maths vector * transformation matrix the
vector is a column. When you do it in OpenSCAD the result you get is what
it would be for a column vector if the matrix was transposed. That makes
the transformation matrix wrong for multmatrix, which expects it in
conventional format as you would see in Wikipedia, for example.
All the user land matrix maths I have seen for OpenSCAD works with
transposed transformations. I found that simply by post multiplying by the
vector you get the correct answer without having to transpose the matrix.
So I have rewritten my maths utilities with conventional transformation
matrices.
function sqr(x) = x * x;
function translate(v) = let(u = is_list(v) ? len(v) == 2 ? [v.x, v.y, 0]
: v
: [0, 0, v])
[ [1, 0, 0, u.x],
[0, 1, 0, u.y],
[0, 0, 1, u.z],
[0, 0, 0, 1] ];
function rotate(a, v) =
is_undef(v) ? let(av = is_list(a) ? a : [0, 0, a],
cx = cos(av[0]),
cy = cos(av[1]),
cz = cos(av[2]),
sx = sin(av[0]),
sy = sin(av[1]),
sz = sin(av[2]))
[
[ cy * cz, cz * sx * sy - cx * sz, cx * cz *
sy + sx * sz, 0],
[ cy * sz, cx * cz + sx * sy * sz,-cz * sx +
cx * sy * sz, 0],
[-sy, cy * sx, cx * cy,
0],
[ 0, 0, 0,
1]
]
: let(s = sin(a),
c = cos(a),
C = 1 - c,
m = sqr(v.x) + sqr(v.y) + sqr(v.z), // m used
instead of norm to avoid irrational roots as much as possible
u = v / sqrt(m))
[
[ C * v.x * v.x / m + c, C * v.x * v.y
/ m - u.z * s, C * v.x * v.z / m + u.y * s, 0],
[ C * v.y * v.x / m + u.z * s, C * v.y * v.y
/ m + c, C * v.y * v.z / m - u.x * s, 0],
[ C * v.z * v.x / m - u.y * s, C * v.z * v.y
/ m + u.x * s, C * v.z * v.z / m + c, 0],
[ 0, 0,
0, 1]
];
function scale(v) = let(s = len(v) ? v : [v, v, v])
[
[s.x, 0, 0, 0],
[0, s.y, 0, 0],
[0, 0, s.z, 0],
[0, 0, 0, 1]
];
function vec3(v) = [v.x, v.y, v.z];
function transform(v, m) = vec3(m * [v.x, v.y, v.z, 1]);
function transform_points(path, m) = [for(p = path) transform(p, m)];
This makes far more sense to me as I can pass my matrices to multmatrix
without transposing them. Note that in my transform(v, m) I post multiply
by v whereas if OpenSCAD treated v as a column it should be pre-multiplied.
I think if you transpose a row vector you would get a column vector.
On Tue, 2 Apr 2019 at 18:25, adrianv avm4@cornell.edu wrote:
I experimented a bit with these operations and then I also read the manual.
:) Matrix*matrix products work exactly as expected, when both matrices are
lists of lists. What is perhaps a bit trickier is the handling of
vectors,
where a vector is a list of scalars.
Note that there is no meaningful notion of "row vector" vs "column vector"
for a list of scalars, nor is there any meaningful notion of
transpose---these objects are just vectors. So I can't make sense of
"transpose(v)" as an OpenSCAD operation on a vector, v. How would it
change?
Simply put, when you do matrixvector or vectormatrix operations, OpenSCAD
treats the vector as either a column or row as needed to make the operation
possible.
So in OpenSCAD, Mv = vtranspose(M). But if you want to transform a list
of points, then you have to pay attention to the orientation of the data,
so
M*[v1,v2,v3,v4,...] will fail because you have now organized the data as a
matrix of row vectors, whereas multiplying on the right (by the transpose)
will work: [v1,v2,v3,v4,...]transpose(M). And of course it would also
work to do Mtranspose([v1,v2,v3,v4,...]) but then the result would need to
be transposed again to get a list of points.
Ronaldo wrote
Mathematically, the product of a matrix by a row matrix is undefined
(except if the matrix has just one column) but in OpenSCAD, the vector is
considered a column vector instead of a row vector in the product of a
matrix by a vector. On the other hand, the product of a vector by a
matrix
in OpenSCAD has the same meaning it has in Mathematics. So, in
Mathematics,
the following holds for a row vector v and matrix M :
v * M = transpose(M)*transpose(v)
but in OpenSCAD we get an undefined vector in the evaluation of the right
expression.
--
Sent from: http://forum.openscad.org/
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
nophead wrote
Simply put, when you do matrixvector or vectormatrix operations,
OpenSCAD treats the vector as either a column or row as needed to make
the
operation possible.
No it doesn't. In conventional maths vector * transformation matrix the
vector is a column.
This is not true. There are two conventions. In my experience it's more
common to choose the convention of column vectors with transformation
operators represented by matrix multiplication on the left. But it is
entirely valid to choose the convention of row vectors and transformations
as matrices multiplying on the right, and some authors definitely make this
choice.
When you do it in OpenSCAD the result you get is what
it would be for a column vector if the matrix was transposed. That makes
the transformation matrix wrong for multmatrix, which expects it in
conventional format as you would see in Wikipedia, for example.
All the user land matrix maths I have seen for OpenSCAD works with
transposed transformations. I found that simply by post multiplying by the
vector you get the correct answer without having to transpose the matrix.
So I have rewritten my maths utilities with conventional transformation
matrices.
I have not studied a lot of OpenSCAD code, so I don't know what people tend
to do. I'm just observing what OpenSCAD itself does.
function transform(v, m) = vec3(m * [v.x, v.y, v.z, 1]);
function transform_points(path, m) = [for(p = path) transform(p, m)];
This makes far more sense to me as I can pass my matrices to multmatrix
without transposing them. Note that in my transform(v, m) I post multiply
by v whereas if OpenSCAD treated v as a column it should be
pre-multiplied.
I think if you transpose a row vector you would get a column vector.
In your transform(v,m) you have the matrix on the left and the vector on the
right, which means the vector is a column vector.
Can you transpose a row vector and get a column vector? Please show me. It
appears that I was not clear in my explanation of how OpenSCAD works.
At the risk of repeating myself here, it is necessary to distinguish between
operations that include a vector, meaning a list of scalars like [1,2,3] and
operations between matrices (lists of vectors), where a vector could appear
as [[1,2,3]], or alternatively as [[1],[2],[3]]. Really, please pay
attention to this distinction.
In the second situation there is no confusion. [[1,2,3]] is a row vector
and [[1],[2],[3]] is a column vector. The operations all behave as
expected. No problem. But I suspect you never created an object like
[[1],[2],[3]] in OpenSCAD. The way OpenSCAD is designed it is more natural
to use row vectors if you are going to work with objects like these. I
don't know why multmatrix() was chosen to use the column vector convention
when the rest of the design seems to be pointing towards row vectors.
But maybe you prefer to work with the first type of object, a vector like
[1,2,3] that is simply a list. Is this a row vector or a column vector?
Well, and this is important: there is no way to tell. You cannot
"transpose" it because what would the transposed object look like? How can
you "transpose" the list [1,2,3] into some other list that is still a vector
but not the same? You cannot. So the decision is arbitrary. A
mathematician would say you could tell by whether transformations operate on
the left or the right. But that doesn't work in this case because OpenSCAD
treats a list [1,2,3] as a column vector if you multiply on the left and a
row vector if you multiply on the right.
In other words, both Mv and vtranspose(M) are legal. Both compute the
same thing. In the former case v is a column vector and in the latter it is
a row vector.
I said above that row vectors are the natural way to use OpenSCAD. Consider
your transform_path function which you wrote as a loop that invokes
transform. I would be inclined to write this using a single matrix product
rather than a loop of matrix vector products like this:
function transform_path(path,m) = path*transpose(m);
This seems more elegant and I might imagine it would be faster on a long
path, though I haven't tested that code. Here path is an array of points
that are row vectors and we are applying the transformation on the right,
unfortunately with the obligatory transpose.
On Tue, 2 Apr 2019 at 18:25, adrianv <avm4@> wrote:
I experimented a bit with these operations and then I also read the
manual.
:) Matrix*matrix products work exactly as expected, when both matrices
are
lists of lists. What is perhaps a bit trickier is the handling of
vectors,
where a vector is a list of scalars.
Note that there is no meaningful notion of "row vector" vs "column vector"
for a list of scalars, nor is there any meaningful notion of
transpose---these objects are just vectors. So I can't make sense of
"transpose(v)" as an OpenSCAD operation on a vector, v. How would it
change?
Simply put, when you do matrixvector or vectormatrix operations,
OpenSCAD
treats the vector as either a column or row as needed to make the
operation
possible.
So in OpenSCAD, Mv = vtranspose(M). But if you want to transform a list
of points, then you have to pay attention to the orientation of the data,
so
M*[v1,v2,v3,v4,...] will fail because you have now organized the data as a
matrix of row vectors, whereas multiplying on the right (by the transpose)
will work: [v1,v2,v3,v4,...]transpose(M). And of course it would also
work to do Mtranspose([v1,v2,v3,v4,...]) but then the result would need
to
be transposed again to get a list of points.
Ronaldo wrote
Mathematically, the product of a matrix by a row matrix is undefined
(except if the matrix has just one column) but in OpenSCAD, the vector
is
considered a column vector instead of a row vector in the product of a
matrix by a vector. On the other hand, the product of a vector by a
matrix
in OpenSCAD has the same meaning it has in Mathematics. So, in
Mathematics,
the following holds for a row vector v and matrix M :
v * M = transpose(M)*transpose(v)
but in OpenSCAD we get an undefined vector in the evaluation of the
right
expression.
--
Sent from: http://forum.openscad.org/
OpenSCAD mailing list
Discuss@.openscad
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
OpenSCAD mailing list
Discuss@.openscad
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
--
Sent from: http://forum.openscad.org/
Thanks. Yes it was me that had it all wrong. It all makes sense now.
Can you transpose a row vector and get a column vector? Please show me.
It appears that I was not clear in my explanation of how OpenSCAD works.
I meant mathematically, or on paper. OpenSCAD doesn't have anyway of
differentiating singe dimensions vectors. As you say matrix multiplication
just picks the appropriate one, so the net result is it transposes m. I
think this is what led to my confusion.
If you use single row or column matrices then multiplication with a matrix
is only happy if the correct one is passed. It gives undef for a column on
the left or a row on the right and gives the correct form of output vector.
It is all explicit and clear but the results are single row or column
matrices, so not very useful. I don't think there is any distinction in
maths: one dimensional matrices are vectors. It is just computer science
where matrices are often lists of lists and vectors are just lists
I would be inclined to write this using a single matrix product rather than
a loop of matrix vector products like this:
function transform_path(path,m) = path*transpose(m);
Yes I think that might be quicker but it produces vec4s and polyhedron only
seems to accept vec3. Stripping the ones with a for loop after makes it
slower.
On Tue, 2 Apr 2019 at 23:31, adrianv avm4@cornell.edu wrote:
nophead wrote
Simply put, when you do matrixvector or vectormatrix operations,
OpenSCAD treats the vector as either a column or row as needed to make
the
operation possible.
No it doesn't. In conventional maths vector * transformation matrix the
vector is a column.
This is not true. There are two conventions. In my experience it's more
common to choose the convention of column vectors with transformation
operators represented by matrix multiplication on the left. But it is
entirely valid to choose the convention of row vectors and transformations
as matrices multiplying on the right, and some authors definitely make this
choice.
When you do it in OpenSCAD the result you get is what
it would be for a column vector if the matrix was transposed. That makes
the transformation matrix wrong for multmatrix, which expects it in
conventional format as you would see in Wikipedia, for example.
All the user land matrix maths I have seen for OpenSCAD works with
transposed transformations. I found that simply by post multiplying by
the
vector you get the correct answer without having to transpose the matrix.
So I have rewritten my maths utilities with conventional transformation
matrices.
I have not studied a lot of OpenSCAD code, so I don't know what people tend
to do. I'm just observing what OpenSCAD itself does.
function transform(v, m) = vec3(m * [v.x, v.y, v.z, 1]);
function transform_points(path, m) = [for(p = path) transform(p, m)];
This makes far more sense to me as I can pass my matrices to multmatrix
without transposing them. Note that in my transform(v, m) I post multiply
by v whereas if OpenSCAD treated v as a column it should be
pre-multiplied.
I think if you transpose a row vector you would get a column vector.
In your transform(v,m) you have the matrix on the left and the vector on
the
right, which means the vector is a column vector.
Can you transpose a row vector and get a column vector? Please show me.
It
appears that I was not clear in my explanation of how OpenSCAD works.
At the risk of repeating myself here, it is necessary to distinguish
between
operations that include a vector, meaning a list of scalars like [1,2,3]
and
operations between matrices (lists of vectors), where a vector could appear
as [[1,2,3]], or alternatively as [[1],[2],[3]]. Really, please pay
attention to this distinction.
In the second situation there is no confusion. [[1,2,3]] is a row vector
and [[1],[2],[3]] is a column vector. The operations all behave as
expected. No problem. But I suspect you never created an object like
[[1],[2],[3]] in OpenSCAD. The way OpenSCAD is designed it is more
natural
to use row vectors if you are going to work with objects like these. I
don't know why multmatrix() was chosen to use the column vector convention
when the rest of the design seems to be pointing towards row vectors.
But maybe you prefer to work with the first type of object, a vector like
[1,2,3] that is simply a list. Is this a row vector or a column vector?
Well, and this is important: there is no way to tell. You cannot
"transpose" it because what would the transposed object look like? How
can
you "transpose" the list [1,2,3] into some other list that is still a
vector
but not the same? You cannot. So the decision is arbitrary. A
mathematician would say you could tell by whether transformations operate
on
the left or the right. But that doesn't work in this case because OpenSCAD
treats a list [1,2,3] as a column vector if you multiply on the left and a
row vector if you multiply on the right.
In other words, both Mv and vtranspose(M) are legal. Both compute the
same thing. In the former case v is a column vector and in the latter it
is
a row vector.
I said above that row vectors are the natural way to use OpenSCAD.
Consider
your transform_path function which you wrote as a loop that invokes
transform. I would be inclined to write this using a single matrix product
rather than a loop of matrix vector products like this:
function transform_path(path,m) = path*transpose(m);
This seems more elegant and I might imagine it would be faster on a long
path, though I haven't tested that code. Here path is an array of points
that are row vectors and we are applying the transformation on the right,
unfortunately with the obligatory transpose.
On Tue, 2 Apr 2019 at 18:25, adrianv <avm4@> wrote:
I experimented a bit with these operations and then I also read the
manual.
:) Matrix*matrix products work exactly as expected, when both matrices
are
lists of lists. What is perhaps a bit trickier is the handling of
vectors,
where a vector is a list of scalars.
Note that there is no meaningful notion of "row vector" vs "column
vector"
for a list of scalars, nor is there any meaningful notion of
transpose---these objects are just vectors. So I can't make sense of
"transpose(v)" as an OpenSCAD operation on a vector, v. How would it
change?
Simply put, when you do matrixvector or vectormatrix operations,
OpenSCAD
treats the vector as either a column or row as needed to make the
operation
possible.
So in OpenSCAD, Mv = vtranspose(M). But if you want to transform a
list
of points, then you have to pay attention to the orientation of the data,
so
M*[v1,v2,v3,v4,...] will fail because you have now organized the data as
a
matrix of row vectors, whereas multiplying on the right (by the
transpose)
will work: [v1,v2,v3,v4,...]transpose(M). And of course it would also
work to do Mtranspose([v1,v2,v3,v4,...]) but then the result would need
to
be transposed again to get a list of points.
Ronaldo wrote
Mathematically, the product of a matrix by a row matrix is undefined
(except if the matrix has just one column) but in OpenSCAD, the vector
is
considered a column vector instead of a row vector in the product of a
matrix by a vector. On the other hand, the product of a vector by a
matrix
in OpenSCAD has the same meaning it has in Mathematics. So, in
Mathematics,
the following holds for a row vector v and matrix M :
v * M = transpose(M)*transpose(v)
but in OpenSCAD we get an undefined vector in the evaluation of the
right
expression.
--
Sent from: http://forum.openscad.org/
OpenSCAD mailing list
Discuss@.openscad
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
OpenSCAD mailing list
Discuss@.openscad
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
--
Sent from: http://forum.openscad.org/
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org