00001 #include <math.h>
00002 #include <stdio.h>
00003 #include <time.h>
00004 #include "agg_rendering_buffer.h"
00005 #include "agg_conv_transform.h"
00006 #include "agg_conv_stroke.h"
00007 #include "agg_conv_dash.h"
00008 #include "agg_scanline_u.h"
00009 #include "agg_renderer_scanline.h"
00010 #include "agg_rasterizer_outline_aa.h"
00011 #include "agg_rasterizer_scanline_aa.h"
00012 #include "agg_pattern_filters_rgba.h"
00013 #include "agg_renderer_outline_aa.h"
00014 #include "agg_renderer_outline_image.h"
00015 #include "agg_arc.h"
00016 #include "agg_bezier_arc.h"
00017 #include "agg_pixfmt_rgb.h"
00018 #include "ctrl/agg_slider_ctrl.h"
00019 #include "ctrl/agg_bezier_ctrl.h"
00020 #include "ctrl/agg_rbox_ctrl.h"
00021 #include "ctrl/agg_cbox_ctrl.h"
00022 #include "platform/agg_platform_support.h"
00023
00024
00025 enum flip_y_e { flip_y = true };
00026
00027 typedef agg::pixfmt_bgr24 pixfmt;
00028
00029
00030 void bezier4_point(double x1, double y1, double x2, double y2,
00031 double x3, double y3, double x4, double y4,
00032 double mu,
00033 double* x, double* y)
00034 {
00035 double mum1, mum13, mu3;
00036
00037 mum1 = 1 - mu;
00038 mum13 = mum1 * mum1 * mum1;
00039 mu3 = mu * mu * mu;
00040
00041 *x = mum13*x1 + 3*mu*mum1*mum1*x2 + 3*mu*mu*mum1*x3 + mu3*x4;
00042 *y = mum13*y1 + 3*mu*mum1*mum1*y2 + 3*mu*mu*mum1*y3 + mu3*y4;
00043 }
00044
00045
00046
00047
00048 class the_application : public agg::platform_support
00049 {
00050 agg::rgba8 m_ctrl_color;
00051 agg::bezier_ctrl<agg::rgba8> m_curve1;
00052 agg::slider_ctrl<agg::rgba8> m_angle_tolerance;
00053 agg::slider_ctrl<agg::rgba8> m_approximation_scale;
00054 agg::slider_ctrl<agg::rgba8> m_cusp_limit;
00055 agg::slider_ctrl<agg::rgba8> m_width;
00056 agg::cbox_ctrl<agg::rgba8> m_show_points;
00057 agg::cbox_ctrl<agg::rgba8> m_show_outline;
00058 agg::rbox_ctrl<agg::rgba8> m_curve_type;
00059 agg::rbox_ctrl<agg::rgba8> m_case_type;
00060 agg::rbox_ctrl<agg::rgba8> m_inner_join;
00061 agg::rbox_ctrl<agg::rgba8> m_line_join;
00062 agg::rbox_ctrl<agg::rgba8> m_line_cap;
00063
00064 int m_cur_case_type;
00065
00066 public:
00067 typedef agg::renderer_base<pixfmt> renderer_base;
00068 typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_scanline;
00069 typedef agg::rasterizer_scanline_aa<> rasterizer_scanline;
00070 typedef agg::scanline_u8 scanline;
00071
00072
00073 the_application(agg::pix_format_e format, bool flip_y) :
00074 agg::platform_support(format, flip_y),
00075 m_ctrl_color(agg::rgba(0, 0.3, 0.5, 0.8)),
00076 m_angle_tolerance (5.0, 5.0, 240.0, 12.0, !flip_y),
00077 m_approximation_scale(5.0, 17+5.0, 240.0, 17+12.0, !flip_y),
00078 m_cusp_limit (5.0, 17+17+5.0, 240.0, 17+17+12.0, !flip_y),
00079 m_width (245.0, 5.0, 495.0, 12.0, !flip_y),
00080 m_show_points (250.0, 15+5, "Show Points", !flip_y),
00081 m_show_outline (250.0, 30+5, "Show Stroke Outline", !flip_y),
00082 m_curve_type (535.0, 5.0, 535.0+115.0, 55.0, !flip_y),
00083 m_case_type (535.0, 60.0, 535.0+115.0, 195.0, !flip_y),
00084 m_inner_join (535.0, 200.0, 535.0+115.0, 290.0, !flip_y),
00085 m_line_join (535.0, 295.0, 535.0+115.0, 385.0, !flip_y),
00086 m_line_cap (535.0, 395.0, 535.0+115.0, 455.0, !flip_y),
00087 m_cur_case_type(-1)
00088 {
00089 m_curve1.line_color(m_ctrl_color);
00090
00091 m_curve1.curve(170, 424, 13, 87, 488, 423, 26, 333);
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108 add_ctrl(m_curve1);
00109 m_curve1.no_transform();
00110
00111 m_angle_tolerance.label("Angle Tolerance=%.0f deg");
00112 m_angle_tolerance.range(0, 90);
00113 m_angle_tolerance.value(15);
00114 add_ctrl(m_angle_tolerance);
00115 m_angle_tolerance.no_transform();
00116
00117 m_approximation_scale.label("Approximation Scale=%.3f");
00118 m_approximation_scale.range(0.1, 5);
00119 m_approximation_scale.value(1.0);
00120 add_ctrl(m_approximation_scale);
00121 m_approximation_scale.no_transform();
00122
00123 m_cusp_limit.label("Cusp Limit=%.0f deg");
00124 m_cusp_limit.range(0, 90);
00125 m_cusp_limit.value(0);
00126 add_ctrl(m_cusp_limit);
00127 m_cusp_limit.no_transform();
00128
00129 m_width.label("Width=%.2f");
00130 m_width.range(-50, 100);
00131 m_width.value(50.0);
00132 add_ctrl(m_width);
00133 m_width.no_transform();
00134
00135 add_ctrl(m_show_points);
00136 m_show_points.no_transform();
00137 m_show_points.status(true);
00138
00139 add_ctrl(m_show_outline);
00140 m_show_outline.no_transform();
00141 m_show_outline.status(true);
00142
00143 m_curve_type.add_item("Incremental");
00144 m_curve_type.add_item("Subdiv");
00145 m_curve_type.cur_item(1);
00146 add_ctrl(m_curve_type);
00147 m_curve_type.no_transform();
00148
00149 m_case_type.text_size(7);
00150 m_case_type.text_thickness(1.0);
00151 m_case_type.add_item("Random");
00152 m_case_type.add_item("13---24");
00153 m_case_type.add_item("Smooth Cusp 1");
00154 m_case_type.add_item("Smooth Cusp 2");
00155 m_case_type.add_item("Real Cusp 1");
00156 m_case_type.add_item("Real Cusp 2");
00157 m_case_type.add_item("Fancy Stroke");
00158 m_case_type.add_item("Jaw");
00159 m_case_type.add_item("Ugly Jaw");
00160 add_ctrl(m_case_type);
00161 m_case_type.no_transform();
00162
00163 m_inner_join.text_size(8);
00164 m_inner_join.add_item("Inner Bevel");
00165 m_inner_join.add_item("Inner Miter");
00166 m_inner_join.add_item("Inner Jag");
00167 m_inner_join.add_item("Inner Round");
00168 m_inner_join.cur_item(3);
00169 add_ctrl(m_inner_join);
00170 m_inner_join.no_transform();
00171
00172 m_line_join.text_size(8);
00173 m_line_join.add_item("Miter Join");
00174 m_line_join.add_item("Miter Revert");
00175 m_line_join.add_item("Round Join");
00176 m_line_join.add_item("Bevel Join");
00177 m_line_join.add_item("Miter Round");
00178
00179 m_line_join.cur_item(1);
00180 add_ctrl(m_line_join);
00181 m_line_join.no_transform();
00182
00183 m_line_cap.text_size(8);
00184 m_line_cap.add_item("Butt Cap");
00185 m_line_cap.add_item("Square Cap");
00186 m_line_cap.add_item("Round Cap");
00187 m_line_cap.cur_item(0);
00188 add_ctrl(m_line_cap);
00189 m_line_cap.no_transform();
00190 }
00191
00192
00193 template<class Curve> double measure_time(Curve& curve)
00194 {
00195 start_timer();
00196 for(int i = 0; i < 100; i++)
00197 {
00198 double x, y;
00199 curve.init(m_curve1.x1(), m_curve1.y1(),
00200 m_curve1.x2(), m_curve1.y2(),
00201 m_curve1.x3(), m_curve1.y3(),
00202 m_curve1.x4(), m_curve1.y4());
00203 curve.rewind(0);
00204 while(!agg::is_stop(curve.vertex(&x, &y)));
00205 }
00206 return elapsed_time() * 10;
00207 }
00208
00209
00210 template<class Path>
00211 bool find_point(const Path& path, double dist, unsigned* i, unsigned* j)
00212 {
00213 int k;
00214 *j = path.size() - 1;
00215
00216 for(*i = 0; (*j - *i) > 1; )
00217 {
00218 if(dist < path[k = (*i + *j) >> 1].dist) *j = k;
00219 else *i = k;
00220 }
00221 return true;
00222 }
00223
00224 struct curve_point
00225 {
00226 curve_point() {}
00227 curve_point(double x1, double y1, double mu1) : x(x1), y(y1), mu(mu1) {}
00228 double x, y, dist, mu;
00229 };
00230
00231 template<class Curve> double calc_max_error(Curve& curve, double scale,
00232 double* max_angle_error)
00233 {
00234 curve.approximation_scale(m_approximation_scale.value() * scale);
00235 curve.init(m_curve1.x1(), m_curve1.y1(),
00236 m_curve1.x2(), m_curve1.y2(),
00237 m_curve1.x3(), m_curve1.y3(),
00238 m_curve1.x4(), m_curve1.y4());
00239
00240 agg::pod_bvector<agg::vertex_dist, 8> curve_points;
00241 unsigned cmd;
00242 double x, y;
00243 curve.rewind(0);
00244 while(!agg::is_stop(cmd = curve.vertex(&x, &y)))
00245 {
00246 if(agg::is_vertex(cmd))
00247 {
00248 curve_points.add(agg::vertex_dist(x, y));
00249 }
00250 }
00251 unsigned i;
00252 double curve_dist = 0;
00253 for(i = 1; i < curve_points.size(); i++)
00254 {
00255 curve_points[i - 1].dist = curve_dist;
00256 curve_dist += agg::calc_distance(curve_points[i-1].x, curve_points[i-1].y,
00257 curve_points[i].x, curve_points[i].y);
00258 }
00259 curve_points[curve_points.size() - 1].dist = curve_dist;
00260
00261 agg::pod_bvector<curve_point, 8> reference_points;
00262 for(i = 0; i < 4096; i++)
00263 {
00264 double mu = i / 4095.0;
00265 bezier4_point(m_curve1.x1(), m_curve1.y1(),
00266 m_curve1.x2(), m_curve1.y2(),
00267 m_curve1.x3(), m_curve1.y3(),
00268 m_curve1.x4(), m_curve1.y4(),
00269 mu, &x, &y);
00270 reference_points.add(curve_point(x, y, mu));
00271 }
00272
00273 double reference_dist = 0;
00274 for(i = 1; i < reference_points.size(); i++)
00275 {
00276 reference_points[i - 1].dist = reference_dist;
00277 reference_dist += agg::calc_distance(reference_points[i-1].x, reference_points[i-1].y,
00278 reference_points[i].x, reference_points[i].y);
00279 }
00280 reference_points[reference_points.size() - 1].dist = reference_dist;
00281
00282
00283 unsigned idx1 = 0;
00284 unsigned idx2 = 1;
00285 double max_error = 0;
00286 for(i = 0; i < reference_points.size(); i++)
00287 {
00288 if(find_point(curve_points, reference_points[i].dist, &idx1, &idx2))
00289 {
00290 double err = fabs(agg::calc_line_point_distance(curve_points[idx1].x, curve_points[idx1].y,
00291 curve_points[idx2].x, curve_points[idx2].y,
00292 reference_points[i].x, reference_points[i].y));
00293 if(err > max_error) max_error = err;
00294 }
00295 }
00296
00297 double aerr = 0;
00298 for(i = 2; i < curve_points.size(); i++)
00299 {
00300 double a1 = atan2(curve_points[i-1].y - curve_points[i-2].y,
00301 curve_points[i-1].x - curve_points[i-2].x);
00302 double a2 = atan2(curve_points[i].y - curve_points[i-1].y,
00303 curve_points[i].x - curve_points[i-1].x);
00304
00305 double da = fabs(a1 - a2);
00306 if(da >= agg::pi) da = 2*agg::pi - da;
00307 if(da > aerr) aerr = da;
00308 }
00309
00310
00311 *max_angle_error = aerr * 180.0 / agg::pi;
00312 return max_error * scale;
00313 }
00314
00315
00316
00317 virtual void on_draw()
00318 {
00319 pixfmt pf(rbuf_window());
00320 renderer_base ren_base(pf);
00321 ren_base.clear(agg::rgba(1.0, 1.0, 0.95));
00322 renderer_scanline ren(ren_base);
00323
00324 rasterizer_scanline ras;
00325 scanline sl;
00326
00327 agg::path_storage path;
00328
00329 double x, y;
00330 double curve_time = 0;
00331
00332 path.remove_all();
00333 agg::curve4 curve;
00334 curve.approximation_method(agg::curve_approximation_method_e(m_curve_type.cur_item()));
00335 curve.approximation_scale(m_approximation_scale.value());
00336 curve.angle_tolerance(agg::deg2rad(m_angle_tolerance.value()));
00337 curve.cusp_limit(agg::deg2rad(m_cusp_limit.value()));
00338 curve_time = measure_time(curve);
00339 double max_angle_error_01 = 0;
00340 double max_angle_error_1 = 0;
00341 double max_angle_error1 = 0;
00342 double max_angle_error_10 = 0;
00343 double max_angle_error_100 = 0;
00344 double max_error_01 = 0;
00345 double max_error_1 = 0;
00346 double max_error1 = 0;
00347 double max_error_10 = 0;
00348 double max_error_100 = 0;
00349
00350 max_error_01 = calc_max_error(curve, 0.01, &max_angle_error_01);
00351 max_error_1 = calc_max_error(curve, 0.1, &max_angle_error_1);
00352 max_error1 = calc_max_error(curve, 1, &max_angle_error1);
00353 max_error_10 = calc_max_error(curve, 10, &max_angle_error_10);
00354 max_error_100 = calc_max_error(curve, 100, &max_angle_error_100);
00355
00356 curve.approximation_scale(m_approximation_scale.value());
00357 curve.angle_tolerance(agg::deg2rad(m_angle_tolerance.value()));
00358 curve.cusp_limit(agg::deg2rad(m_cusp_limit.value()));
00359 curve.init(m_curve1.x1(), m_curve1.y1(),
00360 m_curve1.x2(), m_curve1.y2(),
00361 m_curve1.x3(), m_curve1.y3(),
00362 m_curve1.x4(), m_curve1.y4());
00363 path.concat_path(curve);
00364
00365
00366 agg::conv_stroke<agg::path_storage> stroke(path);
00367 stroke.width(m_width.value());
00368 stroke.line_join(agg::line_join_e(m_line_join.cur_item()));
00369 stroke.line_cap(agg::line_cap_e(m_line_cap.cur_item()));
00370 stroke.inner_join(agg::inner_join_e(m_inner_join.cur_item()));
00371 stroke.inner_miter_limit(1.01);
00372
00373 ras.add_path(stroke);
00374 ren.color(agg::rgba(0, 0.5, 0, 0.5));
00375 agg::render_scanlines(ras, sl, ren);
00376
00377 unsigned cmd;
00378 unsigned num_points1 = 0;
00379 path.rewind(0);
00380 while(!agg::is_stop(cmd = path.vertex(&x, &y)))
00381 {
00382 if(m_show_points.status())
00383 {
00384 agg::ellipse ell(x, y, 1.5, 1.5, 8);
00385 ras.add_path(ell);
00386 ren.color(agg::rgba(0,0,0, 0.5));
00387 agg::render_scanlines(ras, sl, ren);
00388 }
00389 ++num_points1;
00390 }
00391
00392 if(m_show_outline.status())
00393 {
00394
00395
00396 agg::conv_stroke<agg::conv_stroke<agg::path_storage> > stroke2(stroke);
00397 ras.add_path(stroke2);
00398 ren.color(agg::rgba(0,0,0, 0.5));
00399 agg::render_scanlines(ras, sl, ren);
00400 }
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431 char buf[512];
00432 agg::gsv_text t;
00433 t.size(8.0);
00434
00435 agg::conv_stroke<agg::gsv_text> pt(t);
00436 pt.line_cap(agg::round_cap);
00437 pt.line_join(agg::round_join);
00438 pt.width(1.5);
00439
00440 sprintf(buf, "Num Points=%d Time=%.2fmks\n\n"
00441 " Dist Error: x0.01=%.5f x0.1=%.5f x1=%.5f x10=%.5f x100=%.5f\n\n"
00442 "Angle Error: x0.01=%.1f x0.1=%.1f x1=%.1f x10=%.1f x100=%.1f",
00443 num_points1, curve_time,
00444 max_error_01,
00445 max_error_1,
00446 max_error1,
00447 max_error_10,
00448 max_error_100,
00449 max_angle_error_01,
00450 max_angle_error_1,
00451 max_angle_error1,
00452 max_angle_error_10,
00453 max_angle_error_100);
00454
00455 t.start_point(10.0, 85.0);
00456 t.text(buf);
00457
00458 ras.add_path(pt);
00459 ren.color(agg::rgba(0,0,0));
00460 agg::render_scanlines(ras, sl, ren);
00461
00462 agg::render_ctrl(ras, sl, ren_base, m_curve1);
00463 agg::render_ctrl(ras, sl, ren_base, m_angle_tolerance);
00464 agg::render_ctrl(ras, sl, ren_base, m_approximation_scale);
00465 agg::render_ctrl(ras, sl, ren_base, m_cusp_limit);
00466 agg::render_ctrl(ras, sl, ren_base, m_width);
00467 agg::render_ctrl(ras, sl, ren_base, m_show_points);
00468 agg::render_ctrl(ras, sl, ren_base, m_show_outline);
00469 agg::render_ctrl(ras, sl, ren_base, m_curve_type);
00470 agg::render_ctrl(ras, sl, ren_base, m_case_type);
00471 agg::render_ctrl(ras, sl, ren_base, m_inner_join);
00472 agg::render_ctrl(ras, sl, ren_base, m_line_join);
00473 agg::render_ctrl(ras, sl, ren_base, m_line_cap);
00474 }
00475
00476
00477 virtual void on_key(int x, int y, unsigned key, unsigned flags)
00478 {
00479 if(key == ' ')
00480 {
00481 FILE* fd = fopen(full_file_name("coord"), "w");
00482 fprintf(fd, "%.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f",
00483 m_curve1.x1(), m_curve1.y1(),
00484 m_curve1.x2(), m_curve1.y2(),
00485 m_curve1.x3(), m_curve1.y3(),
00486 m_curve1.x4(), m_curve1.y4());
00487 fclose(fd);
00488 }
00489 }
00490
00491 virtual void on_ctrl_change()
00492 {
00493 if(m_case_type.cur_item() != m_cur_case_type)
00494 {
00495 switch(m_case_type.cur_item())
00496 {
00497 case 0:
00498 {
00499 int w = int(width() - 120);
00500 int h = int(height() - 80);
00501 m_curve1.curve(rand() % w, rand() % h + 80, rand() % w, rand() % h + 80,
00502 rand() % w, rand() % h + 80, rand() % w, rand() % h + 80);
00503 }
00504 break;
00505
00506 case 1:
00507 m_curve1.curve(150, 150, 350, 150, 150, 150, 350, 150);
00508
00509
00510 break;
00511
00512 case 2:
00513 m_curve1.curve(50, 142, 483, 251, 496, 62, 26, 333);
00514 break;
00515
00516 case 3:
00517 m_curve1.curve(50, 142, 484, 251, 496, 62, 26, 333);
00518 break;
00519
00520 case 4:
00521 m_curve1.curve(100, 100, 300, 200, 200, 200, 200, 100);
00522 break;
00523
00524 case 5:
00525 m_curve1.curve(475, 157, 200, 100, 453, 100, 222, 157);
00526 break;
00527
00528 case 6:
00529 m_curve1.curve(129, 233, 32, 283, 258, 285, 159, 232);
00530 m_width.value(100);
00531 break;
00532
00533 case 7:
00534 m_curve1.curve(100, 100, 300, 200, 264, 286, 264, 284);
00535 break;
00536
00537 case 8:
00538 m_curve1.curve(100, 100, 413, 304, 264, 286, 264, 284);
00539 break;
00540 }
00541 force_redraw();
00542 m_cur_case_type = m_case_type.cur_item();
00543 }
00544 }
00545 };
00546
00547
00548 int agg_main(int argc, char* argv[])
00549 {
00550 the_application app(agg::pix_format_bgr24, flip_y);
00551 app.caption("AGG Example");
00552 if(app.init(655, 520, agg::window_resize))
00553 {
00554 return app.run();
00555 }
00556 return 1;
00557 }
00558
00559
00560
00561
00562