]> git.donarmstrong.com Git - lilypond.git/blob - lily/cluster.cc
(brew_molecule): cleaned up Cluster code and
[lilypond.git] / lily / cluster.cc
1 /*
2   cluster.cc -- implement Cluster
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2002--2003 Juergen Reuter <reuter@ipd.uka.de>
7
8   Han-Wen Nienhuys <hanwen@cs.uu.nl>
9
10 */
11
12 #include <stdio.h>
13 #include "cluster.hh"
14 #include "grob.hh"
15 #include "spanner.hh"
16 #include "item.hh"
17 #include "pitch.hh"
18 #include "staff-symbol-referencer.hh"
19 #include "lookup.hh"
20 #include "box.hh"
21 #include "interval.hh"
22 #include "paper-def.hh"
23 #include "paper-column.hh"
24 #include "note-column.hh"
25
26 /*
27  * TODO: Add support for cubic spline segments.
28  */
29 Molecule
30 brew_cluster_piece (Grob *me, Array<Offset> bottom_points, Array<Offset> top_points)
31 {
32 #if 0
33   Real blotdiameter = me->get_paper ()->get_var ("blotdiameter");
34 #else
35   Real blotdiameter = Staff_symbol_referencer::staff_space (me)/2;
36 #endif
37
38   Real padding;
39   SCM padding_scm = me->get_grob_property ("padding");
40   if (gh_number_p (padding_scm))
41     padding = gh_scm2double (padding_scm);
42   else
43     padding = 0.0;
44   Offset vpadding = Offset (0, padding);
45   Offset hpadding = Offset (0.5 * blotdiameter, 0);
46   Offset hvpadding = 0.5 * hpadding + vpadding;
47
48   SCM shape_scm = me->get_grob_property ("shape");
49   String shape;
50   if (gh_symbol_p (shape_scm))
51     {
52       shape = ly_symbol2string (shape_scm);
53     }
54   else
55     {
56       shape = "leftsided-stairs";
57     }
58
59
60   Molecule out = Molecule ();
61   Array<Offset> points;
62   points.clear ();
63   int size = bottom_points.size ();
64   if (String::compare (shape, "leftsided-stairs") == 0)
65     {
66       for (int i = 0; i < size - 1; i++)
67         {
68           Box box;
69           box.add_point (bottom_points[i] - hvpadding);
70           box.add_point (Offset(top_points[i + 1][X_AXIS],
71                                 top_points[i][Y_AXIS]) + hvpadding);
72           out.add_molecule (Lookup::roundfilledbox (box, blotdiameter));
73         }
74     }
75   else if (String::compare (shape, "rightsided-stairs") == 0)
76     {
77       for (int i = 0; i < size - 1; i++)
78         {
79           Box box;
80           box.add_point (Offset(bottom_points[i][X_AXIS],
81                                 bottom_points[i + 1][Y_AXIS]) - hvpadding);
82           box.add_point (top_points[i + 1] + hvpadding);
83           out.add_molecule (Lookup::roundfilledbox (box, blotdiameter));
84         }
85     }
86   else if (String::compare (shape, "centered-stairs") == 0)
87     {
88       Real left_xmid = bottom_points[0][X_AXIS];
89       for (int i = 0; i < size - 1; i++)
90         {
91           Real right_xmid =
92             0.5 * (bottom_points[i][X_AXIS] + bottom_points[i + 1][X_AXIS]);
93           Box box;
94           box.add_point (Offset (left_xmid, bottom_points[i][Y_AXIS]) -
95                          hvpadding);
96           box.add_point (Offset (right_xmid, top_points[i][Y_AXIS]) +
97                          hvpadding);
98           out.add_molecule (Lookup::roundfilledbox (box, blotdiameter));
99           left_xmid = right_xmid;
100         }
101       Real right_xmid = bottom_points[size - 1][X_AXIS];
102       Box box;
103       box.add_point (Offset (left_xmid, bottom_points[size - 1][Y_AXIS]) -
104                      hvpadding);
105       box.add_point (Offset (right_xmid, top_points[size - 1][Y_AXIS]) +
106                      hvpadding);
107       out.add_molecule (Lookup::roundfilledbox (box, blotdiameter));
108     }
109   else if (String::compare (shape, "ramp") == 0)
110     {
111       points.push (bottom_points[0] - vpadding + hpadding);
112       for (int i = 1; i < size - 1; i++)
113         {
114           points.push (bottom_points[i] - vpadding);
115         }
116       points.push (bottom_points[size - 1] - vpadding - hpadding);
117       points.push (top_points[size - 1] + vpadding - hpadding);
118       for (int i = size - 2; i > 0; i--)
119         {
120           points.push (top_points[i] + vpadding);
121         }
122       points.push (top_points[0] + vpadding + hpadding);
123       out.add_molecule (Lookup::round_filled_polygon (points, blotdiameter));
124     }
125   else
126     {
127       me->warning (_f ("unknown cluster shape `%s'", shape.to_str0 ()));
128     }
129   return out;
130 }
131
132 MAKE_SCHEME_CALLBACK (Cluster,brew_molecule,1);
133 SCM
134 Cluster::brew_molecule (SCM smob)
135 {
136   Grob *me = unsmob_grob (smob);
137
138   Spanner *spanner = dynamic_cast<Spanner*> (me);
139   if (!spanner)
140     {
141       me->programming_error ("Cluster::brew_molecule(): not a spanner");
142       return SCM_EOL;
143     }
144
145   Item *left_bound = spanner->get_bound (LEFT);
146   Item *right_bound = spanner->get_bound (RIGHT);
147
148   Grob *common = left_bound->common_refpoint (right_bound, X_AXIS);
149   SCM cols  =me->get_grob_property ("columns");
150   if (!gh_pair_p (cols))
151     {
152       me->warning ("junking empty cluster");
153       me->suicide ();
154       
155       return SCM_EOL;
156     }
157   common = common_refpoint_of_list (cols, common, X_AXIS);
158   Array<Offset> bottom_points;
159   Array<Offset> top_points;
160
161
162   Real left_coord = left_bound->relative_coordinate (common, X_AXIS);
163
164   for (SCM s = cols; gh_pair_p (s); s = ly_cdr (s))
165     {
166       Grob * col = unsmob_grob (ly_car (s));
167       Slice s = Note_column::head_positions_interval (col);
168       Grob * h = Note_column::first_head (col);
169
170       Real x = h->relative_coordinate (common, X_AXIS) - left_coord;
171       bottom_points.push (Offset (x, s[DOWN] *0.5));
172       top_points.push (Offset (x, s[UP] * 0.5));
173     }
174
175   /*
176     Across a line break we anticipate on the next pitches.
177    */
178   if (spanner->original_)
179     {
180       Spanner *orig = dynamic_cast<Spanner*> (spanner->original_);
181       
182       if (spanner->break_index_ < orig->broken_intos_.size()-1)
183         {
184           Spanner * next = orig->broken_intos_[spanner->break_index_+1];
185           SCM cols = next->get_grob_property ("columns");
186           if (gh_pair_p (cols))
187             {
188               Grob * col = unsmob_grob (ly_car (scm_last_pair (cols)));
189               Slice s = Note_column::head_positions_interval (col);
190               Real x = right_bound->relative_coordinate (common,X_AXIS) - left_coord;
191               
192               bottom_points.insert (Offset (x, s[DOWN] * 0.5),0);
193               top_points.insert (Offset (x, s[UP] * 0.5),0);
194             }
195         }
196     }
197
198   bottom_points.reverse ();
199   top_points.reverse ();
200
201   Molecule out = brew_cluster_piece (me, bottom_points, top_points);
202   return out.smobbed_copy ();
203 }
204
205 ADD_INTERFACE (Cluster,"cluster-interface",
206   "A graphically drawn musical cluster.",
207   "shape padding columns");