Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 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 :
23 : #include "connector.h"
24 :
25 : #include "engravingitem.h"
26 : #include "engravingobject.h"
27 : #include "score.h"
28 :
29 : #include "log.h"
30 :
31 : using namespace mu;
32 : using namespace mu::engraving;
33 :
34 : namespace mu::engraving {
35 : //---------------------------------------------------------
36 : // ConnectorInfo
37 : //---------------------------------------------------------
38 :
39 3903 : ConnectorInfo::ConnectorInfo(const EngravingItem* current, int track, Fraction frac)
40 3903 : : m_currentLoc(Location::absolute()), m_current(current), m_score(current->score())
41 : {
42 3903 : IF_ASSERT_FAILED(current) {
43 0 : return;
44 : }
45 :
46 : // It is not always possible to determine the track number correctly from
47 : // the current element (for example, in case of a Segment).
48 : // If the caller does not know the track number and passes -1
49 : // it may be corrected later.
50 3903 : if (track >= 0) {
51 3903 : m_currentLoc.setTrack(track);
52 : }
53 3903 : if (frac >= Fraction(0, 1)) {
54 0 : m_currentLoc.setFrac(frac);
55 : }
56 : }
57 :
58 : //---------------------------------------------------------
59 : // ConnectorInfo
60 : //---------------------------------------------------------
61 :
62 0 : ConnectorInfo::ConnectorInfo(const Score* score, const Location& currentLocation)
63 0 : : m_currentLoc(currentLocation), m_score(score)
64 0 : {}
65 :
66 : //---------------------------------------------------------
67 : // ConnectorInfo::updateLocation
68 : //---------------------------------------------------------
69 :
70 3903 : void ConnectorInfo::updateLocation(const EngravingItem* e, Location& l, bool clipboardmode)
71 : {
72 3903 : l.fillForElement(e, clipboardmode);
73 3903 : }
74 :
75 : //---------------------------------------------------------
76 : // ConnectorInfo::updateCurrentInfo
77 : //---------------------------------------------------------
78 :
79 3903 : void ConnectorInfo::updateCurrentInfo(bool clipboardmode)
80 : {
81 3903 : if (!currentUpdated() && m_current) {
82 3903 : updateLocation(m_current, m_currentLoc, clipboardmode);
83 : }
84 3903 : setCurrentUpdated(true);
85 3903 : }
86 :
87 : //---------------------------------------------------------
88 : // ConnectorInfo::connect
89 : //---------------------------------------------------------
90 :
91 5008 : bool ConnectorInfo::connect(ConnectorInfo* other)
92 : {
93 5008 : if (!other || (this == other)) {
94 1954 : return false;
95 : }
96 3054 : if (m_type != other->m_type || m_score != other->m_score) {
97 405 : return false;
98 : }
99 2705 : if (hasPrevious() && m_prev == nullptr
100 2705 : && other->hasNext() && other->m_next == nullptr
101 : ) {
102 44 : if ((m_prevLoc == other->m_currentLoc)
103 44 : && (m_currentLoc == other->m_nextLoc)
104 : ) {
105 35 : m_prev = other;
106 35 : other->m_next = this;
107 35 : return true;
108 : }
109 : }
110 5207 : if (hasNext() && m_next == nullptr
111 5207 : && other->hasPrevious() && other->m_prev == nullptr
112 : ) {
113 1941 : if ((m_nextLoc == other->m_currentLoc)
114 1941 : && (m_currentLoc == other->m_prevLoc)
115 : ) {
116 1914 : m_next = other;
117 1914 : other->m_prev = this;
118 1914 : return true;
119 : }
120 : }
121 700 : return false;
122 : }
123 :
124 : //---------------------------------------------------------
125 : // ConnectorInfo::forceConnect
126 : //---------------------------------------------------------
127 :
128 2 : void ConnectorInfo::forceConnect(ConnectorInfo* other)
129 : {
130 2 : if (!other || (this == other)) {
131 0 : return;
132 : }
133 2 : m_next = other;
134 2 : other->m_prev = this;
135 : }
136 :
137 : //---------------------------------------------------------
138 : // distance
139 : //---------------------------------------------------------
140 :
141 2 : static int distance(const Location& l1, const Location& l2)
142 : {
143 2 : constexpr int commonDenominator = 1000;
144 2 : Fraction dfrac = (l2.frac() - l1.frac()).absValue();
145 2 : int dpos = dfrac.numerator() * commonDenominator / dfrac.denominator();
146 2 : dpos += 10000 * std::abs(l2.measure() - l1.measure());
147 2 : return 1000 * dpos + 100 * std::abs(l2.track() - l1.track()) + 10 * std::abs(l2.note() - l1.note()) + std::abs(
148 2 : l2.graceIndex() - l1.graceIndex());
149 : }
150 :
151 : //---------------------------------------------------------
152 : // ConnectorInfo::orderedConnectionDistance
153 : //---------------------------------------------------------
154 :
155 2 : int ConnectorInfo::orderedConnectionDistance(const ConnectorInfo& c1, const ConnectorInfo& c2)
156 : {
157 2 : Location c1Next = c1.m_nextLoc;
158 2 : c1Next.toRelative(c1.m_currentLoc);
159 2 : Location c2Prev = c2.m_currentLoc; // inversed order to get equal signs
160 2 : c2Prev.toRelative(c2.m_prevLoc);
161 2 : if (c1Next == c2Prev) {
162 2 : return distance(c1.m_nextLoc, c2.m_currentLoc);
163 : }
164 0 : return INT_MAX;
165 : }
166 :
167 : //---------------------------------------------------------
168 : // ConnectorInfo::connectionDistance
169 : // Returns a "distance" representing a likelihood of
170 : // that the checked connectors should be connected.
171 : // Returns 0 if can be readily connected via connect(),
172 : // < 0 if other is likely to be the first,
173 : // INT_MAX if cannot be connected
174 : //---------------------------------------------------------
175 :
176 6 : int ConnectorInfo::connectionDistance(const ConnectorInfo& other) const
177 : {
178 6 : if (m_type != other.m_type || m_score != other.m_score) {
179 4 : return INT_MAX;
180 : }
181 2 : int distThisOther = INT_MAX;
182 2 : int distOtherThis = INT_MAX;
183 2 : if (hasNext() && m_next == nullptr
184 2 : && other.hasPrevious() && other.m_prev == nullptr) {
185 0 : distThisOther = orderedConnectionDistance(*this, other);
186 : }
187 4 : if (hasPrevious() && m_prev == nullptr
188 4 : && other.hasNext() && other.m_next == nullptr) {
189 2 : distOtherThis = orderedConnectionDistance(other, *this);
190 : }
191 2 : if (distOtherThis < distThisOther) {
192 2 : return -distOtherThis;
193 : }
194 0 : return distThisOther;
195 : }
196 :
197 : //---------------------------------------------------------
198 : // ConnectorInfo::findFirst
199 : //---------------------------------------------------------
200 :
201 5861 : ConnectorInfo* ConnectorInfo::findFirst()
202 : {
203 5861 : ConnectorInfo* i = this;
204 7851 : while (i->m_prev) {
205 1990 : i = i->m_prev;
206 1990 : if (i == this) {
207 0 : LOGW("ConnectorInfo::findFirst: circular connector %p", this);
208 0 : return nullptr;
209 : }
210 : }
211 5861 : return i;
212 : }
213 :
214 : //---------------------------------------------------------
215 : // ConnectorInfo::findFirst
216 : //---------------------------------------------------------
217 :
218 1954 : const ConnectorInfo* ConnectorInfo::findFirst() const
219 : {
220 1954 : return const_cast<ConnectorInfo*>(this)->findFirst();
221 : }
222 :
223 : //---------------------------------------------------------
224 : // ConnectorInfo::findLast
225 : //---------------------------------------------------------
226 :
227 1953 : ConnectorInfo* ConnectorInfo::findLast()
228 : {
229 1953 : ConnectorInfo* i = this;
230 3869 : while (i->m_next) {
231 1916 : i = i->m_next;
232 1916 : if (i == this) {
233 0 : LOGW("ConnectorInfo::findLast: circular connector %p", this);
234 0 : return nullptr;
235 : }
236 : }
237 1953 : return i;
238 : }
239 :
240 : //---------------------------------------------------------
241 : // ConnectorInfo::findLast
242 : //---------------------------------------------------------
243 :
244 1953 : const ConnectorInfo* ConnectorInfo::findLast() const
245 : {
246 1953 : return const_cast<ConnectorInfo*>(this)->findLast();
247 : }
248 :
249 : //---------------------------------------------------------
250 : // ConnectorInfo::finished
251 : //---------------------------------------------------------
252 :
253 1954 : bool ConnectorInfo::finished() const
254 : {
255 1954 : return finishedLeft() && finishedRight();
256 : }
257 :
258 : //---------------------------------------------------------
259 : // ConnectorInfo::finishedLeft
260 : //---------------------------------------------------------
261 :
262 1954 : bool ConnectorInfo::finishedLeft() const
263 : {
264 1954 : const ConnectorInfo* i = findFirst();
265 1954 : return i && !i->hasPrevious();
266 : }
267 :
268 : //---------------------------------------------------------
269 : // ConnectorInfo::finishedRight
270 : //---------------------------------------------------------
271 :
272 1953 : bool ConnectorInfo::finishedRight() const
273 : {
274 1953 : const ConnectorInfo* i = findLast();
275 1953 : return i && !i->hasNext();
276 : }
277 :
278 : //---------------------------------------------------------
279 : // ConnectorInfo::start
280 : //---------------------------------------------------------
281 :
282 4 : ConnectorInfo* ConnectorInfo::start()
283 : {
284 4 : ConnectorInfo* i = findFirst();
285 4 : if (i && i->hasPrevious()) {
286 0 : return nullptr;
287 : }
288 4 : return i;
289 : }
290 :
291 : //---------------------------------------------------------
292 : // ConnectorInfo::end
293 : //---------------------------------------------------------
294 :
295 0 : ConnectorInfo* ConnectorInfo::end()
296 : {
297 0 : ConnectorInfo* i = findLast();
298 0 : if (i && i->hasNext()) {
299 0 : return nullptr;
300 : }
301 0 : return i;
302 : }
303 : }
|