From 02f5e2dd78f91093bf35f6a3560fee9bc4b56103 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Sun, 20 Oct 2024 17:47:30 +0200 Subject: [PATCH 1/7] Improve overlap calculation with elements of other layer --- src/layerelement.cpp | 53 +++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/src/layerelement.cpp b/src/layerelement.cpp index 9351443a93..45d5da7f07 100644 --- a/src/layerelement.cpp +++ b/src/layerelement.cpp @@ -1019,9 +1019,8 @@ int LayerElement::CalcLayerOverlap(const Doc *doc, int direction, int y1, int y2 Staff *staff = this->GetAncestorStaff(); const int unit = doc->GetDrawingUnit(staff->m_drawingStaffSize); - int leftMargin = 0; - int rightMargin = 0; - bool sameDirElement = false; + int leftOverlap = 0; + int rightOverlap = 0; std::vector elementOverlaps; for (Object *object : collidingElementsList) { LayerElement *layerElement = vrv_cast(object); @@ -1029,53 +1028,47 @@ int LayerElement::CalcLayerOverlap(const Doc *doc, int direction, int y1, int y2 const int elementBottom = layerElement->GetDrawingBottom(doc, staff->m_drawingStaffSize); const int elementTop = layerElement->GetDrawingTop(doc, staff->m_drawingStaffSize); if (direction > 0) { - // make sure that there's actual overlap first + // Ensure that there's actual overlap first if ((elementBottom > y1) && (elementBottom > y2)) continue; const int currentBottom = this->GetDrawingBottom(doc, staff->m_drawingStaffSize); if (currentBottom >= elementTop) continue; - const StemmedDrawingInterface *stemInterface = layerElement->GetStemmedDrawingInterface(); - if (stemInterface && (sameDirElement || (stemInterface->GetDrawingStemDir() == STEMDIRECTION_up))) { - if (elementBottom - stemInterface->GetDrawingStemLen() < currentBottom) continue; - leftMargin = unit + y1 - elementBottom; - rightMargin = unit + y2 - elementBottom; - sameDirElement = true; + // If there is a mild overlap, then decrease the beam stem length via negative overlap + if (elementBottom > std::max(y1, y2) - 3 * unit) { + leftOverlap = std::min(elementBottom - y1, 0); + rightOverlap = std::min(elementBottom - y2, 0); } else { - leftMargin = elementTop - y1; - rightMargin = elementTop - y2; + leftOverlap = std::max(elementTop - y1, 0); + rightOverlap = std::max(elementTop - y2, 0); } } else { - // make sure that there's actual overlap first + // Ensure that there's actual overlap first if ((elementTop < y1) && (elementTop < y2)) continue; const int currentTop = this->GetDrawingTop(doc, staff->m_drawingStaffSize); if (currentTop <= elementBottom) continue; - const StemmedDrawingInterface *stemInterface = layerElement->GetStemmedDrawingInterface(); - if (stemInterface && (sameDirElement || (stemInterface->GetDrawingStemDir() == STEMDIRECTION_down))) { - if (currentTop - stemInterface->GetDrawingStemLen() > currentTop) continue; - leftMargin = unit + y1 - elementTop; - rightMargin = unit + y2 - elementTop; - sameDirElement = true; + // If there is a mild overlap, then decrease the beam stem length via negative overlap + if (elementTop < std::min(y1, y2) + 3 * unit) { + leftOverlap = std::min(y1 - elementTop, 0); + rightOverlap = std::min(y2 - elementTop, 0); } else { - leftMargin = elementBottom - y1; - rightMargin = elementBottom - y2; + leftOverlap = std::max(y1 - elementBottom, 0); + rightOverlap = std::max(y2 - elementBottom, 0); } } - elementOverlaps.emplace_back(std::max(leftMargin * direction, rightMargin * direction)); + elementOverlaps.emplace_back(leftOverlap); + elementOverlaps.emplace_back(rightOverlap); } if (elementOverlaps.empty()) return 0; - const auto maxOverlap = std::max_element(elementOverlaps.begin(), elementOverlaps.end()); + const auto [minOverlap, maxOverlap] = std::minmax_element(elementOverlaps.begin(), elementOverlaps.end()); int overlap = 0; - if (*maxOverlap >= 0) { - const int multiplier = sameDirElement ? -1 : 1; - overlap = ((*maxOverlap == 0) ? unit : *maxOverlap) * direction * multiplier; + if (*maxOverlap > 0) { + overlap = *maxOverlap * direction; } - else { - int maxShorteningInHalfUnits = (std::abs(*maxOverlap) / unit) * 2; - if (maxShorteningInHalfUnits > 0) --maxShorteningInHalfUnits; - this->SetElementShortening(maxShorteningInHalfUnits); + else if (*minOverlap < 0) { + overlap = (*minOverlap - unit) * direction; } return overlap; } From 9cb4e960999e39c58942b549ce6fbfd615e125ab Mon Sep 17 00:00:00 2001 From: David Bauer Date: Sun, 20 Oct 2024 18:08:51 +0200 Subject: [PATCH 2/7] Remove beam max shortening as it was not properly used --- include/vrv/beam.h | 7 ------- include/vrv/ftrem.h | 5 ----- include/vrv/layerelement.h | 5 ----- src/beam.cpp | 12 +----------- src/ftrem.cpp | 6 ------ 5 files changed, 1 insertion(+), 34 deletions(-) diff --git a/include/vrv/beam.h b/include/vrv/beam.h index 2ab3afd24c..464499f98d 100644 --- a/include/vrv/beam.h +++ b/include/vrv/beam.h @@ -375,11 +375,6 @@ class Beam : public LayerElement, */ void FilterList(ListOfConstObjects &childList) const override; - /** - * See LayerElement::SetElementShortening - */ - void SetElementShortening(int shortening) override; - private: /** * A pointer to the beam with which stems are shared. @@ -410,7 +405,6 @@ class BeamElementCoord { m_tabDurSym = NULL; m_stem = NULL; m_overlapMargin = 0; - m_maxShortening = -1; m_beamRelativePlace = BEAMPLACE_NONE; m_partialFlagPlace = BEAMPLACE_NONE; } @@ -458,7 +452,6 @@ class BeamElementCoord { data_DURATION m_dur; // drawing duration int m_breaksec; int m_overlapMargin; - int m_maxShortening; // maximum allowed shortening in half units bool m_centered; // beam is centered on the line data_BEAMPLACE m_beamRelativePlace; char m_partialFlags[MAX_DURATION_PARTIALS]; diff --git a/include/vrv/ftrem.h b/include/vrv/ftrem.h index 79e1e80577..4e38e755e5 100644 --- a/include/vrv/ftrem.h +++ b/include/vrv/ftrem.h @@ -90,11 +90,6 @@ class FTrem : public LayerElement, public BeamDrawingInterface, public AttFTremV */ void FilterList(ListOfConstObjects &childList) const override; - /** - * See LayerElement::SetElementShortening - */ - void SetElementShortening(int shortening) override; - public: /** */ BeamSegment m_beamSegment; diff --git a/include/vrv/layerelement.h b/include/vrv/layerelement.h index b4557c22f6..d03c0eb0b1 100644 --- a/include/vrv/layerelement.h +++ b/include/vrv/layerelement.h @@ -304,11 +304,6 @@ class LayerElement : public Object, std::pair CalcElementHorizontalOverlap(const Doc *doc, const std::vector &otherElements, bool areDotsAdjusted, bool isChordElement, bool isLowerElement = false, bool unison = true); - /** - * Helper function to set shortening for elements with beam interface - */ - virtual void SetElementShortening(int shortening) {} - /** * Get the stem mod for the element (if any) */ diff --git a/src/beam.cpp b/src/beam.cpp index 5cffc7fb90..f779239884 100644 --- a/src/beam.cpp +++ b/src/beam.cpp @@ -1951,13 +1951,9 @@ int BeamElementCoord::CalculateStemLength( const int standardStemLen = STANDARD_STEMLENGTH * 2; // Check if the stem has to be shortened because outside the staff // In this case, Note::CalcStemLenInThirdUnits will return a value shorter than 2 * STANDARD_STEMLENGTH - int stemLenInHalfUnits - = !m_maxShortening ? standardStemLen : m_closestNote->CalcStemLenInThirdUnits(staff, stemDir) * 2 / 3; + const int stemLenInHalfUnits = m_closestNote->CalcStemLenInThirdUnits(staff, stemDir) * 2 / 3; // Do not extend when not on the staff line if (stemLenInHalfUnits != standardStemLen) { - if ((m_maxShortening > 0) && ((stemLenInHalfUnits - standardStemLen) > m_maxShortening)) { - stemLenInHalfUnits = standardStemLen - m_maxShortening; - } extend = false; } @@ -2098,12 +2094,6 @@ std::pair Beam::GetAdditionalBeamCount() const return { topShortestDur - DURATION_8, bottomShortestDur - DURATION_8 }; } -void Beam::SetElementShortening(int shortening) -{ - std::for_each(m_beamSegment.m_beamElementCoordRefs.begin(), m_beamSegment.m_beamElementCoordRefs.end(), - [shortening](BeamElementCoord *coord) { coord->m_maxShortening = shortening; }); -} - int Beam::GetBeamPartDuration(int x, bool includeRests) const { // find element with position closest to the specified coordinate diff --git a/src/ftrem.cpp b/src/ftrem.cpp index f89d56e183..869d9b489f 100644 --- a/src/ftrem.cpp +++ b/src/ftrem.cpp @@ -112,12 +112,6 @@ std::pair FTrem::GetFloatingBeamCount() const return { this->GetBeams(), this->GetBeamsFloat() }; } -void FTrem::SetElementShortening(int shortening) -{ - std::for_each(m_beamSegment.m_beamElementCoordRefs.begin(), m_beamSegment.m_beamElementCoordRefs.end(), - [shortening](BeamElementCoord *coord) { coord->m_maxShortening = shortening; }); -} - //---------------------------------------------------------------------------- // Functors methods //---------------------------------------------------------------------------- From 7d2b646280b4bf3b97ce639f9d8649372d9fb962 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Mon, 21 Oct 2024 18:07:11 +0200 Subject: [PATCH 3/7] Move CalcLayerOverlap into AdjustBeamsFunctor --- include/vrv/adjustbeamsfunctor.h | 6 +++ include/vrv/layerelement.h | 6 --- src/adjustbeamsfunctor.cpp | 83 +++++++++++++++++++++++++++++++- src/layerelement.cpp | 77 ----------------------------- 4 files changed, 87 insertions(+), 85 deletions(-) diff --git a/include/vrv/adjustbeamsfunctor.h b/include/vrv/adjustbeamsfunctor.h index bf8462a161..27535ab12d 100644 --- a/include/vrv/adjustbeamsfunctor.h +++ b/include/vrv/adjustbeamsfunctor.h @@ -53,6 +53,12 @@ class AdjustBeamsFunctor : public DocFunctor { // Get the drawing interface of the outer beam or the outer ftrem BeamDrawingInterface *GetOuterBeamInterface() const; + /** + * Calculate the overlap with other layer elements that + * are placed within the duration of the element + */ + int CalcLayerOverlap(LayerElement *beamElement); + public: // private: diff --git a/include/vrv/layerelement.h b/include/vrv/layerelement.h index d03c0eb0b1..6a9e1cc55d 100644 --- a/include/vrv/layerelement.h +++ b/include/vrv/layerelement.h @@ -325,12 +325,6 @@ class LayerElement : public Object, */ MapOfDotLocs CalcOptimalDotLocations(); - /** - * Calculate the overlap with other layer elements that - * are placed within the duration of the element - */ - int CalcLayerOverlap(const Doc *doc, int direction, int y1, int y2); - //----------// // Functors // //----------// diff --git a/src/adjustbeamsfunctor.cpp b/src/adjustbeamsfunctor.cpp index 86c2f41b52..3a2c26ea55 100644 --- a/src/adjustbeamsfunctor.cpp +++ b/src/adjustbeamsfunctor.cpp @@ -63,7 +63,7 @@ FunctorCode AdjustBeamsFunctor::VisitBeam(Beam *beam) m_x2 = beamSegment.m_beamElementCoordRefs.back()->m_x; m_beamSlope = beamSegment.m_beamSlope; m_directionBias = (beam->m_drawingPlace == BEAMPLACE_above) ? 1 : -1; - m_overlapMargin = beam->CalcLayerOverlap(m_doc, m_directionBias, m_y1, m_y2); + m_overlapMargin = this->CalcLayerOverlap(beam); } return FUNCTOR_CONTINUE; } @@ -181,7 +181,7 @@ FunctorCode AdjustBeamsFunctor::VisitFTrem(FTrem *fTrem) m_x2 = beamSegment.m_beamElementCoordRefs.back()->m_x; m_beamSlope = beamSegment.m_beamSlope; m_directionBias = (fTrem->m_drawingPlace == BEAMPLACE_above) ? 1 : -1; - m_overlapMargin = fTrem->CalcLayerOverlap(m_doc, m_directionBias, m_y1, m_y2); + m_overlapMargin = this->CalcLayerOverlap(fTrem); } return FUNCTOR_CONTINUE; } @@ -350,4 +350,83 @@ BeamDrawingInterface *AdjustBeamsFunctor::GetOuterBeamInterface() const return NULL; } +int AdjustBeamsFunctor::CalcLayerOverlap(LayerElement *beamElement) +{ + assert(beamElement); + + Layer *parentLayer = vrv_cast(beamElement->GetFirstAncestor(LAYER)); + if (!parentLayer) return 0; + // Check whether there are elements on the other layer in the duration of the current beam + ListOfObjects collidingElementsList = parentLayer->GetLayerElementsForTimeSpanOf(beamElement, true); + // Ignore any elements part of a stem-sameas beam + if (beamElement->Is(BEAM)) { + const Beam *beam = vrv_cast(beamElement); + const Beam *stemSameAsBeam = beam->GetStemSameasBeam(); + if (stemSameAsBeam) { + collidingElementsList.remove_if([stemSameAsBeam](Object *object) { + const LayerElement *layerElement = vrv_cast(object); + return (layerElement->GetAncestorBeam() == stemSameAsBeam); + }); + } + } + // If there are none - stop here, there's nothing to be done + if (collidingElementsList.empty()) return 0; + + Staff *staff = beamElement->GetAncestorStaff(); + + const int unit = m_doc->GetDrawingUnit(staff->m_drawingStaffSize); + int leftOverlap = 0; + int rightOverlap = 0; + std::vector elementOverlaps; + for (Object *object : collidingElementsList) { + LayerElement *layerElement = vrv_cast(object); + if (!beamElement->HorizontalContentOverlap(object)) continue; + const int elementBottom = layerElement->GetDrawingBottom(m_doc, staff->m_drawingStaffSize); + const int elementTop = layerElement->GetDrawingTop(m_doc, staff->m_drawingStaffSize); + if (m_directionBias > 0) { + // Ensure that there's actual overlap first + if ((elementBottom > m_y1) && (elementBottom > m_y2)) continue; + const int currentBottom = beamElement->GetDrawingBottom(m_doc, staff->m_drawingStaffSize); + if (currentBottom >= elementTop) continue; + // If there is a mild overlap, then decrease the beam stem length via negative overlap + if (elementBottom > std::max(m_y1, m_y2) - 3 * unit) { + leftOverlap = std::min(elementBottom - m_y1, 0); + rightOverlap = std::min(elementBottom - m_y2, 0); + } + else { + leftOverlap = std::max(elementTop - m_y1, 0); + rightOverlap = std::max(elementTop - m_y2, 0); + } + } + else { + // Ensure that there's actual overlap first + if ((elementTop < m_y1) && (elementTop < m_y2)) continue; + const int currentTop = beamElement->GetDrawingTop(m_doc, staff->m_drawingStaffSize); + if (currentTop <= elementBottom) continue; + // If there is a mild overlap, then decrease the beam stem length via negative overlap + if (elementTop < std::min(m_y1, m_y2) + 3 * unit) { + leftOverlap = std::min(m_y1 - elementTop, 0); + rightOverlap = std::min(m_y2 - elementTop, 0); + } + else { + leftOverlap = std::max(m_y1 - elementBottom, 0); + rightOverlap = std::max(m_y2 - elementBottom, 0); + } + } + elementOverlaps.emplace_back(leftOverlap); + elementOverlaps.emplace_back(rightOverlap); + } + if (elementOverlaps.empty()) return 0; + + const auto [minOverlap, maxOverlap] = std::minmax_element(elementOverlaps.begin(), elementOverlaps.end()); + int overlap = 0; + if (*maxOverlap > 0) { + overlap = *maxOverlap * m_directionBias; + } + else if (*minOverlap < 0) { + overlap = (*minOverlap - unit) * m_directionBias; + } + return overlap; +} + } // namespace vrv diff --git a/src/layerelement.cpp b/src/layerelement.cpp index 45d5da7f07..8585bd8be3 100644 --- a/src/layerelement.cpp +++ b/src/layerelement.cpp @@ -996,83 +996,6 @@ MapOfDotLocs LayerElement::CalcOptimalDotLocations() return usePrimary ? dotLocs1 : dotLocs2; } -int LayerElement::CalcLayerOverlap(const Doc *doc, int direction, int y1, int y2) -{ - Layer *parentLayer = vrv_cast(this->GetFirstAncestor(LAYER)); - if (!parentLayer) return 0; - // Check whether there are elements on the other layer in the duration of the current beam - ListOfObjects collidingElementsList = parentLayer->GetLayerElementsForTimeSpanOf(this, true); - // Ignore any elements part of a stem-sameas beam - if (this->Is(BEAM)) { - const Beam *beam = vrv_cast(this); - const Beam *stemSameAsBeam = beam->GetStemSameasBeam(); - if (stemSameAsBeam) { - collidingElementsList.remove_if([stemSameAsBeam](Object *object) { - const LayerElement *layerElement = vrv_cast(object); - return (layerElement->GetAncestorBeam() == stemSameAsBeam); - }); - } - } - // If there are none - stop here, there's nothing to be done - if (collidingElementsList.empty()) return 0; - - Staff *staff = this->GetAncestorStaff(); - - const int unit = doc->GetDrawingUnit(staff->m_drawingStaffSize); - int leftOverlap = 0; - int rightOverlap = 0; - std::vector elementOverlaps; - for (Object *object : collidingElementsList) { - LayerElement *layerElement = vrv_cast(object); - if (!this->HorizontalContentOverlap(object)) continue; - const int elementBottom = layerElement->GetDrawingBottom(doc, staff->m_drawingStaffSize); - const int elementTop = layerElement->GetDrawingTop(doc, staff->m_drawingStaffSize); - if (direction > 0) { - // Ensure that there's actual overlap first - if ((elementBottom > y1) && (elementBottom > y2)) continue; - const int currentBottom = this->GetDrawingBottom(doc, staff->m_drawingStaffSize); - if (currentBottom >= elementTop) continue; - // If there is a mild overlap, then decrease the beam stem length via negative overlap - if (elementBottom > std::max(y1, y2) - 3 * unit) { - leftOverlap = std::min(elementBottom - y1, 0); - rightOverlap = std::min(elementBottom - y2, 0); - } - else { - leftOverlap = std::max(elementTop - y1, 0); - rightOverlap = std::max(elementTop - y2, 0); - } - } - else { - // Ensure that there's actual overlap first - if ((elementTop < y1) && (elementTop < y2)) continue; - const int currentTop = this->GetDrawingTop(doc, staff->m_drawingStaffSize); - if (currentTop <= elementBottom) continue; - // If there is a mild overlap, then decrease the beam stem length via negative overlap - if (elementTop < std::min(y1, y2) + 3 * unit) { - leftOverlap = std::min(y1 - elementTop, 0); - rightOverlap = std::min(y2 - elementTop, 0); - } - else { - leftOverlap = std::max(y1 - elementBottom, 0); - rightOverlap = std::max(y2 - elementBottom, 0); - } - } - elementOverlaps.emplace_back(leftOverlap); - elementOverlaps.emplace_back(rightOverlap); - } - if (elementOverlaps.empty()) return 0; - - const auto [minOverlap, maxOverlap] = std::minmax_element(elementOverlaps.begin(), elementOverlaps.end()); - int overlap = 0; - if (*maxOverlap > 0) { - overlap = *maxOverlap * direction; - } - else if (*minOverlap < 0) { - overlap = (*minOverlap - unit) * direction; - } - return overlap; -} - data_STEMMODIFIER LayerElement::GetDrawingStemMod() const { const AttStems *stem = dynamic_cast(this); From 0973df69103d2e4e8ca2df31a90f2e83529f0c27 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Mon, 21 Oct 2024 18:15:41 +0200 Subject: [PATCH 4/7] Make CalcLayerOverlap method const --- include/vrv/adjustbeamsfunctor.h | 2 +- src/adjustbeamsfunctor.cpp | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/vrv/adjustbeamsfunctor.h b/include/vrv/adjustbeamsfunctor.h index 27535ab12d..00d6287ce9 100644 --- a/include/vrv/adjustbeamsfunctor.h +++ b/include/vrv/adjustbeamsfunctor.h @@ -57,7 +57,7 @@ class AdjustBeamsFunctor : public DocFunctor { * Calculate the overlap with other layer elements that * are placed within the duration of the element */ - int CalcLayerOverlap(LayerElement *beamElement); + int CalcLayerOverlap(const LayerElement *beamElement) const; public: // diff --git a/src/adjustbeamsfunctor.cpp b/src/adjustbeamsfunctor.cpp index 3a2c26ea55..92ed039aff 100644 --- a/src/adjustbeamsfunctor.cpp +++ b/src/adjustbeamsfunctor.cpp @@ -350,21 +350,21 @@ BeamDrawingInterface *AdjustBeamsFunctor::GetOuterBeamInterface() const return NULL; } -int AdjustBeamsFunctor::CalcLayerOverlap(LayerElement *beamElement) +int AdjustBeamsFunctor::CalcLayerOverlap(const LayerElement *beamElement) const { assert(beamElement); - Layer *parentLayer = vrv_cast(beamElement->GetFirstAncestor(LAYER)); + const Layer *parentLayer = vrv_cast(beamElement->GetFirstAncestor(LAYER)); if (!parentLayer) return 0; // Check whether there are elements on the other layer in the duration of the current beam - ListOfObjects collidingElementsList = parentLayer->GetLayerElementsForTimeSpanOf(beamElement, true); + ListOfConstObjects collidingElementsList = parentLayer->GetLayerElementsForTimeSpanOf(beamElement, true); // Ignore any elements part of a stem-sameas beam if (beamElement->Is(BEAM)) { - const Beam *beam = vrv_cast(beamElement); + const Beam *beam = vrv_cast(beamElement); const Beam *stemSameAsBeam = beam->GetStemSameasBeam(); if (stemSameAsBeam) { - collidingElementsList.remove_if([stemSameAsBeam](Object *object) { - const LayerElement *layerElement = vrv_cast(object); + collidingElementsList.remove_if([stemSameAsBeam](const Object *object) { + const LayerElement *layerElement = vrv_cast(object); return (layerElement->GetAncestorBeam() == stemSameAsBeam); }); } @@ -372,14 +372,14 @@ int AdjustBeamsFunctor::CalcLayerOverlap(LayerElement *beamElement) // If there are none - stop here, there's nothing to be done if (collidingElementsList.empty()) return 0; - Staff *staff = beamElement->GetAncestorStaff(); + const Staff *staff = beamElement->GetAncestorStaff(); const int unit = m_doc->GetDrawingUnit(staff->m_drawingStaffSize); int leftOverlap = 0; int rightOverlap = 0; std::vector elementOverlaps; - for (Object *object : collidingElementsList) { - LayerElement *layerElement = vrv_cast(object); + for (const Object *object : collidingElementsList) { + const LayerElement *layerElement = vrv_cast(object); if (!beamElement->HorizontalContentOverlap(object)) continue; const int elementBottom = layerElement->GetDrawingBottom(m_doc, staff->m_drawingStaffSize); const int elementTop = layerElement->GetDrawingTop(m_doc, staff->m_drawingStaffSize); From 0b93ad0809242eb46978936203710fa8f00913aa Mon Sep 17 00:00:00 2001 From: David Bauer Date: Mon, 21 Oct 2024 18:52:50 +0200 Subject: [PATCH 5/7] Round overlap to half unit multiple --- include/vrv/adjustbeamsfunctor.h | 3 +++ src/adjustbeamsfunctor.cpp | 27 +++++++++++++++++---------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/include/vrv/adjustbeamsfunctor.h b/include/vrv/adjustbeamsfunctor.h index 00d6287ce9..83cc3efb93 100644 --- a/include/vrv/adjustbeamsfunctor.h +++ b/include/vrv/adjustbeamsfunctor.h @@ -59,6 +59,9 @@ class AdjustBeamsFunctor : public DocFunctor { */ int CalcLayerOverlap(const LayerElement *beamElement) const; + // Rounds the overlap to the closest multiple of a half unit + int AdjustOverlapToHalfUnit(int overlap, int unit) const; + public: // private: diff --git a/src/adjustbeamsfunctor.cpp b/src/adjustbeamsfunctor.cpp index 92ed039aff..9d763d3432 100644 --- a/src/adjustbeamsfunctor.cpp +++ b/src/adjustbeamsfunctor.cpp @@ -148,15 +148,13 @@ FunctorCode AdjustBeamsFunctor::VisitClef(Clef *clef) // calculate margins for the clef const int leftMargin = m_directionBias * (currentBeamYLeft - clefBounds) - beams * beamWidth; const int rightMargin = m_directionBias * (currentBeamYRight - clefBounds) - beams * beamWidth; - const int overlapMargin = std::min(leftMargin, rightMargin); + int overlapMargin = std::min(leftMargin, rightMargin); if (overlapMargin >= 0) return FUNCTOR_CONTINUE; // calculate offset required for the beam + overlapMargin *= -m_directionBias; const int unit = m_doc->GetDrawingUnit(staff->m_drawingStaffSize); - const int unitChangeNumber = ((std::abs(overlapMargin) + unit / 6) / unit); - if (unitChangeNumber > 0) { - const int adjust = unitChangeNumber * unit * m_directionBias; - if (std::abs(adjust) > std::abs(m_overlapMargin)) m_overlapMargin = adjust; - } + const int adjust = this->AdjustOverlapToHalfUnit(overlapMargin, unit); + if (std::abs(adjust) > std::abs(m_overlapMargin)) m_overlapMargin = adjust; return FUNCTOR_CONTINUE; } @@ -301,7 +299,7 @@ FunctorCode AdjustBeamsFunctor::VisitRest(Rest *rest) // Calculate possible overlap for the rest with beams const int beams = m_outerBeam->GetBeamPartDuration(rest, false) - DURATION_4; const int beamWidth = m_outerBeam->m_beamWidth; - const int overlapMargin = rest->Intersects(m_outerBeam, SELF, beams * beamWidth, true) * m_directionBias; + int overlapMargin = rest->Intersects(m_outerBeam, SELF, beams * beamWidth, true) * m_directionBias; // Adjust drawing location for the rest based on the overlap with beams. // Adjustment should be an even number, so that the rest is positioned properly @@ -335,9 +333,9 @@ FunctorCode AdjustBeamsFunctor::VisitRest(Rest *rest) } } + overlapMargin *= -m_directionBias; const int unit = m_doc->GetDrawingUnit(staff->m_drawingStaffSize); - const int unitChangeNumber = std::abs(overlapMargin) / unit + 1; - const int adjust = unitChangeNumber * unit * m_directionBias; + const int adjust = this->AdjustOverlapToHalfUnit(overlapMargin, unit); if (std::abs(adjust) > std::abs(m_overlapMargin)) m_overlapMargin = adjust; return FUNCTOR_CONTINUE; @@ -426,7 +424,16 @@ int AdjustBeamsFunctor::CalcLayerOverlap(const LayerElement *beamElement) const else if (*minOverlap < 0) { overlap = (*minOverlap - unit) * m_directionBias; } - return overlap; + const int adjust = this->AdjustOverlapToHalfUnit(overlap, unit); + return adjust; +} + +int AdjustBeamsFunctor::AdjustOverlapToHalfUnit(int overlap, int unit) const +{ + const int overlapSign = (overlap >= 0) ? 1 : -1; + const int halfUnit = unit / 2; + const int halfUnitChangeNumber = (std::abs(overlap) + halfUnit / 2) / halfUnit; + return halfUnitChangeNumber * halfUnit * overlapSign; } } // namespace vrv From 4dcfc48b39372f40e7480591753b7e9ed19e30ce Mon Sep 17 00:00:00 2001 From: David Bauer Date: Mon, 21 Oct 2024 19:10:35 +0200 Subject: [PATCH 6/7] Use bounding boxes for layer element boundary --- src/adjustbeamsfunctor.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/adjustbeamsfunctor.cpp b/src/adjustbeamsfunctor.cpp index 9d763d3432..3418c5ffbc 100644 --- a/src/adjustbeamsfunctor.cpp +++ b/src/adjustbeamsfunctor.cpp @@ -371,6 +371,7 @@ int AdjustBeamsFunctor::CalcLayerOverlap(const LayerElement *beamElement) const if (collidingElementsList.empty()) return 0; const Staff *staff = beamElement->GetAncestorStaff(); + const int drawingY = beamElement->GetDrawingY(); const int unit = m_doc->GetDrawingUnit(staff->m_drawingStaffSize); int leftOverlap = 0; @@ -379,13 +380,12 @@ int AdjustBeamsFunctor::CalcLayerOverlap(const LayerElement *beamElement) const for (const Object *object : collidingElementsList) { const LayerElement *layerElement = vrv_cast(object); if (!beamElement->HorizontalContentOverlap(object)) continue; - const int elementBottom = layerElement->GetDrawingBottom(m_doc, staff->m_drawingStaffSize); - const int elementTop = layerElement->GetDrawingTop(m_doc, staff->m_drawingStaffSize); + const int elementBottom = layerElement->GetContentBottom(); + const int elementTop = layerElement->GetContentTop(); if (m_directionBias > 0) { // Ensure that there's actual overlap first if ((elementBottom > m_y1) && (elementBottom > m_y2)) continue; - const int currentBottom = beamElement->GetDrawingBottom(m_doc, staff->m_drawingStaffSize); - if (currentBottom >= elementTop) continue; + if (drawingY >= elementTop) continue; // If there is a mild overlap, then decrease the beam stem length via negative overlap if (elementBottom > std::max(m_y1, m_y2) - 3 * unit) { leftOverlap = std::min(elementBottom - m_y1, 0); @@ -399,8 +399,7 @@ int AdjustBeamsFunctor::CalcLayerOverlap(const LayerElement *beamElement) const else { // Ensure that there's actual overlap first if ((elementTop < m_y1) && (elementTop < m_y2)) continue; - const int currentTop = beamElement->GetDrawingTop(m_doc, staff->m_drawingStaffSize); - if (currentTop <= elementBottom) continue; + if (drawingY <= elementBottom) continue; // If there is a mild overlap, then decrease the beam stem length via negative overlap if (elementTop < std::min(m_y1, m_y2) + 3 * unit) { leftOverlap = std::min(m_y1 - elementTop, 0); From ee55ea0642e21bf5ba1910adbf92e864d0e78ef1 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Mon, 21 Oct 2024 19:25:12 +0200 Subject: [PATCH 7/7] Use yMin and yMax to shorten the overlap calculation --- src/adjustbeamsfunctor.cpp | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/adjustbeamsfunctor.cpp b/src/adjustbeamsfunctor.cpp index 3418c5ffbc..ebb4629c4b 100644 --- a/src/adjustbeamsfunctor.cpp +++ b/src/adjustbeamsfunctor.cpp @@ -372,10 +372,11 @@ int AdjustBeamsFunctor::CalcLayerOverlap(const LayerElement *beamElement) const const Staff *staff = beamElement->GetAncestorStaff(); const int drawingY = beamElement->GetDrawingY(); - + const int yMin = std::min(m_y1, m_y2); + const int yMax = std::max(m_y1, m_y2); const int unit = m_doc->GetDrawingUnit(staff->m_drawingStaffSize); - int leftOverlap = 0; - int rightOverlap = 0; + + int elementOverlap = 0; std::vector elementOverlaps; for (const Object *object : collidingElementsList) { const LayerElement *layerElement = vrv_cast(object); @@ -384,34 +385,29 @@ int AdjustBeamsFunctor::CalcLayerOverlap(const LayerElement *beamElement) const const int elementTop = layerElement->GetContentTop(); if (m_directionBias > 0) { // Ensure that there's actual overlap first - if ((elementBottom > m_y1) && (elementBottom > m_y2)) continue; + if (elementBottom > yMax) continue; if (drawingY >= elementTop) continue; // If there is a mild overlap, then decrease the beam stem length via negative overlap - if (elementBottom > std::max(m_y1, m_y2) - 3 * unit) { - leftOverlap = std::min(elementBottom - m_y1, 0); - rightOverlap = std::min(elementBottom - m_y2, 0); + if (elementBottom > yMax - 3 * unit) { + elementOverlap = std::min(elementBottom - yMax, 0); } else { - leftOverlap = std::max(elementTop - m_y1, 0); - rightOverlap = std::max(elementTop - m_y2, 0); + elementOverlap = std::max(elementTop - yMin, 0); } } else { // Ensure that there's actual overlap first - if ((elementTop < m_y1) && (elementTop < m_y2)) continue; + if (elementTop < yMin) continue; if (drawingY <= elementBottom) continue; // If there is a mild overlap, then decrease the beam stem length via negative overlap - if (elementTop < std::min(m_y1, m_y2) + 3 * unit) { - leftOverlap = std::min(m_y1 - elementTop, 0); - rightOverlap = std::min(m_y2 - elementTop, 0); + if (elementTop < yMin + 3 * unit) { + elementOverlap = std::min(yMin - elementTop, 0); } else { - leftOverlap = std::max(m_y1 - elementBottom, 0); - rightOverlap = std::max(m_y2 - elementBottom, 0); + elementOverlap = std::max(yMax - elementBottom, 0); } } - elementOverlaps.emplace_back(leftOverlap); - elementOverlaps.emplace_back(rightOverlap); + elementOverlaps.emplace_back(elementOverlap); } if (elementOverlaps.empty()) return 0;