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 } | |
99 | |
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 } | 87 } |
116 | 88 |
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) |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 != SCM_BOOL_F) | 138 != SCM_BOOL_F) |
167 return l; | 139 return l; |
168 SCM res = get_path_list (scm_car (l)); | 140 SCM res = get_path_list (scm_car (l)); |
169 if (res == SCM_BOOL_F) | 141 if (res == SCM_BOOL_F) |
170 return get_path_list (scm_cdr (l)); | 142 return get_path_list (scm_cdr (l)); |
171 return res; | 143 return res; |
172 } | 144 } |
173 return SCM_BOOL_F; | 145 return SCM_BOOL_F; |
174 } | 146 } |
175 | 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 |
176 //// END UTILITY FUNCTIONS | 158 //// END UTILITY FUNCTIONS |
177 | 159 |
178 /* | 160 /* |
179 below, for all of the functions make_X_boxes, the expression | 161 below, for all of the functions make_X_boxes, the expression |
180 is always unpacked into variables. | 162 is always unpacked into variables. |
181 then, after a line of /////, there are manipulations of these variables | 163 then, after a line of /////, there are manipulations of these variables |
182 (there may be no manipulations necessary depending on the function) | 164 (there may be no manipulations necessary depending on the function) |
183 afterwards, there is another ///// followed by the creation of points | 165 afterwards, there is another ///// followed by the creation of points |
184 and boxes | 166 and boxes |
185 */ | 167 */ |
186 | 168 |
187 vector<Box> | 169 void |
188 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) |
189 { | 171 { |
190 vector<Box> boxes; | |
191 Real thick = robust_scm2double (scm_car (expr), 0.0); | 172 Real thick = robust_scm2double (scm_car (expr), 0.0); |
192 expr = scm_cdr (expr); | 173 expr = scm_cdr (expr); |
193 Real x0 = robust_scm2double (scm_car (expr), 0.0); | 174 Real x0 = robust_scm2double (scm_car (expr), 0.0); |
194 expr = scm_cdr (expr); | 175 expr = scm_cdr (expr); |
195 Real y0 = robust_scm2double (scm_car (expr), 0.0); | 176 Real y0 = robust_scm2double (scm_car (expr), 0.0); |
196 expr = scm_cdr (expr); | 177 expr = scm_cdr (expr); |
197 Real x1 = robust_scm2double (scm_car (expr), 0.0); | 178 Real x1 = robust_scm2double (scm_car (expr), 0.0); |
198 expr = scm_cdr (expr); | 179 expr = scm_cdr (expr); |
199 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); |
200 ////////////////////// | 182 ////////////////////// |
201 vector<Offset> points; | 183 if (x1 < x0) |
202 for (vsize i = 0; i < 1 + CURVE_QUANTIZATION; i++) | 184 { |
203 { | 185 swap (x0, x1); |
204 Offset pt (linear_map (x0, x1, 0, CURVE_QUANTIZATION, i), | 186 swap (y0, y1); |
205 linear_map (y0, y1, 0, CURVE_QUANTIZATION, i)); | 187 } |
206 pango_matrix_transform_point (&trans, &pt[X_AXIS], &pt[Y_AXIS]); | 188 Offset left (x0, y0); |
207 points.push_back (pt); | 189 Offset right (x1, y1); |
208 } | 190 Direction d = DOWN; |
209 Translate_scale_rotate tsr = to_translate_scale_rotate (trans); | 191 do |
210 for (vsize i = 0; i < CURVE_QUANTIZATION; i++) | 192 { |
211 { | 193 Offset inter_l = get_point_in_y_direction (left, perpendicular_slope (slop
e), thick / 2, d); |
212 Box b; | 194 Offset inter_r = get_point_in_y_direction (right, perpendicular_slope (slo
pe), thick / 2, d); |
213 b.add_point (points[i]); | 195 pango_matrix_transform_point (&trans, &inter_l[X_AXIS], &inter_l[Y_AXIS]); |
214 b.add_point (points[i + 1]); | 196 pango_matrix_transform_point (&trans, &inter_r[X_AXIS], &inter_r[Y_AXIS]); |
215 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])) |
216 boxes.push_back (b); | 198 { |
217 } | 199 Box b; |
218 return boxes; | 200 b.add_point (inter_l); |
219 } | 201 b.add_point (inter_r); |
220 | 202 boxes.push_back (b); |
221 vector<Box> | 203 } |
222 make_partial_ellipse_boxes (PangoMatrix trans, SCM expr) | 204 else if (use_building) |
223 { | 205 buildings.push_back (Drul_array<Offset> (inter_l, inter_r)); |
224 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 { |
225 Real x_rad = robust_scm2double (scm_car (expr), 0.0); | 261 Real x_rad = robust_scm2double (scm_car (expr), 0.0); |
226 expr = scm_cdr (expr); | 262 expr = scm_cdr (expr); |
227 Real y_rad = robust_scm2double (scm_car (expr), 0.0); | 263 Real y_rad = robust_scm2double (scm_car (expr), 0.0); |
228 expr = scm_cdr (expr); | 264 expr = scm_cdr (expr); |
229 Real start = robust_scm2double (scm_car (expr), 0.0); | 265 Real start = robust_scm2double (scm_car (expr), 0.0); |
230 expr = scm_cdr (expr); | 266 expr = scm_cdr (expr); |
231 Real end = robust_scm2double (scm_car (expr), 0.0); | 267 Real end = robust_scm2double (scm_car (expr), 0.0); |
232 expr = scm_cdr (expr); | 268 expr = scm_cdr (expr); |
233 Real th = robust_scm2double (scm_car (expr), 0.0); | 269 Real th = robust_scm2double (scm_car (expr), 0.0); |
234 expr = scm_cdr (expr); | 270 expr = scm_cdr (expr); |
235 bool connect = to_boolean (scm_car (expr)); | 271 bool connect = to_boolean (scm_car (expr)); |
236 expr = scm_cdr (expr); | 272 expr = scm_cdr (expr); |
237 bool fill = to_boolean (scm_car (expr)); | 273 bool fill = to_boolean (scm_car (expr)); |
238 ////////////////////// | 274 ////////////////////// |
239 start = M_PI * start / 180; | 275 start = M_PI * start / 180; |
240 end = M_PI * end / 180; | 276 end = M_PI * end / 180; |
241 if (end == start) | 277 if (end == start) |
242 end += (2 * M_PI); | 278 end += (2 * M_PI); |
243 complex<Real> sunit = polar (1.0, start); | 279 complex<Real> sunit = polar (1.0, start); |
244 complex<Real> eunit = polar (1.0, end); | 280 complex<Real> eunit = polar (1.0, end); |
245 Offset sp (real (sunit) * x_rad, imag (sunit) * y_rad); | 281 Offset sp (real (sunit) * x_rad, imag (sunit) * y_rad); |
246 Offset ep (real (eunit) * x_rad, imag (eunit) * y_rad); | 282 Offset ep (real (eunit) * x_rad, imag (eunit) * y_rad); |
247 ////////////////////// | 283 ////////////////////// |
248 vector<Offset> points; | 284 Drul_array<vector<Offset> > points; |
249 for (vsize i = 0; i < 1 + ELLIPSE_QUANTIZATION; i++) | 285 Direction d = DOWN; |
250 { | 286 int quantization = max (1, (int) (((x_rad * trans.xx) + (y_rad * trans.yy)) *
M_PI / QUANTIZATION_UNIT)); |
251 Real ang = linear_map (start, end, 0, ELLIPSE_QUANTIZATION, i); | 287 do |
252 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); |
253 Offset pt (real (coord) * x_rad, | 329 Offset pt (real (coord) * x_rad, |
254 imag (coord) * y_rad); | 330 imag (coord) * y_rad); |
255 pango_matrix_transform_point (&trans, &pt[X_AXIS], &pt[Y_AXIS]); | 331 Real slope = pt[Y_AXIS] / pt[X_AXIS]; |
256 points.push_back (pt); | 332 create_path_cap (boxes, |
257 } | 333 buildings, |
258 Translate_scale_rotate tsr = to_translate_scale_rotate (trans); | 334 trans, |
259 for (vsize i = 0; i < ELLIPSE_QUANTIZATION; i++) | 335 pt, |
260 { | 336 th / 2, |
261 Box b; | 337 perpendicular_slope (slope), |
262 b.add_point (points[i]); | 338 Direction (sign (slope))); |
263 b.add_point (points[i + 1]); | 339 |
264 b.widen (abs (th * tsr.scale_[X_AXIS]) / 2, abs (th * tsr.scale_[Y_AXIS])
/ 2); | 340 // end line cap |
265 boxes.push_back (b); | 341 coord = polar (1.0, start); |
266 } | 342 pt = Offset (real (coord) * x_rad, |
267 if (connect || fill) | 343 imag (coord) * y_rad); |
268 { | 344 slope = pt[Y_AXIS] / pt[X_AXIS]; |
269 vector<Box> db = make_draw_line_boxes (trans, scm_list_5(scm_from_double (
th), | 345 create_path_cap (boxes, |
270 scm_from_double (
sp[X_AXIS]), | 346 buildings, |
271 scm_from_double (
sp[Y_AXIS]), | 347 trans, |
272 scm_from_double (
ep[X_AXIS]), | 348 pt, |
273 scm_from_double (
ep[Y_AXIS]))); | 349 th / 2, |
274 boxes.insert (boxes.end (), db.begin (), db.end ()); | 350 perpendicular_slope (slope), |
275 } | 351 Direction (sign (-slope))); |
276 return boxes; | 352 } |
277 } | 353 } |
278 | 354 |
279 vector<Box> | 355 void |
280 make_round_filled_box_boxes (PangoMatrix trans, SCM expr) | 356 make_round_filled_box_boxes (vector<Box> &boxes, PangoMatrix trans, SCM expr) |
281 { | 357 { |
282 vector<Box> boxes; | |
283 Real left = robust_scm2double (scm_car (expr), 0.0); | 358 Real left = robust_scm2double (scm_car (expr), 0.0); |
284 expr = scm_cdr (expr); | 359 expr = scm_cdr (expr); |
285 Real right = robust_scm2double (scm_car (expr), 0.0); | 360 Real right = robust_scm2double (scm_car (expr), 0.0); |
286 expr = scm_cdr (expr); | 361 expr = scm_cdr (expr); |
287 Real bottom = robust_scm2double (scm_car (expr), 0.0); | 362 Real bottom = robust_scm2double (scm_car (expr), 0.0); |
288 expr = scm_cdr (expr); | 363 expr = scm_cdr (expr); |
289 Real top = robust_scm2double (scm_car (expr), 0.0); | 364 Real top = robust_scm2double (scm_car (expr), 0.0); |
290 expr = scm_cdr (expr); | 365 expr = scm_cdr (expr); |
291 Real th = robust_scm2double (scm_car (expr), 0.0); | 366 Real th = robust_scm2double (scm_car (expr), 0.0); |
292 ////////////////////// | 367 ////////////////////// |
293 vector<Offset> points; | 368 vector<Offset> points; |
294 Box b; | 369 Box b; |
295 Offset p0 = Offset (-left, -bottom); | 370 Offset p0 = Offset (-left - (th / 2), -bottom - (th / 2)); |
296 Offset p1 = Offset (right, top); | 371 Offset p1 = Offset (right + (th / 2), top + (th / 2)); |
297 pango_matrix_transform_point (&trans, &p0[X_AXIS], &p0[Y_AXIS]); | 372 pango_matrix_transform_point (&trans, &p0[X_AXIS], &p0[Y_AXIS]); |
298 pango_matrix_transform_point (&trans, &p1[X_AXIS], &p1[Y_AXIS]); | 373 pango_matrix_transform_point (&trans, &p1[X_AXIS], &p1[Y_AXIS]); |
299 b.add_point (p0); | 374 b.add_point (p0); |
300 b.add_point (p1); | 375 b.add_point (p1); |
301 Translate_scale_rotate tsr = to_translate_scale_rotate (trans); | |
302 b.widen (abs (th * tsr.scale_[X_AXIS]) / 2, abs (th * tsr.scale_[Y_AXIS]) / 2)
; | |
303 boxes.push_back (b); | 376 boxes.push_back (b); |
304 return boxes; | 377 } |
305 } | 378 |
306 | 379 void |
307 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) |
308 make_draw_bezier_boxes (PangoMatrix trans, SCM expr) | 381 { |
309 { | 382 Real angle = atan (slope) * 180 / M_PI; |
310 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 { |
311 Real th = robust_scm2double (scm_car (expr), 0.0); | 409 Real th = robust_scm2double (scm_car (expr), 0.0); |
312 expr = scm_cdr (expr); | 410 expr = scm_cdr (expr); |
313 Real x0 = robust_scm2double (scm_car (expr), 0.0); | 411 Real x0 = robust_scm2double (scm_car (expr), 0.0); |
314 expr = scm_cdr (expr); | 412 expr = scm_cdr (expr); |
315 Real y0 = robust_scm2double (scm_car (expr), 0.0); | 413 Real y0 = robust_scm2double (scm_car (expr), 0.0); |
316 expr = scm_cdr (expr); | 414 expr = scm_cdr (expr); |
317 Real x1 = robust_scm2double (scm_car (expr), 0.0); | 415 Real x1 = robust_scm2double (scm_car (expr), 0.0); |
318 expr = scm_cdr (expr); | 416 expr = scm_cdr (expr); |
319 Real y1 = robust_scm2double (scm_car (expr), 0.0); | 417 Real y1 = robust_scm2double (scm_car (expr), 0.0); |
320 expr = scm_cdr (expr); | 418 expr = scm_cdr (expr); |
321 Real x2 = robust_scm2double (scm_car (expr), 0.0); | 419 Real x2 = robust_scm2double (scm_car (expr), 0.0); |
322 expr = scm_cdr (expr); | 420 expr = scm_cdr (expr); |
323 Real y2 = robust_scm2double (scm_car (expr), 0.0); | 421 Real y2 = robust_scm2double (scm_car (expr), 0.0); |
324 expr = scm_cdr (expr); | 422 expr = scm_cdr (expr); |
325 Real x3 = robust_scm2double (scm_car (expr), 0.0); | 423 Real x3 = robust_scm2double (scm_car (expr), 0.0); |
326 expr = scm_cdr (expr); | 424 expr = scm_cdr (expr); |
327 Real y3 = robust_scm2double (scm_car (expr), 0.0); | 425 Real y3 = robust_scm2double (scm_car (expr), 0.0); |
328 ////////////////////// | 426 ////////////////////// |
329 Bezier curve; | 427 Bezier curve; |
330 curve.control_[0] = Offset (x0, y0); | 428 curve.control_[0] = Offset (x0, y0); |
331 curve.control_[1] = Offset (x1, y1); | 429 curve.control_[1] = Offset (x1, y1); |
332 curve.control_[2] = Offset (x2, y2); | 430 curve.control_[2] = Offset (x2, y2); |
333 curve.control_[3] = Offset (x3, y3); | 431 curve.control_[3] = Offset (x3, y3); |
334 pango_matrix_transform_point (&trans, &curve.control_[0][X_AXIS], &curve.contr
ol_[0][Y_AXIS]); | 432 Offset temp0 (x0, y0); |
335 pango_matrix_transform_point (&trans, &curve.control_[1][X_AXIS], &curve.contr
ol_[1][Y_AXIS]); | 433 Offset temp1 (x1, y1); |
336 pango_matrix_transform_point (&trans, &curve.control_[2][X_AXIS], &curve.contr
ol_[2][Y_AXIS]); | 434 Offset temp2 (x2, y2); |
337 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]); |
338 ////////////////////// | 440 ////////////////////// |
339 vector<Offset> points; | 441 Drul_array<vector<Offset> > points; |
340 points.push_back (curve.control_[0]); | 442 Direction d = DOWN; |
341 for (vsize i = 1; i < CURVE_QUANTIZATION; i++) | 443 int quantization = int (((temp1 - temp0).length () |
342 points.push_back (curve.curve_point ((i * 1.0) / CURVE_QUANTIZATION)); | 444 + (temp2 - temp1).length () |
343 points.push_back (curve.control_[3]); | 445 + (temp3 - temp2).length ()) |
344 Translate_scale_rotate tsr = to_translate_scale_rotate (trans); | 446 / QUANTIZATION_UNIT); |
345 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++) |
346 { | 466 { |
347 Box b; | 467 Box b; |
348 b.add_point (points[i]); | 468 do |
349 b.add_point (points[i + 1]); | 469 { |
350 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); |
351 boxes.push_back (b); | 474 boxes.push_back (b); |
352 } | 475 } |
353 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 } |
354 } | 507 } |
355 | 508 |
356 /* | 509 /* |
357 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 |
358 for example: | 511 for example: |
359 '(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) |
360 becomes | 513 becomes |
361 '((1 2 3 4) | 514 '((1 2 3 4) |
362 (3 4 2 3) | 515 (3 4 2 3) |
363 (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... |
431 expr = scm_cdr (expr); | 584 expr = scm_cdr (expr); |
432 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]), |
433 scm_from_double (current[Y_AXIS]), | 586 scm_from_double (current[Y_AXIS]), |
434 scm_from_double (x1), | 587 scm_from_double (x1), |
435 scm_from_double (y1), | 588 scm_from_double (y1), |
436 scm_from_double (x2), | 589 scm_from_double (x2), |
437 scm_from_double (y2), | 590 scm_from_double (y2), |
438 scm_from_double (x3), | 591 scm_from_double (x3), |
439 scm_from_double (y3), | 592 scm_from_double (y3), |
440 SCM_UNDEFINED), | 593 SCM_UNDEFINED), |
441 out); | 594 out); |
442 current = Offset (x3, y3); | 595 current = Offset (x3, y3); |
443 } | 596 } |
444 else if (scm_car (expr) == ly_symbol2scm ("rcurveto")) | 597 else if (scm_car (expr) == ly_symbol2scm ("rcurveto")) |
445 { | 598 { |
446 Real x1 = robust_scm2double (scm_cadr (expr), 0.0); | 599 Real x1 = robust_scm2double (scm_cadr (expr), 0.0); |
447 expr = scm_cddr (expr); | 600 expr = scm_cddr (expr); |
448 Real y1 = robust_scm2double (scm_car (expr), 0.0); | 601 Real y1 = robust_scm2double (scm_car (expr), 0.0); |
449 expr = scm_cdr (expr); | 602 expr = scm_cdr (expr); |
450 Real x2 = robust_scm2double (scm_car (expr), 0.0); | 603 Real x2 = robust_scm2double (scm_car (expr), 0.0); |
451 expr = scm_cdr (expr); | 604 expr = scm_cdr (expr); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
483 else | 636 else |
484 { | 637 { |
485 warning ("Malformed path for path stencil."); | 638 warning ("Malformed path for path stencil."); |
486 return out; | 639 return out; |
487 } | 640 } |
488 first = false; | 641 first = false; |
489 } | 642 } |
490 return scm_reverse_x (out, SCM_EOL); | 643 return scm_reverse_x (out, SCM_EOL); |
491 } | 644 } |
492 | 645 |
493 vector<Box> | 646 void |
494 internal_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) |
495 { | 648 { |
496 vector<Box> boxes; | |
497 SCM blot = scm_car (expr); | 649 SCM blot = scm_car (expr); |
498 expr = scm_cdr (expr); | 650 expr = scm_cdr (expr); |
499 SCM path = all_commands_to_absolute_and_group (expr); | 651 SCM path = all_commands_to_absolute_and_group (expr); |
500 // 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 |
501 ////////////////////// | 653 ////////////////////// |
502 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)) |
503 { | 655 { |
504 vector<Box> bxs = scm_to_int (scm_length (scm_car (s))) == 4 | 656 scm_to_int (scm_length (scm_car (s))) == 4 |
505 ? 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) |
506 : 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))); |
507 boxes.insert (boxes.end (), bxs.begin (), bxs.end ()); | 659 } |
508 } | 660 } |
509 return boxes; | 661 |
510 } | 662 void |
511 | 663 make_path_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings, Pan
goMatrix trans, SCM expr) |
512 vector<Box> | 664 { |
513 make_path_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); |
514 { | 666 } |
515 return internal_make_path_boxes (trans, scm_cons (scm_car (expr), get_path_lis
t (scm_cdr (expr)))); | 667 |
516 } | 668 void |
517 vector<Box> | 669 make_polygon_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings,
PangoMatrix trans, SCM expr) |
518 make_polygon_boxes (PangoMatrix trans, SCM expr) | 670 { |
519 { | |
520 vector<Box> boxes; | |
521 SCM coords = get_number_list (scm_car (expr)); | 671 SCM coords = get_number_list (scm_car (expr)); |
522 expr = scm_cdr (expr); | 672 expr = scm_cdr (expr); |
523 SCM blot_diameter = scm_car (expr); | 673 SCM blot_diameter = scm_car (expr); |
524 ////////////////////// | 674 ////////////////////// |
525 bool first = true; | 675 bool first = true; |
526 SCM l = SCM_EOL; | 676 SCM l = SCM_EOL; |
527 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)) |
528 { | 678 { |
529 l = scm_cons (first ? ly_symbol2scm ("moveto") : ly_symbol2scm ("lineto"),
l); | 679 l = scm_cons (first ? ly_symbol2scm ("moveto") : ly_symbol2scm ("lineto"),
l); |
530 l = scm_cons (scm_car (s), l); | 680 l = scm_cons (scm_car (s), l); |
531 l = scm_cons (scm_cadr (s), l); | 681 l = scm_cons (scm_cadr (s), l); |
532 first = false; | 682 first = false; |
533 } | 683 } |
534 l = scm_cons (ly_symbol2scm ("closepath"), l); | 684 l = scm_cons (ly_symbol2scm ("closepath"), l); |
535 return internal_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); |
536 } | 686 } |
537 | 687 |
538 vector<Box> | 688 void |
539 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) |
540 { | 690 { |
541 vector<Box> boxes; | 691 SCM fm_scm = scm_car (expr); |
542 Font_metric *fm = unsmob_metrics (scm_car (expr)); | 692 Font_metric *fm = unsmob_metrics (fm_scm); |
543 expr = scm_cdr (expr); | 693 expr = scm_cdr (expr); |
544 SCM glyph = scm_car (expr); | 694 SCM glyph = scm_car (expr); |
| 695 string glyph_s = ly_scm2string (glyph); |
| 696 |
545 ////////////////////// | 697 ////////////////////// |
546 string font_name = String_convert::to_lower (fm->font_name ()); | 698 Open_type_font *open_fm |
547 SCM box_table = ly_lily_module_constant ("box-hash"); | 699 = dynamic_cast<Open_type_font *> |
548 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 ()); |
549 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"); |
550 Stencil m = fm->find_by_name (ly_scm2string (glyph)); | 702 |
551 // mmx and mmy give the bounding box for the original stencil | 703 size_t gidx = open_fm->name_to_index (glyph_s); |
552 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); |
553 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); |
554 // xex and yex give the bounding box for the current stencil | 706 SCM outline = open_fm->get_glyph_outline (gidx); |
555 Interval xex = m.extent (X_AXIS); | 707 Box real_bbox = fm->get_indexed_char_dimensions (gidx); |
556 Interval yex = m.extent (Y_AXIS); | 708 |
557 Offset scale (xex.length () / mmx.length (), yex.length () / mmy.length ()); | 709 /* |
558 // 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 |
559 pango_matrix_translate (&trans, xex[LEFT], yex[DOWN]); | 711 real_bbox may not be the one that freetype calculates. |
560 pango_matrix_scale (&trans, scale[X_AXIS], scale[Y_AXIS]); | 712 |
561 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 |
562 ////////////////////// | 723 ////////////////////// |
563 for (SCM s = ly_assoc_get (ly_symbol2scm ("paths"), glyph_info, SCM_EOL); | 724 for (SCM s = outline; |
564 scm_is_pair (s); | 725 scm_is_pair (s); |
565 s = scm_cdr (s)) | 726 s = scm_cdr (s)) |
566 { | 727 { |
567 vector<Box> bxs = scm_to_int (scm_length (scm_car (s))) == 4 | 728 scm_to_int (scm_length (scm_car (s))) == 4 |
568 ? 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) |
569 : 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))); |
570 boxes.insert (boxes.end (), bxs.begin (), bxs.end ()); | 731 } |
571 } | 732 } |
572 return boxes; | 733 |
573 } | 734 void |
574 | 735 make_glyph_string_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildi
ngs, PangoMatrix trans, SCM expr) |
575 vector<Box> | 736 { |
576 make_glyph_string_boxes (PangoMatrix trans, SCM expr) | 737 SCM fm_scm = scm_car (expr); |
577 { | 738 Font_metric *fm = unsmob_metrics (fm_scm); |
578 vector<Box> boxes; | 739 expr = scm_cdr (expr); |
579 expr = scm_cdr (expr); // font-name | 740 expr = scm_cdr (expr); // font-name |
580 expr = scm_cdr (expr); // size | 741 expr = scm_cdr (expr); // size |
581 expr = scm_cdr (expr); // cid? | 742 expr = scm_cdr (expr); // cid? |
582 SCM whxy = scm_cadar (expr); | 743 SCM whxy = scm_cadar (expr); |
583 vector<Real> widths; | 744 vector<Real> widths; |
584 vector<Interval> heights; | 745 vector<Interval> heights; |
585 vector<Real> xos; | 746 vector<Real> xos; |
586 vector<Real> yos; | 747 vector<Real> yos; |
| 748 vector<string> char_ids; |
587 ////////////////////// | 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 |
588 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)) |
589 { | 754 { |
590 SCM now = scm_car (s); | 755 SCM now = scm_car (s); |
591 widths.push_back (robust_scm2double (scm_car (now), 0.0)); | 756 widths.push_back (robust_scm2double (scm_car (now), 0.0)); |
592 now = scm_cdr (now); | 757 now = scm_cdr (now); |
593 heights.push_back (robust_scm2interval (scm_car (now), Interval (0,0))); | 758 heights.push_back (robust_scm2interval (scm_car (now), Interval (0, 0))); |
594 now = scm_cdr (now); | 759 now = scm_cdr (now); |
595 xos.push_back (robust_scm2double (scm_car (now), 0.0)); | 760 xos.push_back (robust_scm2double (scm_car (now), 0.0)); |
596 now = scm_cdr (now); | 761 now = scm_cdr (now); |
597 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), "")); |
598 } | 765 } |
599 Real cumulative_x = 0.0; | 766 Real cumulative_x = 0.0; |
600 for (vsize i = 0; i < widths.size (); i++) | 767 for (vsize i = 0; i < widths.size (); i++) |
601 { | 768 { |
| 769 PangoMatrix transcopy (trans); |
602 Offset pt0 (cumulative_x + xos[i], heights[i][DOWN] + yos[i]); | 770 Offset pt0 (cumulative_x + xos[i], heights[i][DOWN] + yos[i]); |
603 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]); |
604 pango_matrix_transform_point (&trans, &pt0[X_AXIS], &pt0[Y_AXIS]); | |
605 pango_matrix_transform_point (&trans, &pt1[X_AXIS], &pt1[Y_AXIS]); | |
606 Box b; | |
607 b.add_point (pt0); | |
608 b.add_point (pt1); | |
609 boxes.push_back (b); | |
610 cumulative_x += widths[i]; | 772 cumulative_x += widths[i]; |
611 } | 773 |
612 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 } |
613 } | 820 } |
614 | 821 |
615 /* | 822 /* |
616 receives a stencil expression and a transform matrix | 823 receives a stencil expression and a transform matrix |
617 depending on the stencil name, dispatches it to the appropriate function | 824 depending on the stencil name, dispatches it to the appropriate function |
618 */ | 825 */ |
619 | 826 |
620 vector<Box> | 827 void |
621 stencil_dispatcher (PangoMatrix trans, SCM expr) | 828 stencil_dispatcher (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings,
PangoMatrix trans, SCM expr) |
622 { | 829 { |
623 if (not scm_is_pair (expr)) | 830 if (not scm_is_pair (expr)) |
624 return vector<Box> (); | 831 return; |
625 if (scm_car (expr) == ly_symbol2scm ("draw-line")) | 832 if (scm_car (expr) == ly_symbol2scm ("draw-line")) |
626 return make_draw_line_boxes (trans, scm_cdr (expr)); | 833 make_draw_line_boxes (boxes, buildings, trans, scm_cdr (expr), true); |
627 else if (scm_car (expr) == ly_symbol2scm ("dashed-line")) | 834 else if (scm_car (expr) == ly_symbol2scm ("dashed-line")) |
628 { | 835 { |
629 expr = scm_cdr (expr); | 836 expr = scm_cdr (expr); |
630 SCM th = scm_car (expr); | 837 SCM th = scm_car (expr); |
631 expr = scm_cdr (expr); | 838 expr = scm_cdr (expr); |
632 expr = scm_cdr (expr); // on | 839 expr = scm_cdr (expr); // on |
633 expr = scm_cdr (expr); // off | 840 expr = scm_cdr (expr); // off |
634 SCM x1 = scm_car (expr); | 841 SCM x1 = scm_car (expr); |
635 expr = scm_cdr (expr); | 842 expr = scm_cdr (expr); |
636 SCM x2 = scm_car (expr); | 843 SCM x2 = scm_car (expr); |
637 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); |
638 } | 845 } |
639 else if (scm_car (expr) == ly_symbol2scm ("circle")) | 846 else if (scm_car (expr) == ly_symbol2scm ("circle")) |
640 { | 847 { |
641 expr = scm_cdr (expr); | 848 expr = scm_cdr (expr); |
642 SCM rad = scm_car (expr); | 849 SCM rad = scm_car (expr); |
643 expr = scm_cdr (expr); | 850 expr = scm_cdr (expr); |
644 SCM th = scm_car (expr); | 851 SCM th = scm_car (expr); |
645 return make_partial_ellipse_boxes (trans, | 852 make_partial_ellipse_boxes (boxes, buildings, trans, |
646 scm_list_n (rad, | 853 scm_list_n (rad, |
647 rad, | 854 rad, |
648 scm_from_double (0.0), | 855 scm_from_double (0.0), |
649 scm_from_double (360.0), | 856 scm_from_double (360.0), |
650 th, | 857 th, |
651 SCM_BOOL_F, | 858 SCM_BOOL_F, |
652 SCM_BOOL_T, | 859 SCM_BOOL_T, |
653 SCM_UNDEFINED)); | 860 SCM_UNDEFINED)); |
654 } | 861 } |
655 else if (scm_car (expr) == ly_symbol2scm ("ellipse")) | 862 else if (scm_car (expr) == ly_symbol2scm ("ellipse")) |
656 { | 863 { |
657 expr = scm_cdr (expr); | 864 expr = scm_cdr (expr); |
658 SCM x_rad = scm_car (expr); | 865 SCM x_rad = scm_car (expr); |
659 expr = scm_cdr (expr); | 866 expr = scm_cdr (expr); |
660 SCM y_rad = scm_car (expr); | 867 SCM y_rad = scm_car (expr); |
661 expr = scm_cdr (expr); | 868 expr = scm_cdr (expr); |
662 SCM th = scm_car (expr); | 869 SCM th = scm_car (expr); |
663 return make_partial_ellipse_boxes (trans, | 870 make_partial_ellipse_boxes (boxes, buildings, trans, |
664 scm_list_n (x_rad, | 871 scm_list_n (x_rad, |
665 y_rad, | 872 y_rad, |
666 scm_from_double (0.0), | 873 scm_from_double (0.0), |
667 scm_from_double (360.0), | 874 scm_from_double (360.0), |
668 th, | 875 th, |
669 SCM_BOOL_F, | 876 SCM_BOOL_F, |
670 SCM_BOOL_T, | 877 SCM_BOOL_T, |
671 SCM_UNDEFINED)); | 878 SCM_UNDEFINED)); |
672 } | 879 } |
673 else if (scm_car (expr) == ly_symbol2scm ("partial-ellipse")) | 880 else if (scm_car (expr) == ly_symbol2scm ("partial-ellipse")) |
674 return make_partial_ellipse_boxes (trans, scm_cdr (expr)); | 881 make_partial_ellipse_boxes (boxes, buildings, trans, scm_cdr (expr)); |
675 else if (scm_car (expr) == ly_symbol2scm ("round-filled-box")) | 882 else if (scm_car (expr) == ly_symbol2scm ("round-filled-box")) |
676 return make_round_filled_box_boxes (trans, scm_cdr (expr)); | 883 make_round_filled_box_boxes (boxes, trans, scm_cdr (expr)); |
677 else if (scm_car (expr) == ly_symbol2scm ("named-glyph")) | 884 else if (scm_car (expr) == ly_symbol2scm ("named-glyph")) |
678 return make_named_glyph_boxes (trans, scm_cdr (expr)); | 885 make_named_glyph_boxes (boxes, buildings, trans, scm_cdr (expr)); |
679 else if (scm_car (expr) == ly_symbol2scm ("polygon")) | 886 else if (scm_car (expr) == ly_symbol2scm ("polygon")) |
680 return make_polygon_boxes (trans, scm_cdr (expr)); | 887 make_polygon_boxes (boxes, buildings, trans, scm_cdr (expr)); |
681 else if (scm_car (expr) == ly_symbol2scm ("path")) | 888 else if (scm_car (expr) == ly_symbol2scm ("path")) |
682 return make_path_boxes (trans, scm_cdr (expr)); | 889 make_path_boxes (boxes, buildings, trans, scm_cdr (expr)); |
683 else if (scm_car (expr) == ly_symbol2scm ("glyph-string")) | 890 else if (scm_car (expr) == ly_symbol2scm ("glyph-string")) |
684 return make_glyph_string_boxes (trans, scm_cdr (expr)); | 891 make_glyph_string_boxes (boxes, buildings, trans, scm_cdr (expr)); |
685 else | 892 else |
686 { | 893 { |
687 #if 0 | 894 #if 0 |
688 warning ("Stencil expression not supported by the veritcal skylines."); | 895 warning ("Stencil expression not supported by the veritcal skylines."); |
689 #endif | 896 #endif |
690 /* | 897 /* |
691 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 |
692 is doing stencil-checking correctly. | 899 is doing stencil-checking correctly. |
693 */ | 900 */ |
694 return vector<Box> (); | |
695 } | 901 } |
696 } | 902 } |
697 | 903 |
698 /* | 904 /* |
699 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 |
700 the struct Transform_matrix_and_expression contains two members, | 906 the struct Transform_matrix_and_expression contains two members, |
701 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 |
702 to show how to construct the stencil | 908 to show how to construct the stencil |
703 */ | 909 */ |
704 vector<Transform_matrix_and_expression> | 910 vector<Transform_matrix_and_expression> |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
755 else | 961 else |
756 { | 962 { |
757 vector<Transform_matrix_and_expression> out; | 963 vector<Transform_matrix_and_expression> out; |
758 out.push_back (Transform_matrix_and_expression (trans, expr)); | 964 out.push_back (Transform_matrix_and_expression (trans, expr)); |
759 return out; | 965 return out; |
760 } | 966 } |
761 warning ("Stencil expression not supported by the veritcal skylines."); | 967 warning ("Stencil expression not supported by the veritcal skylines."); |
762 return vector<Transform_matrix_and_expression> (); | 968 return vector<Transform_matrix_and_expression> (); |
763 } | 969 } |
764 | 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 |
765 MAKE_SCHEME_CALLBACK (Grob, vertical_skylines_from_stencil, 1); | 1035 MAKE_SCHEME_CALLBACK (Grob, vertical_skylines_from_stencil, 1); |
766 SCM | 1036 SCM |
767 Grob::vertical_skylines_from_stencil (SCM smob) | 1037 Grob::vertical_skylines_from_stencil (SCM smob) |
768 { | 1038 { |
769 Grob *me = unsmob_grob (smob); | 1039 Grob *me = unsmob_grob (smob); |
770 Stencil *s = unsmob_stencil (me->get_property ("stencil")); | 1040 |
771 if (!s) | 1041 Real pad = robust_scm2double (me->get_property ("skyline-horizontal-padding"),
0.0); |
772 return Skyline_pair ().smobbed_copy (); | 1042 SCM out = Stencil::skylines_from_stencil (me->get_property ("stencil"), pad, X
_AXIS); |
773 vector<Transform_matrix_and_expression> data = | 1043 |
774 stencil_traverser (make_transform_matrix (1.0,0.0,0.0,1.0,0.0,0.0), | 1044 return out; |
775 s->expr ()); | 1045 } |
776 vector<Box> boxes; | 1046 |
777 for (vsize i = 0; i < data.size (); i++) | 1047 MAKE_SCHEME_CALLBACK (Grob, horizontal_skylines_from_stencil, 1); |
778 { | |
779 vector<Box> bxs = stencil_dispatcher (data[i].tm_, data[i].expr_); | |
780 boxes.insert (boxes.end (), bxs.begin (), bxs.end ()); | |
781 } | |
782 if (!boxes.size ()) | |
783 { | |
784 // we use the bounding box | |
785 boxes.push_back (Box (s->extent (X_AXIS), s->extent (Y_AXIS))); | |
786 } | |
787 return Skyline_pair (boxes, 0.0, X_AXIS).smobbed_copy (); | |
788 } | |
789 | |
790 MAKE_SCHEME_CALLBACK (Grob, vertical_skylines_from_element_stencils, 1); | |
791 SCM | 1048 SCM |
792 Grob::vertical_skylines_from_element_stencils (SCM smob) | 1049 Grob::horizontal_skylines_from_stencil (SCM smob) |
793 { | 1050 { |
794 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 |
795 extract_grob_set (me, "elements", elts); | 1064 extract_grob_set (me, "elements", elts); |
796 vector<Real> x_pos; | 1065 vector<Real> x_pos; |
797 vector<Real> y_pos; | 1066 vector<Real> y_pos; |
798 Grob *x_common = common_refpoint_of_array (elts, me, X_AXIS); | 1067 Grob *x_common = common_refpoint_of_array (elts, me, X_AXIS); |
799 Grob *y_common = common_refpoint_of_array (elts, me, Y_AXIS); | 1068 Grob *y_common = common_refpoint_of_array (elts, me, Y_AXIS); |
800 for (vsize i = 0; i < elts.size (); i++) | 1069 for (vsize i = 0; i < elts.size (); i++) |
801 { | 1070 { |
802 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)); |
803 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)); |
804 } | 1073 } |
805 Real my_x = me->relative_coordinate (x_common, X_AXIS); | 1074 Real my_x = me->relative_coordinate (x_common, X_AXIS); |
806 Real my_y = me->relative_coordinate (y_common, Y_AXIS); | 1075 Real my_y = me->relative_coordinate (y_common, Y_AXIS); |
807 Skyline_pair res; | 1076 Skyline_pair res; |
808 for (vsize i = 0; i < elts.size (); i++) | 1077 for (vsize i = 0; i < elts.size (); i++) |
809 { | 1078 { |
810 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")); |
811 if (skyp) | 1080 if (skyp) |
812 { | 1081 { |
813 /* | 1082 /* |
814 Here, copying is essential. Otherwise, the skyline pair will | 1083 Here, copying is essential. Otherwise, the skyline pair will |
815 get doubly shifted! | 1084 get doubly shifted! |
816 */ | 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 */ |
817 Skyline_pair copy = Skyline_pair (*skyp); | 1092 Skyline_pair copy = Skyline_pair (*skyp); |
818 copy.shift (x_pos[i] - my_x); | 1093 if (a == X_AXIS) |
819 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 } |
820 res.merge (copy); | 1103 res.merge (copy); |
821 } | 1104 } |
822 } | 1105 } |
823 return res.smobbed_copy (); | 1106 return res.smobbed_copy (); |
824 } | 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 |