John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 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" |
Lei Zhang | 0b36f36 | 2020-10-02 23:45:07 +0000 | [diff] [blame] | 24 | namespace pdfium |
| 25 | { |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 26 | namespace agg |
| 27 | { |
| 28 | enum line_cap_e { |
| 29 | butt_cap, |
| 30 | square_cap, |
| 31 | round_cap |
| 32 | }; |
| 33 | enum line_join_e { |
| 34 | miter_join = 0, |
| 35 | miter_join_revert = 1, |
| 36 | miter_join_round = 4, |
| 37 | round_join = 2, |
| 38 | bevel_join = 3 |
| 39 | }; |
| 40 | enum inner_join_e { |
| 41 | inner_bevel, |
| 42 | inner_miter, |
| 43 | inner_jag, |
| 44 | inner_round |
| 45 | }; |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 46 | const float stroke_theta = 1.0f / 1000.0f; |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 47 | template<class VertexConsumer> |
| 48 | void stroke_calc_arc(VertexConsumer& out_vertices, |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 49 | float x, float y, |
| 50 | float dx1, float dy1, |
| 51 | float dx2, float dy2, |
| 52 | float width, |
| 53 | float approximation_scale) |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 54 | { |
| 55 | typedef typename VertexConsumer::value_type coord_type; |
Dan Sinclair | 669a418 | 2017-04-03 14:51:45 -0400 | [diff] [blame] | 56 | float a1 = atan2(dy1, dx1); |
| 57 | float a2 = atan2(dy2, dx2); |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 58 | float da = a1 - a2; |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 59 | bool ccw = da > 0 && da < FX_PI; |
| 60 | if(width < 0) { |
| 61 | width = -width; |
| 62 | } |
Dan Sinclair | 669a418 | 2017-04-03 14:51:45 -0400 | [diff] [blame] | 63 | da = acos(width / (width + ((1.0f / 8) / approximation_scale))) * 2; |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 64 | out_vertices.add(coord_type(x + dx1, y + dy1)); |
thestig | 8833342 | 2016-04-06 23:57:31 -0700 | [diff] [blame] | 65 | if (da > 0) { |
| 66 | if (!ccw) { |
| 67 | if (a1 > a2) { |
| 68 | a2 += 2 * FX_PI; |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 69 | } |
| 70 | a2 -= da / 4; |
| 71 | a1 += da; |
thestig | 8833342 | 2016-04-06 23:57:31 -0700 | [diff] [blame] | 72 | while (a1 < a2) { |
Dan Sinclair | 669a418 | 2017-04-03 14:51:45 -0400 | [diff] [blame] | 73 | out_vertices.add( |
| 74 | coord_type(x + (width * cos(a1)), y + (width * sin(a1)))); |
thestig | 8833342 | 2016-04-06 23:57:31 -0700 | [diff] [blame] | 75 | a1 += da; |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 76 | } |
thestig | 8833342 | 2016-04-06 23:57:31 -0700 | [diff] [blame] | 77 | } else { |
| 78 | if (a1 < a2) { |
| 79 | a2 -= 2 * FX_PI; |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 80 | } |
| 81 | a2 += da / 4; |
| 82 | a1 -= da; |
thestig | 8833342 | 2016-04-06 23:57:31 -0700 | [diff] [blame] | 83 | while (a1 > a2) { |
Dan Sinclair | 669a418 | 2017-04-03 14:51:45 -0400 | [diff] [blame] | 84 | out_vertices.add( |
| 85 | coord_type(x + (width * cos(a1)), y + (width * sin(a1)))); |
thestig | 8833342 | 2016-04-06 23:57:31 -0700 | [diff] [blame] | 86 | a1 -= da; |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 87 | } |
thestig | 8833342 | 2016-04-06 23:57:31 -0700 | [diff] [blame] | 88 | } |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 89 | } |
| 90 | out_vertices.add(coord_type(x + dx2, y + dy2)); |
| 91 | } |
| 92 | template<class VertexConsumer> |
| 93 | void stroke_calc_miter(VertexConsumer& out_vertices, |
| 94 | const vertex_dist& v0, |
| 95 | const vertex_dist& v1, |
| 96 | const vertex_dist& v2, |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 97 | float dx1, float dy1, |
| 98 | float dx2, float dy2, |
| 99 | float width, |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 100 | line_join_e line_join, |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 101 | float miter_limit, |
| 102 | float approximation_scale) |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 103 | { |
| 104 | typedef typename VertexConsumer::value_type coord_type; |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 105 | float xi = v1.x; |
| 106 | float yi = v1.y; |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 107 | bool miter_limit_exceeded = true; |
| 108 | if(calc_intersection(v0.x + dx1, v0.y - dy1, |
| 109 | v1.x + dx1, v1.y - dy1, |
| 110 | v1.x + dx2, v1.y - dy2, |
| 111 | v2.x + dx2, v2.y - dy2, |
| 112 | &xi, &yi)) { |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 113 | float d1 = calc_distance(v1.x, v1.y, xi, yi); |
| 114 | float lim = width * miter_limit; |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 115 | if(d1 <= lim) { |
| 116 | out_vertices.add(coord_type(xi, yi)); |
| 117 | miter_limit_exceeded = false; |
| 118 | } |
| 119 | } else { |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 120 | float x2 = v1.x + dx1; |
| 121 | float y2 = v1.y - dy1; |
Dan Sinclair | 2c8fad4 | 2016-02-23 15:23:29 -0500 | [diff] [blame] | 122 | if ((((x2 - v0.x) * dy1) - ((v0.y - y2) * dx1) < 0) != |
| 123 | (((x2 - v2.x) * dy1) - ((v2.y - y2) * dx1) < 0)) { |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 124 | out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1)); |
| 125 | miter_limit_exceeded = false; |
| 126 | } |
| 127 | } |
| 128 | if(miter_limit_exceeded) { |
| 129 | switch(line_join) { |
| 130 | case miter_join_revert: |
| 131 | out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1)); |
| 132 | out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2)); |
| 133 | break; |
| 134 | case miter_join_round: |
| 135 | stroke_calc_arc(out_vertices, |
| 136 | v1.x, v1.y, dx1, -dy1, dx2, -dy2, |
| 137 | width, approximation_scale); |
| 138 | break; |
| 139 | default: |
Dan Sinclair | 2c8fad4 | 2016-02-23 15:23:29 -0500 | [diff] [blame] | 140 | out_vertices.add(coord_type(v1.x + dx1 + (dy1 * miter_limit), |
| 141 | v1.y - dy1 + (dx1 * miter_limit))); |
| 142 | out_vertices.add(coord_type(v1.x + dx2 - (dy2 * miter_limit), |
| 143 | v1.y - dy2 - (dx2 * miter_limit))); |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 144 | break; |
| 145 | } |
| 146 | } |
| 147 | } |
| 148 | template<class VertexConsumer> |
| 149 | void stroke_calc_cap(VertexConsumer& out_vertices, |
| 150 | const vertex_dist& v0, |
| 151 | const vertex_dist& v1, |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 152 | float len, |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 153 | line_cap_e line_cap, |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 154 | float width, |
| 155 | float approximation_scale) |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 156 | { |
| 157 | typedef typename VertexConsumer::value_type coord_type; |
| 158 | out_vertices.remove_all(); |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 159 | float dx1 = (v1.y - v0.y) / len; |
| 160 | float dy1 = (v1.x - v0.x) / len; |
| 161 | float dx2 = 0; |
| 162 | float dy2 = 0; |
Dan Sinclair | 2c8fad4 | 2016-02-23 15:23:29 -0500 | [diff] [blame] | 163 | dx1 = dx1 * width; |
| 164 | dy1 = dy1 * width; |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 165 | if(line_cap != round_cap) { |
| 166 | if(line_cap == square_cap) { |
| 167 | dx2 = dy1; |
| 168 | dy2 = dx1; |
| 169 | } |
| 170 | out_vertices.add(coord_type(v0.x - dx1 - dx2, v0.y + dy1 - dy2)); |
| 171 | out_vertices.add(coord_type(v0.x + dx1 - dx2, v0.y - dy1 - dy2)); |
| 172 | } else { |
Dan Sinclair | 669a418 | 2017-04-03 14:51:45 -0400 | [diff] [blame] | 173 | float a1 = atan2(dy1, -dx1); |
| 174 | float a2 = a1 + FX_PI; |
| 175 | float da = acos(width / (width + ((1.0f / 8) / approximation_scale))) * 2; |
Tom Sepez | a3806cb | 2021-01-12 00:44:50 +0000 | [diff] [blame] | 176 | if (da < stroke_theta) { |
| 177 | da = stroke_theta; |
| 178 | } |
Dan Sinclair | 669a418 | 2017-04-03 14:51:45 -0400 | [diff] [blame] | 179 | out_vertices.add(coord_type(v0.x - dx1, v0.y + dy1)); |
| 180 | a1 += da; |
| 181 | a2 -= da / 4; |
| 182 | while (a1 < a2) { |
| 183 | out_vertices.add( |
| 184 | coord_type(v0.x + (width * cos(a1)), v0.y + (width * sin(a1)))); |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 185 | a1 += da; |
Tom Sepez | a3806cb | 2021-01-12 00:44:50 +0000 | [diff] [blame] | 186 | } |
| 187 | out_vertices.add(coord_type(v0.x + dx1, v0.y - dy1)); |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 188 | } |
| 189 | } |
| 190 | template<class VertexConsumer> |
| 191 | void stroke_calc_join(VertexConsumer& out_vertices, |
| 192 | const vertex_dist& v0, |
| 193 | const vertex_dist& v1, |
| 194 | const vertex_dist& v2, |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 195 | float len1, |
| 196 | float len2, |
| 197 | float width, |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 198 | line_join_e line_join, |
| 199 | inner_join_e inner_join, |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 200 | float miter_limit, |
| 201 | float inner_miter_limit, |
| 202 | float approximation_scale) |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 203 | { |
| 204 | typedef typename VertexConsumer::value_type coord_type; |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 205 | float dx1, dy1, dx2, dy2; |
Dan Sinclair | 435604d | 2016-02-23 16:31:44 -0500 | [diff] [blame] | 206 | dx1 = width * (v1.y - v0.y) / len1; |
| 207 | dy1 = width * (v1.x - v0.x) / len1; |
| 208 | dx2 = width * (v2.y - v1.y) / len2; |
| 209 | dy2 = width * (v2.x - v1.x) / len2; |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 210 | out_vertices.remove_all(); |
| 211 | if(calc_point_location(v0.x, v0.y, v1.x, v1.y, v2.x, v2.y) > 0) { |
| 212 | switch(inner_join) { |
| 213 | default: |
| 214 | out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1)); |
| 215 | out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2)); |
| 216 | break; |
| 217 | case inner_miter: |
| 218 | stroke_calc_miter(out_vertices, |
| 219 | v0, v1, v2, dx1, dy1, dx2, dy2, |
| 220 | width, |
| 221 | miter_join_revert, |
| 222 | inner_miter_limit, |
| 223 | 1.0f); |
| 224 | break; |
| 225 | case inner_jag: |
| 226 | case inner_round: { |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 227 | float d = (dx1 - dx2) * (dx1 - dx2) + (dy1 - dy2) * (dy1 - dy2); |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 228 | if(d < len1 * len1 && d < len2 * len2) { |
| 229 | stroke_calc_miter(out_vertices, |
| 230 | v0, v1, v2, dx1, dy1, dx2, dy2, |
| 231 | width, |
| 232 | miter_join_revert, |
| 233 | inner_miter_limit, |
| 234 | 1.0f); |
| 235 | } else { |
| 236 | if(inner_join == inner_jag) { |
| 237 | out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1)); |
| 238 | out_vertices.add(coord_type(v1.x, v1.y )); |
| 239 | out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2)); |
| 240 | } else { |
| 241 | out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1)); |
| 242 | out_vertices.add(coord_type(v1.x, v1.y )); |
| 243 | stroke_calc_arc(out_vertices, |
| 244 | v1.x, v1.y, dx2, -dy2, dx1, -dy1, |
| 245 | width, approximation_scale); |
| 246 | out_vertices.add(coord_type(v1.x, v1.y )); |
| 247 | out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2)); |
| 248 | } |
| 249 | } |
| 250 | } |
| 251 | break; |
| 252 | } |
| 253 | } else { |
| 254 | switch(line_join) { |
| 255 | case miter_join: |
| 256 | case miter_join_revert: |
| 257 | case miter_join_round: |
| 258 | stroke_calc_miter(out_vertices, |
| 259 | v0, v1, v2, dx1, dy1, dx2, dy2, |
| 260 | width, |
| 261 | line_join, |
| 262 | miter_limit, |
| 263 | approximation_scale); |
| 264 | break; |
| 265 | case round_join: |
| 266 | stroke_calc_arc(out_vertices, |
| 267 | v1.x, v1.y, dx1, -dy1, dx2, -dy2, |
| 268 | width, approximation_scale); |
| 269 | break; |
| 270 | default: |
| 271 | out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1)); |
| 272 | out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2)); |
| 273 | break; |
| 274 | } |
| 275 | } |
| 276 | } |
| 277 | } |
Lei Zhang | 0b36f36 | 2020-10-02 23:45:07 +0000 | [diff] [blame] | 278 | } // namespace pdfium |
John Abd-El-Malek | 5110c47 | 2014-05-17 22:33:34 -0700 | [diff] [blame] | 279 | #endif |