Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

interactive_polygon.cpp

Go to the documentation of this file.
00001 #include "agg_basics.h"
00002 #include "interactive_polygon.h"
00003 
00004 namespace agg
00005 {
00006     interactive_polygon::interactive_polygon(unsigned np, double point_radius) :
00007         m_polygon(np * 2),
00008         m_num_points(np),
00009         m_node(-1),
00010         m_edge(-1),
00011         m_vs(&m_polygon[0], m_num_points, false),
00012         m_stroke(m_vs),
00013         m_point_radius(point_radius),
00014         m_status(0),
00015         m_dx(0.0),
00016         m_dy(0.0)
00017     {
00018         m_stroke.width(1.0);
00019     }
00020 
00021 
00022     void interactive_polygon::rewind(unsigned)
00023     {
00024         m_status = 0;
00025         m_stroke.rewind(0);
00026     }
00027 
00028     unsigned interactive_polygon::vertex(double* x, double* y)
00029     {
00030         unsigned cmd = path_cmd_stop;
00031         double r = m_point_radius;
00032         if(m_status == 0)
00033         {
00034             cmd = m_stroke.vertex(x, y);
00035             if(!is_stop(cmd)) return cmd;
00036             if(m_node >= 0 && m_node == int(m_status)) r *= 1.2;
00037             m_ellipse.init(xn(m_status), yn(m_status), r, r, 32);
00038             ++m_status;
00039         }
00040         cmd = m_ellipse.vertex(x, y);
00041         if(!is_stop(cmd)) return cmd;
00042         if(m_status >= m_num_points) return path_cmd_stop;
00043         if(m_node >= 0 && m_node == int(m_status)) r *= 1.2;
00044         m_ellipse.init(xn(m_status), yn(m_status), r, r, 32);
00045         ++m_status;
00046         return m_ellipse.vertex(x, y);
00047     }
00048 
00049 
00050     bool interactive_polygon::check_edge(unsigned i, double x, double y) const
00051     {
00052        bool ret = false;
00053 
00054        unsigned n1 = i;
00055        unsigned n2 = (i + m_num_points - 1) % m_num_points;
00056        double x1 = xn(n1);
00057        double y1 = yn(n1);
00058        double x2 = xn(n2);
00059        double y2 = yn(n2);
00060 
00061        double dx = x2 - x1;
00062        double dy = y2 - y1;
00063 
00064        if(sqrt(dx*dx + dy*dy) > 0.0000001)
00065        {
00066           double x3 = x;
00067           double y3 = y;
00068           double x4 = x3 - dy;
00069           double y4 = y3 + dx;
00070 
00071           double den = (y4-y3) * (x2-x1) - (x4-x3) * (y2-y1);
00072           double u1 = ((x4-x3) * (y1-y3) - (y4-y3) * (x1-x3)) / den;
00073 
00074           double xi = x1 + u1 * (x2 - x1);
00075           double yi = y1 + u1 * (y2 - y1);
00076 
00077           dx = xi - x;
00078           dy = yi - y;
00079 
00080           if (u1 > 0.0 && u1 < 1.0 && sqrt(dx*dx + dy*dy) <= m_point_radius)
00081           {
00082              ret = true;
00083           }
00084        }
00085        return ret;
00086     }
00087 
00088 
00089 
00090     bool interactive_polygon::on_mouse_button_down(double x, double y)
00091     {
00092         unsigned i;
00093         bool ret = false;
00094         m_node = -1;
00095         m_edge = -1;
00096         for (i = 0; i < m_num_points; i++)
00097         {
00098             if(sqrt( (x-xn(i)) * (x-xn(i)) + (y-yn(i)) * (y-yn(i)) ) < m_point_radius)
00099             {
00100                 m_dx = x - xn(i);
00101                 m_dy = y - yn(i);
00102                 m_node = int(i);
00103                 ret = true;
00104                 break;
00105             }
00106         }
00107 
00108         if(!ret)
00109         {
00110             for (i = 0; i < m_num_points; i++)
00111             {
00112                 if(check_edge(i, x, y))
00113                 {
00114                     m_dx = x;
00115                     m_dy = y;
00116                     m_edge = int(i);
00117                     ret = true;
00118                     break;
00119                 }
00120             }
00121         }
00122 
00123         if(!ret)
00124         {
00125             if(point_in_polygon(x, y))
00126             {
00127                 m_dx = x;
00128                 m_dy = y;
00129                 m_node = int(m_num_points);
00130                 ret = true;
00131             }
00132         }
00133         return ret;
00134     }
00135 
00136 
00137     bool interactive_polygon::on_mouse_move(double x, double y)
00138     {
00139         bool ret = false;
00140         double dx;
00141         double dy;
00142         if(m_node == int(m_num_points))
00143         {
00144             dx = x - m_dx;
00145             dy = y - m_dy;
00146             unsigned i;
00147             for(i = 0; i < m_num_points; i++)
00148             {
00149                 xn(i) += dx;
00150                 yn(i) += dy;
00151             }
00152             m_dx = x;
00153             m_dy = y;
00154             ret = true;
00155         }
00156         else
00157         {
00158             if(m_edge >= 0)
00159             {
00160                 unsigned n1 = m_edge;
00161                 unsigned n2 = (n1 + m_num_points - 1) % m_num_points;
00162                 dx = x - m_dx;
00163                 dy = y - m_dy;
00164                 xn(n1) += dx;
00165                 yn(n1) += dy;
00166                 xn(n2) += dx;
00167                 yn(n2) += dy;
00168                 m_dx = x;
00169                 m_dy = y;
00170                 ret = true;
00171             }
00172             else
00173             {
00174                 if(m_node >= 0)
00175                 {
00176                     xn(m_node) = x - m_dx;
00177                     yn(m_node) = y - m_dy;
00178                     ret = true;
00179                 }
00180             }
00181         }
00182         return ret;
00183     }
00184 
00185     bool interactive_polygon::on_mouse_button_up(double x, double y)
00186     {
00187         bool ret = (m_node >= 0) || (m_edge >= 0);
00188         m_node = -1;
00189         m_edge = -1;
00190         return ret;
00191     }
00192 
00193 
00194 
00195     //======= Crossings Multiply algorithm of InsideTest ======================== 
00196     //
00197     // By Eric Haines, 3D/Eye Inc, erich@eye.com
00198     //
00199     // This version is usually somewhat faster than the original published in
00200     // Graphics Gems IV; by turning the division for testing the X axis crossing
00201     // into a tricky multiplication test this part of the test became faster,
00202     // which had the additional effect of making the test for "both to left or
00203     // both to right" a bit slower for triangles than simply computing the
00204     // intersection each time.  The main increase is in triangle testing speed,
00205     // which was about 15% faster; all other polygon complexities were pretty much
00206     // the same as before.  On machines where division is very expensive (not the
00207     // case on the HP 9000 series on which I tested) this test should be much
00208     // faster overall than the old code.  Your mileage may (in fact, will) vary,
00209     // depending on the machine and the test data, but in general I believe this
00210     // code is both shorter and faster.  This test was inspired by unpublished
00211     // Graphics Gems submitted by Joseph Samosky and Mark Haigh-Hutchinson.
00212     // Related work by Samosky is in:
00213     //
00214     // Samosky, Joseph, "SectionView: A system for interactively specifying and
00215     // visualizing sections through three-dimensional medical image data",
00216     // M.S. Thesis, Department of Electrical Engineering and Computer Science,
00217     // Massachusetts Institute of Technology, 1993.
00218     //
00219     // Shoot a test ray along +X axis.  The strategy is to compare vertex Y values
00220     // to the testing point's Y and quickly discard edges which are entirely to one
00221     // side of the test ray.  Note that CONVEX and WINDING code can be added as
00222     // for the CrossingsTest() code; it is left out here for clarity.
00223     //
00224     // Input 2D polygon _pgon_ with _numverts_ number of vertices and test point
00225     // _point_, returns 1 if inside, 0 if outside.
00226     bool interactive_polygon::point_in_polygon(double tx, double ty) const
00227     {
00228         if(m_num_points < 3) return false;
00229 
00230         unsigned j;
00231         int yflag0, yflag1, inside_flag;
00232         double  vtx0, vty0, vtx1, vty1;
00233 
00234         vtx0 = xn(m_num_points - 1);
00235         vty0 = yn(m_num_points - 1);
00236 
00237         // get test bit for above/below X axis
00238         yflag0 = (vty0 >= ty);
00239 
00240         vtx1 = xn(0);
00241         vty1 = yn(0);
00242 
00243         inside_flag = 0;
00244         for (j = 1; j <= m_num_points; ++j) 
00245         {
00246             yflag1 = (vty1 >= ty);
00247             // Check if endpoints straddle (are on opposite sides) of X axis
00248             // (i.e. the Y's differ); if so, +X ray could intersect this edge.
00249             // The old test also checked whether the endpoints are both to the
00250             // right or to the left of the test point.  However, given the faster
00251             // intersection point computation used below, this test was found to
00252             // be a break-even proposition for most polygons and a loser for
00253             // triangles (where 50% or more of the edges which survive this test
00254             // will cross quadrants and so have to have the X intersection computed
00255             // anyway).  I credit Joseph Samosky with inspiring me to try dropping
00256             // the "both left or both right" part of my code.
00257             if (yflag0 != yflag1) 
00258             {
00259                 // Check intersection of pgon segment with +X ray.
00260                 // Note if >= point's X; if so, the ray hits it.
00261                 // The division operation is avoided for the ">=" test by checking
00262                 // the sign of the first vertex wrto the test point; idea inspired
00263                 // by Joseph Samosky's and Mark Haigh-Hutchinson's different
00264                 // polygon inclusion tests.
00265                 if ( ((vty1-ty) * (vtx0-vtx1) >=
00266                       (vtx1-tx) * (vty0-vty1)) == yflag1 ) 
00267                 {
00268                     inside_flag ^= 1;
00269                 }
00270             }
00271 
00272             // Move to the next pair of vertices, retaining info as possible.
00273             yflag0 = yflag1;
00274             vtx0 = vtx1;
00275             vty0 = vty1;
00276 
00277             unsigned k = (j >= m_num_points) ? j - m_num_points : j;
00278             vtx1 = xn(k);
00279             vty1 = yn(k);
00280         }
00281         return inside_flag != 0;
00282     }
00283 }
00284 

© sourcejam.com 2005-2008