X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fstencil.cc;h=dc5549f6314393a0c3393fd088d62cee50db1b70;hb=90e4d7057f3857da049dfda3d130017d4719bd6b;hp=6a094d28905af39a9cbb831faeb772676f838a7d;hpb=55ac733b69643a6bc6a83b706c65cb56efd388ef;p=lilypond.git diff --git a/lily/stencil.cc b/lily/stencil.cc index 6a094d2890..dc5549f631 100644 --- a/lily/stencil.cc +++ b/lily/stencil.cc @@ -1,7 +1,7 @@ /* This file is part of LilyPond, the GNU music typesetter. - Copyright (C) 1997--2011 Han-Wen Nienhuys + Copyright (C) 1997--2015 Han-Wen Nienhuys LilyPond is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,7 +25,6 @@ #include "string-convert.hh" #include "warn.hh" -#include "ly-smobs.icc" Stencil::Stencil () { @@ -39,24 +38,13 @@ Stencil::Stencil (Box b, SCM func) dim_ = b; } -int -Stencil::print_smob (SCM, SCM port, scm_print_state *) -{ - scm_puts ("#", port); - return 1; -} - SCM -Stencil::mark_smob (SCM smob) +Stencil::mark_smob () const { - Stencil *s = (Stencil *) SCM_CELL_WORD_1 (smob); - return s->expr_; + return expr_; } -IMPLEMENT_SIMPLE_SMOBS (Stencil); -IMPLEMENT_TYPE_P (Stencil, "ly:stencil?"); -IMPLEMENT_DEFAULT_EQUAL_P (Stencil); +const char * const Stencil::type_p_name_ = "ly:stencil?"; Interval Stencil::extent (Axis a) const @@ -67,9 +55,14 @@ Stencil::extent (Axis a) const bool Stencil::is_empty () const { - return (expr_ == SCM_EOL - || dim_[X_AXIS].is_empty () - || dim_[Y_AXIS].is_empty ()); + return (scm_is_null (expr_) + || dim_.is_empty ()); +} + +bool +Stencil::is_empty (Axis a) const +{ + return dim_.is_empty (a); } SCM @@ -87,7 +80,7 @@ Stencil::extent_box () const void Stencil::rotate (Real a, Offset off) { - rotate_degrees (a * 180/M_PI, off); + rotate_degrees (a, off); } /* @@ -111,10 +104,10 @@ Stencil::rotate_degrees_absolute (Real a, Offset absolute_off) * *this = rotated() */ - expr_ = scm_list_n (ly_symbol2scm ("rotate-stencil"), - scm_list_2 (scm_from_double (a), - scm_cons (scm_from_double (x), scm_from_double (y))), - expr_, SCM_UNDEFINED); + expr_ = scm_list_3 (ly_symbol2scm ("rotate-stencil"), + scm_list_2 (scm_from_double (a), + scm_cons (scm_from_double (x), scm_from_double (y))), + expr_); /* * Calculate the new bounding box @@ -123,12 +116,12 @@ Stencil::rotate_degrees_absolute (Real a, Offset absolute_off) shifted_box.translate (-absolute_off); vector pts; - pts.push_back (Offset (shifted_box.x ().at(LEFT), shifted_box.y ().at(DOWN))); - pts.push_back (Offset (shifted_box.x ().at(RIGHT), shifted_box.y ().at(DOWN))); - pts.push_back (Offset (shifted_box.x ().at(RIGHT), shifted_box.y ().at(UP))); - pts.push_back (Offset (shifted_box.x ().at(LEFT), shifted_box.y ().at(UP))); + pts.push_back (Offset (shifted_box.x ().at (LEFT), shifted_box.y ().at (DOWN))); + pts.push_back (Offset (shifted_box.x ().at (RIGHT), shifted_box.y ().at (DOWN))); + pts.push_back (Offset (shifted_box.x ().at (RIGHT), shifted_box.y ().at (UP))); + pts.push_back (Offset (shifted_box.x ().at (LEFT), shifted_box.y ().at (UP))); - const Offset rot = complex_exp (Offset (0, a * M_PI / 180.0)); + const Offset rot (offset_directed (a)); dim_.set_empty (); for (vsize i = 0; i < pts.size (); i++) dim_.add_point (pts[i] * rot + absolute_off); @@ -158,26 +151,26 @@ Stencil::translate (Offset o) while (a < NO_AXES) { if (isinf (o[a]) - || isnan (o[a]) - - // ugh, hardcoded. - || fabs (o[a]) > 1e6) - { - programming_error (String_convert::form_string ("Improbable offset for stencil: %f staff space", o[a]) - + "\n" - + "Setting to zero."); - o[a] = 0.0; - if (strict_infinity_checking) - scm_misc_error (__FUNCTION__, "Improbable offset.", SCM_EOL); - } + || isnan (o[a]) + + // ugh, hardcoded. + || fabs (o[a]) > 1e6) + { + programming_error (String_convert::form_string ("Improbable offset for stencil: %f staff space", o[a]) + + "\n" + + "Setting to zero."); + o[a] = 0.0; + if (strict_infinity_checking) + scm_misc_error (__FUNCTION__, "Improbable offset.", SCM_EOL); + } incr (a); } - expr_ = scm_list_n (ly_symbol2scm ("translate-stencil"), - ly_offset2scm (o), - expr_, SCM_UNDEFINED); - if (!is_empty ()) - dim_.translate (o); + if (!scm_is_null (expr_)) + expr_ = scm_list_3 (ly_symbol2scm ("translate-stencil"), + ly_offset2scm (o), + expr_); + dim_.translate (o); } void @@ -192,9 +185,9 @@ void Stencil::scale (Real x, Real y) { expr_ = scm_list_3 (ly_symbol2scm ("scale-stencil"), - scm_list_2 (scm_from_double (x), - scm_from_double (y)), - expr_); + scm_list_2 (scm_from_double (x), + scm_from_double (y)), + expr_); dim_[X_AXIS] *= x; dim_[Y_AXIS] *= y; } @@ -202,7 +195,28 @@ Stencil::scale (Real x, Real y) void Stencil::add_stencil (Stencil const &s) { - expr_ = scm_list_3 (ly_symbol2scm ("combine-stencil"), s.expr_, expr_); + SCM cs = ly_symbol2scm ("combine-stencil"); + if (scm_is_null (expr_)) + expr_ = s.expr_; + else if (scm_is_null (s.expr_)) + ; + else if (scm_is_pair (expr_) + && scm_is_eq (cs, scm_car (expr_))) + { + if (scm_is_pair (s.expr_) + && scm_is_eq (cs, scm_car (s.expr_))) + expr_ = scm_append (scm_list_2 (s.expr_, scm_cdr (expr_))); + else + expr_ = scm_cons2 (cs, s.expr_, scm_cdr (expr_)); + } + else + { + if (scm_is_pair (s.expr_) + && scm_is_eq (cs, scm_car (s.expr_))) + expr_ = scm_append (scm_list_2 (s.expr_, scm_list_1 (expr_))); + else + expr_ = scm_list_3 (cs, s.expr_, expr_); + } dim_.unite (s.dim_); } @@ -224,7 +238,7 @@ Stencil::set_empty (bool e) void Stencil::align_to (Axis a, Real x) { - if (is_empty ()) + if (is_empty (a)) return; Interval i (extent (a)); @@ -232,37 +246,164 @@ Stencil::align_to (Axis a, Real x) } /* See scheme Function. */ + +// Any stencil that is empty in the orthogonal axis is spacing. +// Spacing is not subjected to the max (0) rule and can thus be +// negative. + void Stencil::add_at_edge (Axis a, Direction d, Stencil const &s, Real padding) { - Interval my_extent = dim_[a]; - Interval i (s.extent (a)); - Real his_extent; - if (i.is_empty ()) + // Material that is empty in the axis of reference has only limited + // usefulness for combining. We still retain as much information as + // available since there may be uses like setting page links or + // background color or watermarks, and off-axis extents. + + if (is_empty (a)) { - programming_error ("Stencil::add_at_edge: adding empty stencil."); - his_extent = 0.0; + add_stencil (s); + return; } - else - his_extent = i[-d]; - Real offset = (my_extent.is_empty () ? 0.0 : my_extent[d] - his_extent) - + d * padding; + Interval first_extent = extent (a); + + if (s.is_empty (a)) + { + Stencil toadd (s); + // translation does not affect axis-empty extent box. + toadd.translate_axis (first_extent[d], a); + add_stencil (toadd); + return; + } + + Interval next_extent = s.extent (a); + + bool first_is_spacing = is_empty (other_axis (a)); + bool next_is_spacing = s.is_empty (other_axis (a)); + + Real offset = first_extent[d] - next_extent[-d]; + + if (!(first_is_spacing || next_is_spacing)) + { + offset += d * padding; + } Stencil toadd (s); toadd.translate_axis (offset, a); add_stencil (toadd); } +// Stencil::stack is mainly used for assembling lines or columns +// of stencils. For the most common case of adding at the right, the +// reference point of the added stencil is usually placed at the right +// edge of the current one, unless the added stencil has a negative +// left extent in which case its left edge is placed at the right edge +// of the current one. +// +// Spacing is special in that it is applied without padding. Spacing +// at the right edge shifts the right edge accordingly. +// +// For spacing at the left edge, there are several approaches. In +// order to get to predictable behavior, we want to have at least a +// continuous approach. An obvious idea is to do a "translate" by the +// appropriate amount. Doing that while retaining the nominal left +// edge seems like the most straightforward way. + +void +Stencil::stack (Axis a, Direction d, Stencil const &s, Real padding, Real mindist) +{ + // Material that is empty in the axis of reference can't be sensibly + // stacked. We just revert to add_at_edge behavior then. + + if (is_empty (a)) + { + Stencil toadd (s); + toadd.add_stencil (*this); + expr_ = toadd.expr (); + dim_ = toadd.extent_box (); + return; + } + + Interval first_extent = extent (a); + + if (s.is_empty (a)) + { + Stencil toadd (s); + toadd.translate_axis (first_extent[d], a); + toadd.add_stencil (*this); + expr_ = toadd.expr (); + dim_ = toadd.extent_box (); + return; + } + + Interval next_extent = s.extent (a); + + // It is somewhat tedious to special-case all spacing, but it turns + // out that not doing so makes it astonishingly hard to make the + // code do the correct thing. + + // If first is spacing, we translate second accordingly without + // letting this affect its backward edge. + if (is_empty (other_axis (a))) + { + Stencil toadd (s); + Real offset = d * first_extent.delta (); + toadd.translate_axis (offset, a); + toadd.add_stencil (*this); + expr_ = toadd.expr (); + dim_ = toadd.extent_box (); + dim_[a][-d] = next_extent[-d]; + dim_[a][d] = next_extent[d] + offset; + return; + } + + // If next is spacing, similar action: + if (s.is_empty (other_axis (a))) + { + Stencil toadd (s); + Real offset = first_extent [d]; + toadd.translate_axis (offset, a); + toadd.add_stencil (*this); + expr_ = toadd.expr (); + dim_ = toadd.extent_box (); + dim_[a][-d] = first_extent[-d]; + dim_[a][d] = first_extent[d] + d * next_extent.delta (); + return; + } + + + Real offset = first_extent[d]; + + // If the added stencil has a backwardly protruding edge, we make + // room for it when combining. + + if (d * next_extent [-d] < 0) + offset -= next_extent [-d]; + + offset += d * padding; + + if (offset * d < mindist) + offset = d * mindist; + + Stencil toadd (s); + toadd.translate_axis (offset, a); + toadd.add_stencil (*this); + expr_ = toadd.expr (); + dim_ = toadd.extent_box (); + dim_[a][-d] = first_extent [-d]; + dim_[a][d] = next_extent [d] + offset; +} + + Stencil Stencil::in_color (Real r, Real g, Real b) const { Stencil new_stencil (extent_box (), - scm_list_3 (ly_symbol2scm ("color"), - scm_list_3 (scm_from_double (r), - scm_from_double (g), - scm_from_double (b)), - expr ())); + scm_list_3 (ly_symbol2scm ("color"), + scm_list_3 (scm_from_double (r), + scm_from_double (g), + scm_from_double (b)), + expr ())); return new_stencil; } @@ -274,3 +415,13 @@ Stencil::translated (Offset z) const s.translate (z); return s; } + +Stencil +Stencil::with_outline (Stencil const &ol) const +{ + Stencil new_stencil (ol.extent_box (), + scm_list_3 (ly_symbol2scm ("with-outline"), + ol.expr (), + expr ())); + return new_stencil; +}