Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

gesture.H

Go to the documentation of this file.
00001 /*! ********************************************************************
00002  * \file gesture.H
00003  *
00004  **********************************************************************/
00005 #ifndef GESTURE_H_HAS_BEEN_INCLUDED
00006 #define GESTURE_H_HAS_BEEN_INCLUDED
00007 
00008 #include "disp/view.H"
00009 #include "geom/command.H"
00010 #include "geom/fsa.H"
00011 #include "mlib/points.H"
00012 #include "mlib/vec2.H"
00013 #include "std/stop_watch.H"
00014 #include "std/config.H"
00015 
00016 extern const double MIN_GESTURE_LENGTH;
00017 extern const double MIN_GESTURE_SPREAD;
00018 
00019 class GestureDrawer;
00020 class GEST_INT;
00021 
00022 MAKE_PTR_SUBC(GESTURE,GEL);
00023 typedef const GESTURE CGESTURE;
00024 typedef const GESTUREptr CGESTUREptr;
00025 
00026 
00027 /*!***************************************************************
00028  * GESTURE
00029  *
00030  *      Class that defines a gesture -- a pixel trail drawn by
00031  *      the user, with timing info and ability to "recognize"
00032  *      certain meanings, like a tap, a straight line, a circle,
00033  *      a dot, etc.
00034  *****************************************************************/
00035 
00036 class GESTURE : public GEL {
00037  public:
00038 
00039    //******** MANAGERS ********
00040 
00041    // constructor that begins to build the gesture
00042    GESTURE(GEST_INT* gi, int index, mlib::CPIXEL& p, double pressure,
00043            GestureDrawer* drawer=0, CEvent& down = Event()) :
00044       _gest_int(gi), _index(index),
00045       _start_frame(0), _end_frame(0),
00046       _drawer(drawer), _complete(false) { init(p, down, pressure); }
00047 
00048 
00049    GESTURE(CGESTURE& gest) :
00050      _gest_int(0), _index(0), 
00051      _pts(gest.pts()), _times(gest.timing()), _pressures(gest.pressures()),
00052      _start_frame(0), _end_frame(0),
00053      _bbox(gest.bbox(0)), _pix_bbox(gest.pix_bbox()),
00054      _complete(true){}
00055 
00056    //******** RUN-TIME TYPE ID ********
00057 
00058    DEFINE_RTTI_METHODS3("GESTURE", GESTURE*, GEL, CDATA_ITEM *);
00059 
00060    //******** BUILDING METHODS ********
00061 
00062    void init    (mlib::CPIXEL& p, CEvent& down, double pressure);
00063    void add     (mlib::CPIXEL& p, double min_dist, double pressure);
00064    void complete(mlib::CPIXEL& p, CEvent& up = Event());
00065    void trim();
00066 
00067    //******** CONFIGURING ********
00068 
00069    GestureDrawer* drawer() { return _drawer; }
00070    void set_drawer(GestureDrawer* drawer) { _drawer = drawer; }
00071 
00072    //******** UNDO ********
00073 
00074    // in case the gesture triggered some action and
00075    // later it was decided to interpret the gesture in
00076    // a whole nuther way, it's possible to undo the
00077    // first action via the following mechanism
00078    void set_command(CCOMMANDptr& u) { _cmd = u; }
00079    void undo() {
00080       if (_cmd)
00081          _cmd->undoit();
00082    }
00083    
00084    //******** ACCESSORS/EVALUATORS ********
00085 
00086    /// pixel locations:
00087    const  mlib::PIXEL_list& pts()     const { return _pts; }
00088   /// first pixel in the gesture
00089    mlib::PIXEL  start()               const { return _pts[0]; }
00090   /// last pixel in the gesture
00091    mlib::PIXEL  end()                 const { return _pts.last(); }
00092   /// centroid of the gesture computed as the average
00093    mlib::PIXEL  center()              const { return _pts.average(); }
00094   /// vector from starting point to endpoint
00095    mlib::VEXEL  endpt_vec()           const { return (end() - start()); }
00096   /// mid point of line segment between start and end points in pixel space
00097    mlib::PIXEL  endpt_midpt()         const { return (end() + start())*0.5; }
00098   /// length of the gesture along its curve(s)
00099    double length()              const { return _pts.length(); }
00100   /// straight-line pixel distance between start and end points
00101   double endpoint_dist()       const { return start().dist(end()); }
00102   /// pixel-space distance between this gesture and the one provided, computed as distance between centers
00103    double dist(CGESTUREptr& g)  const { return center().dist(g->center()); }
00104    bool   complete()            const { return _complete; }
00105 
00106    /// run a single pass of smoothing on the point list:
00107    void smooth_points();
00108 
00109    /// run n passes of smoothing on the point list:
00110    void smooth_points(int n);
00111 
00112    /// max distance to center
00113    double spread() const { return _pts.spread(); }
00114 
00115    /// reflect points about a line
00116    void reflect_points(const mlib::PIXELline& l);
00117 
00118    void fix_endpoints(mlib::CPIXEL& a, mlib::CPIXEL& b) {
00119       _pts.fix_endpoints(a,b);
00120    }
00121 
00122    mlib::PIXELline  endpt_line() const { return mlib::PIXELline(start(), end()); }
00123    mlib::PIXEL_list endpt_seg()  const {
00124       mlib::PIXEL_list ret; ret += start(); ret += end(); return ret;
00125    }
00126 
00127   /// does gesture intersect itself?
00128    bool self_intersects()       const { return _pts.self_intersects(); }
00129 
00130   /// does gesture intersect the line provided?
00131    bool intersects_line(const mlib::PIXELline& l) const {
00132       return _pts.intersects_line(l);
00133    }
00134 
00135   /// does gesture intersect the line segment provided?
00136    bool intersects_seg(const mlib::PIXELline& l) const {
00137       return _pts.intersects_seg(l);
00138    }
00139 
00140    // thresholds applied to general strokes
00141   /// is the gesture length less than the minimum gesture length?
00142    bool below_min_length() const { return length() < MIN_GESTURE_LENGTH; }
00143   /// is the gesture length below the minimum allowed spread (max distance to center)
00144    bool below_min_spread() const { return length() < MIN_GESTURE_SPREAD; }
00145 
00146    // timing:
00147    CARRAY<double>& timing()     const { return _times; }
00148   /// time at which first pixel was drawn
00149    double start_time()          const { return _times[0]; }
00150   /// time at which last pixel was drawn
00151    double end_time()            const { return _times.last(); }
00152   /// time that elapsed between first and last pixels drawn
00153    double elapsed_time()        const { return end_time() - start_time(); }
00154   /// time that elapsed between the drawing of the first pixel and pixel whose index is given
00155    double elapsed_time(int i)   const { return _times[i] - start_time(); }
00156   /// time that elapsed between the drawing of the pixel whose index is given, and the last pixel in the gesture
00157    double remaining_time(int i) const { return end_time() - _times[i]; }
00158   /// time that elapsed between the completion of this gesture and the start of the gesture provided
00159    double elapsed_time(CGESTUREptr& g) const {
00160       return fabs(end_time() - g->start_time());
00161    }
00162    double between_time(CGESTUREptr& g) const {
00163       return fabs(start_time() - g->end_time());
00164    }
00165    double age() const { return stop_watch::sys_time() - end_time(); }
00166 
00167    // pressure:
00168    CARRAY<double>& pressures()  const  { return _pressures; }
00169    void  set_pressure(int i, double p) { if (i>0 && i<_pressures.num()) _pressures[i] = p; }
00170 
00171    // measurements
00172    double radius()              const; ///< avg distance to center
00173    double speed()               const; ///< length divided by elapsed time
00174 
00175    /// Time spent within the given threshold distance of the 1st point.
00176    /// Used to measure a gesture that begins w/ a pause.
00177    double startup_time(
00178       double dist_thresh=Config::get_var_dbl("GEST_STARTUP_DIST_THRESH",10.0,true)
00179       ) const;
00180 
00181    double remaining_time(
00182       double dist_thresh=Config::get_var_dbl("GEST_STARTUP_DIST_THRESH",10.0,true)
00183       ) const {
00184       // Time spent after the "startup" period within the given
00185       // distance of the 1st point.
00186       return elapsed_time() - startup_time(dist_thresh);
00187    }
00188 
00189   /// how straight is the gesture? returns 1 for straight and tends to zero as curvature increases
00190    double straightness() const {
00191       double l = length(); return (l > 0) ? endpoint_dist()/length() : 0;
00192    }
00193    double winding    (bool do_trim=1, bool abs=0) const;
00194    double winding_abs(bool do_trim=1) const { return winding(do_trim, true); }
00195 
00196    int  index()                 const   { return _index; }
00197    void set_index(int k)                { _index = k; }
00198 
00199    GESTUREptr prev(int k=1) const;
00200 
00201    //******** RECOGNIZERS ********
00202 
00203    // Returns true if pts[i] is an endpoint, or an internal
00204    // point where exterior angle is large:
00205    bool is_corner(int i)  const;
00206    int  num_corners()     const  { return corners().num(); }
00207    ARRAY<int> corners()   const;
00208 
00209    virtual bool is_stroke()      const; // anything formed by down/up events
00210 
00211    // straight line:
00212    virtual bool is_line(double min_straightness, double min_len) const;
00213    // gets values from environment variables JOT_LINE_MIN_STRAIGHTNESS
00214    // and JOT_LINE_MIN_LEN, or uses 0.95 and 20 (pixels) by default:
00215    virtual bool is_line() const;
00216 
00217    virtual bool is_tap()         const;
00218    virtual bool is_double_tap()  const;
00219    virtual bool is_slash()       const; ///< quick, short, straight stroke
00220    virtual bool is_dslash()      const; ///< delayed slash (starts w/ pause)
00221    virtual bool is_tslash()      const; ///< tap-slash (tap, then slash)
00222    virtual bool is_slash_tap()   const; ///< slash/tap
00223    virtual bool is_dot()         const; ///< small, tight spiral
00224    virtual bool is_scribble()    const; ///< used for crossing out stuff
00225 
00226    virtual bool is_zip_zap()     const; ///< forward/back slash
00227    virtual bool is_arc()         const; ///< slightly curving stroke
00228    virtual bool is_small_arc()   const; ///< a small arc (eg under 60 pixels long)
00229 
00230    virtual bool is_closed()      const;
00231    virtual bool is_loop()        const;
00232    virtual bool is_lasso()       const;
00233 
00234    virtual bool is_circle(double max_ratio=1.25) const;
00235 
00236    virtual bool is_small_circle(double max_ratio=1.25) const;
00237 
00238    virtual bool is_ellipse(
00239       mlib::PIXEL& center, mlib::VEXEL& axis,
00240       double& r1, double& r2, double err_mult=1
00241       ) const;
00242 
00243    virtual bool is_almost_ellipse(mlib::PIXEL& center, mlib::VEXEL& axis,
00244                                   double& r1, double& r2) const {
00245       return is_ellipse(center, axis, r1, r2,
00246       Config::get_var_dbl("ALMOST_ELLIPSE_MULTIPLIER", 3,true)
00247          );
00248    }
00249 
00250    virtual bool is_ellipse() const {
00251       mlib::PIXEL center; mlib::VEXEL axis; double r1=0, r2=0;
00252       return is_ellipse(center, axis, r1, r2);
00253    }
00254 
00255    virtual bool is_n_line()      const;
00256    virtual bool is_e_line()      const;
00257    virtual bool is_s_line()      const;
00258    virtual bool is_w_line()      const;
00259    virtual bool is_ne_line()     const;
00260    virtual bool is_se_line()     const;
00261    virtual bool is_sw_line()     const;
00262    virtual bool is_nw_line()     const;
00263    virtual bool is_x()           const; // two short straight lines forming X
00264 
00265    virtual bool is_click_hold()  const;
00266    virtual bool is_press_hold()  const;
00267 
00268    //******** DIAGNOSTIC ********
00269 
00270    void print_stats() const;
00271    void print_types() const;
00272 
00273    //******** GEL METHODS ********
00274 
00275    virtual int draw(CVIEWptr &v);
00276    virtual int draw_final(CVIEWptr &v);
00277 
00278    // because gestures are antialiased they have "transparency":
00279    virtual bool needs_blend()           const { return true; }
00280 
00281    virtual BBOX        bbox(int)        const { return _bbox; }
00282    virtual BBOXpix     pix_bbox()    const { return _pix_bbox; }
00283 
00284    //******** DATA_ITEM METHODS ********
00285 
00286    virtual DATA_ITEM *dup() const {
00287       // XXX - no need for duping
00288       return 0;
00289       // return new GESTURE(_drawer);
00290    }
00291 
00292  protected:
00293 
00294    //******** MEMBER DATA ********
00295 
00296    GEST_INT*            _gest_int;      ///< owner of this
00297    int                  _index;         ///< index of this in owner's list
00298    mlib::PIXEL_list           _pts;     ///< pixel trail
00299    ARRAY<double>        _times;         ///< times for each pixel added
00300    ARRAY<double>        _pressures;     ///< pressures recorded for each pixel
00301    int                  _start_frame;   ///< frame number of down event
00302    double               _end_frame;     ///< frame number of up event
00303    Event                _down, _up;     ///< down and up events
00304    GestureDrawer*       _drawer;        ///< thing that can draw this
00305    COMMANDptr           _cmd;           ///< how to undo previous result of this
00306    BBOX                 _bbox;
00307    BBOXpix              _pix_bbox;
00308    bool                 _complete;     ///< if complete() was called...
00309 
00310    //******** INTERNAL METHODS ********
00311 
00312    // one reason they're internal is they don't do error checking
00313    mlib::VEXEL  vec  (int i) const { return _pts[i] - _pts[i-1]; }
00314    mlib::VEXEL  vecn (int i) const { return vec(i).normalized(); }
00315    double angle(int i) const { return mlib::Acos(vecn(i)*vecn(i+1)); }
00316 };
00317 
00318 /*****************************************************************
00319  * GestureDrawer
00320  *
00321  *      Base class for object that can draw a PIXEL_list
00322  *      (I.e. a screen-space polyline). Draws using an OpengGL
00323  *      line strip; derived types might use strokes or
00324  *      something.
00325  *****************************************************************/
00326 class GestureDrawer {
00327  public:
00328    virtual ~GestureDrawer() {}
00329    virtual GestureDrawer* dup() const { return new GestureDrawer; }
00330    virtual int draw(const GESTURE*, CVIEWptr& view);
00331 };
00332 
00333 #endif  // GESTURE_H_HAS_BEEN_INCLUDED
00334 
00335 // end of file gesture.H

Generated on Mon Sep 18 11:39:30 2006 for jot by  doxygen 1.4.4