/// <summary> /// Moves rests onto the top and bottom stafflines. Most rests move two gaps from the centre staffline, /// but breve and semibreve rests in the top voice move to a position 1 gap above the top staffline, and /// breve and semibreve rests in the bottom voice move onto the bottom staffline. /// Breve and semibreve rests outside the stafflines have a single, visible "ledgerline". /// </summary> private void MoveRestsOntoOuterStafflines() { for (int voiceIndex = 0; voiceIndex < 2; ++voiceIndex) { foreach (NoteObject noteObject in Voices[voiceIndex].NoteObjects) { RestSymbol rest = noteObject as RestSymbol; if (rest != null) { RestMetrics metrics = (RestMetrics)rest.Metrics; if (voiceIndex == 0) { if (rest.DurationClass == DurationClass.breve || rest.DurationClass == DurationClass.semibreve) { metrics.LedgerlineVisible = true; // only affects breves, semibreves and minims } metrics.Move(0F, this.Gap * -2); } else { if (rest.DurationClass == DurationClass.breve || rest.DurationClass == DurationClass.semibreve) { metrics.Move(0F, this.Gap * 3); } else { metrics.Move(0F, this.Gap * 2); } } } } } }
private void AdjustRestRestCollisions() { List <NoteObject> upperObjects = Voices[0].NoteObjects; List <NoteObject> lowerObjects = Voices[1].NoteObjects; // If a rest in the top voice collides with a rest in the lower voice at the same msPosition, // both rests are moved in gap steps outwards until they no longer overlap. foreach (NoteObject topObject in upperObjects) { RestSymbol topRest = topObject as RestSymbol; if (topRest != null) { RestMetrics upperRestMetrics = topRest.Metrics as RestMetrics; foreach (NoteObject lowerObject in lowerObjects) { RestSymbol lowerRestSymbol = lowerObject as RestSymbol; if (lowerRestSymbol != null) { if (topRest.MsPosition < lowerRestSymbol.MsPosition) { break; } if (topRest.MsPosition == lowerRestSymbol.MsPosition) { RestMetrics lowerRestMetrics = (RestMetrics)lowerRestSymbol.Metrics; float verticalOverlap = lowerRestMetrics.OverlapHeight(upperRestMetrics, 0F); bool moveBottomRest = true; while (verticalOverlap > 0) { float newMinBottom = upperRestMetrics.Bottom - verticalOverlap; if (upperRestMetrics.Bottom > newMinBottom) { if (moveBottomRest) { lowerRestMetrics.LedgerlineVisible = true; // only affects breves, semibreves and minims lowerRestMetrics.Move(0F, Gap); moveBottomRest = false; } else { upperRestMetrics.LedgerlineVisible = true; // only affects breves, semibreves and minims upperRestMetrics.Move(0F, -Gap); moveBottomRest = true; } } verticalOverlap = lowerRestMetrics.OverlapHeight(upperRestMetrics, 0F); } } } } } } }
private void AdjustRestsForVerticalChordCollisions(int restsChannelIndex) { Debug.Assert(restsChannelIndex == 0 || restsChannelIndex == 1); List <NoteObject> restObjects; List <NoteObject> chordObjects; bool shiftRestUp; if (restsChannelIndex == 0) { shiftRestUp = true; restObjects = Voices[0].NoteObjects; chordObjects = Voices[1].NoteObjects; } else { shiftRestUp = false; restObjects = Voices[1].NoteObjects; chordObjects = Voices[0].NoteObjects; } // Move rests in the top voice up by gap increments if they are synchronous with an overlapping chord in the lower voice. // Move rests in the bottom voice down by gap increments if they are synchronous with an overlapping chord in the top voice. foreach (NoteObject restObject in restObjects) { RestSymbol restSymbol = restObject as RestSymbol; if (restSymbol != null) { foreach (NoteObject chordObject in chordObjects) { OutputChordSymbol chordSymbol = chordObject as OutputChordSymbol; if (chordSymbol != null) { if (chordSymbol.MsPosition > restSymbol.MsPosition) { break; } if (chordSymbol.MsPosition == restSymbol.MsPosition) { RestMetrics restMetrics = restSymbol.RestMetrics; ChordMetrics chordMetrics = chordSymbol.ChordMetrics; //float verticalOverlap = chordMetrics.OverlapHeight(restMetrics, Gap / 2F); float verticalOverlap = chordMetrics.OverlapHeight(restMetrics, 0F); if (verticalOverlap > 0) { if (shiftRestUp) { //float newMaxBottom = chordMetrics.Top - Gap; float newMaxBottom = chordMetrics.Top; newMaxBottom += DurationClassDeltaAbove(restSymbol.DurationClass, Gap); while (restMetrics.Bottom > newMaxBottom) { restMetrics.LedgerlineVisible = true; // only affects breves, semibreves and minims restMetrics.Move(0F, -Gap); } break; // to next rest symbol } else { //float newMinTop = chordMetrics.Bottom + Gap; float newMinTop = chordMetrics.Bottom; newMinTop += DurationClassDeltaBelow(restSymbol.DurationClass, Gap); while (restMetrics.Top < newMinTop) { restMetrics.LedgerlineVisible = true; // only affects breves, semibreves and minims restMetrics.Move(0F, Gap); } break; // to next rest symbol } } } } } } } }