Closed dmitrio95 closed 3 years ago
Thanks! I will review this after the other PRs, hope very soon
Great! The solution looks promising and improves the layout in all scores with wedges in the regression test set. So I will merge it.
It turns out that note and rest shapes currently belong to a GmoBoxSliceStaff box which maintain a list of their child shapes in engraving order. As staff objects seem to be engraved ordered by time, shapes in the GmoBoxSliceStaff's list are also sorted by the time of the corresponding internal model objects. They are not however sorted by their x coordinates, and in order to obtain the leftmost note at a certain position one has to check all the notes in the current time position. Also the same list contains shapes for auxiliary and relation objects which are already engraved, so only a part of this list is useful for engravers.
Its been years since I do not touch the GM so I do not remember some details. As I remember, the GM was designed to satisfy three needs:
For renderization, each GmoBox is traversed and the contained shapes asked to draw themselves. No special requirements on ordering for StaffObjs shapes, thus they are currently ordered in engraving order. But other shapes must be ordered in z-order (bottom layer first). As z-order is taken into account by AuxObjs engravers, shapes for AuxObjs must be stored in engraving order. Therefore, I do not see problems in splitting the list in two, one for StaffObjs shapes and other for AuxObjs shapes. Also I do not see problems in inserting the StaffObjs shapes in order, instead of appended at the end, to keep the list ordered by xPos if more convenient for engravers.
To find the Shape pointed by the mouse or inside a rectangle, in each document page (GmoBoxDocPage) there is a list containing the shapes in that page, ordered by layer and creation order. Thus, by iterating this list it is easy to find the shape at the given point. This is slow for other tasks, but not for user interaction related methods. This list is redundant and could be removed to save memory, as the same results can be obtained traversing the boxes and the contained shapes. But I postponed optimizations until I had a clear view of all the needs and Lomse was advanced enough.
There are two global maps std::map<ImoId, GmoShape*>
and std::map<ImoId, GmoBox*>
oriented to solve the needs to locate the shape or box generated by and ImoObj.
And, finally, the GmoBoxSystem box contains a table relating timepos to x positions, useful to locate the x left position for a note/rest or a barline.
Concerning the end point of a wedge, ...
To me, the Elaine Gould book is the bible, so when there are doubts I normally rely on it. If it does not solve my doubts I also look up these two:
And, finally, the GmoBoxSystem box contains a table relating timepos to x positions, useful to locate the x left position for a note/rest or a barline.
Actually when creating #309 I have initially thought about something like this sort of structure, didn't realize that this already exists. Still engravers need some more detailed information like notehead edges (without accidentals or whatever else), and it is probably not worth it to maintain this information for the entire score.
To me, the Elaine Gould book is the bible, so when there are doubts I normally rely on it. If it does not solve my doubts I also look up these two:
* Gardner Read, “Music notation. A manual of modern practice”, 1982 * Kurt Stone, “Music notation in the twenty century”, 1980
Thanks, I'll try to check these books as well. My doubts in this case are because there seem to be multiple common options in use, so it would be interesting to see what other sources state on this topic.
For score edition oriented applications, I thought it would be convenient to display the estimated time position at the position pointed by the mouse, so that the user could decide where to insert a note/rest. Remember that lomse edition model is not constrained by measures, as MuseScore and most editors do. Lomse model is blank paper and objects can be inserted at any place without restrictions.
Thus, for this purpose, it was necessary to maintain a table xPos/Timepos (the TimeGridTable) for all occupied x positions. Also, with this table, in mouse data entry mode the editor could automatically display a grid pattern, with grey vertical lines indicating where the note/rest can be placed. The grid lines positions are based on the note value selected in a tool box. To option to display this grid is currently disabled, and I'm still considering the convenience or not of providing this facility.
The TimeGridTable is a table with the relation timepos <-> position for all valid positions to insert a note. The recorded positions are for the center of note heads or rests (not sure, perhaps later I changed this and now are the left side; I need to check this). The last position is for the barline (if exists). This object is responsible for supplying all valid timepos and their x positions so that other objects could:
a) Determine the timepos to assign to a mouse click in a certain position. b) Draw a grid of valid timepos
There is a TimeGridTable for each system, stored and owned by GmoBoxSystem, but GmoBoxSystem just owns the table and provides access to it. All methods to manage the table and to provide information are on the TimeGridTable object.
Later, this table was very useful for other purposes, such as locating positions for implementing methods so that the user application can move the tempo line (playback visual effect) to a given position or to display 'fragment marks' (http://lenmus.github.io/lomse/classFragmentMark.html). For instance:
Yes, the table is indeed useful, I just thought that adding more engraving-related information to it would likely be not worth the potential benefit. Sorry if this was not clear from my previous comment.
oh no, sorry! Your comments were clear. It is just that I added more information to explain how it was used.
This pull request provides a proof-of-concept implementation of a horizontal alignment of an object attached to an
ImoDirection
to staff object shapes by finding them in the graphical model, like discussed in #309.It turns out that note and rest shapes currently belong to a
GmoBoxSliceStaff
box which maintain a list of their child shapes in engraving order. As staff objects seem to be engraved ordered by time, shapes in theGmoBoxSliceStaff
's list are also sorted by the time of the corresponding internal model objects. They are not however sorted by theirx
coordinates, and in order to obtain the leftmost note at a certain position one has to check all the notes in the current time position. Also the same list contains shapes for auxiliary and relation objects which are already engraved, so only a part of this list is useful for engravers.To handle all this I have implemented a helper
StaffObjShapeCursor
class which implements basic iterating overGmoBox
child shapes with filtering of staff object shapes and support for basic time point limitations. Currently it iterates only overGmoBoxSliceStaff
which makes it limited only to a current measure and staff but it can potentially be expanded to handle the entire instrument or all instruments and to support iterating over several measures. Even with these limitations it can be useful but from what I see expanding iteration abilities of this cursor will likely be needed in future. For example, the current cursor does not allow to handle wedges attached to a direction starting before a barline, like in the situation described in #277. However I am not sure about the semantics of such MusicXML encoding, perhaps in that case it was intended to leave the wedge start before that barline.To demonstrate the usage of the newly implemented cursor I have implemented some changes to the wedge horizontal positioning.
First, I have added an alignment of a wedge start to its starting note when it is possible to determine one with the current implementation of the cursor. If it is not possible I have added a small offset to the old position, just to avoid a possible collision with a barline in cases like #277.
Concerning the end point of a wedge, the situation seems to be a bit more difficult. From what I see in "Behind Bars" Gould recommends aligning a wedge end to the start of the next notehead (which is close to what Lomse does currently), Lilypond according to its documentation aligns it to the end note's right edge, and in printed music I have observed really different options of that. Therefore in this PR I went for a more conservative approach and just added an offset before the barline if a wedge happens to end just before it. The option to align a wedge end to the end note's right edge is also trivial to implement with the new cursor, although it does not currently handle notes in a different staff of the same instrument, like mentioned above.
Therefore to reach its full potential
StaffObjShapeCursor
will probably need to be expanded, and possibly some minor changes to the internal model may be needed to improve performance of the cursor if it happens to be slow (for example, to avoid linear search for the shape position in the list). However this method may already be useful even with its current limitations. Therefore if we decide to go that way this PR can be useful as it is, or I can try to expand the cursor further to see how it will look like if multiple staves and measures are to be handled.