| OLD | NEW |
| (Empty) |
| 1 | |
| 2 //---------------------------------------------------------------------------- | |
| 3 // Anti-Grain Geometry - Version 2.3 | |
| 4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) | |
| 5 // | |
| 6 // Permission to copy, use, modify, sell and distribute this software | |
| 7 // is granted provided this copyright notice appears in all copies. | |
| 8 // This software is provided "as is" without express or implied | |
| 9 // warranty, and with no claim as to its suitability for any purpose. | |
| 10 // | |
| 11 //---------------------------------------------------------------------------- | |
| 12 // Contact: mcseem@antigrain.com | |
| 13 // mcseemagg@yahoo.com | |
| 14 // http://www.antigrain.com | |
| 15 //---------------------------------------------------------------------------- | |
| 16 // | |
| 17 // Stroke math | |
| 18 // | |
| 19 //---------------------------------------------------------------------------- | |
| 20 #ifndef AGG_STROKE_MATH_INCLUDED | |
| 21 #define AGG_STROKE_MATH_INCLUDED | |
| 22 #include "agg_math.h" | |
| 23 #include "agg_vertex_sequence.h" | |
| 24 namespace agg | |
| 25 { | |
| 26 enum line_cap_e { | |
| 27 butt_cap, | |
| 28 square_cap, | |
| 29 round_cap | |
| 30 }; | |
| 31 enum line_join_e { | |
| 32 miter_join = 0, | |
| 33 miter_join_revert = 1, | |
| 34 miter_join_round = 4, | |
| 35 round_join = 2, | |
| 36 bevel_join = 3 | |
| 37 }; | |
| 38 enum inner_join_e { | |
| 39 inner_bevel, | |
| 40 inner_miter, | |
| 41 inner_jag, | |
| 42 inner_round | |
| 43 }; | |
| 44 const FX_FLOAT stroke_theta = 1.0f / 1000.0f; | |
| 45 template<class VertexConsumer> | |
| 46 void stroke_calc_arc(VertexConsumer& out_vertices, | |
| 47 FX_FLOAT x, FX_FLOAT y, | |
| 48 FX_FLOAT dx1, FX_FLOAT dy1, | |
| 49 FX_FLOAT dx2, FX_FLOAT dy2, | |
| 50 FX_FLOAT width, | |
| 51 FX_FLOAT approximation_scale) | |
| 52 { | |
| 53 typedef typename VertexConsumer::value_type coord_type; | |
| 54 FX_FLOAT a1 = FXSYS_atan2(dy1, dx1); | |
| 55 FX_FLOAT a2 = FXSYS_atan2(dy2, dx2); | |
| 56 FX_FLOAT da = a1 - a2; | |
| 57 bool ccw = da > 0 && da < FX_PI; | |
| 58 if(width < 0) { | |
| 59 width = -width; | |
| 60 } | |
| 61 da = FXSYS_acos(FXSYS_Div(width, width + FXSYS_Div(1.0f / 8, approximation_s
cale))) * 2; | |
| 62 out_vertices.add(coord_type(x + dx1, y + dy1)); | |
| 63 if(!ccw) { | |
| 64 if(a1 > a2) { | |
| 65 a2 += 2 * FX_PI; | |
| 66 } | |
| 67 a2 -= da / 4; | |
| 68 a1 += da; | |
| 69 while(a1 < a2) { | |
| 70 out_vertices.add(coord_type(x + FXSYS_Mul(width, FXSYS_cos(a1)), | |
| 71 y + FXSYS_Mul(width, FXSYS_sin(a1)))); | |
| 72 a1 += da; | |
| 73 } | |
| 74 } else { | |
| 75 if(a1 < a2) { | |
| 76 a2 -= 2 * FX_PI; | |
| 77 } | |
| 78 a2 += da / 4; | |
| 79 a1 -= da; | |
| 80 while(a1 > a2) { | |
| 81 out_vertices.add(coord_type(x + FXSYS_Mul(width, FXSYS_cos(a1)), | |
| 82 y + FXSYS_Mul(width, FXSYS_sin(a1)))); | |
| 83 a1 -= da; | |
| 84 } | |
| 85 } | |
| 86 out_vertices.add(coord_type(x + dx2, y + dy2)); | |
| 87 } | |
| 88 template<class VertexConsumer> | |
| 89 void stroke_calc_miter(VertexConsumer& out_vertices, | |
| 90 const vertex_dist& v0, | |
| 91 const vertex_dist& v1, | |
| 92 const vertex_dist& v2, | |
| 93 FX_FLOAT dx1, FX_FLOAT dy1, | |
| 94 FX_FLOAT dx2, FX_FLOAT dy2, | |
| 95 FX_FLOAT width, | |
| 96 line_join_e line_join, | |
| 97 FX_FLOAT miter_limit, | |
| 98 FX_FLOAT approximation_scale) | |
| 99 { | |
| 100 typedef typename VertexConsumer::value_type coord_type; | |
| 101 FX_FLOAT xi = v1.x; | |
| 102 FX_FLOAT yi = v1.y; | |
| 103 bool miter_limit_exceeded = true; | |
| 104 if(calc_intersection(v0.x + dx1, v0.y - dy1, | |
| 105 v1.x + dx1, v1.y - dy1, | |
| 106 v1.x + dx2, v1.y - dy2, | |
| 107 v2.x + dx2, v2.y - dy2, | |
| 108 &xi, &yi)) { | |
| 109 FX_FLOAT d1 = calc_distance(v1.x, v1.y, xi, yi); | |
| 110 FX_FLOAT lim = FXSYS_Mul(width, miter_limit); | |
| 111 if(d1 <= lim) { | |
| 112 out_vertices.add(coord_type(xi, yi)); | |
| 113 miter_limit_exceeded = false; | |
| 114 } | |
| 115 } else { | |
| 116 FX_FLOAT x2 = v1.x + dx1; | |
| 117 FX_FLOAT y2 = v1.y - dy1; | |
| 118 if((FXSYS_Mul(x2 - v0.x, dy1) - FXSYS_Mul(v0.y - y2, dx1) < 0) != | |
| 119 (FXSYS_Mul(x2 - v2.x, dy1) - FXSYS_Mul(v2.y - y2, dx1) < 0)) { | |
| 120 out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1)); | |
| 121 miter_limit_exceeded = false; | |
| 122 } | |
| 123 } | |
| 124 if(miter_limit_exceeded) { | |
| 125 switch(line_join) { | |
| 126 case miter_join_revert: | |
| 127 out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1)); | |
| 128 out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2)); | |
| 129 break; | |
| 130 case miter_join_round: | |
| 131 stroke_calc_arc(out_vertices, | |
| 132 v1.x, v1.y, dx1, -dy1, dx2, -dy2, | |
| 133 width, approximation_scale); | |
| 134 break; | |
| 135 default: | |
| 136 out_vertices.add(coord_type(v1.x + dx1 + FXSYS_Mul(dy1, miter_li
mit), | |
| 137 v1.y - dy1 + FXSYS_Mul(dx1, miter_li
mit))); | |
| 138 out_vertices.add(coord_type(v1.x + dx2 - FXSYS_Mul(dy2, miter_li
mit), | |
| 139 v1.y - dy2 - FXSYS_Mul(dx2, miter_li
mit))); | |
| 140 break; | |
| 141 } | |
| 142 } | |
| 143 } | |
| 144 template<class VertexConsumer> | |
| 145 void stroke_calc_cap(VertexConsumer& out_vertices, | |
| 146 const vertex_dist& v0, | |
| 147 const vertex_dist& v1, | |
| 148 FX_FLOAT len, | |
| 149 line_cap_e line_cap, | |
| 150 FX_FLOAT width, | |
| 151 FX_FLOAT approximation_scale) | |
| 152 { | |
| 153 typedef typename VertexConsumer::value_type coord_type; | |
| 154 out_vertices.remove_all(); | |
| 155 FX_FLOAT dx1 = FXSYS_Div(v1.y - v0.y, len); | |
| 156 FX_FLOAT dy1 = FXSYS_Div(v1.x - v0.x, len); | |
| 157 FX_FLOAT dx2 = 0; | |
| 158 FX_FLOAT dy2 = 0; | |
| 159 dx1 = FXSYS_Mul(dx1, width); | |
| 160 dy1 = FXSYS_Mul(dy1, width); | |
| 161 if(line_cap != round_cap) { | |
| 162 if(line_cap == square_cap) { | |
| 163 dx2 = dy1; | |
| 164 dy2 = dx1; | |
| 165 } | |
| 166 out_vertices.add(coord_type(v0.x - dx1 - dx2, v0.y + dy1 - dy2)); | |
| 167 out_vertices.add(coord_type(v0.x + dx1 - dx2, v0.y - dy1 - dy2)); | |
| 168 } else { | |
| 169 FX_FLOAT a1 = FXSYS_atan2(dy1, -dx1); | |
| 170 FX_FLOAT a2 = a1 + FX_PI; | |
| 171 FX_FLOAT da = FXSYS_acos(FXSYS_Div(width, width + | |
| 172 FXSYS_Div(1.0f / 8, approximation_sca
le))) * 2; | |
| 173 out_vertices.add(coord_type(v0.x - dx1, v0.y + dy1)); | |
| 174 a1 += da; | |
| 175 a2 -= da / 4; | |
| 176 while(a1 < a2) { | |
| 177 out_vertices.add(coord_type(v0.x + FXSYS_Mul(width, FXSYS_cos(a1)), | |
| 178 v0.y + FXSYS_Mul(width, FXSYS_sin(a1))))
; | |
| 179 a1 += da; | |
| 180 } | |
| 181 out_vertices.add(coord_type(v0.x + dx1, v0.y - dy1)); | |
| 182 } | |
| 183 } | |
| 184 template<class VertexConsumer> | |
| 185 void stroke_calc_join(VertexConsumer& out_vertices, | |
| 186 const vertex_dist& v0, | |
| 187 const vertex_dist& v1, | |
| 188 const vertex_dist& v2, | |
| 189 FX_FLOAT len1, | |
| 190 FX_FLOAT len2, | |
| 191 FX_FLOAT width, | |
| 192 line_join_e line_join, | |
| 193 inner_join_e inner_join, | |
| 194 FX_FLOAT miter_limit, | |
| 195 FX_FLOAT inner_miter_limit, | |
| 196 FX_FLOAT approximation_scale) | |
| 197 { | |
| 198 typedef typename VertexConsumer::value_type coord_type; | |
| 199 FX_FLOAT dx1, dy1, dx2, dy2; | |
| 200 dx1 = FXSYS_MulDiv(width, v1.y - v0.y, len1); | |
| 201 dy1 = FXSYS_MulDiv(width, v1.x - v0.x, len1); | |
| 202 dx2 = FXSYS_MulDiv(width, v2.y - v1.y, len2); | |
| 203 dy2 = FXSYS_MulDiv(width, v2.x - v1.x, len2); | |
| 204 out_vertices.remove_all(); | |
| 205 if(calc_point_location(v0.x, v0.y, v1.x, v1.y, v2.x, v2.y) > 0) { | |
| 206 switch(inner_join) { | |
| 207 default: | |
| 208 out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1)); | |
| 209 out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2)); | |
| 210 break; | |
| 211 case inner_miter: | |
| 212 stroke_calc_miter(out_vertices, | |
| 213 v0, v1, v2, dx1, dy1, dx2, dy2, | |
| 214 width, | |
| 215 miter_join_revert, | |
| 216 inner_miter_limit, | |
| 217 1.0f); | |
| 218 break; | |
| 219 case inner_jag: | |
| 220 case inner_round: { | |
| 221 FX_FLOAT d = (dx1 - dx2) * (dx1 - dx2) + (dy1 - dy2) * (dy1
- dy2); | |
| 222 if(d < len1 * len1 && d < len2 * len2) { | |
| 223 stroke_calc_miter(out_vertices, | |
| 224 v0, v1, v2, dx1, dy1, dx2, dy2, | |
| 225 width, | |
| 226 miter_join_revert, | |
| 227 inner_miter_limit, | |
| 228 1.0f); | |
| 229 } else { | |
| 230 if(inner_join == inner_jag) { | |
| 231 out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1))
; | |
| 232 out_vertices.add(coord_type(v1.x, v1.y ))
; | |
| 233 out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2))
; | |
| 234 } else { | |
| 235 out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1))
; | |
| 236 out_vertices.add(coord_type(v1.x, v1.y ))
; | |
| 237 stroke_calc_arc(out_vertices, | |
| 238 v1.x, v1.y, dx2, -dy2, dx1, -dy1, | |
| 239 width, approximation_scale); | |
| 240 out_vertices.add(coord_type(v1.x, v1.y ))
; | |
| 241 out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2))
; | |
| 242 } | |
| 243 } | |
| 244 } | |
| 245 break; | |
| 246 } | |
| 247 } else { | |
| 248 switch(line_join) { | |
| 249 case miter_join: | |
| 250 case miter_join_revert: | |
| 251 case miter_join_round: | |
| 252 stroke_calc_miter(out_vertices, | |
| 253 v0, v1, v2, dx1, dy1, dx2, dy2, | |
| 254 width, | |
| 255 line_join, | |
| 256 miter_limit, | |
| 257 approximation_scale); | |
| 258 break; | |
| 259 case round_join: | |
| 260 stroke_calc_arc(out_vertices, | |
| 261 v1.x, v1.y, dx1, -dy1, dx2, -dy2, | |
| 262 width, approximation_scale); | |
| 263 break; | |
| 264 default: | |
| 265 out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1)); | |
| 266 out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2)); | |
| 267 break; | |
| 268 } | |
| 269 } | |
| 270 } | |
| 271 } | |
| 272 #endif | |
| OLD | NEW |