00001 #ifndef CDQUICKHULL3D_H 00002 #define CDQUICKHULL3D_H 00003 00004 #include <Base/Affine.h> 00005 #include <Base/TQuaternion.h> 00006 #include <iosfwd> 00007 #include <vector> 00008 00009 #define HULL_EPSILON 1e-6f ///< QuickHullで扱う最小の数値 00010 #define HULL_INFINITE 1e8f ///< QuickHullで扱う最大の数値 00011 00012 //#define HULL_DEBUG // デバッグ出力 00013 #ifdef HULL_DEBUG 00014 #define HULL_DEBUG_EVAL(x) x 00015 #else 00016 #define HULL_DEBUG_EVAL(x) 00017 #endif 00018 00019 namespace Spr{; 00020 00021 /// QuickHullで作られる面 00022 template <class TVtx> 00023 class CDQHPlane{ 00024 public: 00025 Vec3d normal; ///< 面の法線 00026 double dist; ///< 面の原点からの距離 00027 00028 TVtx* vtx[3]; ///< 面を構成する頂点 00029 CDQHPlane* neighbor[3]; ///< 隣の面 vtx[0]-vtx[1] の隣が neighbor[0] 00030 bool deleted; ///< 削除された面はtrue 00031 void Clear(); ///< メモリクリア.使う前に呼ぶ. 00032 bool Visible(TVtx* p); ///< 頂点 v から表側が見えるかどうか 00033 /// vの頂点番号を返す(0..2を返す).見つからなければ3を返す. 00034 int GetVtxID(TVtx* v); 00035 void CalcNormal(); ///< 法線ベクトルと距離を計算する. 00036 void Reverse(); ///< 表裏をひっくり返す. 00037 /// 点との距離を計算する.精度を考慮して一番近い点で計算する. 00038 double CalcDist(TVtx* v); 00039 /// デバッグ用表示 00040 void Print(std::ostream& os) const; 00041 }; 00042 00043 /// 面のバッファ 00044 template <class TVtx> 00045 class CDQHPlanes{ 00046 public: 00047 TVtx** vtxBeginInput; ///< 残っている頂点の先頭 00048 TVtx** vtxEndInput; ///< 残っている頂点の最後の次 00049 /// 頂点のVector 00050 class TVtxs: public std::vector<TVtx*>{ 00051 public: 00052 void Print(std::ostream& os) const{ 00053 for(TVtxs::const_iterator it = begin(); it != end(); ++it){ 00054 (*it)->Print(os); 00055 } 00056 } 00057 }; 00058 typedef CDQHPlane<TVtx> CDQHPlane; 00059 00060 CDQHPlane* buffer; ///< バッファへのポインタ new する. 00061 int len; ///< バッファの長さ 00062 CDQHPlane* begin; ///< 最初の面 00063 CDQHPlane* end; ///< 最後の面の次 00064 TVtx** vtxBegin; ///< 残っている頂点の先頭 00065 TVtx** vtxEnd; ///< 残っている頂点の最後の次 00066 int nPlanes; ///< 面の数 00067 unsigned size(); ///< 使用済みバッファのサイズ 00068 CDQHPlanes(int l); 00069 void Clear(); 00070 ~CDQHPlanes(); 00071 /** bからeまでの頂点から凸包を作る.使用した頂点はbからvtxBegin, 00072 使用しなかった頂点は,vtxBeginからeに移動する. 00073 beginからendは頂点を3つ含む面になる.それらの面うち凸包に使われた面 00074 は CDQHPlane::deleted が false になっている. */ 00075 void CreateConvexHull(TVtx** b, TVtx** e); 00076 void Print(std::ostream& os) const; 00077 00078 private: 00079 /** 最初の凸多面体=2枚の三角形(表裏)を作る. 00080 できるだけ大きい3角形を作ると効率が良いので,x最大,x最小, 00081 2点が作る直線から一番遠い頂点で3角形を作る. 00082 使用した頂点は,vtxBeginの手前に移動して,頂点リストからはずす. 00083 */ 00084 void CreateFirstConvex(); 00085 /** horizon を作る. cur が穴をあける面,vtx が新しい頂点. 00086 rv にhorizonを辺に持つ3角形を1つ返す.*/ 00087 void FindHorizon(TVtx*& rv, CDQHPlane* cur, TVtx* vtx); 00088 /** 頂点とhorizonの間にコーンを作る.*/ 00089 void CreateCone(TVtx* firstVtx, TVtx* top); 00090 /** 一番遠くの頂点を見つける.見つけたらそれを頂点リストからはずす */ 00091 bool FindFarthest(CDQHPlane* plane); 00092 /* 外側 内側 の順に並べる. 00093 外側の終わり=内側の始まりが inner */ 00094 TVtx** DivideByPlaneR(CDQHPlane* plane, TVtx** start, TVtx** end); 00095 TVtx** DivideByPlane(CDQHPlane* plane, TVtx** start, TVtx** end); 00096 /** 一つの面に対する処理を行う.一番遠くの頂点を見つけ, 00097 地平線を調べ,コーンを作り,内部の頂点をはずす.*/ 00098 void TreatPlane(CDQHPlane* cur); 00099 }; 00100 00101 /// 頂点クラスの例 00102 class CDQHVtx3DSample{ 00103 public: 00104 ///@name QuickHullが使用するメンバ.必須. 00105 //@{ 00106 /** QuickHullアルゴリズム用ワークエリア. 00107 一番遠い頂点から見える面を削除したあと残った形状のエッジ部分 00108 を一周接続しておくためのポインタ. 00109 頂点→面の接続. 面→頂点は頂点の並び順から分かる. */ 00110 CDQHPlane<CDQHVtx3DSample>* horizon; 00111 /// 頂点の位置 00112 Vec3f GetPos() const; 00113 //@} 00114 /// 位置の設定 00115 void SetPos(Vec3f p); 00116 public: 00117 Vec3f dir; ///< 原点からの向き 00118 float dist; ///< 原点からの距離 00119 public: 00120 int id_; 00121 00122 /// デバッグ用表示 00123 void Print(std::ostream& os) const; 00124 }; 00125 00126 } 00127 00128 #endif