←Previous | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | Next→
      if (y < ymin) {
        ymin = y;
      } else if (ymax < y) {
        ymax = y;
      }
      if (z < zmin) {
        zmin = z;
      } else if (zmax < z) {
        zmax = z;
      }
    }
    ph.ph$reciprocalMatrix = nScaleXYZ (nNewITranslateXYZ (-xmin, -ymin, -zmin), 1 / (xmax - xmin), 1 / (ymax - ymin), 1 / (zmax - zmin));
  }
  return ph;
}

//ph = phNewBox (x0, x1, y0, y1, z0, z1, ox0, ox1, oy0, oy1, oz0, oz1)
//  (x0,y0,z0)-(x1,y1,z1)を対角線とする直方体を作る
//  面を開放するかどうか指定する
//        7+-------+6
//        /|      /|
//       / |     / |
//  z1 4+-------+5 |
//      | 3+----|--+2 y1
//      | /     | /       +z  +y
//      |/      |/        ↑/
//  z0 0+-------+1 y0       →+x
//      x0      x1
function phNewBox (x0, x1, y0, y1, z0, z1, ox0, ox1, oy0, oy1, oz0, oz1) {
  let va = [[x0, y0, z0],  //0
            [x1, y0, z0],  //1
            [x1, y1, z0],  //2
            [x0, y1, z0],  //3
            [x0, y0, z1],  //4
            [x1, y0, z1],  //5
            [x1, y1, z1],  //6
            [x0, y1, z1]];  //7
  let fa = [[0, 4, 7, 3],  //-x
            [1, 2, 6, 5],  //+x
            [0, 1, 5, 4],  //-y
            [2, 3, 7, 6],  //+y
            [0, 3, 2, 1],  //-z
            [4, 5, 6, 7]];  //+z
  let oa = [ox0, ox1, oy0, oy1, oz0, oz1];
  return phMakeFields ({
    ph$vertexArray: va,
    ph$faceArray: fa,
    ph$openArray: oa
    });
}

//ph = phNewCylinderXY (x, y, r, z0, z1)
//ph = phNewCylinderYZ (y, z, r, x0, x1)
//ph = phNewCylinderZX (z, x, r, y0, y1)
//  円柱を作る
function phNewCylinderXY (x, y, r, z0, z1) {
  const step = 5;
  let va = [];
  for (let d = 0; d < 360; d += step) {
    let t = rad (d);
    va.push ([x + r * cos (t), y + r * sin (t)]);
  }
  return phNewPolygonXY1 (va, [z0, z1]);
}
function phNewCylinderYZ (y, z, r, x0, x1) {
  return phExchangeYZX (phNewCylinderXY (y, z, r, x0, x1));
}
function phNewCylinderZX (z, x, r, y0, y1) {
  return phExchangeZXY (phNewCylinderXY (z, x, r, y0, y1));
}

//ph = phNewRegularDodecahedron ()
//  正12面体を作る
//                                    1
//                            ____----●-__
//                  2●---~~~~         │  ~~--__
//                 / |                  |        >●0
//                / 3●---____        4    __--~~    \
//               /  /         ~~~~----●-~~           \
//              /  /                   | △6            \
//           7▲  /                    │                 \
//            /  /  _             _--~  |    ~\           \
//           /  /    ~~--      --~      │      ~\         ▲5
//          /  /         11▽            |         ~     / /
//         / 8▲                         │         12▽   /
//        //~  \          |            ▲9          /   /
//    10▼~       ~\       │        _-~  ~--__     /   /
//        \          ~\     |    _--~          ~~--__  /
//         \            ~\   _--~                    ▼13
//           \           14▼~                    /  /
//             \            | □  --____            /
//              \    __--~  │16        ~~~~-  □17/
//             15■<        |                  | /
//                   ~~--__  │         ____---■18
//                         ~~-■----~~~~
//                            19
function phNewRegularDodecahedron () {
  return phMakeFields ({
    ph$vertexArray: [
      [1/15*sqrt(150-30*sqrt(5)), 0, 1/15*sqrt(75+30*sqrt(5))],  //0
      [1/15*sqrt(75-30*sqrt(5)), 1/3*sqrt(3), 1/15*sqrt(75+30*sqrt(5))],  //1
      [-1/30*sqrt(150+30*sqrt(5)), 1/6*sqrt(3)*(sqrt(5)-1), 1/15*sqrt(75+30*sqrt(5))],  //2
      [-1/30*sqrt(150+30*sqrt(5)), -1/6*sqrt(3)*(sqrt(5)-1), 1/15*sqrt(75+30*sqrt(5))],  //3
      [1/15*sqrt(75-30*sqrt(5)), -1/3*sqrt(3), 1/15*sqrt(75+30*sqrt(5))],  //4
      [1/15*sqrt(150+30*sqrt(5)), 0, 1/15*sqrt(75-30*sqrt(5))],  //5
      [1/30*sqrt(150-30*sqrt(5)), 1/6*sqrt(3)*(sqrt(5)+1), 1/15*sqrt(75-30*sqrt(5))],  //6
      [-1/15*sqrt(75+30*sqrt(5)), 1/3*sqrt(3), 1/15*sqrt(75-30*sqrt(5))],  //7
      [-1/15*sqrt(75+30*sqrt(5)), -1/3*sqrt(3), 1/15*sqrt(75-30*sqrt(5))],  //8
      [1/30*sqrt(150-30*sqrt(5)), -1/6*sqrt(3)*(sqrt(5)+1), 1/15*sqrt(75-30*sqrt(5))],  //9
      [-1/15*sqrt(150+30*sqrt(5)), 0, -1/15*sqrt(75-30*sqrt(5))],  //10
      [-1/30*sqrt(150-30*sqrt(5)), 1/6*sqrt(3)*(sqrt(5)+1), -1/15*sqrt(75-30*sqrt(5))],  //11
      [1/15*sqrt(75+30*sqrt(5)), 1/3*sqrt(3), -1/15*sqrt(75-30*sqrt(5))],  //12
      [1/15*sqrt(75+30*sqrt(5)), -1/3*sqrt(3), -1/15*sqrt(75-30*sqrt(5))],  //13
      [-1/30*sqrt(150-30*sqrt(5)), -1/6*sqrt(3)*(sqrt(5)+1), -1/15*sqrt(75-30*sqrt(5))],  //14
      [-1/15*sqrt(150-30*sqrt(5)), 0, -1/15*sqrt(75+30*sqrt(5))],  //15
      [-1/15*sqrt(75-30*sqrt(5)), 1/3*sqrt(3), -1/15*sqrt(75+30*sqrt(5))],  //16
      [1/30*sqrt(150+30*sqrt(5)), 1/6*sqrt(3)*(sqrt(5)-1), -1/15*sqrt(75+30*sqrt(5))],  //17
      [1/30*sqrt(150+30*sqrt(5)), -1/6*sqrt(3)*(sqrt(5)-1), -1/15*sqrt(75+30*sqrt(5))],  //18
      [-1/15*sqrt(75-30*sqrt(5)), -1/3*sqrt(3), -1/15*sqrt(75+30*sqrt(5))]  //19
      ],
    ph$faceArray: [
      [0, 1, 2, 3, 4],  //0
      [0, 4, 9, 13, 5],  //1
      [0, 5, 12, 6, 1],  //2
      [1, 6, 11, 7, 2],  //3
      [2, 7, 10, 8, 3],  //4
      [3, 8, 14, 9, 4],  //5
      [5, 13, 18, 17, 12],  //6
      [6, 12, 17, 16, 11],  //7
      [7, 11, 16, 15, 10],  //8
      [8, 10, 15, 19, 14],  //9
      [9, 14, 19, 18, 13],  //10
      [15, 16, 17, 18, 19]  //11
      ]
    });
}

