Back to home page

EIC code displayed by LXR

 
 

    


Warning, /include/Geant4/tools/sg/pick_action is written in an unsupported language. File is not indexed.

0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003 
0004 #ifndef tools_sg_pick_action
0005 #define tools_sg_pick_action
0006 
0007 #include "matrix_action"
0008 #include "primitive_visitor"
0009 
0010 #include "../lina/plane"
0011 #include "../vmanip"
0012 
0013 #include "node"
0014 
0015 namespace tools {
0016 namespace sg {
0017 
0018 class pick_element {
0019 public:
0020   pick_element(sg::node& a_node,const std::vector<float>& a_zs,const std::vector<float>& a_ws,const sg::state& a_state)
0021   :m_node(a_node)
0022   ,m_zs(a_zs)
0023   ,m_ws(a_ws)
0024   ,m_state(a_state)
0025   {}
0026   virtual ~pick_element(){}
0027 public:
0028   pick_element(const pick_element& a_from)
0029   :m_node(a_from.m_node)
0030   ,m_zs(a_from.m_zs)
0031   ,m_ws(a_from.m_ws)
0032   ,m_state(a_from.m_state)
0033   {}
0034   pick_element& operator=(const pick_element& a_from){
0035     m_zs = a_from.m_zs;
0036     m_ws = a_from.m_ws;
0037     m_state = a_from.m_state;
0038     return *this;
0039   }
0040 public:
0041   const sg::node& node() const {return m_node;}
0042   sg::node& node() {return m_node;}
0043 
0044   const std::vector<float>& zs() const {return m_zs;}
0045   std::vector<float>& zs() {return m_zs;}
0046 
0047   const std::vector<float>& ws() const {return m_ws;}
0048   std::vector<float>& ws() {return m_ws;}
0049 
0050   const sg::state& state() const {return m_state;}
0051   sg::state& state() {return m_state;}
0052 protected:
0053   sg::node& m_node;
0054   std::vector<float> m_zs;
0055   std::vector<float> m_ws;
0056   sg::state m_state;
0057 };
0058 
0059 class pick_action : public matrix_action, public primitive_visitor {
0060   TOOLS_ACTION(pick_action,tools::sg::pick_action,matrix_action)
0061 protected:
0062 
0063   virtual bool project(float& a_x,float& a_y,float& a_z,float& a_w) {
0064     return parent::project_point(a_x,a_y,a_z,a_w);
0065   }
0066 
0067   virtual bool add_point(float a_x,float a_y,float a_z,float a_w) {
0068     if(is_inside(a_x,a_y,a_z,a_w)) { //we have a pick.
0069       m_done = true;
0070       return false; //to stop
0071     }
0072     return true; //continue.
0073   }
0074 
0075   virtual bool add_point(float a_x,float a_y,float a_z,float a_w,
0076                          float,float,float,float) {
0077     return pick_action::add_point(a_x,a_y,a_z,a_w);
0078   }
0079 
0080   virtual bool add_line(float a_bx,float a_by,float a_bz,float a_bw,
0081                         float a_ex,float a_ey,float a_ez,float a_ew) {
0082     if(is_inside(a_bx,a_by,a_bz,a_bw)) {
0083       m_done = true;
0084       return false;
0085     }
0086     if(is_inside(a_ex,a_ey,a_ez,a_ew)) {
0087       m_done = true;
0088       return false;
0089     }
0090     if(intersect_line(a_bx,a_by,a_bz,a_bw,
0091                       a_ex,a_ey,a_ez,a_ew)) {
0092       m_done = true;
0093       return false;
0094     }
0095     return true;
0096   }
0097 
0098   virtual bool add_line(float a_bx,float a_by,float a_bz,float a_bw,
0099                         float,float,float,float,
0100                         float a_ex,float a_ey,float a_ez,float a_ew,
0101                         float,float,float,float){
0102     return pick_action::add_line(a_bx,a_by,a_bz,a_bw,a_ex,a_ey,a_ez,a_ew);
0103   }
0104 
0105   virtual bool add_triangle(float a_p1x,float a_p1y,float a_p1z,float a_p1w,
0106                             float a_p2x,float a_p2y,float a_p2z,float a_p2w,
0107                             float a_p3x,float a_p3y,float a_p3z,float a_p3w){
0108     if(intersect_triangle(a_p1x,a_p1y,a_p1z,a_p1w,
0109                           a_p2x,a_p2y,a_p2z,a_p2w,
0110                           a_p3x,a_p3y,a_p3z,a_p3w)) {
0111       m_done = true;
0112       return false;
0113     }
0114     return true;
0115   }
0116 
0117   virtual bool add_triangle(float a_p1x,float a_p1y,float a_p1z,float a_p1w,
0118                             float,float,float,float,
0119                             float a_p2x,float a_p2y,float a_p2z,float a_p2w,
0120                             float,float,float,float,
0121                             float a_p3x,float a_p3y,float a_p3z,float a_p3w,
0122                             float,float,float,float){
0123     return pick_action::add_triangle(a_p1x,a_p1y,a_p1z,a_p1w,
0124                                      a_p2x,a_p2y,a_p2z,a_p2w,
0125                                      a_p3x,a_p3y,a_p3z,a_p3w);
0126   }
0127 
0128   virtual bool project_normal(float&,float&,float&) {return true;}
0129   virtual bool add_point_normal(float a_x,float a_y,float a_z,float a_w,
0130                                 float,float,float) {
0131     return pick_action::add_point(a_x,a_y,a_z,a_w);
0132   }
0133 
0134   virtual bool add_point_normal(float a_x,float a_y,float a_z,float a_w,
0135                                 float,float,float,
0136                                 float,float,float,float) {
0137     return pick_action::add_point(a_x,a_y,a_z,a_w);
0138   }
0139 
0140   virtual bool add_line_normal(float a_bx,float a_by,float a_bz,float a_bw, float,float,float,
0141                                float a_ex,float a_ey,float a_ez,float a_ew, float,float,float) {
0142     return pick_action::add_line(a_bx,a_by,a_bz,a_bw,a_ex,a_ey,a_ez,a_ew);
0143   }
0144   virtual bool add_line_normal(float a_bx,float a_by,float a_bz,float a_bw, float,float,float, float,float,float,float,
0145                                float a_ex,float a_ey,float a_ez,float a_ew, float,float,float, float,float,float,float) {
0146     return pick_action::add_line(a_bx,a_by,a_bz,a_bw,a_ex,a_ey,a_ez,a_ew);
0147   }
0148 
0149   virtual bool add_triangle_normal(float a_p1x,float a_p1y,float a_p1z,float a_p1w, float,float,float,
0150                                    float a_p2x,float a_p2y,float a_p2z,float a_p2w, float,float,float,
0151                                    float a_p3x,float a_p3y,float a_p3z,float a_p3w, float,float,float) {
0152     return pick_action::add_triangle(a_p1x,a_p1y,a_p1z,a_p1w,
0153                                      a_p2x,a_p2y,a_p2z,a_p2w,
0154                                      a_p3x,a_p3y,a_p3z,a_p3w);
0155   }
0156   virtual bool add_triangle_normal(float a_p1x,float a_p1y,float a_p1z,float a_p1w,
0157                                    float,float,float, float,float,float,float,
0158                                    float a_p2x,float a_p2y,float a_p2z,float a_p2w,
0159                                    float,float,float, float,float,float,float,
0160                                    float a_p3x,float a_p3y,float a_p3z,float a_p3w,
0161                                    float,float,float, float,float,float,float) {
0162     return pick_action::add_triangle(a_p1x,a_p1y,a_p1z,a_p1w,
0163                                      a_p2x,a_p2y,a_p2z,a_p2w,
0164                                      a_p3x,a_p3y,a_p3z,a_p3w);
0165   }
0166 public:
0167   pick_action(std::ostream& a_out,unsigned int a_ww,unsigned int a_wh,float a_l,float a_r,float a_b,float a_t)
0168   :parent(a_out,a_ww,a_wh)
0169   ,m_l(a_l)
0170   ,m_r(a_r)
0171   ,m_b(a_b)
0172   ,m_t(a_t)
0173   ,m_stop_at_first(false) //same as selection
0174   ,m_done(false)
0175   ,m_node(0)
0176   {
0177     set_to_pick_ndc(); //OPTIMIZATION
0178   }
0179   virtual ~pick_action(){}
0180 public:
0181   pick_action(const pick_action& a_from)
0182   :parent(a_from)
0183   ,primitive_visitor(a_from)
0184   ,m_l(a_from.m_l)
0185   ,m_r(a_from.m_r)
0186   ,m_b(a_from.m_b)
0187   ,m_t(a_from.m_t)
0188   ,m_stop_at_first(a_from.m_stop_at_first)
0189   ,m_done(false)
0190   ,m_node(0)
0191   {
0192     set_to_pick_ndc(); //OPTIMIZATION
0193   }
0194   pick_action& operator=(const pick_action& a_from){
0195     parent::operator=(a_from);
0196     primitive_visitor::operator=(a_from);
0197     m_l = a_from.m_l;
0198     m_r = a_from.m_r;
0199     m_b = a_from.m_b;
0200     m_t = a_from.m_t;
0201     m_stop_at_first = a_from.m_stop_at_first;
0202     m_done = false;
0203     m_node = 0;
0204     m_zs.clear();
0205     m_ws.clear();
0206     m_picks.clear();
0207     set_to_pick_ndc(); //OPTIMIZATION
0208     return *this;
0209   }
0210 public:
0211   void reset() {
0212     parent::reset();
0213     m_done = false;
0214     m_node = 0;
0215     m_zs.clear();
0216     m_ws.clear();
0217     m_picks.clear();
0218   }
0219 
0220   void set_win_size(unsigned a_ww,unsigned int a_wh) {
0221     m_ww = a_ww;
0222     m_wh = a_wh;
0223     sg::state& _state = state();
0224     _state.m_ww = a_ww;
0225     _state.m_wh = a_wh;
0226     m_states.clear();
0227     reset();
0228   }
0229 
0230   void set_area(float a_l,float a_r,float a_b,float a_t) {
0231     // a_l,a_r,a_b,a_t are in window coordinates (pixels)
0232     // but handled in floats for intersection computation precision.
0233     // WARNING : we must have a_t>a_b and a_r>a_l. No check is done for that.
0234     m_l = a_l;
0235     m_r = a_r;
0236     m_b = a_b;
0237     m_t = a_t;
0238     set_to_pick_ndc(); //OPTIMIZATION
0239   }
0240 
0241   void get_area(float& a_l,float& a_r,float& a_b,float& a_t) const {
0242     a_l = m_l;
0243     a_r = m_r;
0244     a_b = m_b;
0245     a_t = m_t;
0246   }
0247 
0248   /////////////////////////////////////////////
0249   /////////////////////////////////////////////
0250   /////////////////////////////////////////////
0251   void set_stop_at_first(bool a_value) {m_stop_at_first = a_value;}
0252   bool stop_at_first() const {return m_stop_at_first;}
0253 
0254   void set_done(bool a_value) {m_done = a_value;}
0255   bool done() const {return m_done;}
0256 
0257   void set_node(sg::node* a_node) {m_node = a_node;}
0258   sg::node* node() const {return m_node;}
0259 
0260   /////////////////////////////////////////////
0261   /////////////////////////////////////////////
0262   /////////////////////////////////////////////
0263   typedef pick_element pick_t;
0264 
0265   void add_pick(sg::node& a_node,
0266                 const std::vector<float>& a_zs,
0267                 const std::vector<float>& a_ws,
0268                 const sg::state& a_state) {
0269     m_picks.push_back(pick_t(a_node,a_zs,a_ws,a_state));
0270   }
0271   const std::vector<pick_t>& picks() const {return m_picks;}
0272 
0273   void dump_picks() {
0274     m_out << "tools::sg::pick_action :"
0275           << " number of picks " << m_picks.size()
0276           << std::endl;
0277     std::vector<pick_t>::const_iterator it;
0278     for(it=m_picks.begin();it!=m_picks.end();++it) {
0279       m_out << "  " << (*it).node().s_cls();
0280 
0281       std::vector<float>::const_iterator itz;
0282       for(itz=(*it).zs().begin();itz!=(*it).zs().end();++itz) {
0283         m_out  << "  " << *itz;
0284       }
0285 
0286       m_out << std::endl;
0287     }
0288   }
0289 
0290   pick_t* closest_pick() {
0291     if(m_picks.empty()) return 0;
0292     //closest point is minimum z !
0293     //  near -> -1
0294     //  far  ->  1
0295 
0296     // find first pick_t with not empty zs :
0297     pick_t* pck = 0;
0298     float z;
0299     std::vector<pick_t>::const_iterator it;
0300     for(it=m_picks.begin();it!=m_picks.end();++it) {
0301       if(minimum((*it).zs(),z)) {
0302         pck = (pick_t*)&(*it);
0303         break;
0304       }
0305     }
0306     if(!pck) return 0;
0307     it++;
0308     for(;it!=m_picks.end();++it) {
0309       float zi;
0310       if(minimum((*it).zs(),zi)) {
0311         if(zi<=z) {
0312           pck = (pick_t*)&(*it);
0313           z = zi;
0314         }
0315       }
0316     }
0317     return pck;
0318   }
0319 
0320   const std::vector<float>& zs() const {return m_zs;}
0321   std::vector<float>& zs() {return m_zs;}
0322 
0323   const std::vector<float>& ws() const {return m_ws;}
0324   std::vector<float>& ws() {return m_ws;}
0325 
0326   void set_matrices_to_identity() {
0327     projection_matrix() = m_identity;
0328     model_matrix() = m_identity;
0329   }
0330   void set_matrices_from_state() {
0331     const sg::state& _state = state();
0332     projection_matrix() = _state.m_proj;
0333     model_matrix() = _state.m_model;
0334   }
0335 public:
0336   bool add__primitive_xy(sg::node& a_node,
0337                          gl::mode_t a_mode,
0338                          size_t a_floatn,const float* a_xys,
0339                          bool a_stop = false,
0340                          bool a_triangle_revert = false){
0341     if(!a_floatn) return false;
0342     if(m_stop_at_first){
0343       add_primitive_xy(a_mode,a_floatn,a_xys,a_stop,a_triangle_revert);
0344       if(m_done) {
0345         m_node = &a_node;
0346         return true;
0347       }
0348     } else {
0349       m_done = false;
0350       m_zs.clear();
0351       add_primitive_xy(a_mode,a_floatn,a_xys,a_stop,a_triangle_revert);
0352       if(m_done) {
0353         add_pick(a_node,m_zs,m_ws,state());
0354         m_done = false;
0355         return true;
0356       }
0357     }
0358     return false;
0359   }
0360 
0361   bool add__primitive_xy(sg::node& a_node,
0362                          gl::mode_t a_mode,
0363                          const std::vector<float>& a_xys,
0364                          bool a_stop = false,
0365                          bool a_triangle_revert = false){
0366     if(a_xys.empty()) return false;
0367     if(m_stop_at_first){
0368       add_primitive_xy(a_mode,a_xys,a_stop,a_triangle_revert);
0369       if(m_done) {
0370         m_node = &a_node;
0371         return true;
0372       }
0373     } else {
0374       m_done = false;
0375       m_zs.clear();
0376       add_primitive_xy(a_mode,a_xys,a_stop,a_triangle_revert);
0377       if(m_done) {
0378         add_pick(a_node,m_zs,m_ws,state());
0379         m_done = false;
0380         return true;
0381       }
0382     }
0383     return false;
0384   }
0385 
0386   bool add__line_strip_xy(sg::node& a_node,size_t a_floatn,const float* a_xys,bool a_stop = false){
0387     if(!a_floatn) return false;
0388     if(m_stop_at_first){
0389       add_line_strip_xy(a_floatn,a_xys,a_stop);
0390       if(m_done) {
0391         m_node = &a_node;
0392         return true;
0393       }
0394     } else {
0395       m_done = false;
0396       m_zs.clear();
0397       add_line_strip_xy(a_floatn,a_xys,a_stop);
0398       if(m_done) {
0399         add_pick(a_node,m_zs,m_ws,state());
0400         m_done = false;
0401         return true;
0402       }
0403     }
0404     return false;
0405   }
0406 
0407   bool add__lines_xy(sg::node& a_node,
0408                      const std::vector<float>& a_xys,
0409                      bool a_stop = false) {
0410     if(a_xys.empty()) return false;
0411     if(m_stop_at_first){
0412       add_lines_xy(a_xys,a_stop);
0413       if(m_done) {
0414         m_node = &a_node;
0415         return true;
0416       }
0417     } else {
0418       m_done = false;
0419       m_zs.clear();
0420       add_lines_xy(a_xys,a_stop);
0421       if(m_done) {
0422         add_pick(a_node,m_zs,m_ws,state());
0423         m_done = false;
0424         return true;
0425       }
0426     }
0427     return false;
0428   }
0429 
0430 public:
0431   bool add__primitive(sg::node& a_node,gl::mode_t a_mode,size_t a_floatn,const float* a_xyzs,bool a_stop = false){
0432     if(!a_floatn) return false;
0433     if(m_stop_at_first){
0434       add_primitive(a_mode,a_floatn,a_xyzs,a_stop);
0435       if(m_done) {
0436         m_node = &a_node;
0437         return true;
0438       }
0439     } else {
0440       m_done = false;
0441       m_zs.clear();
0442       add_primitive(a_mode,a_floatn,a_xyzs,a_stop);
0443       if(m_done) {
0444         add_pick(a_node,m_zs,m_ws,state());
0445         m_done = false;
0446         return true;
0447       }
0448     }
0449     return false;
0450   }
0451 
0452   bool add__primitive(sg::node& a_node,gl::mode_t a_mode,const std::vector<float>& a_xyzs,bool a_stop = false) {
0453     if(a_xyzs.empty()) return false;
0454     if(m_stop_at_first){
0455       add_primitive(a_mode,a_xyzs,a_stop);
0456       if(m_done) {
0457         m_node = &a_node;
0458         return true;
0459       }
0460     } else {
0461       m_done = false;
0462       m_zs.clear();
0463       add_primitive(a_mode,a_xyzs,a_stop);
0464       if(m_done) {
0465         add_pick(a_node,m_zs,m_ws,state());
0466         m_done = false;
0467         return true;
0468       }
0469     }
0470     return false;
0471   }
0472 
0473   bool add__line_strip(sg::node& a_node,size_t a_floatn,const float* a_xyzs,bool a_stop = false){
0474     if(!a_floatn) return false;
0475     if(m_stop_at_first){
0476       add_line_strip(a_floatn,a_xyzs,a_stop);
0477       if(m_done) {
0478         m_node = &a_node;
0479         return true;
0480       }
0481     } else {
0482       m_done = false;
0483       m_zs.clear();
0484       add_line_strip(a_floatn,a_xyzs,a_stop);
0485       if(m_done) {
0486         add_pick(a_node,m_zs,m_ws,state());
0487         m_done = false;
0488         return true;
0489       }
0490     }
0491     return false;
0492   }
0493 
0494   bool add__triangles(sg::node& a_node,
0495                       size_t a_floatn,
0496                       const float* a_xyzs,
0497                       bool a_stop = false){
0498     if(!a_floatn) return false;
0499     if(m_stop_at_first){
0500       add_triangles(a_floatn,a_xyzs,a_stop);
0501       if(m_done) {
0502         m_node = &a_node;
0503         return true;
0504       }
0505     } else {
0506       m_done = false;
0507       m_zs.clear();
0508       add_triangles(a_floatn,a_xyzs,a_stop);
0509       if(m_done) {
0510         add_pick(a_node,m_zs,m_ws,state());
0511         m_done = false;
0512         return true;
0513       }
0514     }
0515     return false;
0516   }
0517 
0518   bool add__lines(sg::node& a_node,
0519                   const std::vector<float>& a_xyzs,
0520                   bool a_stop = false){
0521     if(a_xyzs.empty()) return false;
0522     if(m_stop_at_first){
0523       add_lines(a_xyzs,a_stop);
0524       if(m_done) {
0525         m_node = &a_node;
0526         return true;
0527       }
0528     } else {
0529       m_done = false;
0530       m_zs.clear();
0531       add_lines(a_xyzs,a_stop);
0532       if(m_done) {
0533         add_pick(a_node,m_zs,m_ws,state());
0534         m_done = false;
0535         return true;
0536       }
0537     }
0538     return false;
0539   }
0540 
0541 public: //for markers
0542   bool is_inside(float a_x,float a_y,float a_z,float a_w) {
0543     //std::cout << "debug : tools::sg::pick_action::is_inside :"
0544     //      << " x " << a_x
0545     //      << " y " << a_y
0546     //      << std::endl;
0547 
0548     // In principle we should receive (because of proj x model matrix
0549     // mult of world coord points) point in [-1,1]x[-1,1].
0550 
0551     float x,y;
0552     to_pick_ndc(a_x,a_y,x,y);
0553 
0554     if(x<-1) return false;
0555     if(1<x) return false;
0556     if(y<-1) return false;
0557     if(1<y) return false;
0558 
0559     //std::cout << "debug : tools::sg::pick_action::is_inside :"
0560     //      << " inside !"
0561     //      << std::endl;
0562 
0563     m_zs.push_back(a_z);
0564     m_ws.push_back(a_w);
0565 
0566     return true;
0567   }
0568   bool intersect_line(float a_bx,float a_by,float a_bz,float a_bw,
0569                       float a_ex,float a_ey,float a_ez,float a_ew) {
0570 
0571     // a_bz, a_ez are used only to compute the intersection point.
0572 
0573     float bx,by;
0574     to_pick_ndc(a_bx,a_by,bx,by);
0575     float ex,ey;
0576     to_pick_ndc(a_ex,a_ey,ex,ey);
0577 
0578     //no check on z is done.
0579     float bz = a_bz;
0580     float bw = a_bw;
0581     float ez = a_ez;
0582     float ew = a_ew;
0583 
0584     bool toggle;
0585     if(!ortho_clip_line(bx,by,bz,bw, ex,ey,ez,ew, toggle)) return false;
0586 
0587     m_zs.push_back(bz);
0588     m_ws.push_back(bw);
0589 
0590     return true;
0591   }
0592 
0593 protected:
0594   bool intersect_triangle(float a_1x,float a_1y,float a_1z,float a_1w,
0595                           float a_2x,float a_2y,float a_2z,float a_2w,
0596                           float a_3x,float a_3y,float a_3z,float a_3w) {
0597     //test a triangle.
0598 
0599     if(is_inside(a_1x,a_1y,a_1z,a_1w)) return true;
0600     if(is_inside(a_2x,a_2y,a_2z,a_2w)) return true;
0601     if(is_inside(a_3x,a_3y,a_3z,a_3w)) return true;
0602 
0603     // alll points are outside.
0604 
0605     float x1,y1;
0606     to_pick_ndc(a_1x,a_1y,x1,y1);
0607     float x2,y2;
0608     to_pick_ndc(a_2x,a_2y,x2,y2);
0609 
0610     bool toggle;
0611     float bx,by,bz,bw,ex,ey,ez,ew;
0612 
0613     bx = x1;
0614     by = y1;
0615     bz = a_1z;
0616     bw = a_1w;
0617 
0618     ex = x2;
0619     ey = y2;
0620     ez = a_2z;
0621     ew = a_2w;
0622     if(ortho_clip_line(bx,by,bz,bw, ex,ey,ez,ew, toggle)) {
0623       m_zs.push_back(bz);
0624       m_ws.push_back(bw);
0625       return true;
0626     }
0627 
0628     float x3,y3;
0629     to_pick_ndc(a_3x,a_3y,x3,y3);
0630 
0631     bx = x2;
0632     by = y2;
0633     bz = a_2z;
0634     bw = a_2w;
0635 
0636     ex = x3;
0637     ey = y3;
0638     ez = a_3z;
0639     ew = a_3w;
0640     if(ortho_clip_line(bx,by,bz,bw, ex,ey,ez,ew, toggle)) {
0641       m_zs.push_back(bz);
0642       m_ws.push_back(bw);
0643       return true;
0644     }
0645 
0646     bx = x1;
0647     by = y1;
0648     bz = a_1z;
0649     bw = a_1w;
0650 
0651     ex = x3;
0652     ey = y3;
0653     ez = a_3z;
0654     ew = a_3w;
0655     if(ortho_clip_line(bx,by,bz,bw, ex,ey,ez,ew, toggle)) {
0656       m_zs.push_back(bz);
0657       m_ws.push_back(bw);
0658       return true;
0659     }
0660 
0661     // no intersection with edges.
0662     // but the triangle may surround [-1,1]x[-1,1] !
0663 
0664     // test if O=(0,0) is inside the triangle :
0665 
0666     float xo = 0;
0667     float yo = 0;
0668     //float zo = 0;
0669 
0670    {float cp2 = (x2-x1)*(y3-y1)-(y2-y1)*(x3-x1);  //(2-1).cross(3-1)
0671     if(cp2==0) return false;       // (1,2,3) aligned points.
0672     float cp1 = (x2-x1)*(yo-y1)-(y2-y1)*(xo-x1);
0673     if(cp1==0) { // O on (1,2). We can't pass here.
0674       //m_out << "pick_action::intersect_triangle : case 0." << std::endl;
0675       //m_zs.push_back(???);
0676       //m_ws.push_back(???);
0677       return false;
0678     }
0679     if((cp1*cp2)<0) return false;} // O 3 not on same side than (1,2)
0680 
0681    {float cp2 = (x3-x2)*(y1-y2)-(y3-y2)*(x1-x2); //(3-2).cross(1-2)
0682     if(cp2==0) return false;       // (1,2,3) aligned points.
0683     float cp1 = (x3-x2)*(yo-y2)-(y3-y2)*(xo-x2);
0684     if(cp1==0) { // O on (2,3). We can't pass here.
0685       //m_out << "pick_action::intersect_triangle : case 1." << std::endl;
0686       //m_zs.push_back(???);
0687       //m_ws.push_back(???);
0688       return false;
0689     }
0690     if((cp1*cp2)<0) return false;} // O 1 not on same side than (2,3)
0691 
0692    {float cp2 = (x1-x3)*(y2-y3)-(y1-y3)*(x2-x3); //(1-3).cross(2-3)
0693     if(cp2==0) return false;       // (1,2,3) aligned points.
0694     float cp1 = (x1-x3)*(yo-y3)-(y1-y3)*(xo-x3);
0695     if(cp1==0) { // O on (3,1). We can't pass here.
0696       //m_out << "pick_action::intersect_triangle : case 2." << std::endl;
0697       //m_zs.push_back(???);
0698       //m_ws.push_back(???);
0699       return false;
0700     }
0701     if((cp1*cp2)<0) return false;} // O 2 not on same side than (3,1)
0702 
0703     //std::cout << " (0,0) inside. " << std::endl;
0704 
0705     //get z of O=(0,0) on the triangle :
0706 
0707     //NOTE : optimize ?
0708 
0709     vec3f O(0,0,0);
0710     line<vec3f> ln(O,O+vec3f(0,0,1));
0711 
0712     vec3f pz;
0713    {vec3f p1(x1,y1,a_1z);
0714     vec3f p2(x2,y2,a_2z);
0715     vec3f p3(x3,y3,a_3z);
0716     plane<vec3f> pl(p1,p2,p3);
0717     if(!pl.intersect(ln,pz)) {
0718       m_out << "pick_action::intersect_triangle :"
0719             << " z plane/line intersection failed."
0720             << std::endl;
0721       return false;
0722     }}
0723 
0724     // we can get w by the same plane intersection by changing the zs to ws :
0725     // (in the xy plane, 1,2,3 points have same projection, then the
0726     //  z axis intersection with the triangle hits the same point done with zs
0727     //  than with ws).
0728     vec3f pw;
0729    {vec3f p1(x1,y1,a_1w);
0730     vec3f p2(x2,y2,a_2w);
0731     vec3f p3(x3,y3,a_3w);
0732     plane<vec3f> pl(p1,p2,p3);
0733     if(!pl.intersect(ln,pw)) {
0734       m_out << "pick_action::intersect_triangle :"
0735             << " plane/line intersection failed."
0736             << std::endl;
0737       return false;
0738     }}
0739     //::printf("debug : w planey %g\n",p[2]);
0740 
0741     //m_out << "pick_action::intersect_triangle :"
0742     //      << " p " << p[0] << " " << p[1] << " " << p[2]
0743     //      << std::endl;
0744 
0745     m_zs.push_back(pz[2]);
0746     m_ws.push_back(pw[2]);
0747 
0748 /*
0749     // check by using interpolation :
0750    {vec3f p1(x1,y1,a_1z);
0751     vec3f p2(x2,y2,a_2z);
0752     vec3f p3(x3,y3,a_3z);
0753     line<vec3f> l1p(p1,pz);
0754     line<vec3fy> l23(p2,p3);
0755     vec3f q; //on 23 side.
0756     float prec = 1e10-8;
0757     if(!l1p.intersect(l23,q,prec)) {
0758       m_out << "pick_action::intersect_triangle :"
0759             << " line/line intersection failed."
0760             << std::endl;
0761       return false;
0762     }
0763     float dq2 = (q-p2).length();
0764     float d32 = (p3-p2).length();
0765     if(d32==0) {
0766       m_out << "pick_action::intersect_triangle :"
0767             << " zero d32."
0768             << std::endl;
0769       return false;
0770     }
0771     float dp1 = (pz-p1).length();
0772     float dq1 = (q-p1).length();
0773     if(dq1==0) {
0774       m_out << "pick_action::intersect_triangle :"
0775             << " zero dq1."
0776             << std::endl;
0777       return false;
0778     }
0779 
0780     float wq = a_2w + (a_3w-a_2w)*(dq2/d32);
0781     float wp = a_1w + (wq-a_1w)*(dp1/dq1);
0782 
0783     float zq = a_2z + (a_3z-a_2z)*(dq2/d32);
0784     float zp = a_1z + (zq-a_1z)*(dp1/dq1);
0785 
0786     ::printf("debug : pz[2] %g zp %g\n",pz[2],zp);
0787     ::printf("debug : pw[2] %g wp %g\n",pw[2],wp);
0788     }
0789 */
0790 
0791     return true;
0792   }
0793 protected:
0794   void set_to_pick_ndc() { //OPTIMIZATION
0795     float cx = (m_l+m_r)/2;
0796     cx /= float(m_ww);
0797     cx *= 2;
0798     float cy = (m_b+m_t)/2;
0799     cy /= float(m_wh);
0800     cy *= 2;
0801 
0802     float sx = m_r-m_l;
0803     sx /= float(m_ww);
0804     sx *= 2;
0805     float sy = m_t-m_b;
0806     sy /= float(m_wh);
0807     sy *= 2;
0808 
0809     //then now cx,cy,sx,sw in [0,2]x[0,2] coords.
0810     cx -= 1;
0811     cy -= 1;
0812     //then now cx,cy,sx,sw in [-1,1]x[-1,1] coords.
0813     m_cx = cx;
0814     m_cy = cy;
0815     m_sx = sx;
0816     m_sy = sy;
0817   }
0818   void to_pick_ndc(const float& a_fx,const float& a_fy,float& a_x,float& a_y) const {
0819     a_x = 2*(a_fx-m_cx)/m_sx;
0820     a_y = 2*(a_fy-m_cy)/m_sy;
0821   }
0822 protected:
0823   static bool ortho_clip_line(float& a_bx,float& a_by,float& a_bz,float& a_bw,
0824                               float& a_ex,float& a_ey,float& a_ez,float& a_ew,
0825                               /*bool a_doz,*/bool& a_toggle) {
0826     // it tests against a [-1,1]x[-1,1] box.
0827 
0828     // toggle means that at return begin contains end and end contains begin).
0829     //
0830     // begin out, end out
0831     //   output : a_toggle = false, return false.
0832     // begin in, end  in
0833     //   output : a_toggle = false, return true.
0834     // begin in, end out
0835     //   output : a_toggle = true, begin = clipping point, return true.
0836     // begin out, end  in
0837     //   output : a_toggle = false, begin = clipping point, return true.
0838 
0839     a_toggle = false;
0840 
0841     const unsigned int FILTER__NOZ = 0xf;   //4 left right bits set to 1.
0842     //const unsigned int FILTER__Z = 0x3f;  //6 left right bits set to 1.
0843 
0844     bool accept = false;
0845     bool done = false;
0846     do {
0847       unsigned int bout = ortho_out(a_bx,a_by/*,a_bz,a_doz*/);
0848       unsigned int eout = ortho_out(a_ex,a_ey/*,a_ez,a_doz*/);
0849       bool reject = ( (bout & eout & FILTER__NOZ) !=0  ? true : false);
0850       if(reject) { //begin and end have a common "outside bit" raised.
0851         done = true;
0852       } else {
0853         accept = !bout && !eout;
0854         if(accept) { //begin and end have all outside-bits to zero.
0855           done = true;
0856         } else {
0857           if(!bout) { // begin inside. toggle begin and end.
0858             unsigned int tout = eout;
0859             float tx = a_ex;
0860             float ty = a_ey;
0861             float tz = a_ez;
0862             float tw = a_ew;
0863 
0864             eout = bout;
0865             a_ex = a_bx;
0866             a_ey = a_by;
0867             a_ez = a_bz;
0868             a_ew = a_bw;
0869 
0870             bout = tout;
0871             a_bx = tx;
0872             a_by = ty;
0873             a_bz = tz;
0874             a_bw = tw;
0875 
0876             a_toggle = true;
0877           }
0878           if(bout & (1<<0)) { // by > 1
0879             float t = a_ey - a_by;
0880             //CHECK_DIV(t,"ClipLineParallel")
0881             t = (1 - a_by)/t;
0882             a_bx += (a_ex - a_bx) * t;
0883             a_by  = 1;
0884             a_bz += (a_ez - a_bz) * t;
0885             a_bw += (a_ew - a_bw) * t;
0886           } else if(bout & (1<<1)) { // by < -1
0887             float t = a_ey-a_by;
0888             //CHECK_DIV(t,"ClipLineParallel")
0889             t = (-1 - a_by)/t;
0890             a_bx += (a_ex - a_bx) * t;
0891             a_by  = -1;
0892             a_bz += (a_ez - a_bz) * t;
0893             a_bw += (a_ew - a_bw) * t;
0894           } else if(bout & (1<<2)) { // bx > 1
0895             float t = a_ex-a_bx;
0896             //CHECK_DIV    (t,"ClipLineParallel")
0897             t = (1 - a_bx)/t;
0898             a_bx  = 1;
0899             a_by += (a_ey - a_by) * t;
0900             a_bz += (a_ez - a_bz) * t;
0901             a_bw += (a_ew - a_bw) * t;
0902           } else if(bout & (1<<3)) { // bx < -1
0903             float t = a_ex-a_bx;
0904             //CHECK_DIV    (t,"ClipLineParallel")
0905             t = (-1 - a_bx)/t;
0906             a_bx  = -1;
0907             a_by += (a_ey - a_by) * t;
0908             a_bz += (a_ez - a_bz) * t;
0909             a_bw += (a_ew - a_bw) * t;
0910           }
0911           // z = -1.
0912           // z =  0.
0913           // G.Barrand : do not do z clipping
0914        /* else if(a_doz && (bout & (1<<4)) ) { //bz < -1
0915             float t = a_ez-a_bz;
0916             //CHECK_DIV    (t,"ClipLineParallel")
0917             t = (-1 - a_z)/t;
0918             a_bx += (a_ex - a_bx) * t;
0919             a_by += (a_ey - a_by) * t;
0920             a_bz  = -1;
0921             a_bw += (a_ew - a_bw) * t;
0922           } else if(a_doz && (bout & (1<<5)) ) { //bz > 0
0923             t = a_ez - a_bz;
0924             //CHECK_DIV    (t,"ClipLineParallel")
0925             t = (- a_bz)/t;
0926             a_bx += (a_ex - a_bx) * t;
0927             a_by += (a_ey - a_by) * t;
0928             a_bz  = 0;
0929             a_bw += (a_ew - a_bw) * t;
0930           } */
0931         }
0932       }
0933     } while (!done);
0934     return accept;
0935   }
0936 
0937   static unsigned int ortho_out(float a_x,float a_y/*,float a_z,bool a_doz*/){
0938     unsigned int out = 0;
0939     if(a_y> 1) out |= (1<<0);
0940     if(a_y<-1) out |= (1<<1);
0941     if(a_x> 1) out |= (1<<2);
0942     if(a_x<-1) out |= (1<<3);
0943     //if(!a_doz) return out;
0944     //if(a_z<-1) out |= (1<<4);
0945     //if(a_z> 0) out |= (1<<5);
0946     return out;
0947   }
0948 
0949 protected:
0950   // picking region (in window coordinates, (0,0) = bottom-left ) :
0951   float m_l;
0952   float m_r;
0953   float m_b;
0954   float m_t;
0955 
0956   bool m_stop_at_first;
0957 
0958   bool m_done;
0959   sg::node* m_node;
0960 
0961   std::vector<float> m_zs;
0962   std::vector<float> m_ws;
0963   std::vector<pick_t> m_picks;
0964 
0965   //OPTIMIZATION:
0966   float m_cx,m_cy,m_sx,m_sy;
0967 };
0968 
0969 }}
0970 
0971 #endif