gxcamera.cc

Go to the documentation of this file.
00001 
00003 
00004 //
00005 // Copyright (c) 2002-2004 California Institute of Technology
00006 // Copyright (c) 2004-2007 University of Southern California
00007 // Rob Peters <rjpeters at usc dot edu>
00008 //
00009 // created: Thu Nov 21 15:22:25 2002
00010 // commit: $Id: gxcamera.cc 10065 2007-04-12 05:54:56Z rjpeters $
00011 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/gfx/gxcamera.cc $
00012 //
00013 // --------------------------------------------------------------------
00014 //
00015 // This file is part of GroovX.
00016 //   [http://ilab.usc.edu/rjpeters/groovx/]
00017 //
00018 // GroovX is free software; you can redistribute it and/or modify it
00019 // under the terms of the GNU General Public License as published by
00020 // the Free Software Foundation; either version 2 of the License, or
00021 // (at your option) any later version.
00022 //
00023 // GroovX is distributed in the hope that it will be useful, but
00024 // WITHOUT ANY WARRANTY; without even the implied warranty of
00025 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00026 // General Public License for more details.
00027 //
00028 // You should have received a copy of the GNU General Public License
00029 // along with GroovX; if not, write to the Free Software Foundation,
00030 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00031 //
00033 
00034 #ifndef GROOVX_GFX_GXCAMERA_CC_UTC20050626084024_DEFINED
00035 #define GROOVX_GFX_GXCAMERA_CC_UTC20050626084024_DEFINED
00036 
00037 #include "gxcamera.h"
00038 
00039 #include "gfx/canvas.h"
00040 
00041 #include "io/reader.h"
00042 #include "io/writer.h"
00043 
00044 #include "rutz/error.h"
00045 
00046 #include <cmath>
00047 
00048 #include "rutz/debug.h"
00049 GVX_DBG_REGISTER
00050 #include "rutz/trace.h"
00051 
00052 namespace
00053 {
00054   const int GXPC_SVID = 0;
00055   const int GXFSC_SVID = 0;
00056   const int GXPPC_SVID = 0;
00057 }
00058 
00059 GxCamera::~GxCamera() throw() {}
00060 
00061 void GxCamera::reshape(Gfx::Canvas& canvas, int w, int h)
00062 {
00063 GVX_TRACE("GxCamera::reshape");
00064 
00065   dbg_eval(3, itsWidth); dbg_eval_nl(3, itsHeight);
00066 
00067   itsWidth = w; itsHeight = h;
00068 
00069   dbg_eval(3, itsWidth); dbg_eval_nl(3, itsHeight);
00070 
00071   // NOTE: We must call draw() here in order to make sure that e.g. the
00072   // right viewport() gets set. Without the draw() call, the potential
00073   // problem is that the viewport only gets updated inside a redraw
00074   // sequence. Since GxScene::render() wraps such a sequence inside a
00075   // MatrixSaver, any change to the viewport will be lost following the
00076   // redraw sequence. Then we run into problems if e.g. we try to grab
00077   // pixels from the current viewport into a GxPixmap, since the viewport
00078   // doesn't reflect the full window size.
00079   draw(canvas);
00080 }
00081 
00082 GxPerspectiveCamera::GxPerspectiveCamera() :
00083   GxCamera(),
00084   FieldContainer(&sigNodeChanged),
00085   itsFovY(30),
00086   itsNearZ(1),
00087   itsFarZ(30)
00088 {}
00089 
00090 GxPerspectiveCamera::~GxPerspectiveCamera() throw() {}
00091 
00092 const FieldMap& GxPerspectiveCamera::classFields()
00093 {
00094 GVX_TRACE("GxPerspectiveCamera::classFields");
00095   static const Field FIELD_ARRAY[] =
00096   {
00097     Field("fovY", &GxPerspectiveCamera::itsFovY, 30.0, 1.0, 180.0, 1.0,
00098           Field::NEW_GROUP),
00099     Field("nearZ", &GxPerspectiveCamera::itsNearZ, 1.0, 1.0, 50.0, 0.1),
00100     Field("farZ", &GxPerspectiveCamera::itsFarZ, 30.0, 1.0, 50.0, 0.1),
00101     Field("translation", Field::ValueType(), &GxPerspectiveCamera::translation,
00102           "0. 0. 0.", "-50. -50. -10.", "50. 50. 50.", "0.1 0.1 0.1",
00103           Field::MULTI)
00104   };
00105 
00106   static FieldMap FIELD_MAP(FIELD_ARRAY);
00107 
00108   return FIELD_MAP;
00109 }
00110 
00111 io::version_id GxPerspectiveCamera::class_version_id() const
00112 {
00113 GVX_TRACE("GxPerspectiveCamera::class_version_id");
00114   return GXPC_SVID;
00115 }
00116 
00117 void GxPerspectiveCamera::read_from(io::reader& reader)
00118 {
00119 GVX_TRACE("GxPerspectiveCamera::read_from");
00120   readFieldsFrom(reader, classFields());
00121 }
00122 
00123 void GxPerspectiveCamera::write_to(io::writer& writer) const
00124 {
00125 GVX_TRACE("GxPerspectiveCamera::write_to");
00126   writeFieldsTo(writer, classFields(), GXPC_SVID);
00127 }
00128 
00129 void GxPerspectiveCamera::draw(Gfx::Canvas& canvas) const
00130 {
00131 GVX_TRACE("GxPerspectiveCamera::draw");
00132 
00133   dbg_eval(2, width()); dbg_eval_nl(2, height());
00134 
00135   canvas.viewport(0, 0, width(), height());
00136 
00137   canvas.perspective(itsFovY,
00138                      double(width()) / double(height()),
00139                      itsNearZ, itsFarZ);
00140 
00141   canvas.translate(translation.vec());
00142 }
00143 
00144 
00145 GxFixedRectCamera::~GxFixedRectCamera() throw() {}
00146 
00147 void GxFixedRectCamera::draw(Gfx::Canvas& canvas) const
00148 {
00149 GVX_TRACE("GxFixedRectCamera::draw");
00150 
00151   canvas.viewport(0, 0, width(), height());
00152   canvas.orthographic(itsRect, -10.0, 10.0);
00153 }
00154 
00155 GxMinRectCamera::~GxMinRectCamera() throw() {}
00156 
00157 void GxMinRectCamera::draw(Gfx::Canvas& canvas) const
00158 {
00159 GVX_TRACE("GxMinRectCamera::draw");
00160 
00161   canvas.viewport(0, 0, width(), height());
00162 
00163   // the actual rect that we'll build:
00164   geom::rect<double> port(itsRect);
00165 
00166   // the desired conditions are as follows:
00167   //    (1) port contains itsRect
00168   //    (2) port.aspect() == getAspect()
00169   //    (3) port is the smallest rectangle that meets (1) and (2)
00170 
00171   const double window_aspect = double(width()) / double(height());
00172 
00173   const double ratio_of_aspects = itsRect.aspect() / window_aspect;
00174 
00175   if ( ratio_of_aspects < 1 ) // the available space is too wide...
00176     {
00177       port.scale_x(1/ratio_of_aspects); // so use some extra width
00178     }
00179   else                        // the available space is too tall...
00180     {
00181       port.scale_y(ratio_of_aspects); // so use some extra height
00182     }
00183 
00184   canvas.orthographic(port, -10.0, 10.0);
00185 }
00186 
00187 namespace
00188 {
00189   void orthoFixed(Gfx::Canvas& canvas, int w, int h, double ppu)
00190   {
00191     const double l = -1 * (w / 2.0) / ppu;
00192     const double r =      (w / 2.0) / ppu;
00193     const double b = -1 * (h / 2.0) / ppu;
00194     const double t =      (h / 2.0) / ppu;
00195 
00196     canvas.orthographic(geom::rect<double>::ltrb(l,t,r,b), -10.0, 10.0);
00197   }
00198 }
00199 
00200 GxFixedScaleCamera::GxFixedScaleCamera() :
00201   GxCamera(),
00202   FieldContainer(&sigNodeChanged),
00203   itsPixelsPerUnit(100.0)
00204 {}
00205 
00206 GxFixedScaleCamera::~GxFixedScaleCamera() throw() {}
00207 
00208 const FieldMap& GxFixedScaleCamera::classFields()
00209 {
00210 GVX_TRACE("GxFixedScaleCamera::classFields");
00211   static const Field FIELD_ARRAY[] =
00212   {
00213     Field("pixelsPerUnit",
00214           &GxFixedScaleCamera::getPixelsPerUnit,
00215           &GxFixedScaleCamera::setPixelsPerUnit,
00216           2.05, 1.0, 10000.0, 1.0,
00217           Field::NEW_GROUP),
00218     Field("logPixelsPerUnit",
00219           &GxFixedScaleCamera::getLogPixelsPerUnit,
00220           &GxFixedScaleCamera::setLogPixelsPerUnit,
00221           0.5, 0.0, 5.0, 0.025,
00222           Field::TRANSIENT)
00223   };
00224 
00225   static FieldMap FIELD_MAP(FIELD_ARRAY);
00226 
00227   return FIELD_MAP;
00228 }
00229 
00230 io::version_id GxFixedScaleCamera::class_version_id() const
00231 {
00232 GVX_TRACE("GxFixedScaleCamera::class_version_id");
00233   return GXFSC_SVID;
00234 }
00235 
00236 void GxFixedScaleCamera::read_from(io::reader& reader)
00237 {
00238 GVX_TRACE("GxFixedScaleCamera::read_from");
00239   readFieldsFrom(reader, classFields());
00240 }
00241 
00242 void GxFixedScaleCamera::write_to(io::writer& writer) const
00243 {
00244 GVX_TRACE("GxFixedScaleCamera::write_to");
00245   writeFieldsTo(writer, classFields(), GXFSC_SVID);
00246 }
00247 
00248 double GxFixedScaleCamera::getLogPixelsPerUnit() const
00249 {
00250   return log10(itsPixelsPerUnit);
00251 }
00252 
00253 void GxFixedScaleCamera::setLogPixelsPerUnit(double s)
00254 {
00255   setPixelsPerUnit(pow(10.0, s));
00256 }
00257 
00258 void GxFixedScaleCamera::setPixelsPerUnit(double s)
00259 {
00260   if (s <= 0.0)
00261     throw rutz::error("invalid scaling factor", SRC_POS);
00262 
00263   itsPixelsPerUnit = s;
00264 }
00265 
00266 void GxFixedScaleCamera::draw(Gfx::Canvas& canvas) const
00267 {
00268 GVX_TRACE("GxFixedScaleCamera::draw");
00269 
00270   dbg_eval(3, width()); dbg_eval_nl(3, height());
00271   canvas.viewport(0, 0, width(), height());
00272 
00273   orthoFixed(canvas, width(), height(), itsPixelsPerUnit);
00274 }
00275 
00276 GxPsyphyCamera::GxPsyphyCamera() :
00277   GxCamera(),
00278   FieldContainer(&sigNodeChanged),
00279   itsDegreesPerUnit(2.05),
00280   itsViewingDistance(30.0)
00281 {}
00282 
00283 GxPsyphyCamera::~GxPsyphyCamera() throw() {}
00284 
00285 const FieldMap& GxPsyphyCamera::classFields()
00286 {
00287 GVX_TRACE("GxPsyphyCamera::classFields");
00288   static const Field FIELD_ARRAY[] =
00289   {
00290     Field("unitAngle",
00291           &GxPsyphyCamera::getUnitAngle,
00292           &GxPsyphyCamera::setUnitAngle,
00293           2.05, 0.1, 100.0, 0.1,
00294           Field::NEW_GROUP),
00295     Field("viewingDistIn",
00296           &GxPsyphyCamera::getViewingDistIn,
00297           &GxPsyphyCamera::setViewingDistIn,
00298           30.0, 1.0, 500.0, 1.0),
00299   };
00300 
00301   static FieldMap FIELD_MAP(FIELD_ARRAY);
00302 
00303   return FIELD_MAP;
00304 }
00305 
00306 io::version_id GxPsyphyCamera::class_version_id() const
00307 {
00308 GVX_TRACE("GxPsyphyCamera::class_version_id");
00309   return GXPPC_SVID;
00310 }
00311 
00312 void GxPsyphyCamera::read_from(io::reader& reader)
00313 {
00314 GVX_TRACE("GxPsyphyCamera::read_from");
00315   readFieldsFrom(reader, classFields());
00316 }
00317 
00318 void GxPsyphyCamera::write_to(io::writer& writer) const
00319 {
00320 GVX_TRACE("GxPsyphyCamera::write_to");
00321   writeFieldsTo(writer, classFields(), GXPPC_SVID);
00322 }
00323 
00324 void GxPsyphyCamera::setUnitAngle(double deg_per_unit)
00325 {
00326   if (deg_per_unit <= 0.0)
00327     throw rutz::error("unit angle must be positive", SRC_POS);
00328 
00329   itsDegreesPerUnit = deg_per_unit;
00330 }
00331 
00332 void GxPsyphyCamera::setViewingDistIn(double inches)
00333 {
00334   if (inches <= 0.0)
00335     throw rutz::error("viewing distance must be positive (duh)", SRC_POS);
00336 
00337   itsViewingDistance = inches;
00338 }
00339 
00340 void GxPsyphyCamera::draw(Gfx::Canvas& canvas) const
00341 {
00342 GVX_TRACE("GxPsyphyCamera::draw");
00343 
00344   canvas.viewport(0, 0, width(), height());
00345 
00346   static const double deg_to_rad = M_PI/180.0;
00347 
00348   const double pixels_per_inch = 72.0; // FIXME should get this from Canvas
00349 
00350   // geometry 101:
00351   //                   tan(angle_per_unit) == inches_per_unit/viewing_dist;
00352   const double inches_per_unit =
00353     tan(itsDegreesPerUnit*deg_to_rad) * itsViewingDistance;
00354 
00355   const double pixels_per_unit = pixels_per_inch * inches_per_unit;
00356 
00357   orthoFixed(canvas, width(), height(), pixels_per_unit);
00358 }
00359 
00360 static const char __attribute__((used)) vcid_groovx_gfx_gxcamera_cc_utc20050626084024[] = "$Id: gxcamera.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00361 #endif // !GROOVX_GFX_GXCAMERA_CC_UTC20050626084024_DEFINED

The software described here is Copyright (c) 1998-2005, Rob Peters.
This page was generated Wed Dec 3 06:49:38 2008 by Doxygen version 1.5.5.