internal void FinalizeBeamBlock(double rightBarlineX) { M.Assert(this.BeamBlock != null); M.Assert(this.BeamBlockDef != null); BeamBlock.FinalizeBeamBlock(BeamBlockDef, rightBarlineX); }
public ChordMetrics(System.Drawing.Graphics graphics, ChordSymbol chord, VerticalDir voiceStemDirection, float gap, float stemStrokeWidthVBPX) : base() { _top = float.MaxValue; _right = float.MinValue; _bottom = float.MinValue; _left = float.MaxValue; _drawObjects = chord.DrawObjects; _gap = gap; // The _objectType is written to the SVG file as a group name, but is otherwise not used. if(chord is CautionaryChordSymbol) _objectType = "cautionary chord"; else _objectType = "chord"; GetStaffParameters(chord); // sets _clef to the most recent clef, and _nStafflines. // For each component, find its characterID, deltaX and deltaY re the chord's origin. // The chord's x-origin is the centre of the outermost notehead. // (deltaX of the outermost notehead is 0.) // The chord's y-origin is the top line of the staff. // (deltaY of a notehead on the top line of the staff is 0.) if(chord.BeamBlock != null && chord.BeamBlock.Chords[0] == chord) this.BeamBlock = chord.BeamBlock; SetHeadsMetrics(chord, stemStrokeWidthVBPX); if(chord.Stem.Draw) // false for cautionary chords SetStemAndFlags(chord, _headsMetricsTopDown, stemStrokeWidthVBPX); // if the chord is part of a beamGroup, the stem tips are all at one height here. // These objects are created with originX and originY at 0,0 (the chord's origin). CreateLedgerlineAndAccidentalMetrics(chord.FontHeight, chord.HeadsTopDown, _headsMetricsTopDown, stemStrokeWidthVBPX); CautionaryChordSymbol cautionaryChordSymbol = chord as CautionaryChordSymbol; if(cautionaryChordSymbol != null) { CreateCautionaryBracketsMetrics(cautionaryChordSymbol); } else { bool dynamicIsBelow; bool ornamentIsBelow; _lyricMetrics = NewLyricMetrics(chord.Voice.StemDirection, graphics, gap); GetRelativePositions(chord.Voice.StemDirection, _lyricMetrics, out ornamentIsBelow, out dynamicIsBelow); _ornamentMetrics = NewOrnamentMetrics(graphics, gap, ornamentIsBelow); _dynamicMetrics = NewDynamicMetrics(gap, dynamicIsBelow); MoveAuxilliaries(chord.Stem.Direction, gap); } SetExternalBoundary(); }
/// <summary> /// Adjusts the heights of stem tips attached to beam blocks in staves which have 2 voices. /// The stem tips are moved vertically (all to the same height) to take account of chords in the other /// voice which would otherwise collide with the beamBlock. /// This is done so that account can be taken of the stems and auxilliaries when justifying horizontally. /// The BeamBlocks themselves are finalized later, at which point the stem tips are moved again. /// </summary> public void AdjustBeamedStemHeights(int voiceIndex) { Debug.Assert(Voices.Count == 2); Debug.Assert(voiceIndex == 0 || voiceIndex == 1); Debug.Assert(Voices[0].StemDirection == VerticalDir.up); Debug.Assert(Voices[1].StemDirection == VerticalDir.down); int adjustVoiceIndex = 0; int otherVoiceIndex = 1; if (voiceIndex == 1) { adjustVoiceIndex = 1; otherVoiceIndex = 0; } foreach (ChordSymbol chordSymbol in Voices[adjustVoiceIndex].ChordSymbols) { if (chordSymbol.BeamBlock != null) { BeamBlock beamBlock = chordSymbol.BeamBlock; List <ChordSymbol> enclosedChords = beamBlock.EnclosedChords(Voices[otherVoiceIndex]); foreach (ChordSymbol chord in beamBlock.Chords) { foreach (ChordSymbol otherChord in enclosedChords) { chord.ChordMetrics.AdjustStemLengthAndFlagBlock(chord.DurationClass, chord.FontHeight, otherChord.ChordMetrics.HeadsMetrics); } } if (adjustVoiceIndex == 0) { float minStemTip = float.MaxValue; foreach (ChordSymbol beamedChord in beamBlock.Chords) { minStemTip = minStemTip < beamedChord.ChordMetrics.StemMetrics.Top ? minStemTip : beamedChord.ChordMetrics.StemMetrics.Top; } foreach (ChordSymbol beamedChord in beamBlock.Chords) { beamedChord.ChordMetrics.MoveOuterStemTip(minStemTip, VerticalDir.up); } } else { float maxStemTip = float.MinValue; foreach (ChordSymbol beamedChord in beamBlock.Chords) { maxStemTip = maxStemTip > beamedChord.ChordMetrics.StemMetrics.Bottom ? maxStemTip : beamedChord.ChordMetrics.StemMetrics.Bottom; } foreach (ChordSymbol beamedChord in beamBlock.Chords) { beamedChord.ChordMetrics.MoveOuterStemTip(maxStemTip, VerticalDir.down); } } } } }
private void MoveFramedTextAboveBeamBlock(Metrics framedTextMetrics, BeamBlock beamBlock) { double padding = Gap * 1.5; double verticalOverlap = beamBlock.OverlapHeight(framedTextMetrics, padding); if (verticalOverlap > 0) { verticalOverlap = (verticalOverlap > padding) ? verticalOverlap : padding; framedTextMetrics.Move(0, -verticalOverlap); } }
private StemMetrics NewStemMetrics( List<HeadMetrics> topDownHeadsMetrics, VerticalDir stemDirection, float fontHeight, Metrics flagsBlockMetrics, BeamBlock beamBlock, float strokeWidth) { HeadMetrics outerNotehead = FindOuterNotehead(topDownHeadsMetrics, stemDirection); HeadMetrics innerNotehead = FindInnerNotehead(topDownHeadsMetrics, stemDirection); string noteheadID = outerNotehead.ID_Type; NoteheadStemPositions_px nspPX = CLichtFontMetrics.ClichtNoteheadStemPositionsDictPX[noteheadID]; float outerNoteheadAlignmentY = (outerNotehead.Bottom + outerNotehead.Top) / 2F; float innerNoteheadAlignmentY = (innerNotehead.Bottom + innerNotehead.Top) / 2F; float delta = _gap * 0.1F; float octave = (_gap * 3.5F) + delta; // a little more than 1 octave float sixth = (_gap * 2.5F) + delta; // a little more than 1 sixth float top = 0F; float bottom = 0F; float x = 0F; if(stemDirection == VerticalDir.up) { x = outerNotehead.RightStemX - (strokeWidth / 2); bottom = outerNoteheadAlignmentY + (nspPX.RightStemY_px * fontHeight); if(beamBlock != null) { top = beamBlock.DefaultStemTipY; } else { if(flagsBlockMetrics != null) { top = flagsBlockMetrics.Top; } else top = innerNoteheadAlignmentY - octave; if(top > (_gap * 2)) { top = (_gap * 2) - delta; } } } else // stem is down { x = outerNotehead.LeftStemX + (strokeWidth / 2); top = outerNoteheadAlignmentY + (nspPX.LeftStemY_px * fontHeight); if(beamBlock != null) { bottom = beamBlock.DefaultStemTipY; } else { if(flagsBlockMetrics != null) { bottom = flagsBlockMetrics.Bottom; } else bottom = innerNoteheadAlignmentY + octave; if(bottom < (_gap * 2)) { bottom = (_gap * 2) + delta; } } } StemMetrics stemMetrics = new StemMetrics(top, x, bottom, strokeWidth, stemDirection); return stemMetrics; }
/// <summary> /// Returns the stem which the otherChordTopDownHeadsMetrics would have if their duration class was crotchet. /// DummyStemMetrics are used when aligning synchronous chords. /// </summary> private StemMetrics DummyStemMetrics( List<HeadMetrics> otherChordTopDownHeadsMetrics, VerticalDir stemDirection, float fontHeight, Metrics flagsBlockMetrics, BeamBlock beamBlock, float strokeWidth) { List<HeadMetrics> tempTopDownHeadsMetrics = new List<HeadMetrics>(); foreach(HeadMetrics headMetrics in otherChordTopDownHeadsMetrics) { HeadMetrics newHeadMetrics = new HeadMetrics(headMetrics, DurationClass.crotchet); tempTopDownHeadsMetrics.Add(newHeadMetrics); } return NewStemMetrics(tempTopDownHeadsMetrics, stemDirection, fontHeight, flagsBlockMetrics, beamBlock, strokeWidth); }