geom_drawing_area.cpp

00001
00002 /***************************************************************************
00003  *  geom_drawing_area.cpp - A Gtk::DrawingArea for objects of the Fawkes
00004  *  geometry library
00005  *
00006  *  Created: Wed Oct 08 18:52:10 2008
00007  *  Copyright  2008  Daniel Beck
00008  *
00009  ****************************************************************************/
00010
00011 /*  This program is free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version. A runtime exception applies to
00015  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00016  *
00017  *  This program is distributed in the hope that it will be useful,
00018  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  *  GNU Library General Public License for more details.
00021  *
00022  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00023  */
00024
00025 #include <geometry/gtk/geom_drawing_area.h>
00026 #include <geometry/hom_point.h>
00027 #include <geometry/gtk/hom_point_drawer.h>
00028 #include <geometry/hom_vector.h>
00029 #include <geometry/gtk/hom_vector_drawer.h>
00030 #include <geometry/line_segment.h>
00031 #include <geometry/gtk/line_segment_drawer.h>
00032 #include <geometry/bezier.h>
00033 #include <geometry/gtk/spline_drawer.h>
00034 #include <geometry/spline.h>
00035 #include <geometry/gtk/bezier_drawer.h>
00036 #include <geometry/gtk/drawing_manipulator.h>
00037 #include <cmath>
00038
00039 using namespace std;
00040
00041 namespace fawkes{
00042 
00043 /** @class fawkes::GeomDrawingArea <geometry/gtk/geom_drawing_area.h>
00044  * A Gtk::DrawingArea that allows to easily display drawable objects
00045  * of the geometry library.
00046  * @author Daniel Beck
00047  */
00048 
00049 /** @var fawkes::GeomDrawingArea::m_drawers
00050  * A list of drawers for objects that have been requested to be drawn.
00051  */
00052 
00053 /** @var fawkes::GeomDrawingArea::m_max_x
00054  * Right boundary of the drawing area.
00055  */
00056 
00057 /** @var fawkes::GeomDrawingArea::m_max_y
00058  * Top boundary of the drawing area.
00059  */
00060 
00061 /** @var fawkes::GeomDrawingArea::m_min_x
00062  * Left boundary of the drawing area.
00063  */
00064 
00065 /** @var fawkes::GeomDrawingArea::m_min_y
00066  * Bottom boundary of the drawing area.
00067  */
00068 
00069 /** Constructor.
00070  * @param max_x top right corner
00071  * @param max_y top right corner
00072  * @param min_x bottom left corner
00073  * @param min_y bottom left corner
00074  */
00075 GeomDrawingArea::GeomDrawingArea( float max_x,
00076                                   float max_y,
00077                                   float min_x,
00078                                   float min_y )
00079   : m_max_x(max_x),
00080     m_max_y(max_y),
00081     m_min_x(min_x),
00082     m_min_y(min_y)
00083 {
00084   m_cur_drawing_manipulator = NULL;
00085 }
00086 
00087 /** Constructor.
00088  * @param cobject pointer to the base object
00089  * @param ref_xml Glade XML file
00090  */
00091 GeomDrawingArea::GeomDrawingArea( BaseObjectType* cobject,
00092                                   const Glib::RefPtr<Gnome::Glade::Xml>& ref_xml )
00093   : Gtk::DrawingArea(cobject)
00094 {
00095   m_max_x =  5.0;
00096   m_max_y =  5.0;
00097   m_min_x = -5.0;
00098   m_min_y = -5.0;
00099
00100   m_cur_drawing_manipulator = NULL;
00101 }
00102 
00103 /** Destructor. */
00104 GeomDrawingArea::~GeomDrawingArea()
00105 {
00106   clear();
00107 }
00108 
00109 /** Clear the drawing area. */
00110 void
00111 GeomDrawingArea::clear()
00112 {
00113   for ( vector<GeomDrawer*>::iterator iter = m_drawers.begin();
00114         iter != m_drawers.end();
00115         ++iter )
00116     {
00117       delete *iter;
00118     }
00119
00120   m_drawers.clear();
00121
00122   m_cur_drawing_manipulator = NULL;
00123 }
00124 
00125 /** <<-operator for HomPoint objects
00126  * @param p a HomPoint object
00127  * @return a reference to the drawing area
00128  */
00129 GeomDrawingArea&
00130 GeomDrawingArea::operator<<(fawkes::HomPoint& p)
00131 {
00132   HomPointDrawer* d = new HomPointDrawer(p);
00133
00134   if (m_cur_drawing_manipulator)
00135     { d->set_point_size( m_cur_drawing_manipulator->get_point_size() ); }
00136
00137   m_drawers.push_back(d);
00138
00139   return *this;
00140 }
00141 
00142 /** <<-operator for HomPoint objects
00143  * @param p a HomPoint object
00144  * @return a reference to the drawing area
00145  */
00146 GeomDrawingArea&
00147 GeomDrawingArea::operator<<(const fawkes::HomPoint& p)
00148 {
00149   HomPointDrawer* d = new HomPointDrawer(p);
00150
00151   if (m_cur_drawing_manipulator)
00152     { d->set_point_size( m_cur_drawing_manipulator->get_point_size() ); }
00153
00154   m_drawers.push_back(d);
00155
00156   return *this;
00157 }
00158 
00159 /** <<-operator for HomVector objects
00160  * @param vp a pair constisting of the vector and the offset
00161  * @return a reference to the drawing area
00162  */
00163 GeomDrawingArea&
00164 GeomDrawingArea::operator<<(std::pair<HomVector, HomPoint> vp)
00165 {
00166   const HomVector& v = vp.first;
00167   const HomPoint& offset = vp.second;
00168   HomVectorDrawer* d = new HomVectorDrawer(v, offset);
00169   m_drawers.push_back(d);
00170
00171   return *this;
00172 }
00173 
00174 /** <<-operator for LineSegments objects
00175  * @param l a LineSegment object
00176  * @return a reference to the drawing area
00177  */
00178 GeomDrawingArea&
00179 GeomDrawingArea::operator<<(fawkes::LineSegment& l)
00180 {
00181   LineSegmentDrawer* d = new LineSegmentDrawer(l);
00182   m_drawers.push_back(d);
00183
00184   return *this;
00185 }
00186 
00187 /** <<-operator for Bezier objects.
00188  * @param b a Bezier object
00189  * @return a reference to the drawing area
00190  */
00191 GeomDrawingArea&
00192 GeomDrawingArea::operator<<(fawkes::Bezier& b)
00193 {
00194   BezierDrawer* d = new BezierDrawer(b);
00195   m_drawers.push_back(d);
00196
00197   return *this;
00198 }
00199 
00200 /** <<-operator for Spline objects.
00201  * @param s a Spline object
00202  * @return a reference to the drawing area
00203  */
00204 GeomDrawingArea&
00205 GeomDrawingArea::operator<<(fawkes::Spline& s)
00206 {
00207   SplineDrawer* d = new SplineDrawer(s);
00208   m_drawers.push_back(d);
00209
00210   return *this;
00211 }
00212 
00213 /** <<-operator for Spline objects.
00214  * @param s a Spline object
00215  * @return a reference to the drawing area
00216  */
00217 GeomDrawingArea&
00218 GeomDrawingArea::operator<<(const fawkes::Spline& s)
00219 {
00220   SplineDrawer* d = new SplineDrawer(s);
00221   m_drawers.push_back(d);
00222
00223   return *this;
00224 }
00225 
00226 /** <<-operator for DrawingManipulator objects.
00227  * Note: the drawing area takes over the ownwership of the manipulator.
00228  * @param m a DrawingManipulator object
00229  * @return a reference to the drawing area
00230  */
00231 GeomDrawingArea&
00232 GeomDrawingArea::operator<<(fawkes::DrawingManipulator* m)
00233 {
00234   if (m_cur_drawing_manipulator)
00235     { m->integrate(m_cur_drawing_manipulator); }
00236
00237   m_cur_drawing_manipulator = m;
00238   m_drawers.push_back(m);
00239
00240   return *this;
00241 }
00242 
00243 /** Signal handler for the expose event.
00244  * @param event the event
00245  * @return true if event has been handled
00246  */
00247 bool
00248 GeomDrawingArea::on_expose_event(GdkEventExpose* event)
00249 {
00250   Glib::RefPtr<Gdk::Window> window = get_window();
00251   if (window)
00252     {
00253       Gtk::Allocation allocation = get_allocation();
00254       m_window_width = allocation.get_width();
00255       m_window_height = allocation.get_height();
00256
00257       Cairo::RefPtr<Cairo::Context> context = window->create_cairo_context();
00258
00259       if (event)
00260         {
00261           context->rectangle( event->area.x, event->area.y,
00262                               event->area.width, event->area.height );
00263           context->clip();
00264         }
00265
00266       float unit_width  = fabs(m_max_x) + fabs(m_min_x);
00267       float unit_height = fabs(m_max_y) + fabs(m_min_y);
00268       if ( (m_window_width / unit_width) <= (m_window_height / unit_height) )
00269         { m_unit = m_window_width / unit_width; }
00270       else
00271         { m_unit = m_window_height / unit_height; }
00272
00273       pre_draw(context);
00274
00275       for ( vector<GeomDrawer*>::iterator iter = m_drawers.begin();
00276             iter != m_drawers.end();
00277             ++iter )
00278         {
00279           GeomDrawer* d = *iter;
00280           d->draw(context);
00281         }
00282
00283       post_draw(context);
00284
00285       context->stroke();
00286     }
00287
00288   return true;
00289 }
00290 
00291 /** Convert the given window coordinates into the frame of the drawing area.
00292  * @param window_x the window coordinate
00293  * @param window_y the window coordinate
00294  * @param drawing_x the drawing coordinate
00295  * @param drawing_y the drawing coordinate
00296  */
00297 void
00298 GeomDrawingArea::to_drawing_coords( int window_x, int window_y,
00299                                     float& drawing_x, float& drawing_y )
00300 {
00301   float unit_width  = fabs(m_max_x) + fabs(m_min_x);
00302
00303   float pixel_per_unit = m_window_width / unit_width;
00304
00305   drawing_x =   window_x / pixel_per_unit + m_min_x;
00306   drawing_y = -(window_y / pixel_per_unit + m_min_y);
00307 }
00308 
00309 /** This method is called by the expose signal handler before the draw
00310  * routines of the registered drawers are called.
00311  * Derived classes might want to change this to add static drawing
00312  * elements or to change the viewing matrix.
00313  * @param context the drawing context
00314  */
00315 void
00316 GeomDrawingArea::pre_draw(Cairo::RefPtr<Cairo::Context>& context)
00317 {
00318   context->translate( m_window_width / 2.0, m_window_height / 2.0 );
00319   context->scale(m_unit, -m_unit);
00320 }
00321 
00322 /** This method is called by the expose signal handler after the
00323  * draw routines of the registered drawers are called.
00324  * Derived classes might want to change this to add static drawing
00325  * elements.
00326  * @param context the drawing context
00327  */
00328 void
00329 GeomDrawingArea::post_draw(Cairo::RefPtr<Cairo::Context>& context)
00330 {
00331 }
00332
00333 } // end namespace fawkes