//ph = phNewRegularHexahedron ()
//  正6面体を作る
//       1-----------0
//      /|           |\
//     / |           | \
//    2-----------------3
//    |  |           |  |
//    |  |           |  |
//    |  5-----------4  |
//    |  |           |  |
//    | |             | |
//    ||               ||
//    6-----------------7
function phNewRegularHexahedron () {
  return phMakeFields ({
    ph$vertexArray: [
      [1/3*sqrt(3), 1/3*sqrt(3), 1/3*sqrt(3)],  //0
      [-1/3*sqrt(3), 1/3*sqrt(3), 1/3*sqrt(3)],  //1
      [-1/3*sqrt(3), -1/3*sqrt(3), 1/3*sqrt(3)],  //2
      [1/3*sqrt(3), -1/3*sqrt(3), 1/3*sqrt(3)],  //3
      [1/3*sqrt(3), 1/3*sqrt(3), -1/3*sqrt(3)],  //4
      [-1/3*sqrt(3), 1/3*sqrt(3), -1/3*sqrt(3)],  //5
      [-1/3*sqrt(3), -1/3*sqrt(3), -1/3*sqrt(3)],  //6
      [1/3*sqrt(3), -1/3*sqrt(3), -1/3*sqrt(3)]  //7
      ],
    ph$faceArray: [
      [0, 1, 2, 3],  //0
      [0, 3, 7, 4],  //1
      [0, 4, 5, 1],  //2
      [1, 5, 6, 2],  //3
      [2, 6, 7, 3],  //4
      [4, 7, 6, 5]  //5
      ]
    });
}

