Exemplo n.º 1
0
        private float GetDefaultStemTipY(ClefSymbol currentClef, List <ChordSymbol> chordsBeamedTogether)
        {
            float       headMinTop         = float.MaxValue;
            float       headMaxBottom      = float.MinValue;
            float       gap                = chordsBeamedTogether[0].Voice.Staff.Gap;
            int         numberOfStafflines = chordsBeamedTogether[0].Voice.Staff.NumberOfStafflines;
            VerticalDir direction          = chordsBeamedTogether[0].Stem.Direction;

            foreach (ChordSymbol chord in chordsBeamedTogether)
            {
                foreach (Head head in chord.HeadsTopDown)
                {
                    float headY = head.GetOriginY(currentClef, gap);
                    headMinTop    = headMinTop < headY ? headMinTop : headY;
                    headMaxBottom = headMaxBottom > headY ? headMaxBottom : headY;
                }
            }

            if (direction == VerticalDir.up)
            {
                return(headMinTop - (gap * numberOfStafflines));
            }
            else
            {
                return(headMaxBottom + (gap * numberOfStafflines));
            }
        }
Exemplo n.º 2
0
 public Stem(ChordSymbol chordSymbol, Stem stem)
 {
     Chord = chordSymbol;
     if(stem != null)
     {
         Direction = stem.Direction;
     }
 }
Exemplo n.º 3
0
        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();
        }
Exemplo n.º 4
0
 public StemMetrics(double top, double x, double bottom, double strokeWidth, VerticalDir verticalDir)
     : base(CSSObjectClass.stem, strokeWidth, "black")
 {
     _originX    = x;
     _originY    = top;
     _top        = top;
     _right      = x + strokeWidth;
     _bottom     = bottom;
     _left       = x - strokeWidth;
     VerticalDir = verticalDir;
     StrokeWidth = strokeWidth;
 }
Exemplo n.º 5
0
 public StemMetrics(float top, float x, float bottom, float strokeWidth, VerticalDir verticalDir)
     : base()
 {
     _originX    = x;
     _originY    = top;
     _top        = top;
     _right      = x + strokeWidth;
     _bottom     = bottom;
     _left       = x - strokeWidth;
     VerticalDir = verticalDir;
     StrokeWidth = strokeWidth;
 }
Exemplo n.º 6
0
        /// <summary>
        /// 20.01.2012 N.B. Neither this function nor ChordMetrics.MoveAuxilliariesToLyricHeight()
        /// have been thoroughly tested yet.
        /// This function should align the lyrics in each voice, moving ornaments and dynamics
        /// which are on the same side of the staff. (Lyrics are closest to the staff.)
        /// </summary>
        public override void AlignLyrics(List <Staff> staves)
        {
            foreach (Staff staff in staves)
            {
                if (!(staff is InvisibleOutputStaff))
                {
                    for (int voiceIndex = 0; voiceIndex < staff.Voices.Count; ++voiceIndex)
                    {
                        VerticalDir voiceStemDirection = VerticalDir.none;
                        if (staff.Voices.Count > 1)
                        {   // 2-Voice staff
                            if (voiceIndex == 0)
                            {
                                voiceStemDirection = VerticalDir.up; // top voice
                            }
                            else
                            {
                                voiceStemDirection = VerticalDir.down; // bottom voice
                            }
                        }

                        float lyricMaxTop    = float.MinValue;
                        float lyricMinBottom = float.MaxValue;
                        foreach (ChordSymbol chordSymbol in staff.Voices[voiceIndex].ChordSymbols)
                        {
                            Metrics lyricMetrics = chordSymbol.ChordMetrics.LyricMetrics;
                            if (lyricMetrics != null)
                            {
                                lyricMaxTop    = (lyricMaxTop > lyricMetrics.Top) ? lyricMaxTop : lyricMetrics.Top;
                                lyricMinBottom = (lyricMinBottom < lyricMetrics.Bottom) ? lyricMinBottom : lyricMetrics.Bottom;
                            }
                        }
                        if (lyricMaxTop != float.MinValue)
                        {   // the voice has lyrics
                            if (voiceStemDirection == VerticalDir.none || voiceStemDirection == VerticalDir.down)
                            {
                                // the lyrics are below the staff
                                float lyricMinTop = staff.Metrics.StafflinesBottom + (staff.SVGSystem.Score.PageFormat.Gap * 1.5F);
                                lyricMaxTop = lyricMaxTop > lyricMinTop ? lyricMaxTop : lyricMinTop;
                            }
                            foreach (ChordSymbol chordSymbol in staff.Voices[voiceIndex].ChordSymbols)
                            {
                                chordSymbol.ChordMetrics.MoveAuxilliariesToLyricHeight(voiceStemDirection, lyricMaxTop, lyricMinBottom);
                            }
                        }
                    }
                }
            }
        }
Exemplo n.º 7
0
        /// <summary>
        /// Shifts a horizontal beam vertically to the correct position (wrt the beamBlock) for its duration class
        /// </summary>
        /// <param name="outerLeftY"></param>
        /// <param name="gap"></param>
        /// <param name="stemDirection"></param>
        /// <param name="beamThickness"></param>
        /// <param name="nGaps"></param>
        protected void ShiftYsForBeamBlock(double outerLeftY, double gap, VerticalDir stemDirection, double beamThickness, int nGaps)
        {
            double dy = 0;

            if (stemDirection == VerticalDir.down)
            {
                dy = -(beamThickness + (gap * nGaps));
            }
            else
            {
                dy = gap * nGaps;
            }
            dy += outerLeftY - _leftTopY;
            MoveYs(dy, dy);
        }
