lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: DurationLine avoiding RehearsalMarks


From: Jean Abou Samra
Subject: Re: DurationLine avoiding RehearsalMarks
Date: Tue, 12 Apr 2022 12:34:41 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.7.0

Le 12/04/2022 à 11:35, Thomas Morley a écrit :
Hi Jean,

this one is about codings

Am Mo., 11. Apr. 2022 um 18:04 Uhr schrieb Jean Abou Samra <jean@abou-samra.fr>:

How about adding a Scheme interface for Axis_group_interface::staff_extent
from lily/axis-group-interface.cc and using it in duration-line::print?
Please remember I don't know C++, thus I don't fully understand what's
done in lily/axis-group-interface.cc, same for the porting to scheme.
Maybe some comments would help.

Do you mean code comments?
Yes

Or comments from me in this email?
There is a (lonely) comment above staff_extent in the source:

/* This is like generic_group_extent, but it only counts the grobs that
     are children of some other axis-group. This is uncached; if it becomes
     commonly used, it may be necessary to cache it somehow. */


In short: it's roughly like ly:relative-group-extent, except that
it only takes the combined extents of grobs that are children of
a certain grob on a certain axis.
Yeah, I found this comment, it nicely describes the intended results
of using it.
But it didn't help me to understand all the details

[...]

The typical case would be

(axis-group-interface::staff-extent [NonMusicalPaperColumn] [System] X
[VerticalAxisGroup] Y)
This is a usage description, which I found very helpful.
 From here on I may have found my way.
Of course the explicit implementation below clears it all.

which gives you the width of the NonMusicalPaperColumn "on the
staff VerticalAxisGroup": instead of taking the union of the widths
of all breakable items in the NonMusicalPaperColumn, you just take
the extents of those items that are children of the VerticalAxisGroup.
If there are items on other staves, they are ignored in this
calculation.

My Scheme mock-code was meant to explain what this function
did (well, it would have been clearer if I had explained it with
words ...), but of course it would be preferable to export it from
C++, to avoid code duplication. If you want to experiment with it
in a patch, you can do the exporting part with
I would love to have it available as ly:axis-group-interface::selective-extent.
Though, I hesitate to upload a patch with the code below: it's your work!



Well, there hasn't been agreement about adding Scheme interfaces that
aren't used in the code base, so I hesitate to upload it alone ... If
you use it in a patch, feel free to put it in a separate commit attributed
to me (git commit --author="Jean Abou Samra <jean@abou-samra.fr>" ...).



And a I have a small understanding problem:

diff --git a/lily/axis-group-interface.cc b/lily/axis-group-interface.cc
index ede8e9686c..a7ad87791c 100644
--- a/lily/axis-group-interface.cc
+++ b/lily/axis-group-interface.cc
@@ -256,6 +256,25 @@ Axis_group_interface::staff_extent (Grob *me, Grob
*refp, Axis ext_a, Grob *staf
     return relative_group_extent (new_elts, refp, ext_a);
   }

+MAKE_DOCUMENTED_SCHEME_CALLBACK (Axis_group_interface,
selective_extent, 5,
+                                 R"(
+Return the combined extent of elements from @var{grob} on @var{axis}
+relative to @var{refpoint}.  Only retain those elements that are children
+of @var{staff} on @var{parent-axis}.
+                                 )");
+SCM
+Axis_group_interface::selective_extent (SCM grob, SCM refpoint, SCM
axis, SCM staff, SCM parent_axis)
+{
+  auto *const g = LY_ASSERT_SMOB (Grob, grob, 1);
+  auto *const r = LY_ASSERT_SMOB (Grob, refpoint, 2);
+  LY_ASSERT_TYPE (is_scm<Axis>, axis, 3);
+  Axis a = from_scm<Axis> (axis);
+  auto *const s = LY_ASSERT_SMOB (Grob, staff, 4);
+  LY_ASSERT_TYPE (is_scm<Axis>, parent_axis, 5);
+  Axis pa = from_scm<Axis> (parent_axis);
+  return to_scm (staff_extent (g, r, a, s, pa));
+}
+
   MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_pure_relevant_grobs, 1);
   SCM
   Axis_group_interface::calc_pure_relevant_grobs (SCM smob)
