📄 notationgroup.cpp
字号:
bool inside = false; bool found = false; for (NELIterator i = getInitialNote(); i != getContainer().end(); ++i) { NotationElement* el = static_cast<NotationElement*>(*i); if (el->isNote() && el->event()->has(BaseProperties::NOTE_TYPE) && el->event()->get <Int>(BaseProperties::NOTE_TYPE) < Note::Crotchet && el->event()->has(BaseProperties::BEAMED_GROUP_ID) && el->event()->get<Int>(BaseProperties::BEAMED_GROUP_ID) == m_groupNo) { if (found) return true; // a rest is wholly enclosed by beamed notes inside = true; } if (el->isRest() && inside) found = true; if (i == getFinalNote()) break; } return false;}NotationGroup::BeamNotationGroup::calculateBeam(NotationStaff &staff){ Beam beam; beam.aboveNotes = !(m_weightAbove > m_weightBelow); beam.startY = 0; beam.gradient = 0; beam.necessary = false; NELIterator initialNote(getInitialNote()), finalNote( getFinalNote()); if (initialNote == getContainer().end() || initialNote == finalNote) { return beam; // no notes, or at most one: no case to answer } if ((*initialNote)->event()->has(NotationProperties::BEAM_ABOVE)) { beam.aboveNotes = (*initialNote)->event()->get <Bool> (NotationProperties::BEAM_ABOVE); } timeT crotchet = Note(Note::Crotchet).getDuration(); beam.necessary = (*initialNote)->getViewDuration() < crotchet && (*finalNote)->getViewDuration() < crotchet && (*finalNote)->getViewAbsoluteTime() > (*initialNote)->getViewAbsoluteTime(); // We continue even if the beam is not necessary, because the // same data is used to generate the tupling line in tupled // groups that do not have beams // if (!beam.necessary) return beam; NotationChord initialChord(getContainer(), initialNote, &getQuantizer(), m_properties, m_clef, m_key), finalChord(getContainer(), finalNote, &getQuantizer(), m_properties, m_clef, m_key); if (initialChord.getInitialElement() == finalChord.getInitialElement()) { return beam; } int initialHeight, finalHeight, extremeHeight; NELIterator extremeNote; if (beam.aboveNotes) { initialHeight = height(initialChord.getHighestNote()); finalHeight = height( finalChord.getHighestNote()); extremeHeight = height( getHighestNote()); extremeNote = getHighestNote(); } else { initialHeight = height(initialChord.getLowestNote()); finalHeight = height( finalChord.getLowestNote()); extremeHeight = height( getLowestNote()); extremeNote = getLowestNote(); } int diff = initialHeight - finalHeight; if (diff < 0) diff = -diff; bool linear = (beam.aboveNotes ? (extremeHeight <= std::max(initialHeight, finalHeight)) : (extremeHeight >= std::min(initialHeight, finalHeight))); if (!linear) { if (diff > 2) diff = 1; else diff = 0; } // Now, we need to judge the height of the beam such that the // nearest note of the whole group, the nearest note of the first // chord and the nearest note of the final chord are all at least // two note-body-heights away from it, and at least one of the // start and end points is at least the usual note stem-length // away from it. This is a straight-line equation y = mx + c, // where we have m and two x,y pairs and need to find c. //!!! If we find that making one extreme a sensible distance from //the note head makes the other extreme way too far away from it //in the direction of the gradient, then we should flatten the //gradient. There may be a better heuristic for this. int initialX = (int)(*initialNote)->getLayoutX(); int finalDX = (int) (*finalNote)->getLayoutX() - initialX; int extremeDX = (int)(*extremeNote)->getLayoutX() - initialX; int spacing = staff.getNotePixmapFactory(m_type == Grace).getLineSpacing(); beam.gradient = 0; if (finalDX > 0) { do { if (diff == 0) break; else if (diff > 3) diff = 3; else --diff; beam.gradient = (diff * spacing * 100) / (finalDX * 2); } while (beam.gradient > 18); } else { beam.gradient = 0; } if (initialHeight < finalHeight) beam.gradient = -beam.gradient; int finalY = staff.getLayoutYForHeight(finalHeight); int extremeY = staff.getLayoutYForHeight(extremeHeight); int c0 = staff.getLayoutYForHeight(initialHeight), c1, c2; double dgrad = (double)beam.gradient / 100.0; Equation::solve(Equation::C, extremeY, dgrad, extremeDX, c1); Equation::solve(Equation::C, finalY, dgrad, finalDX, c2); using std::max; using std::min; long shortestNoteType = Note::Quaver; if (!(*getShortestElement())->event()->get <Int>(BaseProperties::NOTE_TYPE, shortestNoteType)) { NOTATION_DEBUG << "NotationGroup::calculateBeam: WARNING: Shortest element has no note-type; should this be possible?" << endl; NOTATION_DEBUG << "(Event dump follows)" << endl; (*getShortestElement())->event()->dump(std::cerr); } // minimal stem lengths at start, middle-extreme and end of beam int sl = staff.getNotePixmapFactory(m_type == Grace).getStemLength(); int ml = spacing * 2; int el = sl; NOTATION_DEBUG << "c0: " << c0 << ", c1: " << c1 << ", c2: " << c2 << endl; NOTATION_DEBUG << "sl: " << sl << ", ml: " << ml << ", el: " << el << endl; // If the stems are down, we will need to ensure they end at // heights lower than 0 if there's an internal rest -- likewise // with stems up and an internal rest we need to ensure they end // at higher than 8. // [Avoid doing expensive haveInternalRest() test where possible] if (beam.aboveNotes) { int topY = staff.getLayoutYForHeight(8); if ((c0 - sl > topY) || (c1 - ml > topY) || (c2 - el > topY)) { if (haveInternalRest()) { if (c0 - sl > topY) sl = c0 - topY; if (c1 - ml > topY) ml = c1 - topY; if (c2 - el > topY) el = c2 - topY; NOTATION_DEBUG << "made internal rest adjustment for above notes" << endl; NOTATION_DEBUG << "sl: " << sl << ", ml: " << ml << ", el: " << el << endl; } } } else { int bottomY = staff.getLayoutYForHeight(0); if ((c0 + sl < bottomY) || (c1 + ml < bottomY) || (c2 + el < bottomY)) { if (haveInternalRest()) { if (c0 + sl < bottomY) sl = bottomY - c0; if (c1 + ml < bottomY) ml = bottomY - c1; if (c2 + el < bottomY) el = bottomY - c2; NOTATION_DEBUG << "made internal rest adjustment for below notes" << endl; NOTATION_DEBUG << "sl: " << sl << ", ml: " << ml << ", el: " << el << endl; } } } if (shortestNoteType < Note::Semiquaver) { int off = spacing * (Note::Semiquaver - shortestNoteType); sl += off; el += off; } if (shortestNoteType < Note::Quaver) { int off = spacing * (Note::Quaver - shortestNoteType); ml += off; } int midY = staff.getLayoutYForHeight(4); // ensure extended to middle line if necessary, and assign suitable stem length if (beam.aboveNotes) { if (c0 - sl > midY) sl = c0 - midY; if (c1 - ml > midY) ml = c1 - midY; if (c2 - el > midY) el = c2 - midY; if (extremeDX > 1.0 || extremeDX < -1.0) { // beam.gradient = int(100 * double(c2 - c0) / double(extremeDX)); } beam.startY = min(min(c0 - sl, c1 - ml), c2 - el); } else { if (c0 + sl < midY) sl = midY - c0; if (c1 + ml < midY) ml = midY - c1; if (c2 + el < midY) el = midY - c2; if (extremeDX > 1.0 || extremeDX < -1.0) { // beam.gradient = int(100 * double(c2 - c0) / double(extremeDX)); } beam.startY = max(max(c0 + sl, c1 + ml), c2 + el); } /* NOTATION_DEBUG << "NotationGroup::calculateBeam: beam data:" << endl << "gradient: " << beam.gradient << endl << "(c0 " << c0 << ", c2 " << c2 << ", extremeDX " << extremeDX << ")" << endl << "startY: " << beam.startY << endl << "aboveNotes: " << beam.aboveNotes << endl << "shortestNoteType: " << shortestNoteType << endl << "necessary: " << beam.necessary << endl; */ return beam;}voidNotationGroup::applyBeam(NotationStaff &staff){ // NOTATION_DEBUG << "NotationGroup::applyBeam, group no is " << m_groupNo << endl; /* NOTATION_DEBUG << "\nNotationGroup::applyBeam" << endl; NOTATION_DEBUG << "Group id: " << m_groupNo << ", type " << m_type << endl; NOTATION_DEBUG << "Coverage:" << endl; int i = 0; for (NELIterator i = getInitialElement(); i != getContainer().end(); ++i) { (*i)->event()->dump(cerr); if (i == getFinalElement()) break; } { NELIterator i(getInitialNote()); NOTATION_DEBUG << "Initial note: " << (i == getContainer().end() ? -1 : (*i)->event()->getAbsoluteTime()) << endl; } { NELIterator i(getFinalNote()); NOTATION_DEBUG << "Final note: " << (i == getContainer().end() ? -1 : (*i)->event()->getAbsoluteTime()) << endl; } { NELIterator i(getHighestNote()); NOTATION_DEBUG << "Highest note: " << (i == getContainer().end() ? -1 : (*i)->event()->getAbsoluteTime()) << endl; } { NELIterator i(getLowestNote()); NOTATION_DEBUG << "Lowest note: " << (i == getContainer().end() ? -1 : (*i)->event()->getAbsoluteTime()) << endl; } */ Beam beam(calculateBeam(staff)); if (!beam.necessary) { for (NELIterator i = getInitialNote(); i != getContainer().end(); ++i) { (*i)->event()->unset(NotationProperties::BEAMED); (*i)->event()->unset(m_properties.TUPLING_LINE_MY_Y); if (i == getFinalNote()) break; } return ; } // NOTATION_DEBUG << "NotationGroup::applyBeam: Beam is necessary" << endl; NELIterator initialNote(getInitialNote()), finalNote( getFinalNote()); int initialX = (int)(*initialNote)->getLayoutX(); timeT finalTime = (*finalNote)->getViewAbsoluteTime(); // For each chord in the group, we nominate the note head furthest // from the beam as the primary note, the one that "owns" the stem // and the section of beam up to the following chord. For this // note, we need to: // // * Set the start height, start x-coord and gradient of the beam // (we can't set the stem length for this note directly, because // we don't know its y-coordinate yet) // // * Set width of this section of beam // // * Set the number of beams required for the following note (one // slight complication here: a beamed group in which the very // first chord is shorter than the following one. Here the first // chord needs to know it's the first, or else it can't draw the // part-beams immediately to its right correctly.)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -