Several refinements and improvements of ties

This commit is contained in:
Michele Spagnolo 2023-11-24 15:55:23 +01:00
parent 175540079f
commit 0b2916c767
8 changed files with 135 additions and 22 deletions

View File

@ -3596,6 +3596,34 @@ bool Note::isGraceBendStart() const
return bend && bend->type() == GuitarBendType::GRACE_NOTE_BEND;
}
bool Note::hasAnotherStraightAboveOrBelow(bool above) const
{
if (!chord()) {
return false;
}
const std::vector<Note*>& notes = chord()->notes();
if ((above && this == notes.back()) || (!above && this == notes.front())) {
return false;
}
const double limitDiff = 0.5 * spatium();
for (Note* note : notes) {
if (note == this) {
continue;
}
if (abs(note->pos().x() - pos().x()) > limitDiff) {
return false;
}
if ((above && note->line() < m_line) || (!above && note->line() > m_line)) {
return true;
}
}
return false;
}
mu::PointF Note::posInStaffCoordinates()
{
double X = x() + chord()->x() + chord()->segment()->x() + chord()->measure()->x() + headWidth() / 2;

View File

@ -431,6 +431,8 @@ public:
bool isPreBendStart() const;
bool isGraceBendStart() const;
bool hasAnotherStraightAboveOrBelow(bool above) const;
void addLineAttachPoint(mu::PointF point, EngravingItem* line);
std::vector<LineAttachPoint>& lineAttachPoints() { return m_lineAttachPoints; }
const std::vector<LineAttachPoint>& lineAttachPoints() const { return m_lineAttachPoints; }

View File

@ -182,13 +182,21 @@ void TieSegment::editDrag(EditData& ed)
void TieSegment::computeMidThickness(double tieLengthInSp)
{
m_midThickness = style().styleMM(Sid::SlurMidWidth) - style().styleMM(Sid::SlurEndWidth);
if (staff()) {
m_midThickness *= staff()->staffMag(tie()->tick());
}
static constexpr double shortTieLimit = 2;
if (tieLengthInSp < shortTieLimit) {
m_midThickness *= sqrt(tieLengthInSp / shortTieLimit);
const double mag = staff() ? staff()->staffMag(tie()->tick()) : 1.0;
const double minTieLength = mag * style().styleS(Sid::MinTieLength).val();
const double shortTieLimit = mag * 4.0;
const double minTieThickness = mag * (0.15 * spatium() - style().styleMM(Sid::SlurEndWidth));
const double normalThickness = mag * (style().styleMM(Sid::SlurMidWidth) - style().styleMM(Sid::SlurEndWidth));
bool invalid = RealIsEqualOrMore(minTieLength, shortTieLimit);
if (tieLengthInSp > shortTieLimit || invalid) {
m_midThickness = normalThickness;
} else {
const double A = 1 / (shortTieLimit - minTieLength);
const double B = normalThickness - minTieThickness;
const double C = shortTieLimit * minTieThickness - minTieLength * normalThickness;
m_midThickness = A * (B * tieLengthInSp + C);
}
}

View File

@ -266,8 +266,8 @@ SpannerSegment* SlurTieLayout::layoutSystem(Slur* item, System* system, LayoutCo
Chord* sc = item->startCR()->isChord() ? toChord(item->startCR()) : nullptr;
// on chord
if (sc && sc->notes().size() == 1) {
Tie* tie = sc->notes()[0]->tieFor();
if (sc) {
Tie* tie = (item->up() ? sc->upNote() : sc->downNote())->tieFor();
PointF endPoint = PointF();
if (tie && (tie->isInside() || tie->up() != item->up())) {
// there is a tie that starts on this chordrest
@ -367,8 +367,8 @@ SpannerSegment* SlurTieLayout::layoutSystem(Slur* item, System* system, LayoutCo
Chord* ec = item->endCR()->isChord() ? toChord(item->endCR()) : nullptr;
// on chord
if (ec && ec->notes().size() == 1) {
Tie* tie = ec->notes()[0]->tieBack();
if (ec) {
Tie* tie = (item->up() ? ec->upNote() : ec->downNote())->tieBack();
PointF endPoint;
if (tie && (tie->isInside() || tie->up() != item->up())) {
tie = nullptr;
@ -1147,7 +1147,7 @@ TieSegment* SlurTieLayout::tieLayoutFor(Tie* item, System* system)
}
}
adjustForLedgerLines(segment, sPos);
adjustYforLedgerLines(segment, sPos);
segment->ups(Grip::START).p = sPos.p1;
segment->ups(Grip::END).p = sPos.p2;
@ -1194,7 +1194,7 @@ TieSegment* SlurTieLayout::tieLayoutBack(Tie* item, System* system)
adjustX(segment, sPos, Grip::END);
}
adjustForLedgerLines(segment, sPos);
adjustYforLedgerLines(segment, sPos);
segment->ups(Grip::START).p = sPos.p1;
segment->ups(Grip::END).p = sPos.p2;
@ -1262,7 +1262,16 @@ PointF SlurTieLayout::computeDefaultStartOrEndPoint(const Tie* tie, Grip startOr
result += PointF(baseX, baseY);
const double visualInset = (inside ? 0.20 : 0.1) * spatium * leftRightSign; // TODO: style
double visualInsetSp = 0.0;
if (inside) {
visualInsetSp = 0.2;
} else if (note->hasAnotherStraightAboveOrBelow(up)) {
visualInsetSp = 0.45;
} else {
visualInsetSp = 0.1;
}
double visualInset = visualInsetSp * spatium * leftRightSign;
const double yOffset = 0.20 * spatium * upSign; // TODO: style
result += PointF(visualInset, yOffset);
@ -1370,8 +1379,9 @@ void SlurTieLayout::adjustX(TieSegment* tieSegment, SlurTiePos& sPos, Grip start
chordSystemPos += PointF(0.0, yDiff);
}
Shape chordShape = chord->shape().translate(chordSystemPos);
chordShape.remove_if([note](ShapeElement& s) {
return !s.item() || (s.item() == note || s.item()->isHook() || s.item()->isLedgerLine());
bool ignoreDot = start && isOuterTieOfChord;
chordShape.remove_if([&](ShapeElement& s) {
return !s.item() || (s.item() == note || s.item()->isHook() || s.item()->isLedgerLine() || (s.item()->isNoteDot() && ignoreDot));
});
const double arcSideMargin = 0.3 * spatium;
@ -1386,11 +1396,53 @@ void SlurTieLayout::adjustX(TieSegment* tieSegment, SlurTiePos& sPos, Grip start
resultingX = start ? std::max(resultingX, pointToClear) : std::min(resultingX, pointToClear);
adjustXforLedgerLines(tieSegment, start, chord, note, chordSystemPos, padding, resultingX);
tieSegment->addAdjustmentOffset(PointF(resultingX - tiePoint.x(), 0.0), startOrEnd);
tiePoint.setX(resultingX);
}
void SlurTieLayout::adjustForLedgerLines(TieSegment* tieSegment, SlurTiePos& sPos)
void SlurTieLayout::adjustXforLedgerLines(TieSegment* tieSegment, bool start, Chord* chord, Note* note,
const PointF& chordSystemPos, double padding, double& resultingX)
{
if (tieSegment->tie()->isInside() || !chord->ledgerLines()) {
return;
}
bool isOuterNote = note == chord->upNote() || note == chord->downNote();
if (isOuterNote) {
return;
}
bool ledgersAbove = false;
bool ledgersBelow = false;
for (LedgerLine* ledger = chord->ledgerLines(); ledger; ledger = ledger->next()) {
if (ledger->y() < 0.0) {
ledgersAbove = true;
} else {
ledgersBelow = true;
}
if (ledgersAbove && ledgersBelow) {
break;
}
}
int noteLine = note->line();
bool isOddLine = noteLine % 2 != 0;
bool isAboveStaff = noteLine <= 0;
bool isBelowStaff = noteLine >= 2 * (note->staff()->lines(note->tick()) - 1);
bool isInsideStaff = !isAboveStaff && !isBelowStaff;
if (isOddLine || isInsideStaff || (isAboveStaff && !ledgersAbove) || (isBelowStaff && !ledgersBelow)) {
return;
}
Shape noteShape = note->shape().translated(note->pos() + chordSystemPos);
double xNoteEdge = (start ? noteShape.right() : -noteShape.left()) + padding;
resultingX = start ? std::max(resultingX, xNoteEdge) : std::min(resultingX, xNoteEdge);
}
void SlurTieLayout::adjustYforLedgerLines(TieSegment* tieSegment, SlurTiePos& sPos)
{
Tie* tie = tieSegment->tie();
Note* note = tieSegment->isSingleBeginType() ? tie->startNote() : tie->endNote();
@ -1497,9 +1549,7 @@ void SlurTieLayout::adjustY(TieSegment* tieSegment)
bool isInside = tie2->isInside();
bool isOuterOfChord = tie2->isOuterTieOfChord(Grip::START) || tie2->isOuterTieOfChord(Grip::END);
bool hasTiedSecondInside = tie2->hasTiedSecondInside();
bool hasEndPointAboveNote = abs(tieSegment->adjustmentOffset(Grip::START).x()) < 0.5 * note->width()
|| abs(tieSegment->adjustmentOffset(Grip::END).x()) < 0.5 * note->width();
if (!isInside && !isOuterOfChord && !hasTiedSecondInside && !hasEndPointAboveNote) {
if (!isInside && !isOuterOfChord && !hasTiedSecondInside && !hasEndPointAboveNote(tieSegment)) {
double currentY = tieSegment->ups(Grip::START).p.y();
double yCorrection = -upSign * (badArcIntersectionLimit - outwardMargin);
tieSegment->addAdjustmentOffset(PointF(0.0, yCorrection), Grip::START);
@ -1532,6 +1582,27 @@ void SlurTieLayout::adjustY(TieSegment* tieSegment)
}
}
bool SlurTieLayout::hasEndPointAboveNote(TieSegment* tieSegment)
{
Note* startNote = tieSegment->tie()->startNote();
Note* endNote = tieSegment->tie()->endNote();
if ((tieSegment->isSingleBeginType() && !startNote) || (tieSegment->isSingleEndType() && !endNote)) {
return false;
}
Chord* startChord = startNote->chord();
PointF startNotePos = startNote->pos() + startChord->pos() + startChord->segment()->pos() + startChord->measure()->pos();
Chord* endChord = endNote->chord();
PointF endNotePos = endNote->pos() + endChord->pos() + endChord->segment()->pos() + endChord->measure()->pos();
PointF tieStartPos = tieSegment->ups(Grip::START).pos();
PointF tieEndPos = tieSegment->ups(Grip::END).pos();
return tieStartPos.x() < startNotePos.x() + startNote->width() || tieEndPos.x() > endNotePos.x();
}
void SlurTieLayout::resolveVerticalTieCollisions(const std::vector<TieSegment*>& stackedTies)
{
if (stackedTies.size() < 2) {
@ -1567,7 +1638,7 @@ void SlurTieLayout::resolveVerticalTieCollisions(const std::vector<TieSegment*>&
double yMidPoint = 0.5 * (thisTieOuterY + nextTieInnerY);
double halfLineDist = 0.5 * staff->lineDistance(tick) * spatium;
int midLine = round(yMidPoint / halfLineDist);
bool insideStaff = midLine > 0 && midLine < 2 * (staff->lines(tick) - 1) - 1;
bool insideStaff = midLine >= -1 && midLine <= 2 * (staff->lines(tick) - 1) + 1;
if (insideStaff) {
yMidPoint = midLine * halfLineDist;
}

View File

@ -63,8 +63,12 @@ private:
static void correctForCrossStaff(Tie* tie, SlurTiePos& sPos);
static void forceHorizontal(Tie* tie, SlurTiePos& sPos);
static void adjustX(TieSegment* tieSegment, SlurTiePos& sPos, Grip startOrEnd);
static void adjustForLedgerLines(TieSegment* tieSegment, SlurTiePos& sPos);
static void adjustXforLedgerLines(TieSegment* tieSegment, bool start, Chord* chord, Note* note, const PointF& chordSystemPos,
double padding, double& resultingX);
static void adjustYforLedgerLines(TieSegment* tieSegment, SlurTiePos& sPos);
static void adjustY(TieSegment* tieSegment);
static bool hasEndPointAboveNote(TieSegment* tieSegment);
static TieSegment* layoutTieWithNoEndNote(Tie* item);
static double defaultStemLengthStart(Tremolo* tremolo);

BIN
vtest/scores/tie-10.mscz Normal file

Binary file not shown.

BIN
vtest/scores/tie-11.mscz Normal file

Binary file not shown.

BIN
vtest/scores/tie-12.mscz Normal file

Binary file not shown.