diff --git a/lily/include/axis-group-interface.hh
b/lily/include/axis-group-interface.hh
index 46f3369c05..4300e9a60a 100644
--- a/lily/include/axis-group-interface.hh
+++ b/lily/include/axis-group-interface.hh
@@ -47,6 +47,7 @@ public:
     DECLARE_SCHEME_CALLBACK (calc_pure_staff_staff_spacing, (SCM, SCM,
SCM));
     DECLARE_SCHEME_CALLBACK (calc_pure_relevant_grobs, (SCM));
     DECLARE_SCHEME_CALLBACK (calc_pure_y_common, (SCM));
+  DECLARE_SCHEME_CALLBACK (selective_extent, (SCM, SCM, SCM, SCM, SCM));
     static SCM internal_calc_pure_relevant_grobs (Grob *, const
std::string &);
     static Interval relative_group_extent (std::vector<Grob *> const &list,
                                            Grob *common, Axis);
@@ -72,4 +73,3 @@ public:
   };

   #endif /* AXIS_GROUP_INTERFACE_HH */
-
Why is below needed?

diff --git a/lily/include/lily-guile-macros.hh
b/lily/include/lily-guile-macros.hh
index 59fdd9c497..1842d70bc8 100644
--- a/lily/include/lily-guile-macros.hh
+++ b/lily/include/lily-guile-macros.hh
@@ -120,6 +120,12 @@ struct ly_scm_func_of_arity<4>
     typedef SCM (*ptr_type) (SCM, SCM, SCM, SCM);
   };

+template <>
+struct ly_scm_func_of_arity<5>
+{
+  typedef SCM (*ptr_type) (SCM, SCM, SCM, SCM, SCM);
+};
+
   /*
     Make TYPE::FUNC available as a Scheme function.
   */


Scheme macros are very powerful: they manipulate source expressions,
which are plain data (lists of symbols, strings, numbers, etc.), so
they can do any sort of programming on what they are fed with. (Modern
Scheme even has lexically scoped macros with syntax-rules/syntax-case,
see !1273.) C++ on the other hand has a very different macro story:
a macro is a simple textual transformation -- think writing code with
(format #f ...). The MAKE_SCHEME_CALLBACK macro takes an integer
number of arguments, in this case 5, and needs to construct the function
signature (SCM, SCM, SCM, SCM, SCM), where there are as many SCMs as
the integer (here, 5). This isn't possible to do just with literal
string templates, so the macro uses

ly_scm_func_of_arity<5>::ptr_type

where ly_scm_func_of_arity manually defines ly_scm_func_of_arity<0>::ptr_type -> (), ly_scm_func_of_arity<1>::ptr_type -> (SCM), ly_scm_func_of_arity<2> -> (SCM, SCM),
etc. This is all manual. Up to now, there had never been a need for
5-argument Scheme callbacks, so the ptr_types were only defined up
to 4.


What do you mean with:
(with whatever name: staff-extent, selective-extent, etc.)


I mean that there are lots of options for naming the function:
ly:axis-group-interface::staff-extent,
ly:axis-group-interface::selective-extent,
ly:axis-group-interface::extent-on-staff,
...


Probably unrelated:
ly:relative-group-extent accepts a grob-list, but errors if an empty
list provided.
Would it be feasible not to error but to return an empty-interval or '(0 . 0)?



Ouch, it definitely shouldn't error.
https://gitlab.com/lilypond/lilypond/-/merge_requests/1306
makes it return the empty interval. (I think that's the best choice,
as the union of 0 intervals is empty and "ly:relative-group-extent"
doesn't have "robust" in the name like "ly:grob-robust-relative-extent".
It is also what the C++ function already does).

Best,
Jean




reply via email to

[Prev in Thread] Current Thread [Next in Thread]