This answer addresses your underlying goal of applying a transformation matrix to a triple, rather than your specific question.
First of all, here is a method that converts a linear map specified by a real 3x3 matrix to a transform3
:
transform3 linMapToTransform3(real[][] matrix) {
transform3 T = copy(matrix); // Produce a deep copy, so that the changes below won't affect the original matrix.
T[0].push(0); // Append a zero to the first row.
T[1].push(0); // Append a zero to the second row.
T[2].push(0); // Append a zero to the third row.
T.push(new real[]{0,0,0,1}); // Add a fourth row, which looks like {0,0,0,1}.
return T;
}
An file that tests the function above to make sure it works as expected (and, incidentally, illustrates conversion both ways between a triple and an array; see the fourth-from-last line of code):
import three; // Required for the type triple
// The function we want to test
transform3 linMapToTransform3(real[][] matrix) {
transform3 T = copy(matrix); // Produce a deep copy, so that the changes below won't affect the original matrix.
T[0].push(0); // Append a zero to the first row.
T[1].push(0); // Append a zero to the second row.
T[2].push(0); // Append a zero to the third row.
T.push(new real[]{0,0,0,1}); // Add a fourth row, which looks like {0,0,0,1}.
return T;
}
// Define matrix multiplication
real[] operator *(real[][] T, real[] v) {
real[] toReturn = array(n=v.length, value=0);
for (int i = 0; i < T.length; ++i) {
for (int j = 0; j < v.length; ++j) {
toReturn[i] += T[i][j] * v[j];
}
}
return toReturn;
}
real[][] linTransform = new real[3][3]; // Initialize a 3x3 matrix
for (int i = 0; i < linTransform.length; ++i)
for (int j = 0; j < linTransform[i].length; ++j)
linTransform[i][j] = unitrand(); // Initialize each entry to a random number between 0 and 1
triple v = (unitrand(), unitrand(), unitrand()); //Initialize a vector to multiply by
real[] vec = new real[]{v.x, v.y, v.z}; //Convert the triple v to an array vdc
real[] product1 = linTransform * vec; //Product obtained by matrix multiplication
triple product2 = linMapToTransform3(linTransform) * v; //Convert the linear map to a transform3 and apply it to the triple v
assert(product2 == (product1[0], product1[1], product1[2])); // If the two products do not represent the same thing, stop execution and display an error.
In Asymptote, one can often make this sort of thing automatic by defining a cast operator to convert one object to another that fits. Unfortunately, this is not possible here because transform3
is really just an alias for a two-dimensional real array as explained below, so you'd be trying to cast from real[][]
to real[][]
, which does not work.
Explanation:
There are a number of modules included in the plain
module, which is loaded every time Asymptote is run. Among these modules are plain_prethree
(it's included by plain_picture.asy
, which is included by plain.asy
).
The second line of code in the file plain_prethree.asy
is
typedef real[][] transform3;
The typedef
command in Asymptote is similar to \def
or \let
in TeX (but with the arguments in the opposite order). Thus, this line of code essentially defines the type transform3
as an alias for real[][]
, i.e., a two-dimensional array of real numbers. Testing and further consulting the source code reveals that in fact a transform3
is always expected to be a 4x4 matrix; if T
is the transform3 specified by the matrix
{{a, b, c, d},
{e, f, g, h},
{i, j, k, l},
{0, 0, 0, 1}}
and v
is a triple
, then T*v
is the triple obtained by multiplying this matrix on the right by the vertical vector {v.x, v.y, v.z, 1}
and then dropping the last entry (which is necessarily 1
). In other words, T*v
is the triple
(a*v.x + b*v.y + c*v.z + d,
e*v.x + f*v.y + g*v.z + h,
i*v.x + j*v.y + k*v.z + l)
real[][] q = new real[3][10]; triple v=(1,2,3); void toarray(triple t, real[][] a, int i){ a[0][i] = t.x; a[1][i] = t.y; a[2][i] = t.z; } toarray(v,q,0); real[][] q2 = new real[3][]; void pushtoarray(triple t, real[][] a){ a[0].push(t.x); a[1].push(t.y); a[2].push(t.z); } pushtoarray(v,q2); pushtoarray(v + (2,4,6),q2); write(q2);
.asy
files and not included in the body of a.tex
file as the MWE would suggest.write(q);
differs fromreal[] x ={1,2,3}; write(x);