Exemplo n.º 8
0
        /// <summary>
        /// Shifts a horizontal beam vertically to the correct position (wrt the beamBlock) for its duration class
        /// </summary>
        /// <param name="outerLeftY"></param>
        /// <param name="gap"></param>
        /// <param name="stemDirection"></param>
        /// <param name="beamThickness"></param>
        /// <param name="nGaps"></param>
        protected void ShiftYsForBeamBlock(float outerLeftY, float gap, VerticalDir stemDirection, float beamThickness, int nGaps)
        {
            float dy = 0F;

            if (stemDirection == VerticalDir.down)
            {
                dy = -(beamThickness + (gap * nGaps));
            }
            else
            {
                dy = gap * nGaps;
            }
            dy += outerLeftY - _leftTopY;
            MoveYs(dy, dy);
        }
Exemplo n.º 9
0
        public BeamBlock(ClefSymbol clef, List<ChordSymbol> chordsBeamedTogether, VerticalDir voiceStemDirection, float beamThickness, float strokeThickness)
            : base(null, 0, 0)
        {
            Chords = new List<ChordSymbol>(chordsBeamedTogether);
            SetBeamedGroupStemDirection(clef, chordsBeamedTogether, voiceStemDirection);
            foreach(ChordSymbol chord in chordsBeamedTogether)
                chord.BeamBlock = this; // prevents an isolated flag from being created

            _gap = Chords[0].Voice.Staff.Gap;
            _beamSeparation = _gap;
            _beamThickness = beamThickness;
            _strokeThickness = strokeThickness;
            _stemDirection = Chords[0].Stem.Direction;

            /******************************************************************************
             * Important to set stem tips to this value before justifying horizontally.
             * Allows collisions between the objects outside the tips (e.g. dynamics or ornaments)
             * to be detected correctly. */
            _defaultStemTipY = GetDefaultStemTipY(clef, chordsBeamedTogether);
        }
Exemplo n.º 10
0
        public BeamBlock(ClefSymbol clef, List <ChordSymbol> chordsBeamedTogether, VerticalDir voiceStemDirection, float beamThickness, float strokeThickness)
            : base(null, 0, 0)
        {
            Chords = new List <ChordSymbol>(chordsBeamedTogether);
            SetBeamedGroupStemDirection(clef, chordsBeamedTogether, voiceStemDirection);
            foreach (ChordSymbol chord in chordsBeamedTogether)
            {
                chord.BeamBlock = this; // prevents an isolated flag from being created
            }
            _gap             = Chords[0].Voice.Staff.Gap;
            _beamSeparation  = _gap;
            _beamThickness   = beamThickness;
            _strokeThickness = strokeThickness;
            _stemDirection   = Chords[0].Stem.Direction;

            /******************************************************************************
             * Important to set stem tips to this value before justifying horizontally.
             * Allows collisions between the objects outside the tips (e.g. dynamics or ornaments)
             * to be detected correctly. */
            _defaultStemTipY = GetDefaultStemTipY(clef, chordsBeamedTogether);
        }
Exemplo n.º 11
0
        /// <summary>
        /// This algorithm follows Gardner Read when the stemDirection is "none" (i.e. not forced):
        /// If there were no beam, and the majority of the stems would go up, then all the stems in the beam go up.
        /// ji: if there are the same number of default up and default down stems, then the direction is decided by
        /// the most extreme notehead in the beam group. If both extremes are the same (e.g. 1 ledgeline up and down)
        /// then the stems are all down.
        /// </summary>
        /// <param name="currentClef"></param>
        /// <param name="chordsBeamedTogether"></param>
        private void SetBeamedGroupStemDirection(ClefSymbol currentClef, List <ChordSymbol> chordsBeamedTogether, VerticalDir voiceStemDirection)
        {
            Debug.Assert(chordsBeamedTogether.Count > 1);
            VerticalDir groupStemDirection = voiceStemDirection;

            if (voiceStemDirection == VerticalDir.none)
            {   // here, there is only one voice in the staff, so the direction depends on the height of the noteheads.
                int upStems   = 0;
                int downStems = 0;
                foreach (ChordSymbol chord in chordsBeamedTogether)
                {
                    VerticalDir direction = chord.DefaultStemDirection(currentClef);
                    if (direction == VerticalDir.up)
                    {
                        upStems++;
                    }
                    else
                    {
                        downStems++;
                    }
                }

                if (upStems == downStems)
                {
                    groupStemDirection = GetDirectionFromExtremes(currentClef, chordsBeamedTogether);
                }
                else if (upStems > downStems)
                {
                    groupStemDirection = VerticalDir.up;
                }
                else
                {
                    groupStemDirection = VerticalDir.down;
                }
            }
            foreach (ChordSymbol chord in chordsBeamedTogether)
            {
                chord.Stem.Direction = groupStemDirection;
            }
        }
