```//  Array a
//  double t
function wNewRotateXY (a, t) {
let c = cos (t), s = sin (t);  //double
let ax = a[0], ay = a[1];  //double
return [c * ax - s * ay,
s * ax + c * ay,
a[2]];
}

//------------------------------------------------------------------------
//rotateYZ 回転(+y→+z)
//
//    [1    0      0    0]   [x]   [        x        ]
//    [0 cos(t) -sin(t) 0] * [y] = [cos(t)*y-sin(t)*z]
//    [0 sin(t)  cos(t) 0]   [z]   [sin(t)*y+cos(t)*z]
//    [0    0      0    1]   [1]   [        1        ]
//

//a = wRotateYZ (a, t)
//  Array a
//  double t
function wRotateYZ (a, t) {
let c = cos (t), s = sin (t);  //double
let ay = a[1], az = a[2];  //double
a[1] = c * ay - s * az;
a[2] = s * ay + c * az;
return a;
}

//o = wLetRotateYZ (o, a, t)
//  Array o
//  Array a
//  double t
function wLetRotateYZ (o, a, t) {
let c = cos (t), s = sin (t);  //double
let ay = a[1], az = a[2];  //double
o[0] = a[0];
o[1] = c * ay - s * az;
o[2] = s * ay + c * az;
return o;
}

//o = wNewRotateYZ (a, t)
//  Array o
//  Array a
//  double t
function wNewRotateYZ (a, t) {
let c = cos (t), s = sin (t);  //double
let ay = a[1], az = a[2];  //double
return [a[0],
c * ay - s * az,
s * ay + c * az];
}

//------------------------------------------------------------------------
//rotateZX 回転(+z→+x)
//
//    [ cos(t) 0 sin(t) 0]   [x]   [sin(t)*z+cos(t)*x]
//    [   0    1   0    0] * [y] = [        y        ]
//    [-sin(t) 0 cos(t) 0]   [z]   [cos(t)*z-sin(t)*x]
//    [   0    0   0    1]   [1]   [        1        ]
//

//a = wRotateZX (a, t)
//  Array a
//  double t
function wRotateZX (a, t) {
let c = cos (t), s = sin (t);  //double
let ax = a[0], az = a[2];  //double
a[0] = s * az + c * ax;
a[2] = c * az - s * ax;
return a;
}

//o = wLetRotateZX (o, a, t)
//  Array o
//  Array a
//  double t
function wLetRotateZX (o, a, t) {
let c = cos (t), s = sin (t);  //double
let ax = a[0], az = a[2];  //double
o[0] = s * az + c * ax;
o[1] = a[1];
o[2] = c * az - s * ax;
return o;
}

//o = wNewRotateZX (a, t)
//  Array o
//  Array a
//  double t
function wNewRotateZX (a, t) {
let c = cos (t), s = sin (t);  //double
let ax = a[0], az = a[2];  //double
return [s * az + c * ax,
a[1],
c * az - s * ax];
}

//------------------------------------------------------------------------
//scalar スカラーベクトル
//  s

//o = wLetScalarX (o, s)
//  Array o
//  double s
function wLetScalarX (o, s) {
o[0] = s;
o[1] = 0;
o[2] = 0;
return o;
}

//o = wNewScalarX (s)
//  Array o
//  double s
function wNewScalarX (s) {
return [s,
0,
0];
}

//o = wLetScalarY (o, s)
//  Array o
//  double s
function wLetScalarY (o, s) {
o[0] = 0;
o[1] = s;
o[2] = 0;
return o;
}

//o = wNewScalarY (s)
//  Array o
//  double s
function wNewScalarY (s) {
return [0,
s,
0];
}

//o = wLetScalarZ (o, s)
//  Array o
//  double s
function wLetScalarZ (o, s) {
o[0] = 0;
o[1] = 0;
o[2] = s;
return o;
}

//o = wNewScalarZ (s)
//  Array o
//  double s
function wNewScalarZ (s) {
return [0,
0,
s];
}

//------------------------------------------------------------------------
//scale 拡大縮小
//
//    [p 0 0 0]   [x]   [p*x]
//    [0 q 0 0] * [y] = [q*y]
//    [0 0 r 0]   [z]   [r*z]
//    [0 0 0 1]   [1]   [ 1 ]
//
//  s*a

//a = wScaleS (a, s)
//  Array a
//  double s
function wScaleS (a, s) {
a[0] *= s;
a[1] *= s;
a[2] *= s;
return a;
}

//o = wLetScaleS (o, a, s)
//  Array o
//  Array a
//  double s
function wLetScaleS (o, a, s) {
o[0] = a[0] * s;
o[1] = a[1] * s;
o[2] = a[2] * s;
return o;
}

//o = wNewScaleS (a, s)
//  Array o
//  Array a
//  double s
function wNewScaleS (a, s) {
return [a[0] * s,
a[1] * s,
a[2] * s];
}

//a = wScaleW (a, w)
//  Array a
//  Array w
function wScaleW (a, w) {
a[0] *= w[0];
a[1] *= w[1];
a[2] *= w[2];
return a;
}

//o = wLetScaleW (o, a, w)
//  Array o
//  Array a
//  Array w
function wLetScaleW (o, a, w) {
o[0] = a[0] * w[0];
o[1] = a[1] * w[1];
o[2] = a[2] * w[2];
return o;
}

//o = wNewScaleW (a, w)
//  Array o
//  Array a
//  Array w
function wNewScaleW (a, w) {
return [a[0] * w[0],
a[1] * w[1],
a[2] * w[2]];
}

//a = wScaleX (a, p)
//  Array a
//  double p
function wScaleX (a, p) {
a[0] *= p;
return a;
}

//o = wLetScaleX (o, a, p)
//  Array o
//  Array a
//  double p
function wLetScaleX (o, a, p) {
o[0] = a[0] * p;
o[1] = a[1];
o[2] = a[2];
return o;
}

//o = wNewScaleX (a, p)
//  Array o
//  Array a
//  double p
function wNewScaleX (a, p) {
return [a[0] * p,
a[1],
a[2]];
}

//a = wScaleY (a, q)
//  Array a
//  double q
function wScaleY (a, q) {
a[1] *= q;
return a;
}

//o = wLetScaleY (o, a, q)
//  Array o
//  Array a
//  double q
function wLetScaleY (o, a, q) {
o[0] = a[0];
o[1] = a[1] * q;
o[2] = a[2];
return o;
}

//o = wNewScaleY (a, q)
//  Array o
//  Array a
//  double q
function wNewScaleY (a, q) {
return [a[0],
a[1] * q,
a[2]];
}

//a = wScaleZ (a, r)
//  Array a
//  double r
function wScaleZ (a, r) {
a[2] *= r;
return a;
}

//o = wLetScaleZ (o, a, r)
//  Array o
//  Array a
//  double r
function wLetScaleZ (o, a, r) {
o[0] = a[0];
o[1] = a[1];
o[2] = a[2] * r;
return o;
}

//o = wNewScaleZ (a, r)
//  Array o
//  Array a
//  double r
function wNewScaleZ (a, r) {
return [a[0],
a[1],
a[2] * r];
}

//a = wScaleXYZ (a, p, q, r)
//  Array a
//  double p
//  double q
//  double r
function wScaleXYZ (a, p, q, r) {
a[0] *= p;
a[1] *= q;
a[2] *= r;
return a;
}

//o = wLetScaleXYZ (o, a, p, q, r)
//  Array o
//  Array a
//  double p
//  double q
//  double r
function wLetScaleXYZ (o, a, p, q, r) {
o[0] = a[0] * p;
o[1] = a[1] * q;
o[2] = a[2] * r;
return o;
}

//o = wNewScaleXYZ (a, p, q, r)
//  Array o
//  Array a
//  double p
//  double q
//  double r
function wNewScaleXYZ (a, p, q, r) {
return [a[0] * p,
a[1] * q,
a[2] * r];
}

//------------------------------------------------------------------------
//stretch 長さ(ノルム)変更
//  hat(a)*(|a|*s+t)=a/|a|*(|a|*s+t)=a*(s+t/|a|)
//  ゼロベクトルは不可

//a = wStretch (a, s, t)
//  Array a
//  double s
//  double t
function wStretch (a, s, t) {
let ax = a[0], ay = a[1], az = a[2];  //double
s += t / hypot3 (ax, ay, az);
a[0] = ax * s;
a[1] = ay * s;
a[2] = az * s;
return a;
}

//o = wLetStretch (o, a, s, t)
//  Array o
//  Array a
//  double s
//  double t
function wLetStretch (o, a, s, t) {
let ax = a[0], ay = a[1], az = a[2];  //double
s += t / hypot3 (ax, ay, az);
o[0] = ax * s;
o[1] = ay * s;
o[2] = az * s;
return o;
}

//o = wNewStretch (a, s, t)
//  Array o
//  Array a
//  double s
//  double t
function wNewStretch (a, s, t) {
let ax = a[0], ay = a[1], az = a[2];  //double
s += t / hypot3 (ax, ay, az);
return [ax * s,
ay * s,
az * s];
}

//------------------------------------------------------------------------
//stretch from 距離変更
//  hat(a-b)*(|a-b|*s+t)+b=(a-b)/|a-b|*(|a-b|*s+t)+b=(a-b)*(s+t/|a-b|)+b
//  a==bは不可

//a = wStretchFrom (a, s, t, b)
//  Array a
//  double s
//  double t
//  Array b
function wStretchFrom (a, s, t, b) {
let ax = a[0], ay = a[1], az = a[2];  //double
let bx = b[0], by = b[1], bz = b[2];  //double
ax -= bx;
ay -= by;
az -= bz;
s += t / hypot3 (ax, ay, az);
a[0] = ax * s + bx;
a[1] = ay * s + by;
a[2] = az * s + bz;
return a;
}

//o = wLetStretchFrom (o, a, s, t, b)
//  Array o
//  Array a
//  double s
//  double t
//  Array b
function wLetStretchFrom (o, a, s, t, b) {
let ax = a[0], ay = a[1], az = a[2];  //double
let bx = b[0], by = b[1], bz = b[2];  //double
ax -= bx;
ay -= by;
az -= bz;
s += t / hypot3 (ax, ay, az);
o[0] = ax * s + bx;
o[1] = ay * s + by;
o[2] = az * s + bz;
return o;
}

//o = wNewStretchFrom (a, s, t, b)
//  Array o
//  Array a
//  double s
//  double t
//  Array b
function wNewStretchFrom (a, s, t, b) {
let ax = a[0], ay = a[1], az = a[2];  //double
let bx = b[0], by = b[1], bz = b[2];  //double
ax -= bx;
ay -= by;
az -= bz;
s += t / hypot3 (ax, ay, az);
return [ax * s + bx,
ay * s + by,
az * s + bz];
}

//------------------------------------------------------------------------
//subtract 減算
//
//    [1 0 0 -d]   [x]   [x-d]
//    [0 1 0 -e] * [y] = [y-e]
//    [0 0 1 -f]   [z]   [z-f]
//    [0 0 0  1]   [1]   [ 1 ]
//
//  a-b

//a = wSubtractW (a, b)
//  Array a
//  Array b
function wSubtractW (a, b) {
a[0] -= b[0];
a[1] -= b[1];
a[2] -= b[2];
return a;
}

//o = wLetSubtractW (o, a, b)
//  Array o
//  Array a
//  Array b
function wLetSubtractW (o, a, b) {
o[0] = a[0] - b[0];
o[1] = a[1] - b[1];
o[2] = a[2] - b[2];
return o;
}

//o = wNewSubtractW (a, b)
//  Array o
//  Array a
//  Array b
function wNewSubtractW (a, b) {
return [a[0] - b[0],
a[1] - b[1],
a[2] - b[2]];
}

//a = wSubtractX (a, d)
//  Array a
//  double d
function wSubtractX (a, d) {
a[0] -= d;
return a;
}

//o = wLetSubtractX (o, a, d)
//  Array o
//  Array a
//  double d
function wLetSubtractX (o, a, d) {
o[0] = a[0] - d;
o[1] = a[1];
o[2] = a[2];
return o;
}

//o = wNewSubtractX (a, d)
//  Array o
//  Array a
//  double d
function wNewSubtractX (a, d) {
return [a[0] - d,
a[1],
a[2]];
}

//a = wSubtractY (a, e)
//  Array a
//  double e
function wSubtractY (a, e) {
a[1] -= e;
return a;
}

//o = wLetSubtractY (o, a, e)
//  Array o
//  Array a
//  double e
function wLetSubtractY (o, a, e) {
o[0] = a[0];
o[1] = a[1] - e;
o[2] = a[2];
return o;
}

//o = wNewSubtractY (a, e)
//  Array o
//  Array a
//  double e
function wNewSubtractY (a, e) {
return [a[0],
a[1] - e,
a[2]];
}

//a = wSubtractZ (a, f)
//  Array a
//  double f
function wSubtractZ (a, f) {
a[2] -= f;
return a;
}

//o = wLetSubtractZ (o, a, f)
//  Array o
//  Array a
//  double f
function wLetSubtractZ (o, a, f) {
o[0] = a[0];
o[1] = a[1];
o[2] = a[2] - f;
return o;
}

//o = wNewSubtractZ (a, f)
//  Array o
//  Array a
//  double f
function wNewSubtractZ (a, f) {
return [a[0],
a[1],
a[2] - f];
}

//a = wSubtractXYZ (a, d, e, f)
//  Array a
//  double d
//  double e
//  double f
function wSubtractXYZ (a, d, e, f) {
a[0] -= d;
a[1] -= e;
a[2] -= f;
return a;
}

//o = wLetSubtractXYZ (o, a, d, e, f)
//  Array o
//  Array a
//  double d
//  double e
//  double f
function wLetSubtractXYZ (o, a, d, e, f) {
o[0] = a[0] - d;
o[1] = a[1] - e;
o[2] = a[2] - f;
return o;
}

//o = wNewSubtractXYZ (a, d, e, f)
//  Array o
//  Array a
//  double d
//  double e
//  double f
function wNewSubtractXYZ (a, d, e, f) {
return [a[0] - d,
a[1] - e,
a[2] - f];
}

//------------------------------------------------------------------------
//transform 変換
//
//    [n11 n12 n13 n14]   [x]   [n11*x+n12*y+n13*z+n14]
//    [n21 n22 n23 n24] * [y] = [n21*x+n22*y+n23*z+n24]
//    [n31 n32 n33 n34]   [z]   [n31*x+n32*y+n33*z+n34]
//    [ 0   0   0   1 ]   [1]   [          1          ]
//
//  n*a
//  引数の順序に注意

//a = wTransform (a, n)
//  Array a
//  Array n
function wTransform (a, n) {
let ax = a[0], ay = a[1], az = a[2];  //double
a[0] = n[0] * ax + n[1] * ay + n[ 2] * az + n[ 3];
a[1] = n[4] * ax + n[5] * ay + n[ 6] * az + n[ 7];
a[2] = n[8] * ax + n[9] * ay + n[10] * az + n[11];
return a;
}

//o = wLetTransform (o, a, n)
//  Array o
//  Array a
//  Array n
function wLetTransform (o, a, n) {
let ax = a[0], ay = a[1], az = a[2];  //double
o[0] = n[0] * ax + n[1] * ay + n[ 2] * az + n[ 3];
o[1] = n[4] * ax + n[5] * ay + n[ 6] * az + n[ 7];
o[2] = n[8] * ax + n[9] * ay + n[10] * az + n[11];
return o;
}

//o = wNewTransform (a, n)
//  Array o
//  Array a
//  Array n
function wNewTransform (a, n) {
let ax = a[0], ay = a[1], az = a[2];  //double
return [n[0] * ax + n[1] * ay + n[ 2] * az + n[ 3],
n[4] * ax + n[5] * ay + n[ 6] * az + n[ 7],
n[8] * ax + n[9] * ay + n[10] * az + n[11]];
}

//------------------------------------------------------------------------
//translate 平行移動
//
//    [1 0 0 d]   [x]   [x+d]
//    [0 1 0 e] * [y] = [y+e]
//    [0 0 1 f]   [z]   [z+f]
//    [0 0 0 1]   [1]   [ 1 ]
//
//  a+b

//a = wTranslateW (a, b)
//  Array a
//  Array b
function wTranslateW (a, b) {
a[0] += b[0];
a[1] += b[1];
a[2] += b[2];
return a;
}

//o = wLetTranslateW (o, a, b)
//  Array o
//  Array a
//  Array b
function wLetTranslateW (o, a, b) {
o[0] = a[0] + b[0];
o[1] = a[1] + b[1];
o[2] = a[2] + b[2];
return o;
}

//o = wNewTranslateW (a, b)
//  Array o
//  Array a
//  Array b
function wNewTranslateW (a, b) {
return [a[0] + b[0],
a[1] + b[1],
a[2] + b[2]];
}

//a = wTranslateX (a, d)
//  Array a
//  double d
function wTranslateX (a, d) {
a[0] += d;
return a;
}

//o = wLetTranslateX (o, a, d)
//  Array o
//  Array a
//  double d
function wLetTranslateX (o, a, d) {
o[0] = a[0] + d;
o[1] = a[1];
o[2] = a[2];
return o;
}

//o = wNewTranslateX (a, d)
//  Array o
//  Array a
//  double d
function wNewTranslateX (a, d) {
return [a[0] + d,
a[1],
a[2]];
}

//a = wTranslateY (a, e)
//  Array a
//  double e
function wTranslateY (a, e) {
a[1] += e;
return a;
}

//o = wLetTranslateY (o, a, e)
//  Array o
//  Array a
//  double e
function wLetTranslateY (o, a, e) {
o[0] = a[0];
o[1] = a[1] + e;
o[2] = a[2];
return o;
}

//o = wNewTranslateY (a, e)
//  Array o
//  Array a
//  double e
function wNewTranslateY (a, e) {
return [a[0],
a[1] + e,
a[2]];
}

//a = wTranslateZ (a, f)
//  Array a
//  double f
function wTranslateZ (a, f) {
a[2] += f;
return a;
}

//o = wLetTranslateZ (o, a, f)
//  Array o
//  Array a
//  double f
function wLetTranslateZ (o, a, f) {
o[0] = a[0];
o[1] = a[1];
o[2] = a[2] + f;
return o;
}

//o = wNewTranslateZ (a, f)
//  Array o
//  Array a
//  double f
function wNewTranslateZ (a, f) {
return [a[0],
a[1],
a[2] + f];
}

//a = wTranslateXYZ (a, d, e, f)
//  Array a
//  double d
//  double e
//  double f
function wTranslateXYZ (a, d, e, f) {
a[0] += d;
a[1] += e;
a[2] += f;
return a;
}

//o = wLetTranslateXYZ (o, a, d, e, f)
//  Array o
//  Array a
//  double d
//  double e
//  double f
function wLetTranslateXYZ (o, a, d, e, f) {
o[0] = a[0] + d;
o[1] = a[1] + e;
o[2] = a[2] + f;
return o;
}

//o = wNewTranslateXYZ (a, d, e, f)
//  Array o
//  Array a
//  double d
//  double e
//  double f
function wNewTranslateXYZ (a, d, e, f) {
return [a[0] + d,
a[1] + e,
a[2] + f];
}

//------------------------------------------------------------------------
//trisect 3分割
//  2/3*a+1/3*b

//a = wTrisect (a, b)
//  Array a
//  Array b
function wTrisect (a, b) {
a[0] = TWO_3 * a[0] + ONE_3 * b[0];
a[1] = TWO_3 * a[1] + ONE_3 * b[1];
a[2] = TWO_3 * a[2] + ONE_3 * b[2];
return a;
}

//o = wLetTrisect (o, a, b)
//  Array o
//  Array a
//  Array b
function wLetTrisect (o, a, b) {
o[0] = TWO_3 * a[0] + ONE_3 * b[0];
o[1] = TWO_3 * a[1] + ONE_3 * b[1];
o[2] = TWO_3 * a[2] + ONE_3 * b[2];
return o;
}

//o = wNewTrisect (a, b)
//  Array o
//  Array a
//  Array b
function wNewTrisect (a, b) {
return [TWO_3 * a[0] + ONE_3 * b[0],
TWO_3 * a[1] + ONE_3 * b[1],
TWO_3 * a[2] + ONE_3 * b[2]];
}

//------------------------------------------------------------------------
//zero 0ベクトル
//  0

//o = wLetZero (o)
//  Array o
function wLetZero (o) {
o[0] = 0;
o[1] = 0;
o[2] = 0;
return o;
}

//o = wNewZero ()
//  Array o
function wNewZero () {
return [0,
0,
0];
}

//========================================================================
//平面アフィン変換(m～)
//
//    [m11 m12 m13]   [m[0] m[1] m[2]]
//    [m21 m22 m23] = [m[3] m[4] m[5]]
//    [ 0   0   1 ]   [  0    0    1 ]
//
//    [m11 m12 m13]   [x]   [m11*x+m12*y+m13]
//    [m21 m22 m23] * [y] = [m21*x+m22*y+m23]
//    [ 0   0   1 ]   [1]   [       1       ]
//
//    要素の順序がSVGのtransformと異なることに注意
//    SVGのtransformの順序はm11,m21,m12,m22,m13,m23
//

//------------------------------------------------------------------------
//concatenate 連結
//
//    [a11 a12 a13]   [m11 m12 m13]   [a11*m11+a12*m21 a11*m12+a12*m22 a11*m13+a12*m23+a13]
//    [a21 a22 a23] * [m21 m22 m23] = [a21*m11+a22*m21 a21*m12+a22*m22 a21*m13+a22*m23+a23]
//    [ 0   0   1 ]   [ 0   0   1 ]   [       0               0                 1         ]
//
//  a*m
//  引数の順序に注意

//m = mConcatenate (m, a)
//  Array m
//  Array a
function mConcatenate (m, a) {
let a11 = a[0], a12 = a[1], a13 = a[2];  //double
let a21 = a[3], a22 = a[4], a23 = a[5];  //double
let m11 = m[0], m12 = m[1], m13 = m[2];  //double
let m21 = m[3], m22 = m[4], m23 = m[5];  //double
m[0] = a11 * m11 + a12 * m21;
m[1] = a11 * m12 + a12 * m22;
m[2] = a11 * m13 + a12 * m23 + a13;
m[3] = a21 * m11 + a22 * m21;
m[4] = a21 * m12 + a22 * m22;
m[5] = a21 * m13 + a22 * m23 + a23;
return m;
}

//o = mLetConcatenate (o, m, a)
//  Array o
//  Array m
//  Array a
function mLetConcatenate (o, m, a) {
let a11 = a[0], a12 = a[1], a13 = a[2];  //double
let a21 = a[3], a22 = a[4], a23 = a[5];  //double
let m11 = m[0], m12 = m[1], m13 = m[2];  //double
let m21 = m[3], m22 = m[4], m23 = m[5];  //double
o[0] = a11 * m11 + a12 * m21;
o[1] = a11 * m12 + a12 * m22;
o[2] = a11 * m13 + a12 * m23 + a13;
o[3] = a21 * m11 + a22 * m21;
o[4] = a21 * m12 + a22 * m22;
o[5] = a21 * m13 + a22 * m23 + a23;
return o;
}

//o = mNewConcatenate (m, a)
//  Array o
//  Array m
//  Array a
function mNewConcatenate (m, a) {
let a11 = a[0], a12 = a[1], a13 = a[2];  //double
let a21 = a[3], a22 = a[4], a23 = a[5];  //double
let m11 = m[0], m12 = m[1], m13 = m[2];  //double
let m21 = m[3], m22 = m[4], m23 = m[5];  //double
return [a11 * m11 + a12 * m21, a11 * m12 + a12 * m22, a11 * m13 + a12 * m23 + a13,
a21 * m11 + a22 * m21, a21 * m12 + a22 * m22, a21 * m13 + a22 * m23 + a23];
}

//------------------------------------------------------------------------
//copy コピー

//o = mLetCopy (o, m)
//  Array o
//  Array m
function mLetCopy (o, m) {
o[0] = m[0];
o[1] = m[1];
o[2] = m[2];
o[3] = m[3];
o[4] = m[4];
o[5] = m[5];
return o;
}

//o = mNewCopy (m)
//  Array o
//  Array m
function mNewCopy (m) {
return m.concat ();
}

//------------------------------------------------------------------------
//exchange 軸交換(+x→+y,+y→+x)
//
//    [m11 m12 m13]     [m22 m21 m23]
//    [m21 m22 m23] ==> [m12 m11 m13]
//    [ 0   0   1 ]     [ 0   0   1 ]
//

//m = mExchange (m)```