Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2023 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 : #pragma once
23 :
24 : #include "vectorview.h"
25 :
26 : #include "shape.h"
27 :
28 : namespace mu::engraving {
29 : class Accidental;
30 : class Chord;
31 : class EngravingItem;
32 : class LedgerLine;
33 : class Shape;
34 : struct ShapeElement;
35 : }
36 :
37 : namespace mu::engraving::rendering::score {
38 : class LayoutContext;
39 :
40 : using AccidentalGroups = std::vector<std::vector<Accidental*> >;
41 :
42 : class AccidentalsLayout
43 : {
44 : public:
45 : static void layoutAccidentals(const std::vector<Chord*>& chords, LayoutContext& ctx);
46 :
47 : private:
48 : struct AccidentalsLayoutContext {
49 : AccidentalsLayoutContext (std::vector<Accidental*> acc, std::vector<Chord*> ch);
50 :
51 : std::vector<Accidental*> allAccidentals;
52 : std::vector<Chord*> chords;
53 : AccidentalGroups accidentalSubChords;
54 : std::vector<Accidental*> stackedAccidentals;
55 : Shape stackedAccidentalsShape;
56 : Shape chordsShape;
57 : size_t subChordsCountBeforeOctaveMerge = 1;
58 :
59 80878 : double spatium() const { return m_spatium; }
60 5196 : double verticalAccidentalToAccidentalClearance() const { return m_verticalAccidentalToAccidentalClearance; }
61 13436 : double verticalSharpToSharpClearance() const { return m_verticalSharpToSharpClearance; }
62 136035 : double verticalAccidentalToChordClearance() const { return m_verticalAccidentalToChordClearance; }
63 17641 : double accidentalAccidentalDistance() const { return m_accidentalAccidentalDistance; }
64 2891 : double additionalPaddingForVerticals() const { return m_additionalPaddingForVerticals; }
65 3581 : double xPosSplitThreshold() const { return m_xPosSplitThreshold; }
66 352 : double xVerticalAlignmentThreshold() const { return m_xVerticalAlignmentThreshold; }
67 8567 : double sharpAndNaturalLedgerLinePadding() const { return m_sharpAndNaturalLedgerLinePadding; }
68 550 : double reducedFlatToNotePadding() const { return m_reducedFlatToNotePadding; }
69 129 : double flatKerningOfFourth() const { return m_flatKerningOfFourth; }
70 6 : double naturalKerningOfFourth() const { return m_naturalKerningOfFourth; }
71 :
72 3128 : bool orderFollowNoteDisplacement() const { return m_orderFollowNoteDisplacement; }
73 6241 : bool alignOctavesAcrossSubChords() const { return m_alignOctavesAcrossSubChords; }
74 4275 : bool keepSecondsTogether() const { return m_keepSecondsTogether; }
75 3043 : bool alignOffsetOctaves() const { return m_alignOffsetOctaves; }
76 120 : size_t largeGroupLimit() const { return m_largeGroupLimit; }
77 3458 : size_t smallGroupLimit() const { return m_smallGroupLimit; }
78 :
79 : private:
80 : void initConstants();
81 :
82 : double m_spatium = 0.0;
83 : double m_verticalAccidentalToAccidentalClearance = 0.0;
84 : double m_verticalSharpToSharpClearance = 0.0;
85 : double m_verticalAccidentalToChordClearance = 0.0;
86 : double m_accidentalAccidentalDistance = 0.0;
87 : double m_additionalPaddingForVerticals = 0.0;
88 : double m_xPosSplitThreshold = 0.0;
89 : double m_xVerticalAlignmentThreshold = 0.0;
90 : double m_sharpAndNaturalLedgerLinePadding = 0.0;
91 : double m_reducedFlatToNotePadding = 0.0;
92 : double m_flatKerningOfFourth = 0.0;
93 : double m_naturalKerningOfFourth = 0.0;
94 : bool m_orderFollowNoteDisplacement = false;
95 : bool m_alignOctavesAcrossSubChords = false;
96 : bool m_keepSecondsTogether = false;
97 : bool m_alignOffsetOctaves = false;
98 :
99 : static constexpr size_t m_smallGroupLimit = 3;
100 : static constexpr size_t m_largeGroupLimit = 6;
101 : };
102 :
103 : using AccidentalsVectorView = muse::VectorView<Accidental*>;
104 :
105 : static void collectAccidentals(const std::vector<Chord*> chords, std::vector<Accidental*>& allAccidentals,
106 : std::vector<Accidental*>& redundantAccidentals, std::vector<Accidental*>& invisibleAccidentals);
107 : static bool accidentalIsRedundant(const Accidental* acc, const std::vector<Accidental*>& allAccidentals);
108 :
109 : static void doAccidentalPlacement(AccidentalsLayoutContext& ctx);
110 :
111 : static void findOctavesAndSeconds(const AccidentalsLayoutContext& ctx);
112 :
113 : static void splitIntoSubChords(AccidentalsLayoutContext& ctx);
114 : static void mergeAdjacentSubGroupsIfTooSmall(AccidentalsLayoutContext& ctx);
115 : static void mergeSubGroupsWithOctavesAcross(AccidentalsLayoutContext& ctx);
116 :
117 : static void createChordsShape(AccidentalsLayoutContext& ctx);
118 :
119 : static void layoutSubChord(std::vector<Accidental*>& accidentals, AccidentalsLayoutContext& ctx);
120 : static void stackAccidental(Accidental* acc, AccidentalsLayoutContext& ctx);
121 :
122 : static void computeOrdering(std::vector<Accidental*>& accidentals, AccidentalsLayoutContext& ctx);
123 : static AccidentalGroups splitIntoPriorityGroups(std::vector<Accidental*>& accidentals, AccidentalsLayoutContext& ctx);
124 :
125 : static AccidentalGroups splitAccordingToAccidDisplacement(std::vector<Accidental*>& accidentals, const AccidentalsLayoutContext& ctx);
126 : static AccidentalGroups groupAccidentalsByXPos(std::vector<Accidental*>& accidentals, const AccidentalsLayoutContext& ctx);
127 : static void moveOctavesToSecondGroup(AccidentalGroups& subGroups);
128 :
129 : static AccidentalGroups splitAccordingToNoteDisplacement(std::vector<Accidental*>& accidentals, const AccidentalsLayoutContext& ctx);
130 : static AccidentalGroups groupAccidentalsByNoteXPos(const std::vector<Accidental*>& accidentals);
131 : static void moveSecondsInSameGroup(AccidentalGroups& subGroups);
132 :
133 : static void determineStackingOrder(std::vector<Accidental*>& accidentals, AccidentalsLayoutContext& ctx);
134 : static void computeStandardOrdering(std::vector<Accidental*>& accidentals, AccidentalsLayoutContext& ctx);
135 : static void computeCompactOrdering(std::vector<Accidental*>& accidentals, AccidentalsLayoutContext& ctx);
136 : static void computeOrderingWithLeastColumns(std::vector<Accidental*>& accidentals, AccidentalsLayoutContext& ctx);
137 : static void findAndInsertSecond(Accidental* acc, std::vector<Accidental*>& accidentalsPlaced, AccidentalsVectorView& accidentalsToPlace,
138 : AccidentalsLayoutContext& ctx);
139 : static bool findAndInsertOctave(Accidental* acc, std::vector<Accidental*>& accidentalsPlaced, AccidentalsVectorView& accidentalsToPlace,
140 : AccidentalsLayoutContext& ctx, bool acceptAbove = true, bool acceptBelow = true);
141 :
142 : static void applyOrderingOffsets(std::vector<Accidental*>& accidentals);
143 :
144 : static double minAccidentalToChordDistance(Accidental* acc, const Shape& accShape, const AccidentalsLayoutContext& ctx);
145 : static double kerningLimitationsIntoChord(Accidental* acc, const Shape& accShape, const ShapeElement& chordElement,
146 : const AccidentalsLayoutContext& ctx);
147 : static double computePadding(Accidental* acc, const EngravingItem* chordElement, const AccidentalsLayoutContext& ctx);
148 :
149 : static double minAccidentalToAccidentalGroupDistance(Accidental* acc, Shape accShape, const Shape& accidentalsShape,
150 : const AccidentalsLayoutContext& ctx);
151 : static double kerningOfFourth(const Shape& accShape, const ShapeElement& accGroupShapeElement, const AccidentalsLayoutContext& ctx);
152 : static void checkZeroColumn(Accidental* acc, const AccidentalsLayoutContext& ctx);
153 :
154 : static double additionalPaddingForVerticals(const Accidental* acc, const EngravingItem* item, const AccidentalsLayoutContext& ctx);
155 :
156 : static void verticallyAlignAccidentals(AccidentalsLayoutContext& ctx);
157 : static void collectVerticalSetsOfOffsetOctaves(std::set<Accidental*>& accidentalsAlreadyGrouped, std::map<Accidental*,
158 : std::vector<Accidental*> >& verticalSets, AccidentalsLayoutContext& ctx);
159 : static void collectVerticalSets(std::set<Accidental*>& accidentalsAlreadyGrouped, std::map<Accidental*,
160 : std::vector<Accidental*> >& verticalSets,
161 : AccidentalsLayoutContext& ctx);
162 : static void alignVerticalSets(AccidentalGroups& vertSets, AccidentalsLayoutContext& ctx);
163 :
164 : static double verticalPadding(const Accidental* acc1, const Accidental* acc2, const AccidentalsLayoutContext& ctx);
165 : static bool canFitInSameColumn(const Accidental* acc1, const Accidental* acc2, AccidentalsLayoutContext& ctx);
166 :
167 : static double horizontalPadding(const Accidental* acc1, const Accidental* acc2, const AccidentalsLayoutContext& ctx);
168 :
169 : static bool isExceptionOfFourth(const Accidental* acc1, const Accidental* acc2);
170 : static bool isExceptionOfNaturalsSixth(const Accidental* acc1, const Accidental* acc2);
171 : static bool isOctave(const Accidental* acc1, const Accidental* acc2);
172 :
173 : static void setXposRelativeToSegment(Accidental* accidental, double x);
174 : static double xPosRelativeToSegment(const Accidental* accidental);
175 :
176 : static void sortTopDown(std::vector<Accidental*>& accidentals);
177 :
178 : static bool keepAccidentalsCloseToChord(const Chord* chord);
179 : };
180 : }
|