Exemplo n.º 12
0
 /// <summary>
 /// N.B. This function has not been thoroughly tested yet. 20.01.2012
 /// If there is a lyric in this chord:
 /// If voiceStemDirection is none or down, the top of the lyric is aligned to lyricTop,
 /// If voiceStemDirection is up, this chord is in the upper voice of a 2-voice staff, and
 /// the lyric is above the chord. In this case, the bottom of the lyric is aligned to lyricBottom.
 /// If there is a dynamic or ornament on the same side of the staff, these are also moved by
 /// the same amount.
 /// If this chord has no lyric, nothing happens.
 /// </summary>
 public void MoveAuxilliariesToLyricHeight(VerticalDir voiceStemDirection, float lyricTop, float lyricBottom)
 {
     if(_lyricMetrics != null)
     {
         bool ornamentIsBelow;
         bool dynamicIsBelow;
         GetRelativePositions(voiceStemDirection, _lyricMetrics, out ornamentIsBelow, out dynamicIsBelow);
         float delta = 0F;
         if(_lyricMetrics.IsBelow)
         {
             delta = lyricTop - _lyricMetrics.Top;
             delta *= 0.7F; // this line added 12.08.2015
             _lyricMetrics.Move(0F, delta);
             if(ornamentIsBelow && _ornamentMetrics != null)
                 _ornamentMetrics.Move(0F, delta);
             if(dynamicIsBelow && _dynamicMetrics != null)
                 _dynamicMetrics.Move(0F, delta);
         }
         else // lyric is above
         {
             delta = lyricBottom - _lyricMetrics.Bottom;
             _lyricMetrics.Move(0F, delta);
             if(!ornamentIsBelow && _ornamentMetrics != null)
                 _ornamentMetrics.Move(0F, delta);
             if(!dynamicIsBelow && _dynamicMetrics != null)
                 _dynamicMetrics.Move(0F, delta);
         }
     }
 }
Exemplo n.º 13
0
        /// <summary>
        /// The flagBlock is moved to the correct x-position wrt noteheads.
        /// The distance between the inner notehead's alignmentY and the closest edge of the flagsBlock is set to a little less than two spaces.
        /// If there is only one flag, the distance is increased to a little less than three spaces (1 octave).
        /// If the stem is up and the bottom of the flagBlock is too low, the flagBlock is moved up.
        /// If the stem is down and the top of the flagBlock is too high, the flagBlock is moved down.
        /// </summary>
        private void SetFlagsPositionReNoteheads(List<HeadMetrics> topDownHeadsMetrics, Metrics flagsBlockMetrics, VerticalDir stemDirection, float stemThickness)
        {
            Debug.Assert(flagsBlockMetrics != null);

            HeadMetrics outerNoteheadMetrics = FindOuterNotehead(topDownHeadsMetrics, stemDirection);
            HeadMetrics innerNoteheadMetrics = FindInnerNotehead(topDownHeadsMetrics, stemDirection);
            float innerNoteheadAlignmentY = (innerNoteheadMetrics.Bottom + innerNoteheadMetrics.Top) / 2F;
            float minDist = _gap * 1.8F; // constant found by experiment
            float deltaX = 0;
            float deltaY = 0;
            if(stemDirection == VerticalDir.up)
            {
                deltaY = minDist - (innerNoteheadAlignmentY - flagsBlockMetrics.Bottom);
                if(flagsBlockMetrics.ID_Type == "Right1Flag")
                    deltaY += _gap;
                deltaY *= -1;

                if(flagsBlockMetrics.ID_Type == "Right1Flag")
                {
                    if((flagsBlockMetrics.Bottom + deltaY) > (_gap * 2.5F))
                    {
                        deltaY = (_gap * 2.5F) - flagsBlockMetrics.Bottom;
                    }
                }
                else // other right flag types
                    if((flagsBlockMetrics.Bottom + deltaY) > (_gap * 3.5F))
                    {
                        deltaY = (_gap * 3.5F) - flagsBlockMetrics.Bottom;
                    }

                deltaX = outerNoteheadMetrics.RightStemX - (stemThickness / 2F);
            }
            else // stem is down
            {
                deltaY = minDist - (flagsBlockMetrics.Top - innerNoteheadAlignmentY);
                if(flagsBlockMetrics.ID_Type == "Left1Flag")
                    deltaY += _gap;

                if(flagsBlockMetrics.ID_Type == "Left1Flag")
                {
                    if((flagsBlockMetrics.Top + deltaY) < (_gap * 1.5F))
                    {
                        deltaY = (_gap * 1.5F) - flagsBlockMetrics.Top;
                    }
                }
                else // other left flag types
                    if((flagsBlockMetrics.Top + deltaY) < (_gap * 0.5F))
                    {
                        deltaY = (_gap * 0.5F) - flagsBlockMetrics.Top;
                    }

                deltaX = outerNoteheadMetrics.LeftStemX + (stemThickness / 2F);
            }
            flagsBlockMetrics.Move(deltaX, deltaY);
            // the flagsBlockMetrics is added to either this.MetricsList or this.PostJustificationMetrics in a later function.
        }
Exemplo n.º 14
0
 public abstract Metrics NoteObjectMetrics(Graphics graphics, NoteObject noteObject, VerticalDir voiceStemDirection, double gap, PageFormat pageFormat, string currentClefType);
Exemplo n.º 15
0
 public abstract void ShiftYsForBeamBlock(float outerLeftY, float gap, VerticalDir stemDirection, float beamThickness);
Exemplo n.º 16
0
 public StemMetrics(float top, float x, float bottom, float strokeWidth, VerticalDir verticalDir)
     : base()
 {
     _originX = x;
     _originY = top;
     _top = top;
     _right = x + strokeWidth;
     _bottom = bottom;
     _left = x - strokeWidth;
     VerticalDir = verticalDir;
     StrokeWidth = strokeWidth;
 }
