1 //---------------------------------------------------------------------------- 2 // Anti-Grain Geometry - Version 2.4 3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) 4 // 5 // Permission to copy, use, modify, sell and distribute this software 6 // is granted provided this copyright notice appears in all copies. 7 // This software is provided "as is" without express or implied 8 // warranty, and with no claim as to its suitability for any purpose. 9 // 10 //---------------------------------------------------------------------------- 11 // Contact: mcseem@antigrain.com 12 // mcseemagg@yahoo.com 13 // http://www.antigrain.com 14 //---------------------------------------------------------------------------- 15 #ifndef AGG_RASTERIZER_OUTLINE_AA_INCLUDED 16 #define AGG_RASTERIZER_OUTLINE_AA_INCLUDED 17 18 #include "agg_basics.h" 19 #include "agg_line_aa_basics.h" 20 #include "agg_vertex_sequence.h" 21 22 namespace agg 23 { 24 25 //------------------------------------------------------------------------- cmp_dist_start(int d)26 inline bool cmp_dist_start(int d) { return d > 0; } cmp_dist_end(int d)27 inline bool cmp_dist_end(int d) { return d <= 0; } 28 29 30 31 //-----------------------------------------------------------line_aa_vertex 32 // Vertex (x, y) with the distance to the next one. The last vertex has 33 // the distance between the last and the first points 34 struct line_aa_vertex 35 { 36 int x; 37 int y; 38 int len; 39 line_aa_vertexline_aa_vertex40 line_aa_vertex() {} line_aa_vertexline_aa_vertex41 line_aa_vertex(int x_, int y_) : 42 x(x_), 43 y(y_), 44 len(0) 45 { 46 } 47 operatorline_aa_vertex48 bool operator () (const line_aa_vertex& val) 49 { 50 double dx = val.x - x; 51 double dy = val.y - y; 52 return (len = uround(sqrt(dx * dx + dy * dy))) > 53 (line_subpixel_scale + line_subpixel_scale / 2); 54 } 55 }; 56 57 58 //----------------------------------------------------------outline_aa_join_e 59 enum outline_aa_join_e 60 { 61 outline_no_join, //-----outline_no_join 62 outline_miter_join, //-----outline_miter_join 63 outline_round_join, //-----outline_round_join 64 outline_miter_accurate_join //-----outline_accurate_join 65 }; 66 67 //=======================================================rasterizer_outline_aa 68 template<class Renderer, class Coord=line_coord> class rasterizer_outline_aa 69 { 70 private: 71 //------------------------------------------------------------------------ 72 struct draw_vars 73 { 74 unsigned idx; 75 int x1, y1, x2, y2; 76 line_parameters curr, next; 77 int lcurr, lnext; 78 int xb1, yb1, xb2, yb2; 79 unsigned flags; 80 }; 81 82 void draw(draw_vars& dv, unsigned start, unsigned end); 83 84 public: 85 typedef line_aa_vertex vertex_type; 86 typedef vertex_sequence<vertex_type, 6> vertex_storage_type; 87 rasterizer_outline_aa(Renderer & ren)88 rasterizer_outline_aa(Renderer& ren) : 89 m_ren(&ren), 90 m_line_join(ren.accurate_join_only() ? 91 outline_miter_accurate_join : 92 outline_round_join), 93 m_round_cap(false), 94 m_start_x(0), 95 m_start_y(0) 96 {} attach(Renderer & ren)97 void attach(Renderer& ren) { m_ren = &ren; } 98 99 //------------------------------------------------------------------------ line_join(outline_aa_join_e join)100 void line_join(outline_aa_join_e join) 101 { 102 m_line_join = m_ren->accurate_join_only() ? 103 outline_miter_accurate_join : 104 join; 105 } line_join()106 bool line_join() const { return m_line_join; } 107 108 //------------------------------------------------------------------------ round_cap(bool v)109 void round_cap(bool v) { m_round_cap = v; } round_cap()110 bool round_cap() const { return m_round_cap; } 111 112 //------------------------------------------------------------------------ move_to(int x,int y)113 void move_to(int x, int y) 114 { 115 m_src_vertices.modify_last(vertex_type(m_start_x = x, m_start_y = y)); 116 } 117 118 //------------------------------------------------------------------------ line_to(int x,int y)119 void line_to(int x, int y) 120 { 121 m_src_vertices.add(vertex_type(x, y)); 122 } 123 124 //------------------------------------------------------------------------ move_to_d(double x,double y)125 void move_to_d(double x, double y) 126 { 127 move_to(Coord::conv(x), Coord::conv(y)); 128 } 129 130 //------------------------------------------------------------------------ line_to_d(double x,double y)131 void line_to_d(double x, double y) 132 { 133 line_to(Coord::conv(x), Coord::conv(y)); 134 } 135 136 //------------------------------------------------------------------------ 137 void render(bool close_polygon); 138 139 //------------------------------------------------------------------------ add_vertex(double x,double y,unsigned cmd)140 void add_vertex(double x, double y, unsigned cmd) 141 { 142 if(is_move_to(cmd)) 143 { 144 render(false); 145 move_to_d(x, y); 146 } 147 else 148 { 149 if(is_end_poly(cmd)) 150 { 151 render(is_closed(cmd)); 152 if(is_closed(cmd)) 153 { 154 move_to(m_start_x, m_start_y); 155 } 156 } 157 else 158 { 159 line_to_d(x, y); 160 } 161 } 162 } 163 164 //------------------------------------------------------------------------ 165 template<class VertexSource> 166 void add_path(VertexSource& vs, unsigned path_id=0) 167 { 168 double x; 169 double y; 170 171 unsigned cmd; 172 vs.rewind(path_id); 173 while(!is_stop(cmd = vs.vertex(&x, &y))) 174 { 175 add_vertex(x, y, cmd); 176 } 177 render(false); 178 } 179 180 181 //------------------------------------------------------------------------ 182 template<class VertexSource, class ColorStorage, class PathId> render_all_paths(VertexSource & vs,const ColorStorage & colors,const PathId & path_id,unsigned num_paths)183 void render_all_paths(VertexSource& vs, 184 const ColorStorage& colors, 185 const PathId& path_id, 186 unsigned num_paths) 187 { 188 for(unsigned i = 0; i < num_paths; i++) 189 { 190 m_ren->color(colors[i]); 191 add_path(vs, path_id[i]); 192 } 193 } 194 195 196 //------------------------------------------------------------------------ render_ctrl(Ctrl & c)197 template<class Ctrl> void render_ctrl(Ctrl& c) 198 { 199 unsigned i; 200 for(i = 0; i < c.num_paths(); i++) 201 { 202 m_ren->color(c.color(i)); 203 add_path(c, i); 204 } 205 } 206 207 private: 208 rasterizer_outline_aa(const rasterizer_outline_aa<Renderer, Coord>&); 209 const rasterizer_outline_aa<Renderer, Coord>& operator = 210 (const rasterizer_outline_aa<Renderer, Coord>&); 211 212 Renderer* m_ren; 213 vertex_storage_type m_src_vertices; 214 outline_aa_join_e m_line_join; 215 bool m_round_cap; 216 int m_start_x; 217 int m_start_y; 218 }; 219 220 221 222 223 224 225 226 227 //---------------------------------------------------------------------------- 228 template<class Renderer, class Coord> draw(draw_vars & dv,unsigned start,unsigned end)229 void rasterizer_outline_aa<Renderer, Coord>::draw(draw_vars& dv, 230 unsigned start, 231 unsigned end) 232 { 233 unsigned i; 234 const vertex_storage_type::value_type* v; 235 236 for(i = start; i < end; i++) 237 { 238 if(m_line_join == outline_round_join) 239 { 240 dv.xb1 = dv.curr.x1 + (dv.curr.y2 - dv.curr.y1); 241 dv.yb1 = dv.curr.y1 - (dv.curr.x2 - dv.curr.x1); 242 dv.xb2 = dv.curr.x2 + (dv.curr.y2 - dv.curr.y1); 243 dv.yb2 = dv.curr.y2 - (dv.curr.x2 - dv.curr.x1); 244 } 245 246 switch(dv.flags) 247 { 248 case 0: m_ren->line3(dv.curr, dv.xb1, dv.yb1, dv.xb2, dv.yb2); break; 249 case 1: m_ren->line2(dv.curr, dv.xb2, dv.yb2); break; 250 case 2: m_ren->line1(dv.curr, dv.xb1, dv.yb1); break; 251 case 3: m_ren->line0(dv.curr); break; 252 } 253 254 if(m_line_join == outline_round_join && (dv.flags & 2) == 0) 255 { 256 m_ren->pie(dv.curr.x2, dv.curr.y2, 257 dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), 258 dv.curr.y2 - (dv.curr.x2 - dv.curr.x1), 259 dv.curr.x2 + (dv.next.y2 - dv.next.y1), 260 dv.curr.y2 - (dv.next.x2 - dv.next.x1)); 261 } 262 263 dv.x1 = dv.x2; 264 dv.y1 = dv.y2; 265 dv.lcurr = dv.lnext; 266 dv.lnext = m_src_vertices[dv.idx].len; 267 268 ++dv.idx; 269 if(dv.idx >= m_src_vertices.size()) dv.idx = 0; 270 271 v = &m_src_vertices[dv.idx]; 272 dv.x2 = v->x; 273 dv.y2 = v->y; 274 275 dv.curr = dv.next; 276 dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext); 277 dv.xb1 = dv.xb2; 278 dv.yb1 = dv.yb2; 279 280 switch(m_line_join) 281 { 282 case outline_no_join: 283 dv.flags = 3; 284 break; 285 286 case outline_miter_join: 287 dv.flags >>= 1; 288 dv.flags |= ((dv.curr.diagonal_quadrant() == 289 dv.next.diagonal_quadrant()) << 1); 290 if((dv.flags & 2) == 0) 291 { 292 bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2); 293 } 294 break; 295 296 case outline_round_join: 297 dv.flags >>= 1; 298 dv.flags |= ((dv.curr.diagonal_quadrant() == 299 dv.next.diagonal_quadrant()) << 1); 300 break; 301 302 case outline_miter_accurate_join: 303 dv.flags = 0; 304 bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2); 305 break; 306 } 307 } 308 } 309 310 311 312 313 //---------------------------------------------------------------------------- 314 template<class Renderer, class Coord> render(bool close_polygon)315 void rasterizer_outline_aa<Renderer, Coord>::render(bool close_polygon) 316 { 317 m_src_vertices.close(close_polygon); 318 draw_vars dv; 319 const vertex_storage_type::value_type* v; 320 int x1; 321 int y1; 322 int x2; 323 int y2; 324 int lprev; 325 326 if(close_polygon) 327 { 328 if(m_src_vertices.size() >= 3) 329 { 330 dv.idx = 2; 331 332 v = &m_src_vertices[m_src_vertices.size() - 1]; 333 x1 = v->x; 334 y1 = v->y; 335 lprev = v->len; 336 337 v = &m_src_vertices[0]; 338 x2 = v->x; 339 y2 = v->y; 340 dv.lcurr = v->len; 341 line_parameters prev(x1, y1, x2, y2, lprev); 342 343 v = &m_src_vertices[1]; 344 dv.x1 = v->x; 345 dv.y1 = v->y; 346 dv.lnext = v->len; 347 dv.curr = line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr); 348 349 v = &m_src_vertices[dv.idx]; 350 dv.x2 = v->x; 351 dv.y2 = v->y; 352 dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext); 353 354 dv.xb1 = 0; 355 dv.yb1 = 0; 356 dv.xb2 = 0; 357 dv.yb2 = 0; 358 359 switch(m_line_join) 360 { 361 case outline_no_join: 362 dv.flags = 3; 363 break; 364 365 case outline_miter_join: 366 case outline_round_join: 367 dv.flags = 368 (prev.diagonal_quadrant() == dv.curr.diagonal_quadrant()) | 369 ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1); 370 break; 371 372 case outline_miter_accurate_join: 373 dv.flags = 0; 374 break; 375 } 376 377 if((dv.flags & 1) == 0 && m_line_join != outline_round_join) 378 { 379 bisectrix(prev, dv.curr, &dv.xb1, &dv.yb1); 380 } 381 382 if((dv.flags & 2) == 0 && m_line_join != outline_round_join) 383 { 384 bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2); 385 } 386 draw(dv, 0, m_src_vertices.size()); 387 } 388 } 389 else 390 { 391 switch(m_src_vertices.size()) 392 { 393 case 0: 394 case 1: 395 break; 396 397 case 2: 398 { 399 v = &m_src_vertices[0]; 400 x1 = v->x; 401 y1 = v->y; 402 lprev = v->len; 403 v = &m_src_vertices[1]; 404 x2 = v->x; 405 y2 = v->y; 406 line_parameters lp(x1, y1, x2, y2, lprev); 407 if(m_round_cap) 408 { 409 m_ren->semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1)); 410 } 411 m_ren->line3(lp, 412 x1 + (y2 - y1), 413 y1 - (x2 - x1), 414 x2 + (y2 - y1), 415 y2 - (x2 - x1)); 416 if(m_round_cap) 417 { 418 m_ren->semidot(cmp_dist_end, x2, y2, x2 + (y2 - y1), y2 - (x2 - x1)); 419 } 420 } 421 break; 422 423 case 3: 424 { 425 int x3, y3; 426 int lnext; 427 v = &m_src_vertices[0]; 428 x1 = v->x; 429 y1 = v->y; 430 lprev = v->len; 431 v = &m_src_vertices[1]; 432 x2 = v->x; 433 y2 = v->y; 434 lnext = v->len; 435 v = &m_src_vertices[2]; 436 x3 = v->x; 437 y3 = v->y; 438 line_parameters lp1(x1, y1, x2, y2, lprev); 439 line_parameters lp2(x2, y2, x3, y3, lnext); 440 441 if(m_round_cap) 442 { 443 m_ren->semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1)); 444 } 445 446 if(m_line_join == outline_round_join) 447 { 448 m_ren->line3(lp1, x1 + (y2 - y1), y1 - (x2 - x1), 449 x2 + (y2 - y1), y2 - (x2 - x1)); 450 451 m_ren->pie(x2, y2, x2 + (y2 - y1), y2 - (x2 - x1), 452 x2 + (y3 - y2), y2 - (x3 - x2)); 453 454 m_ren->line3(lp2, x2 + (y3 - y2), y2 - (x3 - x2), 455 x3 + (y3 - y2), y3 - (x3 - x2)); 456 } 457 else 458 { 459 bisectrix(lp1, lp2, &dv.xb1, &dv.yb1); 460 m_ren->line3(lp1, x1 + (y2 - y1), y1 - (x2 - x1), 461 dv.xb1, dv.yb1); 462 463 m_ren->line3(lp2, dv.xb1, dv.yb1, 464 x3 + (y3 - y2), y3 - (x3 - x2)); 465 } 466 if(m_round_cap) 467 { 468 m_ren->semidot(cmp_dist_end, x3, y3, x3 + (y3 - y2), y3 - (x3 - x2)); 469 } 470 } 471 break; 472 473 default: 474 { 475 dv.idx = 3; 476 477 v = &m_src_vertices[0]; 478 x1 = v->x; 479 y1 = v->y; 480 lprev = v->len; 481 482 v = &m_src_vertices[1]; 483 x2 = v->x; 484 y2 = v->y; 485 dv.lcurr = v->len; 486 line_parameters prev(x1, y1, x2, y2, lprev); 487 488 v = &m_src_vertices[2]; 489 dv.x1 = v->x; 490 dv.y1 = v->y; 491 dv.lnext = v->len; 492 dv.curr = line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr); 493 494 v = &m_src_vertices[dv.idx]; 495 dv.x2 = v->x; 496 dv.y2 = v->y; 497 dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext); 498 499 dv.xb1 = 0; 500 dv.yb1 = 0; 501 dv.xb2 = 0; 502 dv.yb2 = 0; 503 504 switch(m_line_join) 505 { 506 case outline_no_join: 507 dv.flags = 3; 508 break; 509 510 case outline_miter_join: 511 case outline_round_join: 512 dv.flags = 513 (prev.diagonal_quadrant() == dv.curr.diagonal_quadrant()) | 514 ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1); 515 break; 516 517 case outline_miter_accurate_join: 518 dv.flags = 0; 519 break; 520 } 521 522 if(m_round_cap) 523 { 524 m_ren->semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1)); 525 } 526 if((dv.flags & 1) == 0) 527 { 528 if(m_line_join == outline_round_join) 529 { 530 m_ren->line3(prev, x1 + (y2 - y1), y1 - (x2 - x1), 531 x2 + (y2 - y1), y2 - (x2 - x1)); 532 m_ren->pie(prev.x2, prev.y2, 533 x2 + (y2 - y1), y2 - (x2 - x1), 534 dv.curr.x1 + (dv.curr.y2 - dv.curr.y1), 535 dv.curr.y1 - (dv.curr.x2 - dv.curr.x1)); 536 } 537 else 538 { 539 bisectrix(prev, dv.curr, &dv.xb1, &dv.yb1); 540 m_ren->line3(prev, x1 + (y2 - y1), y1 - (x2 - x1), 541 dv.xb1, dv.yb1); 542 } 543 } 544 else 545 { 546 m_ren->line1(prev, 547 x1 + (y2 - y1), 548 y1 - (x2 - x1)); 549 } 550 if((dv.flags & 2) == 0 && m_line_join != outline_round_join) 551 { 552 bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2); 553 } 554 555 draw(dv, 1, m_src_vertices.size() - 2); 556 557 if((dv.flags & 1) == 0) 558 { 559 if(m_line_join == outline_round_join) 560 { 561 m_ren->line3(dv.curr, 562 dv.curr.x1 + (dv.curr.y2 - dv.curr.y1), 563 dv.curr.y1 - (dv.curr.x2 - dv.curr.x1), 564 dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), 565 dv.curr.y2 - (dv.curr.x2 - dv.curr.x1)); 566 } 567 else 568 { 569 m_ren->line3(dv.curr, dv.xb1, dv.yb1, 570 dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), 571 dv.curr.y2 - (dv.curr.x2 - dv.curr.x1)); 572 } 573 } 574 else 575 { 576 m_ren->line2(dv.curr, 577 dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), 578 dv.curr.y2 - (dv.curr.x2 - dv.curr.x1)); 579 } 580 if(m_round_cap) 581 { 582 m_ren->semidot(cmp_dist_end, dv.curr.x2, dv.curr.y2, 583 dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), 584 dv.curr.y2 - (dv.curr.x2 - dv.curr.x1)); 585 } 586 587 } 588 break; 589 } 590 } 591 m_src_vertices.remove_all(); 592 } 593 594 595 } 596 597 598 #endif 599 600