渐近线:将三元组转换为数组

渐近线:将三元组转换为数组

我如何将三个实数组成的三元组转换为数组,或者以其他方式将其视为数组。我可以从数组转换为三元组,如下所示:

\documentclass{article}
\usepackage{graphicx}
\usepackage{asymptote}
\begin{document}
\begin{asy}
  triple[] p;
  real[] b={1,2,3};

  triple totriple(real[] x, int i){
     return p[i] = (x[0],x[1],x[2]);
  }

  totriple(b,1);
  write(p[1]);
\end{asy}
\end{document}

但另一个方向却让我困惑,我尝试了一下:

real[][] q;
triple v=(1,2,3);

real[] toarray(triple t, int i){
    return q[1]={t.x,t.y,t.z};
}

目标是可视化三维中的线性变换。我有一些三元组定义三维空间中对象的边界,我想将它们转换为数组(以便我可以乘以变换矩阵),然后再转换为三元组进行绘图。我可能错过了 Asymptote 中一些可以开箱即用地完成此操作的功能,或者其他更好的方法,因此欢迎提出任何建议。希望这是主题。

答案1

虽然显式函数当然是一种直接且可移植的方式,但它Asymptote提供了一种扩展机制来将一种类型转换为另一种类型,从而使转换自动化且干净利落:

triple operator cast(real[] r){
  real[] t={0,0,0};
  for(int i=0;i<min(r.length,3);++i)t[i]=r[i];
  return (t[0],t[1],t[2]);
}

real[] operator cast(triple tv){
  return new real[]{tv.x,tv.y,tv.z};
}

triple[] p;
real[] b={1,2,3};

p[0]=new real[]{};
p[1]=new real[]{100};
p[2]=new real[]{100,200};
p[3]=new real[]{100,200,300};
p[4]=new real[]{100,200,300,400,500};

p[6]=b;

write("p=",p);

triple t=(9,8,7);

b[3:]=t;

write("b=",b);

输出为:

p=
0:      (0,0,0)
1:      (100,0,0)
2:      (100,200,0)
3:      (100,200,300)
4:      (100,200,300)
5:
6:      (1,2,3)
b=
0:      1
1:      2
2:      3
3:      9
4:      8
5:      7

答案2

我提供了两个函数来完成这项工作。第一个函数toarray需要在调用之前确定数组的大小,并知道要将数据放在哪个索引处(记住asymptote,索引从 开始0)。第二个函数pushtoarray将三元组的内容添加到数组的末尾(动态调整其大小)。

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);
write(q)

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);

答案3

这个答案解决了将变换矩阵应用于三元组的根本目标,而不是您的具体问题。

首先,这里有一个将实数 3x3 矩阵指定的线性映射转换为的方法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;
}

测试上述函数的文件,以确保它按预期工作(并且顺便说明三元组和数组之间的双向转换;请参阅倒数第四行代码):

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.

在 Asymptote 中,通常可以通过定义转换运算符将一个对象转换为另一个合适的对象来自动完成此类操作。不幸的是,这在这里是不可能的,因为transform3实际上只是二维实数数组的别名(如下所述),因此您会尝试从 转换为real[][]real[][]但这行不通。


解释: 模块中包含许多模块plain,每次运行 Asymptote 时都会加载该模块。这些模块包括plain_prethree(它包含在 中plain_picture.asy,它包含在 中plain.asy)。

文件中的第二行代码plain_prethree.asy

typedef real[][] transform3;

Asymptote 中的命令typedef类似于TeX 中的\def\let(但参数顺序相反)。因此,这行代码本质上将类型定义transform3为的别名real[][],即实数的二维数组。测试并进一步查阅源代码表明,事实上 atransform3始终是 4x4 矩阵;如果T是矩阵指定的变换 3

{{a, b, c, d},
{e, f, g, h},
{i, j, k, l},
{0, 0, 0, 1}}

并且vtriple,那么T*v就是将右边的这个矩阵乘以垂直向量{v.x, v.y, v.z, 1},然后去掉最后一个元素(必然是1)得到的三元组。换句话说,T*v就是三元组

(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)

相关内容