//ph = phNewRegularIcosahedron ()
//  正20面体を作る
//                            0
//                         __●_
//                    __--~/ |\~--_
//               __--~  _/   │\ 2 ~--_
//           _--~     /____-- | △-__  ~--_
//        3▲-----~~/         │  \ ~--__ ~--_
//        │|\  _/            |    \     ~--__~--_
//        | |  /             / │    \        ~--▲1
//       │ |/   \         /   |      \   __--~~/|
//       |4▲-----_____     /   5│    __--~~     /│
//      │ / \        ~~~~~-----▲--~~     \    / |
//      | /    \     __--▽---- / _\        \ / │
//     │/      \ ~~    │7   /     \~~~-----▽8|
//     |/__--~~   \      |   /        ~\   /| │
//    6▼--_        \    │ /            ~\  | |
//      ~--_~~--_     \     /           /   \|│
//          ~--_ ~~--_ \  /         _____-----▼9
//              ~--_  ~~-▼-----~~~~~      _--~
//                  ~--_ 10\│   /   _--~~
//                      ~--_\| /_--~~
//                          ~■~~
//                           11
function phNewRegularIcosahedron () {
  return phMakeFields ({
    ph$vertexArray: [
      [0, 0, 1],  //0
      [0, -2/5*sqrt(5), 1/5*sqrt(5)],  //1
      [1/10*sqrt(50+10*sqrt(5)), -1/10*(5-sqrt(5)), 1/5*sqrt(5)],  //2
      [1/10*sqrt(50-10*sqrt(5)), 1/10*(5+sqrt(5)), 1/5*sqrt(5)],  //3
      [-1/10*sqrt(50-10*sqrt(5)), 1/10*(5+sqrt(5)), 1/5*sqrt(5)],  //4
      [-1/10*sqrt(50+10*sqrt(5)), -1/10*(5-sqrt(5)), 1/5*sqrt(5)],  //5
      [0, 2/5*sqrt(5), -1/5*sqrt(5)],  //6
      [1/10*sqrt(50+10*sqrt(5)), 1/10*(5-sqrt(5)), -1/5*sqrt(5)],  //7
      [1/10*sqrt(50-10*sqrt(5)), -1/10*(5+sqrt(5)), -1/5*sqrt(5)],  //8
      [-1/10*sqrt(50-10*sqrt(5)), -1/10*(5+sqrt(5)), -1/5*sqrt(5)],  //9
      [-1/10*sqrt(50+10*sqrt(5)), 1/10*(5-sqrt(5)), -1/5*sqrt(5)],  //10
      [0, 0, -1 ]  //11
      ],
    ph$faceArray: [
      [0, 1, 2],  //0
      [0, 2, 3],  //1
      [0, 3, 4],  //2
      [0, 4, 5],  //3
      [0, 5, 1],  //4
      [1, 8, 2],  //5
      [2, 7, 3],  //6
      [3, 6, 4],  //7
      [4, 10, 5],  //8
      [5, 9, 1],  //9
      [11, 6, 7],  //10
      [11, 7, 8],  //11
      [11, 8, 9],  //12
      [11, 9, 10],  //13
      [11, 10, 6],  //14
      [6, 3, 7],  //15
      [7, 2, 8],  //16
      [8, 1, 9],  //17
      [9, 5, 10],  //18
      [10, 4, 6]  //19
      ]
    });
}

//ph = phNewRegularOctahedron ()
//  正8面体を作る
//            0
//         //|\
//       / │|  \
//     / __|-2-_  \
//    3-~~ │ |  ~-_ \
//     ~-_ | │   __--1
//       \~4---~~~ _-~
//        \\|  _-~
//           5-~
function phNewRegularOctahedron () {
  return phMakeFields ({
    ph$vertexArray: [
      [0, 0, 1],  //0
      [1, 0, 0],  //1
      [0, 1, 0],  //2
      [-1, 0, 0],  //3
      [0, -1, 0],  //4
      [0, 0, -1]  //5
      ],
    ph$faceArray: [
      [0, 1, 2],  //0
      [0, 2, 3],  //1
      [0, 3, 4],  //2
      [0, 4, 1],  //3
      [1, 4, 5],  //4
      [1, 5, 2],  //5
      [2, 5, 3],  //6
      [3, 5, 4]  //7
      ]
    });
}

//ph = phNewRegularTetrahedron ()
//  正4面体を作る
//           0
//         //\
//       / /   \
//     2__ /      \
//     |  / ─__    \
//    │ /      ~~─__\
//    │/          ___--1
//    |/  ___---~~~
//    3~~~
function phNewRegularTetrahedron () {
  return phMakeFields ({
    ph$vertexArray: [
      [0, 0, 1],  //0
      [2/3*sqrt(2), 0, -1/3],  //1
      [-1/3*sqrt(2), 1/3*sqrt(6), -1/3],  //2
      [-1/3*sqrt(2), -1/3*sqrt(6), -1/3]  //3
      ],
    ph$faceArray: [
      [0, 1, 2],  //0
      [0, 2, 3],  //1
      [0, 3, 1],  //2
      [1, 3, 2]  //3
      ]
    });
}

//ph = phNewPolygonXY (pg, za)
//ph = phNewPolygonYZ (pg, xa)
//ph = phNewPolygonZX (pg, ya)
//ph = phNewPolygonXY1 (va, za)
//ph = phNewPolygonYZ1 (va, xa)
//ph = phNewPolygonZX1 (va, ya)
//  xy平面の多角形とz座標のリストから多面体を作る
//  多角形は左回りであること
//  z座標は昇順で2つ以上あること
//  pg = {
//    pg$vertexArray: [
//      [x0, y0],
//      [x1, y1],
//        :
//      ],
//    pg$faceArray: [
//      [vn00, vn01, ...],
//      [vn10, vn11, ...],
//        :
//      ]
//    }
//  za=[z0,z1,...]

