Fixes Issue 1504, allowing feather beam line breaking.
[lilypond/patrick.git] / lily / spacing-interface.cc
blobf9d3287cb0cf45f1b20846332a7adb59be29e02f
1 /*
2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2007--2011 Joe Neeman <joeneeman@gmail.com>
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.
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.
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/>.
20 #include "spacing-interface.hh"
22 #include "grob.hh"
23 #include "grob-array.hh"
24 #include "item.hh"
25 #include "note-column.hh"
26 #include "pointer-group-interface.hh"
27 #include "paper-column.hh"
28 #include "separation-item.hh"
29 #include "skyline.hh"
30 #include "skyline-pair.hh"
31 #include "system.hh"
33 /* return the right-pointing skyline of the left-items and the left-pointing
34 skyline of the right-items (with the skyline of the left-items in
35 ret[LEFT]) */
36 Drul_array<Skyline>
37 Spacing_interface::skylines (Grob *me, Grob *right_col)
39 /* the logic here is a little convoluted.
40 A {Staff,Note}_spacing doesn't copy left-items when it clones,
41 so in order to find the separation items, we need to use the original
42 spacing grob. But once we find the separation items, we need to get back
43 the broken piece.
46 Grob *orig = me->original () ? me->original () : me;
47 Drul_array<Direction> break_dirs (dynamic_cast<Item*> (me)->break_status_dir (),
48 dynamic_cast<Item*> (right_col)->break_status_dir ());
49 Drul_array<Skyline> skylines = Drul_array<Skyline> (Skyline (RIGHT), Skyline (LEFT));
50 Drul_array<vector<Grob*> > items (ly_scm2link_array (orig->get_object ("left-items")),
51 ly_scm2link_array (orig->get_object ("right-items")));
53 Grob *system = me->get_system ();
54 Grob *left_col = dynamic_cast<Item*> (me)->get_column ();
56 Drul_array<Grob*> columns (left_col, right_col);
58 Direction d = LEFT;
61 for (vsize i = 0; i < items[d].size (); i++)
63 Item *g = dynamic_cast<Item*> (items[d][i]);
64 if (g)
65 if (Item *piece = g->find_prebroken_piece (break_dirs[d]))
66 g = piece;
68 if (g && Separation_item::has_interface (g) && g->get_column () == columns[d])
70 SCM sky_scm = g->get_property ("horizontal-skylines");
71 Skyline_pair *sky = Skyline_pair::unsmob (sky_scm);
73 extract_grob_set (g, "elements", elts);
74 Grob *ycommon = common_refpoint_of_array (elts, g, Y_AXIS);
75 Real shift = ycommon->pure_relative_y_coordinate (system, 0, INT_MAX);
77 skylines[d].shift (-shift);
79 if (sky)
80 skylines[d].merge ((*sky)[-d]);
81 else
82 programming_error ("separation item has no skyline");
84 if (d == RIGHT && items[LEFT].size ())
85 skylines[d].merge (Separation_item::conditional_skyline (items[d][i], items[LEFT][0]));
87 skylines[d].shift (shift);
91 while (flip (&d) != LEFT);
93 return skylines;
96 Real
97 Spacing_interface::minimum_distance (Grob *me, Grob *right)
99 Drul_array<Skyline> skylines = Spacing_interface::skylines (me, right);
101 return max (0.0, skylines[LEFT].distance (skylines[RIGHT]));
105 Compute the left-most column of the right-items.
107 Item *
108 Spacing_interface::right_column (Grob *me)
110 if (!me->is_live ())
111 return 0;
113 Grob_array *a = unsmob_grob_array (me->get_object ("right-items"));
114 Item *mincol = 0;
115 int min_rank = INT_MAX;
116 for (vsize i = 0; a && i < a->size (); i++)
118 Item *ri = a->item (i);
119 Item *col = ri->get_column ();
121 int rank = Paper_column::get_rank (col);
123 if (rank < min_rank)
125 min_rank = rank;
126 mincol = col;
130 return mincol;
133 Item *
134 Spacing_interface::left_column (Grob *me)
136 if (!me->is_live ())
137 return 0;
139 return dynamic_cast<Item *> (me)->get_column ();
142 static vector<Item*>
143 get_note_columns (vector<Grob*> const &elts)
145 vector<Item*> ret;
147 for (vsize i = 0; i < elts.size (); i++)
149 if (Note_column::has_interface (elts[i]))
150 ret.push_back (dynamic_cast<Item*> (elts[i]));
151 else if (Separation_item::has_interface (elts[i]))
153 extract_grob_set (elts[i], "elements", more_elts);
154 vector<Item*> ncs = get_note_columns (more_elts);
156 ret.insert (ret.end (), ncs.begin (), ncs.end ());
160 return ret;
163 vector<Item*>
164 Spacing_interface::right_note_columns (Grob *me)
166 extract_grob_set (me, "right-items", elts);
167 return get_note_columns (elts);
170 vector<Item*>
171 Spacing_interface::left_note_columns (Grob *me)
173 extract_grob_set (me, "left-items", elts);
174 return get_note_columns (elts);
178 Try to find the break-aligned symbol that belongs on the D-side
179 of ME, sticking out in direction -D. The x size is put in LAST_EXT
181 Grob *
182 Spacing_interface::extremal_break_aligned_grob (Grob *me,
183 Direction d,
184 Direction break_dir,
185 Interval *last_ext)
187 Grob *col = 0;
188 last_ext->set_empty ();
189 Grob *last_grob = 0;
191 extract_grob_set (me, d == LEFT ? "left-break-aligned" : "right-break-aligned", elts);
193 for (vsize i = elts.size (); i--;)
195 Item *break_item = dynamic_cast<Item*> (elts[i]);
197 if (break_item->break_status_dir () != break_dir)
198 break_item = break_item->find_prebroken_piece (break_dir);
200 if (!break_item || !scm_is_pair (break_item->get_property ("space-alist")))
201 continue;
203 if (!col)
204 col = dynamic_cast<Item*> (elts[0])->get_column ()->find_prebroken_piece (break_dir);
206 Interval ext = break_item->extent (col, X_AXIS);
208 if (ext.is_empty ())
209 continue;
211 if (!last_grob
212 || (last_grob && d * (ext[-d]- (*last_ext)[-d]) < 0))
214 *last_ext = ext;
215 last_grob = break_item;
219 return last_grob;
223 ADD_INTERFACE (Spacing_interface,
224 "This object calculates the desired and minimum distances"
225 " between two columns.",
227 /* properties */
228 "left-items "
229 "right-items "