
12

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?
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


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?
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


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 < [hidden email]> escreveu:
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?
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


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.
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. 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 < [hidden email]> escreveu:
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?
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


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
transposethese 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 matrix*vector or vector*matrix operations, OpenSCAD
treats the vector as either a column or row as needed to make the operation
possible.
So in OpenSCAD, M*v = v*transpose(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 M*transpose([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
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


Simply put, when you do matrix*vector or vector*matrix 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 premultiplied.
I think if you transpose a row vector you would get a column vector. 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
transposethese 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 matrix*vector or vector*matrix operations, OpenSCAD
treats the vector as either a column or row as needed to make the operation
possible.
So in OpenSCAD, M*v = v*transpose(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 M*transpose([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
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
_______________________________________________
OpenSCAD mailing list
[hidden email]
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 rowmajor 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).
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 matrix*vector or vector*matrix 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 premultiplied.
I think if you transpose a row vector you would get a column vector.
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
transposethese 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 matrix*vector or vector*matrix operations, OpenSCAD
treats the vector as either a column or row as needed to make the operation
possible.
So in OpenSCAD, M*v = v*transpose(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 M*transpose([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.

_______________________________________________
OpenSCAD mailing list
_______________________________________________
OpenSCAD mailing list
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
_______________________________________________
OpenSCAD mailing list
[hidden email]
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. > 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":
quote: "(a×b) denotes a matrix with a rows and b columns".
In OpenSCAD, an a×b matrix is written in rowmajor 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).
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 matrix*vector or vector*matrix 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 premultiplied.
I think if you transpose a row vector you would get a column vector.
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
transposethese 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 matrix*vector or vector*matrix operations, OpenSCAD
treats the vector as either a column or row as needed to make the operation
possible.
So in OpenSCAD, M*v = v*transpose(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 M*transpose([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.

_______________________________________________
OpenSCAD mailing list
_______________________________________________
OpenSCAD mailing list
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


nophead wrote
>>
>> Simply put, when you do matrix*vector or vector*matrix 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
> premultiplied.
>
> 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 M*v and v*transpose(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
> transposethese 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 matrix*vector or vector*matrix operations,
> OpenSCAD
> treats the vector as either a column or row as needed to make the
> operation
> possible.
>
> So in OpenSCAD, M*v = v*transpose(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 M*transpose([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
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.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. nophead wrote
>>
>> Simply put, when you do matrix*vector or vector*matrix 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
> premultiplied.
>
> 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 M*v and v*transpose(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
> transposethese 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 matrix*vector or vector*matrix operations,
> OpenSCAD
> treats the vector as either a column or row as needed to make the
> operation
> possible.
>
> So in OpenSCAD, M*v = v*transpose(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 M*transpose([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
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


On Wed, Apr 03, 2019 at 11:22:54AM +0100, nop head wrote:
> 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
No. In math there is a difference between column vectors and
rowvectors. If you multiply a column vector with a row vector one way
and you get a matrix, multiply them the other way around, you get a
scalar.
It is computer science that cannot simply distiguish between the two:
a vector is a vector. As you say: you can make an Nx1 and an 1xN
matrices to show the difference.
Roger.

** [hidden email] ** https://www.BitWizard.nl/ ** +31152049110 **
** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 **
The plan was simple, like my brotherinlaw Phil. But unlike
Phil, this plan just might work.
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


I meant there are no 1xn or nx1 matrices in maths, they are just row or column vectors. On Wed, Apr 03, 2019 at 11:22:54AM +0100, nop head wrote:
> 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
No. In math there is a difference between column vectors and
rowvectors. If you multiply a column vector with a row vector one way
and you get a matrix, multiply them the other way around, you get a
scalar.
It is computer science that cannot simply distiguish between the two:
a vector is a vector. As you say: you can make an Nx1 and an 1xN
matrices to show the difference.
Roger.

** [hidden email] ** https://www.BitWizard.nl/ ** +31152049110 **
** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 **
The plan was simple, like my brotherinlaw Phil. But unlike
Phil, this plan just might work.
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


On Wed, Apr 03, 2019 at 11:48:44AM +0100, nop head wrote:
> I meant there are no 1xn or nx1 matrices in maths, they are just row or
> column vectors.
Oh, ok. I think in maths a 1xN or Nx1 matrix is precisely equivalent
to the corresponding vector.
Everything is a matrix, what is commonly known as a vector is a matrix
with one dimension "1". What is commonly known as a "scalar" is a
matrix with both dimensions "1"....
Roger.

** [hidden email] ** https://www.BitWizard.nl/ ** +31152049110 **
** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 **
The plan was simple, like my brotherinlaw Phil. But unlike
Phil, this plan just might work.
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


It is... er... matter of definitions.
If scalar was 1x1 matrix you could not multiply MxN matrix by scalar.
On 4/3/2019 1:53 PM, Rogier Wolff wrote:
> On Wed, Apr 03, 2019 at 11:48:44AM +0100, nop head wrote:
>> I meant there are no 1xn or nx1 matrices in maths, they are just row or
>> column vectors.
>
> Oh, ok. I think in maths a 1xN or Nx1 matrix is precisely equivalent
> to the corresponding vector.
>
> Everything is a matrix, what is commonly known as a vector is a matrix
> with one dimension "1". What is commonly known as a "scalar" is a
> matrix with both dimensions "1"....
>
> Roger.
>
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


Let me try to summarize this discussion regarding OpenSCAD codes:
a) matrices in OpenSCAD are list of lists of scalars; simple vectors (list of scalars) are not matrices; b) as such, vectors can't be transposed like matrices; c) in products v*M, where v is a vector and M an appropriate matrix, v may be regarded as a row matrix; d) in products M*v, v may be regarded as a column matrix; e) v*M == T(M)*v and v*T(M) == M*v where T is the transpose operator; f) v*w is a scalar when v and w are vectors of same dimension. g) the product of a matrix 1xn by a matrix nXm is a matrix 1xm which is not a mdimensional vector; h) T(Q*R) = T(R)*T(Q) for any matrix Q nXm and matrix R mXk where T is the transpose operator.
So, OpenSCAD matrix multiplications agree the mathematical equivalent. The differences between math and OpenSCAD are just the a), b) and d) above.
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


True but in maths a "row vector" and a "row matrix" are alternative names for the exactly same thing, similarly with column vector and column matrix. In OpenSCAD they are different things. So you can pass an actual row matrix as the first operand of a multiplication by a matrix and receive a row matrix back, or you can pass a vector that will be treated as a row vector and get a vector back. So using "row matrix" and column matrix" in c) and d) could be a little confusing. Let me try to summarize this discussion regarding OpenSCAD codes:
a) matrices in OpenSCAD are list of lists of scalars; simple vectors (list of scalars) are not matrices; b) as such, vectors can't be transposed like matrices; c) in products v*M, where v is a vector and M an appropriate matrix, v may be regarded as a row matrix; d) in products M*v, v may be regarded as a column matrix; e) v*M == T(M)*v and v*T(M) == M*v where T is the transpose operator; f) v*w is a scalar when v and w are vectors of same dimension. g) the product of a matrix 1xn by a matrix nXm is a matrix 1xm which is not a mdimensional vector; h) T(Q*R) = T(R)*T(Q) for any matrix Q nXm and matrix R mXk where T is the transpose operator.
So, OpenSCAD matrix multiplications agree the mathematical equivalent. The differences between math and OpenSCAD are just the a), b) and d) above.
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


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.
Striping the ones may be avoided if the matrices are 3x4. The operator multmatrix() ignores the last row and accepts 3x4 matrices so if you drop the last row of your matrices, multmatrix() will work as expected. However, to apply a 3x4 matrix to a list of 4D points, we will need to transpose the matrix:
[for(i=[0:len(p)1]) p[i]] * transpose(M)
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


Ronaldo wrote
> nop head <
> nop.head@
> > wrote:
>
>> 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.
>>
>
> Striping the ones may be avoided if the matrices are 3x4. The operator
> multmatrix() ignores the last row and accepts 3x4 matrices so if you drop
> the last row of your matrices, multmatrix() will work as expected.
> However,
> to apply a 3x4 matrix to a list of 4D points, we will need to transpose
> the
> matrix:
>
> [for(i=[0:len(p)1]) p[i]] * transpose(M)
Wouldn't simply
p*transpose(M)
be better, where M is 3x4?

Sent from: http://forum.openscad.org/_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

12
