inlib  1.2.0
/Users/barrand/private/dev/softinex/old/inexlib-1.2/inlib/inlib/sg/pick_action
Go to the documentation of this file.
00001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
00002 // See the file inlib.license for terms.
00003 
00004 #ifndef inlib_sg_pick_action
00005 #define inlib_sg_pick_action
00006 
00007 // inheritance :
00008 #include "mtx_action"
00009 
00010 //#include "../cast"
00011 #include "../mat4f"
00012 #include "../vec2f"
00013 //#include "cbk"
00014 
00015 namespace inlib {
00016 namespace sg {
00017   class node;
00018 }}
00019 
00020 namespace inlib {
00021 namespace sg {
00022 
00023 class pick_action : public mtx_action {
00024 //public:
00025   //static const std::string& s_class() {
00026   //  static const std::string s_v("inlib::sg::pick_action");
00027   //  return s_v;
00028   //}
00029 public:
00030 /*
00031   virtual void* cast(const std::string& a_class) const {
00032     if(void* p = inlib::cmp_cast<pick_action>(this,a_class)) {return p;}
00033     if(void* p = inlib::cmp_cast<action>(this,a_class)) {return p;}
00034     return 0;
00035   }
00036 */
00037 public:
00038   pick_action(std::ostream& a_out,
00039                      unsigned int a_ww,unsigned int a_wh,
00040                      float a_l,float a_r,
00041                      float a_b,float a_t)
00042   : mtx_action(a_out,a_ww,a_wh)
00043   ,m_l(a_l)
00044   ,m_r(a_r)
00045   ,m_b(a_b)
00046   ,m_t(a_t)
00047   ,m_done(false)
00048   ,m_node(0)
00049   {
00050     set_to_pick_ndc(); //OPTIMIZATION
00051   }
00052   virtual ~pick_action(){
00053     //clear_cbks();
00054   }
00055 private:
00056   pick_action(const inlib::sg::pick_action& a_from)
00057   : mtx_action(a_from)
00058   {}
00059   inlib::sg::pick_action& operator=(const inlib::sg::pick_action& a_from){
00060     mtx_action::operator=(a_from);
00061     return *this;
00062   }
00063 public:
00064   void reset() {
00065     mtx_action::reset();
00066     m_done = false;
00067     m_node = 0;
00068     //clear_cbks();
00069   }
00070 
00071   void set_done(bool a_value) {m_done = a_value;}
00072   bool done() const {return m_done;}
00073 
00074   void set_node(inlib::sg::node* a_node) {m_node = a_node;}
00075   inlib::sg::node* node() const {return m_node;}
00076 
00077 /*
00078   void add_cbk(inlib::sg::cbk* a_cbk) {
00079     //we take ownership of a_cbk
00080     m_cbks.push_back(a_cbk);
00081   }
00082   bool has_cbks() {return m_cbks.empty()?false:true;}
00083   const std::vector<inlib::sg::cbk*>& cbks() const {return m_cbks;}
00084 
00085   //void exec_cbks() {
00086   //  std::vector<inlib::sg::cbk*>::iterator it;
00087   //  for(it=m_cbks.begin();it!=m_cbks.end();++it) {
00088   //    (*it)->action();
00089   //  }
00090   //}
00091 
00092   void clear_cbks() {
00093     std::vector<inlib::sg::cbk*>::iterator it;
00094     for(it=m_cbks.begin();it!=m_cbks.end();) {
00095       inlib::sg::cbk* cbk = *it;
00096       it = m_cbks.erase(it);        
00097       delete cbk;
00098     }    
00099     m_cbks.clear();
00100   }
00101 */
00102 
00103   void set_area(float a_l,float a_r,
00104                        float a_b,float a_t) {
00105     // a_l,a_r,a_b,a_t are in window coordinates (pixels)
00106     // but handled in floats for intersection computation precision.
00107     // WARNING : we must have a_t>a_b and a_r>a_l. No check is done for that. 
00108     m_l = a_l;
00109     m_r = a_r;
00110     m_b = a_b;
00111     m_t = a_t;
00112     set_to_pick_ndc(); //OPTIMIZATION
00113   }
00114 
00115   bool is_inside(float a_x,float a_y) const {
00116     //std::cout << "debug : inlib::sg::pick_action::is_inside :"
00117     //      << " x " << a_x
00118     //      << " y " << a_y
00119     //      << std::endl;
00120 
00121     // In principle we should receive (because of proj x model matrix
00122     // mult of world coord points) point in [-1,1]x[-1,1].
00123 
00124     float x,y;
00125     to_pick_ndc(a_x,a_y,x,y);
00126 
00127     if(x<-1) return false;
00128     if(1<x) return false;
00129     if(y<-1) return false;
00130     if(1<y) return false;
00131 
00132     //std::cout << "debug : inlib::sg::pick_action::is_inside :"
00133     //      << " inside !"
00134     //      << std::endl;
00135 
00136     return true;
00137   }
00138   bool intersect(float a_bx,float a_by,
00139                         float a_ex,float a_ey) const {
00140 
00141     // ortho_clip_line works by testing against a [-1,1]x[-1,1] box.
00142     // In principle we should receive (because of proj x model matrix
00143     // mult of world coord points) points in [-1,1]x[-1,1] too.
00144 
00145     float bx,by;
00146     to_pick_ndc(a_bx,a_by,bx,by);
00147 
00148     float ex,ey;
00149     to_pick_ndc(a_ex,a_ey,ex,ey);
00150 
00151     //no check on z is done.
00152     float bz = 0;
00153     float ez = 0;
00154 
00155     bool toggle;
00156     bool status = ortho_clip_line(bx,by,bz,ex,ey,ez,false,toggle);
00157 
00158     //if(status) {
00159     //  std::cout << "debug : inlib::sg::pick_action::intersect :"
00160     //        << " intersect !"
00161     //        << std::endl;
00162     //}
00163 
00164     return status;
00165   }
00166 
00167   bool intersect(float a_1x,float a_1y,
00168                         float a_2x,float a_2y,
00169                         float a_3x,float a_3y) const {
00170     //test a triangle.
00171 
00172     if(is_inside(a_1x,a_1y)) return true;
00173     if(is_inside(a_2x,a_2y)) return true;
00174     if(is_inside(a_3x,a_3y)) return true;
00175     
00176     // alll points are outside. 
00177 
00178     if(intersect(a_1x,a_1y, a_2x,a_2y)) return true;
00179     if(intersect(a_2x,a_2y, a_3x,a_3y)) return true;
00180     if(intersect(a_1x,a_1y, a_3x,a_3y)) return true;
00181 
00182     // no intersection with edges.
00183     // but the triangle may surround [-1,1]x[-1,1] !
00184 
00185     float x1,y1;
00186     to_pick_ndc(a_1x,a_1y,x1,y1);
00187     float x2,y2;
00188     to_pick_ndc(a_2x,a_2y,x2,y2);
00189     float x3,y3;
00190     to_pick_ndc(a_3x,a_3y,x3,y3);
00191 
00192     // test if (0,0) is inside the triangle :    
00193     inlib::vec2f p1(x1,y1);
00194     inlib::vec2f p2(x2,y2);
00195     inlib::vec2f p3(x3,y3);
00196 
00197     //std::cout << "pick_action::intersect : " << std::endl;
00198     //std::cout << " p1 " << p1[0] << " " << p1[1] << std::endl;
00199     //std::cout << " p2 " << p2[0] << " " << p2[1] << std::endl;
00200     //std::cout << " p3 " << p3[0] << " " << p3[1] << std::endl;
00201 
00202     inlib::vec2f o(0,0);
00203 
00204    {float cp2 = (p2-p1).cross(p3-p1);
00205     if(cp2==0) return false;       // (p1,p2,p3) aligned points.
00206     float cp1 = (p2-p1).cross( o-p1);
00207     if(cp1==0) return true;        // o on (p1,p2). We can't pass here.
00208     if((cp1*cp2)<0) return false;} // o p3 not on same side than (p1,p2)
00209 
00210    {float cp2 = (p3-p2).cross(p1-p2);
00211     if(cp2==0) return false;       // (p1,p2,p3) aligned points.
00212     float cp1 = (p3-p2).cross( o-p2);
00213     if(cp1==0) return true;        // o on (p2,p3). We can't pass here.
00214     if((cp1*cp2)<0) return false;} // o p1 not on same side than (p2,p3)
00215 
00216    {float cp2 = (p1-p3).cross(p2-p3);
00217     if(cp2==0) return false;       // (p1,p2,p3) aligned points.
00218     float cp1 = (p1-p3).cross( o-p3);
00219     if(cp1==0) return true;        // o on (p3,p1). We can't pass here.
00220     if((cp1*cp2)<0) return false;} // o p2 not on same side than (p3,p1)
00221 
00222     //std::cout << " (0,0) inside. " << std::endl;
00223 
00224     return true;
00225   }
00226 private:
00227   void set_to_pick_ndc() { //OPTIMIZATION
00228     float cx = (m_l+m_r)/2;
00229     cx /= float(m_ww);
00230     cx *= 2;
00231     float cy = (m_b+m_t)/2;
00232     cy /= float(m_wh);
00233     cy *= 2;
00234 
00235     float sx = m_r-m_l;
00236     sx /= float(m_ww);
00237     sx *= 2;
00238     float sy = m_t-m_b;
00239     sy /= float(m_wh);
00240     sx *= 2;
00241 
00242     //then now cx,cy,sx,sw in [0,2]x[0,2] coords.
00243     cx -= 1;
00244     cy -= 1;
00245     //then now cx,cy,sx,sw in [-1,1]x[-1,1] coords.
00246 
00247     m_cx = cx;
00248     m_cy = cy;
00249     m_sx = sx;
00250     m_sy = sy;
00251   }
00252   void to_pick_ndc(const float& a_fx,const float& a_fy,
00253                      float& a_x,float& a_y) const {
00254     a_x = 2*(a_fx-m_cx)/m_sx;
00255     a_y = 2*(a_fy-m_cy)/m_sy;
00256   }
00257 private:
00258   static bool ortho_clip_line(float& a_bx,float& a_by,float& a_bz,
00259                               float& a_ex,float& a_ey,float& a_ez,
00260                               bool a_doz,bool& a_toggle) {
00261 
00262     // toggle means that at return begin contains end and end contains begin).
00263     //
00264     // begin out, end out
00265     //   output : a_toggle = false, return false.
00266     // begin in, end  in
00267     //   output : a_toggle = false, return true.
00268     // begin in, end out
00269     //   output : a_toggle = true, begin = clipping point, return true.
00270     // begin out, end  in
00271     //   output : a_toggle = false, begin = clipping point, return true.
00272 
00273     a_toggle = false;
00274 
00275     const unsigned int FILTER__NOZ = 0xf;   //4 left right bits set to 1.
00276     //const unsigned int FILTER__Z = 0x3f;  //6 left right bits set to 1.
00277 
00278     bool accept = false;
00279     bool done = false;
00280     do {
00281       unsigned int bout = ortho_out(a_bx,a_by,a_bz,a_doz);
00282       unsigned int eout = ortho_out(a_ex,a_ey,a_ez,a_doz);
00283       bool reject = ( (bout & eout & FILTER__NOZ) !=0  ? true : false);
00284       if(reject) { //begin and end have a common "outside bit" raised.
00285         done = true;
00286       } else {
00287         accept = !bout && !eout;
00288         if(accept) { //begin and end have all outside-bits to zero.
00289           done = true;
00290         } else {
00291           if(!bout) { // begin inside. toggle begin and end.
00292             unsigned int tout = eout;
00293             float tx = a_ex;
00294             float ty = a_ey;
00295             float tz = a_ez;
00296 
00297             eout = bout;
00298             a_ex = a_bx;
00299             a_ey = a_by;
00300             a_ez = a_bz;
00301 
00302             bout = tout;
00303             a_bx = tx;
00304             a_by = ty;
00305             a_bz = tz;
00306 
00307             a_toggle = true;
00308           }
00309           if(bout & (1<<0)) { // by > 1
00310             float t = a_ey - a_by;
00311             //CHECK_DIV(t,"ClipLineParallel")
00312             t = (1 - a_by)/t;
00313             a_bx += (a_ex - a_bx) * t;
00314             a_by  = 1;
00315             a_bz += (a_ez - a_bz) * t;
00316           } else if(bout & (1<<1)) { // by < -1
00317             float t = a_ey-a_by;
00318             //CHECK_DIV(t,"ClipLineParallel")
00319             t = (-1 - a_by)/t;
00320             a_bx += (a_ex - a_bx) * t;
00321             a_by  = -1;
00322             a_bz += (a_ez - a_bz) * t;
00323           } else if(bout & (1<<2)) { // bx > 1
00324             float t = a_ex-a_bx;
00325             //CHECK_DIV    (t,"ClipLineParallel")
00326             t = (1 - a_bx)/t;
00327             a_bx  = 1;
00328             a_by += (a_ey - a_by) * t;
00329             a_bz += (a_ez - a_bz) * t;
00330           } else if(bout & (1<<3)) { // bx < -1
00331             float t = a_ex-a_bx;
00332             //CHECK_DIV    (t,"ClipLineParallel")
00333             t = (-1 - a_bx)/t;
00334             a_bx  = -1;
00335             a_by += (a_ey - a_by) * t;
00336             a_bz += (a_ez - a_bz) * t;
00337           }
00338           // z = -1.
00339           // z =  0.
00340           // G.Barrand : do not do z clipping
00341        /* else if(a_doz && (bout & (1<<4)) ) { //bz < -1 
00342             float t = a_ez-a_bz;
00343             //CHECK_DIV    (t,"ClipLineParallel")
00344             t = (-1 - a_z)/t;
00345             a_bx += (a_ex - a_bx) * t;
00346             a_by += (a_ey - a_by) * t;
00347             a_bz  = -1;
00348           } else if(a_doz && (bout & (1<<5)) ) { //bz > 0
00349             t = a_ez - a_bz;
00350             //CHECK_DIV    (t,"ClipLineParallel")
00351             t = (- a_bz)/t;
00352             a_bx += (a_ex - a_bx) * t;
00353             a_by += (a_ey - a_by) * t;
00354             a_bz  = 0;
00355           } */
00356         }
00357       }
00358     } while (!done);
00359     return accept;
00360   }
00361 
00362   static unsigned int ortho_out(float a_x,float a_y,float a_z,bool a_doz){
00363     unsigned int out = 0;
00364     if(a_y> 1) out |= (1<<0);
00365     if(a_y<-1) out |= (1<<1);
00366     if(a_x> 1) out |= (1<<2);
00367     if(a_x<-1) out |= (1<<3);
00368     if(!a_doz) return out;
00369     if(a_z<-1) out |= (1<<4);
00370     if(a_z> 0) out |= (1<<5);
00371     return out;
00372   }
00373 
00374 private:
00375   // picking region (in window coordinates, (0,0) = bottom-left ) :
00376   float m_l;
00377   float m_r;
00378   float m_b;
00379   float m_t;
00380   
00381   bool m_done;
00382   inlib::sg::node* m_node;
00383   //std::vector<inlib::sg::cbk*> m_cbks;
00384 
00385   //OPTIMIZATION:
00386   float m_cx,m_cy,m_sx,m_sy;
00387 };
00388 
00389 }}
00390 
00391 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines