Anti-Grain Geometry - AGG (libagg)  2.5
agg-2.5/include/agg_rasterizer_outline_aa.h
Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 // Anti-Grain Geometry (AGG) - Version 2.5
00003 // A high quality rendering engine for C++
00004 // Copyright (C) 2002-2006 Maxim Shemanarev
00005 // Contact: mcseem@antigrain.com
00006 //          mcseemagg@yahoo.com
00007 //          http://antigrain.com
00008 // 
00009 // AGG is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU General Public License
00011 // as published by the Free Software Foundation; either version 2
00012 // of the License, or (at your option) any later version.
00013 // 
00014 // AGG is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 // GNU General Public License for more details.
00018 // 
00019 // You should have received a copy of the GNU General Public License
00020 // along with AGG; if not, write to the Free Software
00021 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
00022 // MA 02110-1301, USA.
00023 //----------------------------------------------------------------------------
00024 
00025 #ifndef AGG_RASTERIZER_OUTLINE_AA_INCLUDED
00026 #define AGG_RASTERIZER_OUTLINE_AA_INCLUDED
00027 
00028 #include "agg_basics.h"
00029 #include "agg_line_aa_basics.h"
00030 #include "agg_vertex_sequence.h"
00031 
00032 namespace agg
00033 {
00034 
00035     //-------------------------------------------------------------------------
00036     inline bool cmp_dist_start(int d) { return d > 0;  }
00037     inline bool cmp_dist_end(int d)   { return d <= 0; }
00038 
00039 
00040 
00041     //-----------------------------------------------------------line_aa_vertex
00042     // Vertex (x, y) with the distance to the next one. The last vertex has 
00043     // the distance between the last and the first points
00044     struct line_aa_vertex
00045     {
00046         int x;
00047         int y;
00048         int len;
00049 
00050         line_aa_vertex() {}
00051         line_aa_vertex(int x_, int y_) :
00052             x(x_),
00053             y(y_),
00054             len(0)
00055         {
00056         }
00057 
00058         bool operator () (const line_aa_vertex& val)
00059         {
00060             double dx = val.x - x;
00061             double dy = val.y - y;
00062             return (len = uround(sqrt(dx * dx + dy * dy))) > 
00063                    (line_subpixel_scale + line_subpixel_scale / 2);
00064         }
00065     };
00066 
00067 
00068     //----------------------------------------------------------outline_aa_join_e
00069     enum outline_aa_join_e
00070     {
00071         outline_no_join,             //-----outline_no_join
00072         outline_miter_join,          //-----outline_miter_join
00073         outline_round_join,          //-----outline_round_join
00074         outline_miter_accurate_join  //-----outline_accurate_join
00075     };
00076 
00077     //=======================================================rasterizer_outline_aa
00078     template<class Renderer, class Coord=line_coord> class rasterizer_outline_aa
00079     {
00080     private:
00081         //------------------------------------------------------------------------
00082         struct draw_vars
00083         {
00084             unsigned idx;
00085             int x1, y1, x2, y2;
00086             line_parameters curr, next;
00087             int lcurr, lnext;
00088             int xb1, yb1, xb2, yb2;
00089             unsigned flags;
00090         };
00091 
00092         void draw(draw_vars& dv, unsigned start, unsigned end);
00093 
00094     public:
00095         typedef line_aa_vertex                  vertex_type;
00096         typedef vertex_sequence<vertex_type, 6> vertex_storage_type;
00097 
00098         explicit rasterizer_outline_aa(Renderer& ren) : 
00099             m_ren(&ren), 
00100             m_line_join(ren.accurate_join_only() ? 
00101                             outline_miter_accurate_join : 
00102                             outline_round_join),
00103             m_round_cap(false),
00104             m_start_x(0),
00105             m_start_y(0)
00106         {}
00107         void attach(Renderer& ren) { m_ren = &ren; }
00108 
00109         //------------------------------------------------------------------------
00110         void line_join(outline_aa_join_e join) 
00111         { 
00112             m_line_join = m_ren->accurate_join_only() ? 
00113                 outline_miter_accurate_join : 
00114                 join; 
00115         }
00116         bool line_join() const { return m_line_join; }
00117 
00118         //------------------------------------------------------------------------
00119         void round_cap(bool v) { m_round_cap = v; }
00120         bool round_cap() const { return m_round_cap; }
00121 
00122         //------------------------------------------------------------------------
00123         void move_to(int x, int y)
00124         {
00125             m_src_vertices.modify_last(vertex_type(m_start_x = x, m_start_y = y));
00126         }
00127 
00128         //------------------------------------------------------------------------
00129         void line_to(int x, int y)
00130         {
00131             m_src_vertices.add(vertex_type(x, y));
00132         }
00133 
00134         //------------------------------------------------------------------------
00135         void move_to_d(double x, double y)
00136         {
00137             move_to(Coord::conv(x), Coord::conv(y));
00138         }
00139 
00140         //------------------------------------------------------------------------
00141         void line_to_d(double x, double y)
00142         {
00143             line_to(Coord::conv(x), Coord::conv(y));
00144         }
00145 
00146         //------------------------------------------------------------------------
00147         void render(bool close_polygon);
00148 
00149         //------------------------------------------------------------------------
00150         void add_vertex(double x, double y, unsigned cmd)
00151         {
00152             if(is_move_to(cmd)) 
00153             {
00154                 render(false);
00155                 move_to_d(x, y);
00156             }
00157             else 
00158             {
00159                 if(is_end_poly(cmd))
00160                 {
00161                     render(is_closed(cmd));
00162                     if(is_closed(cmd)) 
00163                     {
00164                         move_to(m_start_x, m_start_y);
00165                     }
00166                 }
00167                 else
00168                 {
00169                     line_to_d(x, y);
00170                 }
00171             }
00172         }
00173 
00174         //------------------------------------------------------------------------
00175         template<class VertexSource>
00176         void add_path(VertexSource& vs, unsigned path_id=0)
00177         {
00178             double x;
00179             double y;
00180 
00181             unsigned cmd;
00182             vs.rewind(path_id);
00183             while(!is_stop(cmd = vs.vertex(&x, &y)))
00184             {
00185                 add_vertex(x, y, cmd);
00186             }
00187             render(false);
00188         }
00189 
00190 
00191         //------------------------------------------------------------------------
00192         template<class VertexSource, class ColorStorage, class PathId>
00193         void render_all_paths(VertexSource& vs, 
00194                               const ColorStorage& colors, 
00195                               const PathId& path_id,
00196                               unsigned num_paths)
00197         {
00198             for(unsigned i = 0; i < num_paths; i++)
00199             {
00200                 m_ren->color(colors[i]);
00201                 add_path(vs, path_id[i]);
00202             }
00203         }
00204 
00205 
00206         //------------------------------------------------------------------------
00207         template<class Ctrl> void render_ctrl(Ctrl& c)
00208         {
00209             unsigned i;
00210             for(i = 0; i < c.num_paths(); i++)
00211             {
00212                 m_ren->color(c.color(i));
00213                 add_path(c, i);
00214             }
00215         }
00216 
00217     private:
00218         rasterizer_outline_aa(const rasterizer_outline_aa<Renderer, Coord>&);
00219         const rasterizer_outline_aa<Renderer, Coord>& operator = 
00220             (const rasterizer_outline_aa<Renderer, Coord>&);
00221 
00222         Renderer*           m_ren;
00223         vertex_storage_type m_src_vertices;
00224         outline_aa_join_e   m_line_join;
00225         bool                m_round_cap;
00226         int                 m_start_x;
00227         int                 m_start_y;
00228     };
00229 
00230 
00231 
00232 
00233 
00234 
00235 
00236 
00237     //----------------------------------------------------------------------------
00238     template<class Renderer, class Coord> 
00239     void rasterizer_outline_aa<Renderer, Coord>::draw(draw_vars& dv, 
00240                                                       unsigned start, 
00241                                                       unsigned end)
00242     {
00243         unsigned i;
00244         const vertex_storage_type::value_type* v;
00245 
00246         for(i = start; i < end; i++)
00247         {
00248             if(m_line_join == outline_round_join)
00249             {
00250                 dv.xb1 = dv.curr.x1 + (dv.curr.y2 - dv.curr.y1); 
00251                 dv.yb1 = dv.curr.y1 - (dv.curr.x2 - dv.curr.x1); 
00252                 dv.xb2 = dv.curr.x2 + (dv.curr.y2 - dv.curr.y1); 
00253                 dv.yb2 = dv.curr.y2 - (dv.curr.x2 - dv.curr.x1);
00254             }
00255 
00256             switch(dv.flags)
00257             {
00258             case 0: m_ren->line3(dv.curr, dv.xb1, dv.yb1, dv.xb2, dv.yb2); break;
00259             case 1: m_ren->line2(dv.curr, dv.xb2, dv.yb2); break;
00260             case 2: m_ren->line1(dv.curr, dv.xb1, dv.yb1); break;
00261             case 3: m_ren->line0(dv.curr); break;
00262             }
00263 
00264             if(m_line_join == outline_round_join && (dv.flags & 2) == 0)
00265             {
00266                 m_ren->pie(dv.curr.x2, dv.curr.y2, 
00267                            dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
00268                            dv.curr.y2 - (dv.curr.x2 - dv.curr.x1),
00269                            dv.curr.x2 + (dv.next.y2 - dv.next.y1),
00270                            dv.curr.y2 - (dv.next.x2 - dv.next.x1));
00271             }
00272 
00273             dv.x1 = dv.x2;
00274             dv.y1 = dv.y2;
00275             dv.lcurr = dv.lnext;
00276             dv.lnext = m_src_vertices[dv.idx].len;
00277 
00278             ++dv.idx;
00279             if(dv.idx >= m_src_vertices.size()) dv.idx = 0; 
00280 
00281             v = &m_src_vertices[dv.idx];
00282             dv.x2 = v->x;
00283             dv.y2 = v->y;
00284 
00285             dv.curr = dv.next;
00286             dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
00287             dv.xb1 = dv.xb2;
00288             dv.yb1 = dv.yb2;
00289 
00290             switch(m_line_join)
00291             {
00292             case outline_no_join:
00293                 dv.flags = 3;
00294                 break;
00295 
00296             case outline_miter_join:
00297                 dv.flags >>= 1;
00298                 dv.flags |= ((dv.curr.diagonal_quadrant() == 
00299                               dv.next.diagonal_quadrant()) << 1);
00300                 if((dv.flags & 2) == 0)
00301                 {
00302                     bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2);
00303                 }
00304                 break;
00305 
00306             case outline_round_join:
00307                 dv.flags >>= 1;
00308                 dv.flags |= ((dv.curr.diagonal_quadrant() == 
00309                               dv.next.diagonal_quadrant()) << 1);
00310                 break;
00311 
00312             case outline_miter_accurate_join:
00313                 dv.flags = 0;
00314                 bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2);
00315                 break;
00316             }
00317         }
00318     }
00319 
00320 
00321 
00322 
00323     //----------------------------------------------------------------------------
00324     template<class Renderer, class Coord> 
00325     void rasterizer_outline_aa<Renderer, Coord>::render(bool close_polygon)
00326     {
00327         m_src_vertices.close(close_polygon);
00328         draw_vars dv;
00329         const vertex_storage_type::value_type* v;
00330         int x1;
00331         int y1;
00332         int x2;
00333         int y2;
00334         int lprev;
00335 
00336         if(close_polygon)
00337         {
00338             if(m_src_vertices.size() >= 3)
00339             {
00340                 dv.idx = 2;
00341 
00342                 v     = &m_src_vertices[m_src_vertices.size() - 1];
00343                 x1    = v->x;
00344                 y1    = v->y;
00345                 lprev = v->len;
00346 
00347                 v  = &m_src_vertices[0];
00348                 x2 = v->x;
00349                 y2 = v->y;
00350                 dv.lcurr = v->len;
00351                 line_parameters prev(x1, y1, x2, y2, lprev);
00352 
00353                 v = &m_src_vertices[1];
00354                 dv.x1    = v->x;
00355                 dv.y1    = v->y;
00356                 dv.lnext = v->len;
00357                 dv.curr = line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr);
00358 
00359                 v = &m_src_vertices[dv.idx];
00360                 dv.x2 = v->x;
00361                 dv.y2 = v->y;
00362                 dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
00363 
00364                 dv.xb1 = 0;
00365                 dv.yb1 = 0;
00366                 dv.xb2 = 0;
00367                 dv.yb2 = 0;
00368 
00369                 switch(m_line_join)
00370                 {
00371                 case outline_no_join:
00372                     dv.flags = 3;
00373                     break;
00374 
00375                 case outline_miter_join:
00376                 case outline_round_join:
00377                     dv.flags = 
00378                             (prev.diagonal_quadrant() == dv.curr.diagonal_quadrant()) |
00379                         ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1);
00380                     break;
00381 
00382                 case outline_miter_accurate_join:
00383                     dv.flags = 0;
00384                     break;
00385                 }
00386 
00387                 if((dv.flags & 1) == 0 && m_line_join != outline_round_join)
00388                 {
00389                     bisectrix(prev, dv.curr, &dv.xb1, &dv.yb1);
00390                 }
00391 
00392                 if((dv.flags & 2) == 0 && m_line_join != outline_round_join)
00393                 {
00394                     bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2);
00395                 }
00396                 draw(dv, 0, m_src_vertices.size());
00397             }
00398         }
00399         else
00400         {
00401             switch(m_src_vertices.size())
00402             {
00403                 case 0:
00404                 case 1:
00405                     break;
00406 
00407                 case 2:
00408                 {
00409                     v     = &m_src_vertices[0];
00410                     x1    = v->x;
00411                     y1    = v->y;
00412                     lprev = v->len;
00413                     v     = &m_src_vertices[1];
00414                     x2    = v->x;
00415                     y2    = v->y;
00416                     line_parameters lp(x1, y1, x2, y2, lprev);
00417                     if(m_round_cap) 
00418                     {
00419                         m_ren->semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1));
00420                     }
00421                     m_ren->line3(lp, 
00422                                  x1 + (y2 - y1), 
00423                                  y1 - (x2 - x1),
00424                                  x2 + (y2 - y1), 
00425                                  y2 - (x2 - x1));
00426                     if(m_round_cap) 
00427                     {
00428                         m_ren->semidot(cmp_dist_end, x2, y2, x2 + (y2 - y1), y2 - (x2 - x1));
00429                     }
00430                 }
00431                 break;
00432 
00433                 case 3:
00434                 {
00435                     int x3, y3;
00436                     int lnext;
00437                     v     = &m_src_vertices[0];
00438                     x1    = v->x;
00439                     y1    = v->y;
00440                     lprev = v->len;
00441                     v     = &m_src_vertices[1];
00442                     x2    = v->x;
00443                     y2    = v->y;
00444                     lnext = v->len;
00445                     v     = &m_src_vertices[2];
00446                     x3    = v->x;
00447                     y3    = v->y;
00448                     line_parameters lp1(x1, y1, x2, y2, lprev);
00449                     line_parameters lp2(x2, y2, x3, y3, lnext);
00450 
00451                     if(m_round_cap) 
00452                     {
00453                         m_ren->semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1));
00454                     }
00455 
00456                     if(m_line_join == outline_round_join)
00457                     {
00458                         m_ren->line3(lp1, x1 + (y2 - y1), y1 - (x2 - x1), 
00459                                           x2 + (y2 - y1), y2 - (x2 - x1));
00460 
00461                         m_ren->pie(x2, y2, x2 + (y2 - y1), y2 - (x2 - x1),
00462                                            x2 + (y3 - y2), y2 - (x3 - x2));
00463 
00464                         m_ren->line3(lp2, x2 + (y3 - y2), y2 - (x3 - x2),
00465                                           x3 + (y3 - y2), y3 - (x3 - x2));
00466                     }
00467                     else
00468                     {
00469                         bisectrix(lp1, lp2, &dv.xb1, &dv.yb1);
00470                         m_ren->line3(lp1, x1 + (y2 - y1), y1 - (x2 - x1),
00471                                           dv.xb1,         dv.yb1);
00472 
00473                         m_ren->line3(lp2, dv.xb1,         dv.yb1,
00474                                           x3 + (y3 - y2), y3 - (x3 - x2));
00475                     }
00476                     if(m_round_cap) 
00477                     {
00478                         m_ren->semidot(cmp_dist_end, x3, y3, x3 + (y3 - y2), y3 - (x3 - x2));
00479                     }
00480                 }
00481                 break;
00482 
00483                 default:
00484                 {
00485                     dv.idx = 3;
00486 
00487                     v     = &m_src_vertices[0];
00488                     x1    = v->x;
00489                     y1    = v->y;
00490                     lprev = v->len;
00491 
00492                     v  = &m_src_vertices[1];
00493                     x2 = v->x;
00494                     y2 = v->y;
00495                     dv.lcurr = v->len;
00496                     line_parameters prev(x1, y1, x2, y2, lprev);
00497 
00498                     v = &m_src_vertices[2];
00499                     dv.x1    = v->x;
00500                     dv.y1    = v->y;
00501                     dv.lnext = v->len;
00502                     dv.curr = line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr);
00503 
00504                     v = &m_src_vertices[dv.idx];
00505                     dv.x2 = v->x;
00506                     dv.y2 = v->y;
00507                     dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
00508 
00509                     dv.xb1 = 0;
00510                     dv.yb1 = 0;
00511                     dv.xb2 = 0;
00512                     dv.yb2 = 0;
00513 
00514                     switch(m_line_join)
00515                     {
00516                     case outline_no_join:
00517                         dv.flags = 3;
00518                         break;
00519 
00520                     case outline_miter_join:
00521                     case outline_round_join:
00522                         dv.flags = 
00523                                 (prev.diagonal_quadrant() == dv.curr.diagonal_quadrant()) |
00524                             ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1);
00525                         break;
00526 
00527                     case outline_miter_accurate_join:
00528                         dv.flags = 0;
00529                         break;
00530                     }
00531 
00532                     if(m_round_cap) 
00533                     {
00534                         m_ren->semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1));
00535                     }
00536                     if((dv.flags & 1) == 0)
00537                     {
00538                         if(m_line_join == outline_round_join)
00539                         {
00540                             m_ren->line3(prev, x1 + (y2 - y1), y1 - (x2 - x1),
00541                                                x2 + (y2 - y1), y2 - (x2 - x1));
00542                             m_ren->pie(prev.x2, prev.y2, 
00543                                        x2 + (y2 - y1), y2 - (x2 - x1),
00544                                        dv.curr.x1 + (dv.curr.y2 - dv.curr.y1), 
00545                                        dv.curr.y1 - (dv.curr.x2 - dv.curr.x1));
00546                         }
00547                         else
00548                         {
00549                             bisectrix(prev, dv.curr, &dv.xb1, &dv.yb1);
00550                             m_ren->line3(prev, x1 + (y2 - y1), y1 - (x2 - x1),
00551                                                dv.xb1,         dv.yb1);
00552                         }
00553                     }
00554                     else
00555                     {
00556                         m_ren->line1(prev, 
00557                                      x1 + (y2 - y1), 
00558                                      y1 - (x2 - x1));
00559                     }
00560                     if((dv.flags & 2) == 0 && m_line_join != outline_round_join)
00561                     {
00562                         bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2);
00563                     }
00564 
00565                     draw(dv, 1, m_src_vertices.size() - 2);
00566 
00567                     if((dv.flags & 1) == 0)
00568                     {
00569                         if(m_line_join == outline_round_join)
00570                         {
00571                             m_ren->line3(dv.curr, 
00572                                          dv.curr.x1 + (dv.curr.y2 - dv.curr.y1), 
00573                                          dv.curr.y1 - (dv.curr.x2 - dv.curr.x1),
00574                                          dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), 
00575                                          dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
00576                         }
00577                         else
00578                         {
00579                             m_ren->line3(dv.curr, dv.xb1, dv.yb1,
00580                                          dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), 
00581                                          dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
00582                         }
00583                     }
00584                     else
00585                     {
00586                         m_ren->line2(dv.curr, 
00587                                      dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), 
00588                                      dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
00589                     }
00590                     if(m_round_cap) 
00591                     {
00592                         m_ren->semidot(cmp_dist_end, dv.curr.x2, dv.curr.y2,
00593                                        dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
00594                                        dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
00595                     }
00596 
00597                 }
00598                 break;
00599             }
00600         }
00601         m_src_vertices.remove_all();
00602     }
00603 
00604 
00605 }
00606 
00607 
00608 #endif
00609 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines