Improved by scanning all chord notes and factoring some common computations.

This commit is contained in:
Maurizio M. Gavioli 2013-08-03 01:45:46 +02:00
parent d5997be5fc
commit 704483c50a
2 changed files with 59 additions and 80 deletions

View file

@ -523,42 +523,21 @@ qreal Chord::maxHeadWidth()
//---------------------------------------------------------
// addLedgerLine
/// Add a ledger line to a chord.
/// \arg x note head position
/// \arg staffIdx determines the y origin
/// \arg track track the ledger line belongs to
/// \arg line vertical position of line
/// \arg lr extend to left and/or right
/// \arg hw max head width in chord
/// \arg visible whether the line is visible or not
/// \arg x start x-position
/// \arg len line length
//---------------------------------------------------------
void Chord::addLedgerLine(qreal x, int staffIdx, int line, int lr, bool visible, qreal hw)
void Chord::addLedgerLine(int track, int line, bool visible, qreal x, Spatium len)
{
qreal _spatium = spatium();
qreal hw2 = hw * .5;
LedgerLine* h = new LedgerLine(score());
h->setParent(this);
h->setTrack(staff2track(staffIdx));
if (staff()->invisible())
visible = false;
h->setTrack(track);
h->setVisible(visible);
// ledger lines extend less than half a space on each side
// of the notehead:
//
qreal ll = hw + score()->styleS(ST_ledgerLineLength).val() * _spatium;
if (_noteType != NOTE_NORMAL)
ll *= score()->styleD(ST_graceNoteMag);
x -= ll * .5;
x += (lr & 1) ? -hw2 : hw2;
if (lr == 3)
ll += hw;
Spatium len(ll / _spatium);
//
// Experimental:
// shorten ledger line to avoid collisions with accidentals
@ -573,6 +552,7 @@ void Chord::addLedgerLine(qreal x, int staffIdx, int line, int lr, bool visible,
break;
}
}
h->setLen(len);
h->setPos(x, line * _spatium * .5);
h->setNext(_ledgerLines);
@ -583,53 +563,56 @@ void Chord::addLedgerLine(qreal x, int staffIdx, int line, int lr, bool visible,
// addLedgerLines
//---------------------------------------------------------
void Chord::addLedgerLines(qreal x, int move)
void Chord::addLedgerLines(int move)
{
int uppos = 1000;
int ulr = 0;
int idx = staffIdx() + move;
int idx = staffIdx() + move;
qreal hw = _notes[0]->headWidth();
qreal minX = 0, maxX=0; // no ledger line width yet
int minLine = 0, maxLine = 0; // no line yet
bool visible = false;
qreal x;
// the line pos corresponding to the first ledger line below the staff
int minLineBelow = score()->staff(idx)->lines() * 2;
// make ledger lines invisible if all notes
// are invisible
bool visible = false;
// scan chord notes, collecting visibility and x and y extrema
int n = _notes.size();
for (int i = 0; i < n; ++i) {
if (_notes.at(i)->visible()) {
visible = true;
break;
}
}
qreal hw = maxHeadWidth();
for (int ni = n - 1; ni >= 0; --ni) {
const Note* note = _notes[ni];
int l = note->line();
if (l >= 0)
break;
for (int i = (uppos+1) & ~1; i < l; i += 2)
addLedgerLine(x, idx, i, ulr, visible, hw);
ulr |= (up() ^ note->mirror()) ? 0x1 : 0x2;
uppos = l;
}
for (int i = (uppos+1) & ~1; i <= -2; i += 2)
addLedgerLine(x, idx, i, ulr, visible, hw);
int downpos = -1000;
int dlr = 0;
for (int i = 0; i < n; ++i) {
const Note* note = _notes.at(i);
int l = note->line();
if (l <= 8)
break;
for (int i = downpos & ~1; i > l; i -= 2)
addLedgerLine(x, idx, i, dlr, visible, hw);
dlr |= (up() ^ note->mirror()) ? 0x1 : 0x2;
downpos = l;
if (_notes.at(i)->visible()) // if one note is visible,
visible = true; // all lines are visible (WHICH IS NOT ALWAYS TRUE!)
int l = note->line(); // check note line outside current range
if (l < minLine) minLine = l;
if (l > maxLine) maxLine = l;
x = note->pos().x(); // check note pos and width outside current range
if (x < minX) minX = x;
if (x+hw > maxX) maxX = x+hw;
}
for (int i = downpos & ~1; i >= 10; i -= 2)
addLedgerLine(x, idx, i, dlr, visible, hw);
if (minLine > -2 && maxLine < minLineBelow)
return; // no ledger lines for this chord
// some values and calculations common to all ledger lines
if (staff()->invisible()) // but if staff is invisible,
visible = false; // lines are invisible too
qreal _spatium = spatium();
qreal extraLen = score()->styleS(ST_ledgerLineLength).val() * _spatium;
qreal lineLen = maxX - minX + extraLen; // line length in raster units
Spatium len(lineLen / _spatium); // line length in Spatium units
int track = staff2track(idx); // the track lines belong to
minX -= extraLen * .5; // the starting point x-pos
// lines above the staff
for (int i = (minLine+1) & ~1; i < 0; i += 2)
addLedgerLine(track, i, visible, minX, len);
// lines above the staff
maxLine &= ~1; // round maxLine to even number
for (int i = minLineBelow; i <= maxLine; i += 2)
addLedgerLine(track, i, visible, minX, len);
}
//-----------------------------------------------------------------------------
@ -1559,22 +1542,18 @@ void Chord::layoutPitched()
}
//-----------------------------------------
// create ledger lines
// stem position
//-----------------------------------------
qreal stemX;
// Y: only needed if there is an actual stem
if (stem())
stem()->rypos() = (_up ? downNote() : upNote())->rypos();
if (_up) {
stemX = score()->noteHeadWidth();
if (_noteType != NOTE_NORMAL)
stemX *= score()->styleD(ST_graceNoteMag);
}
else
stemX = 0.0;
//-----------------------------------------
// create ledger lines
//-----------------------------------------
addLedgerLines(stemX, staffMove());
addLedgerLines(staffMove());
for (LedgerLine* ll = _ledgerLines; ll; ll = ll->next())
ll->layout();

View file

@ -78,8 +78,8 @@ class Chord : public ChordRest {
virtual qreal upPos() const;
virtual qreal downPos() const;
virtual qreal centerX() const;
void addLedgerLine(qreal x, int staffIdx, int line, int extend, bool visible, qreal hw);
void addLedgerLines(qreal x, int move);
void addLedgerLine(int staffIdx, int line, bool visible, qreal x, Spatium len);
void addLedgerLines(int move);
void processSiblings(std::function<void(Element*)> func);
void layoutPitched();
void layoutTablature();