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
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
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
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
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257 if (yflag0 != yflag1)
00258 {
00259
00260
00261
00262
00263
00264
00265 if ( ((vty1-ty) * (vtx0-vtx1) >=
00266 (vtx1-tx) * (vty0-vty1)) == yflag1 )
00267 {
00268 inside_flag ^= 1;
00269 }
00270 }
00271
00272
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