Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1094)

Delta Between Two Patch Sets: lily/outside-staff-interface.cc

Issue 7185044: Caches the interior skylines of vertical axis groups and systems. Base URL: http://git.savannah.gnu.org/gitweb/?p=lilypond.git/trunk/
Left Patch Set: Fixes bug in slurs Created 12 years ago
Right Patch Set: Gives Hairpin outside-staff-interface Created 11 years, 11 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
LEFTRIGHT
(no file at all)
1 /*
2 This file is part of LilyPond, the GNU music typesetter.
3
4 Copyright (C) 2013 Mike Solomon <mike@mikesolomon.org>
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 #include "outside-staff-interface.hh"
21
22 #include "axis-group-interface.hh"
23 #include "directional-element-interface.hh"
24 #include "grob.hh"
25 #include "international.hh"
26 #include "interval-set.hh"
27 #include "pointer-group-interface.hh"
28 #include "skyline-pair.hh"
29 #include "unpure-pure-container.hh"
30
31 // Returns the value that the grob elt (whose skylines are given by
32 // v_skyline) needs to move UP or DOWN so that it doesn't intersect with
33 // anything in other_v_skylines. This can be added to the grob's Y-offset
34 // to avoid collisions.
35
36 // the other_X arguments represent other skylines, their vertical padding
37 // (amount of vertical space between them and other skylines) and
38 // horizontal padding used to determine if there is overlap along
39 // the X-axis between two skylines. dir is the placement above or
40 // below the staff.
41
42 // Note that this function will try to keep elements as close to the staff
43 // as possible. So, if the element fits under other elements above the staff,
44 // it will be shifted under instead of over these elements. So, the dir
45 // property does not refer to the placement with respect to other vertical
46 // skylines, but rather with respect to the staff.
47
48 Real
49 distance_needed_to_avoid_outside_staff_collisions (Skyline_pair *v_skyline,
50 Real padding,
51 Real horizon_padding,
52 vector<Skyline_pair> const &o ther_v_skylines,
53 vector<Real> const &other_pad ding,
54 vector<Real> const &other_hor izon_padding,
55 Direction const dir)
56 {
57 assert (other_v_skylines.size () == other_padding.size ());
58 assert (other_v_skylines.size () == other_horizon_padding.size ());
59 vector<Interval> forbidden_intervals;
60 for (vsize j = 0; j < other_v_skylines.size (); j++)
61 {
62 Skyline_pair const &v_other = other_v_skylines[j];
63 Real pad = (padding + other_padding[j]);
64 Real horizon_pad = (horizon_padding + other_horizon_padding[j]);
65
66 // We need to push elt up by at least this much to be above v_other.
67 Real up = (*v_skyline)[DOWN].distance (v_other[UP], horizon_pad) + pad;
68 // We need to push elt down by at least this much to be below v_other.
69 Real down = (*v_skyline)[UP].distance (v_other[DOWN], horizon_pad) + pad;
70
71 forbidden_intervals.push_back (Interval (-down, up));
72 }
73
74 Interval_set allowed_shifts
75 = Interval_set::interval_union (forbidden_intervals).complement ();
76 return allowed_shifts.nearest_point (0, dir);
77 }
78
79 /*
80 TODO - this will eventually need to handle pure skylines for outside staff
81 placement approximations. It'll require better pure skyline approximations
82 (for now they are all rather brute) as well as calls to maybe_pure_property
83 for the skylines.
84 */
85
86 MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Outside_staff_interface, y_aligned_side, 2, 1 , "");
87 SCM
88 Outside_staff_interface::y_aligned_side (SCM smob, SCM current_off)
89 {
90 Grob *me = unsmob_grob (smob);
91 Real current = robust_scm2double (current_off, 0.0);
92 return scm_from_double (calc_outside_staff_offset (me, false, 0, 0, current));
93 }
94
95 MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Outside_staff_interface, pure_y_aligned_side, 4, 1, "");
96 SCM
97 Outside_staff_interface::pure_y_aligned_side (SCM /*smob*/, SCM /*start*/, SCM / *end*/, SCM current_off)
98 {
99 return current_off;
100 }
101
102 Real
103 Outside_staff_interface::calc_outside_staff_offset (Grob *me, bool pure, int sta rt, int end, Real current_offset)
104 {
105 /*
106 If the grob has an outside-staff-priority, we do outside-staff-placement
107 based on previously-placed grobs.
108 */
109
110 if (!scm_is_number (me->get_property ("outside-staff-priority"))
111 || pure)
112 return current_offset;
113
114 Direction dir = get_grob_direction (me);
115 SCM v_orig_scm = me->get_property ("vertical-skylines");
116 Skyline_pair *v_orig = Skyline_pair::unsmob (v_orig_scm);
117 assert (v_orig); // Should be assured by the Grob constructor
118 Skyline_pair v_skylines (*v_orig);
119
120 // possible if empty stencil
121 if (v_orig->is_empty ())
122 return current_offset;
123
124 Grob *vag = Grob::get_vertical_axis_group (me);
125 // possible if vetical axis group has been hara-kiri'd
126 if (!vag || !vag->is_live ())
127 return current_offset;
128
129 // ugh...gets called too often...?
130 Axis_group_interface::prepare_for_outside_staff_calculations (vag);
131 extract_grob_set (vag, "vertical-skyline-elements", elements);
132
133 Grob *x_common = common_refpoint_of_array (elements, vag, X_AXIS);
134 Grob *y_common = common_refpoint_of_array (elements, vag, Y_AXIS);
135
136 assert (y_common == vag);
137
138 Skyline_pair skylines;
139 SCM iss = vag->get_object ("inside-staff-skylines");
140 if (Skyline_pair *inside_staff_skylines = Skyline_pair::unsmob (iss))
141 skylines = Skyline_pair (*inside_staff_skylines);
142
143 // These are the skylines of all outside-staff grobs
144 // that have already been processed. We keep them around in order to
145 // check them for collisions with the currently active outside-staff grob.
146 Drul_array<vector<Skyline_pair> > all_v_skylines;
147 Drul_array<vector<Real> > all_paddings;
148 Drul_array<vector<Real> > all_horizon_paddings;
149 for (UP_and_DOWN (d))
150 {
151 all_v_skylines[d].push_back (skylines);
152 all_paddings[d].push_back (0);
153 all_horizon_paddings[d].push_back (0);
154 }
155
156 vsize i = 0;
157
158 // ensure inside staff elements are placed
159 for (; i < elements.size ()
160 && !scm_is_number (elements[i]->get_property ("outside-staff-priority")); i++)
161 (void) elements[i]->get_property ("Y-offset");
162
163 // then build skyline vector for placement
164 for (; i < elements.size () && elements[i] != me; i++)
165 {
166 Grob *elt = elements[i];
167 SCM elt_sky_scm = elt->get_property ("vertical-skylines");
168 Skyline_pair *elt_sky = Skyline_pair::unsmob (elt_sky_scm);
169 if (elt_sky->is_empty ())
170 continue;
171
172 Skyline_pair elt_v_skylines (*elt_sky);
173 elt_v_skylines.shift (elt->relative_coordinate (x_common, X_AXIS));
174 elt_v_skylines.raise (elt->relative_coordinate (y_common, Y_AXIS));
175 Real padding
176 = robust_scm2double (elt->get_property ("outside-staff-padding"), 0.25);
177 Real horizon_padding
178 = robust_scm2double (elt->get_property ("outside-staff-horizontal-paddin g"), 0.0);
179
180 all_v_skylines[dir].push_back (elt_v_skylines);
181 all_paddings[dir].push_back (padding);
182 all_horizon_paddings[dir].push_back (horizon_padding);
183 }
184
185 Real padding
186 = robust_scm2double (me->get_property ("outside-staff-padding"), 0.25);
187 Real horizon_padding
188 = robust_scm2double (me->get_property ("outside-staff-horizontal-padding"), 0.0);
189
190 if (dir == CENTER)
191 {
192 warning (_ ("an outside-staff object should have a direction, defaulting t o up"));
193 dir = UP;
194 }
195
196 v_skylines.shift (me->relative_coordinate (x_common, X_AXIS));
197 Real mommy_offset = me->get_parent (Y_AXIS)->maybe_pure_coordinate (y_common, Y_AXIS, pure, start, end);
198 v_skylines.raise (current_offset + mommy_offset);
199
200 return current_offset
201 + distance_needed_to_avoid_outside_staff_collisions (&v_skylines,
202 padding,
203 horizon_padding,
204 all_v_skylines[dir ],
205 all_paddings[dir],
206 all_horizon_paddin gs[dir],
207 dir);
208 }
209
210 void
211 Outside_staff_interface::chain_y_offset_callback (Grob *me)
212 {
213 chain_offset_callback (me,
214 ly_make_unpure_pure_container (y_aligned_side_proc, pur e_y_aligned_side_proc),
215 Y_AXIS);
216 }
217
218 ADD_INTERFACE (Outside_staff_interface,
219 "Position a victim object (this one) outside the staff.",
220
221 /* properties */
222 "outside-staff-horizontal-padding "
223 "outside-staff-padding "
224 "outside-staff-priority "
225 );
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b