Exemplo n.º 17
0
 public abstract Metrics NoteObjectMetrics(Graphics graphics, NoteObject noteObject, VerticalDir voiceStemDirection, float gap, float storkeWidth);
Exemplo n.º 18
0
        public override Metrics NoteObjectMetrics(Graphics graphics, NoteObject noteObject, VerticalDir voiceStemDirection, float gap, float strokeWidth)
        {
            Metrics returnMetrics = null;
            ClefSymbol clef = noteObject as ClefSymbol;
            Barline barline = noteObject as Barline;
            CautionaryOutputChordSymbol cautionaryOutputChordSymbol = noteObject as CautionaryOutputChordSymbol;
            CautionaryInputChordSymbol cautionaryInputChordSymbol = noteObject as CautionaryInputChordSymbol;
            ChordSymbol chord = noteObject as ChordSymbol;
            RestSymbol rest = noteObject as RestSymbol;
            if(barline != null)
            {
                returnMetrics = new BarlineMetrics(graphics, barline, gap);
            }
            else if(clef != null)
            {
                if(clef.ClefType != "n")
                    returnMetrics = new ClefMetrics(clef, gap);
            }
            else if(cautionaryOutputChordSymbol != null)
            {
                returnMetrics = new ChordMetrics(graphics, cautionaryOutputChordSymbol, voiceStemDirection, gap, strokeWidth);
            }
            else if(cautionaryInputChordSymbol != null)
            {
                returnMetrics = new ChordMetrics(graphics, cautionaryInputChordSymbol, voiceStemDirection, gap, strokeWidth);
            }
            else if(chord != null)
            {
                returnMetrics = new ChordMetrics(graphics, chord, voiceStemDirection, gap, strokeWidth);
            }
            else if(rest != null)
            {
                // All rests are originally created on the centre line.
                // They are moved vertically later, if they are on a 2-Voice staff.
                returnMetrics = new RestMetrics(graphics, rest, gap, noteObject.Voice.Staff.NumberOfStafflines, strokeWidth);
            }

            return returnMetrics;
        }
Exemplo n.º 19
0
        /// <summary>
        /// Returns null if the durationClass does not have a flagsBlock,
        /// otherwise returns the metrics for the flagsBlock attached to this chord, correctly positioned wrt the noteheads.
        /// </summary>
        private FlagsBlockMetrics GetFlagsBlockMetrics(List<HeadMetrics> topDownHeadsMetrics, DurationClass durationClass, float fontSize, VerticalDir stemDirection, float stemThickness)
        {
            Debug.Assert(durationClass == DurationClass.quaver
                || durationClass == DurationClass.semiquaver
                || durationClass == DurationClass.threeFlags
                || durationClass == DurationClass.fourFlags
                || durationClass == DurationClass.fiveFlags);

            FlagsBlockMetrics flagsBlockMetrics = new FlagsBlockMetrics(durationClass, fontSize, stemDirection);

            if(flagsBlockMetrics != null)
            {
                // flagsMetrics contains a metrics for the flags block with the outermost point at OriginX=0, BaselineY=0
                // Now move the flagblock so that is positioned correctly wrt the noteheads.
                SetFlagsPositionReNoteheads(topDownHeadsMetrics, flagsBlockMetrics, stemDirection, stemThickness);
            }
            return flagsBlockMetrics;
        }
Exemplo n.º 20
0
 /// <summary>
 /// Returns the notehead to which the stem is attached.
 /// </summary>
 private HeadMetrics FindOuterNotehead(List<HeadMetrics> topDownHeadsMetrics, VerticalDir stemDirection)
 {
     Debug.Assert(topDownHeadsMetrics.Count > 0);
     HeadMetrics outerNotehead = null;
     if(stemDirection == VerticalDir.up)
     {
         outerNotehead = topDownHeadsMetrics[topDownHeadsMetrics.Count - 1];
     }
     else
     {
         outerNotehead = topDownHeadsMetrics[0];
     }
     return outerNotehead;
 }
Exemplo n.º 21
0
        /// <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);
        }
Exemplo n.º 22
0
 public abstract void ShiftYsForBeamBlock(float outerLeftY, float gap, VerticalDir stemDirection, float beamThickness);
