メインページ | ネームスペース一覧 | クラス階層 | 構成 | Directories | ファイル一覧 | ネームスペースメンバ | 構成メンバ | ファイルメンバ | 関連ページ

CDQuickHull2DImp.h

00001 #ifndef CDQUICKHULL2DIMP_H
00002 #define CDQUICKHULL2DIMP_H
00003 
00004 #include "CDQuickHull2D.h"
00005 #include <Base/Affine.h>
00006 #include <Base/BaseDebug.h>
00007 #include <vector>
00008 #include <float.h>
00009 
00010 namespace Spr{;
00011 
00012 template <class TVtx>
00013 void CDQHLine<TVtx>::Clear(){           ///<    メモリクリア.使う前に呼ぶ.
00014     deleted = false;
00015 }
00016 template <class TVtx>
00017 bool CDQHLine<TVtx>::Visible(TVtx* p){
00018     Vec2d pos = p->GetPos();
00019     return pos*normal > dist;
00020 }
00021 template <class TVtx>
00022 int CDQHLine<TVtx>::GetVtxID(TVtx* v){
00023     int i;
00024     for(i=0; i<2; ++i) if(v == vtx[i]) break;
00025     return i;
00026 }
00027 template <class TVtx>
00028 void CDQHLine<TVtx>::CalcNormal(){
00029     Vec2d pos0 = vtx[0]->GetPos();
00030     Vec2d pos1 = vtx[1]->GetPos();
00031     Vec2d a = pos1 - pos0;
00032     normal = Vec2d(-a.y, a.x);
00033     assert(normal.norm());
00034     normal.unitize();
00035     dist = pos0 * normal;
00036 }
00037 template <class TVtx>
00038 double CDQHLine<TVtx>::CalcDist(TVtx* v){
00039     Vec2d vPos = v->GetPos();
00040     Vec2d diffMin = vPos - Vec2d(vtx[0]->GetPos());
00041     return diffMin * normal;
00042 }
00043 template <class TVtx>
00044 void CDQHLine<TVtx>::Print(std::ostream& os) const {
00045     os << "Plane:";
00046     for(int i=0; i<2; ++i){
00047         os << " " << *vtx[i];
00048     }
00049     os << " d:" << dist << " n:" << normal;
00050     if (deleted) os << " del";
00051     os << std::endl;
00052 }
00053 
00054 template <class TVtx>
00055 std::ostream& operator << (std::ostream& os, const CDQHLine<TVtx>& pl){
00056     pl.Print(os);
00057     return os;
00058 }
00059 
00060 template <class TVtx>
00061 unsigned CDQHLines<TVtx>::size(){
00062     return end - begin; 
00063 }
00064 template <class TVtx>
00065 CDQHLines<TVtx>::CDQHLines(int l):len(l), epsilon(1e-6), infinite(1e8){
00066     buffer = new CDQHLine[len];
00067     Clear();
00068 }
00069 template <class TVtx>
00070 void CDQHLines<TVtx>::Clear(){
00071     begin = buffer;
00072     end = begin;
00073     nLines = 0;
00074 }
00075 template <class TVtx>
00076 void CDQHLine<TVtx>::Reverse(){ 
00077     normal = -normal;
00078     dist = -dist;
00079     std::swap(vtx[0], vtx[1]);
00080 }
00081 template <class TVtx>
00082 CDQHLines<TVtx>::~CDQHLines(){
00083     delete [] buffer;
00084 }
00085 /** bからeまでの頂点から凸包を作る.使用した頂点はbからvtxBegin,
00086 使用しなかった頂点は,vtxBeginからeに移動する. 
00087 beginからendは頂点を3つ含む面になる.それらの面うち凸包に使われた面
00088 は CDQHLine::deleted が false になっている.    */
00089 template <class TVtx>
00090 void CDQHLines<TVtx>::CreateConvexHull(TVtx** b, TVtx** e){
00091     if (e-b < 2){
00092         if (e-b == 1){
00093             end->Clear();
00094             end->vtx[0] = b[0];
00095             end->vtx[1] = b[0];
00096             end->neighbor[0] = end->neighbor[1] = end;
00097             end++;
00098         }
00099         return;
00100     }
00101     vtxBeginInput = b;
00102     vtxEndInput = e;
00103     vtxBegin = b;
00104     vtxEnd = e;
00105     //  最初の面を作る
00106     CreateFirstConvex();
00107     HULL_DEBUG_EVAL(
00108         DSTR << "First:" << begin->vtx[0]->GetPos() << begin->vtx[1]->GetPos() << std::endl;
00109         if ((begin->vtx[1]->GetPos() - begin->vtx[0]->GetPos()).norm() < 0.001) {
00110             DSTR << "same error" << std::endl;
00111         }
00112         DSTR << begin->dist << begin->normal << std::endl;
00113     )
00114     for(CDQHLine* cur = begin; cur != end; ++cur){
00115         if (cur->deleted) continue;
00116         TreatPlane(cur);
00117         assert(end < buffer+len);
00118     }
00119 }
00120     
00121 template <class TVtx>
00122 void CDQHLines<TVtx>::Print(std::ostream& os) const {
00123     int num=0;
00124     for(const CDQHLine* it = begin; it != end; ++it){
00125         if (!it->deleted) num ++;
00126     }
00127     os << num << " lines." << std::endl;
00128     for(const CDQHLine* it = begin; it != end; ++it){
00129         it->Print(os);
00130     }
00131 }
00132 
00133 template <class TVtx>
00134 void CDQHLines<TVtx>::CreateFirstConvex(){
00135     CDQHLines& lines = *this;
00136     double xMin, xMax;
00137     TVtxs::iterator it, xMinVtx, xMaxVtx;
00138     xMin = xMax = (*vtxBegin)->GetPos().X();
00139     xMinVtx = xMaxVtx = vtxBegin;
00140     //  最大と最小を見つける
00141     for(it = vtxBegin+1; it != vtxEnd; ++it){
00142         double x = (*it)->GetPos().X();
00143         if (x < xMin){
00144             xMin = x;
00145             xMinVtx = it;
00146         }
00147         if (x > xMax){
00148             xMax = x;
00149             xMaxVtx = it;
00150         }
00151     }
00152     //  最大を最初,最小を最初から2番目に置く
00153     std::swap(*xMaxVtx, vtxBegin[0]);       //  先頭と最大を入れ替え
00154     if (xMinVtx == vtxBegin){               //  先頭が最小だったら
00155         std::swap(*xMaxVtx, vtxBegin[1]);   //  最大だった場所=先頭が入っている場所が最小
00156     }else{
00157         std::swap(*xMinVtx, vtxBegin[1]);   //  最小を先頭から2番目と入れ替え
00158     }
00159 
00160     //  最初の辺を作る
00161     lines.end->Clear();
00162     lines.end->vtx[0] = vtxBegin[1];
00163     lines.end->vtx[1] = vtxBegin[0];
00164     lines.end->CalcNormal();
00165     lines.end++;
00166     
00167     //  裏表を作って最初の凸多面体にする.
00168     *lines.end = *lines.begin;
00169     lines.end->Reverse();
00170     lines.begin->neighbor[0] = lines.end;
00171     lines.begin->neighbor[1] = lines.end;
00172     lines.end->neighbor[0] = lines.begin;
00173     lines.end->neighbor[1] = lines.begin;
00174     lines.end++;
00175     //  使用した頂点を頂点リストからはずす.
00176     vtxBegin += 2;
00177     nLines = 2;
00178 }
00179 
00180 /** 辺curと,その面から一番遠い頂点 top を受け取り,
00181     curとその周囲の辺を削除し,凸包にtopを含める.
00182     end[-1], end[-2]が新たに作られた辺になる.  */
00183 template <class TVtx>
00184 void CDQHLines<TVtx>::CreateCone(CDQHLine* cur, TVtx* top){
00185     cur->deleted = true;                            //  curは削除
00186     nLines --;
00187     //  隣の辺を見ていって,頂点からみえる辺は削除する.
00188     CDQHLine* horizon[2];
00189     for(int i=0; i<2; ++i){
00190         horizon[i] = cur->neighbor[i];
00191         while(horizon[i]->Visible(top) && nLines>1){
00192             horizon[i]->deleted = true;
00193             nLines --;
00194             horizon[i] = horizon[i]->neighbor[i];
00195         }
00196     }
00197     //  削除されなかった辺と頂点の間に辺を作る.
00198     //  horizon[0]側の辺
00199     end->Clear();
00200     horizon[0]->neighbor[1] = end;
00201     end->vtx[0] = horizon[0]->vtx[1];
00202     end->vtx[1] = top;
00203     end->neighbor[0] = horizon[0];
00204     end->neighbor[1] = end+1;
00205     end->CalcNormal();
00206     end++;
00207     nLines ++;
00208     //  horizon[1]側の辺
00209     end->Clear();
00210     horizon[1]->neighbor[0] = end;
00211     end->vtx[0] = top;
00212     end->vtx[1] = horizon[1]->vtx[0];
00213     end->neighbor[0] = end-1;
00214     end->neighbor[1] = horizon[1];
00215     end->CalcNormal();
00216     end++;
00217     nLines ++;
00218 }   
00219 /** 一番遠くの頂点を見つける.見つけたらそれを頂点リストからはずす  */
00220 template <class TVtx>
00221 bool CDQHLines<TVtx>::FindFarthest(CDQHLine* line){
00222     TVtx** maxVtx=NULL;
00223     double maxDist = epsilon;
00224     for(TVtx** it=vtxBegin; it!= vtxEnd; ++it){
00225         double dist = line->CalcDist(*it);
00226         if (dist > maxDist){
00227             maxDist = dist; 
00228             maxVtx = it;
00229         }
00230     }
00231     if (maxVtx){
00232         std::swap(*vtxBegin, *maxVtx);
00233         vtxBegin++;
00234 #ifdef _DEBUG
00235         if (    vtxBegin[-1]->GetPos() == line->vtx[0]->GetPos()
00236             ||  vtxBegin[-1]->GetPos() == line->vtx[1]->GetPos()){
00237             DSTR << "Error: same position." << std::endl;
00238             for(int i=0; i<2; ++i){
00239                 DSTR << "V" << i << ": " << line->vtx[i]->GetPos() << std::endl;
00240             }
00241             DSTR << "P : " << vtxBegin[-1]->GetPos() << std::endl;
00242             assert(0);
00243         }
00244 #endif
00245         return true;
00246     }
00247     return false;
00248 }
00249 /*  外側 内側 の順に並べる.
00250 外側の終わり=内側の始まりが inner  */
00251 template <class TVtx>
00252 TVtx** CDQHLines<TVtx>::DivideByPlaneR(CDQHLine* plane, TVtx** start, TVtx** end){
00253     double INNER_DISTANCE = epsilon * plane->dist;
00254     while(start != end){
00255         double d = -plane->CalcDist(*start);
00256         if (d <= INNER_DISTANCE){   //  内側の場合は後ろに移動
00257             -- end;
00258             std::swap(*end, *start);
00259         }else{
00260             ++ start;
00261         }
00262     }
00263     return start;
00264 }
00265 template <class TVtx>
00266 TVtx** CDQHLines<TVtx>::DivideByPlane(CDQHLine* plane, TVtx** start, TVtx** end){
00267     double INNER_DISTANCE = epsilon * plane->dist;
00268     while(start != end){
00269         double d = plane->CalcDist(*start);
00270         if (d <= INNER_DISTANCE){   //  内側の場合は後ろに移動
00271             -- end;
00272             std::swap(*end, *start);
00273         }else{
00274             ++ start;
00275         }
00276     }
00277     return start;
00278 }
00279 /** 一つの面に対する処理を行う.一番遠くの頂点を見つけ,
00280 地平線を調べ,コーンを作り,内部の頂点をはずす.*/
00281 template <class TVtx>
00282 void CDQHLines<TVtx>::TreatPlane(CDQHLine* cur){
00283     //  一番遠くの頂点の探索
00284     if (!FindFarthest(cur)) return;
00285     HULL_DEBUG_EVAL(
00286         DSTR << "Farthest:" << vtxBegin[-1]->GetPos();
00287         DSTR << " cmp:" << vtxBegin[-1]->GetPos()*cur->normal << " > " << cur->dist << std::endl;
00288         if (cur->dist < 0){
00289             DSTR << "faceDist:" << cur->dist << std::endl;
00290         }
00291     )
00292     //  新しい頂点で凸包を作る.
00293     CreateCone(cur, vtxBegin[-1]);
00294     HULL_DEBUG_EVAL(
00295         if (!hor){
00296             DSTR << "No Horizon Error!!" << std::endl;
00297             assert(hor);
00298         }
00299     )
00300     //  注目した辺(cur)と新たな辺(end-2,end-1)によって閉じ込められる頂点をvtxEndの後ろに移動
00301     TVtx** inner = DivideByPlaneR(cur, vtxBegin, vtxEnd);
00302     for(CDQHLine* it=end-2; it!=end; ++it){
00303         HULL_DEBUG_EVAL(
00304             std::cout << "Inner:";
00305             for(TVtx** v = inner; v != vtxEnd; ++v){
00306                 std::cout << **v;
00307             }
00308             std::cout << std::endl;
00309         );
00310         inner = DivideByPlane(it, inner, vtxEnd);
00311     }
00312     HULL_DEBUG_EVAL(
00313         std::cout << "InnerFinal:";
00314         for(TVtx** v = inner; v != vtxEnd; ++v){
00315             std::cout << **v;
00316         }
00317         std::cout << std::endl;
00318     );
00319     vtxEnd = inner;
00320 }
00321 
00322 template <class TVtx>
00323 std::ostream& operator << (std::ostream& os, const CDQHLines<TVtx>& pls){
00324     pls.Print(os);
00325     return os;
00326 }
00327 template <class CDQHVtx2DSample>
00328 inline std::ostream& operator << (std::ostream& os, const TYPENAME CDQHLines<CDQHVtx2DSample>::TVtxs& f){
00329     f.Print(os); return os;
00330 }
00331 
00332 inline void CDQHVtx2DSample::Print(std::ostream& os) const {
00333 //      os << Vtx();
00334         os << id_ << " ";
00335 }
00336 inline std::ostream& operator << (std::ostream& os, const CDQHVtx2DSample& f){
00337     f.Print(os); return os;
00338 }
00339 
00340 }
00341 
00342 #endif

Springheadに対してSun Apr 16 01:57:49 2006に生成されました。  doxygen 1.4.1