LCOV - code coverage report
Current view: top level - src/engraving/dom - connector.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 82.9 % 111 92
Test Date: 2026-11-05 04:07:02

            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              : }
        

Generated by: LCOV version 2.0-1