2 spacing-interface.cc -- functionality that is shared between Note_spacing
5 source file of the GNU LilyPond music typesetter
7 (c) 2007--2009 Joe Neeman <joeneeman@gmail.com>
10 #include "spacing-interface.hh"
13 #include "grob-array.hh"
15 #include "note-column.hh"
16 #include "pointer-group-interface.hh"
17 #include "paper-column.hh"
18 #include "separation-item.hh"
20 #include "skyline-pair.hh"
23 /* return the right-pointing skyline of the left-items and the left-pointing
24 skyline of the right-items (with the skyline of the left-items in
27 Spacing_interface::skylines (Grob *me, Grob *right_col)
29 /* the logic here is a little convoluted.
30 A {Staff,Note}_spacing doesn't copy left-items when it clones,
31 so in order to find the separation items, we need to use the original
32 spacing grob. But once we find the separation items, we need to get back
36 Grob *orig = me->original () ? me->original () : me;
37 Drul_array<Direction> break_dirs (dynamic_cast<Item*> (me)->break_status_dir (),
38 dynamic_cast<Item*> (right_col)->break_status_dir ());
39 Drul_array<Skyline> skylines = Drul_array<Skyline> (Skyline (RIGHT), Skyline (LEFT));
40 Drul_array<vector<Grob*> > items (ly_scm2link_array (orig->get_object ("left-items")),
41 ly_scm2link_array (orig->get_object ("right-items")));
43 Grob *system = me->get_system ();
44 Grob *left_col = dynamic_cast<Item*> (me)->get_column ();
46 Drul_array<Grob*> columns (left_col, right_col);
51 for (vsize i = 0; i < items[d].size (); i++)
53 Item *g = dynamic_cast<Item*> (items[d][i]);
55 if (Item *piece = g->find_prebroken_piece (break_dirs[d]))
58 if (g && Separation_item::has_interface (g) && g->get_column () == columns[d])
60 SCM sky_scm = g->get_property ("horizontal-skylines");
61 Skyline_pair *sky = Skyline_pair::unsmob (sky_scm);
63 extract_grob_set (g, "elements", elts);
64 Grob *ycommon = common_refpoint_of_array (elts, g, Y_AXIS);
65 Real shift = ycommon->pure_relative_y_coordinate (system, 0, INT_MAX);
67 skylines[d].shift (-shift);
70 skylines[d].merge ((*sky)[-d]);
72 programming_error ("separation item has no skyline");
74 if (d == RIGHT && items[LEFT].size ())
75 skylines[d].merge (Separation_item::conditional_skyline (items[d][i], items[LEFT][0]));
77 skylines[d].shift (shift);
81 while (flip (&d) != LEFT);
87 Spacing_interface::minimum_distance (Grob *me, Grob *right)
89 Drul_array<Skyline> skylines = Spacing_interface::skylines (me, right);
91 return max (0.0, skylines[LEFT].distance (skylines[RIGHT]));
95 Compute the left-most column of the right-items.
98 Spacing_interface::right_column (Grob *me)
103 Grob_array *a = unsmob_grob_array (me->get_object ("right-items"));
105 int min_rank = INT_MAX;
106 for (vsize i = 0; a && i < a->size (); i++)
108 Item *ri = a->item (i);
109 Item *col = ri->get_column ();
111 int rank = Paper_column::get_rank (col);
124 Spacing_interface::left_column (Grob *me)
129 return dynamic_cast<Item *> (me)->get_column ();
133 get_note_columns (vector<Grob*> const &elts)
137 for (vsize i = 0; i < elts.size (); i++)
139 if (Note_column::has_interface (elts[i]))
140 ret.push_back (dynamic_cast<Item*> (elts[i]));
141 else if (Separation_item::has_interface (elts[i]))
143 extract_grob_set (elts[i], "elements", more_elts);
144 vector<Item*> ncs = get_note_columns (more_elts);
146 ret.insert (ret.end (), ncs.begin (), ncs.end ());
154 Spacing_interface::right_note_columns (Grob *me)
156 extract_grob_set (me, "right-items", elts);
157 return get_note_columns (elts);
161 Spacing_interface::left_note_columns (Grob *me)
163 extract_grob_set (me, "left-items", elts);
164 return get_note_columns (elts);
168 Try to find the break-aligned symbol that belongs on the D-side
169 of ME, sticking out in direction -D. The x size is put in LAST_EXT
172 Spacing_interface::extremal_break_aligned_grob (Grob *me,
178 last_ext->set_empty ();
181 extract_grob_set (me, d == LEFT ? "left-break-aligned" : "right-break-aligned", elts);
183 for (vsize i = elts.size (); i--;)
185 Item *break_item = dynamic_cast<Item*> (elts[i]);
187 if (break_item->break_status_dir () != break_dir)
188 break_item = break_item->find_prebroken_piece (break_dir);
190 if (!break_item || !scm_is_pair (break_item->get_property ("space-alist")))
194 col = dynamic_cast<Item*> (elts[0])->get_column ()->find_prebroken_piece (break_dir);
196 Interval ext = break_item->extent (col, X_AXIS);
202 || (last_grob && d * (ext[-d]- (*last_ext)[-d]) < 0))
205 last_grob = break_item;
213 ADD_INTERFACE (Spacing_interface,
214 "This object calculates the desired and minimum distances"
215 " between two columns.",