Exemplo n.º 23
0
        /// <summary>
        /// topBoundary is set to topStaffline
        /// bottomBoundary is set to bottomStaffline
        /// then these bounds are widened if the chord lies outside:
        /// If there is no stem,
        ///     topBoundary is set to topNotehead.Top
        ///     bottomBoundary is set to bottomNotehead.Bottom
        /// else if stem is up, 
        ///     topBoundardy is set to stemTopTipY or topNoteheadTop, 
        ///     bottomBoundary is set to bottomNotehead.Bottom.
        /// else if stem is down, 
        ///     topBoundary is set to topNotehead.Top, 
        ///     bottomBoundary is set to stemBottomTipY or bottomNoteheadBottom. 
        /// </summary>
        private void GetTopAndBottomBounds(VerticalDir stemDirection, out float topBoundary, out float bottomBoundary)
        {
            float topStaffline = _clef.Voice.Staff.Metrics.StafflinesTop;

            topBoundary = topStaffline; // top of staff
            bottomBoundary = topStaffline + (_gap * 4F); // bottom of staff
            if(_stemMetrics == null)
            {
                float topOfTopHead = _headsMetricsTopDown[0].Top;
                topBoundary = (topBoundary < topOfTopHead) ? topBoundary : topOfTopHead;

                float bottomOfBottomHead = _headsMetricsTopDown[_headsMetricsTopDown.Count - 1].Bottom;
                bottomBoundary = (bottomBoundary > bottomOfBottomHead) ? bottomBoundary : bottomOfBottomHead;
            }
            else if(_stemMetrics.VerticalDir == VerticalDir.up)
            {
                topBoundary = (topBoundary < _stemMetrics.Top) ? topBoundary : _stemMetrics.Top;

                float bottomOfBottomHead = _headsMetricsTopDown[_headsMetricsTopDown.Count - 1].Bottom;
                bottomBoundary = (bottomBoundary > bottomOfBottomHead) ? bottomBoundary : bottomOfBottomHead;
            }
            else
            {
                float topOfTopHead = _headsMetricsTopDown[0].Top;
                topBoundary = (topBoundary < topOfTopHead) ? topBoundary : topOfTopHead;

                bottomBoundary = (bottomBoundary > _stemMetrics.Bottom) ? bottomBoundary : _stemMetrics.Bottom;
            }
        }
Exemplo n.º 24
0
        public void MoveOuterStemTip(float stemTipY, VerticalDir stemDirection)
        {
            if(stemDirection == VerticalDir.up)
            {
                _stemMetrics.SetTop(stemTipY);
            }
            else //(_stemDirection == VerticalDir.down)
            {
                _stemMetrics.SetBottom(stemTipY);
            }

            MoveAuxilliaries(stemDirection, _gap, 0F, _gap * 0.3F);
            SetExternalBoundary();
        }
Exemplo n.º 25
0
 public Voice(Staff staff, Voice voice)
 {
     Staff = staff;
     StemDirection = voice.StemDirection;
     this.AppendNoteObjects(voice.NoteObjects);
 }
Exemplo n.º 26
0
        /// <summary>
        /// Should be called with a duration class having a flag block
        /// </summary>
        public FlagsBlockMetrics(DurationClass durationClass, float fontHeight, VerticalDir stemDirection)
            : base()
        {
            _left          = 0F;
            _right         = 0.31809F * fontHeight;
            _originX       = 0F;
            _originY       = 0F;
            _fontHeight    = fontHeight;
            _stemDirection = stemDirection;

            float offset = 0F;

            switch (durationClass)
            {
            case DurationClass.quaver:
                if (_stemDirection == VerticalDir.up)
                {
                    _objectType = "Right1Flag";
                }
                else
                {
                    _objectType = "Left1Flag";
                }
                break;

            case DurationClass.semiquaver:
                if (_stemDirection == VerticalDir.up)
                {
                    _objectType = "Right2Flags";
                }
                else
                {
                    _objectType = "Left2Flags";
                }
                offset = 0.25F;
                break;

            case DurationClass.threeFlags:
                if (_stemDirection == VerticalDir.up)
                {
                    _objectType = "Right3Flags";
                }
                else
                {
                    _objectType = "Left3Flags";
                }
                offset = 0.5F;
                break;

            case DurationClass.fourFlags:
                if (_stemDirection == VerticalDir.up)
                {
                    _objectType = "Right4Flags";
                }
                else
                {
                    _objectType = "Left4Flags";
                }
                offset = 0.75F;
                break;

            case DurationClass.fiveFlags:
                if (_stemDirection == VerticalDir.up)
                {
                    _objectType = "Right5Flags";
                }
                else
                {
                    _objectType = "Left5Flags";
                }
                offset = 1F;
                break;

            default:
                Debug.Assert(false, "This duration class has no flags.");
                break;
            }
            if (_stemDirection == VerticalDir.up)
            {
                _top    = 0F;
                _bottom = (0.2467F + offset) * fontHeight;
            }
            else
            {
                _top    = (-(0.2467F + offset)) * fontHeight;
                _bottom = 0F;
            }
        }
Exemplo n.º 27
0
 public override void ShiftYsForBeamBlock(float outerLeftY, float gap, VerticalDir stemDirection, float beamThickness)
 {
     ShiftYsForBeamBlock(outerLeftY, gap, stemDirection, beamThickness, 1);
 }
Exemplo n.º 28
0
        /// <summary>
        /// Should be called with a duration class having a flag block
        /// </summary>
        public FlagsBlockMetrics(DurationClass durationClass, float fontHeight, VerticalDir stemDirection)
            : base()
        {
            _left = 0F;
            _right = 0.31809F * fontHeight;
            _originX = 0F;
            _originY = 0F;
            _fontHeight = fontHeight;
            _stemDirection = stemDirection;

            float offset = 0F;
            switch(durationClass)
            {
                case DurationClass.quaver:
                    if(_stemDirection == VerticalDir.up)
                        _objectType = "Right1Flag";
                    else
                        _objectType = "Left1Flag";
                    break;
                case DurationClass.semiquaver:
                    if(_stemDirection == VerticalDir.up)
                        _objectType = "Right2Flags";
                    else
                        _objectType = "Left2Flags";
                    offset = 0.25F;
                    break;
                case DurationClass.threeFlags:
                    if(_stemDirection == VerticalDir.up)
                        _objectType = "Right3Flags";
                    else
                        _objectType = "Left3Flags";
                    offset = 0.5F;
                    break;
                case DurationClass.fourFlags:
                    if(_stemDirection == VerticalDir.up)
                        _objectType = "Right4Flags";
                    else
                        _objectType = "Left4Flags";
                    offset = 0.75F;
                    break;
                case DurationClass.fiveFlags:
                    if(_stemDirection == VerticalDir.up)
                        _objectType = "Right5Flags";
                    else
                        _objectType = "Left5Flags";
                    offset = 1F;
                    break;
                default:
                    Debug.Assert(false, "This duration class has no flags.");
                    break;
            }
            if(_stemDirection == VerticalDir.up)
            {
                _top = 0F;
                _bottom = (0.2467F + offset) * fontHeight;
            }
            else
            {
                _top = (-(0.2467F + offset)) * fontHeight;
                _bottom = 0F;
            }
        }
