################################################################
# different systems of a .ly file.
+def read_pipe (c):
+ print 'pipe' , c
+ return os.popen (c).read ()
+
+def system (c):
+ print 'system' , c
+ s = os.system (c)
+ if s :
+ raise Exception ("failed")
+ return
+
+def compare_png_images (old, new, dir):
+ def png_dims (f):
+ m = re.search ('([0-9]+) x ([0-9]+)', read_pipe ('file %s' % f))
+
+ return tuple (map (int, m.groups ()))
+
+ dims1 = png_dims (old)
+ dims2 = png_dims (new)
+
+ dims = (min (dims1[0], dims2[0]),
+ min (dims1[1], dims2[1]))
+
+ system ('convert -crop %dx%d+0+0 %s crop1.png' % (dims + (old,)))
+ system ('convert -crop %dx%d+0+0 %s crop2.png' % (dims + (new,)))
+
+ system ('compare crop1.png crop2.png diff.png')
+
+ system ("convert diff.png -border 2 -blur 0x3 -negate -channel alpha,blue -type TrueColorMatte -fx 'intensity' matte.png")
+
+ dest = os.path.join (dir, new.replace ('.png', '.compare.png'))
+ system ("composite matte.png %(new)s %(dest)s" % locals ())
class FileLink:
def __init__ (self):
self.add_system_link (link, system_index[0])
def link_files_for_html (self, old_dir, new_dir, dest_dir):
+ png_linked = [[], []]
for ext in ('.png', '.ly', '-page*png'):
+
for oldnew in (0,1):
for f in glob.glob (self.base_names[oldnew] + ext):
- print f
- link_file (f, dest_dir + '/' + f)
+ dst = dest_dir + '/' + f
+ link_file (f, dst)
+
+ if f.endswith ('.png'):
+ png_linked[oldnew].append (f)
+
+ for (old,new) in zip (png_linked[0], png_linked[1]):
+ compare_png_images (old, new, dest_dir)
def html_record_string (self, old_dir, new_dir):
def img_cell (ly, img, name):
def cell (base, name):
- pages = glob.glob (base + '-page*.png')
-
+ pat = base + '-page*.png'
+ pages = glob.glob (pat)
+
if pages:
return multi_img_cell (base + '.ly', sorted (pages), name)
else:
</tr>
''' % (self.distance (), html_2,
cell (self.base_names[0], name),
- cell (self.base_names[1], name))
+ cell (self.base_names[1], name).replace ('.png', '.compare.png'))
return html_entry
link.link_files_for_html (dir1, dir2, dest_dir)
link.write_html_system_details (dir1, dir2, dest_dir)
+
html += link.html_record_string (dir1, dir2)
## introduce differences
system ('cp 19-1.signature dir2/20-1.signature')
+ system ('cp 19.png dir2/20.png')
+ system ('cp 19multipage-page1.png dir2/20multipage-page1.png')
system ('cp 20-1.signature dir2/subdir/19-sub-1.signature')
+ system ('cp 20.png dir2/subdir/19-sub.png')
## radical diffs.
system ('cp 19-1.signature dir2/20grob-1.signature')
def run_tests ():
- dir = 'output-distance-test'
+ dir = 'test-output-distance'
do_clean = not os.path.exists (dir)
--- /dev/null
+\header
+{
+
+texidoc = "Even in case of incorrect contexts (eg. shortlived
+ contexts) that break linking of columns through spacing wishes,
+ @code{strict-note-spacing} defaults to a robust solution."
+
+}
+
+\version "2.11.2"
+
+
+%% \new Staff cause shortlived, disconnected Voice contexts
+%% breaking spacing-wishes links.
+\new Staff {
+ \override Score.SpacingSpanner #'strict-note-spacing = ##t
+ \afterGrace c'4 {c'32 c'32 }
+ c'4
+}
\header {
texidoc = "System separators maybe defined as markups in the
-@code{systemSeparator} field of the bookpaper block. They are centered
+@code{systemSeparator} field of the paper block. They are centered
between the boundary staffs of each system. "
}
TODO: prune to public interface.
*/
class Spacing_spanner
+
{
public:
+ static void set_distances_for_loose_col (Grob *me, Grob *c, Drul_array<Item *> next_door, Spacing_options const *);
static void generate_pair_spacing (Grob *me,
Paper_column *l, Paper_column *r,
Paper_column *nextr,
vector<Grob*> const &
internal_extract_grob_array (Grob const *elt, SCM symbol)
{
- return ly_scm2link_array (elt->internal_get_object (symbol));
+ return elt
+ ? ly_scm2link_array (elt->internal_get_object (symbol))
+ : empty_array;
}
vector<Item*>
if (!to_boolean (col->get_property ("allow-loose-spacing")))
return false;
+
if ((options->float_nonmusical_columns_
||options->float_grace_columns_)
&& Paper_column::when_mom (col).grace_part_)
- return true;
+ {
+ return true;
+ }
+
if (Paper_column::is_musical (col)
|| Paper_column::is_breakable (col))
return false;
- extract_grob_set (col, "right-neighbors", rns);
- extract_grob_set (col, "left-neighbors", lns);
-
/*
If this column doesn't have a proper neighbor, we should really
make it loose, but spacing it correctly is more than we can
such a borderline case.)
*/
+
+ extract_grob_set (col, "right-neighbors", rns);
+ extract_grob_set (col, "left-neighbors", lns);
+
if (lns.empty () || rns.empty ())
return false;
+
Item *l_neighbor = dynamic_cast<Item *> (lns[0]);
Item *r_neighbor = dynamic_cast<Item *> (rns[0]);
return true;
}
+void
+Spacing_spanner::set_distances_for_loose_col (Grob *me, Grob *c,
+ Drul_array<Item *> next_door,
+ Spacing_options const *options)
+{
+ Direction d = LEFT;
+ Drul_array<Real> dists (0, 0);
+
+ do
+ {
+ Item *lc = dynamic_cast<Item *> ((d == LEFT) ? next_door[LEFT] : c);
+ Item *rc = dynamic_cast<Item *> (d == LEFT ? c : next_door[RIGHT]);
+
+ extract_grob_set (lc, "spacing-wishes", wishes);
+ for (vsize k = wishes.size (); k--;)
+ {
+ Grob *sp = wishes[k];
+ if (Note_spacing::left_column (sp) != lc
+ || Note_spacing::right_column (sp) != rc)
+ continue;
+
+ if (Note_spacing::has_interface (sp))
+ {
+ /*
+ The note spacing should be taken from the musical
+ columns.
+ */
+ Real space = 0.0;
+ Real fixed = 0.0;
+ bool dummy = false;
+
+ Real base = note_spacing (me, lc, rc, options, &dummy);
+ Note_spacing::get_spacing (sp, rc, base, options->increment_,
+ &space, &fixed);
+
+ space -= options->increment_;
+
+ dists[d] = max (dists[d], space);
+ }
+ else if (Staff_spacing::has_interface (sp))
+ {
+ Real space = 0;
+ Real fixed_space = 0;
+ Staff_spacing::get_spacing_params (sp,
+ &space, &fixed_space);
+
+ dists[d] = max (dists[d], fixed_space);
+ }
+ else
+ programming_error ("Subversive spacing wish");
+ }
+ }
+ while (flip (&d) != LEFT);
+
+ Rod r;
+ r.distance_ = dists[LEFT] + dists[RIGHT];
+ r.item_drul_ = next_door;
+
+ r.add_to_cols ();
+}
+
+
/*
Remove columns that are not tightly fitting from COLS. In the
removed columns, set 'between-cols to the columns where it is in
*/
extract_grob_set (unsmob_grob (rns), "right-items", right_items);
- c->set_object ("between-cols", scm_cons (lns,
- right_items[0]->self_scm ()));
-
- /*
- Set distance constraints for loose columns
- */
- Drul_array<Grob *> next_door (cols->at (i - 1),
- cols->at (i + 1));
- Direction d = LEFT;
- Drul_array<Real> dists (0, 0);
-
- do
+ if (right_items.size () == 0 || !unsmob_grob (lns))
{
- Item *lc = dynamic_cast<Item *> ((d == LEFT) ? next_door[LEFT] : c);
- Item *rc = dynamic_cast<Item *> (d == LEFT ? c : next_door[RIGHT]);
-
- extract_grob_set (lc, "spacing-wishes", wishes);
- for (vsize k = wishes.size (); k--;)
- {
- Grob *sp = wishes[k];
- if (Note_spacing::left_column (sp) != lc
- || Note_spacing::right_column (sp) != rc)
- continue;
-
- if (Note_spacing::has_interface (sp))
- {
- /*
- The note spacing should be taken from the musical
- columns.
- */
- Real space = 0.0;
- Real fixed = 0.0;
- bool dummy = false;
-
- Real base = note_spacing (me, lc, rc, options, &dummy);
- Note_spacing::get_spacing (sp, rc, base, options->increment_,
- &space, &fixed);
-
- space -= options->increment_;
-
- dists[d] = max (dists[d], space);
- }
- else if (Staff_spacing::has_interface (sp))
- {
- Real space = 0;
- Real fixed_space = 0;
- Staff_spacing::get_spacing_params (sp,
- &space, &fixed_space);
-
- dists[d] = max (dists[d], fixed_space);
- }
- else
- programming_error ("Subversive spacing wish");
- }
+ c->programming_error ("Can't determine neighbors for floating column. ");
+ c->set_object ("between-cols", scm_cons (cols->at (i-1)->self_scm (),
+ cols->at (i+1)->self_scm ()));
}
- while (flip (&d) != LEFT);
+ else
+ {
+ c->set_object ("between-cols", scm_cons (lns,
+ right_items[0]->self_scm ()));
- Rod r;
- r.distance_ = dists[LEFT] + dists[RIGHT];
- r.item_drul_[LEFT] = dynamic_cast<Item *> (cols->at (i - 1));
- r.item_drul_[RIGHT] = dynamic_cast<Item *> (cols->at (i + 1));
+ /*
+ Set distance constraints for loose columns
+ */
+ Drul_array<Item *> next_door (dynamic_cast<Item*> (cols->at (i - 1)),
+ dynamic_cast<Item*> (cols->at (i + 1)));
- r.add_to_cols ();
+ set_distances_for_loose_col (me, c, next_door, options);
+ }
}
- else
+
+ if (!loose)
newcols.push_back (c);
}
using namespace std;
void
-Tie_column::add_tie (Grob *me, Grob *tie)
+Tie_column::add_tie (Grob *tc, Grob *tie)
{
+ Spanner *me = dynamic_cast<Spanner *> (tc);
+
if (tie->get_parent (Y_AXIS)
&& Tie_column::has_interface (tie->get_parent (Y_AXIS)))
return;
- if (!Pointer_group_interface::count (me, ly_symbol2scm ("ties")))
+ if (!me->get_bound (LEFT)
+ || (Paper_column::get_rank (me->get_bound (LEFT)->get_column ())
+ > Paper_column::get_rank (dynamic_cast<Spanner*> (tie)->get_bound (LEFT)->get_column ())))
{
- dynamic_cast<Spanner *> (me)->set_bound (LEFT, Tie::head (tie, LEFT));
- dynamic_cast<Spanner *> (me)->set_bound (RIGHT, Tie::head (tie, RIGHT));
+ me->set_bound (LEFT, Tie::head (tie, LEFT));
+ me->set_bound (RIGHT, Tie::head (tie, RIGHT));
}
-
+
tie->set_parent (me, Y_AXIS);
Pointer_group_interface::add_grob (me, ly_symbol2scm ("ties"), tie);
}