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 // 16 // Stroke generator 17 // 18 //---------------------------------------------------------------------------- 19 #include <math.h> 20 #include "agg_vcgen_stroke.h" 21 #include "agg_shorten_path.h" 22 23 namespace agg 24 { 25 26 //------------------------------------------------------------------------ 27 vcgen_stroke::vcgen_stroke() : 28 m_src_vertices(), 29 m_out_vertices(), 30 m_width(0.5), 31 m_miter_limit(4.0), 32 m_inner_miter_limit(1.0 + 1.0/64.0), 33 m_approx_scale(1.0), 34 m_shorten(0.0), 35 m_line_cap(butt_cap), 36 m_line_join(miter_join), 37 m_inner_line_join(miter_join_revert), 38 m_closed(0), 39 m_status(initial), 40 m_src_vertex(0), 41 m_out_vertex(0) 42 { 43 } 44 45 46 //------------------------------------------------------------------------ 47 void vcgen_stroke::miter_limit_theta(double t) 48 { 49 m_miter_limit = 1.0 / sin(t * 0.5) ; 50 } 51 52 53 //------------------------------------------------------------------------ 54 void vcgen_stroke::remove_all() 55 { 56 m_src_vertices.remove_all(); 57 m_closed = 0; 58 m_status = initial; 59 } 60 61 62 //------------------------------------------------------------------------ 63 void vcgen_stroke::add_vertex(double x, double y, unsigned cmd) 64 { 65 m_status = initial; 66 if(is_move_to(cmd)) 67 { 68 m_src_vertices.modify_last(vertex_dist(x, y)); 69 } 70 else 71 { 72 if(is_vertex(cmd)) 73 { 74 m_src_vertices.add(vertex_dist(x, y)); 75 } 76 else 77 { 78 m_closed = get_close_flag(cmd); 79 } 80 } 81 } 82 83 84 //------------------------------------------------------------------------ 85 void vcgen_stroke::rewind(unsigned) 86 { 87 if(m_status == initial) 88 { 89 m_src_vertices.close(m_closed != 0); 90 shorten_path(m_src_vertices, m_shorten, m_closed); 91 if(m_src_vertices.size() < 3) m_closed = 0; 92 } 93 m_status = ready; 94 m_src_vertex = 0; 95 m_out_vertex = 0; 96 } 97 98 99 //------------------------------------------------------------------------ 100 unsigned vcgen_stroke::vertex(double* x, double* y) 101 { 102 unsigned cmd = path_cmd_line_to; 103 while(!is_stop(cmd)) 104 { 105 switch(m_status) 106 { 107 case initial: 108 rewind(0); 109 110 case ready: 111 if(m_src_vertices.size() < 2 + unsigned(m_closed != 0)) 112 { 113 cmd = path_cmd_stop; 114 break; 115 } 116 m_status = m_closed ? outline1 : cap1; 117 cmd = path_cmd_move_to; 118 m_src_vertex = 0; 119 m_out_vertex = 0; 120 break; 121 122 case cap1: 123 stroke_calc_cap(m_out_vertices, 124 m_src_vertices[0], 125 m_src_vertices[1], 126 m_src_vertices[0].dist, 127 m_line_cap, 128 m_width, 129 m_approx_scale); 130 m_src_vertex = 1; 131 m_prev_status = outline1; 132 m_status = out_vertices; 133 m_out_vertex = 0; 134 break; 135 136 case cap2: 137 stroke_calc_cap(m_out_vertices, 138 m_src_vertices[m_src_vertices.size() - 1], 139 m_src_vertices[m_src_vertices.size() - 2], 140 m_src_vertices[m_src_vertices.size() - 2].dist, 141 m_line_cap, 142 m_width, 143 m_approx_scale); 144 m_prev_status = outline2; 145 m_status = out_vertices; 146 m_out_vertex = 0; 147 break; 148 149 case outline1: 150 if(m_closed) 151 { 152 if(m_src_vertex >= m_src_vertices.size()) 153 { 154 m_prev_status = close_first; 155 m_status = end_poly1; 156 break; 157 } 158 } 159 else 160 { 161 if(m_src_vertex >= m_src_vertices.size() - 1) 162 { 163 m_status = cap2; 164 break; 165 } 166 } 167 stroke_calc_join(m_out_vertices, 168 m_src_vertices.prev(m_src_vertex), 169 m_src_vertices.curr(m_src_vertex), 170 m_src_vertices.next(m_src_vertex), 171 m_src_vertices.prev(m_src_vertex).dist, 172 m_src_vertices.curr(m_src_vertex).dist, 173 m_width, 174 m_line_join, 175 m_inner_line_join, 176 m_miter_limit, 177 m_inner_miter_limit, 178 m_approx_scale); 179 ++m_src_vertex; 180 m_prev_status = m_status; 181 m_status = out_vertices; 182 m_out_vertex = 0; 183 break; 184 185 case close_first: 186 m_status = outline2; 187 cmd = path_cmd_move_to; 188 189 case outline2: 190 if(m_src_vertex <= unsigned(m_closed == 0)) 191 { 192 m_status = end_poly2; 193 m_prev_status = stop; 194 break; 195 } 196 197 --m_src_vertex; 198 stroke_calc_join(m_out_vertices, 199 m_src_vertices.next(m_src_vertex), 200 m_src_vertices.curr(m_src_vertex), 201 m_src_vertices.prev(m_src_vertex), 202 m_src_vertices.curr(m_src_vertex).dist, 203 m_src_vertices.prev(m_src_vertex).dist, 204 m_width, 205 m_line_join, 206 m_inner_line_join, 207 m_miter_limit, 208 m_inner_miter_limit, 209 m_approx_scale); 210 211 m_prev_status = m_status; 212 m_status = out_vertices; 213 m_out_vertex = 0; 214 break; 215 216 case out_vertices: 217 if(m_out_vertex >= m_out_vertices.size()) 218 { 219 m_status = m_prev_status; 220 } 221 else 222 { 223 const point_type& c = m_out_vertices[m_out_vertex++]; 224 *x = c.x; 225 *y = c.y; 226 return cmd; 227 } 228 break; 229 230 case end_poly1: 231 m_status = m_prev_status; 232 return path_cmd_end_poly | path_flags_close | path_flags_ccw; 233 234 case end_poly2: 235 m_status = m_prev_status; 236 return path_cmd_end_poly | path_flags_close | path_flags_cw; 237 238 case stop: 239 cmd = path_cmd_stop; 240 break; 241 } 242 } 243 return cmd; 244 } 245 246 } 247