Exemplo n.º 29
0
        public override Metrics NoteObjectMetrics(Graphics graphics, NoteObject noteObject, VerticalDir voiceStemDirection, float gap, float strokeWidth)
        {
            Metrics               returnMetrics         = null;
            ClefSymbol            clef                  = noteObject as ClefSymbol;
            Barline               barline               = noteObject as Barline;
            CautionaryChordSymbol cautionaryChordSymbol = noteObject as CautionaryChordSymbol;
            ChordSymbol           chord                 = noteObject as ChordSymbol;
            RestSymbol            rest                  = noteObject as RestSymbol;

            if (barline != null)
            {
                returnMetrics = new BarlineMetrics(graphics, barline, gap);
            }
            else if (clef != null)
            {
                if (clef.ClefType != "n")
                {
                    returnMetrics = new ClefMetrics(clef, gap);
                }
            }
            else if (cautionaryChordSymbol != null)
            {
                returnMetrics = new ChordMetrics(graphics, cautionaryChordSymbol, voiceStemDirection, gap, strokeWidth);
            }
            else if (chord != null)
            {
                returnMetrics = new ChordMetrics(graphics, chord, voiceStemDirection, gap, strokeWidth);
            }
            else if (rest != null)
            {
                // All rests are originally created on the centre line.
                // They are moved vertically later, if they are on a 2-Voice staff.
                returnMetrics = new RestMetrics(graphics, rest, gap, noteObject.Voice.Staff.NumberOfStafflines, strokeWidth);
            }

            return(returnMetrics);
        }
Exemplo n.º 30
0
        /// <summary>
        /// Should be called with a duration class having a flag block
        /// </summary>
        public FlagsMetrics(DurationClass durationClass, double fontHeight, VerticalDir stemDirection)
            : base(CSSObjectClass.flag)
        {
            _left = 0;

            // (0.31809F * fontHeight) is maximum x in the flag def.
            _right = (0.31809F * fontHeight);
            if (stemDirection == VerticalDir.up)
            {
                double rightPadding = (0.06F * fontHeight);
                _right += rightPadding;
            }

            _originX = 0;
            _originY = 0;

            double offset = 0;

            switch (durationClass)
            {
            // Bravura says there is a maximum of 8 flags
            case DurationClass.quaver:
                if (stemDirection == VerticalDir.up)
                {
                    _flagID = FlagID.right1Flag;
                }
                else
                {
                    _flagID = FlagID.left1Flag;
                }
                break;

            case DurationClass.semiquaver:
                if (stemDirection == VerticalDir.up)
                {
                    _flagID = FlagID.right2Flags;
                }
                else
                {
                    _flagID = FlagID.left2Flags;
                }
                offset = 0.25;
                break;

            case DurationClass.threeFlags:
                if (stemDirection == VerticalDir.up)
                {
                    _flagID = FlagID.right3Flags;
                }
                else
                {
                    _flagID = FlagID.left3Flags;
                }
                offset = 0.5;
                break;

            case DurationClass.fourFlags:
                if (stemDirection == VerticalDir.up)
                {
                    _flagID = FlagID.right4Flags;
                }
                else
                {
                    _flagID = FlagID.left4Flags;
                }
                offset = 0.75;
                break;

            case DurationClass.fiveFlags:
                if (stemDirection == VerticalDir.up)
                {
                    _flagID = FlagID.right5Flags;
                }
                else
                {
                    _flagID = FlagID.left5Flags;
                }
                offset = 1;
                break;

            case DurationClass.sixFlags:
                if (stemDirection == VerticalDir.up)
                {
                    _flagID = FlagID.right6Flags;
                }
                else
                {
                    _flagID = FlagID.left6Flags;
                }
                offset = 1.25;
                break;

            case DurationClass.sevenFlags:
                if (stemDirection == VerticalDir.up)
                {
                    _flagID = FlagID.right7Flags;
                }
                else
                {
                    _flagID = FlagID.left7Flags;
                }
                offset = 1.5;
                break;

            case DurationClass.eightFlags:
                if (stemDirection == VerticalDir.up)
                {
                    _flagID = FlagID.right8Flags;
                }
                else
                {
                    _flagID = FlagID.left8Flags;
                }
                offset = 1.75;
                break;

            default:
                M.Assert(false, "This duration class has no flags.");
                break;
            }
            if (stemDirection == VerticalDir.up)
            {
                _top    = 0;
                _bottom = (0.2467F + offset) * fontHeight;
            }
            else
            {
                _top    = (-(0.2467F + offset)) * fontHeight;
                _bottom = 0;
            }

            if (!_usedFlagIDs.Contains((FlagID)_flagID))
            {
                _usedFlagIDs.Add((FlagID)_flagID);
            }
        }