function phNewPolygonXY (pg, za) {
  let va2 = pg.pg$vertexArray;
  let fa2 = pg.pg$faceArray;
  let va2l = va2.length;  //多角形の頂点の数
  let fa2l = fa2.length;  //多角形の面の数
  let zal = za.length;  //z座標の数
  //頂点を作る
  let va3 = [];
  for (let zai = zal - 1; 0 <= zai; zai--) {  //降順
    let z = za[zai];
    for (let va2i = 0; va2i < va2l; va2i++) {
      let v2 = va2[va2i];
      va3.push ([v2[0], v2[1], z]);
    }
  }
  //面を作る
  let fa3 = [];
  let na3 = [];
  //  天井
  for (let fa2i = 0; fa2i < fa2l; fa2i++) {
    let f2 = fa2[fa2i];
    let f2l = f2.length;
    let f3 = [];
    for (let f2i = 0; f2i < f2l; f2i++) {  //昇順。天井を上から見て左回り
      f3.push (f2[f2i]);
    }
    fa3.push (f3);
    na3.push ([0, 0, 1]);  //法線ベクトルは+z
  }
  //  床
  for (let fa2i = 0; fa2i < fa2l; fa2i++) {
    let f2 = fa2[fa2i];
    let f2l = f2.length;
    let f3 = [];
    for (let f2i = f2l - 1; 0 <= f2i; f2i--) {  //降順。床を下から見て左回り
      f3.push (f2[f2i] + va2l * (zal - 1));
    }
    fa3.push (f3);
    na3.push ([0, 0, -1]);  //法線ベクトルは-z
  }
  //  壁
  for (let zai = 0; zai + 1 < zal; zai++) {
    for (let fa2i = 0; fa2i < fa2l; fa2i++) {
      let f2 = fa2[fa2i];
      let f2l = f2.length;
      for (let f2i = 0; f2i < f2l; f2i++) {
        let f2i1 = f2i + 1 < f2l ? f2i + 1 : 0;
        fa3.push ([f2[f2i] + va2l * zai,  //左上
                   f2[f2i] + va2l * (zai + 1),  //左下
                   f2[f2i1] + va2l * (zai + 1),  //右下
                   f2[f2i1] + va2l * zai]);  //右上
        let vtl = va2[f2[f2i]];  //左上
        let vtr = va2[f2[f2i1]];  //右上
        na3.push ([vtr[1] - vtl[1], vtl[0] - vtr[0], 0]);  //法線ベクトル
      }
    }
  }
  //  内側の重複した壁を取り除く
  for (let fa3i = 0; fa3i + 1 < fa3.length; fa3i++) {  //fa3.lengthは変化する
    for (let fa3j = fa3i + 1; fa3j < fa3.length; fa3j++) {  //fa3.lengthは変化する
      if (phIsReversedFace (fa3[fa3i], fa3[fa3j])) {
        fa3.splice (fa3j, 1);
        na3.splice (fa3j, 1);
        fa3.splice (fa3i, 1);
        na3.splice (fa3i, 1);
        fa3i--;
        break;
      }
    }
  }
  //  内側の不要な頂点を取り除く
  //    頂点の使用状況を確認する
  let ra = [];  //頂点使用フラグ兼リナンバーテーブル
  for (let va3i = 0; va3i < va3.length; va3i++) {
    ra[va3i] = -1;  //使われていない
  }
  for (let fa3i = 0; fa3i < fa3.length; fa3i++) {
    let f3 = fa3[fa3i];
    for (let f3i = 0; f3i < f3.length; f3i++) {
      ra[f3[f3i]] = 0;  //使われている
    }
  }
  //    使われている頂点を詰める
  let n = 0;  //使われている頂点の数
  for (let va3i = 0; va3i < va3.length; va3i++) {
    if (ra[va3i] == 0) {  //使われている
      va3[n] = va3[va3i];  //詰める
      ra[va3i] = n;  //古い番号→新しい番号
      n++;
    }
  }
  va3.splice (n, va3.length - n);  //余った部分を切り捨てる
  //    面の頂点の番号を振り直す
  for (let fa3i = 0; fa3i < fa3.length; fa3i++) {
    let f3 = fa3[fa3i];
    for (let f3i = 0; f3i < f3.length; f3i++) {
      f3[f3i] = ra[f3[f3i]];  //古い番号→新しい番号
    }
  }
  return phMakeFields ({
    ph$vertexArray: va3,
    ph$faceArray: fa3,
    ph$normalArray: na3
    });
}

function phNewPolygonYZ (pg, xa) {
  return phExchangeYZX (phNewPolygonXY (pg, xa));
}

function phNewPolygonZX (pg, ya) {
  return phExchangeZXY (phNewPolygonXY (pg, ya));
}

function phNewPolygonXY1 (va, za) {
  let f = [];
  for (let vai = 0; vai < va.length; vai++) {
    f.push (vai);
  }
  return phNewPolygonXY ({ pg$vertexArray: va, pg$faceArray: [f] }, za);
}

function phNewPolygonYZ1 (va, xa) {
  let f = [];
  for (let vai = 0; vai < va.length; vai++) {
    f.push (vai);
  }
  return phNewPolygonYZ ({ pg$vertexArray: va, pg$faceArray: [f] }, xa);
}

function phNewPolygonZX1 (va, ya) {
  let f = [];
  for (let vai = 0; vai < va.length; vai++) {
    f.push (vai);
  }
  return phNewPolygonZX ({ pg$vertexArray: va, pg$faceArray: [f] }, ya);
}

