ぬの部屋(仮)
nu-no-he-ya
  •    1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
         12
    3456789
    10111213141516
    17181920212223
    242526272829 
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
        123
    45678910
    11121314151617
    18192021222324
    25262728   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    15161718192021
    293031    
           
         12
    3456789
    10111213141516
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
          1
    2345678
    9101112131415
    16171819202122
    232425262728 
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
  • ICO球の作り方(2)

    前回ICO球の作り方をやったので、今回はそれをC++で実装する。

    https://suzulang.com/cpp-code-ico-q-1/

    ソースコード

    #pragma warning(disable:4996)
    
    
    #include <GL/glut.h>
    
    #include <fstream>
    #include <sstream>
    #include <vector>
    #include <algorithm>
    
    #include <unordered_map>
    #include <array>
    
    
    //! @brief 三次元の座標値 struct xyz { double x, y, z; xyz() {} xyz(const double X, const double Y, const double Z) : x(X), y(Y), z(Z) {} }; //! @brief 三つの頂点IDで表す三角形 struct tri { size_t a, b, c; tri() {} tri(const size_t A, const size_t B, const size_t C) : a(A), b(B), c(C) {} }; //////////////////////////////////////////////////////////////// //! @brief ハッシュ値を統合する ( 汎用的に使用できる関数 ) //! @param [in,out] seed in:既存のハッシュ値 out:元のseedとvから作成したハッシュ値を統合した値 //! @param [in] v 新たにハッシュ値を作成する値 template<typename T> void hash_combine(size_t& seed, T const& v) { //基本型に関するハッシュ生成は標準ライブラリが提供している std::hash<T> primitive_type_hash; //生成したハッシュを合成する。このコードはboostものを使用する seed ^= primitive_type_hash(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } namespace ICOQ { //! @brief 二つの頂点IDで表すエッジ struct edge { size_t a, b; edge(const size_t A, const size_t B) :a(A), b(B) {} //! @brief 比較演算子。順序が逆でも同じと見なす bool operator==(const edge& e)const { return (e.a == a && e.b == b) || (e.a == b && e.b == a); } }; //! @brief エッジ用のハッシュ関数 struct EHash { public: size_t operator()(const edge& data)const { //クラスのメンバの値それぞれについてハッシュ生成して、それらを結合して一つのハッシュ値にする std::size_t seed = 0; if (data.a < data.b) { hash_combine(seed, data.a); hash_combine(seed, data.b); } else { hash_combine(seed, data.b); hash_combine(seed, data.a); } return seed; } }; //! @brief ICO球作成 class icoQ { public: //結果を格納する配列 std::vector<xyz> vlist; std::vector<tri> tlist; private: double R; //! @brief 頂点を正規化して原点からの距離Rにする //! @param [in,out] vtx 頂点座標 //! @param [in] R 半径 static void normalize(xyz& vtx,double R) { double x = vtx.x; double y = vtx.y; double z = vtx.z; double len = sqrt(x * x + y * y + z * z); vtx.x /= len; vtx.y /= len; vtx.z /= len; vtx.x *= R; vtx.y *= R; vtx.z *= R; } public: icoQ() { R = 1; } //! @brief 指定したエッジの中点(球上)の登録 void calc_middle(std::unordered_map<edge, size_t, EHash> * ehash, std::vector<xyz> * vtx, const size_t j, const size_t k) { double p[3] = { (*vtx)[j].x,(*vtx)[j].y,(*vtx)[j].z }; double q[3] = { (*vtx)[k].x,(*vtx)[k].y,(*vtx)[k].z }; xyz newV( (p[0] + q[0]) / 2, (p[1] + q[1]) / 2, (p[2] + q[2]) / 2 ); normalize(newV, R); vtx->push_back(newV); (*ehash)[edge(j, k)] = vtx->size() - 1; } //! @brief エッジの中間点を計算し、頂点をアップデートする //! @param [in,out] ehash エッジからエッジの中点のIDを取り出すためのハッシュ //! @param [in,out] vtx 頂点一覧。増えることはあっても順序は変わらない //! @param [in] tri_now 現在の三角形一覧 void update_middle_hash(std::unordered_map<edge, size_t, EHash> * ehash, std::vector<xyz> * vtx, const std::vector<tri> & tri_now) { ehash->clear(); // エッジの中間点となる頂点を作成し、ハッシュに登録する for (auto& t : tri_now) { std::unordered_map<edge, size_t, EHash>::iterator ei; // t.a -> t.b の中間点 ei = ehash->find(edge(t.a, t.b)); if (ei == std::end(*ehash)) { calc_middle(ehash, vtx, t.a, t.b); } // t.b -> t.c の中間点 ei = ehash->find(edge(t.b, t.c)); if (ei == std::end(*ehash)) { calc_middle(ehash, vtx, t.b, t.c); } // t.c -> t.a の中間点 ei = ehash->find(edge(t.c, t.a)); if (ei == std::end(*ehash)) { calc_middle(ehash, vtx, t.c, t.a); } } } //! @brief 初期状態の正二十面体を作成する void setSeeds( std::vector<xyz>& svtx, std::vector<tri>& stri){ svtx.resize(12); // create 12 vertices of a icosahedron // 正二十面体を構成する頂点を全て列挙する const double t = (1.0 + sqrt(5.0)) / 2.0; svtx[0] = xyz(-1, t, 0); svtx[1] = xyz(1, t, 0); svtx[2] = xyz(-1, -t, 0); svtx[3] = xyz(1, -t, 0); svtx[4] = xyz(0, -1, t); svtx[5] = xyz(0, 1, t); svtx[6] = xyz(0, -1, -t); svtx[7] = xyz(0, 1, -t); svtx[8] = xyz(t, 0, -1); svtx[9] = xyz(t, 0, 1); svtx[10] = xyz(-t, 0, -1); svtx[11] = xyz(-t, 0, 1); //すべての頂点座標を球の上に置く for (size_t i = 0; i < svtx.size(); i++) { normalize(svtx[i], R); } stri.resize(20); // create 20 triangles of the icosahedron // 正二十面体を構成する三角形を全て列挙する // 5 faces around point 0 stri[0] = tri(0, 11, 5); stri[1] = tri(0, 5, 1); stri[2] = tri(0, 1, 7); stri[3] = tri(0, 7, 10); stri[4] = tri(0, 10, 11); // 5 adjacent faces stri[5] = tri(1, 5, 9); stri[6] = tri(5, 11, 4); stri[7] = tri(11, 10, 2); stri[8] = tri(10, 7, 6); stri[9] = tri(7, 1, 8); // 5 faces around point 3 stri[10] = tri(3, 9, 4); stri[11] = tri(3, 4, 2); stri[12] = tri(3, 2, 6); stri[13] = tri(3, 6, 8); stri[14] = tri(3, 8, 9); // 5 adjacent faces stri[15] = tri(4, 9, 5); stri[16] = tri(2, 4, 11); stri[17] = tri(6, 2, 10); stri[18] = tri(8, 6, 7); stri[19] = tri(9, 8, 1); }
     
        //! @brief 球の作成
    
    void refine(const double r,const int level) { //半径の決定 R = r; // エッジの中間点を表すハッシュ std::unordered_map<edge, size_t, EHash> ehash; //初期状態の頂点・三角形群 std::vector<tri> tri_now; std::vector<xyz> vtx; setSeeds(vtx, tri_now); //初期形状の頂点情報の配列 //ICO球となる三角形 std::vector<tri> retQ; //「全ての三角形を4分割する」という作業をlevel回繰り返す for (size_t i = 0; i < level; i++) { //エッジの中点を求め、頂点一覧に追加し、そのハッシュを作成する update_middle_hash(&ehash, &vtx, tri_now); //今までの結果をクリア retQ.clear(); //全ての三角形を分割 for (auto& t : tri_now) { size_t a = t.a; size_t b = t.b; size_t c = t.c; size_t d = ehash[edge(a, b)]; size_t e = ehash[edge(b, c)]; size_t f = ehash[edge(c, a)]; //△t、つまり△abcを分割し新三角形を4つ作る /* a /\ / \ / \ d / \ f / \ / \ / \ / \ b ~~~~~~~e~~~~~~~ c */ retQ.push_back(tri(a, d, f)); //△adf retQ.push_back(tri(d, b, e)); //△dbe retQ.push_back(tri(d, e, f)); //△def retQ.push_back(tri(f, e, c)); //△fec } tri_now = retQ; } vlist = vtx; tlist = retQ; } }; }
     
    void display(void); void timer(int value) { glutPostRedisplay(); glutTimerFunc(20, timer, 0); } int width, height; void resize(int w, int h) { width = w; height = h; } ICOQ::icoQ icoq; int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutCreateWindow(argv[0]); glutDisplayFunc(display); glutReshapeFunc(resize); glutTimerFunc(20, timer, 0); glutReshapeFunc(resize); icoq.refine(1,4); glutMainLoop(); return 0; } void display(void) { glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45, width/(double)height, 0.1, 20); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslated(0, 0, -4); static int kk = 0; kk++; glRotated(kk, 1, 1.5, 1); glDisable(GL_LIGHTING); glColor3d(1, 1, 1); glLineWidth(2);
    //ICO球エッジ表示
     for (size_t i = 0; i < icoq.tlist.size(); i++) { xyz a = icoq.vlist[icoq.tlist[i].a]; xyz b = icoq.vlist[icoq.tlist[i].b]; xyz c = icoq.vlist[icoq.tlist[i].c]; glBegin(GL_LINE_LOOP); glVertex3d(a.x, a.y, a.z); glVertex3d(b.x, b.y, b.z); glVertex3d(c.x, c.y, c.z); glEnd(); } glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); GLfloat abl[4] = { 1,1,1,1 }; GLfloat zero[4] = { 0,0,0,0 }; glLightfv(GL_LIGHT0, GL_AMBIENT, abl); glLightfv(GL_LIGHT0, GL_DIFFUSE, zero); glLightfv(GL_LIGHT0, GL_SPECULAR, zero); glLightfv(GL_LIGHT0, GL_POSITION, zero); GLfloat ambr[4] = { 1,0,0,1 }; GLfloat ambb[4] = { 0,0,1,1 }; glMaterialfv(GL_FRONT, GL_AMBIENT, ambb); glMaterialfv(GL_BACK, GL_AMBIENT, ambr);
    //ICO球表示 for (size_t i = 0; i < icoq.tlist.size(); i++) { xyz a = icoq.vlist[icoq.tlist[i].a]; xyz b = icoq.vlist[icoq.tlist[i].b]; xyz c = icoq.vlist[icoq.tlist[i].c]; glBegin(GL_TRIANGLES); glVertex3d(a.x, a.y, a.z); glVertex3d(b.x, b.y, b.z); glVertex3d(c.x, c.y, c.z); glEnd(); }
     
    glFlush(); }

    参考文献

    Creating an icosphere mesh in code
    http://blog.andreaskahler.com/2009/06/creating-icosphere-mesh-in-code.html

    Weblog on mebius.tokaichiba.jp
    http://ynomura.dip.jp/archives/2009/08/20.html