Exemplo n.º 31
0
 private void GetRelativePositions(VerticalDir voiceStemDirection, LyricMetrics lyricMetrics,
     out bool ornamentIsBelow, out bool dynamicIsBelow)
 {
     dynamicIsBelow = true;
     ornamentIsBelow = false;
     switch(voiceStemDirection)
     {
         case VerticalDir.none:
             // a 1-Voice staff
             if(lyricMetrics != null && lyricMetrics.IsBelow)
                 dynamicIsBelow = false;
             break;
         case VerticalDir.up:
             // top voice of a 2-Voice staff
             dynamicIsBelow = false;
             ornamentIsBelow = false;
             break;
         case VerticalDir.down:
             // bottom voice of a 2-Voice staff
             dynamicIsBelow = true;
             ornamentIsBelow = true;
             break;
     }
 }
Exemplo n.º 32
0
 /// <summary>
 /// Shifts a horizontal beam vertically to the correct position (wrt the beamBlock) for its duration class 
 /// </summary>
 /// <param name="outerLeftY"></param>
 /// <param name="gap"></param>
 /// <param name="stemDirection"></param>
 /// <param name="beamThickness"></param>
 /// <param name="nGaps"></param>
 protected void ShiftYsForBeamBlock(float outerLeftY, float gap, VerticalDir stemDirection, float beamThickness, int nGaps)
 {
     float dy = 0F;
     if(stemDirection == VerticalDir.down)
     {
         dy = -(beamThickness + (gap * nGaps));
     }
     else
     {
         dy = gap * nGaps;
     }
     dy += outerLeftY - _leftTopY ;
     MoveYs(dy, dy);
 }
Exemplo n.º 33
0
        /// <summary>
        /// This algorithm follows Gardner Read when the stemDirection is "none" (i.e. not forced):
        /// If there were no beam, and the majority of the stems would go up, then all the stems in the beam go up.
        /// ji: if there are the same number of default up and default down stems, then the direction is decided by
        /// the most extreme notehead in the beam group. If both extremes are the same (e.g. 1 ledgeline up and down)
        /// then the stems are all down.
        /// </summary>
        /// <param name="currentClef"></param>
        /// <param name="chordsBeamedTogether"></param>
        private void SetBeamedGroupStemDirection(ClefSymbol currentClef, List<ChordSymbol> chordsBeamedTogether, VerticalDir voiceStemDirection)
        {
            Debug.Assert(chordsBeamedTogether.Count > 1);
            VerticalDir groupStemDirection = voiceStemDirection;
            if(voiceStemDirection == VerticalDir.none)
            {   // here, there is only one voice in the staff, so the direction depends on the height of the noteheads.
                int upStems = 0;
                int downStems = 0;
                foreach(ChordSymbol chord in chordsBeamedTogether)
                {
                    VerticalDir direction = chord.DefaultStemDirection(currentClef);
                    if(direction == VerticalDir.up)
                        upStems++;
                    else
                        downStems++;
                }

                if(upStems == downStems)
                    groupStemDirection = GetDirectionFromExtremes(currentClef, chordsBeamedTogether);
                else if(upStems > downStems)
                    groupStemDirection = VerticalDir.up;
                else
                    groupStemDirection = VerticalDir.down;
            }
            foreach(ChordSymbol chord in chordsBeamedTogether)
            {
                chord.Stem.Direction = groupStemDirection;
            }
        }
