LEFT | RIGHT |
(no file at all) | |
| 1 /* |
| 2 This file is part of LilyPond, the GNU music typesetter. |
| 3 |
| 4 Copyright (C) 2012 Mike Solomon <mike@apollinemike.com> |
| 5 |
| 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 |
| 8 the Free Software Foundation, either version 3 of the License, or |
| 9 (at your option) any later version. |
| 10 |
| 11 LilyPond is distributed in the hope that it will be useful, |
| 12 but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 GNU General Public License for more details. |
| 15 |
| 16 You should have received a copy of the GNU General Public License |
| 17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>. |
| 18 */ |
| 19 |
| 20 /* |
| 21 tools for transform-matrices following the standard at |
| 22 http://www.w3.org/TR/SVG/coords.html |
| 23 |
| 24 a list in the form |
| 25 (list a b c d e f g) |
| 26 becomes this matrix: |
| 27 [ a c e ] |
| 28 [ b d f ] |
| 29 [ 0 0 1 ] |
| 30 when this transforms a point (x,y), the point is written as matrix: |
| 31 [ x ] |
| 32 [ y ] |
| 33 [ 1 ] |
| 34 */ |
| 35 |
| 36 #include <pango/pango-matrix.h> |
| 37 #include <complex> |
| 38 #include "box.hh" |
| 39 #include "bezier.hh" |
| 40 #include "font-metric.hh" |
| 41 #include "grob.hh" |
| 42 #include "interval.hh" |
| 43 #include "freetype.hh" |
| 44 #include "misc.hh" |
| 45 #include "offset.hh" |
| 46 #include "modified-font-metric.hh" |
| 47 #include "open-type-font.hh" |
| 48 #include "pango-font.hh" |
| 49 #include "pointer-group-interface.hh" |
| 50 #include "lily-guile.hh" |
| 51 #include "real.hh" |
| 52 #include "stencil.hh" |
| 53 #include "string-convert.hh" |
| 54 #include "skyline.hh" |
| 55 #include "skyline-pair.hh" |
| 56 using namespace std; |
| 57 |
| 58 Real QUANTIZATION_UNIT = 0.2; |
| 59 |
| 60 void create_path_cap (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings
, PangoMatrix trans, Offset pt, Real rad, Real slope, Direction d); |
| 61 |
| 62 struct Transform_matrix_and_expression |
| 63 { |
| 64 PangoMatrix tm_; |
| 65 SCM expr_; |
| 66 |
| 67 Transform_matrix_and_expression (PangoMatrix tm, SCM expr); |
| 68 }; |
| 69 |
| 70 Transform_matrix_and_expression::Transform_matrix_and_expression (PangoMatrix tm
, SCM expr) |
| 71 { |
| 72 tm_ = tm; |
| 73 expr_ = expr; |
| 74 } |
| 75 |
| 76 PangoMatrix |
| 77 make_transform_matrix (Real p0, Real p1, Real p2, Real p3, Real p4, Real p5) |
| 78 { |
| 79 PangoMatrix out; |
| 80 out.xx = p0; |
| 81 out.xy = p1; |
| 82 out.yx = p2; |
| 83 out.yy = p3; |
| 84 out.x0 = p4; |
| 85 out.y0 = p5; |
| 86 return out; |
| 87 } |
| 88 |
| 89 //// UTILITY FUNCTIONS |
| 90 |
| 91 /* |
| 92 map x's placement between orig_l and orig_r onto |
| 93 the interval final_l final_r |
| 94 */ |
| 95 Real |
| 96 linear_map (Real final_l, Real final_r, Real orig_l, Real orig_r, Real x) |
| 97 { |
| 98 return final_l + ((final_r - final_l) * ((x - orig_l) / (orig_r - orig_l))); |
| 99 } |
| 100 |
| 101 /* |
| 102 from a nested SCM list, return the first list of numbers |
| 103 useful for polygons |
| 104 */ |
| 105 SCM |
| 106 get_number_list (SCM l) |
| 107 { |
| 108 if (scm_is_pair (l)) |
| 109 { |
| 110 if (scm_is_number (scm_car (l))) |
| 111 return l; |
| 112 SCM res = get_number_list (scm_car (l)); |
| 113 if (res == SCM_BOOL_F) |
| 114 return get_number_list (scm_cdr (l)); |
| 115 return res; |
| 116 } |
| 117 return SCM_BOOL_F; |
| 118 } |
| 119 |
| 120 /* |
| 121 from a nested SCM list, return the first list of numbers |
| 122 useful for paths |
| 123 */ |
| 124 SCM |
| 125 get_path_list (SCM l) |
| 126 { |
| 127 if (scm_is_pair (l)) |
| 128 { |
| 129 if (scm_memv (scm_car (l), |
| 130 scm_list_n (ly_symbol2scm ("moveto"), |
| 131 ly_symbol2scm ("rmoveto"), |
| 132 ly_symbol2scm ("lineto"), |
| 133 ly_symbol2scm ("rlineto"), |
| 134 ly_symbol2scm ("curveto"), |
| 135 ly_symbol2scm ("rcurveto"), |
| 136 ly_symbol2scm ("closepath"), |
| 137 SCM_UNDEFINED)) |
| 138 != SCM_BOOL_F) |
| 139 return l; |
| 140 SCM res = get_path_list (scm_car (l)); |
| 141 if (res == SCM_BOOL_F) |
| 142 return get_path_list (scm_cdr (l)); |
| 143 return res; |
| 144 } |
| 145 return SCM_BOOL_F; |
| 146 } |
| 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 |
| 158 //// END UTILITY FUNCTIONS |
| 159 |
| 160 /* |
| 161 below, for all of the functions make_X_boxes, the expression |
| 162 is always unpacked into variables. |
| 163 then, after a line of /////, there are manipulations of these variables |
| 164 (there may be no manipulations necessary depending on the function) |
| 165 afterwards, there is another ///// followed by the creation of points |
| 166 and boxes |
| 167 */ |
| 168 |
| 169 void |
| 170 make_draw_line_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings
, PangoMatrix trans, SCM expr, bool use_building) |
| 171 { |
| 172 Real thick = robust_scm2double (scm_car (expr), 0.0); |
| 173 expr = scm_cdr (expr); |
| 174 Real x0 = robust_scm2double (scm_car (expr), 0.0); |
| 175 expr = scm_cdr (expr); |
| 176 Real y0 = robust_scm2double (scm_car (expr), 0.0); |
| 177 expr = scm_cdr (expr); |
| 178 Real x1 = robust_scm2double (scm_car (expr), 0.0); |
| 179 expr = scm_cdr (expr); |
| 180 Real y1 = robust_scm2double (scm_car (expr), 0.0); |
| 181 Real slope = x1 == x0 ? infinity_f : (y1 - y0) / (x1 - x0); |
| 182 ////////////////////// |
| 183 if (x1 < x0) |
| 184 { |
| 185 swap (x0, x1); |
| 186 swap (y0, y1); |
| 187 } |
| 188 Offset left (x0, y0); |
| 189 Offset right (x1, y1); |
| 190 Direction d = DOWN; |
| 191 do |
| 192 { |
| 193 Offset inter_l = get_point_in_y_direction (left, perpendicular_slope (slop
e), thick / 2, d); |
| 194 Offset inter_r = get_point_in_y_direction (right, perpendicular_slope (slo
pe), thick / 2, d); |
| 195 pango_matrix_transform_point (&trans, &inter_l[X_AXIS], &inter_l[Y_AXIS]); |
| 196 pango_matrix_transform_point (&trans, &inter_r[X_AXIS], &inter_r[Y_AXIS]); |
| 197 if ((inter_l[X_AXIS] == inter_r[X_AXIS]) || (inter_l[Y_AXIS] == inter_r[Y_
AXIS])) |
| 198 { |
| 199 Box b; |
| 200 b.add_point (inter_l); |
| 201 b.add_point (inter_r); |
| 202 boxes.push_back (b); |
| 203 } |
| 204 else if (use_building) |
| 205 buildings.push_back (Drul_array<Offset> (inter_l, inter_r)); |
| 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 { |
| 261 Real x_rad = robust_scm2double (scm_car (expr), 0.0); |
| 262 expr = scm_cdr (expr); |
| 263 Real y_rad = robust_scm2double (scm_car (expr), 0.0); |
| 264 expr = scm_cdr (expr); |
| 265 Real start = robust_scm2double (scm_car (expr), 0.0); |
| 266 expr = scm_cdr (expr); |
| 267 Real end = robust_scm2double (scm_car (expr), 0.0); |
| 268 expr = scm_cdr (expr); |
| 269 Real th = robust_scm2double (scm_car (expr), 0.0); |
| 270 expr = scm_cdr (expr); |
| 271 bool connect = to_boolean (scm_car (expr)); |
| 272 expr = scm_cdr (expr); |
| 273 bool fill = to_boolean (scm_car (expr)); |
| 274 ////////////////////// |
| 275 start = M_PI * start / 180; |
| 276 end = M_PI * end / 180; |
| 277 if (end == start) |
| 278 end += (2 * M_PI); |
| 279 complex<Real> sunit = polar (1.0, start); |
| 280 complex<Real> eunit = polar (1.0, end); |
| 281 Offset sp (real (sunit) * x_rad, imag (sunit) * y_rad); |
| 282 Offset ep (real (eunit) * x_rad, imag (eunit) * y_rad); |
| 283 ////////////////////// |
| 284 Drul_array<vector<Offset> > points; |
| 285 Direction d = DOWN; |
| 286 int quantization = max (1, (int) (((x_rad * trans.xx) + (y_rad * trans.yy)) *
M_PI / QUANTIZATION_UNIT)); |
| 287 do |
| 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); |
| 329 Offset pt (real (coord) * x_rad, |
| 330 imag (coord) * y_rad); |
| 331 Real slope = pt[Y_AXIS] / pt[X_AXIS]; |
| 332 create_path_cap (boxes, |
| 333 buildings, |
| 334 trans, |
| 335 pt, |
| 336 th / 2, |
| 337 perpendicular_slope (slope), |
| 338 Direction (sign (slope))); |
| 339 |
| 340 // end line cap |
| 341 coord = polar (1.0, start); |
| 342 pt = Offset (real (coord) * x_rad, |
| 343 imag (coord) * y_rad); |
| 344 slope = pt[Y_AXIS] / pt[X_AXIS]; |
| 345 create_path_cap (boxes, |
| 346 buildings, |
| 347 trans, |
| 348 pt, |
| 349 th / 2, |
| 350 perpendicular_slope (slope), |
| 351 Direction (sign (-slope))); |
| 352 } |
| 353 } |
| 354 |
| 355 void |
| 356 make_round_filled_box_boxes (vector<Box> &boxes, PangoMatrix trans, SCM expr) |
| 357 { |
| 358 Real left = robust_scm2double (scm_car (expr), 0.0); |
| 359 expr = scm_cdr (expr); |
| 360 Real right = robust_scm2double (scm_car (expr), 0.0); |
| 361 expr = scm_cdr (expr); |
| 362 Real bottom = robust_scm2double (scm_car (expr), 0.0); |
| 363 expr = scm_cdr (expr); |
| 364 Real top = robust_scm2double (scm_car (expr), 0.0); |
| 365 expr = scm_cdr (expr); |
| 366 Real th = robust_scm2double (scm_car (expr), 0.0); |
| 367 ////////////////////// |
| 368 vector<Offset> points; |
| 369 Box b; |
| 370 Offset p0 = Offset (-left - (th / 2), -bottom - (th / 2)); |
| 371 Offset p1 = Offset (right + (th / 2), top + (th / 2)); |
| 372 pango_matrix_transform_point (&trans, &p0[X_AXIS], &p0[Y_AXIS]); |
| 373 pango_matrix_transform_point (&trans, &p1[X_AXIS], &p1[Y_AXIS]); |
| 374 b.add_point (p0); |
| 375 b.add_point (p1); |
| 376 boxes.push_back (b); |
| 377 } |
| 378 |
| 379 void |
| 380 create_path_cap (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings, Pan
goMatrix trans, Offset pt, Real rad, Real slope, Direction d) |
| 381 { |
| 382 Real angle = atan (slope) * 180 / M_PI; |
| 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 { |
| 409 Real th = robust_scm2double (scm_car (expr), 0.0); |
| 410 expr = scm_cdr (expr); |
| 411 Real x0 = robust_scm2double (scm_car (expr), 0.0); |
| 412 expr = scm_cdr (expr); |
| 413 Real y0 = robust_scm2double (scm_car (expr), 0.0); |
| 414 expr = scm_cdr (expr); |
| 415 Real x1 = robust_scm2double (scm_car (expr), 0.0); |
| 416 expr = scm_cdr (expr); |
| 417 Real y1 = robust_scm2double (scm_car (expr), 0.0); |
| 418 expr = scm_cdr (expr); |
| 419 Real x2 = robust_scm2double (scm_car (expr), 0.0); |
| 420 expr = scm_cdr (expr); |
| 421 Real y2 = robust_scm2double (scm_car (expr), 0.0); |
| 422 expr = scm_cdr (expr); |
| 423 Real x3 = robust_scm2double (scm_car (expr), 0.0); |
| 424 expr = scm_cdr (expr); |
| 425 Real y3 = robust_scm2double (scm_car (expr), 0.0); |
| 426 ////////////////////// |
| 427 Bezier curve; |
| 428 curve.control_[0] = Offset (x0, y0); |
| 429 curve.control_[1] = Offset (x1, y1); |
| 430 curve.control_[2] = Offset (x2, y2); |
| 431 curve.control_[3] = Offset (x3, y3); |
| 432 Offset temp0 (x0, y0); |
| 433 Offset temp1 (x1, y1); |
| 434 Offset temp2 (x2, y2); |
| 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]); |
| 440 ////////////////////// |
| 441 Drul_array<vector<Offset> > points; |
| 442 Direction d = DOWN; |
| 443 int quantization = int (((temp1 - temp0).length () |
| 444 + (temp2 - temp1).length () |
| 445 + (temp3 - temp2).length ()) |
| 446 / QUANTIZATION_UNIT); |
| 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++) |
| 466 { |
| 467 Box b; |
| 468 do |
| 469 { |
| 470 b.add_point (points[d][i]); |
| 471 b.add_point (points[d][i + 1]); |
| 472 } |
| 473 while (flip (&d) != DOWN); |
| 474 boxes.push_back (b); |
| 475 } |
| 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 } |
| 507 } |
| 508 |
| 509 /* |
| 510 converts a path into lists of 4 (line) or 8 (curve) absolute coordinates |
| 511 for example: |
| 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) |
| 513 becomes |
| 514 '((1 2 3 4) |
| 515 (3 4 2 3) |
| 516 (2 3 3 3 5 5 6 6) |
| 517 (6 6 5 5 4 4 3 3) |
| 518 (3 3 1 2)) |
| 519 */ |
| 520 |
| 521 SCM |
| 522 all_commands_to_absolute_and_group (SCM expr) |
| 523 { |
| 524 SCM out = SCM_EOL; |
| 525 Offset start (0, 0); |
| 526 Offset current (0, 0); |
| 527 bool first = true; |
| 528 while (scm_is_pair (expr)) |
| 529 { |
| 530 if (scm_car (expr) == ly_symbol2scm ("moveto") |
| 531 || (scm_car (expr) == ly_symbol2scm ("rmoveto") && first)) |
| 532 { |
| 533 Real x = robust_scm2double (scm_cadr (expr), 0.0); |
| 534 Real y = robust_scm2double (scm_caddr (expr), 0.0); |
| 535 start = Offset (x, y); |
| 536 current = start; |
| 537 expr = scm_cdddr (expr); |
| 538 } |
| 539 if (scm_car (expr) == ly_symbol2scm ("rmoveto")) |
| 540 { |
| 541 Real x = robust_scm2double (scm_cadr (expr), 0.0); |
| 542 Real y = robust_scm2double (scm_caddr (expr), 0.0); |
| 543 start = (Offset (x, y) + current); |
| 544 current = start; |
| 545 expr = scm_cdddr (expr); |
| 546 } |
| 547 else if (scm_car (expr) == ly_symbol2scm ("lineto")) |
| 548 { |
| 549 Real x = robust_scm2double (scm_cadr (expr), 0.0); |
| 550 Real y = robust_scm2double (scm_caddr (expr), 0.0); |
| 551 out = scm_cons (scm_list_4 (scm_from_double (current[X_AXIS]), |
| 552 scm_from_double (current[Y_AXIS]), |
| 553 scm_from_double (x), |
| 554 scm_from_double (y)), |
| 555 out); |
| 556 current = Offset (x, y); |
| 557 expr = scm_cdddr (expr); |
| 558 } |
| 559 else if (scm_car (expr) == ly_symbol2scm ("rlineto")) |
| 560 { |
| 561 Real x = robust_scm2double (scm_cadr (expr), 0.0); |
| 562 Real y = robust_scm2double (scm_caddr (expr), 0.0); |
| 563 out = scm_cons (scm_list_4 (scm_from_double (current[X_AXIS]), |
| 564 scm_from_double (current[Y_AXIS]), |
| 565 scm_from_double (x + current[X_AXIS]), |
| 566 scm_from_double (y + current[Y_AXIS])), |
| 567 out); |
| 568 current = (Offset (x, y) + current); |
| 569 expr = scm_cdddr (expr); |
| 570 } |
| 571 else if (scm_car (expr) == ly_symbol2scm ("curveto")) |
| 572 { |
| 573 Real x1 = robust_scm2double (scm_cadr (expr), 0.0); |
| 574 expr = scm_cddr (expr); |
| 575 Real y1 = robust_scm2double (scm_car (expr), 0.0); |
| 576 expr = scm_cdr (expr); |
| 577 Real x2 = robust_scm2double (scm_car (expr), 0.0); |
| 578 expr = scm_cdr (expr); |
| 579 Real y2 = robust_scm2double (scm_car (expr), 0.0); |
| 580 expr = scm_cdr (expr); |
| 581 Real x3 = robust_scm2double (scm_car (expr), 0.0); |
| 582 expr = scm_cdr (expr); |
| 583 Real y3 = robust_scm2double (scm_car (expr), 0.0); |
| 584 expr = scm_cdr (expr); |
| 585 out = scm_cons (scm_list_n (scm_from_double (current[X_AXIS]), |
| 586 scm_from_double (current[Y_AXIS]), |
| 587 scm_from_double (x1), |
| 588 scm_from_double (y1), |
| 589 scm_from_double (x2), |
| 590 scm_from_double (y2), |
| 591 scm_from_double (x3), |
| 592 scm_from_double (y3), |
| 593 SCM_UNDEFINED), |
| 594 out); |
| 595 current = Offset (x3, y3); |
| 596 } |
| 597 else if (scm_car (expr) == ly_symbol2scm ("rcurveto")) |
| 598 { |
| 599 Real x1 = robust_scm2double (scm_cadr (expr), 0.0); |
| 600 expr = scm_cddr (expr); |
| 601 Real y1 = robust_scm2double (scm_car (expr), 0.0); |
| 602 expr = scm_cdr (expr); |
| 603 Real x2 = robust_scm2double (scm_car (expr), 0.0); |
| 604 expr = scm_cdr (expr); |
| 605 Real y2 = robust_scm2double (scm_car (expr), 0.0); |
| 606 expr = scm_cdr (expr); |
| 607 Real x3 = robust_scm2double (scm_car (expr), 0.0); |
| 608 expr = scm_cdr (expr); |
| 609 Real y3 = robust_scm2double (scm_car (expr), 0.0); |
| 610 expr = scm_cdr (expr); |
| 611 out = scm_cons (scm_list_n (scm_from_double (current[X_AXIS]), |
| 612 scm_from_double (current[Y_AXIS]), |
| 613 scm_from_double (x1 + current[X_AXIS]), |
| 614 scm_from_double (y1 + current[Y_AXIS]), |
| 615 scm_from_double (x2 + current[X_AXIS]), |
| 616 scm_from_double (y2 + current[Y_AXIS]), |
| 617 scm_from_double (x3 + current[X_AXIS]), |
| 618 scm_from_double (y3 + current[Y_AXIS]), |
| 619 SCM_UNDEFINED), |
| 620 out); |
| 621 current = (Offset (x3, y3) + current); |
| 622 } |
| 623 else if (scm_car (expr) == ly_symbol2scm ("closepath")) |
| 624 { |
| 625 if ((current[X_AXIS] != start[X_AXIS]) || (current[Y_AXIS] != start[Y_
AXIS])) |
| 626 { |
| 627 out = scm_cons (scm_list_4 (scm_from_double (current[X_AXIS]), |
| 628 scm_from_double (current[Y_AXIS]), |
| 629 scm_from_double (start[X_AXIS]), |
| 630 scm_from_double (start[Y_AXIS])), |
| 631 out); |
| 632 current = start; |
| 633 } |
| 634 expr = scm_cdr (expr); |
| 635 } |
| 636 else |
| 637 { |
| 638 warning ("Malformed path for path stencil."); |
| 639 return out; |
| 640 } |
| 641 first = false; |
| 642 } |
| 643 return scm_reverse_x (out, SCM_EOL); |
| 644 } |
| 645 |
| 646 void |
| 647 internal_make_path_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &build
ings, PangoMatrix trans, SCM expr, bool use_building) |
| 648 { |
| 649 SCM blot = scm_car (expr); |
| 650 expr = scm_cdr (expr); |
| 651 SCM path = all_commands_to_absolute_and_group (expr); |
| 652 // note that expr has more stuff that we don't need after this - simply ignore
it |
| 653 ////////////////////// |
| 654 for (SCM s = path; scm_is_pair (s); s = scm_cdr (s)) |
| 655 { |
| 656 scm_to_int (scm_length (scm_car (s))) == 4 |
| 657 ? make_draw_line_boxes (boxes, buildings, trans, scm_cons (blot, scm_car (
s)), use_building) |
| 658 : make_draw_bezier_boxes (boxes, buildings, trans, scm_cons (blot, scm_car
(s))); |
| 659 } |
| 660 } |
| 661 |
| 662 void |
| 663 make_path_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings, Pan
goMatrix trans, SCM expr) |
| 664 { |
| 665 return internal_make_path_boxes (boxes, buildings, trans, scm_cons (scm_car (e
xpr), get_path_list (scm_cdr (expr))), false); |
| 666 } |
| 667 |
| 668 void |
| 669 make_polygon_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings,
PangoMatrix trans, SCM expr) |
| 670 { |
| 671 SCM coords = get_number_list (scm_car (expr)); |
| 672 expr = scm_cdr (expr); |
| 673 SCM blot_diameter = scm_car (expr); |
| 674 ////////////////////// |
| 675 bool first = true; |
| 676 SCM l = SCM_EOL; |
| 677 for (SCM s = coords; scm_is_pair (s); s = scm_cddr (s)) |
| 678 { |
| 679 l = scm_cons (first ? ly_symbol2scm ("moveto") : ly_symbol2scm ("lineto"),
l); |
| 680 l = scm_cons (scm_car (s), l); |
| 681 l = scm_cons (scm_cadr (s), l); |
| 682 first = false; |
| 683 } |
| 684 l = scm_cons (ly_symbol2scm ("closepath"), l); |
| 685 internal_make_path_boxes (boxes, buildings, trans, scm_cons (blot_diameter, sc
m_reverse_x (l, SCM_EOL)), true); |
| 686 } |
| 687 |
| 688 void |
| 689 make_named_glyph_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildin
gs, PangoMatrix trans, SCM expr) |
| 690 { |
| 691 SCM fm_scm = scm_car (expr); |
| 692 Font_metric *fm = unsmob_metrics (fm_scm); |
| 693 expr = scm_cdr (expr); |
| 694 SCM glyph = scm_car (expr); |
| 695 string glyph_s = ly_scm2string (glyph); |
| 696 |
| 697 ////////////////////// |
| 698 Open_type_font *open_fm |
| 699 = dynamic_cast<Open_type_font *> |
| 700 (dynamic_cast<Modified_font_metric *>(fm)->original_font ()); |
| 701 SCM_ASSERT_TYPE (open_fm, fm_scm, SCM_ARG1, __FUNCTION__, "OpenType font"); |
| 702 |
| 703 size_t gidx = open_fm->name_to_index (glyph_s); |
| 704 //Box bbox = open_fm->get_unscaled_indexed_char_dimensions (gidx); |
| 705 Box bbox = open_fm->get_unscaled_indexed_char_dimensions (gidx); |
| 706 SCM outline = open_fm->get_glyph_outline (gidx); |
| 707 Box real_bbox = fm->get_indexed_char_dimensions (gidx); |
| 708 |
| 709 /* |
| 710 Because extents for named glyphs are cached, the value of |
| 711 real_bbox may not be the one that freetype calculates. |
| 712 |
| 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 |
| 723 ////////////////////// |
| 724 for (SCM s = outline; |
| 725 scm_is_pair (s); |
| 726 s = scm_cdr (s)) |
| 727 { |
| 728 scm_to_int (scm_length (scm_car (s))) == 4 |
| 729 ? make_draw_line_boxes (boxes, buildings, trans, scm_cons (scm_from_double
(0), scm_car (s)), false) |
| 730 : make_draw_bezier_boxes (boxes, buildings, trans, scm_cons (scm_from_doub
le (0), scm_car (s))); |
| 731 } |
| 732 } |
| 733 |
| 734 void |
| 735 make_glyph_string_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildi
ngs, PangoMatrix trans, SCM expr) |
| 736 { |
| 737 SCM fm_scm = scm_car (expr); |
| 738 Font_metric *fm = unsmob_metrics (fm_scm); |
| 739 expr = scm_cdr (expr); |
| 740 expr = scm_cdr (expr); // font-name |
| 741 expr = scm_cdr (expr); // size |
| 742 expr = scm_cdr (expr); // cid? |
| 743 SCM whxy = scm_cadar (expr); |
| 744 vector<Real> widths; |
| 745 vector<Interval> heights; |
| 746 vector<Real> xos; |
| 747 vector<Real> yos; |
| 748 vector<string> char_ids; |
| 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 |
| 753 for (SCM s = whxy; scm_is_pair (s); s = scm_cdr (s)) |
| 754 { |
| 755 SCM now = scm_car (s); |
| 756 widths.push_back (robust_scm2double (scm_car (now), 0.0)); |
| 757 now = scm_cdr (now); |
| 758 heights.push_back (robust_scm2interval (scm_car (now), Interval (0, 0))); |
| 759 now = scm_cdr (now); |
| 760 xos.push_back (robust_scm2double (scm_car (now), 0.0)); |
| 761 now = scm_cdr (now); |
| 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), "")); |
| 765 } |
| 766 Real cumulative_x = 0.0; |
| 767 for (vsize i = 0; i < widths.size (); i++) |
| 768 { |
| 769 PangoMatrix transcopy (trans); |
| 770 Offset pt0 (cumulative_x + xos[i], heights[i][DOWN] + yos[i]); |
| 771 Offset pt1 (cumulative_x + widths[i] + xos[i], heights[i][UP] + yos[i]); |
| 772 cumulative_x += widths[i]; |
| 773 |
| 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 } |
| 820 } |
| 821 |
| 822 /* |
| 823 receives a stencil expression and a transform matrix |
| 824 depending on the stencil name, dispatches it to the appropriate function |
| 825 */ |
| 826 |
| 827 void |
| 828 stencil_dispatcher (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings,
PangoMatrix trans, SCM expr) |
| 829 { |
| 830 if (not scm_is_pair (expr)) |
| 831 return; |
| 832 if (scm_car (expr) == ly_symbol2scm ("draw-line")) |
| 833 make_draw_line_boxes (boxes, buildings, trans, scm_cdr (expr), true); |
| 834 else if (scm_car (expr) == ly_symbol2scm ("dashed-line")) |
| 835 { |
| 836 expr = scm_cdr (expr); |
| 837 SCM th = scm_car (expr); |
| 838 expr = scm_cdr (expr); |
| 839 expr = scm_cdr (expr); // on |
| 840 expr = scm_cdr (expr); // off |
| 841 SCM x1 = scm_car (expr); |
| 842 expr = scm_cdr (expr); |
| 843 SCM x2 = scm_car (expr); |
| 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); |
| 845 } |
| 846 else if (scm_car (expr) == ly_symbol2scm ("circle")) |
| 847 { |
| 848 expr = scm_cdr (expr); |
| 849 SCM rad = scm_car (expr); |
| 850 expr = scm_cdr (expr); |
| 851 SCM th = scm_car (expr); |
| 852 make_partial_ellipse_boxes (boxes, buildings, trans, |
| 853 scm_list_n (rad, |
| 854 rad, |
| 855 scm_from_double (0.0), |
| 856 scm_from_double (360.0), |
| 857 th, |
| 858 SCM_BOOL_F, |
| 859 SCM_BOOL_T, |
| 860 SCM_UNDEFINED)); |
| 861 } |
| 862 else if (scm_car (expr) == ly_symbol2scm ("ellipse")) |
| 863 { |
| 864 expr = scm_cdr (expr); |
| 865 SCM x_rad = scm_car (expr); |
| 866 expr = scm_cdr (expr); |
| 867 SCM y_rad = scm_car (expr); |
| 868 expr = scm_cdr (expr); |
| 869 SCM th = scm_car (expr); |
| 870 make_partial_ellipse_boxes (boxes, buildings, trans, |
| 871 scm_list_n (x_rad, |
| 872 y_rad, |
| 873 scm_from_double (0.0), |
| 874 scm_from_double (360.0), |
| 875 th, |
| 876 SCM_BOOL_F, |
| 877 SCM_BOOL_T, |
| 878 SCM_UNDEFINED)); |
| 879 } |
| 880 else if (scm_car (expr) == ly_symbol2scm ("partial-ellipse")) |
| 881 make_partial_ellipse_boxes (boxes, buildings, trans, scm_cdr (expr)); |
| 882 else if (scm_car (expr) == ly_symbol2scm ("round-filled-box")) |
| 883 make_round_filled_box_boxes (boxes, trans, scm_cdr (expr)); |
| 884 else if (scm_car (expr) == ly_symbol2scm ("named-glyph")) |
| 885 make_named_glyph_boxes (boxes, buildings, trans, scm_cdr (expr)); |
| 886 else if (scm_car (expr) == ly_symbol2scm ("polygon")) |
| 887 make_polygon_boxes (boxes, buildings, trans, scm_cdr (expr)); |
| 888 else if (scm_car (expr) == ly_symbol2scm ("path")) |
| 889 make_path_boxes (boxes, buildings, trans, scm_cdr (expr)); |
| 890 else if (scm_car (expr) == ly_symbol2scm ("glyph-string")) |
| 891 make_glyph_string_boxes (boxes, buildings, trans, scm_cdr (expr)); |
| 892 else |
| 893 { |
| 894 #if 0 |
| 895 warning ("Stencil expression not supported by the veritcal skylines."); |
| 896 #endif |
| 897 /* |
| 898 We don't issue a warning here, as we assume that stencil-expression.cc |
| 899 is doing stencil-checking correctly. |
| 900 */ |
| 901 } |
| 902 } |
| 903 |
| 904 /* |
| 905 traverses a stencil expression, returning a vector of Transform_matrix_and_exp
ression |
| 906 the struct Transform_matrix_and_expression contains two members, |
| 907 a Transform_matrix that indicates where to move a stencil and the stencil expr
ession |
| 908 to show how to construct the stencil |
| 909 */ |
| 910 vector<Transform_matrix_and_expression> |
| 911 stencil_traverser (PangoMatrix trans, SCM expr) |
| 912 { |
| 913 if (scm_is_null (expr)) |
| 914 return vector<Transform_matrix_and_expression> (); |
| 915 else if (expr == ly_string2scm ("")) |
| 916 return vector<Transform_matrix_and_expression> (); |
| 917 else if (scm_car (expr) == ly_symbol2scm ("combine-stencil")) |
| 918 { |
| 919 vector<Transform_matrix_and_expression> out; |
| 920 for (SCM s = scm_cdr (expr); scm_is_pair (s); s = scm_cdr (s)) |
| 921 { |
| 922 vector<Transform_matrix_and_expression> res = stencil_traverser (trans
, scm_car (s)); |
| 923 out.insert (out.end (), res.begin (), res.end ()); |
| 924 } |
| 925 return out; |
| 926 } |
| 927 else if (scm_car (expr) == ly_symbol2scm ("footnote")) |
| 928 return vector<Transform_matrix_and_expression> (); |
| 929 else if (scm_car (expr) == ly_symbol2scm ("translate-stencil")) |
| 930 { |
| 931 Real x = robust_scm2double (scm_caadr (expr), 0.0); |
| 932 Real y = robust_scm2double (scm_cdadr (expr), 0.0); |
| 933 pango_matrix_translate (&trans, x, y); |
| 934 return stencil_traverser (trans, scm_caddr (expr)); |
| 935 } |
| 936 else if (scm_car (expr) == ly_symbol2scm ("scale-stencil")) |
| 937 { |
| 938 Real x = robust_scm2double (scm_caadr (expr), 0.0); |
| 939 Real y = robust_scm2double (scm_cadadr (expr), 0.0); |
| 940 pango_matrix_scale (&trans, x, y); |
| 941 return stencil_traverser (trans, scm_caddr (expr)); |
| 942 } |
| 943 else if (scm_car (expr) == ly_symbol2scm ("rotate-stencil")) |
| 944 { |
| 945 Real ang = robust_scm2double (scm_caadr (expr), 0.0); |
| 946 Real x = robust_scm2double (scm_car (scm_cadadr (expr)), 0.0); |
| 947 Real y = robust_scm2double (scm_cdr (scm_cadadr (expr)), 0.0); |
| 948 pango_matrix_translate (&trans, x, y); |
| 949 pango_matrix_rotate (&trans, -ang); |
| 950 pango_matrix_translate (&trans, -x, -y); |
| 951 return stencil_traverser (trans, scm_caddr (expr)); |
| 952 } |
| 953 else if (scm_car (expr) == ly_symbol2scm ("delay-stencil-evaluation")) |
| 954 return stencil_traverser (trans, scm_force (scm_cadr (expr))); |
| 955 else if (scm_car (expr) == ly_symbol2scm ("grob-cause")) |
| 956 return stencil_traverser (trans, scm_caddr (expr)); |
| 957 else if (scm_car (expr) == ly_symbol2scm ("color")) |
| 958 return stencil_traverser (trans, scm_caddr (expr)); |
| 959 else if (scm_car (expr) == ly_symbol2scm ("id")) |
| 960 return stencil_traverser (trans, scm_caddr (expr)); |
| 961 else |
| 962 { |
| 963 vector<Transform_matrix_and_expression> out; |
| 964 out.push_back (Transform_matrix_and_expression (trans, expr)); |
| 965 return out; |
| 966 } |
| 967 warning ("Stencil expression not supported by the veritcal skylines."); |
| 968 return vector<Transform_matrix_and_expression> (); |
| 969 } |
| 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 |
| 1035 MAKE_SCHEME_CALLBACK (Grob, vertical_skylines_from_stencil, 1); |
| 1036 SCM |
| 1037 Grob::vertical_skylines_from_stencil (SCM smob) |
| 1038 { |
| 1039 Grob *me = unsmob_grob (smob); |
| 1040 |
| 1041 Real pad = robust_scm2double (me->get_property ("skyline-horizontal-padding"),
0.0); |
| 1042 SCM out = Stencil::skylines_from_stencil (me->get_property ("stencil"), pad, X
_AXIS); |
| 1043 |
| 1044 return out; |
| 1045 } |
| 1046 |
| 1047 MAKE_SCHEME_CALLBACK (Grob, horizontal_skylines_from_stencil, 1); |
| 1048 SCM |
| 1049 Grob::horizontal_skylines_from_stencil (SCM smob) |
| 1050 { |
| 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 |
| 1064 extract_grob_set (me, "elements", elts); |
| 1065 vector<Real> x_pos; |
| 1066 vector<Real> y_pos; |
| 1067 Grob *x_common = common_refpoint_of_array (elts, me, X_AXIS); |
| 1068 Grob *y_common = common_refpoint_of_array (elts, me, Y_AXIS); |
| 1069 for (vsize i = 0; i < elts.size (); i++) |
| 1070 { |
| 1071 x_pos.push_back (elts[i]->relative_coordinate (x_common, X_AXIS)); |
| 1072 y_pos.push_back (elts[i]->relative_coordinate (y_common, Y_AXIS)); |
| 1073 } |
| 1074 Real my_x = me->relative_coordinate (x_common, X_AXIS); |
| 1075 Real my_y = me->relative_coordinate (y_common, Y_AXIS); |
| 1076 Skyline_pair res; |
| 1077 for (vsize i = 0; i < elts.size (); i++) |
| 1078 { |
| 1079 Skyline_pair *skyp = Skyline_pair::unsmob (elts[i]->get_property (a == X_A
XIS ? "vertical-skylines" : "horizontal-skylines")); |
| 1080 if (skyp) |
| 1081 { |
| 1082 /* |
| 1083 Here, copying is essential. Otherwise, the skyline pair will |
| 1084 get doubly shifted! |
| 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 */ |
| 1092 Skyline_pair copy = Skyline_pair (*skyp); |
| 1093 if (a == X_AXIS) |
| 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 } |
| 1103 res.merge (copy); |
| 1104 } |
| 1105 } |
| 1106 return res.smobbed_copy (); |
| 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 |