core/vgui/vgui_rubberband_tableau.cxx
Go to the documentation of this file.
00001 // This is core/vgui/vgui_rubberband_tableau.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author K.Y.McGaul
00008 // \date   31-MAR-2000
00009 // \brief  See vgui_rubberband_tableau.h for a description of this file.
00010 
00011 #include "vgui_rubberband_tableau.h"
00012 
00013 #include <vcl_cassert.h>
00014 #include <vcl_cmath.h>
00015 #include <vcl_iostream.h>
00016 #include <vgl/vgl_clip.h>
00017 #include <vnl/vnl_math.h>
00018 
00019 #include <vgui/vgui_matrix_state.h>
00020 #include <vgui/vgui_projection_inspector.h>
00021 #include <vgui/vgui_adaptor.h>
00022 
00023 vgui_rubberband_tableau::object_type vgui_rubberband_tableau::obj_type = none_enum;
00024 
00025 #ifdef __GNUC__ /* __FUNCTION__ is a GNU extension */
00026 # define function_macro { vcl_cerr << __FUNCTION__ << " not yet implemented\n"; }
00027 #else
00028 # define function_macro { vcl_cerr << __FILE__ " : " << __LINE__ << " not yet implemented\n"; }
00029 #endif
00030 void vgui_rubberband_client::add_point(float, float) function_macro
00031 void vgui_rubberband_client::add_line(float,float,float,float) function_macro
00032 void vgui_rubberband_client::add_infinite_line(float,float,float) function_macro
00033 void vgui_rubberband_client::add_circle(float,float,float) function_macro
00034 void vgui_rubberband_client::add_linestrip(int /*n*/,float const *,float const *) function_macro
00035 void vgui_rubberband_client::add_polygon(int /*n*/,float const*,float const*) function_macro
00036 void vgui_rubberband_client::add_box(float,float,float,float) function_macro
00037 void vgui_rubberband_client::clear_highlight() function_macro
00038 #undef function_macro
00039 
00040 
00041 //---------------------------------------------------------------------------
00042 //                                              vgui_rubberband_easy2D_client
00043 
00044 void
00045 vgui_rubberband_easy2D_client::
00046 add_point(float x, float y)
00047 {
00048   easy->add_point(x,y);
00049 }
00050 
00051 void
00052 vgui_rubberband_easy2D_client::
00053 add_line(float x0, float y0, float x1, float y1)
00054 {
00055   easy->add_line(x0, y0, x1, y1);
00056 }
00057 
00058 void
00059 vgui_rubberband_easy2D_client::
00060 add_infinite_line(float a, float b, float c)
00061 {
00062   easy->add_infinite_line(a, b, c);
00063 }
00064 
00065 void
00066 vgui_rubberband_easy2D_client::
00067 add_circle(float x, float y, float r)
00068 {
00069   easy->add_circle(x, y, r);
00070 }
00071 
00072 void
00073 vgui_rubberband_easy2D_client::
00074 add_linestrip(int n, float const* x, float const* y)
00075 {
00076   easy->add_linestrip(n, x, y);
00077 }
00078 
00079 void
00080 vgui_rubberband_easy2D_client::
00081 add_polygon(int n, float const* x, float const* y)
00082 {
00083   easy->add_polygon(n, x, y);
00084 }
00085 
00086 
00087 void
00088 vgui_rubberband_easy2D_client::
00089 add_box(float x0, float y0, float x1, float y1)
00090 {
00091   float x[4] = {x0, x1, x1, x0};
00092   float y[4] = {y0, y0, y1, y1};
00093   this->add_polygon( 4, x, y );
00094 }
00095 
00096 
00097 void
00098 vgui_rubberband_easy2D_client::
00099 clear_highlight()
00100 {
00101   easy->highlight(0);
00102 }
00103 
00104 //---------------------------------------------------------------------------
00105 //                                                    vgui_rubberband_tableau
00106 
00107 void vgui_rubberband_tableau::init(vgui_rubberband_client* the_client)
00108 {
00109   client_ = the_client;
00110   active = false;
00111   obj_type = none_enum;
00112 #ifdef HAS_MFC
00113   // Until somebody implements overlays for mfc, this
00114   // is the default for windows.
00115   use_overlays = true;
00116 #else
00117   // This is the default on non-windows platforms.
00118   // Please keep it that way or document clearly why
00119   // it must be changed. It is the default because
00120   // Mesa (or glx) is too slow otherwise.
00121   use_overlays = true;
00122 #endif
00123 }
00124 
00125 void vgui_rubberband_tableau::rubberband_point()
00126 {
00127   obj_type = point_enum;
00128   gesture0 = vgui_event_condition(vgui_LEFT, vgui_MODIFIER_NULL, true ); // press
00129   gesture1 = vgui_event_condition(vgui_LEFT, vgui_MODIFIER_NULL, false); // release
00130 }
00131 
00132 void vgui_rubberband_tableau::rubberband_line()
00133 {
00134   obj_type = line_enum;
00135   gesture0 = vgui_event_condition(vgui_LEFT, vgui_MODIFIER_NULL, true);
00136   gesture1 = vgui_event_condition(vgui_LEFT, vgui_MODIFIER_NULL, true);
00137 }
00138 
00139 void vgui_rubberband_tableau::rubberband_infinite_line()
00140 {
00141   obj_type = infinite_line_enum;
00142   gesture0 = vgui_event_condition(vgui_LEFT, vgui_MODIFIER_NULL, true);
00143   gesture1 = vgui_event_condition(vgui_LEFT, vgui_MODIFIER_NULL, true);
00144 }
00145 
00146 void vgui_rubberband_tableau::rubberband_circle()
00147 {
00148   obj_type = circle_enum;
00149   gesture0 = vgui_event_condition(vgui_LEFT, vgui_MODIFIER_NULL, true);
00150   gesture1 = vgui_event_condition(vgui_LEFT, vgui_MODIFIER_NULL, true);
00151 }
00152 
00153 void vgui_rubberband_tableau::rubberband_polygon()
00154 {
00155   obj_type = polygon_enum;
00156   gesture0 = vgui_event_condition(vgui_LEFT, vgui_MODIFIER_NULL, true); // begin
00157   gesture1 = vgui_event_condition(vgui_LEFT, vgui_MODIFIER_NULL, true); // new point
00158   // vgui_RIGHT will conflict with popup menus in many cases. add a
00159   // gesture3 field if you really need to respond to both.
00160   gesture2 = vgui_event_condition(vgui_MIDDLE, vgui_MODIFIER_NULL, true); // last point
00161 }
00162 
00163 void vgui_rubberband_tableau::rubberband_linestrip()
00164 {
00165   obj_type = linestrip_enum;
00166   gesture0 = vgui_event_condition(vgui_LEFT, vgui_MODIFIER_NULL, true); // begin
00167   gesture1 = vgui_event_condition(vgui_LEFT, vgui_MODIFIER_NULL, true); // new point
00168   // see above comment.
00169   gesture2 = vgui_event_condition(vgui_MIDDLE, vgui_MODIFIER_NULL, true); // last point
00170 }
00171 
00172 void vgui_rubberband_tableau::rubberband_box()
00173 {
00174   obj_type = box_enum;
00175   gesture0 = vgui_event_condition(vgui_LEFT, vgui_MODIFIER_NULL, true); // begin
00176   gesture1 = vgui_event_condition(vgui_LEFT, vgui_MODIFIER_NULL, true); // end
00177 }
00178 
00179 void vgui_rubberband_tableau::rubberband_none()
00180 {
00181   active = false;
00182   obj_type = none_enum;
00183 }
00184 
00185 //: Render the given point.
00186 void vgui_rubberband_tableau::draw_point(float x, float y)
00187 {
00188   glColor3f(1,1,1);
00189   glBegin(GL_POINTS);
00190 #ifdef DEBUG
00191    vcl_cerr << "vgui_rubberband_tableau::draw_point(" << x << ',' << y << ")\n";
00192 #endif
00193   glVertex2f(x,y);
00194   glEnd();
00195 }
00196 
00197 //: Render the finite line between the given points.
00198 void vgui_rubberband_tableau::draw_line(float x0, float y0, float x1, float y1)
00199 {
00200   glLineWidth(1);
00201   glColor3f(1,1,1);
00202 
00203   glBegin(GL_LINES);
00204   glVertex2f(x0, y0);
00205   glVertex2f(x1, y1);
00206   glEnd();
00207 }
00208 
00209 //: Render the infinite line ax + by + c = 0.
00210 void vgui_rubberband_tableau::draw_infinite_line(float a, float b, float c)
00211 {
00212   // Compute the bounding box.
00213   // This will be the viewport but in the coordinates of the image.
00214   vgui_projection_inspector pi;
00215   float x0, y0, x1, y1;
00216   pi.image_viewport(x0,y0,x1,y1);
00217 
00218   float x3, y3;
00219   float x4, y4;
00220   bool f = vgl_clip_line_to_box(a,b,c, x0, y0, x1, y1, x3, y3, x4,y4);
00221   if (!f)
00222     return; // no intersection
00223 
00224   glBegin(GL_LINES);
00225   glVertex2f(x3,y3);
00226   glVertex2f(x4,y4);
00227   glEnd();
00228 }
00229 
00230 //: Render the rubber circle.
00231 void vgui_rubberband_tableau::draw_circle(float x, float y, float r)
00232 {
00233   glLineWidth(1);
00234   glColor3f(1,1,1);
00235   glBegin(GL_LINE_LOOP);
00236 
00237 
00238   for (int i=0;i<100;i++) {
00239     double angle = (2*vnl_math::pi/100.0)*i;
00240     glVertex2d(vcl_cos(angle)*r + x, vcl_sin(angle)*r + y);
00241   }
00242   glEnd();
00243 }
00244 
00245 //: Render the rubber polygon.
00246 void vgui_rubberband_tableau::draw_polygon(float px, float py)
00247 {
00248   unsigned n=x_coords.size(); assert(n==y_coords.size());
00249   if (n==0)
00250     return;
00251 
00252   vgui_matrix_state M; M.save();
00253 
00254   glLineWidth(1);
00255   glColor3f(1,1,1);
00256   if (n==1)
00257     glBegin(GL_LINES);
00258   else
00259     glBegin(GL_LINE_LOOP);
00260 
00261   for (unsigned i=0; i<n; ++i)
00262     glVertex2f(x_coords[i], y_coords[i]);
00263   glVertex2f(px, py);
00264   glEnd();
00265 }
00266 
00267 //: Render rubber box
00268 void vgui_rubberband_tableau::draw_box(float x0,float y0,float x1,float y1)
00269 {
00270   float sx = x0>x1 ? x1:x0;
00271   float sy = y0>y1 ? y1:y0;
00272   float ex = x0>x1 ? x0:x1;
00273   float ey = y0>y1 ? y0:y1;
00274 
00275   glLineWidth(1);
00276   glColor3f(1,1,1);
00277   glBegin(GL_LINE_LOOP);
00278 
00279   glVertex2f(sx,sy);
00280   glVertex2f(ex,sy);
00281   glVertex2f(ex,ey);
00282   glVertex2f(sx,ey);
00283 
00284   glEnd();
00285 }
00286 
00287 //: Render the rubber line strip
00288 void vgui_rubberband_tableau::draw_linestrip(float px,float py)
00289 {
00290   unsigned n=x_coords.size(); assert(n==y_coords.size());
00291   if (n==0)
00292     return;
00293 
00294   vgui_matrix_state M; M.save();
00295 
00296   glLineWidth(1);
00297   glColor3f(1,1,1);
00298   glBegin(GL_LINE_STRIP);
00299   for (unsigned i=0; i<n; ++i)
00300     glVertex2f(x_coords[i], y_coords[i]);
00301   glVertex2f(px,py);
00302   glEnd();
00303 }
00304 
00305 
00306 bool vgui_rubberband_tableau::handle_point(vgui_event const &e, float ix, float iy)
00307 {
00308   if ((use_overlays && e.type == vgui_DRAW_OVERLAY) || (!use_overlays && e.type == vgui_DRAW))
00309   {
00310     draw_point(lastx, lasty);
00311     return true;
00312   }
00313   if (gesture1(e))
00314   {
00315     // Point is completed, add to client:
00316     client_->add_point(ix,iy);
00317     active = false;
00318     obj_type = none_enum;
00319     post_redraw();
00320     return true;
00321   }
00322   return false;
00323 }
00324 
00325 bool vgui_rubberband_tableau::handle_line(vgui_event const &e, float ix, float iy)
00326 {
00327   if ((use_overlays && e.type == vgui_DRAW_OVERLAY) || (!use_overlays && e.type == vgui_DRAW))
00328   {
00329     draw_line(x_coords[0], y_coords[0], lastx, lasty);
00330     return true;
00331   }
00332   if (gesture1(e))
00333   {
00334     // Line is completed, add to client
00335     client_->add_line(x_coords[0],y_coords[0],ix,iy);
00336     active = false;
00337     obj_type = none_enum;
00338     post_redraw();
00339     return true;
00340   }
00341   return false;
00342 }
00343 
00344 bool vgui_rubberband_tableau::handle_infinite_line(vgui_event const &e, float ix, float iy)
00345 {
00346   if ((use_overlays && e.type == vgui_DRAW_OVERLAY) || (!use_overlays && e.type == vgui_DRAW))
00347   {
00348     draw_infinite_line(-lastx+x_coords[0],y_coords[0] - lasty,
00349                        -(-lastx+x_coords[0])*lastx-lasty*(y_coords[0]-lasty));
00350     return true;
00351   }
00352   if (gesture1(e))
00353   {
00354     // Infinite line is completed, add to rubberband_client
00355     client_->add_infinite_line(-ix+x_coords[0],y_coords[0] - iy,
00356                                -(-ix+x_coords[0])*lastx-iy*(y_coords[0]-lasty));
00357     active = false;
00358     obj_type = none_enum;
00359     post_redraw();
00360     return true;
00361   }
00362   return false; // ?
00363 }
00364 
00365 bool vgui_rubberband_tableau::handle_circle(vgui_event const &e, float ix, float iy)
00366 {
00367   if ((use_overlays && e.type == vgui_DRAW_OVERLAY) || (!use_overlays && e.type == vgui_DRAW))
00368   {
00369     // hypot(x_coords[0] - lastx, y_coords[0]-lasty);
00370     float dx = x_coords[0] - lastx;
00371     float dy = y_coords[0] - lasty;
00372     float radi = vcl_sqrt(dx*dx + dy*dy);
00373     draw_circle(x_coords[0], y_coords[0], radi);
00374     return true;
00375   }
00376   if (gesture1(e))
00377   {
00378     // Circle is completed, add to the client:
00379     float dx = x_coords[0] - ix;
00380     float dy = y_coords[0] - iy;
00381     float radi = vcl_sqrt(dx*dx + dy*dy);
00382     client_->add_circle(x_coords[0],y_coords[0],radi);
00383     active = false;
00384     obj_type = none_enum;
00385     post_redraw();
00386     return true;
00387   }
00388   return false;
00389 }
00390 
00391 bool vgui_rubberband_tableau::handle_polygon(vgui_event const &e, float ix, float iy)
00392 {
00393   unsigned n = x_coords.size();
00394   assert(n == y_coords.size());
00395   assert(n>0);
00396 
00397   if ((use_overlays && e.type == vgui_DRAW_OVERLAY) || (!use_overlays && e.type == vgui_DRAW))
00398   {
00399     draw_polygon(lastx, lasty);
00400     return true;
00401   }
00402   if (gesture1(e))
00403   {
00404     // drop a new point
00405     x_coords.push_back(ix);
00406     y_coords.push_back(iy);
00407     return true;
00408   }
00409 
00410   if (gesture2(e))
00411   {
00412     // last selected point - add to the list of coordinates:
00413     x_coords.push_back(ix);
00414     y_coords.push_back(iy);
00415     n++;
00416 
00417     // Add the first point in as also the last point:
00418     x_coords.push_back(x_coords[0]);
00419     y_coords.push_back(y_coords[0]);
00420     n++;
00421 
00422     client_->add_polygon(n, &x_coords[0], &y_coords[0]); //vector<>::iterator
00423 
00424     post_redraw();
00425     active = false;
00426     obj_type = none_enum;
00427     return true;
00428   }
00429   return false;
00430 }
00431 
00432 bool vgui_rubberband_tableau::handle_box(vgui_event const &e, float ix,float iy)
00433 {
00434   if ((use_overlays && e.type == vgui_DRAW_OVERLAY) || (!use_overlays && e.type == vgui_DRAW))
00435   {
00436     draw_box(x_coords[0], y_coords[0], lastx, lasty);
00437     return true;
00438   }
00439   if (gesture1(e))
00440   {
00441     client_->add_box(x_coords[0],y_coords[0],ix,iy);
00442     active = false;
00443     obj_type = none_enum;
00444     post_redraw();
00445     return true;
00446   }
00447   return false;
00448 }
00449 
00450 bool vgui_rubberband_tableau::handle_linestrip(vgui_event const &e, float ix, float iy)
00451 {
00452   unsigned n = x_coords.size();
00453   assert(n == y_coords.size());
00454   assert(n>0);
00455 
00456   if ((use_overlays && e.type == vgui_DRAW_OVERLAY) || (!use_overlays && e.type == vgui_DRAW))
00457   {
00458     draw_linestrip(lastx, lasty);
00459     return true;
00460   }
00461 
00462   if (gesture1(e))
00463   {
00464     // drop a new point
00465     x_coords.push_back(ix);
00466     y_coords.push_back(iy);
00467     return true;
00468   }
00469 
00470   if (gesture2(e))
00471   {
00472     client_->add_linestrip(n,&x_coords[0],&y_coords[0]); //vector<>::iterator
00473     post_redraw();
00474     active = false;
00475     obj_type = none_enum;
00476     return true;
00477   }
00478   return false;
00479 }
00480 
00481 bool vgui_rubberband_tableau::handle(vgui_event const &e)
00482 {
00483   if(e.origin)
00484     e.origin->make_current();
00485   else
00486     return false;
00487   float ix, iy;
00488   vgui_projection_inspector().window_to_image_coordinates(e.wx, e.wy, ix, iy);
00489 
00490   if (!active) {
00491     if (obj_type != none_enum && gesture0(e))
00492     {
00493       active = true;
00494       if (use_overlays) post_overlay_redraw(); else post_redraw();
00495       client_->clear_highlight();
00496 
00497       lastx = ix;
00498       lasty = iy;
00499       x_coords.clear();
00500       y_coords.clear();
00501       x_coords.push_back(ix);
00502       y_coords.push_back(iy);
00503 
00504       return true;
00505     }
00506     else
00507       return false;
00508   }
00509 
00510   // active :
00511   if (e.type == vgui_MOTION){
00512     lastx = ix;
00513     lasty = iy;
00514     if (use_overlays) post_overlay_redraw(); else post_redraw();
00515     client_->clear_highlight();
00516 
00517     return true;
00518   }
00519 
00520   if (obj_type == point_enum)
00521     return handle_point(e, ix, iy);
00522 
00523   if (obj_type == line_enum)
00524     return handle_line(e, ix, iy);
00525 
00526   if (obj_type == infinite_line_enum)
00527     return handle_infinite_line(e, ix, iy);
00528 
00529   if (obj_type == circle_enum)
00530     return handle_circle(e, ix, iy);
00531 
00532   if (obj_type == polygon_enum)
00533     return handle_polygon(e, ix, iy);
00534 
00535   if (obj_type == linestrip_enum)
00536     return handle_linestrip(e,ix,iy);
00537 
00538   if (obj_type == box_enum)
00539     return handle_box(e,ix,iy);
00540 
00541   return false;
00542 }