//pha = phNewArcXY (ox, oy, ri, ro, t0, t1, z0, z1, ot0, ot1, oz0, oz1)
//pha = phNewArcYZ (oy, oz, ri, ro, t0, t1, x0, x1, ot0, ot1, oz0, oz1)
//pha = phNewArcZX (oz, ox, ri, ro, t0, t1, y0, y1, ot0, ot1, oz0, oz1)
//  円弧を作る
//  ox  中心のx座標
//  oy  中心のy座標
//  ri  内側の半径
//  ro  外側の半径
//  t0  開始角
//  t1  終了角
//  z0  開始z座標
//  z1  終了z座標
//  ot0  t0面を塞がない
//  ot1  t1面を塞がない
//  oz0  z0面を塞がない
//  oz1  z1面を塞がない
//
//  perl -e "use lib'.';use Graph;$PI=$Graph::PI;$g=new Graph(80,40,-0.25,1,-0.25,1);$g->grid();$f=1;for($d=-15;$d<=105;$d+=30){$t=$d*$PI/180;$x1=cos($t);$y1=sin($t);$g->lineaa($x1/2,$y1/2,$x1,$y1);if(!$f){$g->lineaa($x0/2,$y0/2,$x1/2,$y1/2);$g->lineaa($x0,$y0,$x1,$y1);$g->lineaa(($x0+$x1)/2,($y0+$y1)/2,($x0+$x1)/4,($y0+$y1)/4);}$x0=$x1;$y0=$y1;$f=0}print$g;"
//                    +                                                                
//    ----------------|-----------------                                               
//    \               |               / ~--_                                           
//    \               |               /     ~--                                        
//     \              |              /         ~--_                                    
//      \             |             /              ~--                                 
//      \             |             /               - ~--_                             
//       \            |            /               -      ~-_                          
//       \            |            /              -          ~--_                      
//        \           |           /             _~               ~-_                   
//        \           |           /            _                  -~-                  
//         \          |          /            -                 -~   -                 
//         \          |          /           -                -~      ~                
//          \         |         /           -               -~         ~_              
//          \         |         /          -              -~             _             
//           \        |        /          ~             -~                -            
//           \        |       _/        _~            -~                   -_          
//            ~~~~~~~~|~~~~~~~~--_     _            -~                   _-~-          
//                    |           ~--_-           -~                 _--~    -         
//                    |              ---_       -~                _-~         ~        
//                    |                  ~--  -~              _--~             ~_      
//                    |                     ~-             _-~                   _     
//                    |                       -        _--~                       -    
//                    |                        ~    _--                            -   
//          ro*sin(th)|                         ~--~                          __-----  
//                    |                           _                    __----~      |  
//                    |                            -            _----~~             |  
//                    |                             -   __----~~                    |  
//          ri*sin(th)|                              -~~                            |  
//                    |                              |                              |  
//                    |                              |                              |  
//                    |                              |                              |  
//    ----------------+---------------------------------------------------------------+
//                    |0                   ri*cos(th)|                    ro*cos(th)|  
//                    |                              |                              |  
//                    |                              |                              |  
//                    |                              |__                            |  
//                    |                                 ~~----__                    |  
//                    |                                         ~----__             |  
//                    |                                                ~~----_      |  
//                    |                                                       ~~----|  
//
function phNewArcXY (ox, oy, ri, ro, t0, t1, z0, z1, ot0, ot1, oz0, oz1) {
  const step = rad (5);
  let n = max2 (1, roundn ((t1 - t0) / step));  //分割数
  let th = (t1 - t0) / (2 * n);  //1ブロックの中心角の半分
  let xi = ri * cos (th);
  let yi = ri * sin (th);
  let xo = ro * cos (th);
  let yo = ro * sin (th);
  let pha = [];
  for (let k = 0; k < n; k++) {
    //x軸上の台形を底面とする四角柱を作る
    //  この形で外接直方体を設定する
    //                       --+0
    //              1+--~~~~~ /|
    //              /|       / |
    //       yo    /      --+4 |
    //       yi  5+--~~~~~  |  |
    //            |  |      |  |
    //            | 2+--    |  |
    //            | /   ~~~~|--+3  z0
    //            |/        | /
    //      -yi  6+--       |/
    //      -yo      ~~~~~--+7  z1
    //            xi        xo
    let va = [[xo, yo, z0],  //0
              [xi, yi, z0],  //1
              [xi, -yi, z0],  //2
              [xo, -yo, z0],  //3
              [xo, yo, z1],  //4
              [xi, yi, z1],  //5
              [xi, -yi, z1],  //6
              [xo, -yo, z1]];  //7
    let fa = [[1, 2, 6, 5],  //-x  内側
              [3, 0, 4, 7]];  //+x  外側
    let oa = [0,  //-x
              0];  //+x
    if (k == 0) {
      fa.push ([3, 2, 6, 7]);  //-y  t0面
      oa.push (ot0);  //-y
    } else if (k == n - 1) {
      fa.push ([0, 1, 5, 4]);  //+y  t1面
      oa.push (ot1);  //+y
    }
    fa.push ([1, 0, 3, 2]);  //-z  z0面
    oa.push (oz0);
    fa.push ([4, 5, 6, 7]);  //+z  z1面
    oa.push (oz1);
    let ph = phNew (va, fa, oa);
    //t0+(2*k+1)*th(k=0..n-1)回転させる
    phRotateXY (ph, t0 + (2 * k + 1) * th);
    phTranslateXYZ (ph, ox, oy, 0);
    pha.push (ph);
  }
  return pha;
}

function phNewArcYZ (oy, oz, ri, ro, t0, t1, x0, x1, c0, c1, d0, d1) {
  let pha = phNewArcXY (oy, oz, ri, ro, t0, t1, x0, x1, c0, c1, d0, d1);
  for (let i = 0; i < pha.length; i++) {
    phExchangeYZX (pha[i]);
  }
  return pha;
}

function phNewArcZX (oz, ox, ri, ro, t0, t1, y0, y1, c0, c1, d0, d1) {
  let pha = phNewArcXY (oz, ox, ri, ro, t0, t1, y0, y1, c0, c1, d0, d1);
  for (let i = 0; i < pha.length; i++) {
    phExchangeZXY (pha[i]);
  }
  return pha;
}

