00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef __PICK______H
00025 #define __PICK______H
00026
00027 #include <vector>
00028 #include <algorithm>
00029 namespace vcg{
00030
00031 template <class MESH_TYPE>
00032 class GLPickTri
00033 {
00034 typedef typename MESH_TYPE::ScalarType ScalarType;
00035 typedef typename MESH_TYPE::CoordType CoordType;
00036 typedef typename MESH_TYPE::FaceIterator FaceIterator;
00037 typedef typename MESH_TYPE::VertexIterator VertexIterator;
00038 typedef typename MESH_TYPE::FacePointer FacePointer;
00039 typedef typename MESH_TYPE::VertexPointer VertexPointer;
00040 typedef typename MESH_TYPE::VertexType VertexType;
00041
00042 private:
00043
00044 static CoordType Proj(const Eigen::Matrix<ScalarType,4,4> &M, const ScalarType * viewport, const CoordType &p)
00045 {
00046 const ScalarType vx=viewport[0];
00047 const ScalarType vy=viewport[1];
00048 const ScalarType vw2=viewport[2]/ScalarType(2.0);
00049 const ScalarType vh2=viewport[3]/ScalarType(2.0);
00050 Eigen::Matrix<ScalarType,4,1> vp(p[0],p[1],p[2],ScalarType(1.0));
00051 Eigen::Matrix<ScalarType,4,1> vpp = M*vp;
00052 Eigen::Matrix<ScalarType,4,1> ndc = vpp/vpp[3];
00053
00054 CoordType sc(
00055 vw2*ndc[0] + vx+vw2,
00056 vh2*ndc[1] + vy+vh2,
00057 ndc[2]
00058 );
00059
00060 return sc;
00061 }
00062
00063 static void FillProjectedVector(MESH_TYPE &m, std::vector<CoordType> &pVec, const Eigen::Matrix<ScalarType,4,4> &M, const ScalarType * viewportF)
00064 {
00065 pVec.resize(m.vert.size());
00066 for(size_t i=0;i<m.vert.size();++i) if(!m.vert[i].IsD())
00067 {
00068 pVec[i] = Proj(M, viewportF,CoordType::Construct(m.vert[i].P()));
00069 }
00070 }
00071
00072 static void glGetMatrixAndViewport(Eigen::Matrix<ScalarType,4,4> &M, ScalarType *viewportF)
00073 {
00074 Eigen::Matrix4d mp,mm;
00075
00076 GLint viewport[4];
00077 glGetIntegerv(GL_VIEWPORT,viewport);
00078 for(int i=0;i<4;++i) viewportF[i]=viewport[i];
00079
00080 glGetDoublev(GL_PROJECTION_MATRIX, mp.data());
00081 glGetDoublev(GL_MODELVIEW_MATRIX, mm.data());
00082
00083 M = (mp*mm).cast<ScalarType>();
00084 }
00085
00086
00087 static Box3<ScalarType> ComputeDCBox(int x, int y, int width, int height)
00088 {
00089 Box3<ScalarType> bb;
00090 bb.SetNull();
00091 bb.Add(CoordType(x-width/ScalarType(2.0),y-height/ScalarType(2.0),ScalarType(-1.0)));
00092 bb.Add(CoordType(x+width/ScalarType(2.0),y+height/ScalarType(2.0), ScalarType(1.0)));
00093 return bb;
00094 }
00095
00096 public:
00097
00098 static bool PickClosestFace(int x, int y, MESH_TYPE &m, FacePointer &fp,int width=4, int height=4)
00099 {
00100 Eigen::Matrix<ScalarType,4,4> M;
00101 ScalarType viewportF[4];
00102 glGetMatrixAndViewport(M,viewportF);
00103 Box3<ScalarType> reg=ComputeDCBox(x,y,width,height);
00104
00105 ScalarType bzmin = std::numeric_limits<ScalarType>::max();
00106 fp=0;
00107 for(size_t i=0;i<m.face.size();++i) if(!m.face[i].IsD())
00108 {
00109 CoordType bary = vcg::Barycenter(m.face[i]);
00110 CoordType bz = Proj(M, viewportF,bary);
00111
00112 if(bz[2]<bzmin && reg.IsIn(bz))
00113 {
00114 bzmin=bz[2];
00115 fp = &m.face[i];
00116 }
00117 }
00118 return fp!=0;
00119 }
00120
00121 static bool PickClosestVert(int x, int y, MESH_TYPE &m, VertexPointer &vp,int width=4, int height=4)
00122 {
00123 Eigen::Matrix<ScalarType,4,4> M;
00124 ScalarType viewportF[4];
00125 glGetMatrixAndViewport(M,viewportF);
00126 ScalarType bzmin = std::numeric_limits<ScalarType>::max();
00127 vp=0;
00128
00129 Box3<ScalarType> reg=ComputeDCBox(x,y,width,height);
00130
00131 for(size_t i=0;i<m.vert.size();++i) if(!m.vert[i].IsD())
00132 {
00133 CoordType bz = Proj(M, viewportF,m.vert[i].P());
00134 if(bz[2]<bzmin && reg.IsIn(bz))
00135 {
00136 bzmin=bz[2];
00137 vp = &m.vert[i];
00138 }
00139 }
00140 return vp!=0;
00141 }
00142
00143 static int PickVert(int x, int y, MESH_TYPE &m, std::vector<VertexPointer> &result, int width=4, int height=4)
00144 {
00145 result.clear();
00146 static Eigen::Matrix<ScalarType,4,4> lastM;
00147 static MESH_TYPE *lastm=0;
00148 static std::vector<CoordType> pVec;
00149
00150 Eigen::Matrix<ScalarType,4,4> M;
00151 ScalarType viewportF[4];
00152 glGetMatrixAndViewport(M,viewportF);
00153
00154 Box3<ScalarType> reg =ComputeDCBox(x,y,width,height);
00155
00156 if(M!=lastM || &m != lastm)
00157 {
00158 FillProjectedVector(m,pVec,M,viewportF);
00159 lastM = M;
00160 lastm = &m;
00161 }
00162
00163 for(size_t i=0;i<m.vert.size();++i) if(!m.vert[i].IsD())
00164 {
00165 if(reg.IsIn(pVec[i]))
00166 result.push_back(&m.vert[i]);
00167 }
00168 return result.size();
00169 }
00170
00171 static int PickFace(int x, int y, MESH_TYPE &m, std::vector<FacePointer> &result, int width=4, int height=4)
00172 {
00173 static Eigen::Matrix<ScalarType,4,4> lastM;
00174 static MESH_TYPE *lastm=0;
00175 static std::vector<CoordType> pVec;
00176
00177 ScalarType viewportF[4];
00178 Eigen::Matrix<ScalarType,4,4> M;
00179 glGetMatrixAndViewport(M,viewportF);
00180 result.clear();
00181 Box3<ScalarType> reg;
00182 reg.Add(CoordType(x-width/ScalarType(2.0),y-height/ScalarType(2.0),ScalarType(-1.0)));
00183 reg.Add(CoordType(x+width/ScalarType(2.0),y+height/ScalarType(2.0),ScalarType(1.0)));
00184
00185 if(M!=lastM || &m != lastm)
00186 {
00187 FillProjectedVector(m,pVec,M,viewportF);
00188 lastM = M;
00189 lastm = &m;
00190 }
00191
00192 for(size_t i=0;i<m.face.size();++i) if(!m.face[i].IsD())
00193 {
00194 const CoordType &p0 = pVec[tri::Index(m,m.face[i].V(0))];
00195 const CoordType &p1 = pVec[tri::Index(m,m.face[i].V(1))];
00196 const CoordType &p2 = pVec[tri::Index(m,m.face[i].V(2))];
00197 if( (p0[2]>-1.0f) && (p1[2]>-1.0f) && (p2[2]>-1.0f) && IntersectionTriangleBox(reg,p0,p1,p2))
00198 result.push_back(&m.face[i]);
00199 }
00200 return result.size();
00201 }
00202
00203
00204
00205 static int PickVisibleFace(int x, int y, MESH_TYPE &m, std::vector<FacePointer> &resultZ, int width=4, int height=4)
00206 {
00207 ScalarType vp[4];
00208 Eigen::Matrix<ScalarType,4,4> M;
00209 glGetMatrixAndViewport(M,vp);
00210
00211 int screenW = (int)(vp[2]-vp[0]);
00212 int screenH = (int)(vp[3]-vp[1]);
00213
00214 GL_TYPE_NM<Scalarm>::ScalarType *buffer = new GL_TYPE_NM<Scalarm>::ScalarType[screenW*screenH];
00215
00216
00217
00218 glReadPixels(vp[0],vp[1],vp[2],vp[3],GL_DEPTH_COMPONENT,GL_TYPE_NM<Scalarm>::SCALAR(),buffer);
00219
00220 std::vector<FacePointer> result;
00221 PickFace(x,y,m,result,width,height);
00222 ScalarType LocalEpsilon(0.001);
00223 for(size_t i =0;i<result.size();++i)
00224 {
00225 CoordType p = Proj(M,vp,CoordType::Construct(Barycenter(*(result[i])))) ;
00226 if(p[0] >=0 && p[0]<screenW && p[1] >=0 && p[1]<screenH)
00227 {
00228 ScalarType bufZ(buffer[int(p[0])+int(p[1])*screenW]);
00229
00230 if(bufZ + LocalEpsilon >= ScalarType(p[2]+1.0)/2.0)
00231 resultZ.push_back(result[i]);
00232 }
00233 }
00234
00235 delete [] buffer;
00236 return resultZ.size();
00237 }
00238
00239
00240
00241
00242
00243 static int OldPickFaceVisible(int x, int y, MESH_TYPE &m, std::vector<FacePointer> &resultZ, int width=4, int height=4, bool sorted=true)
00244 {
00245
00246
00247 double mm[16];
00248 double mp[16];
00249 GLint vp[4];
00250 glGetIntegerv(GL_VIEWPORT,vp);
00251 glGetDoublev(GL_MODELVIEW_MATRIX ,mm);
00252 glGetDoublev(GL_PROJECTION_MATRIX ,mp);
00253 int screenW = vp[2]-vp[0];
00254 int screenH = vp[3]-vp[1];
00255
00256
00257 GL_TYPE_NM<Scalarm>::ScalarType *buffer = new GL_TYPE_NM<Scalarm>::ScalarType[screenW*screenH];
00258
00259
00260
00261 glReadPixels(vp[0],vp[1],vp[2],vp[3],GL_DEPTH_COMPONENT,GL_TYPE_NM<Scalarm>::SCALAR(),buffer);
00262
00263
00264 std::vector<FacePointer> result;
00265 OldPickFace(x,y,m,result,width,height,sorted);
00266 ScalarType LocalEpsilon(0.001);
00267 for(size_t i =0;i<result.size();++i)
00268 {
00269 CoordType v=Barycenter(*(result[i]));
00270 GLdouble tx,ty,tz;
00271 gluProject(v.X(),v.Y(),v.Z(), mm,mp,vp, &tx,&ty,&tz);
00272 if(tx >=0 && tx<screenW && ty >=0 && ty<screenH)
00273 {
00274 ScalarType bufZ(buffer[int(tx)+int(ty)*screenW]);
00275
00276 if(bufZ + LocalEpsilon >= tz)
00277 resultZ.push_back(result[i]);
00278 }
00279 }
00280
00281 delete [] buffer;
00282 return resultZ.size();
00283 }
00284
00285
00286 static int OldPickFace(int x, int y, MESH_TYPE &m, std::vector<FacePointer> &result, int width=4, int height=4,bool sorted=true)
00287 {
00288 result.clear();
00289 if(width==0 ||height==0) return 0;
00290 long hits;
00291 int sz=m.face.size()*5;
00292 GLuint *selectBuf =new GLuint[sz];
00293
00294 glSelectBuffer(sz, selectBuf);
00295 glRenderMode(GL_SELECT);
00296 glInitNames();
00297
00298
00299 glPushName(-1);
00300 double mp[16];
00301
00302 GLint viewport[4];
00303 glGetIntegerv(GL_VIEWPORT,viewport);
00304 glMatrixMode(GL_PROJECTION);
00305 glGetDoublev(GL_PROJECTION_MATRIX ,mp);
00306 glPushMatrix();
00307 glLoadIdentity();
00308
00309 gluPickMatrix(x, y, width, height, viewport);
00310 glMultMatrixd(mp);
00311
00312 glMatrixMode(GL_MODELVIEW);
00313 glPushMatrix();
00314 int fcnt=0;
00315 FaceIterator fi;
00316 for(fi=m.face.begin();fi!=m.face.end();++fi)
00317 {
00318 if(!(*fi).IsD())
00319 {
00320 glLoadName(fcnt);
00321 glBegin(GL_TRIANGLES);
00322 glVertex( (*fi).V(0)->P() );
00323 glVertex( (*fi).V(1)->P() );
00324 glVertex( (*fi).V(2)->P() );
00325 glEnd();
00326 }
00327 fcnt++;
00328 }
00329
00330 glPopMatrix();
00331 glMatrixMode(GL_PROJECTION);
00332 glPopMatrix();
00333 glMatrixMode(GL_MODELVIEW);
00334 hits = glRenderMode(GL_RENDER);
00335
00336
00337 std::vector< std::pair<double,unsigned int> > H;
00338 for(long ii=0;ii<hits;ii++){
00339
00340 H.push_back( std::pair<double,unsigned int>(selectBuf[ii*4+1]/4294967295.0,selectBuf[ii*4+3]));
00341 }
00342 if(sorted)
00343 std::sort(H.begin(),H.end());
00344
00345 result.resize(H.size());
00346 for(long ii=0;ii<hits;ii++){
00347 FaceIterator fi=m.face.begin();
00348 advance(fi ,H[ii].second);
00349 result[ii]=&*fi;
00350 }
00351
00352 delete [] selectBuf;
00353 return result.size();
00354 }
00355
00356 static int OldPickVert(int x, int y, MESH_TYPE &m, std::vector<VertexPointer> &result, int width=4, int height=4,bool sorted=true)
00357 {
00358 result.clear();
00359 if(width==0 ||height==0) return 0;
00360 long hits;
00361 int sz=m.vert.size()*5;
00362 GLuint *selectBuf =new GLuint[sz];
00363 glSelectBuffer(sz, selectBuf);
00364 glRenderMode(GL_SELECT);
00365 glInitNames();
00366
00367
00368 glPushName(-1);
00369 double mp[16];
00370
00371 GLint viewport[4];
00372 glGetIntegerv(GL_VIEWPORT,viewport);
00373 glMatrixMode(GL_PROJECTION);
00374 glGetDoublev(GL_PROJECTION_MATRIX ,mp);
00375 glPushMatrix();
00376 glLoadIdentity();
00377 gluPickMatrix(x, y, width, height, viewport);
00378 glMultMatrixd(mp);
00379
00380 glMatrixMode(GL_MODELVIEW);
00381 glPushMatrix();
00382 int vcnt=0;
00383 VertexIterator vi;
00384 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00385 {
00386 if(!(*vi).IsD())
00387 {
00388 glLoadName(vcnt);
00389 glBegin(GL_POINTS);
00390 glVertex( (*vi).P() );
00391 glEnd();
00392 }
00393 vcnt++;
00394 }
00395
00396 glPopMatrix();
00397 glMatrixMode(GL_PROJECTION);
00398 glPopMatrix();
00399 glMatrixMode(GL_MODELVIEW);
00400 hits = glRenderMode(GL_RENDER);
00401 std::vector< std::pair<double,unsigned int> > H;
00402 for(long ii=0;ii<hits;ii++){
00403 H.push_back( std::pair<double,unsigned int>(selectBuf[ii*4+1]/4294967295.0,selectBuf[ii*4+3]));
00404 }
00405 if(sorted)
00406 std::sort(H.begin(),H.end());
00407 result.resize(H.size());
00408 for(long ii=0;ii<hits;ii++){
00409 VertexIterator vi=m.vert.begin();
00410 advance(vi ,H[ii].second);
00411 result[ii]=&*vi;
00412 }
00413
00414 delete [] selectBuf;
00415 return result.size();
00416 }
00417
00418 };
00419
00420 }
00421
00422 #endif