discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Matrix multiplication and row vectors

NH
nop head
Mon, Apr 1, 2019 1:28 PM

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 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?
NH
nop head
Mon, Apr 1, 2019 1:32 PM

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?

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? >
RP
Ronaldo Persiano
Mon, Apr 1, 2019 3:14 PM

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?

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? >> > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
NH
nop head
Mon, Apr 1, 2019 6:13 PM

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?

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? >>> >> _______________________________________________ >> 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 >
A
adrianv
Tue, Apr 2, 2019 5:24 PM

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 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.

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 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/
NH
nop head
Tue, Apr 2, 2019 7:39 PM

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 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.

> > 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 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 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@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
DM
Doug Moen
Tue, Apr 2, 2019 9:30 PM

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 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.

> 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 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 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 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@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 >
NH
nop head
Tue, Apr 2, 2019 10:16 PM

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 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.

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 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 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 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@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 >
A
adrianv
Tue, Apr 2, 2019 10:31 PM

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 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.

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 > 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 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 &lt;avm4@&gt; 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 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/
NH
nop head
Wed, Apr 3, 2019 10:22 AM

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 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.

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 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 > > 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 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 &lt;avm4@&gt; 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 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 > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >