#ifndef ATS_VP_H #define ATS_VP_H #include #include #include #include #include #include #include #include #include #include "ats_point.h" #include "ats_component.h" #include "ats_composite.h" #include "ats_leaf.h" #include "ats_exception.h" /******************************************************** * class Vp * ポイント、ポリゴンのインデックス、変換行列がメンバ。 * コンストラクタでのファイルの読み込みが失敗した場合や、 * Compositeで定義される関数が呼ばれた場合は例外 * bad_operationをthrowする。 ********************************************************/ namespace ats { template class Vp : public Leaf3D { protected: std::vector m_nrm_array; std::vector m_pnt_array; std::vector m_nrm_array2; std::vector< std::vector > m_idx_array; // box == x.max x.min y.max y.min z.max z.min Point m_box[6]; // scale x, y, z T m_scale; Vp(){} void set_scale(); void read_pnt(::ifstream& vp); void read_idx(::ifstream& vp); void cul_normal(); public: Vp(const char* filename); virtual ~Vp(){}; virtual void Draw(); virtual void UpdateTime(double) {}; }; // implementation --------------------------------------------------------------------- // オブジェクトが画面内に表示されるよう調整 ---------------------------- // (最大値がsizeで表示されるように) template void Vp::set_scale(){ for(int i=0; i < m_pnt_array.size()/3; i++){ // jが2つ進むとkは1つ進む。 for(int j = 0, k = 0; j < 6; j++, k++){ if(m_box[j].X() < m_pnt_array[i*3 + k]){ m_box[j].SetXYZ(m_pnt_array[i*3], m_pnt_array[i*3+1], m_pnt_array[i*3+2]); } ++j; if(m_box[j].X() > m_pnt_array[i*3 + k]){ m_box[j].SetXYZ(m_pnt_array[i*3], m_pnt_array[i*3+1], m_pnt_array[i*3+2]); } } } T obj_size, scale_size = 1.5; obj_size = fabs(m_box[0].X() - m_box[1].X()); obj_size = (obj_size == 0) ? 0.000000000001 : obj_size; T sx = scale_size / obj_size; obj_size = fabs(m_box[2].Y() - m_box[3].Y()); obj_size = (obj_size == 0) ? 0.000000000001 : obj_size; T sy = scale_size / obj_size; obj_size = fabs(m_box[4].Z() - m_box[5].Z()); obj_size = (obj_size == 0) ? 0.000000000001 : obj_size; T sz = scale_size / obj_size; m_scale = (sx < sy) ? sx : sy; m_scale = (m_scale < sz) ? m_scale : sz; ::cout << "scale : " << m_scale << endl; } // vpファイルの頂点の読み込み ---------------------------------------- template void Vp::read_pnt(::ifstream& vp) { // 頂点の総数の読み込み int pnt_num; vp >> pnt_num; m_pnt_array.resize(pnt_num*3); // vpファイルの頂点の読み込み for(int i=0; i < pnt_num*3; i++){ vp >> m_pnt_array[i]; } // スケールの設定 set_scale(); } // vpファイルのポリゴンのインデックスの読み込み ---------------------- template void Vp::read_idx(::ifstream& vp) { // vpファイルのポリゴンのインデックスの読み込み int index_num, poly_num; vp >> index_num; m_idx_array.resize(index_num); for(int i=0; i < index_num; i++){ vp >> poly_num; m_idx_array[i].resize(poly_num); for(int j=0; j < poly_num; j++){ // デクリメントはインデックスの変換作業 // vpファイルのインデックスは0でなく1から始まる vp >> m_idx_array[i][j]; --(m_idx_array[i][j]); } } } // 面の法線計算 -------------------------------------------------------- template void Vp::cul_normal() { using namespace std; /******************************************************* * 注意!!: * pnt nrm が付く変数は * 1. 同じpnt nrm 系からの変換 * 2. 多次元配列からの変換(m_idx_array[sface][0]) * 3. for(;;)の増加分が3ずつ * 4. 保持する型がxyz成分でなくインデックスの場合(pnt_cnt) * のいずれかでない限り[]の引数に*3が必要!! * これはvectorのように型保証で解決すべきだが * OpenGLとの互換性ために伴う変換処理を回避するため * の処置である。が... * ps : 結局複雑で管理しきれなくなったので関数の中で前後を * 囲むコピー処理を置くことで対処。これはコードの簡略化と * 同時にポインタの排除に効果アリ。 *******************************************************/ /******************************************************* * データ構造 * sface_nrm : 面の法線ベクトル * pnt_cnt : 頂点の面に対する共有カウンタ * pnt_array : ポイントをPoint形式で一時保持 * nrm_array : 法線ベクトルをPoint形式で一時保持 *******************************************************/ int i; vector > sface_nrm(m_idx_array.size()); vector > pnt_cnt; pnt_cnt.resize(m_pnt_array.size()); vector > pnt_array(m_pnt_array.size()/3); vector > nrm_array(m_pnt_array.size()/3); m_nrm_array.resize(m_pnt_array.size()); // T(doubleであることが多い) [3] から Pointへ変換 for(i=0; i < m_pnt_array.size() / 3; i++){ pnt_array[i].SetXYZ(m_pnt_array[i*3], m_pnt_array[i*3+1], m_pnt_array[i*3+2]); } // 共有カウンターセットポイントにどの面であるかを追加 // していく int sface, pnt; for(sface = 0; sface < m_idx_array.size(); sface++){ for(pnt = 0; pnt < m_idx_array[sface].size(); pnt++){ pnt_cnt[m_idx_array[sface][pnt]].push_back(sface); } } // 面の法線ベクトルを計算 // 注:法線ベクトルは頂点の順でなく面の順番でセットされる for(sface = 0; sface < m_idx_array.size(); sface++){ normal(pnt_array[m_idx_array[sface][0]], pnt_array[m_idx_array[sface][1]], pnt_array[m_idx_array[sface][2]], &sface_nrm[sface] ); } typedef std::list::iterator list_itr; // 法線ベクトルを足し合わせた後、平均化。 for(pnt = 0; pnt < nrm_array.size(); pnt++){ for(list_itr sface_itr = pnt_cnt[pnt].begin(); sface_itr != pnt_cnt[pnt].end(); sface_itr++) { nrm_array[pnt] += sface_nrm[(*sface_itr)]; } // 平均化 nrm_array[pnt] /= pnt_cnt[pnt].size(); normalize(nrm_array[pnt]); } // DrawElementsで描画するために一次元配列へコピー for(i = 0; i < m_pnt_array.size()/3; i++){ m_nrm_array[i*3] = nrm_array[i].X(); m_nrm_array[i*3+1] = nrm_array[i].Y(); m_nrm_array[i*3+2] = nrm_array[i].Z(); } } // コンストラクタ ------------------------------------------------------ template Vp::Vp(const char* filename) : m_scale(0) { ::ifstream vp(filename, ios::nocreate); if(!vp.is_open()){ throw cant_open_file("can't open file!"); } read_pnt(vp); read_idx(vp); cul_normal(); vp.close(); } // 描画関数 ----------------------------------------------------------- template void Vp::Draw() { static GLfloat spec[] = { 0.6, 0.6, 0.6, 1 }; static GLfloat shin[] = { 1.0 }; static GLfloat diff[] = { 0.8, 0.8, 0.8, 0 }; static GLfloat ambi[] = { 0.5, 0.5, 0.5, 1 }; static GLfloat l_pos[] = { 20, 20, 20, 0 }; glPushMatrix(); glMaterialfv(GL_FRONT, GL_SPECULAR, spec); glMaterialfv(GL_FRONT, GL_SHININESS, shin); glMaterialfv(GL_FRONT, GL_DIFFUSE, diff); glColor3f(1.0, 1.0, 1.0); glVertexPointer(3, GL_DOUBLE, 0, reinterpret_cast(m_pnt_array.begin()) ); glNormalPointer(GL_DOUBLE, 0, reinterpret_cast(m_nrm_array.begin()) ); glScaled(m_scale, m_scale, m_scale); for(std::vector >::iterator itr = m_idx_array.begin(); itr != m_idx_array.end(); itr++){ glDrawElements(GL_POLYGON, itr->size(), GL_UNSIGNED_INT, reinterpret_cast(itr->begin())); } glDisable(GL_LIGHTING); m_nrm_array2.resize(m_nrm_array.size()); for(int i=0; i < m_nrm_array.size(); i+=3){ glBegin(GL_LINE_STRIP); //glColor3f(0,0,0); //glVertex3d(0,0,0); glColor3f(1,1,0); m_nrm_array2[i] = m_nrm_array[i] + m_pnt_array[i]; m_nrm_array2[i+1] = m_nrm_array[i+1] + m_pnt_array[i+1]; m_nrm_array2[i+2] = m_nrm_array[i+2] + m_pnt_array[i+2]; glVertex3dv(&m_pnt_array[i]); glVertex3dv(&m_nrm_array2[i]); glEnd(); } glPopMatrix(); } } #endif // #ifndef ATS_VP_H