//------------------------------------------------------------------------
//変形

//ph = phRotateXY (ph, t)
//  多面体を回す(X→Y)
function phRotateXY (ph, t) {
  let va = ph.ph$vertexArray;
  let na = ph.ph$normalArray;
  let c = cos (t);
  let s = sin (t);
  for (let i = 0; i < va.length; i++) {
    let v = va[i];
    let vx = v[0];
    let vy = v[1];
    v[0] = c * vx - s * vy;
    v[1] = s * vx + c * vy;
  }
  for (let i = 0; i < na.length; i++) {
    let n = na[i];
    let nx = n[0];
    let ny = n[1];
    n[0] = c * nx - s * ny;
    n[1] = s * nx + c * ny;
  }
  ph.ph$reciprocalMatrix = nNewConcatenate (nNewIRotateXY (-t), ph.ph$reciprocalMatrix);
  return ph;
}

//ph = phRotateYZ (ph, t)
//  多面体を回す(Y→Z)
function phRotateYZ (ph, t) {
  let va = ph.ph$vertexArray;
  let na = ph.ph$normalArray;
  let c = cos (t);
  let s = sin (t);
  for (let i = 0; i < va.length; i++) {
    let v = va[i];
    let vy = v[1];
    let vz = v[2];
    v[1] = c * vy - s * vz;
    v[2] = s * vy + c * vz;
  }
  for (let i = 0; i < na.length; i++) {
    let n = na[i];
    let ny = n[1];
    let nz = n[2];
    n[1] = c * ny - s * nz;
    n[2] = s * ny + c * nz;
  }
  ph.ph$reciprocalMatrix = nNewConcatenate (nNewIRotateYZ (-t), ph.ph$reciprocalMatrix);
  return ph;
}

//ph = phRotateZX (ph, t)
//  多面体を回す(Z→X)
function phRotateZX (ph, t) {
  let va = ph.ph$vertexArray;
  let na = ph.ph$normalArray;
  let c = cos (t);
  let s = sin (t);
  for (let i = 0; i < va.length; i++) {
    let v = va[i];
    let vz = v[2];
    let vx = v[0];
    v[2] = c * vz - s * vx;
    v[0] = s * vz + c * vx;
  }
  for (let i = 0; i < na.length; i++) {
    let n = na[i];
    let nz = n[2];
    let nx = n[0];
    n[2] = c * nz - s * nx;
    n[0] = s * nz + c * nx;
  }
  ph.ph$reciprocalMatrix = nNewConcatenate (nNewIRotateZX (-t), ph.ph$reciprocalMatrix);
  return ph;
}

//ph = phScaleXYZ (ph, s, t, u)
//  多面体を拡大縮小する
//  s==t&&s==uでないときは法線ベクトルを作り直す
function phScaleXYZ (ph, s, t, u) {
  let va = ph.ph$vertexArray;
  for (let i = 0; i < va.length; i++) {
    let v = va[i];
    v[0] *= s;
    v[1] *= t;
    v[2] *= u;
  }
  ph.ph$reciprocalMatrix = nNewConcatenate (nNewIScaleXYZ (1 / s, 1 / t, 1 / u), ph.ph$reciprocalMatrix);
  if (!(s == t && s == u)) {
    ph.ph$normalArray = null;
    phMakeFields (ph);  //法線ベクトルを作り直す
  }
  return ph;
}

//ph = phTranslateXYZ (ph, s, t, u)
//  多面体を平行移動する
//  面を構成する頂点の番号や法線ベクトルは変わらない
function phTranslateXYZ (ph, s, t, u) {
  let va = ph.ph$vertexArray;
  for (let i = 0; i < va.length; i++) {
    let v = va[i];
    v[0] += s;
    v[1] += t;
    v[2] += u;
  }
  ph.ph$reciprocalMatrix = nNewConcatenate (nNewITranslateXYZ (-s, -t, -u), ph.ph$reciprocalMatrix);
  return ph;
}


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

//ph2 = phLetCopy (ph2, ph1)
//  多面体を上書きする
function phLetCopy (ph2, ph1) {
  let va1 = ph1.ph$vertexArray;
  let fa1 = ph1.ph$faceArray;
  let oa1 = ph1.ph$openArray;
  let na1 = ph1.ph$normalArray;
  let rm1 = ph1.ph$reciprocalMatrix;
  let va2 = [];
  for (let i = 0; i < va1.length; i++) {
    va2.push (va1[i].concat ());
  }
  let fa2 = [];
  for (let i = 0; i < fa1.length; i++) {
    fa2.push (fa1[i].concat ());
  }
  let oa2 = oa1.concat ();
  let na2 = [];
  for (let i = 0; i < na1.length; i++) {
    na2.push (na1[i].concat ());
  }
  let rm2 = rm1.concat ();
  ph2.ph$vertexArray = va2;
  ph2.ph$faceArray = fa2;
  ph2.ph$openArray = oa2;
  ph2.ph$normalArray = na2;
  ph2.ph$reciprocalMatrix = rm2;
  return ph2;
}

//ph2 = phNewCopy (ph1)
//  多面体を複製する
function phNewCopy (ph1) {
  return phLetCopy ({}, ph1);
}


//------------------------------------------------------------------------
//軸交換

