Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/externals/g4tools/include/tools/sg/pick_action

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  1 // Copyright (C) 2010, Guy Barrand. All rights reserved.
  2 // See the file tools.license for terms.
  3 
  4 #ifndef tools_sg_pick_action
  5 #define tools_sg_pick_action
  6 
  7 #include "matrix_action"
  8 #include "primitive_visitor"
  9 
 10 #include "../lina/plane"
 11 #include "../vmanip"
 12 
 13 #include "node"
 14 
 15 namespace tools {
 16 namespace sg {
 17 
 18 class pick_element {
 19 public:
 20   pick_element(sg::node& a_node,const std::vector<float>& a_zs,const std::vector<float>& a_ws,const sg::state& a_state)
 21   :m_node(a_node)
 22   ,m_zs(a_zs)
 23   ,m_ws(a_ws)
 24   ,m_state(a_state)
 25   {}
 26   virtual ~pick_element(){}
 27 public:
 28   pick_element(const pick_element& a_from)
 29   :m_node(a_from.m_node)
 30   ,m_zs(a_from.m_zs)
 31   ,m_ws(a_from.m_ws)
 32   ,m_state(a_from.m_state)
 33   {}
 34   pick_element& operator=(const pick_element& a_from){
 35     m_zs = a_from.m_zs;
 36     m_ws = a_from.m_ws;
 37     m_state = a_from.m_state;
 38     return *this;
 39   }
 40 public:
 41   const sg::node& node() const {return m_node;}
 42   sg::node& node() {return m_node;}
 43 
 44   const std::vector<float>& zs() const {return m_zs;}
 45   std::vector<float>& zs() {return m_zs;}
 46 
 47   const std::vector<float>& ws() const {return m_ws;}
 48   std::vector<float>& ws() {return m_ws;}
 49 
 50   const sg::state& state() const {return m_state;}
 51   sg::state& state() {return m_state;}
 52 protected:
 53   sg::node& m_node;
 54   std::vector<float> m_zs;
 55   std::vector<float> m_ws;
 56   sg::state m_state;
 57 };
 58 
 59 class pick_action : public matrix_action, public primitive_visitor {
 60   TOOLS_ACTION(pick_action,tools::sg::pick_action,matrix_action)
 61 protected:
 62 
 63   virtual bool project(float& a_x,float& a_y,float& a_z,float& a_w) {
 64     return parent::project_point(a_x,a_y,a_z,a_w);
 65   }
 66 
 67   virtual bool add_point(float a_x,float a_y,float a_z,float a_w) {
 68     if(is_inside(a_x,a_y,a_z,a_w)) { //we have a pick.
 69       m_done = true;
 70       return false; //to stop
 71     }
 72     return true; //continue.
 73   }
 74 
 75   virtual bool add_point(float a_x,float a_y,float a_z,float a_w,
 76                          float,float,float,float) {
 77     return pick_action::add_point(a_x,a_y,a_z,a_w);
 78   }
 79 
 80   virtual bool add_line(float a_bx,float a_by,float a_bz,float a_bw,
 81                         float a_ex,float a_ey,float a_ez,float a_ew) {
 82     if(is_inside(a_bx,a_by,a_bz,a_bw)) {
 83       m_done = true;
 84       return false;
 85     }
 86     if(is_inside(a_ex,a_ey,a_ez,a_ew)) {
 87       m_done = true;
 88       return false;
 89     }
 90     if(intersect_line(a_bx,a_by,a_bz,a_bw,
 91                       a_ex,a_ey,a_ez,a_ew)) {
 92       m_done = true;
 93       return false;
 94     }
 95     return true;
 96   }
 97 
 98   virtual bool add_line(float a_bx,float a_by,float a_bz,float a_bw,
 99                         float,float,float,float,
100                         float a_ex,float a_ey,float a_ez,float a_ew,
101                         float,float,float,float){
102     return pick_action::add_line(a_bx,a_by,a_bz,a_bw,a_ex,a_ey,a_ez,a_ew);
103   }
104 
105   virtual bool add_triangle(float a_p1x,float a_p1y,float a_p1z,float a_p1w,
106                             float a_p2x,float a_p2y,float a_p2z,float a_p2w,
107                             float a_p3x,float a_p3y,float a_p3z,float a_p3w){
108     if(intersect_triangle(a_p1x,a_p1y,a_p1z,a_p1w,
109                           a_p2x,a_p2y,a_p2z,a_p2w,
110                           a_p3x,a_p3y,a_p3z,a_p3w)) {
111       m_done = true;
112       return false;
113     }
114     return true;
115   }
116 
117   virtual bool add_triangle(float a_p1x,float a_p1y,float a_p1z,float a_p1w,
118                             float,float,float,float,
119                             float a_p2x,float a_p2y,float a_p2z,float a_p2w,
120                             float,float,float,float,
121                             float a_p3x,float a_p3y,float a_p3z,float a_p3w,
122                             float,float,float,float){
123     return pick_action::add_triangle(a_p1x,a_p1y,a_p1z,a_p1w,
124                                      a_p2x,a_p2y,a_p2z,a_p2w,
125                                      a_p3x,a_p3y,a_p3z,a_p3w);
126   }
127 
128   virtual bool project_normal(float&,float&,float&) {return true;}
129   virtual bool add_point_normal(float a_x,float a_y,float a_z,float a_w,
130                                 float,float,float) {
131     return pick_action::add_point(a_x,a_y,a_z,a_w);
132   }
133 
134   virtual bool add_point_normal(float a_x,float a_y,float a_z,float a_w,
135                                 float,float,float,
136                                 float,float,float,float) {
137     return pick_action::add_point(a_x,a_y,a_z,a_w);
138   }
139 
140   virtual bool add_line_normal(float a_bx,float a_by,float a_bz,float a_bw, float,float,float,
141                                float a_ex,float a_ey,float a_ez,float a_ew, float,float,float) {
142     return pick_action::add_line(a_bx,a_by,a_bz,a_bw,a_ex,a_ey,a_ez,a_ew);
143   }
144   virtual bool add_line_normal(float a_bx,float a_by,float a_bz,float a_bw, float,float,float, float,float,float,float,
145                                float a_ex,float a_ey,float a_ez,float a_ew, float,float,float, float,float,float,float) {
146     return pick_action::add_line(a_bx,a_by,a_bz,a_bw,a_ex,a_ey,a_ez,a_ew);
147   }
148 
149   virtual bool add_triangle_normal(float a_p1x,float a_p1y,float a_p1z,float a_p1w, float,float,float,
150                                    float a_p2x,float a_p2y,float a_p2z,float a_p2w, float,float,float,
151                                    float a_p3x,float a_p3y,float a_p3z,float a_p3w, float,float,float) {
152     return pick_action::add_triangle(a_p1x,a_p1y,a_p1z,a_p1w,
153                                      a_p2x,a_p2y,a_p2z,a_p2w,
154                                      a_p3x,a_p3y,a_p3z,a_p3w);
155   }
156   virtual bool add_triangle_normal(float a_p1x,float a_p1y,float a_p1z,float a_p1w,
157                                    float,float,float, float,float,float,float,
158                                    float a_p2x,float a_p2y,float a_p2z,float a_p2w,
159                                    float,float,float, float,float,float,float,
160                                    float a_p3x,float a_p3y,float a_p3z,float a_p3w,
161                                    float,float,float, float,float,float,float) {
162     return pick_action::add_triangle(a_p1x,a_p1y,a_p1z,a_p1w,
163                                      a_p2x,a_p2y,a_p2z,a_p2w,
164                                      a_p3x,a_p3y,a_p3z,a_p3w);
165   }
166 public:
167   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)
168   :parent(a_out,a_ww,a_wh)
169   ,m_l(a_l)
170   ,m_r(a_r)
171   ,m_b(a_b)
172   ,m_t(a_t)
173   ,m_stop_at_first(false) //same as selection
174   ,m_done(false)
175   ,m_node(0)
176   {
177     set_to_pick_ndc(); //OPTIMIZATION
178   }
179   virtual ~pick_action(){}
180 public:
181   pick_action(const pick_action& a_from)
182   :parent(a_from)
183   ,primitive_visitor(a_from)
184   ,m_l(a_from.m_l)
185   ,m_r(a_from.m_r)
186   ,m_b(a_from.m_b)
187   ,m_t(a_from.m_t)
188   ,m_stop_at_first(a_from.m_stop_at_first)
189   ,m_done(false)
190   ,m_node(0)
191   {
192     set_to_pick_ndc(); //OPTIMIZATION
193   }
194   pick_action& operator=(const pick_action& a_from){
195     parent::operator=(a_from);
196     primitive_visitor::operator=(a_from);
197     m_l = a_from.m_l;
198     m_r = a_from.m_r;
199     m_b = a_from.m_b;
200     m_t = a_from.m_t;
201     m_stop_at_first = a_from.m_stop_at_first;
202     m_done = false;
203     m_node = 0;
204     m_zs.clear();
205     m_ws.clear();
206     m_picks.clear();
207     set_to_pick_ndc(); //OPTIMIZATION
208     return *this;
209   }
210 public:
211   void reset() {
212     parent::reset();
213     m_done = false;
214     m_node = 0;
215     m_zs.clear();
216     m_ws.clear();
217     m_picks.clear();
218   }
219 
220   void set_win_size(unsigned a_ww,unsigned int a_wh) {
221     m_ww = a_ww;
222     m_wh = a_wh;
223     sg::state& _state = state();
224     _state.m_ww = a_ww;
225     _state.m_wh = a_wh;
226     m_states.clear();
227     reset();
228   }
229 
230   void set_area(float a_l,float a_r,float a_b,float a_t) {
231     // a_l,a_r,a_b,a_t are in window coordinates (pixels)
232     // but handled in floats for intersection computation precision.
233     // WARNING : we must have a_t>a_b and a_r>a_l. No check is done for that.
234     m_l = a_l;
235     m_r = a_r;
236     m_b = a_b;
237     m_t = a_t;
238     set_to_pick_ndc(); //OPTIMIZATION
239   }
240 
241   void get_area(float& a_l,float& a_r,float& a_b,float& a_t) const {
242     a_l = m_l;
243     a_r = m_r;
244     a_b = m_b;
245     a_t = m_t;
246   }
247 
248   /////////////////////////////////////////////
249   /////////////////////////////////////////////
250   /////////////////////////////////////////////
251   void set_stop_at_first(bool a_value) {m_stop_at_first = a_value;}
252   bool stop_at_first() const {return m_stop_at_first;}
253 
254   void set_done(bool a_value) {m_done = a_value;}
255   bool done() const {return m_done;}
256 
257   void set_node(sg::node* a_node) {m_node = a_node;}
258   sg::node* node() const {return m_node;}
259 
260   /////////////////////////////////////////////
261   /////////////////////////////////////////////
262   /////////////////////////////////////////////
263   typedef pick_element pick_t;
264 
265   void add_pick(sg::node& a_node,
266                 const std::vector<float>& a_zs,
267                 const std::vector<float>& a_ws,
268                 const sg::state& a_state) {
269     m_picks.push_back(pick_t(a_node,a_zs,a_ws,a_state));
270   }
271   const std::vector<pick_t>& picks() const {return m_picks;}
272 
273   void dump_picks() {
274     m_out << "tools::sg::pick_action :"
275           << " number of picks " << m_picks.size()
276           << std::endl;
277     std::vector<pick_t>::const_iterator it;
278     for(it=m_picks.begin();it!=m_picks.end();++it) {
279       m_out << "  " << (*it).node().s_cls();
280 
281       std::vector<float>::const_iterator itz;
282       for(itz=(*it).zs().begin();itz!=(*it).zs().end();++itz) {
283         m_out  << "  " << *itz;
284       }
285 
286       m_out << std::endl;
287     }
288   }
289 
290   pick_t* closest_pick() {
291     if(m_picks.empty()) return 0;
292     //closest point is minimum z !
293     //  near -> -1
294     //  far  ->  1
295 
296     // find first pick_t with not empty zs :
297     pick_t* pck = 0;
298     float z;
299     std::vector<pick_t>::const_iterator it;
300     for(it=m_picks.begin();it!=m_picks.end();++it) {
301       if(minimum((*it).zs(),z)) {
302         pck = (pick_t*)&(*it);
303         break;
304       }
305     }
306     if(!pck) return 0;
307     it++;
308     for(;it!=m_picks.end();++it) {
309       float zi;
310       if(minimum((*it).zs(),zi)) {
311         if(zi<=z) {
312           pck = (pick_t*)&(*it);
313           z = zi;
314         }
315       }
316     }
317     return pck;
318   }
319 
320   const std::vector<float>& zs() const {return m_zs;}
321   std::vector<float>& zs() {return m_zs;}
322 
323   const std::vector<float>& ws() const {return m_ws;}
324   std::vector<float>& ws() {return m_ws;}
325 
326   void set_matrices_to_identity() {
327     projection_matrix() = m_identity;
328     model_matrix() = m_identity;
329   }
330   void set_matrices_from_state() {
331     const sg::state& _state = state();
332     projection_matrix() = _state.m_proj;
333     model_matrix() = _state.m_model;
334   }
335 public:
336   bool add__primitive_xy(sg::node& a_node,
337                          gl::mode_t a_mode,
338                          size_t a_floatn,const float* a_xys,
339                          bool a_stop = false,
340                          bool a_triangle_revert = false){
341     if(!a_floatn) return false;
342     if(m_stop_at_first){
343       add_primitive_xy(a_mode,a_floatn,a_xys,a_stop,a_triangle_revert);
344       if(m_done) {
345         m_node = &a_node;
346         return true;
347       }
348     } else {
349       m_done = false;
350       m_zs.clear();
351       add_primitive_xy(a_mode,a_floatn,a_xys,a_stop,a_triangle_revert);
352       if(m_done) {
353         add_pick(a_node,m_zs,m_ws,state());
354         m_done = false;
355         return true;
356       }
357     }
358     return false;
359   }
360 
361   bool add__primitive_xy(sg::node& a_node,
362                          gl::mode_t a_mode,
363                          const std::vector<float>& a_xys,
364                          bool a_stop = false,
365                          bool a_triangle_revert = false){
366     if(a_xys.empty()) return false;
367     if(m_stop_at_first){
368       add_primitive_xy(a_mode,a_xys,a_stop,a_triangle_revert);
369       if(m_done) {
370         m_node = &a_node;
371         return true;
372       }
373     } else {
374       m_done = false;
375       m_zs.clear();
376       add_primitive_xy(a_mode,a_xys,a_stop,a_triangle_revert);
377       if(m_done) {
378         add_pick(a_node,m_zs,m_ws,state());
379         m_done = false;
380         return true;
381       }
382     }
383     return false;
384   }
385 
386   bool add__line_strip_xy(sg::node& a_node,size_t a_floatn,const float* a_xys,bool a_stop = false){
387     if(!a_floatn) return false;
388     if(m_stop_at_first){
389       add_line_strip_xy(a_floatn,a_xys,a_stop);
390       if(m_done) {
391         m_node = &a_node;
392         return true;
393       }
394     } else {
395       m_done = false;
396       m_zs.clear();
397       add_line_strip_xy(a_floatn,a_xys,a_stop);
398       if(m_done) {
399         add_pick(a_node,m_zs,m_ws,state());
400         m_done = false;
401         return true;
402       }
403     }
404     return false;
405   }
406 
407   bool add__lines_xy(sg::node& a_node,
408                      const std::vector<float>& a_xys,
409                      bool a_stop = false) {
410     if(a_xys.empty()) return false;
411     if(m_stop_at_first){
412       add_lines_xy(a_xys,a_stop);
413       if(m_done) {
414         m_node = &a_node;
415         return true;
416       }
417     } else {
418       m_done = false;
419       m_zs.clear();
420       add_lines_xy(a_xys,a_stop);
421       if(m_done) {
422         add_pick(a_node,m_zs,m_ws,state());
423         m_done = false;
424         return true;
425       }
426     }
427     return false;
428   }
429 
430 public:
431   bool add__primitive(sg::node& a_node,gl::mode_t a_mode,size_t a_floatn,const float* a_xyzs,bool a_stop = false){
432     if(!a_floatn) return false;
433     if(m_stop_at_first){
434       add_primitive(a_mode,a_floatn,a_xyzs,a_stop);
435       if(m_done) {
436         m_node = &a_node;
437         return true;
438       }
439     } else {
440       m_done = false;
441       m_zs.clear();
442       add_primitive(a_mode,a_floatn,a_xyzs,a_stop);
443       if(m_done) {
444         add_pick(a_node,m_zs,m_ws,state());
445         m_done = false;
446         return true;
447       }
448     }
449     return false;
450   }
451 
452   bool add__primitive(sg::node& a_node,gl::mode_t a_mode,const std::vector<float>& a_xyzs,bool a_stop = false) {
453     if(a_xyzs.empty()) return false;
454     if(m_stop_at_first){
455       add_primitive(a_mode,a_xyzs,a_stop);
456       if(m_done) {
457         m_node = &a_node;
458         return true;
459       }
460     } else {
461       m_done = false;
462       m_zs.clear();
463       add_primitive(a_mode,a_xyzs,a_stop);
464       if(m_done) {
465         add_pick(a_node,m_zs,m_ws,state());
466         m_done = false;
467         return true;
468       }
469     }
470     return false;
471   }
472 
473   bool add__line_strip(sg::node& a_node,size_t a_floatn,const float* a_xyzs,bool a_stop = false){
474     if(!a_floatn) return false;
475     if(m_stop_at_first){
476       add_line_strip(a_floatn,a_xyzs,a_stop);
477       if(m_done) {
478         m_node = &a_node;
479         return true;
480       }
481     } else {
482       m_done = false;
483       m_zs.clear();
484       add_line_strip(a_floatn,a_xyzs,a_stop);
485       if(m_done) {
486         add_pick(a_node,m_zs,m_ws,state());
487         m_done = false;
488         return true;
489       }
490     }
491     return false;
492   }
493 
494   bool add__triangles(sg::node& a_node,
495                       size_t a_floatn,
496                       const float* a_xyzs,
497                       bool a_stop = false){
498     if(!a_floatn) return false;
499     if(m_stop_at_first){
500       add_triangles(a_floatn,a_xyzs,a_stop);
501       if(m_done) {
502         m_node = &a_node;
503         return true;
504       }
505     } else {
506       m_done = false;
507       m_zs.clear();
508       add_triangles(a_floatn,a_xyzs,a_stop);
509       if(m_done) {
510         add_pick(a_node,m_zs,m_ws,state());
511         m_done = false;
512         return true;
513       }
514     }
515     return false;
516   }
517 
518   bool add__lines(sg::node& a_node,
519                   const std::vector<float>& a_xyzs,
520                   bool a_stop = false){
521     if(a_xyzs.empty()) return false;
522     if(m_stop_at_first){
523       add_lines(a_xyzs,a_stop);
524       if(m_done) {
525         m_node = &a_node;
526         return true;
527       }
528     } else {
529       m_done = false;
530       m_zs.clear();
531       add_lines(a_xyzs,a_stop);
532       if(m_done) {
533         add_pick(a_node,m_zs,m_ws,state());
534         m_done = false;
535         return true;
536       }
537     }
538     return false;
539   }
540 
541 public: //for markers
542   bool is_inside(float a_x,float a_y,float a_z,float a_w) {
543     //std::cout << "debug : tools::sg::pick_action::is_inside :"
544     //      << " x " << a_x
545     //      << " y " << a_y
546     //      << std::endl;
547 
548     // In principle we should receive (because of proj x model matrix
549     // mult of world coord points) point in [-1,1]x[-1,1].
550 
551     float x,y;
552     to_pick_ndc(a_x,a_y,x,y);
553 
554     if(x<-1) return false;
555     if(1<x) return false;
556     if(y<-1) return false;
557     if(1<y) return false;
558 
559     //std::cout << "debug : tools::sg::pick_action::is_inside :"
560     //      << " inside !"
561     //      << std::endl;
562 
563     m_zs.push_back(a_z);
564     m_ws.push_back(a_w);
565 
566     return true;
567   }
568   bool intersect_line(float a_bx,float a_by,float a_bz,float a_bw,
569                       float a_ex,float a_ey,float a_ez,float a_ew) {
570 
571     // a_bz, a_ez are used only to compute the intersection point.
572 
573     float bx,by;
574     to_pick_ndc(a_bx,a_by,bx,by);
575     float ex,ey;
576     to_pick_ndc(a_ex,a_ey,ex,ey);
577 
578     //no check on z is done.
579     float bz = a_bz;
580     float bw = a_bw;
581     float ez = a_ez;
582     float ew = a_ew;
583 
584     bool toggle;
585     if(!ortho_clip_line(bx,by,bz,bw, ex,ey,ez,ew, toggle)) return false;
586 
587     m_zs.push_back(bz);
588     m_ws.push_back(bw);
589 
590     return true;
591   }
592 
593 protected:
594   bool intersect_triangle(float a_1x,float a_1y,float a_1z,float a_1w,
595                           float a_2x,float a_2y,float a_2z,float a_2w,
596                           float a_3x,float a_3y,float a_3z,float a_3w) {
597     //test a triangle.
598 
599     if(is_inside(a_1x,a_1y,a_1z,a_1w)) return true;
600     if(is_inside(a_2x,a_2y,a_2z,a_2w)) return true;
601     if(is_inside(a_3x,a_3y,a_3z,a_3w)) return true;
602 
603     // alll points are outside.
604 
605     float x1,y1;
606     to_pick_ndc(a_1x,a_1y,x1,y1);
607     float x2,y2;
608     to_pick_ndc(a_2x,a_2y,x2,y2);
609 
610     bool toggle;
611     float bx,by,bz,bw,ex,ey,ez,ew;
612 
613     bx = x1;
614     by = y1;
615     bz = a_1z;
616     bw = a_1w;
617 
618     ex = x2;
619     ey = y2;
620     ez = a_2z;
621     ew = a_2w;
622     if(ortho_clip_line(bx,by,bz,bw, ex,ey,ez,ew, toggle)) {
623       m_zs.push_back(bz);
624       m_ws.push_back(bw);
625       return true;
626     }
627 
628     float x3,y3;
629     to_pick_ndc(a_3x,a_3y,x3,y3);
630 
631     bx = x2;
632     by = y2;
633     bz = a_2z;
634     bw = a_2w;
635 
636     ex = x3;
637     ey = y3;
638     ez = a_3z;
639     ew = a_3w;
640     if(ortho_clip_line(bx,by,bz,bw, ex,ey,ez,ew, toggle)) {
641       m_zs.push_back(bz);
642       m_ws.push_back(bw);
643       return true;
644     }
645 
646     bx = x1;
647     by = y1;
648     bz = a_1z;
649     bw = a_1w;
650 
651     ex = x3;
652     ey = y3;
653     ez = a_3z;
654     ew = a_3w;
655     if(ortho_clip_line(bx,by,bz,bw, ex,ey,ez,ew, toggle)) {
656       m_zs.push_back(bz);
657       m_ws.push_back(bw);
658       return true;
659     }
660 
661     // no intersection with edges.
662     // but the triangle may surround [-1,1]x[-1,1] !
663 
664     // test if O=(0,0) is inside the triangle :
665 
666     float xo = 0;
667     float yo = 0;
668     //float zo = 0;
669 
670    {float cp2 = (x2-x1)*(y3-y1)-(y2-y1)*(x3-x1);  //(2-1).cross(3-1)
671     if(cp2==0) return false;       // (1,2,3) aligned points.
672     float cp1 = (x2-x1)*(yo-y1)-(y2-y1)*(xo-x1);
673     if(cp1==0) { // O on (1,2). We can't pass here.
674       //m_out << "pick_action::intersect_triangle : case 0." << std::endl;
675       //m_zs.push_back(???);
676       //m_ws.push_back(???);
677       return false;
678     }
679     if((cp1*cp2)<0) return false;} // O 3 not on same side than (1,2)
680 
681    {float cp2 = (x3-x2)*(y1-y2)-(y3-y2)*(x1-x2); //(3-2).cross(1-2)
682     if(cp2==0) return false;       // (1,2,3) aligned points.
683     float cp1 = (x3-x2)*(yo-y2)-(y3-y2)*(xo-x2);
684     if(cp1==0) { // O on (2,3). We can't pass here.
685       //m_out << "pick_action::intersect_triangle : case 1." << std::endl;
686       //m_zs.push_back(???);
687       //m_ws.push_back(???);
688       return false;
689     }
690     if((cp1*cp2)<0) return false;} // O 1 not on same side than (2,3)
691 
692    {float cp2 = (x1-x3)*(y2-y3)-(y1-y3)*(x2-x3); //(1-3).cross(2-3)
693     if(cp2==0) return false;       // (1,2,3) aligned points.
694     float cp1 = (x1-x3)*(yo-y3)-(y1-y3)*(xo-x3);
695     if(cp1==0) { // O on (3,1). We can't pass here.
696       //m_out << "pick_action::intersect_triangle : case 2." << std::endl;
697       //m_zs.push_back(???);
698       //m_ws.push_back(???);
699       return false;
700     }
701     if((cp1*cp2)<0) return false;} // O 2 not on same side than (3,1)
702 
703     //std::cout << " (0,0) inside. " << std::endl;
704 
705     //get z of O=(0,0) on the triangle :
706 
707     //NOTE : optimize ?
708 
709     vec3f O(0,0,0);
710     line<vec3f> ln(O,O+vec3f(0,0,1));
711 
712     vec3f pz;
713    {vec3f p1(x1,y1,a_1z);
714     vec3f p2(x2,y2,a_2z);
715     vec3f p3(x3,y3,a_3z);
716     plane<vec3f> pl(p1,p2,p3);
717     if(!pl.intersect(ln,pz)) {
718       m_out << "pick_action::intersect_triangle :"
719             << " z plane/line intersection failed."
720             << std::endl;
721       return false;
722     }}
723 
724     // we can get w by the same plane intersection by changing the zs to ws :
725     // (in the xy plane, 1,2,3 points have same projection, then the
726     //  z axis intersection with the triangle hits the same point done with zs
727     //  than with ws).
728     vec3f pw;
729    {vec3f p1(x1,y1,a_1w);
730     vec3f p2(x2,y2,a_2w);
731     vec3f p3(x3,y3,a_3w);
732     plane<vec3f> pl(p1,p2,p3);
733     if(!pl.intersect(ln,pw)) {
734       m_out << "pick_action::intersect_triangle :"
735             << " plane/line intersection failed."
736             << std::endl;
737       return false;
738     }}
739     //::printf("debug : w planey %g\n",p[2]);
740 
741     //m_out << "pick_action::intersect_triangle :"
742     //      << " p " << p[0] << " " << p[1] << " " << p[2]
743     //      << std::endl;
744 
745     m_zs.push_back(pz[2]);
746     m_ws.push_back(pw[2]);
747 
748 /*
749     // check by using interpolation :
750    {vec3f p1(x1,y1,a_1z);
751     vec3f p2(x2,y2,a_2z);
752     vec3f p3(x3,y3,a_3z);
753     line<vec3f> l1p(p1,pz);
754     line<vec3fy> l23(p2,p3);
755     vec3f q; //on 23 side.
756     float prec = 1e10-8;
757     if(!l1p.intersect(l23,q,prec)) {
758       m_out << "pick_action::intersect_triangle :"
759             << " line/line intersection failed."
760             << std::endl;
761       return false;
762     }
763     float dq2 = (q-p2).length();
764     float d32 = (p3-p2).length();
765     if(d32==0) {
766       m_out << "pick_action::intersect_triangle :"
767             << " zero d32."
768             << std::endl;
769       return false;
770     }
771     float dp1 = (pz-p1).length();
772     float dq1 = (q-p1).length();
773     if(dq1==0) {
774       m_out << "pick_action::intersect_triangle :"
775             << " zero dq1."
776             << std::endl;
777       return false;
778     }
779 
780     float wq = a_2w + (a_3w-a_2w)*(dq2/d32);
781     float wp = a_1w + (wq-a_1w)*(dp1/dq1);
782 
783     float zq = a_2z + (a_3z-a_2z)*(dq2/d32);
784     float zp = a_1z + (zq-a_1z)*(dp1/dq1);
785 
786     ::printf("debug : pz[2] %g zp %g\n",pz[2],zp);
787     ::printf("debug : pw[2] %g wp %g\n",pw[2],wp);
788     }
789 */
790 
791     return true;
792   }
793 protected:
794   void set_to_pick_ndc() { //OPTIMIZATION
795     float cx = (m_l+m_r)/2;
796     cx /= float(m_ww);
797     cx *= 2;
798     float cy = (m_b+m_t)/2;
799     cy /= float(m_wh);
800     cy *= 2;
801 
802     float sx = m_r-m_l;
803     sx /= float(m_ww);
804     sx *= 2;
805     float sy = m_t-m_b;
806     sy /= float(m_wh);
807     sy *= 2;
808 
809     //then now cx,cy,sx,sw in [0,2]x[0,2] coords.
810     cx -= 1;
811     cy -= 1;
812     //then now cx,cy,sx,sw in [-1,1]x[-1,1] coords.
813     m_cx = cx;
814     m_cy = cy;
815     m_sx = sx;
816     m_sy = sy;
817   }
818   void to_pick_ndc(const float& a_fx,const float& a_fy,float& a_x,float& a_y) const {
819     a_x = 2*(a_fx-m_cx)/m_sx;
820     a_y = 2*(a_fy-m_cy)/m_sy;
821   }
822 protected:
823   static bool ortho_clip_line(float& a_bx,float& a_by,float& a_bz,float& a_bw,
824                               float& a_ex,float& a_ey,float& a_ez,float& a_ew,
825                               /*bool a_doz,*/bool& a_toggle) {
826     // it tests against a [-1,1]x[-1,1] box.
827 
828     // toggle means that at return begin contains end and end contains begin).
829     //
830     // begin out, end out
831     //   output : a_toggle = false, return false.
832     // begin in, end  in
833     //   output : a_toggle = false, return true.
834     // begin in, end out
835     //   output : a_toggle = true, begin = clipping point, return true.
836     // begin out, end  in
837     //   output : a_toggle = false, begin = clipping point, return true.
838 
839     a_toggle = false;
840 
841     const unsigned int FILTER__NOZ = 0xf;   //4 left right bits set to 1.
842     //const unsigned int FILTER__Z = 0x3f;  //6 left right bits set to 1.
843 
844     bool accept = false;
845     bool done = false;
846     do {
847       unsigned int bout = ortho_out(a_bx,a_by/*,a_bz,a_doz*/);
848       unsigned int eout = ortho_out(a_ex,a_ey/*,a_ez,a_doz*/);
849       bool reject = ( (bout & eout & FILTER__NOZ) !=0  ? true : false);
850       if(reject) { //begin and end have a common "outside bit" raised.
851         done = true;
852       } else {
853         accept = !bout && !eout;
854         if(accept) { //begin and end have all outside-bits to zero.
855           done = true;
856         } else {
857           if(!bout) { // begin inside. toggle begin and end.
858             unsigned int tout = eout;
859             float tx = a_ex;
860             float ty = a_ey;
861             float tz = a_ez;
862             float tw = a_ew;
863 
864             eout = bout;
865             a_ex = a_bx;
866             a_ey = a_by;
867             a_ez = a_bz;
868             a_ew = a_bw;
869 
870             bout = tout;
871             a_bx = tx;
872             a_by = ty;
873             a_bz = tz;
874             a_bw = tw;
875 
876             a_toggle = true;
877           }
878           if(bout & (1<<0)) { // by > 1
879             float t = a_ey - a_by;
880             //CHECK_DIV(t,"ClipLineParallel")
881             t = (1 - a_by)/t;
882             a_bx += (a_ex - a_bx) * t;
883             a_by  = 1;
884             a_bz += (a_ez - a_bz) * t;
885             a_bw += (a_ew - a_bw) * t;
886           } else if(bout & (1<<1)) { // by < -1
887             float t = a_ey-a_by;
888             //CHECK_DIV(t,"ClipLineParallel")
889             t = (-1 - a_by)/t;
890             a_bx += (a_ex - a_bx) * t;
891             a_by  = -1;
892             a_bz += (a_ez - a_bz) * t;
893             a_bw += (a_ew - a_bw) * t;
894           } else if(bout & (1<<2)) { // bx > 1
895             float t = a_ex-a_bx;
896             //CHECK_DIV    (t,"ClipLineParallel")
897             t = (1 - a_bx)/t;
898             a_bx  = 1;
899             a_by += (a_ey - a_by) * t;
900             a_bz += (a_ez - a_bz) * t;
901             a_bw += (a_ew - a_bw) * t;
902           } else if(bout & (1<<3)) { // bx < -1
903             float t = a_ex-a_bx;
904             //CHECK_DIV    (t,"ClipLineParallel")
905             t = (-1 - a_bx)/t;
906             a_bx  = -1;
907             a_by += (a_ey - a_by) * t;
908             a_bz += (a_ez - a_bz) * t;
909             a_bw += (a_ew - a_bw) * t;
910           }
911           // z = -1.
912           // z =  0.
913           // G.Barrand : do not do z clipping
914        /* else if(a_doz && (bout & (1<<4)) ) { //bz < -1
915             float t = a_ez-a_bz;
916             //CHECK_DIV    (t,"ClipLineParallel")
917             t = (-1 - a_z)/t;
918             a_bx += (a_ex - a_bx) * t;
919             a_by += (a_ey - a_by) * t;
920             a_bz  = -1;
921             a_bw += (a_ew - a_bw) * t;
922           } else if(a_doz && (bout & (1<<5)) ) { //bz > 0
923             t = a_ez - a_bz;
924             //CHECK_DIV    (t,"ClipLineParallel")
925             t = (- a_bz)/t;
926             a_bx += (a_ex - a_bx) * t;
927             a_by += (a_ey - a_by) * t;
928             a_bz  = 0;
929             a_bw += (a_ew - a_bw) * t;
930           } */
931         }
932       }
933     } while (!done);
934     return accept;
935   }
936 
937   static unsigned int ortho_out(float a_x,float a_y/*,float a_z,bool a_doz*/){
938     unsigned int out = 0;
939     if(a_y> 1) out |= (1<<0);
940     if(a_y<-1) out |= (1<<1);
941     if(a_x> 1) out |= (1<<2);
942     if(a_x<-1) out |= (1<<3);
943     //if(!a_doz) return out;
944     //if(a_z<-1) out |= (1<<4);
945     //if(a_z> 0) out |= (1<<5);
946     return out;
947   }
948 
949 protected:
950   // picking region (in window coordinates, (0,0) = bottom-left ) :
951   float m_l;
952   float m_r;
953   float m_b;
954   float m_t;
955 
956   bool m_stop_at_first;
957 
958   bool m_done;
959   sg::node* m_node;
960 
961   std::vector<float> m_zs;
962   std::vector<float> m_ws;
963   std::vector<pick_t> m_picks;
964 
965   //OPTIMIZATION:
966   float m_cx,m_cy,m_sx,m_sy;
967 };
968 
969 }}
970 
971 #endif