1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.3
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
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.
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 // mcseemagg@yahoo.com
13 // http://www.antigrain.com
14 //----------------------------------------------------------------------------
18 //----------------------------------------------------------------------------
20 #ifndef AGG_STROKE_MATH_INCLUDED
21 #define AGG_STROKE_MATH_INCLUDED
24 #include "agg_vertex_sequence.h"
28 //-------------------------------------------------------------line_cap_e
36 //------------------------------------------------------------line_join_e
45 // Minimal angle to calculate round joins, less than 0.1 degree.
46 const double stroke_theta
= 0.001; //----stroke_theta
49 //--------------------------------------------------------stroke_calc_arc
50 template<class VertexConsumer
>
51 void stroke_calc_arc(VertexConsumer
& out_vertices
,
53 double dx1
, double dy1
,
54 double dx2
, double dy2
,
56 double approximation_scale
)
58 typedef typename
VertexConsumer::value_type coord_type
;
60 //// Check if we actually need the arc (this optimization works bad)
62 //double dd = calc_distance(dx1, dy1, dx2, dy2);
63 //if(dd < 1.0/approximation_scale)
65 // out_vertices.add(coord_type(x + dx1, y + dy1));
66 // if(dd > 0.25/approximation_scale)
68 // out_vertices.add(coord_type(x + dx2, y + dy2));
73 double a1
= atan2(dy1
, dx1
);
74 double a2
= atan2(dy2
, dx2
);
77 if(fabs(da
) < stroke_theta
)
79 out_vertices
.add(coord_type((x
+ x
+ dx1
+ dx2
) * 0.5,
80 (y
+ y
+ dy1
+ dy2
) * 0.5));
84 bool ccw
= da
> 0.0 && da
< pi
;
86 if(width
< 0) width
= -width
;
87 da
= fabs(1.0 / (width
* approximation_scale
));
90 if(a1
> a2
) a2
+= 2 * pi
;
93 out_vertices
.add(coord_type(x
+ cos(a1
) * width
, y
+ sin(a1
) * width
));
99 if(a1
< a2
) a2
-= 2 * pi
;
102 out_vertices
.add(coord_type(x
+ cos(a1
) * width
, y
+ sin(a1
) * width
));
106 out_vertices
.add(coord_type(x
+ dx2
, y
+ dy2
));
111 //-------------------------------------------------------stroke_calc_miter
112 template<class VertexConsumer
>
113 void stroke_calc_miter(VertexConsumer
& out_vertices
,
114 const vertex_dist
& v0
,
115 const vertex_dist
& v1
,
116 const vertex_dist
& v2
,
117 double dx1
, double dy1
,
118 double dx2
, double dy2
,
123 typedef typename
VertexConsumer::value_type coord_type
;
128 if(!calc_intersection(v0
.x
+ dx1
, v0
.y
- dy1
,
129 v1
.x
+ dx1
, v1
.y
- dy1
,
130 v1
.x
+ dx2
, v1
.y
- dy2
,
131 v2
.x
+ dx2
, v2
.y
- dy2
,
134 // The calculation didn't succeed, most probaly
135 // the three points lie one straight line
137 if(calc_distance(dx1
, -dy1
, dx2
, -dy2
) < width
* 0.025)
139 // This case means that the next segment continues
140 // the previous one (straight line)
142 out_vertices
.add(coord_type(v1
.x
+ dx1
, v1
.y
- dy1
));
146 // This case means that the next segment goes back
150 out_vertices
.add(coord_type(v1
.x
+ dx1
, v1
.y
- dy1
));
151 out_vertices
.add(coord_type(v1
.x
+ dx2
, v1
.y
- dy2
));
155 // If no miter-revert, calcuate new dx1, dy1, dx2, dy2
156 out_vertices
.add(coord_type(v1
.x
+ dx1
+ dy1
* miter_limit
,
157 v1
.y
- dy1
+ dx1
* miter_limit
));
158 out_vertices
.add(coord_type(v1
.x
+ dx2
- dy2
* miter_limit
,
159 v1
.y
- dy2
- dx2
* miter_limit
));
165 double d1
= calc_distance(v1
.x
, v1
.y
, xi
, yi
);
166 double lim
= width
* miter_limit
;
169 // Miter limit exceeded
170 //------------------------
173 // For the compatibility with SVG, PDF, etc,
174 // we use a simple bevel join instead of
176 //-------------------
177 out_vertices
.add(coord_type(v1
.x
+ dx1
, v1
.y
- dy1
));
178 out_vertices
.add(coord_type(v1
.x
+ dx2
, v1
.y
- dy2
));
182 // Smart bevel that cuts the miter at the limit point
183 //-------------------
185 double x1
= v1
.x
+ dx1
;
186 double y1
= v1
.y
- dy1
;
187 double x2
= v1
.x
+ dx2
;
188 double y2
= v1
.y
- dy2
;
190 x1
+= (xi
- x1
) * d1
;
191 y1
+= (yi
- y1
) * d1
;
192 x2
+= (xi
- x2
) * d1
;
193 y2
+= (yi
- y2
) * d1
;
194 out_vertices
.add(coord_type(x1
, y1
));
195 out_vertices
.add(coord_type(x2
, y2
));
200 // Inside the miter limit
201 //---------------------
202 out_vertices
.add(coord_type(xi
, yi
));
212 //--------------------------------------------------------stroke_calc_cap
213 template<class VertexConsumer
>
214 void stroke_calc_cap(VertexConsumer
& out_vertices
,
215 const vertex_dist
& v0
,
216 const vertex_dist
& v1
,
220 double approximation_scale
)
222 typedef typename
VertexConsumer::value_type coord_type
;
224 out_vertices
.remove_all();
226 double dx1
= width
* (v1
.y
- v0
.y
) / len
;
227 double dy1
= width
* (v1
.x
- v0
.x
) / len
;
231 if(line_cap
== square_cap
)
237 if(line_cap
== round_cap
)
239 double a1
= atan2(dy1
, -dx1
);
241 double da
= fabs(1.0 / (width
* approximation_scale
));
244 out_vertices
.add(coord_type(v0
.x
+ cos(a1
) * width
,
245 v0
.y
+ sin(a1
) * width
));
248 out_vertices
.add(coord_type(v0
.x
+ dx1
, v0
.y
- dy1
));
252 out_vertices
.add(coord_type(v0
.x
- dx1
- dx2
, v0
.y
+ dy1
- dy2
));
253 out_vertices
.add(coord_type(v0
.x
+ dx1
- dx2
, v0
.y
- dy1
- dy2
));
259 //-------------------------------------------------------stroke_calc_join
260 template<class VertexConsumer
>
261 void stroke_calc_join(VertexConsumer
& out_vertices
,
262 const vertex_dist
& v0
,
263 const vertex_dist
& v1
,
264 const vertex_dist
& v2
,
268 line_join_e line_join
,
269 line_join_e inner_line_join
,
271 double inner_miter_limit
,
272 double approximation_scale
)
274 typedef typename
VertexConsumer::value_type coord_type
;
276 double dx1
, dy1
, dx2
, dy2
;
278 dx1
= width
* (v1
.y
- v0
.y
) / len1
;
279 dy1
= width
* (v1
.x
- v0
.x
) / len1
;
281 dx2
= width
* (v2
.y
- v1
.y
) / len2
;
282 dy2
= width
* (v2
.x
- v1
.x
) / len2
;
284 out_vertices
.remove_all();
286 if(calc_point_location(v0
.x
, v0
.y
, v1
.x
, v1
.y
, v2
.x
, v2
.y
) > 0.0)
290 stroke_calc_miter(out_vertices
,
291 v0
, v1
, v2
, dx1
, dy1
, dx2
, dy2
,
293 inner_line_join
== miter_join_revert
,
303 stroke_calc_miter(out_vertices
,
304 v0
, v1
, v2
, dx1
, dy1
, dx2
, dy2
,
310 case miter_join_revert
:
311 stroke_calc_miter(out_vertices
,
312 v0
, v1
, v2
, dx1
, dy1
, dx2
, dy2
,
319 stroke_calc_arc(out_vertices
,
320 v1
.x
, v1
.y
, dx1
, -dy1
, dx2
, -dy2
,
321 width
, approximation_scale
);
324 default: // Bevel join
325 out_vertices
.add(coord_type(v1
.x
+ dx1
, v1
.y
- dy1
));
326 if(calc_distance(dx1
, dy1
, dx2
, dy2
) > approximation_scale
* 0.25)
328 out_vertices
.add(coord_type(v1
.x
+ dx2
, v1
.y
- dy2
));