inlib
1.2.0
|
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