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);– cjorssen May 02 '13 at 22:41.asyfiles and not included in the body of a.texfile as the MWE would suggest. – Scott H. May 03 '13 at 01:38write(q);differs fromreal[] x ={1,2,3}; write(x);– Scott H. May 03 '13 at 04:51triplescan be multiplied byrealsdirectly. Are you sure that you need this conversion at all? – g.kov May 03 '13 at 08:55Transform3is really an alias for a 4x4 transformation matrix (it's defined inplain_prethree.asy). So extend your (I assume) 3x3 matrix to a 4x4 matrix by putting a 1 in the new diagonal entry and 0s in all the other new entries. Call the new 4x4 matrixTand your triplex. Then you should simply be able to writeT*x. – Charles Staats May 03 '13 at 15:29