00001 #ifndef CDQUICKHULL3DIMP_H
00002 #define CDQUICKHULL3DIMP_H
00003
00004 #include "CDQuickHull3D.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 CDQHPlane<TVtx>::Clear(){
00014 deleted = false;
00015 }
00016 template <class TVtx>
00017 bool CDQHPlane<TVtx>::Visible(TVtx* p){
00018
00019 Vec3d GetPos = p->GetPos();
00020 return GetPos*normal > dist;
00021 }
00022 template <class TVtx>
00023 int CDQHPlane<TVtx>::GetVtxID(TVtx* v){
00024 int i;
00025 for(i=0; i<3; ++i) if(v == vtx[i]) break;
00026 return i;
00027 }
00028 template <class TVtx>
00029 void CDQHPlane<TVtx>::CalcNormal(){
00030 Vec3d pos0 = vtx[0]->GetPos();
00031 Vec3d pos1 = vtx[1]->GetPos();
00032 Vec3d pos2 = vtx[2]->GetPos();
00033 Vec3d a = pos1 - pos0;
00034 Vec3d b = pos2 - pos0;
00035 normal = a ^ b;
00036 assert(normal.norm());
00037 normal.unitize();
00038 dist = pos0 * normal;
00039 }
00040 template <class TVtx>
00041 void CDQHPlane<TVtx>::Reverse(){
00042 normal = -normal;
00043 dist = -dist;
00044 std::swap(vtx[0], vtx[2]);
00045 }
00046 template <class TVtx>
00047 double CDQHPlane<TVtx>::CalcDist(TVtx* v){
00048
00049 Vec3d vPos = v->GetPos();
00050 Vec3d diffMin = vPos - Vec3d(vtx[0]->GetPos());
00051
00052
00053
00054
00055
00056
00057 return diffMin * normal;
00058 }
00059 template <class TVtx>
00060 void CDQHPlane<TVtx>::Print(std::ostream& os) const {
00061 os << "Plane:";
00062 for(int i=0; i<3; ++i){
00063 os << " " << *vtx[i];
00064 }
00065 os << " d:" << dist << " n:" << normal;
00066 if (deleted) os << " del";
00067 os << std::endl;
00068 }
00069
00070 template <class TVtx>
00071 std::ostream& operator << (std::ostream& os, const CDQHPlane<TVtx>& pl){
00072 pl.Print(os);
00073 return os;
00074 }
00075
00076 template <class TVtx>
00077 unsigned CDQHPlanes<TVtx>::size(){
00078 return end - begin;
00079 }
00080 template <class TVtx>
00081 CDQHPlanes<TVtx>::CDQHPlanes(int l):len(l){
00082 buffer = new CDQHPlane[len];
00083 Clear();
00084 }
00085 template <class TVtx>
00086 void CDQHPlanes<TVtx>::Clear(){
00087 begin = buffer;
00088 end = begin;
00089 nPlanes = 0;
00090 }
00091 template <class TVtx>
00092 CDQHPlanes<TVtx>::~CDQHPlanes(){
00093 delete [] buffer;
00094 }
00095
00096
00097
00098
00099 template <class TVtx>
00100 void CDQHPlanes<TVtx>::CreateConvexHull(TVtx** b, TVtx** e){
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() << begin->vtx[2]->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(CDQHPlane* 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 CDQHPlanes<TVtx>::Print(std::ostream& os) const {
00123 int num=0;
00124 for(const CDQHPlane* it = begin; it != end; ++it){
00125 if (!it->deleted) num ++;
00126 }
00127 os << num << " planes." << std::endl;
00128 for(const CDQHPlane* it = begin; it != end; ++it){
00129 it->Print(os);
00130 }
00131 }
00132
00133 template <class TVtx>
00134 void CDQHPlanes<TVtx>::CreateFirstConvex(){
00135 CDQHPlanes& planes = *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
00153 std::swap(*xMaxVtx, vtxBegin[0]);
00154 if (xMinVtx == vtxBegin){
00155 std::swap(*xMaxVtx, vtxBegin[1]);
00156 }else{
00157 std::swap(*xMinVtx, vtxBegin[1]);
00158 }
00159
00160
00161 Vec3d dir = vtxBegin[1]->GetPos() - vtxBegin[0]->GetPos();
00162 dir.unitize();
00163 double maxDist = -1;
00164 TVtxs::iterator third;
00165 for(it = vtxBegin+2; it != vtxEnd; ++it){
00166 Vec3d v0 = Vec3d((*it)->GetPos()) - Vec3d(vtxBegin[0]->GetPos());
00167 Vec3d v1 = Vec3d((*it)->GetPos()) - Vec3d(vtxBegin[1]->GetPos());
00168 Vec3d v = v0.square() < v1.square() ? v0 : v1;
00169 double dist2 = v.square() - Square(v*dir);
00170 if (dist2 > maxDist){
00171 maxDist = dist2;
00172 third = it;
00173 }
00174 }
00175 std::swap(*third, vtxBegin[2]);
00176 planes.end->Clear();
00177 planes.end->vtx[0] = vtxBegin[2];
00178 planes.end->vtx[1] = vtxBegin[1];
00179 planes.end->vtx[2] = vtxBegin[0];
00180 planes.end->CalcNormal();
00181 planes.end++;
00182
00183
00184 *planes.end = *planes.begin;
00185 planes.end->Reverse();
00186 planes.begin->neighbor[0] = planes.end;
00187 planes.begin->neighbor[1] = planes.end;
00188 planes.begin->neighbor[2] = planes.end;
00189 planes.end->neighbor[0] = planes.begin;
00190 planes.end->neighbor[1] = planes.begin;
00191 planes.end->neighbor[2] = planes.begin;
00192 planes.end++;
00193
00194 vtxBegin += 3;
00195 nPlanes = 2;
00196 }
00197
00198
00199
00200 template <class TVtx>
00201 void CDQHPlanes<TVtx>::FindHorizon(TVtx*& rv, CDQHPlane* cur, TVtx* vtx){
00202
00203 for(int i=0; i<3; ++i){
00204 CDQHPlane* next = cur->neighbor[i];
00205 if (!next) continue;
00206 for(int j=0; j<3; ++j){
00207 if (next->neighbor[j] == cur){
00208 next->neighbor[j] = NULL;
00209 break;
00210 }
00211 }
00212 }
00213 cur->deleted = true;
00214 nPlanes --;
00215
00216 bool bRecurse = false;
00217 TVtx* rvc;
00218 for(int i=0; i<3; ++i){
00219 CDQHPlane* next = cur->neighbor[i];
00220 if (!next) continue;
00221 if (next->Visible(vtx) && nPlanes>1){
00222 FindHorizon(rv, next, vtx);
00223 bRecurse = true;
00224 }else{
00225
00226 cur->vtx[i]->horizon = next;
00227 rvc = cur->vtx[i];
00228 }
00229 }
00230 if (!bRecurse){
00231 rv = rvc;
00232 }
00233 }
00234
00235 template <class TVtx>
00236 void CDQHPlanes<TVtx>::CreateCone(TVtx* firstVtx, TVtx* top){
00237 CDQHPlanes& planes = *this;
00238 TVtx* curVtx = firstVtx;
00239 CDQHPlane* curHorizon = firstVtx->horizon;
00240 HULL_DEBUG_EVAL( std::cout << "Horizon:" << *curVtx; )
00241
00242 int curVtxID = curHorizon->GetVtxID(curVtx);
00243 int prevVtxID = (curVtxID+2)%3;
00244
00245 planes.end->Clear();
00246 planes.end->vtx[0] = curHorizon->vtx[curVtxID];
00247 planes.end->vtx[1] = curHorizon->vtx[prevVtxID];
00248 planes.end->vtx[2] = top;
00249 planes.end->CalcNormal();
00250
00251 planes.end->neighbor[0] = curHorizon;
00252 curHorizon->neighbor[prevVtxID] = planes.end;
00253 CDQHPlane* firstPlane = planes.end;
00254
00255 planes.end ++;
00256 nPlanes ++;
00257
00258
00259 curVtx = curHorizon->vtx[prevVtxID];
00260 curHorizon = curVtx->horizon;
00261
00262
00263 while(1){
00264 HULL_DEBUG_EVAL(std::cout << *curVtx;);
00265 int curVtxID = curHorizon->GetVtxID(curVtx);
00266 int prevVtxID = (curVtxID+2)%3;
00267
00268 planes.end->Clear();
00269 planes.end->vtx[0] = curHorizon->vtx[curVtxID];
00270 planes.end->vtx[1] = curHorizon->vtx[prevVtxID];
00271 planes.end->vtx[2] = top;
00272 planes.end->CalcNormal();
00273
00274 planes.end->neighbor[0] = curHorizon;
00275 curHorizon->neighbor[prevVtxID] = planes.end;
00276
00277 planes.end[-1].neighbor[1] = planes.end;
00278 planes.end->neighbor[2] = planes.end-1;
00279
00280 planes.end ++;
00281 if (planes.end - planes.begin > len-1){
00282 DSTR << "too many planes:" << std::endl;
00283 for(TVtx** p = vtxBeginInput; p != vtxEndInput; ++p){
00284 DSTR << (*p)->GetPos() << std::endl;
00285 }
00286 DSTR << vtxEndInput - vtxBeginInput << " vertices." << std::endl;
00287
00288 curHorizon = firstVtx->horizon;
00289 for(TVtx** p = vtxBeginInput; p != vtxEndInput; ++p){
00290 if (firstVtx == *p){
00291 DSTR << p - vtxBeginInput << " ";
00292 }
00293 }
00294 for(int i=0; i<len; ++i){
00295 curVtxID = curHorizon->GetVtxID(curVtx);
00296 prevVtxID = (curVtxID+2)%3;
00297 curVtx = curHorizon->vtx[prevVtxID];
00298 curHorizon = curVtx->horizon;
00299 for(TVtx** p = vtxBeginInput; p != vtxEndInput; ++p){
00300 if (curVtx == *p){
00301 DSTR << p - vtxBeginInput << " ";
00302 }
00303 }
00304 }
00305 DSTR << std::endl;
00306 exit(0);
00307 }
00308 nPlanes ++;
00309
00310
00311 curVtx = curHorizon->vtx[prevVtxID];
00312 if (curVtx == firstVtx) break;
00313 curHorizon = curVtx->horizon;
00314 }
00315 HULL_DEBUG_EVAL( std::cout << std::endl;);
00316
00317 firstPlane->neighbor[2] = planes.end-1;
00318 planes.end[-1].neighbor[1] = firstPlane;
00319 }
00320
00321 template <class TVtx>
00322 bool CDQHPlanes<TVtx>::FindFarthest(CDQHPlane* plane){
00323 TVtx** maxVtx=NULL;
00324 double maxDist = HULL_EPSILON;
00325 for(TVtx** it=vtxBegin; it!= vtxEnd; ++it){
00326 double dist = plane->CalcDist(*it);
00327 if (dist > maxDist){
00328 maxDist = dist;
00329 maxVtx = it;
00330 }
00331 }
00332 if (maxVtx){
00333 std::swap(*vtxBegin, *maxVtx);
00334 vtxBegin++;
00335 #ifdef _DEBUG
00336 if ( vtxBegin[-1]->GetPos() == plane->vtx[0]->GetPos()
00337 || vtxBegin[-1]->GetPos() == plane->vtx[1]->GetPos()
00338 || vtxBegin[-1]->GetPos() == plane->vtx[2]->GetPos()){
00339 DSTR << "Error: same position." << std::endl;
00340 for(int i=0; i<3; ++i){
00341 DSTR << "V" << i << ": " << plane->vtx[i]->GetPos() << std::endl;
00342 }
00343 DSTR << "P : " << vtxBegin[-1]->GetPos() << std::endl;
00344 assert(0);
00345 }
00346 #endif
00347 return true;
00348 }
00349 return false;
00350 }
00351
00352
00353
00354 template <class TVtx>
00355 TVtx** CDQHPlanes<TVtx>::DivideByPlaneR(CDQHPlane* plane, TVtx** start, TVtx** end){
00356 double INNER_DISTANCE = HULL_EPSILON * plane->dist;
00357 while(start != end){
00358 double d = -plane->CalcDist(*start);
00359 if (d <= INNER_DISTANCE){
00360 -- end;
00361 std::swap(*end, *start);
00362 }else{
00363 ++ start;
00364 }
00365 }
00366 return start;
00367 }
00368
00369
00370
00371 template <class TVtx>
00372 TVtx** CDQHPlanes<TVtx>::DivideByPlane(CDQHPlane* plane, TVtx** start, TVtx** end){
00373 double INNER_DISTANCE = HULL_EPSILON * plane->dist;
00374 while(start != end){
00375 double d = plane->CalcDist(*start);
00376 if (d <= INNER_DISTANCE){
00377 -- end;
00378 std::swap(*end, *start);
00379 }else{
00380 ++ start;
00381 }
00382 }
00383 return start;
00384 }
00385
00386
00387 template <class TVtx>
00388 void CDQHPlanes<TVtx>::TreatPlane(CDQHPlane* cur){
00389 if (!FindFarthest(cur)) return;
00390 HULL_DEBUG_EVAL(
00391 DSTR << "Farthest:" << vtxBegin[-1]->GetPos();
00392 DSTR << " cmp:" << vtxBegin[-1]->GetPos()*cur->normal << " > " << cur->dist << std::endl;
00393 if (cur->dist < 0){
00394 DSTR << "faceDist:" << cur->dist << std::endl;
00395 }
00396 )
00397
00398 TVtx* hor=NULL;
00399 FindHorizon(hor, cur, vtxBegin[-1]);
00400 HULL_DEBUG_EVAL(
00401 if (!hor){
00402 DSTR << "No Horizon Error!!" << std::endl;
00403 assert(hor);
00404 }
00405 )
00406
00407 CDQHPlane* coneBegin = end;
00408 CreateCone(hor, vtxBegin[-1]);
00409 CDQHPlane* coneEnd = end;
00410
00411 TVtx** inner = DivideByPlaneR(cur, vtxBegin, vtxEnd);
00412 for(CDQHPlane* it=coneBegin; it!=coneEnd; ++it){
00413 if (it->deleted) continue;
00414 HULL_DEBUG_EVAL(
00415 std::cout << "Inner:";
00416 for(TVtx** v = inner; v != vtxEnd; ++v){
00417 std::cout << **v;
00418 }
00419 std::cout << std::endl;
00420 );
00421 inner = DivideByPlane(it, inner, vtxEnd);
00422 }
00423 HULL_DEBUG_EVAL(
00424 std::cout << "InnerFinal:";
00425 for(TVtx** v = inner; v != vtxEnd; ++v){
00426 std::cout << **v;
00427 }
00428 std::cout << std::endl;
00429 );
00430
00431 vtxEnd = inner;
00432 }
00433
00434 template <class TVtx>
00435 std::ostream& operator << (std::ostream& os, const CDQHPlanes<TVtx>& pls){
00436 pls.Print(os);
00437 return os;
00438 }
00439 template <class TVtx>
00440 inline std::ostream& operator << (std::ostream& os, const TYPENAME CDQHPlanes<TVtx>::TVtxs& f){
00441 f.Print(os); return os;
00442 }
00443
00444 inline Vec3f CDQHVtx3DSample::GetPos() const {
00445 return dir * dist;
00446 }
00447 inline void CDQHVtx3DSample::SetPos(Vec3f p){
00448 float d = p.norm();
00449 dir = p / d;
00450 dist = d;
00451 }
00452 inline void CDQHVtx3DSample::Print(std::ostream& os) const {
00453
00454 os << id_ << " ";
00455 }
00456 inline std::ostream& operator << (std::ostream& os, const CDQHVtx3DSample& f){
00457 f.Print(os); return os;
00458 }
00459
00460 }
00461
00462 #endif