Exemplo n.º 34
0
        /// <summary>
        /// topBoundary is set to topStaffline
        /// bottomBoundary is set to bottomStaffline
        /// then these bounds are widened if the chord lies outside:
        /// If there is no stem,
        ///     topBoundary is set to topNotehead.Top or top of top accidental
        ///     bottomBoundary is set to bottomNotehead.Bottom (but not to bottom of bottom accidental).
        /// else if stem is up, 
        ///     topBoundardy is set to stemTopTipY, 
        ///     bottomBoundary is set to bottomNotehead.Bottom (but not to bottom of bottom accidental).
        /// else if stem is down, 
        ///     topBoundary is set to topNotehead.Top or top of top accidental, 
        ///     bottomBoundary is set to stemBottomTipY or bottomNoteheadBottom or bottom of bottom accidental. 
        /// </summary>
        private void GetTopAndBottomBounds(VerticalDir stemDirection, out float topBoundary, out float bottomBoundary)
        {
            float topStaffline = _clef.Voice.Staff.Metrics.StafflinesTop;

            topBoundary = topStaffline; // top of staff
            bottomBoundary = topStaffline + (_gap * 4F); // bottom of staff
            if(_stemMetrics == null)
            {
                float topOfTopHead = _headsMetricsTopDown[0].Top;
                topBoundary = (topBoundary < topOfTopHead) ? topBoundary : topOfTopHead;

                float bottomOfBottomHead = _headsMetricsTopDown[_headsMetricsTopDown.Count - 1].Bottom;
                bottomBoundary = (bottomBoundary > bottomOfBottomHead) ? bottomBoundary : bottomOfBottomHead;

                if(_topDownAccidentalsMetrics != null)
                {
                    Debug.Assert(_topDownAccidentalsMetrics.Count > 0);
                    float topOfTopAccidental = _topDownAccidentalsMetrics[0].Top;
                    topBoundary = (topBoundary < topOfTopAccidental) ? topBoundary : topOfTopAccidental;
                    //float bottomOfBottomAccidental = _topDownAccidentalsMetrics[_topDownAccidentalsMetrics.Count - 1].Bottom;
                    //bottomBoundary = (bottomBoundary > bottomOfBottomAccidental) ? bottomBoundary : bottomOfBottomAccidental;
                }
            }
            else if(_stemMetrics.VerticalDir == VerticalDir.up)
            {
                topBoundary = (topBoundary < _stemMetrics.Top) ? topBoundary : _stemMetrics.Top;

                float bottomOfBottomHead = _headsMetricsTopDown[_headsMetricsTopDown.Count - 1].Bottom;
                bottomBoundary = (bottomBoundary > bottomOfBottomHead) ? bottomBoundary : bottomOfBottomHead;
                //if(_topDownAccidentalsMetrics != null)
                //{
                //    Debug.Assert(_topDownAccidentalsMetrics.Count > 0);
                //    float bottomOfBottomAccidental = _topDownAccidentalsMetrics[_topDownAccidentalsMetrics.Count - 1].Bottom;
                //    bottomBoundary = (bottomBoundary > bottomOfBottomAccidental) ? bottomBoundary : bottomOfBottomAccidental;
                //}
            }
            else
            {
                float topOfTopHead = _headsMetricsTopDown[0].Top;
                topBoundary = (topBoundary < topOfTopHead) ? topBoundary : topOfTopHead;
                if(_topDownAccidentalsMetrics != null)
                {
                    Debug.Assert(_topDownAccidentalsMetrics.Count > 0);
                    float topOfTopAccidental = _topDownAccidentalsMetrics[0].Top;
                    topBoundary = (topBoundary < topOfTopAccidental) ? topBoundary : topOfTopAccidental;
                }

                bottomBoundary = (bottomBoundary > _stemMetrics.Bottom) ? bottomBoundary : _stemMetrics.Bottom;
            }
        }
Exemplo n.º 35
0
 public abstract Metrics NoteObjectMetrics(Graphics graphics, NoteObject noteObject, VerticalDir voiceStemDirection, float gap, float storkeWidth);
Exemplo n.º 36
0
 /// <summary>
 /// Called when the ChordMetrics is first constructed.
 /// It does not yet have any beams.
 /// </summary>
 private void MoveAuxilliaries(VerticalDir stemDirection, float gap)
 {
     MoveAuxilliaries(stemDirection, gap, 0F, 0F);
 }
Exemplo n.º 37
0
 public override void ShiftYsForBeamBlock(float outerLeftY, float gap, VerticalDir stemDirection, float beamThickness)
 {
     ShiftYsForBeamBlock(outerLeftY, gap, stemDirection, beamThickness, 2);
 }
Exemplo n.º 38
0
        /// <summary>
        /// The upper beam padding and lower beam padding is used exclusively for auxilliaries placed next to beams.
        /// These values do not affect the positions of auxilliaries on ordinary flags.
        /// </summary
        private void MoveAuxilliaries(VerticalDir stemDirection, float gap, float upperBeamPadding, float lowerBeamPadding)
        {
            float topBoundary;
            float bottomBoundary;
            GetTopAndBottomBounds(stemDirection, out topBoundary, out bottomBoundary);

            topBoundary -= upperBeamPadding;
            bottomBoundary += lowerBeamPadding;

            // These are moved to a position relative to the outer stem tip or notehead.
            if(_ornamentMetrics != null)
                MoveOrnamentMetrics(gap, ref topBoundary, ref bottomBoundary);
            if(_lyricMetrics != null)
                MoveLyricMetrics(gap, ref topBoundary, ref bottomBoundary);
            if(_dynamicMetrics != null)
                MoveDynamicMetrics(gap, ref topBoundary, ref bottomBoundary);
        }
Exemplo n.º 39
0
 public abstract void ShiftYsForBeamBlock(double outerLeftY, double gap, VerticalDir stemDirection, double beamThickness);
Exemplo n.º 40
0
        /// <summary>
        /// returns null if there is no lyric in the _drawObjects
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="gap"></param>
        /// <param name="lyricIsBelow"></param>
        /// <returns></returns>
        private LyricMetrics NewLyricMetrics(VerticalDir voiceStemDirection, Graphics graphics, float gap)
        {
            LyricText lyric = null;
            foreach(DrawObject drawObject in _drawObjects)
            {
                lyric = drawObject as LyricText;
                if(lyric != null)
                    break;
            }
            _lyricMetrics = null;

            if(lyric != null)
            {
                bool lyricIsBelow = true; // voiceStemDirection == VerticalDir.none || voiceStemDirection == VerticalDir.down
                if(voiceStemDirection == VerticalDir.up)
                    lyricIsBelow = false;
                lyric.Metrics = new LyricMetrics(gap, graphics, lyric.TextInfo, lyricIsBelow);
                _lyricMetrics = (LyricMetrics)lyric.Metrics;
            }

            return _lyricMetrics;
        }
Exemplo n.º 41
0
 public override void ShiftYsForBeamBlock(double outerLeftY, double gap, VerticalDir stemDirection, double beamThickness)
 {
     ShiftYsForBeamBlock(outerLeftY, gap, stemDirection, beamThickness, 0);
 }
Exemplo n.º 42
0
        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;
        }