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

Unified Diff: 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/
Patch Set: Gives Hairpin outside-staff-interface Created 11 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: lily/outside-staff-interface.cc
diff --git a/lily/outside-staff-interface.cc b/lily/outside-staff-interface.cc
new file mode 100644
index 0000000000000000000000000000000000000000..40dfb8a305d72beda3fd0b4c9a2851be0a21644c
--- /dev/null
+++ b/lily/outside-staff-interface.cc
@@ -0,0 +1,225 @@
+/*
+ This file is part of LilyPond, the GNU music typesetter.
+
+ Copyright (C) 2013 Mike Solomon <mike@mikesolomon.org>
+
+ LilyPond is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ LilyPond is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "outside-staff-interface.hh"
+
+#include "axis-group-interface.hh"
+#include "directional-element-interface.hh"
+#include "grob.hh"
+#include "international.hh"
+#include "interval-set.hh"
+#include "pointer-group-interface.hh"
+#include "skyline-pair.hh"
+#include "unpure-pure-container.hh"
+
+// Returns the value that the grob elt (whose skylines are given by
+// v_skyline) needs to move UP or DOWN so that it doesn't intersect with
+// anything in other_v_skylines. This can be added to the grob's Y-offset
+// to avoid collisions.
+
+// the other_X arguments represent other skylines, their vertical padding
+// (amount of vertical space between them and other skylines) and
+// horizontal padding used to determine if there is overlap along
+// the X-axis between two skylines. dir is the placement above or
+// below the staff.
+
+// Note that this function will try to keep elements as close to the staff
+// as possible. So, if the element fits under other elements above the staff,
+// it will be shifted under instead of over these elements. So, the dir
+// property does not refer to the placement with respect to other vertical
+// skylines, but rather with respect to the staff.
+
+Real
+distance_needed_to_avoid_outside_staff_collisions (Skyline_pair *v_skyline,
+ Real padding,
+ Real horizon_padding,
+ vector<Skyline_pair> const &other_v_skylines,
+ vector<Real> const &other_padding,
+ vector<Real> const &other_horizon_padding,
+ Direction const dir)
+{
+ assert (other_v_skylines.size () == other_padding.size ());
+ assert (other_v_skylines.size () == other_horizon_padding.size ());
+ vector<Interval> forbidden_intervals;
+ for (vsize j = 0; j < other_v_skylines.size (); j++)
+ {
+ Skyline_pair const &v_other = other_v_skylines[j];
+ Real pad = (padding + other_padding[j]);
+ Real horizon_pad = (horizon_padding + other_horizon_padding[j]);
+
+ // We need to push elt up by at least this much to be above v_other.
+ Real up = (*v_skyline)[DOWN].distance (v_other[UP], horizon_pad) + pad;
+ // We need to push elt down by at least this much to be below v_other.
+ Real down = (*v_skyline)[UP].distance (v_other[DOWN], horizon_pad) + pad;
+
+ forbidden_intervals.push_back (Interval (-down, up));
+ }
+
+ Interval_set allowed_shifts
+ = Interval_set::interval_union (forbidden_intervals).complement ();
+ return allowed_shifts.nearest_point (0, dir);
+}
+
+/*
+ TODO - this will eventually need to handle pure skylines for outside staff
+ placement approximations. It'll require better pure skyline approximations
+ (for now they are all rather brute) as well as calls to maybe_pure_property
+ for the skylines.
+*/
+
+MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Outside_staff_interface, y_aligned_side, 2, 1, "");
+SCM
+Outside_staff_interface::y_aligned_side (SCM smob, SCM current_off)
+{
+ Grob *me = unsmob_grob (smob);
+ Real current = robust_scm2double (current_off, 0.0);
+ return scm_from_double (calc_outside_staff_offset (me, false, 0, 0, current));
+}
+
+MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Outside_staff_interface, pure_y_aligned_side, 4, 1, "");
+SCM
+Outside_staff_interface::pure_y_aligned_side (SCM /*smob*/, SCM /*start*/, SCM /*end*/, SCM current_off)
+{
+ return current_off;
+}
+
+Real
+Outside_staff_interface::calc_outside_staff_offset (Grob *me, bool pure, int start, int end, Real current_offset)
+{
+ /*
+ If the grob has an outside-staff-priority, we do outside-staff-placement
+ based on previously-placed grobs.
+ */
+
+ if (!scm_is_number (me->get_property ("outside-staff-priority"))
+ || pure)
+ return current_offset;
+
+ Direction dir = get_grob_direction (me);
+ SCM v_orig_scm = me->get_property ("vertical-skylines");
+ Skyline_pair *v_orig = Skyline_pair::unsmob (v_orig_scm);
+ assert (v_orig); // Should be assured by the Grob constructor
+ Skyline_pair v_skylines (*v_orig);
+
+ // possible if empty stencil
+ if (v_orig->is_empty ())
+ return current_offset;
+
+ Grob *vag = Grob::get_vertical_axis_group (me);
+ // possible if vetical axis group has been hara-kiri'd
+ if (!vag || !vag->is_live ())
+ return current_offset;
+
+ // ugh...gets called too often...?
+ Axis_group_interface::prepare_for_outside_staff_calculations (vag);
+ extract_grob_set (vag, "vertical-skyline-elements", elements);
+
+ Grob *x_common = common_refpoint_of_array (elements, vag, X_AXIS);
+ Grob *y_common = common_refpoint_of_array (elements, vag, Y_AXIS);
+
+ assert (y_common == vag);
+
+ Skyline_pair skylines;
+ SCM iss = vag->get_object ("inside-staff-skylines");
+ if (Skyline_pair *inside_staff_skylines = Skyline_pair::unsmob (iss))
+ skylines = Skyline_pair (*inside_staff_skylines);
+
+ // These are the skylines of all outside-staff grobs
+ // that have already been processed. We keep them around in order to
+ // check them for collisions with the currently active outside-staff grob.
+ Drul_array<vector<Skyline_pair> > all_v_skylines;
+ Drul_array<vector<Real> > all_paddings;
+ Drul_array<vector<Real> > all_horizon_paddings;
+ for (UP_and_DOWN (d))
+ {
+ all_v_skylines[d].push_back (skylines);
+ all_paddings[d].push_back (0);
+ all_horizon_paddings[d].push_back (0);
+ }
+
+ vsize i = 0;
+
+ // ensure inside staff elements are placed
+ for (; i < elements.size ()
+ && !scm_is_number (elements[i]->get_property ("outside-staff-priority")); i++)
+ (void) elements[i]->get_property ("Y-offset");
+
+ // then build skyline vector for placement
+ for (; i < elements.size () && elements[i] != me; i++)
+ {
+ Grob *elt = elements[i];
+ SCM elt_sky_scm = elt->get_property ("vertical-skylines");
+ Skyline_pair *elt_sky = Skyline_pair::unsmob (elt_sky_scm);
+ if (elt_sky->is_empty ())
+ continue;
+
+ Skyline_pair elt_v_skylines (*elt_sky);
+ elt_v_skylines.shift (elt->relative_coordinate (x_common, X_AXIS));
+ elt_v_skylines.raise (elt->relative_coordinate (y_common, Y_AXIS));
+ Real padding
+ = robust_scm2double (elt->get_property ("outside-staff-padding"), 0.25);
+ Real horizon_padding
+ = robust_scm2double (elt->get_property ("outside-staff-horizontal-padding"), 0.0);
+
+ all_v_skylines[dir].push_back (elt_v_skylines);
+ all_paddings[dir].push_back (padding);
+ all_horizon_paddings[dir].push_back (horizon_padding);
+ }
+
+ Real padding
+ = robust_scm2double (me->get_property ("outside-staff-padding"), 0.25);
+ Real horizon_padding
+ = robust_scm2double (me->get_property ("outside-staff-horizontal-padding"), 0.0);
+
+ if (dir == CENTER)
+ {
+ warning (_ ("an outside-staff object should have a direction, defaulting to up"));
+ dir = UP;
+ }
+
+ v_skylines.shift (me->relative_coordinate (x_common, X_AXIS));
+ Real mommy_offset = me->get_parent (Y_AXIS)->maybe_pure_coordinate (y_common, Y_AXIS, pure, start, end);
+ v_skylines.raise (current_offset + mommy_offset);
+
+ return current_offset
+ + distance_needed_to_avoid_outside_staff_collisions (&v_skylines,
+ padding,
+ horizon_padding,
+ all_v_skylines[dir],
+ all_paddings[dir],
+ all_horizon_paddings[dir],
+ dir);
+}
+
+void
+Outside_staff_interface::chain_y_offset_callback (Grob *me)
+{
+ chain_offset_callback (me,
+ ly_make_unpure_pure_container (y_aligned_side_proc, pure_y_aligned_side_proc),
+ Y_AXIS);
+}
+
+ADD_INTERFACE (Outside_staff_interface,
+ "Position a victim object (this one) outside the staff.",
+
+ /* properties */
+ "outside-staff-horizontal-padding "
+ "outside-staff-padding "
+ "outside-staff-priority "
+ );

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