function phExchangeYZX (ph) {
  let va = ph.ph$vertexArray;
  let na = ph.ph$normalArray;
  for (let i = 0; i < va.length; i++) {
    let v = va[i];
    let t = v[0];
    v[0] = v[2];  //z→x
    v[2] = v[1];  //y→z
    v[1] = t;  //x→y
  }
  for (let i = 0; i < na.length; i++) {
    let n = na[i];
    let t = n[0];
    n[0] = n[2];
    n[2] = n[1];
    n[1] = t;
  }
  nExchangeYZX (ph.ph$reciprocalMatrix);
  return ph;
}

function phExchangeZXY (ph) {
  let va = ph.ph$vertexArray;
  let na = ph.ph$normalArray;
  for (let i = 0; i < va.length; i++) {
    let v = va[i];
    let t = v[0];
    v[0] = v[1];  //y→x
    v[1] = v[2];  //z→y
    v[2] = t;  //x→z
  }
  for (let i = 0; i < na.length; i++) {
    let n = na[i];
    let t = n[0];
    n[0] = n[1];
    n[1] = n[2];
    n[2] = t;
  }
  nExchangeZXY (ph.ph$reciprocalMatrix);
  return ph;
}


//------------------------------------------------------------------------
//加工

//ph = phRemoveFace (ph, fn)
//  多面体から面を取り除く
function phRemoveFace (ph, fn) {
  let fa = ph.ph$faceArray;
  let oa = ph.ph$openArray;
  let na = ph.ph$normalArray;
  fa.splice (fn, 1, 0);
  oa.splice (fn, 1, 0);
  na.splice (fn, 1, 0);
  return ph;
}


//------------------------------------------------------------------------
//連結

//ph = phJoin (ph, ph2)
//  多面体を連結する
//  同一頂点と同一面をまとめて反転面を打ち消す
//  同一平面にある面が隣り合っても大きい面にはならない
//  面の形が違うと打ち消せないので、phSplitFaceを使って面を分割して面の形を同じにしてから連結すること
function phJoin (ph, ph2) {
  let va = ph.ph$vertexArray;
  let fa = ph.ph$faceArray;
  let oa = ph.ph$openArray;
  let na = ph.ph$normalArray;
  let va2 = ph2.ph$vertexArray;
  let fa2 = ph2.ph$faceArray;
  let oa2 = ph2.ph$openArray;
  let na2 = ph2.ph$normalArray;
  //連結する
  let val = va.length;
  for (let i = 0; i < va2.length; i++) {
    va.push (va2[i].concat ());
  }
  for (let i = 0; i < fa2.length; i++) {
    let ga2 = fa2[i].concat ();
    for (let j = 0; j < ga2.length; j++) {
      ga2[j] += val;
    }
    fa.push (ga2);
    oa.push (oa2[i]);
    na.push (na2[i].concat ());
  }
  //同一頂点をまとめる
  for (let i = 0; i + 1 < va.length; i++) {  //va.lengthは変化する
    for (let j = i + 1; j < va.length; j++) {  //va.lengthは変化する
      if (phIsSameVertex (va[i], va[j])) {  //同一頂点
        //面のjをiに変更してjより大きいものを1減らす
        for (let k = 0; k < fa.length; k++) {
          let f = fa[k];
          for (let l = 0; l < f.length; l++) {
            if (f[l] == j) {
              f[l] = i;
            } else if (j < f[l]) {
              f[l]--;
            }
          }
        }
        //頂点のjを削除する
        va.splice (j, 1);
        j--;
      }
    }
  }
  //同一面をまとめる
  for (let i = 0; i + 1 < fa.length; i++) {
    for (let j = i + 1; j < fa.length; j++) {
      if (phIsSameFace (fa[i], fa[j])) {  //同一面
        //面のjを削除する
        fa.splice (j, 1);
        oa.splice (j, 1);
        na.splice (j, 1);
        j--;
      }
    }
  }
  //反転面を打ち消す
  for (let i = 0; i + 1 < fa.length; i++) {
    for (let j = i + 1; j < fa.length; j++) {
      if (phIsReversedFace (fa[i], fa[j])) {
        //面のiとjを削除する
        fa.splice (j, 1);
        oa.splice (j, 1);
        na.splice (j, 1);
        fa.splice (i, 1);
        oa.splice (i, 1);
        na.splice (i, 1);
        i--;
        break;
      }
    }
  }
  ph.ph$reciprocalMatrix = null;
  phMakeFields (ph);  //単位立方体変換行列を作り直す
  return ph;
}


//------------------------------------------------------------------------
//分割

