2 cluster.cc -- implement Cluster
4 source file of the GNU LilyPond music typesetter
6 (c) 2002--2008 Juergen Reuter <reuter@ipd.uka.de>
8 Han-Wen Nienhuys <hanwen@xs4all.nl>
12 #include "international.hh"
15 #include "output-def.hh"
17 #include "pointer-group-interface.hh"
19 #include "staff-symbol-referencer.hh"
23 TODO: Add support for cubic spline segments.
26 brew_cluster_piece (Grob
*me
, vector
<Offset
> bottom_points
, vector
<Offset
> top_points
)
28 Real blotdiameter
= Staff_symbol_referencer::staff_space (me
) / 2;
30 Real padding
= robust_scm2double (me
->get_property ("padding"), 0.0);
32 Offset vpadding
= Offset (0, padding
);
33 Offset hpadding
= Offset (0.5 * blotdiameter
, 0);
34 Offset hvpadding
= 0.5 * hpadding
+ vpadding
;
36 SCM shape_scm
= me
->get_property ("style");
39 if (scm_is_symbol (shape_scm
))
40 shape
= ly_symbol2string (shape_scm
);
43 programming_error ("#'style should be symbol.");
49 vector
<Offset
> points
;
51 int size
= bottom_points
.size ();
52 if (shape
== "leftsided-stairs")
54 for (int i
= 0; i
< size
- 1; i
++)
57 box
.add_point (bottom_points
[i
] - hvpadding
);
58 box
.add_point (Offset (top_points
[i
+ 1][X_AXIS
],
59 top_points
[i
][Y_AXIS
]) + hvpadding
);
60 out
.add_stencil (Lookup::round_filled_box (box
, blotdiameter
));
63 else if (shape
== "rightsided-stairs")
65 for (int i
= 0; i
< size
- 1; i
++)
68 box
.add_point (Offset (bottom_points
[i
][X_AXIS
],
69 bottom_points
[i
+ 1][Y_AXIS
]) - hvpadding
);
70 box
.add_point (top_points
[i
+ 1] + hvpadding
);
71 out
.add_stencil (Lookup::round_filled_box (box
, blotdiameter
));
74 else if (shape
== "centered-stairs")
76 Real left_xmid
= bottom_points
[0][X_AXIS
];
77 for (int i
= 0; i
< size
- 1; i
++)
80 = 0.5 * (bottom_points
[i
][X_AXIS
] + bottom_points
[i
+ 1][X_AXIS
]);
82 box
.add_point (Offset (left_xmid
, bottom_points
[i
][Y_AXIS
])
84 box
.add_point (Offset (right_xmid
, top_points
[i
][Y_AXIS
])
86 out
.add_stencil (Lookup::round_filled_box (box
, blotdiameter
));
87 left_xmid
= right_xmid
;
89 Real right_xmid
= bottom_points
[size
- 1][X_AXIS
];
91 box
.add_point (Offset (left_xmid
, bottom_points
[size
- 1][Y_AXIS
])
93 box
.add_point (Offset (right_xmid
, top_points
[size
- 1][Y_AXIS
])
95 out
.add_stencil (Lookup::round_filled_box (box
, blotdiameter
));
97 else if (shape
== "ramp")
99 points
.push_back (bottom_points
[0] - vpadding
+ hpadding
);
100 for (int i
= 1; i
< size
- 1; i
++)
101 points
.push_back (bottom_points
[i
] - vpadding
);
102 points
.push_back (bottom_points
[size
- 1] - vpadding
- hpadding
);
103 points
.push_back (top_points
[size
- 1] + vpadding
- hpadding
);
104 for (int i
= size
- 2; i
> 0; i
--)
105 points
.push_back (top_points
[i
] + vpadding
);
106 points
.push_back (top_points
[0] + vpadding
+ hpadding
);
107 out
.add_stencil (Lookup::round_filled_polygon (points
, blotdiameter
));
110 me
->warning (_f ("unknown cluster style `%s'", shape
.c_str ()));
114 MAKE_SCHEME_CALLBACK (Cluster
, calc_cross_staff
, 1);
116 Cluster::calc_cross_staff (SCM smob
)
118 Grob
*me
= unsmob_grob (smob
);
120 extract_grob_set (me
, "columns", cols
);
121 Grob
*commony
= common_refpoint_of_array (cols
, me
, Y_AXIS
);
123 return scm_from_bool (commony
!= me
->get_parent (Y_AXIS
));
126 MAKE_SCHEME_CALLBACK (Cluster
, print
, 1);
128 Cluster::print (SCM smob
)
130 Grob
*me
= unsmob_grob (smob
);
132 Spanner
*spanner
= dynamic_cast<Spanner
*> (me
);
135 me
->programming_error ("Cluster::print (): not a spanner");
139 Item
*left_bound
= spanner
->get_bound (LEFT
);
140 Item
*right_bound
= spanner
->get_bound (RIGHT
);
142 Grob
*commonx
= left_bound
->common_refpoint (right_bound
, X_AXIS
);
144 vector
<Grob
*> const &cols
= extract_grob_array (me
, "columns");
147 me
->warning (_ ("junking empty cluster"));
153 commonx
= common_refpoint_of_array (cols
, commonx
, X_AXIS
);
154 Grob
*commony
= common_refpoint_of_array (cols
, me
, Y_AXIS
);
155 vector
<Offset
> bottom_points
;
156 vector
<Offset
> top_points
;
158 Real left_coord
= left_bound
->relative_coordinate (commonx
, X_AXIS
);
161 TODO: should we move the cluster a little to the right to be in
162 line with the center of the note heads?
165 for (vsize i
= 0; i
< cols
.size (); i
++)
169 Interval yext
= col
->extent (commony
, Y_AXIS
);
171 Real x
= col
->relative_coordinate (commonx
, X_AXIS
) - left_coord
;
172 bottom_points
.push_back (Offset (x
, yext
[DOWN
]));
173 top_points
.push_back (Offset (x
, yext
[UP
]));
177 Across a line break we anticipate on the next pitches.
179 if (Spanner
*next
= spanner
->broken_neighbor (RIGHT
))
181 extract_grob_set (next
, "columns", next_cols
);
182 if (next_cols
.size () > 0)
184 Grob
*next_commony
= common_refpoint_of_array (next_cols
, next
, Y_AXIS
);
185 Grob
*col
= next_cols
[0];
187 Interval v
= col
->extent (next_commony
, Y_AXIS
);
188 Real x
= right_bound
->relative_coordinate (commonx
, X_AXIS
) - left_coord
;
190 bottom_points
.push_back (Offset (x
, v
[DOWN
]));
191 top_points
.push_back (Offset (x
, v
[UP
]));
195 Stencil out
= brew_cluster_piece (me
, bottom_points
, top_points
);
196 out
.translate_axis (- me
->relative_coordinate (commony
, Y_AXIS
), Y_AXIS
);
197 return out
.smobbed_copy ();
200 ADD_INTERFACE (Cluster
,
201 "A graphically drawn musical cluster.\n"
203 "@code{padding} adds to the vertical extent of the shape (top"
206 "The property @code{style} controls the shape of cluster"
207 " segments. Valid values include @code{leftsided-stairs},"
208 " @code{rightsided-stairs}, @code{centered-stairs}, and"
217 struct Cluster_beacon
220 DECLARE_SCHEME_CALLBACK (height
, (SCM
));
221 DECLARE_GROB_INTERFACE ();
224 MAKE_SCHEME_CALLBACK (Cluster_beacon
, height
, 1);
226 Cluster_beacon::height (SCM g
)
228 Grob
*me
= unsmob_grob (g
);
229 Interval v
= robust_scm2interval (me
->get_property ("positions"),
231 return ly_interval2scm (Staff_symbol_referencer::staff_space (me
) * 0.5 * v
);
234 ADD_INTERFACE (Cluster_beacon
,
235 "A place holder for the cluster spanner to determine the"
236 " vertical extents of a cluster spanner at this"