1 //---------------------------------------------------------------------------- 2 // Anti-Grain Geometry - Version 2.2 3 // Copyright (C) 2002-2004 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 //------------------------------------------------------------------------- 26 inline bool cmp_dist_start(int d) { return d > 0; } 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 40 line_aa_vertex() {} 41 line_aa_vertex(int x_, int y_) : 42 x(x_), 43 y(y_), 44 len(0) 45 { 46 } 47 48 bool operator () (const line_aa_vertex& val) 49 { 50 double dx = val.x - x; 51 double dy = val.y - y; 52 return (len = int(sqrt(dx * dx + dy * dy))) > 53 (line_subpixel_size + line_subpixel_size / 2); 54 } 55 }; 56 57 58 59 60 //=======================================================rasterizer_outline_aa 61 template<class Renderer> class rasterizer_outline_aa 62 { 63 private: 64 //------------------------------------------------------------------------ 65 struct draw_vars 66 { 67 unsigned idx; 68 int x1, y1, x2, y2; 69 line_parameters curr, next; 70 int lcurr, lnext; 71 int xb1, yb1, xb2, yb2; 72 unsigned flags; 73 }; 74 75 void draw(draw_vars& dv, unsigned start, unsigned end); 76 77 public: 78 typedef line_aa_vertex vertex_type; 79 typedef vertex_sequence<vertex_type, 6> vertex_storage_type; 80 81 rasterizer_outline_aa(Renderer& ren) : 82 m_ren(ren), 83 m_accurate_join(m_ren.accurate_join_only()), 84 m_round_cap(false), 85 m_start_x(0), 86 m_start_y(0) 87 { 88 } 89 90 //------------------------------------------------------------------------ 91 void accurate_join(bool v) 92 { 93 m_accurate_join = m_ren.accurate_join_only() ? true : v; 94 } 95 bool accurate_join() const { return m_accurate_join; } 96 97 //------------------------------------------------------------------------ 98 void round_cap(bool v) { m_round_cap = v; } 99 bool round_cap() const { return m_round_cap; } 100 101 //------------------------------------------------------------------------ 102 void move_to(int x, int y) 103 { 104 m_src_vertices.modify_last(vertex_type(m_start_x = x, m_start_y = y)); 105 } 106 107 //------------------------------------------------------------------------ 108 void line_to(int x, int y) 109 { 110 m_src_vertices.add(vertex_type(x, y)); 111 } 112 113 //------------------------------------------------------------------------ 114 void move_to_d(double x, double y) 115 { 116 move_to(line_coord(x), line_coord(y)); 117 } 118 119 //------------------------------------------------------------------------ 120 void line_to_d(double x, double y) 121 { 122 line_to(line_coord(x), line_coord(y)); 123 } 124 125 //------------------------------------------------------------------------ 126 void render(bool close_polygon); 127 128 //------------------------------------------------------------------------ 129 void add_vertex(double x, double y, unsigned cmd) 130 { 131 if(is_move_to(cmd)) 132 { 133 render(false); 134 move_to_d(x, y); 135 } 136 else 137 { 138 if(is_end_poly(cmd)) 139 { 140 render(is_closed(cmd)); 141 if(is_closed(cmd)) move_to(m_start_x, m_start_y); 142 } 143 else 144 { 145 line_to_d(x, y); 146 } 147 } 148 } 149 150 //------------------------------------------------------------------------ 151 template<class VertexSource> 152 void add_path(VertexSource& vs, unsigned id=0) 153 { 154 double x; 155 double y; 156 157 unsigned cmd; 158 vs.rewind(id); 159 while(!is_stop(cmd = vs.vertex(&x, &y))) 160 { 161 add_vertex(x, y, cmd); 162 } 163 render(false); 164 } 165 166 167 //------------------------------------------------------------------------ 168 template<class VertexSource, class ColorStorage, class PathId> 169 void render_all_paths(VertexSource& vs, 170 const ColorStorage& colors, 171 const PathId& id, 172 unsigned num_paths) 173 { 174 for(unsigned i = 0; i < num_paths; i++) 175 { 176 m_ren.color(colors[i]); 177 add_path(vs, id[i]); 178 } 179 } 180 181 182 //------------------------------------------------------------------------ 183 template<class Ctrl> void render_ctrl(Ctrl& c) 184 { 185 unsigned i; 186 for(i = 0; i < c.num_paths(); i++) 187 { 188 m_ren.color(c.color(i)); 189 add_path(c, i); 190 } 191 } 192 193 private: 194 rasterizer_outline_aa(const rasterizer_outline_aa<Renderer>&); 195 const rasterizer_outline_aa<Renderer>& operator = 196 (const rasterizer_outline_aa<Renderer>&); 197 198 Renderer& m_ren; 199 vertex_storage_type m_src_vertices; 200 bool m_accurate_join; 201 bool m_round_cap; 202 int m_start_x; 203 int m_start_y; 204 }; 205 206 207 208 209 210 211 212 213 //---------------------------------------------------------------------------- 214 template<class Renderer> 215 void rasterizer_outline_aa<Renderer>::draw(draw_vars& dv, unsigned start, unsigned end) 216 { 217 unsigned i; 218 const vertex_storage_type::value_type* v; 219 220 for(i = start; i < end; i++) 221 { 222 switch(dv.flags) 223 { 224 case 0: m_ren.line3(dv.curr, dv.xb1, dv.yb1, dv.xb2, dv.yb2); break; 225 case 1: m_ren.line2(dv.curr, dv.xb2, dv.yb2); break; 226 case 2: m_ren.line1(dv.curr, dv.xb1, dv.yb1); break; 227 case 3: m_ren.line0(dv.curr); break; 228 } 229 230 dv.x1 = dv.x2; 231 dv.y1 = dv.y2; 232 dv.lcurr = dv.lnext; 233 dv.lnext = m_src_vertices[dv.idx].len; 234 235 ++dv.idx; 236 if(dv.idx >= m_src_vertices.size()) dv.idx = 0; 237 238 v = &m_src_vertices[dv.idx]; 239 dv.x2 = v->x; 240 dv.y2 = v->y; 241 242 dv.curr = dv.next; 243 dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext); 244 dv.xb1 = dv.xb2; 245 dv.yb1 = dv.yb2; 246 247 if(m_accurate_join) 248 { 249 dv.flags = 0; 250 } 251 else 252 { 253 dv.flags >>= 1; 254 dv.flags |= ((dv.curr.diagonal_quadrant() == 255 dv.next.diagonal_quadrant()) << 1); 256 } 257 258 if((dv.flags & 2) == 0) 259 { 260 bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2); 261 } 262 } 263 } 264 265 266 267 268 //---------------------------------------------------------------------------- 269 template<class Renderer> 270 void rasterizer_outline_aa<Renderer>::render(bool close_polygon) 271 { 272 m_src_vertices.close(close_polygon); 273 draw_vars dv; 274 const vertex_storage_type::value_type* v; 275 int x1; 276 int y1; 277 int x2; 278 int y2; 279 int lprev; 280 281 if(close_polygon) 282 { 283 if(m_src_vertices.size() >= 3) 284 { 285 dv.idx = 2; 286 287 v = &m_src_vertices[m_src_vertices.size() - 1]; 288 x1 = v->x; 289 y1 = v->y; 290 lprev = v->len; 291 292 v = &m_src_vertices[0]; 293 x2 = v->x; 294 y2 = v->y; 295 dv.lcurr = v->len; 296 line_parameters prev(x1, y1, x2, y2, lprev); 297 298 v = &m_src_vertices[1]; 299 dv.x1 = v->x; 300 dv.y1 = v->y; 301 dv.lnext = v->len; 302 dv.curr = line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr); 303 304 v = &m_src_vertices[dv.idx]; 305 dv.x2 = v->x; 306 dv.y2 = v->y; 307 dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext); 308 309 dv.xb1 = 0; 310 dv.yb1 = 0; 311 dv.xb2 = 0; 312 dv.yb2 = 0; 313 314 if(m_accurate_join) 315 { 316 dv.flags = 0; 317 } 318 else 319 { 320 dv.flags = 321 (prev.diagonal_quadrant() == dv.curr.diagonal_quadrant()) | 322 ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1); 323 } 324 325 if((dv.flags & 1) == 0) 326 { 327 bisectrix(prev, dv.curr, &dv.xb1, &dv.yb1); 328 } 329 330 if((dv.flags & 2) == 0) 331 { 332 bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2); 333 } 334 draw(dv, 0, m_src_vertices.size()); 335 } 336 } 337 else 338 { 339 switch(m_src_vertices.size()) 340 { 341 case 0: 342 case 1: 343 break; 344 345 case 2: 346 { 347 v = &m_src_vertices[0]; 348 x1 = v->x; 349 y1 = v->y; 350 lprev = v->len; 351 v = &m_src_vertices[1]; 352 x2 = v->x; 353 y2 = v->y; 354 line_parameters lp(x1, y1, x2, y2, lprev); 355 if(m_round_cap) 356 { 357 m_ren.semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1)); 358 } 359 m_ren.line3(lp, 360 x1 + (y2 - y1), 361 y1 - (x2 - x1), 362 x2 + (y2 - y1), 363 y2 - (x2 - x1)); 364 if(m_round_cap) 365 { 366 m_ren.semidot(cmp_dist_end, x2, y2, x2 + (y2 - y1), y2 - (x2 - x1)); 367 } 368 } 369 break; 370 371 case 3: 372 { 373 int x3, y3; 374 int lnext; 375 v = &m_src_vertices[0]; 376 x1 = v->x; 377 y1 = v->y; 378 lprev = v->len; 379 v = &m_src_vertices[1]; 380 x2 = v->x; 381 y2 = v->y; 382 lnext = v->len; 383 v = &m_src_vertices[2]; 384 x3 = v->x; 385 y3 = v->y; 386 line_parameters lp1(x1, y1, x2, y2, lprev); 387 line_parameters lp2(x2, y2, x3, y3, lnext); 388 bisectrix(lp1, lp2, &dv.xb1, &dv.yb1); 389 390 if(m_round_cap) 391 { 392 m_ren.semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1)); 393 } 394 m_ren.line3(lp1, 395 x1 + (y2 - y1), 396 y1 - (x2 - x1), 397 dv.xb1, 398 dv.yb1); 399 400 m_ren.line3(lp2, 401 dv.xb1, 402 dv.yb1, 403 x3 + (y3 - y2), 404 y3 - (x3 - x2)); 405 if(m_round_cap) 406 { 407 m_ren.semidot(cmp_dist_end, x3, y3, x3 + (y3 - y2), y3 - (x3 - x2)); 408 } 409 } 410 break; 411 412 default: 413 { 414 dv.idx = 3; 415 416 v = &m_src_vertices[0]; 417 x1 = v->x; 418 y1 = v->y; 419 lprev = v->len; 420 421 v = &m_src_vertices[1]; 422 x2 = v->x; 423 y2 = v->y; 424 dv.lcurr = v->len; 425 line_parameters prev(x1, y1, x2, y2, lprev); 426 427 v = &m_src_vertices[2]; 428 dv.x1 = v->x; 429 dv.y1 = v->y; 430 dv.lnext = v->len; 431 dv.curr = line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr); 432 433 v = &m_src_vertices[dv.idx]; 434 dv.x2 = v->x; 435 dv.y2 = v->y; 436 dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext); 437 438 dv.xb1 = 0; 439 dv.yb1 = 0; 440 dv.xb2 = 0; 441 dv.yb2 = 0; 442 443 if(m_accurate_join) 444 { 445 dv.flags = 0; 446 } 447 else 448 { 449 dv.flags = 450 (prev.diagonal_quadrant() == dv.curr.diagonal_quadrant()) | 451 ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1); 452 } 453 454 if((dv.flags & 1) == 0) 455 { 456 bisectrix(prev, dv.curr, &dv.xb1, &dv.yb1); 457 m_ren.line3(prev, 458 x1 + (y2 - y1), 459 y1 - (x2 - x1), 460 dv.xb1, 461 dv.yb1); 462 } 463 else 464 { 465 m_ren.line1(prev, 466 x1 + (y2 - y1), 467 y1 - (x2 - x1)); 468 } 469 if(m_round_cap) 470 { 471 m_ren.semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1)); 472 } 473 if((dv.flags & 2) == 0) 474 { 475 bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2); 476 } 477 478 draw(dv, 1, m_src_vertices.size() - 2); 479 480 if((dv.flags & 1) == 0) 481 { 482 m_ren.line3(dv.curr, 483 dv.xb1, 484 dv.yb1, 485 dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), 486 dv.curr.y2 - (dv.curr.x2 - dv.curr.x1)); 487 } 488 else 489 { 490 m_ren.line2(dv.curr, 491 dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), 492 dv.curr.y2 - (dv.curr.x2 - dv.curr.x1)); 493 } 494 if(m_round_cap) 495 { 496 m_ren.semidot(cmp_dist_end, dv.curr.x2, dv.curr.y2, 497 dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), 498 dv.curr.y2 - (dv.curr.x2 - dv.curr.x1)); 499 } 500 501 } 502 break; 503 } 504 } 505 m_src_vertices.remove_all(); 506 } 507 508 509 } 510 511 512 #endif 513 514