//gn = phSplitX (ph, s)
//  多面体の面を平面x=sで分割する
//gn = phSplitY (ph, s)
//  多面体の面を平面y=sで分割する
//gn = phSplitZ (ph, s)
//  多面体の面を平面z=sで分割する
//gn = phSplitByTriangle (ph, a, b, c)
//  多面体の面を3点a,b,cを通る平面で分割する
//gn = phSplitByPlane (ph, p, q, r, s)
//  多面体の面を平面p*x+q*y+r*z+s=0で分割する
//
//  平面
//    p*x+q*y+r*z+s=0
//  の法線ベクトルは
//    (p,q,r)
//  である
//  3点
//    A (ax,ay,az)
//    B (bx,by,bz)
//    C (cx,cy,cz)
//  を通る平面の法線ベクトルは
//    A→B (bx-ax,by-ay,bz-az)
//  と
//    A→C (cx-ax,cy-ay,cz-az)
//  の外積なので
//    p=(by-ay)*(cz-az)-(cy-ay)*(bz-az)
//    q=(bz-az)*(cx-ax)-(cz-az)*(bx-ax)
//    r=(bx-ax)*(cy-ay)-(cx-ax)*(by-ay)
//    s=-(p*ax+q*ay+r*ax)
//
//  sub({p=(by-ay)*(cz-az)-(cy-ay)*(bz-az),q=(bz-az)*(cx-ax)-(cz-az)*(bx-ax),r=(bx-ax)*(cy-ay)-(cx-ax)*(by-ay)},p*ax+q*ay+r*az-(p*ax+q*ay+r*az));
//  sub({p=(by-ay)*(cz-az)-(cy-ay)*(bz-az),q=(bz-az)*(cx-ax)-(cz-az)*(bx-ax),r=(bx-ax)*(cy-ay)-(cx-ax)*(by-ay)},p*bx+q*by+r*bz-(p*ax+q*ay+r*az));
//  sub({p=(by-ay)*(cz-az)-(cy-ay)*(bz-az),q=(bz-az)*(cx-ax)-(cz-az)*(bx-ax),r=(bx-ax)*(cy-ay)-(cx-ax)*(by-ay)},p*cx+q*cy+r*cz-(p*ax+q*ay+r*az));
//
//  3点a,b,cを通る平面と2点d,eを通る直線の交点v
//  vx=ax+s*(bx-ax)+t*(cx-ax)=dx+u*(ex-dx)
//  vy=ay+s*(by-ay)+t*(cy-ay)=dy+u*(ey-dy)
//  vz=az+s*(by-ay)+t*(cz-az)=dz+u*(ez-dz)
//
//  sub(first(solve({ax+s*(bx-ax)+t*(cx-ax)=dx+u*(ex-dx),ay+s*(by-ay)+t*(cy-ay)=dy+u*(ey-dy),az+s*(by-ay)+t*(cz-az)=dz+u*(ez-dz)},{s,t,u})),dx+u*(ex-dx));
//  解けることは解けるが展開したままだと尋常でない長さになってしまう
//
//  平面p*x+q*y+r*z+s=0と2点d,eを通る直線の交点v
//  p*vx+q*vy+r*vz+s=0
//  vx=dx+u*(ex-dx)
//  vy=dy+u*(ey-dy)
//  vz=dz+u*(ez-dz)
//  p*(dx+u*(ex-dx))+q*(dy+u*(ey-dy))+r*(dz+u*(ez-dz))+s=0
//
//  vx:=sub(first(solve(p*(dx+u*(ex-dx))+q*(dy+u*(ey-dy))+r*(dz+u*(ez-dz))+s=0,u)),dx+u*(ex-dx));
//  vy:=sub(first(solve(p*(dx+u*(ex-dx))+q*(dy+u*(ey-dy))+r*(dz+u*(ez-dz))+s=0,u)),dy+u*(ey-dy));
//  vz:=sub(first(solve(p*(dx+u*(ex-dx))+q*(dy+u*(ey-dy))+r*(dz+u*(ez-dz))+s=0,u)),dz+u*(ez-dz));
//
//  vx=((dy*ex-dx*ey)*q+(dz*ex-dx*ez)*r+(ex-dx)*s)/((dx-ex)*p+(dy-ey)*q+(dz-ez)*r)
//  vy=((dx*ey-dy*ex)*p+(dz*ey-dy*ez)*r+(ey-dy)*s)/((dx-ex)*p+(dy-ey)*q+(dz-ez)*r)
//  vz=((dx*ez-dz*ex)*p+(dy*ez-dz*ey)*q+(ez-dz)*s)/((dx-ex)*p+(dy-ey)*q+(dz-ez)*r)
//
//gn = phSplitXL (ph, x0, x1, l)
//  多面体の面をx方向に長さl以上で分割する
//  外側からlずつ削って中央にl以上残す
function phSplitXL (ph, x0, x1, l) {
  while (3 * l <= x1 - x0) {
    x0 += l;
    x1 -= l;
    phSplitX (ph, x0);
    phSplitX (ph, x1);
  }
  if (2 * l <= x1 - x0) {
    phSplitX (ph, (x0 + x1) * 0.5);
  }
  return ph;
}
//gn = phSplitYL (ph, y0, y1, l)
//  多面体の面をy方向に長さl以上で分割する
//  外側からlずつ削って中央にl以上残す
function phSplitYL (ph, y0, y1, l) {
  while (3 * l <= y1 - y0) {
    y0 += l;
    y1 -= l;
    phSplitY (ph, y0);
    phSplitY (ph, y1);
  }
  if (2 * l <= y1 - y0) {
    phSplitY (ph, (y0 + y1) * 0.5);
  }
  return ph;
}
//gn = phSplitZL (ph, z0, z1, l)
//  多面体の面をz方向に長さl以上で分割する
//  外側からlずつ削って中央にl以上残す
function phSplitZL (ph, z0, z1, l) {
  while (3 * l <= z1 - z0) {
    z0 += l;
    z1 -= l;
    phSplitZ (ph, z0);
    phSplitZ (ph, z1);
  }
  if (2 * l <= z1 - z0) {
    phSplitZ (ph, (z0 + z1) * 0.5);
  }
  return ph;
}
//gn = phSplitFaceNXY (ph, p, q)
←Previous | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | Next→