LEFT | RIGHT |
1 /* | 1 /* |
2 This file is part of LilyPond, the GNU music typesetter. | 2 This file is part of LilyPond, the GNU music typesetter. |
3 | 3 |
4 Copyright (C) 2012 Mike Solomon <mike@apollinemike.com> | 4 Copyright (C) 2012 Mike Solomon <mike@apollinemike.com> |
5 | 5 |
6 LilyPond is free software: you can redistribute it and/or modify | 6 LilyPond is free software: you can redistribute it and/or modify |
7 it under the terms of the GNU General Public License as published by | 7 it under the terms of the GNU General Public License as published by |
8 the Free Software Foundation, either version 3 of the License, or | 8 the Free Software Foundation, either version 3 of the License, or |
9 (at your option) any later version. | 9 (at your option) any later version. |
10 | 10 |
(...skipping 22 matching lines...) Expand all Loading... |
33 [ 1 ] | 33 [ 1 ] |
34 */ | 34 */ |
35 | 35 |
36 #include <pango/pango-matrix.h> | 36 #include <pango/pango-matrix.h> |
37 #include <complex> | 37 #include <complex> |
38 #include "box.hh" | 38 #include "box.hh" |
39 #include "bezier.hh" | 39 #include "bezier.hh" |
40 #include "font-metric.hh" | 40 #include "font-metric.hh" |
41 #include "grob.hh" | 41 #include "grob.hh" |
42 #include "interval.hh" | 42 #include "interval.hh" |
| 43 #include "freetype.hh" |
| 44 #include "misc.hh" |
43 #include "offset.hh" | 45 #include "offset.hh" |
| 46 #include "modified-font-metric.hh" |
| 47 #include "open-type-font.hh" |
| 48 #include "pango-font.hh" |
44 #include "pointer-group-interface.hh" | 49 #include "pointer-group-interface.hh" |
45 #include "lily-guile.hh" | 50 #include "lily-guile.hh" |
46 #include "real.hh" | 51 #include "real.hh" |
47 #include "stencil.hh" | 52 #include "stencil.hh" |
48 #include "string-convert.hh" | 53 #include "string-convert.hh" |
| 54 #include "skyline.hh" |
49 #include "skyline-pair.hh" | 55 #include "skyline-pair.hh" |
50 using namespace std; | 56 using namespace std; |
51 | 57 |
52 Real CURVE_QUANTIZATION = 10; | 58 Real QUANTIZATION_UNIT = 0.2; |
53 | 59 |
54 Real ELLIPSE_QUANTIZATION = 20; | 60 void create_path_cap (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings
, PangoMatrix trans, Offset pt, Real rad, Real slope, Direction d); |
55 | 61 |
56 | 62 struct Transform_matrix_and_expression |
57 struct Translate_scale_rotate { | 63 { |
58 Offset translate_; | |
59 Offset scale_; | |
60 Real rotate_; | |
61 }; | |
62 | |
63 Translate_scale_rotate | |
64 make_translate_scale_rotate (Offset translate, Offset scale, Real rotate) | |
65 { | |
66 Translate_scale_rotate out; | |
67 out.translate_ = translate; | |
68 out.scale_ = scale; | |
69 out.rotate_ = rotate; | |
70 return out; | |
71 } | |
72 | |
73 struct Transform_matrix_and_expression { | |
74 PangoMatrix tm_; | 64 PangoMatrix tm_; |
75 SCM expr_; | 65 SCM expr_; |
76 | 66 |
77 Transform_matrix_and_expression (PangoMatrix tm, SCM expr); | 67 Transform_matrix_and_expression (PangoMatrix tm, SCM expr); |
78 }; | 68 }; |
79 | |
80 | 69 |
81 Transform_matrix_and_expression::Transform_matrix_and_expression (PangoMatrix tm
, SCM expr) | 70 Transform_matrix_and_expression::Transform_matrix_and_expression (PangoMatrix tm
, SCM expr) |
82 { | 71 { |
83 tm_ = tm; | 72 tm_ = tm; |
84 expr_ = expr; | 73 expr_ = expr; |
85 } | 74 } |
86 | 75 |
87 PangoMatrix | 76 PangoMatrix |
88 make_transform_matrix (Real p0, Real p1, Real p2, Real p3, Real p4, Real p5) | 77 make_transform_matrix (Real p0, Real p1, Real p2, Real p3, Real p4, Real p5) |
89 { | 78 { |
90 PangoMatrix out; | 79 PangoMatrix out; |
91 out.xx = p0; | 80 out.xx = p0; |
92 out.xy = p1; | 81 out.xy = p1; |
93 out.yx = p2; | 82 out.yx = p2; |
94 out.yy = p3; | 83 out.yy = p3; |
95 out.x0 = p4; | 84 out.x0 = p4; |
96 out.y0 = p5; | 85 out.y0 = p5; |
97 return out; | 86 return out; |
98 } | 87 } |
99 | 88 |
100 /* | |
101 Turns a transform matrix into a translate, scale, and rotate. | |
102 The order is important (rotate first, then scale, then translate). | |
103 */ | |
104 | |
105 Translate_scale_rotate | |
106 to_translate_scale_rotate (PangoMatrix x) | |
107 { | |
108 Real rotate = atan2 (-x.yx, x.xx); | |
109 bool use_sin = cos (rotate) == 0.0; | |
110 | |
111 return make_translate_scale_rotate (Offset (x.x0, x.y0), | |
112 Offset (use_sin ? -x.yx / sin (rotate) : x
.xx / cos (rotate), | |
113 use_sin ? x.xy / sin (rotate) : x.
yy / cos (rotate)), | |
114 rotate); | |
115 } | |
116 | |
117 //// UTILITY FUNCTIONS | 89 //// UTILITY FUNCTIONS |
118 | 90 |
119 /* | 91 /* |
120 map x's placement between orig_l and orig_r onto | 92 map x's placement between orig_l and orig_r onto |
121 the interval final_l final_r | 93 the interval final_l final_r |
122 */ | 94 */ |
123 Real | 95 Real |
124 linear_map (Real final_l, Real final_r, Real orig_l, Real orig_r, Real x) | 96 linear_map (Real final_l, Real final_r, Real orig_l, Real orig_r, Real x) |
125 { | 97 { |
126 return final_l + ((final_r - final_l) * ((x - orig_l) / (orig_r - orig_l))); | 98 return final_l + ((final_r - final_l) * ((x - orig_l) / (orig_r - orig_l))); |
127 } | 99 } |
128 | 100 |
129 /* | 101 /* |
130 from a nested SCM list, return the first list of numbers | 102 from a nested SCM list, return the first list of numbers |
131 useful for polygons | 103 useful for polygons |
132 */ | 104 */ |
133 SCM | 105 SCM |
134 get_number_list (SCM l) | 106 get_number_list (SCM l) |
135 { | 107 { |
136 if (scm_is_pair (l)) | 108 if (scm_is_pair (l)) |
137 { | 109 { |
138 if (scm_is_number (scm_car (l))) | 110 if (scm_is_number (scm_car (l))) |
139 return l; | 111 return l; |
140 SCM res = get_number_list (scm_car (l)); | 112 SCM res = get_number_list (scm_car (l)); |
141 if (res == SCM_BOOL_F) | 113 if (res == SCM_BOOL_F) |
142 return get_number_list (scm_cdr (l)); | 114 return get_number_list (scm_cdr (l)); |
| 115 return res; |
143 } | 116 } |
144 return SCM_BOOL_F; | 117 return SCM_BOOL_F; |
145 } | 118 } |
146 | 119 |
147 /* | 120 /* |
148 from a nested SCM list, return the first list of numbers | 121 from a nested SCM list, return the first list of numbers |
149 useful for paths | 122 useful for paths |
150 */ | 123 */ |
151 SCM | 124 SCM |
152 get_path_list (SCM l) | 125 get_path_list (SCM l) |
(...skipping 12 matching lines...) Expand all Loading... |
165 != SCM_BOOL_F) | 138 != SCM_BOOL_F) |
166 return l; | 139 return l; |
167 SCM res = get_path_list (scm_car (l)); | 140 SCM res = get_path_list (scm_car (l)); |
168 if (res == SCM_BOOL_F) | 141 if (res == SCM_BOOL_F) |
169 return get_path_list (scm_cdr (l)); | 142 return get_path_list (scm_cdr (l)); |
170 return res; | 143 return res; |
171 } | 144 } |
172 return SCM_BOOL_F; | 145 return SCM_BOOL_F; |
173 } | 146 } |
174 | 147 |
| 148 Real |
| 149 perpendicular_slope (Real s) |
| 150 { |
| 151 if (s == 0.0) |
| 152 return infinity_f; |
| 153 if (s == infinity_f) |
| 154 return 0.0; |
| 155 return -1.0 / s; |
| 156 } |
| 157 |
175 //// END UTILITY FUNCTIONS | 158 //// END UTILITY FUNCTIONS |
176 | 159 |
177 /* | 160 /* |
178 below, for all of the functions make_X_boxes, the expression | 161 below, for all of the functions make_X_boxes, the expression |
179 is always unpacked into variables. | 162 is always unpacked into variables. |
180 then, after a line of /////, there are manipulations of these variables | 163 then, after a line of /////, there are manipulations of these variables |
181 (there may be no manipulations necessary depending on the function) | 164 (there may be no manipulations necessary depending on the function) |
182 afterwards, there is another ///// followed by the creation of points | 165 afterwards, there is another ///// followed by the creation of points |
183 and boxes | 166 and boxes |
184 */ | 167 */ |
185 | 168 |
186 vector<Box> | 169 void |
187 make_draw_line_boxes (PangoMatrix trans, SCM expr) | 170 make_draw_line_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings
, PangoMatrix trans, SCM expr, bool use_building) |
188 { | 171 { |
189 vector<Box> boxes; | |
190 Real thick = robust_scm2double (scm_car (expr), 0.0); | 172 Real thick = robust_scm2double (scm_car (expr), 0.0); |
191 expr = scm_cdr (expr); | 173 expr = scm_cdr (expr); |
192 Real x0 = robust_scm2double (scm_car (expr), 0.0); | 174 Real x0 = robust_scm2double (scm_car (expr), 0.0); |
193 expr = scm_cdr (expr); | 175 expr = scm_cdr (expr); |
194 Real y0 = robust_scm2double (scm_car (expr), 0.0); | 176 Real y0 = robust_scm2double (scm_car (expr), 0.0); |
195 expr = scm_cdr (expr); | 177 expr = scm_cdr (expr); |
196 Real x1 = robust_scm2double (scm_car (expr), 0.0); | 178 Real x1 = robust_scm2double (scm_car (expr), 0.0); |
197 expr = scm_cdr (expr); | 179 expr = scm_cdr (expr); |
198 Real y1 = robust_scm2double (scm_car (expr), 0.0); | 180 Real y1 = robust_scm2double (scm_car (expr), 0.0); |
| 181 Real slope = x1 == x0 ? infinity_f : (y1 - y0) / (x1 - x0); |
199 ////////////////////// | 182 ////////////////////// |
200 vector<Offset> points; | 183 if (x1 < x0) |
201 for (vsize i = 0; i < 1 + CURVE_QUANTIZATION; i++) | 184 { |
202 { | 185 swap (x0, x1); |
203 Offset pt (linear_map (x0, x1, 0, CURVE_QUANTIZATION, i), | 186 swap (y0, y1); |
204 linear_map (y0, y1, 0, CURVE_QUANTIZATION, i)); | 187 } |
205 pango_matrix_transform_point (&trans, &pt[X_AXIS], &pt[Y_AXIS]); | 188 Offset left (x0, y0); |
206 points.push_back (pt); | 189 Offset right (x1, y1); |
207 } | 190 Direction d = DOWN; |
208 Translate_scale_rotate tsr = to_translate_scale_rotate (trans); | 191 do |
209 for (vsize i = 0; i < CURVE_QUANTIZATION; i++) | 192 { |
210 { | 193 Offset inter_l = get_point_in_y_direction (left, perpendicular_slope (slop
e), thick / 2, d); |
211 Box b; | 194 Offset inter_r = get_point_in_y_direction (right, perpendicular_slope (slo
pe), thick / 2, d); |
212 b.add_point (points[i]); | 195 pango_matrix_transform_point (&trans, &inter_l[X_AXIS], &inter_l[Y_AXIS]); |
213 b.add_point (points[i + 1]); | 196 pango_matrix_transform_point (&trans, &inter_r[X_AXIS], &inter_r[Y_AXIS]); |
214 b.widen (abs (thick * tsr.scale_[X_AXIS]) / 2, abs (thick * tsr.scale_[Y_A
XIS]) / 2); | 197 if ((inter_l[X_AXIS] == inter_r[X_AXIS]) || (inter_l[Y_AXIS] == inter_r[Y_
AXIS])) |
215 boxes.push_back (b); | 198 { |
216 } | 199 Box b; |
217 return boxes; | 200 b.add_point (inter_l); |
218 } | 201 b.add_point (inter_r); |
219 | 202 boxes.push_back (b); |
220 vector<Box> | 203 } |
221 make_partial_ellipse_boxes (PangoMatrix trans, SCM expr) | 204 else if (use_building) |
222 { | 205 buildings.push_back (Drul_array<Offset> (inter_l, inter_r)); |
223 vector<Box> boxes; | 206 else |
| 207 { |
| 208 Offset inter_l = get_point_in_y_direction (left, perpendicular_slope (
slope), thick / 2, d); |
| 209 Offset inter_r = get_point_in_y_direction (right, perpendicular_slope
(slope), thick / 2, d); |
| 210 pango_matrix_transform_point (&trans, &inter_l[X_AXIS], &inter_l[Y_AXI
S]); |
| 211 pango_matrix_transform_point (&trans, &inter_r[X_AXIS], &inter_r[Y_AXI
S]); |
| 212 Real length = sqrt (((inter_l[X_AXIS] - inter_r[X_AXIS]) * (inter_l[X_
AXIS] - inter_r[X_AXIS])) + ((inter_l[Y_AXIS] - inter_r[Y_AXIS]) * (inter_l[Y_AX
IS] - inter_r[Y_AXIS]))); |
| 213 |
| 214 vsize passes = (vsize) ((length * 2) + 1); |
| 215 vector<Offset> points; |
| 216 |
| 217 for (vsize i = 0; i < 1 + passes; i++) |
| 218 { |
| 219 Offset pt (linear_map (x0, x1, 0, passes, i), |
| 220 linear_map (y0, y1, 0, passes, i)); |
| 221 Offset inter = get_point_in_y_direction (pt, perpendicular_slope (
slope), thick / 2, d); |
| 222 pango_matrix_transform_point (&trans, &inter[X_AXIS], &inter[Y_AXI
S]); |
| 223 points.push_back (inter); |
| 224 } |
| 225 for (vsize i = 0; i < points.size () - 1; i++) |
| 226 { |
| 227 Box b; |
| 228 b.add_point (points[i]); |
| 229 b.add_point (points[i + 1]); |
| 230 boxes.push_back (b); |
| 231 } |
| 232 } |
| 233 } |
| 234 while (flip (&d) != DOWN); |
| 235 |
| 236 if (thick > 0.0) |
| 237 { |
| 238 // beg line cap |
| 239 create_path_cap (boxes, |
| 240 buildings, |
| 241 trans, |
| 242 Offset (x0, y0), |
| 243 thick / 2, |
| 244 perpendicular_slope (slope), |
| 245 Direction (sign (slope))); |
| 246 |
| 247 // end line cap |
| 248 create_path_cap (boxes, |
| 249 buildings, |
| 250 trans, |
| 251 Offset (x1, y1), |
| 252 thick / 2, |
| 253 perpendicular_slope (slope), |
| 254 Direction (sign (-slope))); |
| 255 } |
| 256 } |
| 257 |
| 258 void |
| 259 make_partial_ellipse_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &bui
ldings, PangoMatrix trans, SCM expr) |
| 260 { |
224 Real x_rad = robust_scm2double (scm_car (expr), 0.0); | 261 Real x_rad = robust_scm2double (scm_car (expr), 0.0); |
225 expr = scm_cdr (expr); | 262 expr = scm_cdr (expr); |
226 Real y_rad = robust_scm2double (scm_car (expr), 0.0); | 263 Real y_rad = robust_scm2double (scm_car (expr), 0.0); |
227 expr = scm_cdr (expr); | 264 expr = scm_cdr (expr); |
228 Real start = robust_scm2double (scm_car (expr), 0.0); | 265 Real start = robust_scm2double (scm_car (expr), 0.0); |
229 expr = scm_cdr (expr); | 266 expr = scm_cdr (expr); |
230 Real end = robust_scm2double (scm_car (expr), 0.0); | 267 Real end = robust_scm2double (scm_car (expr), 0.0); |
231 expr = scm_cdr (expr); | 268 expr = scm_cdr (expr); |
232 Real th = robust_scm2double (scm_car (expr), 0.0); | 269 Real th = robust_scm2double (scm_car (expr), 0.0); |
233 expr = scm_cdr (expr); | 270 expr = scm_cdr (expr); |
234 bool connect = to_boolean (scm_car (expr)); | 271 bool connect = to_boolean (scm_car (expr)); |
235 expr = scm_cdr (expr); | 272 expr = scm_cdr (expr); |
236 bool fill = to_boolean (scm_car (expr)); | 273 bool fill = to_boolean (scm_car (expr)); |
237 ////////////////////// | 274 ////////////////////// |
238 start = M_PI * start / 180; | 275 start = M_PI * start / 180; |
239 end = M_PI * end / 180; | 276 end = M_PI * end / 180; |
240 if (end == start) | 277 if (end == start) |
241 end += (2 * M_PI); | 278 end += (2 * M_PI); |
242 complex<Real> sunit = polar (1.0, start); | 279 complex<Real> sunit = polar (1.0, start); |
243 complex<Real> eunit = polar (1.0, end); | 280 complex<Real> eunit = polar (1.0, end); |
244 Offset sp (real (sunit) * x_rad, imag (sunit) * y_rad); | 281 Offset sp (real (sunit) * x_rad, imag (sunit) * y_rad); |
245 Offset ep (real (eunit) * x_rad, imag (eunit) * y_rad); | 282 Offset ep (real (eunit) * x_rad, imag (eunit) * y_rad); |
246 ////////////////////// | 283 ////////////////////// |
247 vector<Offset> points; | 284 Drul_array<vector<Offset> > points; |
248 for (vsize i = 0; i < 1 + ELLIPSE_QUANTIZATION; i++) | 285 Direction d = DOWN; |
249 { | 286 int quantization = max (1, (int) (((x_rad * trans.xx) + (y_rad * trans.yy)) *
M_PI / QUANTIZATION_UNIT)); |
250 Real ang = linear_map (start, end, 0, ELLIPSE_QUANTIZATION, i); | 287 do |
251 complex<Real> coord = polar (1.0, ang); | 288 { |
| 289 for (vsize i = 0; i < 1 + quantization; i++) |
| 290 { |
| 291 Real ang = linear_map (start, end, 0, quantization, i); |
| 292 complex<Real> coord = polar (1.0, ang); |
| 293 Offset pt (real (coord) * x_rad, |
| 294 imag (coord) * y_rad); |
| 295 Real slope = pt[Y_AXIS] / pt[X_AXIS]; |
| 296 Offset inter = get_point_in_y_direction (pt, perpendicular_slope (slop
e), th / 2, d); |
| 297 pango_matrix_transform_point (&trans, &inter[X_AXIS], &inter[Y_AXIS]); |
| 298 points[d].push_back (inter); |
| 299 } |
| 300 } |
| 301 while (flip (&d) != DOWN); |
| 302 |
| 303 for (vsize i = 0; i < points[DOWN].size () - 1; i++) |
| 304 { |
| 305 Box b; |
| 306 do |
| 307 { |
| 308 b.add_point (points[d][i]); |
| 309 b.add_point (points[d][i + 1]); |
| 310 } |
| 311 while (flip (&d) != DOWN); |
| 312 boxes.push_back (b); |
| 313 } |
| 314 |
| 315 if (connect || fill) |
| 316 { |
| 317 make_draw_line_boxes (boxes, buildings, trans, scm_list_5 (scm_from_double
(th), |
| 318 scm_from_double
(sp[X_AXIS]), |
| 319 scm_from_double
(sp[Y_AXIS]), |
| 320 scm_from_double
(ep[X_AXIS]), |
| 321 scm_from_double
(ep[Y_AXIS])), |
| 322 false); |
| 323 } |
| 324 |
| 325 if (th > 0.0) |
| 326 { |
| 327 // beg line cap |
| 328 complex<Real> coord = polar (1.0, start); |
252 Offset pt (real (coord) * x_rad, | 329 Offset pt (real (coord) * x_rad, |
253 imag (coord) * y_rad); | 330 imag (coord) * y_rad); |
254 pango_matrix_transform_point (&trans, &pt[X_AXIS], &pt[Y_AXIS]); | 331 Real slope = pt[Y_AXIS] / pt[X_AXIS]; |
255 points.push_back (pt); | 332 create_path_cap (boxes, |
256 } | 333 buildings, |
257 Translate_scale_rotate tsr = to_translate_scale_rotate (trans); | 334 trans, |
258 for (vsize i = 0; i < ELLIPSE_QUANTIZATION; i++) | 335 pt, |
259 { | 336 th / 2, |
260 Box b; | 337 perpendicular_slope (slope), |
261 b.add_point (points[i]); | 338 Direction (sign (slope))); |
262 b.add_point (points[i + 1]); | 339 |
263 b.widen (abs (th * tsr.scale_[X_AXIS]) / 2, abs (th * tsr.scale_[Y_AXIS])
/ 2); | 340 // end line cap |
264 boxes.push_back (b); | 341 coord = polar (1.0, start); |
265 } | 342 pt = Offset (real (coord) * x_rad, |
266 if (connect || fill) | 343 imag (coord) * y_rad); |
267 { | 344 slope = pt[Y_AXIS] / pt[X_AXIS]; |
268 vector<Box> db = make_draw_line_boxes (trans, scm_list_5(scm_from_double (
th), | 345 create_path_cap (boxes, |
269 scm_from_double (
sp[X_AXIS]), | 346 buildings, |
270 scm_from_double (
sp[Y_AXIS]), | 347 trans, |
271 scm_from_double (
ep[X_AXIS]), | 348 pt, |
272 scm_from_double (
ep[Y_AXIS]))); | 349 th / 2, |
273 boxes.insert (boxes.end (), db.begin (), db.end ()); | 350 perpendicular_slope (slope), |
274 } | 351 Direction (sign (-slope))); |
275 return boxes; | 352 } |
276 } | 353 } |
277 | 354 |
278 vector<Box> | 355 void |
279 make_round_filled_box_boxes (PangoMatrix trans, SCM expr) | 356 make_round_filled_box_boxes (vector<Box> &boxes, PangoMatrix trans, SCM expr) |
280 { | 357 { |
281 vector<Box> boxes; | |
282 Real left = robust_scm2double (scm_car (expr), 0.0); | 358 Real left = robust_scm2double (scm_car (expr), 0.0); |
283 expr = scm_cdr (expr); | 359 expr = scm_cdr (expr); |
284 Real right = robust_scm2double (scm_car (expr), 0.0); | 360 Real right = robust_scm2double (scm_car (expr), 0.0); |
285 expr = scm_cdr (expr); | 361 expr = scm_cdr (expr); |
286 Real bottom = robust_scm2double (scm_car (expr), 0.0); | 362 Real bottom = robust_scm2double (scm_car (expr), 0.0); |
287 expr = scm_cdr (expr); | 363 expr = scm_cdr (expr); |
288 Real top = robust_scm2double (scm_car (expr), 0.0); | 364 Real top = robust_scm2double (scm_car (expr), 0.0); |
289 expr = scm_cdr (expr); | 365 expr = scm_cdr (expr); |
290 Real th = robust_scm2double (scm_car (expr), 0.0); | 366 Real th = robust_scm2double (scm_car (expr), 0.0); |
291 ////////////////////// | 367 ////////////////////// |
292 vector<Offset> points; | 368 vector<Offset> points; |
293 Box b; | 369 Box b; |
294 Offset p0 = Offset (-left, -bottom); | 370 Offset p0 = Offset (-left - (th / 2), -bottom - (th / 2)); |
295 Offset p1 = Offset (right, top); | 371 Offset p1 = Offset (right + (th / 2), top + (th / 2)); |
296 pango_matrix_transform_point (&trans, &p0[X_AXIS], &p0[Y_AXIS]); | 372 pango_matrix_transform_point (&trans, &p0[X_AXIS], &p0[Y_AXIS]); |
297 pango_matrix_transform_point (&trans, &p1[X_AXIS], &p1[Y_AXIS]); | 373 pango_matrix_transform_point (&trans, &p1[X_AXIS], &p1[Y_AXIS]); |
298 b.add_point (p0); | 374 b.add_point (p0); |
299 b.add_point (p1); | 375 b.add_point (p1); |
300 Translate_scale_rotate tsr = to_translate_scale_rotate (trans); | |
301 b.widen (abs (th * tsr.scale_[X_AXIS]) / 2, abs (th * tsr.scale_[Y_AXIS]) / 2)
; | |
302 boxes.push_back (b); | 376 boxes.push_back (b); |
303 return boxes; | 377 } |
304 } | 378 |
305 | 379 void |
306 vector<Box> | 380 create_path_cap (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings, Pan
goMatrix trans, Offset pt, Real rad, Real slope, Direction d) |
307 make_draw_bezier_boxes (PangoMatrix trans, SCM expr) | 381 { |
308 { | 382 Real angle = atan (slope) * 180 / M_PI; |
309 vector<Box> boxes; | 383 Real other = angle > 180 ? angle - 180 : angle + 180; |
| 384 if (angle < other) |
| 385 { |
| 386 Real holder = other; |
| 387 other = angle; |
| 388 angle = holder; |
| 389 } |
| 390 other = (slope >= 0 && d == DOWN) || (slope < 0 && d == UP) |
| 391 ? other + 360.0 |
| 392 : other; |
| 393 PangoMatrix new_trans (trans); |
| 394 pango_matrix_translate (&new_trans, pt[X_AXIS], pt[Y_AXIS]); |
| 395 make_partial_ellipse_boxes (boxes, buildings, new_trans, |
| 396 scm_list_n (scm_from_double (rad), |
| 397 scm_from_double (rad), |
| 398 scm_from_double (angle), |
| 399 scm_from_double (other), |
| 400 scm_from_double (0.0), |
| 401 SCM_BOOL_F, |
| 402 SCM_BOOL_F, |
| 403 SCM_UNDEFINED)); |
| 404 } |
| 405 |
| 406 void |
| 407 make_draw_bezier_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildin
gs, PangoMatrix trans, SCM expr) |
| 408 { |
310 Real th = robust_scm2double (scm_car (expr), 0.0); | 409 Real th = robust_scm2double (scm_car (expr), 0.0); |
311 expr = scm_cdr (expr); | 410 expr = scm_cdr (expr); |
312 Real x0 = robust_scm2double (scm_car (expr), 0.0); | 411 Real x0 = robust_scm2double (scm_car (expr), 0.0); |
313 expr = scm_cdr (expr); | 412 expr = scm_cdr (expr); |
314 Real y0 = robust_scm2double (scm_car (expr), 0.0); | 413 Real y0 = robust_scm2double (scm_car (expr), 0.0); |
315 expr = scm_cdr (expr); | 414 expr = scm_cdr (expr); |
316 Real x1 = robust_scm2double (scm_car (expr), 0.0); | 415 Real x1 = robust_scm2double (scm_car (expr), 0.0); |
317 expr = scm_cdr (expr); | 416 expr = scm_cdr (expr); |
318 Real y1 = robust_scm2double (scm_car (expr), 0.0); | 417 Real y1 = robust_scm2double (scm_car (expr), 0.0); |
319 expr = scm_cdr (expr); | 418 expr = scm_cdr (expr); |
320 Real x2 = robust_scm2double (scm_car (expr), 0.0); | 419 Real x2 = robust_scm2double (scm_car (expr), 0.0); |
321 expr = scm_cdr (expr); | 420 expr = scm_cdr (expr); |
322 Real y2 = robust_scm2double (scm_car (expr), 0.0); | 421 Real y2 = robust_scm2double (scm_car (expr), 0.0); |
323 expr = scm_cdr (expr); | 422 expr = scm_cdr (expr); |
324 Real x3 = robust_scm2double (scm_car (expr), 0.0); | 423 Real x3 = robust_scm2double (scm_car (expr), 0.0); |
325 expr = scm_cdr (expr); | 424 expr = scm_cdr (expr); |
326 Real y3 = robust_scm2double (scm_car (expr), 0.0); | 425 Real y3 = robust_scm2double (scm_car (expr), 0.0); |
327 ////////////////////// | 426 ////////////////////// |
328 Bezier curve; | 427 Bezier curve; |
329 curve.control_[0] = Offset (x0, y0); | 428 curve.control_[0] = Offset (x0, y0); |
330 curve.control_[1] = Offset (x1, y1); | 429 curve.control_[1] = Offset (x1, y1); |
331 curve.control_[2] = Offset (x2, y2); | 430 curve.control_[2] = Offset (x2, y2); |
332 curve.control_[3] = Offset (x3, y3); | 431 curve.control_[3] = Offset (x3, y3); |
333 pango_matrix_transform_point (&trans, &curve.control_[0][X_AXIS], &curve.contr
ol_[0][Y_AXIS]); | 432 Offset temp0 (x0, y0); |
334 pango_matrix_transform_point (&trans, &curve.control_[1][X_AXIS], &curve.contr
ol_[1][Y_AXIS]); | 433 Offset temp1 (x1, y1); |
335 pango_matrix_transform_point (&trans, &curve.control_[2][X_AXIS], &curve.contr
ol_[2][Y_AXIS]); | 434 Offset temp2 (x2, y2); |
336 pango_matrix_transform_point (&trans, &curve.control_[3][X_AXIS], &curve.contr
ol_[3][Y_AXIS]); | 435 Offset temp3 (x3, y3); |
| 436 pango_matrix_transform_point (&trans, &temp0[X_AXIS], &temp0[Y_AXIS]); |
| 437 pango_matrix_transform_point (&trans, &temp1[X_AXIS], &temp1[Y_AXIS]); |
| 438 pango_matrix_transform_point (&trans, &temp2[X_AXIS], &temp2[Y_AXIS]); |
| 439 pango_matrix_transform_point (&trans, &temp3[X_AXIS], &temp3[Y_AXIS]); |
337 ////////////////////// | 440 ////////////////////// |
338 vector<Offset> points; | 441 Drul_array<vector<Offset> > points; |
339 points.push_back (curve.control_[0]); | 442 Direction d = DOWN; |
340 for (vsize i = 1; i < CURVE_QUANTIZATION; i++) | 443 int quantization = int (((temp1 - temp0).length () |
341 points.push_back (curve.curve_point ((i * 1.0) / CURVE_QUANTIZATION)); | 444 + (temp2 - temp1).length () |
342 points.push_back (curve.control_[3]); | 445 + (temp3 - temp2).length ()) |
343 Translate_scale_rotate tsr = to_translate_scale_rotate (trans); | 446 / QUANTIZATION_UNIT); |
344 for (vsize i = 0; i < CURVE_QUANTIZATION; i++) | 447 do |
| 448 { |
| 449 Offset first = get_point_in_y_direction (curve.control_[0], perpendicular_
slope (curve.slope_at_point (0.0)), th / 2, d); |
| 450 pango_matrix_transform_point (&trans, &first[X_AXIS], &first[Y_AXIS]); |
| 451 points[d].push_back (first); |
| 452 for (vsize i = 1; i < quantization; i++) |
| 453 { |
| 454 Real pt = (i * 1.0) / quantization; |
| 455 Offset inter = get_point_in_y_direction (curve.curve_point (pt), perpe
ndicular_slope (curve.slope_at_point (pt)), th / 2, d); |
| 456 pango_matrix_transform_point (&trans, &inter[X_AXIS], &inter[Y_AXIS]); |
| 457 points[d].push_back (inter); |
| 458 } |
| 459 Offset last = get_point_in_y_direction (curve.control_[3], curve.slope_at_
point (1.0), th / 2, d); |
| 460 pango_matrix_transform_point (&trans, &last[X_AXIS], &last[Y_AXIS]); |
| 461 points[d].push_back (last); |
| 462 } |
| 463 while (flip (&d) != DOWN); |
| 464 |
| 465 for (vsize i = 0; i < points[DOWN].size () - 1; i++) |
345 { | 466 { |
346 Box b; | 467 Box b; |
347 b.add_point (points[i]); | 468 do |
348 b.add_point (points[i + 1]); | 469 { |
349 b.widen (abs (th * tsr.scale_[X_AXIS]) / 2, abs (th * tsr.scale_[Y_AXIS])
/ 2); | 470 b.add_point (points[d][i]); |
| 471 b.add_point (points[d][i + 1]); |
| 472 } |
| 473 while (flip (&d) != DOWN); |
350 boxes.push_back (b); | 474 boxes.push_back (b); |
351 } | 475 } |
352 return boxes; | 476 |
| 477 // beg line cap |
| 478 if (th >= 0) |
| 479 { |
| 480 Real slope = curve.slope_at_point (0.0); |
| 481 d = Direction (sign (slope == 0.0 || abs (slope) == infinity_f |
| 482 ? curve.slope_at_point (0.0001) |
| 483 : slope)); |
| 484 |
| 485 create_path_cap (boxes, |
| 486 buildings, |
| 487 trans, |
| 488 curve.control_[0], |
| 489 th / 2, |
| 490 perpendicular_slope (curve.slope_at_point (0.0)), |
| 491 d); |
| 492 |
| 493 // end line cap |
| 494 slope = curve.slope_at_point (1.0); |
| 495 d = Direction (sign (slope == 0.0 || abs (slope) == infinity_f |
| 496 ? curve.slope_at_point (0.9999) |
| 497 : slope)); |
| 498 |
| 499 create_path_cap (boxes, |
| 500 buildings, |
| 501 trans, |
| 502 curve.control_[3], |
| 503 th / 2, |
| 504 perpendicular_slope (curve.slope_at_point (1.0)), |
| 505 d); |
| 506 } |
353 } | 507 } |
354 | 508 |
355 /* | 509 /* |
356 converts a path into lists of 4 (line) or 8 (curve) absolute coordinates | 510 converts a path into lists of 4 (line) or 8 (curve) absolute coordinates |
357 for example: | 511 for example: |
358 '(moveto 1 2 lineto 3 4 rlineto -1 -1 curveto 3 3 5 5 6 6 rcurveto -1 -1 -1 -1
-1 -1 closepath) | 512 '(moveto 1 2 lineto 3 4 rlineto -1 -1 curveto 3 3 5 5 6 6 rcurveto -1 -1 -1 -1
-1 -1 closepath) |
359 becomes | 513 becomes |
360 '((1 2 3 4) | 514 '((1 2 3 4) |
361 (3 4 2 3) | 515 (3 4 2 3) |
362 (2 3 3 3 5 5 6 6) | 516 (2 3 3 3 5 5 6 6) |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
430 expr = scm_cdr (expr); | 584 expr = scm_cdr (expr); |
431 out = scm_cons (scm_list_n (scm_from_double (current[X_AXIS]), | 585 out = scm_cons (scm_list_n (scm_from_double (current[X_AXIS]), |
432 scm_from_double (current[Y_AXIS]), | 586 scm_from_double (current[Y_AXIS]), |
433 scm_from_double (x1), | 587 scm_from_double (x1), |
434 scm_from_double (y1), | 588 scm_from_double (y1), |
435 scm_from_double (x2), | 589 scm_from_double (x2), |
436 scm_from_double (y2), | 590 scm_from_double (y2), |
437 scm_from_double (x3), | 591 scm_from_double (x3), |
438 scm_from_double (y3), | 592 scm_from_double (y3), |
439 SCM_UNDEFINED), | 593 SCM_UNDEFINED), |
440 out); | 594 out); |
441 current = Offset (x3, y3); | 595 current = Offset (x3, y3); |
442 } | 596 } |
443 else if (scm_car (expr) == ly_symbol2scm ("rcurveto")) | 597 else if (scm_car (expr) == ly_symbol2scm ("rcurveto")) |
444 { | 598 { |
445 Real x1 = robust_scm2double (scm_cadr (expr), 0.0); | 599 Real x1 = robust_scm2double (scm_cadr (expr), 0.0); |
446 expr = scm_cddr (expr); | 600 expr = scm_cddr (expr); |
447 Real y1 = robust_scm2double (scm_car (expr), 0.0); | 601 Real y1 = robust_scm2double (scm_car (expr), 0.0); |
448 expr = scm_cdr (expr); | 602 expr = scm_cdr (expr); |
449 Real x2 = robust_scm2double (scm_car (expr), 0.0); | 603 Real x2 = robust_scm2double (scm_car (expr), 0.0); |
450 expr = scm_cdr (expr); | 604 expr = scm_cdr (expr); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
482 else | 636 else |
483 { | 637 { |
484 warning ("Malformed path for path stencil."); | 638 warning ("Malformed path for path stencil."); |
485 return out; | 639 return out; |
486 } | 640 } |
487 first = false; | 641 first = false; |
488 } | 642 } |
489 return scm_reverse_x (out, SCM_EOL); | 643 return scm_reverse_x (out, SCM_EOL); |
490 } | 644 } |
491 | 645 |
492 vector<Box> | 646 void |
493 make_path_boxes (PangoMatrix trans, SCM expr) | 647 internal_make_path_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &build
ings, PangoMatrix trans, SCM expr, bool use_building) |
494 { | 648 { |
495 vector<Box> boxes; | |
496 SCM blot = scm_car (expr); | 649 SCM blot = scm_car (expr); |
497 expr = scm_cdr (expr); | 650 expr = scm_cdr (expr); |
498 SCM path = all_commands_to_absolute_and_group (get_path_list (scm_car (expr)))
; | 651 SCM path = all_commands_to_absolute_and_group (expr); |
499 // note that expr has more stuff that we don't need after this - simply ignore
it | 652 // note that expr has more stuff that we don't need after this - simply ignore
it |
500 ////////////////////// | 653 ////////////////////// |
501 for (SCM s = path; scm_is_pair (s); s = scm_cdr (s)) | 654 for (SCM s = path; scm_is_pair (s); s = scm_cdr (s)) |
502 { | 655 { |
503 vector<Box> bxs = scm_to_int (scm_length (scm_car (s))) == 4 | 656 scm_to_int (scm_length (scm_car (s))) == 4 |
504 ? make_draw_line_boxes (trans, scm_cons (blot, scm_car (
s))) | 657 ? make_draw_line_boxes (boxes, buildings, trans, scm_cons (blot, scm_car (
s)), use_building) |
505 : make_draw_bezier_boxes (trans, scm_cons (blot, scm_car
(s))); | 658 : make_draw_bezier_boxes (boxes, buildings, trans, scm_cons (blot, scm_car
(s))); |
506 boxes.insert (boxes.end (), bxs.begin (), bxs.end ()); | 659 } |
507 } | 660 } |
508 return boxes; | 661 |
509 } | 662 void |
510 | 663 make_path_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings, Pan
goMatrix trans, SCM expr) |
511 vector<Box> | 664 { |
512 make_polygon_boxes (PangoMatrix trans, SCM expr) | 665 return internal_make_path_boxes (boxes, buildings, trans, scm_cons (scm_car (e
xpr), get_path_list (scm_cdr (expr))), false); |
513 { | 666 } |
514 vector<Box> boxes; | 667 |
| 668 void |
| 669 make_polygon_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings,
PangoMatrix trans, SCM expr) |
| 670 { |
515 SCM coords = get_number_list (scm_car (expr)); | 671 SCM coords = get_number_list (scm_car (expr)); |
516 expr = scm_cdr (expr); | 672 expr = scm_cdr (expr); |
517 SCM blot_diameter = scm_car (expr); | 673 SCM blot_diameter = scm_car (expr); |
518 ////////////////////// | 674 ////////////////////// |
519 bool first = true; | 675 bool first = true; |
520 SCM l = SCM_EOL; | 676 SCM l = SCM_EOL; |
521 for (SCM s = coords; scm_is_pair (s); s = scm_cddr (s)) | 677 for (SCM s = coords; scm_is_pair (s); s = scm_cddr (s)) |
522 { | 678 { |
523 l = scm_cons (first ? ly_symbol2scm ("moveto") : ly_symbol2scm ("lineto"),
l); | 679 l = scm_cons (first ? ly_symbol2scm ("moveto") : ly_symbol2scm ("lineto"),
l); |
524 l = scm_cons (scm_car (s), l); | 680 l = scm_cons (scm_car (s), l); |
525 l = scm_cons (scm_cadr (s), l); | 681 l = scm_cons (scm_cadr (s), l); |
526 first = false; | 682 first = false; |
527 } | 683 } |
528 l = scm_cons (ly_symbol2scm ("closepath"), l); | 684 l = scm_cons (ly_symbol2scm ("closepath"), l); |
529 return make_path_boxes (trans, scm_cons (blot_diameter, scm_reverse_x (l, SCM_
EOL))); | 685 internal_make_path_boxes (boxes, buildings, trans, scm_cons (blot_diameter, sc
m_reverse_x (l, SCM_EOL)), true); |
530 } | 686 } |
531 | 687 |
532 vector<Box> | 688 void |
533 make_named_glyph_boxes (PangoMatrix trans, SCM expr) | 689 make_named_glyph_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildin
gs, PangoMatrix trans, SCM expr) |
534 { | 690 { |
535 vector<Box> boxes; | 691 SCM fm_scm = scm_car (expr); |
536 Font_metric *fm = unsmob_metrics (scm_car (expr)); | 692 Font_metric *fm = unsmob_metrics (fm_scm); |
537 expr = scm_cdr (expr); | 693 expr = scm_cdr (expr); |
538 SCM glyph = scm_car (expr); | 694 SCM glyph = scm_car (expr); |
| 695 string glyph_s = ly_scm2string (glyph); |
| 696 |
539 ////////////////////// | 697 ////////////////////// |
540 string font_name = String_convert::to_lower (fm->font_name ()); | 698 Open_type_font *open_fm |
541 SCM box_table = ly_lily_module_constant ("box-hash"); | 699 = dynamic_cast<Open_type_font *> |
542 SCM font_list = scm_hashq_ref (box_table, ly_symbol2scm (font_name.c_str ()),
SCM_EOL); | 700 (dynamic_cast<Modified_font_metric *>(fm)->original_font ()); |
543 SCM glyph_info = scm_hashq_ref (font_list, scm_string_to_symbol (glyph), SCM_E
OL); | 701 SCM_ASSERT_TYPE (open_fm, fm_scm, SCM_ARG1, __FUNCTION__, "OpenType font"); |
544 Stencil m = fm->find_by_name (ly_scm2string (glyph)); | 702 |
545 // mmx and mmy give the bounding box for the original stencil | 703 size_t gidx = open_fm->name_to_index (glyph_s); |
546 Interval mmx = robust_scm2interval (ly_assoc_get (ly_symbol2scm ("mmx"), glyph
_info, SCM_EOL), Interval (0,0)); | 704 //Box bbox = open_fm->get_unscaled_indexed_char_dimensions (gidx); |
547 Interval mmy = robust_scm2interval (ly_assoc_get (ly_symbol2scm ("mmy"), glyph
_info, SCM_EOL), Interval (0,0)); | 705 Box bbox = open_fm->get_unscaled_indexed_char_dimensions (gidx); |
548 // xex and yex give the bounding box for the current stencil | 706 SCM outline = open_fm->get_glyph_outline (gidx); |
549 Interval xex = m.extent (X_AXIS); | 707 Box real_bbox = fm->get_indexed_char_dimensions (gidx); |
550 Interval yex = m.extent (Y_AXIS); | 708 |
551 Offset scale (xex.length () / mmx.length (), yex.length () / mmy.length ()); | 709 /* |
552 // the three operations below move the stencil from its original coordinates t
o current coordinates | 710 Because extents for named glyphs are cached, the value of |
553 pango_matrix_translate (&trans, xex[LEFT], yex[DOWN]); | 711 real_bbox may not be the one that freetype calculates. |
554 pango_matrix_scale (&trans, scale[X_AXIS], scale[Y_AXIS]); | 712 |
555 pango_matrix_translate (&trans, -mmx[LEFT], -mmy[DOWN]); | 713 They should be close, though. |
| 714 A workaround below is to use the max of the two, which may |
| 715 slightly overshoot an extent but generally doesn't. |
| 716 */ |
| 717 Real xlen = real_bbox[X_AXIS].length () / bbox[X_AXIS].length (); |
| 718 Real ylen = real_bbox[Y_AXIS].length () / bbox[Y_AXIS].length (); |
| 719 assert (abs (xlen - ylen) < 10e-3); |
| 720 |
| 721 pango_matrix_scale (&trans, max (xlen, ylen), max (xlen, ylen)); |
| 722 |
556 ////////////////////// | 723 ////////////////////// |
557 for (SCM s = ly_assoc_get (ly_symbol2scm ("paths"), glyph_info, SCM_EOL); | 724 for (SCM s = outline; |
558 scm_is_pair (s); | 725 scm_is_pair (s); |
559 s = scm_cdr (s)) | 726 s = scm_cdr (s)) |
560 { | 727 { |
561 vector<Box> bxs = scm_to_int (scm_length (scm_car (s))) == 4 | 728 scm_to_int (scm_length (scm_car (s))) == 4 |
562 ? make_draw_line_boxes (trans, scm_cons (scm_from_double
(0), scm_car (s))) | 729 ? make_draw_line_boxes (boxes, buildings, trans, scm_cons (scm_from_double
(0), scm_car (s)), false) |
563 : make_draw_bezier_boxes (trans, scm_cons (scm_from_doub
le (0), scm_car (s))); | 730 : make_draw_bezier_boxes (boxes, buildings, trans, scm_cons (scm_from_doub
le (0), scm_car (s))); |
564 boxes.insert (boxes.end (), bxs.begin (), bxs.end ()); | 731 } |
565 } | 732 } |
566 return boxes; | 733 |
567 } | 734 void |
568 | 735 make_glyph_string_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildi
ngs, PangoMatrix trans, SCM expr) |
569 vector<Box> | 736 { |
570 make_glyph_string_boxes (PangoMatrix trans, SCM expr) | 737 SCM fm_scm = scm_car (expr); |
571 { | 738 Font_metric *fm = unsmob_metrics (fm_scm); |
572 vector<Box> boxes; | 739 expr = scm_cdr (expr); |
573 expr = scm_cdr (expr); // font-name | 740 expr = scm_cdr (expr); // font-name |
574 expr = scm_cdr (expr); // size | 741 expr = scm_cdr (expr); // size |
575 expr = scm_cdr (expr); // cid? | 742 expr = scm_cdr (expr); // cid? |
576 SCM whxy = scm_cadar (expr); | 743 SCM whxy = scm_cadar (expr); |
577 vector<Real> widths; | 744 vector<Real> widths; |
578 vector<Interval> heights; | 745 vector<Interval> heights; |
579 vector<Real> xos; | 746 vector<Real> xos; |
580 vector<Real> yos; | 747 vector<Real> yos; |
| 748 vector<string> char_ids; |
581 ////////////////////// | 749 ////////////////////// |
| 750 Pango_font *pango_fm = dynamic_cast<Pango_font *> (fm); |
| 751 SCM_ASSERT_TYPE (pango_fm, fm_scm, SCM_ARG1, __FUNCTION__, "Pango font"); |
| 752 |
582 for (SCM s = whxy; scm_is_pair (s); s = scm_cdr (s)) | 753 for (SCM s = whxy; scm_is_pair (s); s = scm_cdr (s)) |
583 { | 754 { |
584 SCM now = scm_car (s); | 755 SCM now = scm_car (s); |
585 widths.push_back (robust_scm2double (scm_car (now), 0.0)); | 756 widths.push_back (robust_scm2double (scm_car (now), 0.0)); |
586 now = scm_cdr (now); | 757 now = scm_cdr (now); |
587 heights.push_back (robust_scm2interval (scm_car (now), Interval (0,0))); | 758 heights.push_back (robust_scm2interval (scm_car (now), Interval (0, 0))); |
588 now = scm_cdr (now); | 759 now = scm_cdr (now); |
589 xos.push_back (robust_scm2double (scm_car (now), 0.0)); | 760 xos.push_back (robust_scm2double (scm_car (now), 0.0)); |
590 now = scm_cdr (now); | 761 now = scm_cdr (now); |
591 yos.push_back (robust_scm2double (scm_car (now), 0.0)); | 762 yos.push_back (robust_scm2double (scm_car (now), 0.0)); |
| 763 now = scm_cdr (now); |
| 764 char_ids.push_back (robust_scm2string (scm_car (now), "")); |
592 } | 765 } |
593 Real cumulative_x = 0.0; | 766 Real cumulative_x = 0.0; |
594 for (vsize i = 0; i < widths.size (); i++) | 767 for (vsize i = 0; i < widths.size (); i++) |
595 { | 768 { |
| 769 PangoMatrix transcopy (trans); |
596 Offset pt0 (cumulative_x + xos[i], heights[i][DOWN] + yos[i]); | 770 Offset pt0 (cumulative_x + xos[i], heights[i][DOWN] + yos[i]); |
597 Offset pt1 (cumulative_x + widths[i] + xos[i], heights[i][UP] + yos[i]); | 771 Offset pt1 (cumulative_x + widths[i] + xos[i], heights[i][UP] + yos[i]); |
598 pango_matrix_transform_point (&trans, &pt0[X_AXIS], &pt0[Y_AXIS]); | |
599 pango_matrix_transform_point (&trans, &pt1[X_AXIS], &pt1[Y_AXIS]); | |
600 Box b; | |
601 b.add_point (pt0); | |
602 b.add_point (pt1); | |
603 boxes.push_back (b); | |
604 cumulative_x += widths[i]; | 772 cumulative_x += widths[i]; |
605 } | 773 |
606 return boxes; | 774 Box kerned_bbox; |
| 775 kerned_bbox.add_point (pt0); |
| 776 kerned_bbox.add_point (pt1); |
| 777 size_t gidx = pango_fm->name_to_index (char_ids[i]); |
| 778 Box real_bbox = pango_fm->get_scaled_indexed_char_dimensions (gidx); |
| 779 Box bbox = pango_fm->get_unscaled_indexed_char_dimensions (gidx); |
| 780 SCM outline = pango_fm->get_glyph_outline (gidx); |
| 781 |
| 782 // scales may have rounding error but should be close |
| 783 Real xlen = real_bbox[X_AXIS].length () / bbox[X_AXIS].length (); |
| 784 Real ylen = real_bbox[Y_AXIS].length () / bbox[Y_AXIS].length (); |
| 785 |
| 786 /* |
| 787 TODO: |
| 788 |
| 789 The value will be nan for whitespace, in which case we just want |
| 790 filler, so the kerned bbox is ok. |
| 791 |
| 792 However, if the value is inf, this likely means that LilyPond is |
| 793 using a font that is currently difficult to get the measurements |
| 794 from the Pango_font. This should eventually be fixed. The solution |
| 795 for now is just to use the bounding box. |
| 796 */ |
| 797 if (isnan (xlen) || isnan (ylen) || isinf (xlen) || isinf (ylen)) |
| 798 outline = box_to_scheme_lines (kerned_bbox); |
| 799 else |
| 800 { |
| 801 assert (abs (xlen - ylen) < 10e-3); |
| 802 |
| 803 Real scale_factor = max (xlen, ylen); |
| 804 // the three operations below move the stencil from its original coord
inates to current coordinates |
| 805 pango_matrix_translate (&transcopy, kerned_bbox[X_AXIS][LEFT], kerned_
bbox[Y_AXIS][DOWN] - real_bbox[Y_AXIS][DOWN]); |
| 806 pango_matrix_translate (&transcopy, real_bbox[X_AXIS][LEFT], real_bbox
[Y_AXIS][DOWN]); |
| 807 pango_matrix_scale (&transcopy, scale_factor, scale_factor); |
| 808 pango_matrix_translate (&transcopy, -bbox[X_AXIS][LEFT], -bbox[Y_AXIS]
[DOWN]); |
| 809 } |
| 810 ////////////////////// |
| 811 for (SCM s = outline; |
| 812 scm_is_pair (s); |
| 813 s = scm_cdr (s)) |
| 814 { |
| 815 scm_to_int (scm_length (scm_car (s))) == 4 |
| 816 ? make_draw_line_boxes (boxes, buildings, transcopy, scm_cons (scm_fro
m_double (0), scm_car (s)), false) |
| 817 : make_draw_bezier_boxes (boxes, buildings, transcopy, scm_cons (scm_f
rom_double (0), scm_car (s))); |
| 818 } |
| 819 } |
607 } | 820 } |
608 | 821 |
609 /* | 822 /* |
610 receives a stencil expression and a transform matrix | 823 receives a stencil expression and a transform matrix |
611 depending on the stencil name, dispatches it to the appropriate function | 824 depending on the stencil name, dispatches it to the appropriate function |
612 */ | 825 */ |
613 | 826 |
614 vector<Box> | 827 void |
615 stencil_dispatcher (PangoMatrix trans, SCM expr) | 828 stencil_dispatcher (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings,
PangoMatrix trans, SCM expr) |
616 { | 829 { |
617 if (not scm_is_pair (expr)) | 830 if (not scm_is_pair (expr)) |
618 return vector<Box> (); | 831 return; |
619 if (scm_car (expr) == ly_symbol2scm ("draw-line")) | 832 if (scm_car (expr) == ly_symbol2scm ("draw-line")) |
620 return make_draw_line_boxes (trans, scm_cdr (expr)); | 833 make_draw_line_boxes (boxes, buildings, trans, scm_cdr (expr), true); |
621 else if (scm_car (expr) == ly_symbol2scm ("dashed-line")) | 834 else if (scm_car (expr) == ly_symbol2scm ("dashed-line")) |
622 { | 835 { |
623 expr = scm_cdr (expr); | 836 expr = scm_cdr (expr); |
624 SCM th = scm_car (expr); | 837 SCM th = scm_car (expr); |
625 expr = scm_cdr (expr); | 838 expr = scm_cdr (expr); |
626 expr = scm_cdr (expr); // on | 839 expr = scm_cdr (expr); // on |
627 expr = scm_cdr (expr); // off | 840 expr = scm_cdr (expr); // off |
628 SCM x1 = scm_car (expr); | 841 SCM x1 = scm_car (expr); |
629 expr = scm_cdr (expr); | 842 expr = scm_cdr (expr); |
630 SCM x2 = scm_car (expr); | 843 SCM x2 = scm_car (expr); |
631 return make_draw_line_boxes (trans, scm_list_5 (th, scm_from_double (0.0),
scm_from_double (0.0), x1, x2)); | 844 make_draw_line_boxes (boxes, buildings, trans, scm_list_5 (th, scm_from_do
uble (0.0), scm_from_double (0.0), x1, x2), true); |
632 } | 845 } |
633 else if (scm_car (expr) == ly_symbol2scm ("circle")) | 846 else if (scm_car (expr) == ly_symbol2scm ("circle")) |
634 { | 847 { |
635 expr = scm_cdr (expr); | 848 expr = scm_cdr (expr); |
636 SCM rad = scm_car (expr); | 849 SCM rad = scm_car (expr); |
637 expr = scm_cdr (expr); | 850 expr = scm_cdr (expr); |
638 SCM th = scm_car (expr); | 851 SCM th = scm_car (expr); |
639 return make_partial_ellipse_boxes (trans, | 852 make_partial_ellipse_boxes (boxes, buildings, trans, |
640 scm_list_n (rad, | 853 scm_list_n (rad, |
641 rad, | 854 rad, |
642 scm_from_double (0.0), | 855 scm_from_double (0.0), |
643 scm_from_double (360.0), | 856 scm_from_double (360.0), |
644 th, | 857 th, |
645 SCM_BOOL_F, | 858 SCM_BOOL_F, |
646 SCM_BOOL_T, | 859 SCM_BOOL_T, |
647 SCM_UNDEFINED)); | 860 SCM_UNDEFINED)); |
648 } | 861 } |
649 else if (scm_car (expr) == ly_symbol2scm ("ellipse")) | 862 else if (scm_car (expr) == ly_symbol2scm ("ellipse")) |
650 { | 863 { |
651 expr = scm_cdr (expr); | 864 expr = scm_cdr (expr); |
652 SCM x_rad = scm_car (expr); | 865 SCM x_rad = scm_car (expr); |
653 expr = scm_cdr (expr); | 866 expr = scm_cdr (expr); |
654 SCM y_rad = scm_car (expr); | 867 SCM y_rad = scm_car (expr); |
655 expr = scm_cdr (expr); | 868 expr = scm_cdr (expr); |
656 SCM th = scm_car (expr); | 869 SCM th = scm_car (expr); |
657 return make_partial_ellipse_boxes (trans, | 870 make_partial_ellipse_boxes (boxes, buildings, trans, |
658 scm_list_n (x_rad, | 871 scm_list_n (x_rad, |
659 y_rad, | 872 y_rad, |
660 scm_from_double (0.0), | 873 scm_from_double (0.0), |
661 scm_from_double (360.0), | 874 scm_from_double (360.0), |
662 th, | 875 th, |
663 SCM_BOOL_F, | 876 SCM_BOOL_F, |
664 SCM_BOOL_T, | 877 SCM_BOOL_T, |
665 SCM_UNDEFINED)); | 878 SCM_UNDEFINED)); |
666 } | 879 } |
667 else if (scm_car (expr) == ly_symbol2scm ("partial-ellipse")) | 880 else if (scm_car (expr) == ly_symbol2scm ("partial-ellipse")) |
668 return make_partial_ellipse_boxes (trans, scm_cdr (expr)); | 881 make_partial_ellipse_boxes (boxes, buildings, trans, scm_cdr (expr)); |
669 else if (scm_car (expr) == ly_symbol2scm ("round-filled-box")) | 882 else if (scm_car (expr) == ly_symbol2scm ("round-filled-box")) |
670 return make_round_filled_box_boxes (trans, scm_cdr (expr)); | 883 make_round_filled_box_boxes (boxes, trans, scm_cdr (expr)); |
671 else if (scm_car (expr) == ly_symbol2scm ("named-glyph")) | 884 else if (scm_car (expr) == ly_symbol2scm ("named-glyph")) |
672 return make_named_glyph_boxes (trans, scm_cdr (expr)); | 885 make_named_glyph_boxes (boxes, buildings, trans, scm_cdr (expr)); |
673 else if (scm_car (expr) == ly_symbol2scm ("polygon")) | 886 else if (scm_car (expr) == ly_symbol2scm ("polygon")) |
674 return make_polygon_boxes (trans, scm_cdr (expr)); | 887 make_polygon_boxes (boxes, buildings, trans, scm_cdr (expr)); |
675 else if (scm_car (expr) == ly_symbol2scm ("path")) | 888 else if (scm_car (expr) == ly_symbol2scm ("path")) |
676 return make_path_boxes (trans, scm_cdr (expr)); | 889 make_path_boxes (boxes, buildings, trans, scm_cdr (expr)); |
677 else if (scm_car (expr) == ly_symbol2scm ("glyph-string")) | 890 else if (scm_car (expr) == ly_symbol2scm ("glyph-string")) |
678 return make_glyph_string_boxes (trans, scm_cdr (expr)); | 891 make_glyph_string_boxes (boxes, buildings, trans, scm_cdr (expr)); |
679 else | 892 else |
680 { | 893 { |
681 #if 0 | 894 #if 0 |
682 warning ("Stencil expression not supported by the veritcal skylines."); | 895 warning ("Stencil expression not supported by the veritcal skylines."); |
683 #endif | 896 #endif |
684 /* | 897 /* |
685 We don't issue a warning here, as we assume that stencil-expression.cc | 898 We don't issue a warning here, as we assume that stencil-expression.cc |
686 is doing stencil-checking correctly. | 899 is doing stencil-checking correctly. |
687 */ | 900 */ |
688 return vector<Box> (); | |
689 } | 901 } |
690 } | 902 } |
691 | 903 |
692 /* | 904 /* |
693 traverses a stencil expression, returning a vector of Transform_matrix_and_exp
ression | 905 traverses a stencil expression, returning a vector of Transform_matrix_and_exp
ression |
694 the struct Transform_matrix_and_expression contains two members, | 906 the struct Transform_matrix_and_expression contains two members, |
695 a Transform_matrix that indicates where to move a stencil and the stencil expr
ession | 907 a Transform_matrix that indicates where to move a stencil and the stencil expr
ession |
696 to show how to construct the stencil | 908 to show how to construct the stencil |
697 */ | 909 */ |
698 vector<Transform_matrix_and_expression> | 910 vector<Transform_matrix_and_expression> |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
749 else | 961 else |
750 { | 962 { |
751 vector<Transform_matrix_and_expression> out; | 963 vector<Transform_matrix_and_expression> out; |
752 out.push_back (Transform_matrix_and_expression (trans, expr)); | 964 out.push_back (Transform_matrix_and_expression (trans, expr)); |
753 return out; | 965 return out; |
754 } | 966 } |
755 warning ("Stencil expression not supported by the veritcal skylines."); | 967 warning ("Stencil expression not supported by the veritcal skylines."); |
756 return vector<Transform_matrix_and_expression> (); | 968 return vector<Transform_matrix_and_expression> (); |
757 } | 969 } |
758 | 970 |
| 971 SCM |
| 972 Grob::internal_simple_skylines_from_stencil (SCM smob, Axis a) |
| 973 { |
| 974 Grob *me = unsmob_grob (smob); |
| 975 |
| 976 if (to_boolean (me->get_property ("cross-staff"))) |
| 977 return Skyline_pair ().smobbed_copy (); |
| 978 |
| 979 extract_grob_set (me, "elements", elts); |
| 980 if (elts.size ()) |
| 981 return internal_skylines_from_element_stencils (smob, a); |
| 982 |
| 983 Stencil *s = unsmob_stencil (me->get_property ("stencil")); |
| 984 if (!s) |
| 985 return Skyline_pair ().smobbed_copy (); |
| 986 |
| 987 vector<Box> boxes; |
| 988 boxes.push_back (Box (s->extent (X_AXIS), s->extent (Y_AXIS))); |
| 989 return Skyline_pair (boxes, a).smobbed_copy (); |
| 990 } |
| 991 |
| 992 MAKE_SCHEME_CALLBACK (Grob, simple_vertical_skylines_from_stencil, 1); |
| 993 SCM |
| 994 Grob::simple_vertical_skylines_from_stencil (SCM smob) |
| 995 { |
| 996 return internal_simple_skylines_from_stencil (smob, X_AXIS); |
| 997 } |
| 998 |
| 999 MAKE_SCHEME_CALLBACK (Grob, simple_horizontal_skylines_from_stencil, 1); |
| 1000 SCM |
| 1001 Grob::simple_horizontal_skylines_from_stencil (SCM smob) |
| 1002 { |
| 1003 return internal_simple_skylines_from_stencil (smob, Y_AXIS); |
| 1004 } |
| 1005 |
| 1006 SCM |
| 1007 Stencil::skylines_from_stencil (SCM sten, Real pad, Axis a) |
| 1008 { |
| 1009 Stencil *s = unsmob_stencil (sten); |
| 1010 if (!s) |
| 1011 return Skyline_pair ().smobbed_copy (); |
| 1012 |
| 1013 vector<Transform_matrix_and_expression> data |
| 1014 = stencil_traverser (make_transform_matrix (1.0, 0.0, 0.0, 1.0, 0.0, 0.0), |
| 1015 s->expr ()); |
| 1016 vector<Box> boxes; |
| 1017 vector<Drul_array<Offset> > buildings; |
| 1018 for (vsize i = 0; i < data.size (); i++) |
| 1019 stencil_dispatcher (boxes, buildings, data[i].tm_, data[i].expr_); |
| 1020 |
| 1021 // we use the bounding box if there are no boxes |
| 1022 if (!boxes.size () && !buildings.size ()) |
| 1023 boxes.push_back (Box (s->extent (X_AXIS), s->extent (Y_AXIS))); |
| 1024 |
| 1025 Skyline_pair out (boxes, a); |
| 1026 out.merge (Skyline_pair (buildings, a)); |
| 1027 |
| 1028 for (DOWN_and_UP (d)) |
| 1029 out[d] = out[d].padded (pad); |
| 1030 |
| 1031 out.deholify (); |
| 1032 return out.smobbed_copy (); |
| 1033 } |
| 1034 |
759 MAKE_SCHEME_CALLBACK (Grob, vertical_skylines_from_stencil, 1); | 1035 MAKE_SCHEME_CALLBACK (Grob, vertical_skylines_from_stencil, 1); |
760 SCM | 1036 SCM |
761 Grob::vertical_skylines_from_stencil (SCM smob) | 1037 Grob::vertical_skylines_from_stencil (SCM smob) |
762 { | 1038 { |
763 Grob *me = unsmob_grob (smob); | 1039 Grob *me = unsmob_grob (smob); |
764 Stencil *s = unsmob_stencil (me->get_property ("stencil")); | 1040 |
765 if (!s) | 1041 Real pad = robust_scm2double (me->get_property ("skyline-horizontal-padding"),
0.0); |
766 return Skyline_pair ().smobbed_copy (); | 1042 SCM out = Stencil::skylines_from_stencil (me->get_property ("stencil"), pad, X
_AXIS); |
767 vector<Transform_matrix_and_expression> data = | 1043 |
768 stencil_traverser (make_transform_matrix (1.0,0.0,0.0,1.0,0.0,0.0), | 1044 return out; |
769 s->expr ()); | 1045 } |
770 vector<Box> boxes; | 1046 |
771 for (vsize i = 0; i < data.size (); i++) | 1047 MAKE_SCHEME_CALLBACK (Grob, horizontal_skylines_from_stencil, 1); |
772 { | |
773 vector<Box> bxs = stencil_dispatcher (data[i].tm_, data[i].expr_); | |
774 boxes.insert (boxes.end (), bxs.begin (), bxs.end ()); | |
775 } | |
776 if (!boxes.size ()) | |
777 { | |
778 // we use the bounding box | |
779 boxes.push_back (Box (s->extent (X_AXIS), s->extent (Y_AXIS))); | |
780 } | |
781 return Skyline_pair (boxes, 0.0, X_AXIS).smobbed_copy (); | |
782 } | |
783 | |
784 MAKE_SCHEME_CALLBACK (Grob, vertical_skylines_from_element_stencils, 1); | |
785 SCM | 1048 SCM |
786 Grob::vertical_skylines_from_element_stencils (SCM smob) | 1049 Grob::horizontal_skylines_from_stencil (SCM smob) |
787 { | 1050 { |
788 Grob *me = unsmob_grob (smob); | 1051 Grob *me = unsmob_grob (smob); |
| 1052 |
| 1053 Real pad = robust_scm2double (me->get_property ("skyline-vertical-padding"), 0
.0); |
| 1054 SCM out = Stencil::skylines_from_stencil (me->get_property ("stencil"), pad, Y
_AXIS); |
| 1055 |
| 1056 return out; |
| 1057 } |
| 1058 |
| 1059 SCM |
| 1060 Grob::internal_skylines_from_element_stencils (SCM smob, Axis a) |
| 1061 { |
| 1062 Grob *me = unsmob_grob (smob); |
| 1063 |
789 extract_grob_set (me, "elements", elts); | 1064 extract_grob_set (me, "elements", elts); |
790 vector<Real> x_pos; | 1065 vector<Real> x_pos; |
791 vector<Real> y_pos; | 1066 vector<Real> y_pos; |
792 Grob *x_common = common_refpoint_of_array (elts, me, X_AXIS); | 1067 Grob *x_common = common_refpoint_of_array (elts, me, X_AXIS); |
793 Grob *y_common = common_refpoint_of_array (elts, me, Y_AXIS); | 1068 Grob *y_common = common_refpoint_of_array (elts, me, Y_AXIS); |
794 for (vsize i = 0; i < elts.size (); i++) | 1069 for (vsize i = 0; i < elts.size (); i++) |
795 { | 1070 { |
796 x_pos.push_back (elts[i]->relative_coordinate (x_common, X_AXIS)); | 1071 x_pos.push_back (elts[i]->relative_coordinate (x_common, X_AXIS)); |
797 y_pos.push_back (elts[i]->relative_coordinate (y_common, Y_AXIS)); | 1072 y_pos.push_back (elts[i]->relative_coordinate (y_common, Y_AXIS)); |
798 } | 1073 } |
799 Real my_x = me->relative_coordinate (x_common, X_AXIS); | 1074 Real my_x = me->relative_coordinate (x_common, X_AXIS); |
800 Real my_y = me->relative_coordinate (y_common, Y_AXIS); | 1075 Real my_y = me->relative_coordinate (y_common, Y_AXIS); |
801 Skyline_pair res; | 1076 Skyline_pair res; |
802 for (vsize i = 0; i < elts.size (); i++) | 1077 for (vsize i = 0; i < elts.size (); i++) |
803 { | 1078 { |
804 Skyline_pair *skyp = Skyline_pair::unsmob (elts[i]->get_property ("vertica
l-skylines")); | 1079 Skyline_pair *skyp = Skyline_pair::unsmob (elts[i]->get_property (a == X_A
XIS ? "vertical-skylines" : "horizontal-skylines")); |
805 if (skyp) | 1080 if (skyp) |
806 { | 1081 { |
807 /* | 1082 /* |
808 Here, copying is essential. Otherwise, the skyline pair will | 1083 Here, copying is essential. Otherwise, the skyline pair will |
809 get doubly shifted! | 1084 get doubly shifted! |
810 */ | 1085 */ |
| 1086 /* |
| 1087 It took Mike about 6 months of his life to add the `else' clause |
| 1088 below. For horizontal skylines, the raise and shift calls need |
| 1089 to be reversed. This is what was causing the problems in the |
| 1090 shifting with all of the tests. RIP 6 months! |
| 1091 */ |
811 Skyline_pair copy = Skyline_pair (*skyp); | 1092 Skyline_pair copy = Skyline_pair (*skyp); |
812 copy.shift (x_pos[i] - my_x); | 1093 if (a == X_AXIS) |
813 copy.raise (y_pos[i] - my_y); | 1094 { |
| 1095 copy.shift (x_pos[i] - my_x); |
| 1096 copy.raise (y_pos[i] - my_y); |
| 1097 } |
| 1098 else |
| 1099 { |
| 1100 copy.raise (x_pos[i] - my_x); |
| 1101 copy.shift (y_pos[i] - my_y); |
| 1102 } |
814 res.merge (copy); | 1103 res.merge (copy); |
815 } | 1104 } |
816 } | 1105 } |
817 return res.smobbed_copy (); | 1106 return res.smobbed_copy (); |
818 } | 1107 } |
| 1108 |
| 1109 MAKE_SCHEME_CALLBACK (Grob, vertical_skylines_from_element_stencils, 1); |
| 1110 SCM |
| 1111 Grob::vertical_skylines_from_element_stencils (SCM smob) |
| 1112 { |
| 1113 return internal_skylines_from_element_stencils (smob, X_AXIS); |
| 1114 } |
| 1115 |
| 1116 MAKE_SCHEME_CALLBACK (Grob, horizontal_skylines_from_element_stencils, 1); |
| 1117 SCM |
| 1118 Grob::horizontal_skylines_from_element_stencils (SCM smob) |
| 1119 { |
| 1120 return internal_skylines_from_element_stencils (smob, Y_AXIS); |
| 1121 } |
LEFT | RIGHT |