Home | History | Annotate | Download | only in agg23
      1 
      2 //----------------------------------------------------------------------------
      3 // XYQ: 2006-01-22 Copied from AGG project.
      4 // TODO: This file uses intensive floating point operations, so it's NOT suitable
      5 // for platforms like Symbian OS. We need to change to FIX format.
      6 //----------------------------------------------------------------------------
      7 //----------------------------------------------------------------------------
      8 // Anti-Grain Geometry - Version 2.3
      9 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
     10 //
     11 // Permission to copy, use, modify, sell and distribute this software
     12 // is granted provided this copyright notice appears in all copies.
     13 // This software is provided "as is" without express or implied
     14 // warranty, and with no claim as to its suitability for any purpose.
     15 //
     16 //----------------------------------------------------------------------------
     17 // Contact: mcseem (at) antigrain.com
     18 //          mcseemagg (at) yahoo.com
     19 //          http://www.antigrain.com
     20 //----------------------------------------------------------------------------
     21 //
     22 // Stroke generator
     23 //
     24 //----------------------------------------------------------------------------
     25 
     26 #include "agg_vcgen_stroke.h"
     27 #include "core/include/fxcrt/fx_basic.h"
     28 
     29 namespace agg
     30 {
     31 
     32 vcgen_stroke::vcgen_stroke() :
     33     m_src_vertices(),
     34     m_out_vertices(),
     35     m_width(0.5f),
     36     m_miter_limit(4 * 1.0f),
     37     m_inner_miter_limit(1.0f + 1.0f / 100),
     38     m_approx_scale(1.0f),
     39     m_line_cap(butt_cap),
     40     m_line_join(miter_join),
     41     m_inner_join(inner_miter),
     42     m_closed(0),
     43     m_status(initial),
     44     m_src_vertex(0),
     45     m_out_vertex(0)
     46 {
     47 }
     48 void vcgen_stroke::remove_all()
     49 {
     50     m_src_vertices.remove_all();
     51     m_closed = 0;
     52     m_status = initial;
     53 }
     54 void vcgen_stroke::add_vertex(FX_FLOAT x, FX_FLOAT y, unsigned cmd)
     55 {
     56     m_status = initial;
     57     if(is_move_to(cmd)) {
     58         m_src_vertices.modify_last(vertex_dist_cmd(x, y, cmd));
     59     } else {
     60         if(is_vertex(cmd)) {
     61             m_src_vertices.add(vertex_dist_cmd(x, y, cmd));
     62         } else {
     63             m_closed = get_close_flag(cmd);
     64         }
     65     }
     66 }
     67 static inline void calc_butt_cap(FX_FLOAT* cap,
     68                                  const vertex_dist& v0,
     69                                  const vertex_dist& v1,
     70                                  FX_FLOAT len,
     71                                  FX_FLOAT width)
     72 {
     73     FX_FLOAT dx = FXSYS_MulDiv(v1.y - v0.y, width, len);
     74     FX_FLOAT dy = FXSYS_MulDiv(v1.x - v0.x, width, len);
     75     cap[0] = v0.x - dx;
     76     cap[1] = v0.y + dy;
     77     cap[2] = v0.x + dx;
     78     cap[3] = v0.y - dy;
     79 }
     80 void vcgen_stroke::rewind(unsigned)
     81 {
     82     if(m_status == initial) {
     83         m_src_vertices.close(m_closed != 0);
     84         if(m_src_vertices.size() < 3) {
     85             m_closed = 0;
     86         }
     87     }
     88     m_status = ready;
     89     m_src_vertex = 0;
     90     m_out_vertex = 0;
     91 }
     92 unsigned vcgen_stroke::vertex(FX_FLOAT* x, FX_FLOAT* y)
     93 {
     94     unsigned cmd = path_cmd_line_to;
     95     line_join_e curj;
     96     while(!is_stop(cmd)) {
     97         switch(m_status) {
     98             case initial:
     99                 rewind(0);
    100             case ready:
    101                 if(m_src_vertices.size() < 2 + unsigned(m_closed != 0)) {
    102                     cmd = path_cmd_stop;
    103                     break;
    104                 }
    105                 m_status = m_closed ? outline1 : cap1;
    106                 cmd = path_cmd_move_to;
    107                 m_src_vertex = 0;
    108                 m_out_vertex = 0;
    109                 break;
    110             case cap1:
    111                 stroke_calc_cap(m_out_vertices,
    112                                 m_src_vertices[0],
    113                                 m_src_vertices[1],
    114                                 m_src_vertices[0].dist,
    115                                 m_line_cap,
    116                                 m_width,
    117                                 m_approx_scale);
    118                 m_src_vertex = 1;
    119                 m_prev_status = outline1;
    120                 m_status = out_vertices;
    121                 m_out_vertex = 0;
    122                 break;
    123             case cap2:
    124                 stroke_calc_cap(m_out_vertices,
    125                                 m_src_vertices[m_src_vertices.size() - 1],
    126                                 m_src_vertices[m_src_vertices.size() - 2],
    127                                 m_src_vertices[m_src_vertices.size() - 2].dist,
    128                                 m_line_cap,
    129                                 m_width,
    130                                 m_approx_scale);
    131                 m_prev_status = outline2;
    132                 m_status = out_vertices;
    133                 m_out_vertex = 0;
    134                 break;
    135             case outline1:
    136                 if(m_closed) {
    137                     if(m_src_vertex >= m_src_vertices.size()) {
    138                         m_prev_status = close_first;
    139                         m_status = end_poly1;
    140                         break;
    141                     }
    142                 } else {
    143                     if(m_src_vertex >= m_src_vertices.size() - 1) {
    144                         m_status = cap2;
    145                         break;
    146                     }
    147                 }
    148                 curj = m_src_vertices[m_src_vertex].cmd & path_flags_jr ? miter_join_round : m_line_join;
    149                 stroke_calc_join(m_out_vertices,
    150                                  m_src_vertices.prev(m_src_vertex),
    151                                  m_src_vertices.curr(m_src_vertex),
    152                                  m_src_vertices.next(m_src_vertex),
    153                                  m_src_vertices.prev(m_src_vertex).dist,
    154                                  m_src_vertices.curr(m_src_vertex).dist,
    155                                  m_width,
    156                                  curj,
    157                                  m_inner_join,
    158                                  m_miter_limit,
    159                                  m_inner_miter_limit,
    160                                  m_approx_scale);
    161                 ++m_src_vertex;
    162                 m_prev_status = m_status;
    163                 m_status = out_vertices;
    164                 m_out_vertex = 0;
    165                 break;
    166             case close_first:
    167                 m_status = outline2;
    168                 cmd = path_cmd_move_to;
    169             case outline2:
    170                 if(m_src_vertex <= unsigned(m_closed == 0)) {
    171                     m_status = end_poly2;
    172                     m_prev_status = stop;
    173                     break;
    174                 }
    175                 --m_src_vertex;
    176                 curj = m_src_vertices[m_src_vertex].cmd & path_flags_jr ? miter_join_round : m_line_join;
    177                 stroke_calc_join(m_out_vertices,
    178                                  m_src_vertices.next(m_src_vertex),
    179                                  m_src_vertices.curr(m_src_vertex),
    180                                  m_src_vertices.prev(m_src_vertex),
    181                                  m_src_vertices.curr(m_src_vertex).dist,
    182                                  m_src_vertices.prev(m_src_vertex).dist,
    183                                  m_width,
    184                                  curj,
    185                                  m_inner_join,
    186                                  m_miter_limit,
    187                                  m_inner_miter_limit,
    188                                  m_approx_scale);
    189                 m_prev_status = m_status;
    190                 m_status = out_vertices;
    191                 m_out_vertex = 0;
    192                 break;
    193             case out_vertices:
    194                 if(m_out_vertex >= m_out_vertices.size()) {
    195                     m_status = m_prev_status;
    196                 } else {
    197                     const point_type& c = m_out_vertices[m_out_vertex++];
    198                     *x = c.x;
    199                     *y = c.y;
    200                     return cmd;
    201                 }
    202                 break;
    203             case end_poly1:
    204                 m_status = m_prev_status;
    205                 return path_cmd_end_poly | path_flags_close | path_flags_ccw;
    206             case end_poly2:
    207                 m_status = m_prev_status;
    208                 return path_cmd_end_poly | path_flags_close | path_flags_cw;
    209             case stop:
    210                 cmd = path_cmd_stop;
    211                 break;
    212         }
    213     }
    214     return cmd;
    215 }
    216 }
    217