示例#1
0
        private void MoveStemTips()
        {
            float      staffOriginY = Chords[0].Voice.Staff.Metrics.OriginY;
            QuaverBeam quaverBeam   = null;

            foreach (Beam beam in Beams)
            {
                quaverBeam = beam as QuaverBeam;
                if (quaverBeam != null)
                {
                    break;
                }
            }
            Debug.Assert(quaverBeam != null);
            float tanAlpha = (quaverBeam.RightTopY - quaverBeam.LeftTopY) / (quaverBeam.RightX - quaverBeam.LeftX);

            foreach (ChordSymbol chord in Chords)
            {
                ChordMetrics chordMetrics = ((ChordMetrics)chord.Metrics);
                StemMetrics  stemMetrics  = chordMetrics.StemMetrics; // a clone

                Debug.Assert(chord.Stem.Direction == _stemDirection); // just to be sure.

                float stemTipDeltaY = ((stemMetrics.OriginX - this._left) * tanAlpha);
                float stemTipY      = quaverBeam.LeftTopY + stemTipDeltaY;
                chordMetrics.MoveOuterStemTip(stemTipY, _stemDirection); // dont just move the clone! Moves the auxilliaries too.
            }
        }
示例#2
0
文件: Staff.cs 项目: suvjunmd/Moritz
        /// <summary>
        /// This function moves the lowerChord to the left or right in order to avoid collisions with
        /// the noteheads of the upper chord.
        /// The positions of noteheads and ledgerlines relative to their own stem is never changed.
        /// The positions of accidentals are adjusted in both chords after the lower chord has moved.
        /// Stem lengths, and the positions of flags and beamBlocks, are adjusted later in FinalizeBeamBlocks().
        ///
        /// The stems are currently at the standard x-positions for stems up and down at the same MsPosition.
        /// Their lengths have been changed if necessary, for crossing parts. So collisions can be checked
        /// reliably in this function.
        /// There are 7 possible horizontal positions for the stem of the lower chord:
        ///     1. the standard position (aligned as when the lower chord is well below the upper chord)
        ///     2. hairline left of upper noteheads
        ///     3. aligned with upper stem
        ///          (top notehead of the bottom chord is half a space below the bottom notehead of the upper chord)
        ///     4. thin hairline right of upper stem
        ///          (top notehead of the bottom chord is at the same height as the bottom notehead of the upper chord)
        ///     5. thick hairline right of upper stem
        ///          (top notehead of the bottom chord is above the bottom notehead of the upper chord)
        ///     If both upper and lower chords have sideways shifted noteheads, and there are no notehead collisions:
        ///         6. thick hairline right of right-side note head on upper stem
        ///     else
        ///         7. a head width left of its original position
        /// The position selected, is the first of these which can be applied without causing any collisions.
        /// The principle is that the total width of all the noteheads should be minimized.
        /// Accidentals are rearranged (top to bottom, to the left of the combined chord) once the
        /// noteheads and ledgerlines have been given their final positions.
        /// </summary>
        private void AdjustLowerChordXPosition(ChordSymbol upperChord, ChordSymbol lowerChord)
        {
            Debug.Assert(upperChord.MsPosition == lowerChord.MsPosition);
            if (!(upperChord is CautionaryChordSymbol))
            {
                Debug.Assert(upperChord.Stem.Direction == VerticalDir.up);
            }
            if (!(lowerChord is CautionaryChordSymbol))
            {
                Debug.Assert(lowerChord.Stem.Direction == VerticalDir.down);
            }

            List <HeadMetrics> upperChordHeadMetrics = upperChord.ChordMetrics.HeadsMetrics; // a clone
            List <HeadMetrics> lowerChordHeadMetrics = lowerChord.ChordMetrics.HeadsMetrics; // a clone
            StemMetrics        lowerChordStemMetrics = lowerChord.ChordMetrics.StemMetrics;  // a clone

            float deltaX = LowerChordDeltaX(upperChordHeadMetrics, lowerChordHeadMetrics, lowerChordStemMetrics);

            if (deltaX != 0)
            {
                lowerChord.ChordMetrics.Move(deltaX, 0F); // move the whole chord, including accidentals
            }
            // adjust the positions of accidentals in both chords
            lowerChord.AdjustAccidentalsX(upperChord);
        }
示例#3
0
        /// <summary>
        /// Notehead metrics.Left and metrics.Right include horizontal padding,
        /// so head overlaps cannot be checked using the standard Metrics.Overlaps function.
        /// </summary>
        public bool OverlapsStem(StemMetrics stemMetrics)
        {
            // See the above constructor. Sorry, I didnt want to save the value in every Head!
            float thisHorizontalPadding = this._fontHeight * 0.04F;
            float thisRealLeft          = _left + thisHorizontalPadding;
            float thisRealRight         = _right - thisHorizontalPadding;

            bool verticalOverlap   = this.Bottom >= stemMetrics.Top && this.Top <= stemMetrics.Bottom;
            bool horizontalOverlap = thisRealRight >= stemMetrics.Left && thisRealLeft <= stemMetrics.Right;

            return(verticalOverlap && horizontalOverlap);
        }
示例#4
0
文件: Staff.cs 项目: suvjunmd/Moritz
        private bool NoHeadStemCollisions(float deltaX, List <HeadMetrics> upperHMList, StemMetrics lowerStemMetrics)
        {
            // N.B. Notehead metrics.Left and metrics.Right include horizontal padding,
            // so this function does not use the standard Metrics.Overlaps functions.
            bool noHeadStemCollisions = true;

            if (lowerStemMetrics != null)
            {
                lowerStemMetrics.Move(deltaX, 0F);
                foreach (HeadMetrics upperHM in upperHMList)
                {
                    if (upperHM.OverlapsStem(lowerStemMetrics))
                    {
                        noHeadStemCollisions = false;
                        break;
                    }
                }
                lowerStemMetrics.Move(-deltaX, 0F); // its a clone of the real stemMetrics, but move it back anyway.
            }
            return(noHeadStemCollisions);
        }
示例#5
0
文件: Staff.cs 项目: suvjunmd/Moritz
        /// <summary>
        /// Returns the amount by which to move the lower of two synchronous
        /// chords to avoid notehead and stem collisions between them.
        /// </summary>
        private float LowerChordDeltaX(List <HeadMetrics> upperHM, List <HeadMetrics> lowerHM, StemMetrics lowerChordStemMetrics)
        {
            float deltaX               = 0F;
            float iota                 = 0.001F; // tolerance for float comparisons
            float stemThickness        = SVGSystem.Score.PageFormat.StafflineStemStrokeWidth;
            float upperHeadRightStemX  = upperHM[upperHM.Count - 1].RightStemX;
            float lowerHeadLeftStemX   = lowerHM[0].LeftStemX;
            float verticalChordOverlap = upperHM[upperHM.Count - 1].Top - lowerHM[0].Top + Gap;

            // position 1: if there is no vertical overlap between the chords, deltaX is 0
            if (verticalChordOverlap > 0F)
            {
                // position 2: hairline left of upper noteheads
                float testDeltaX = -(stemThickness * 2F);
                if (NoNoteheadCollisions(testDeltaX + iota, upperHM, lowerHM))
                {
                    deltaX = testDeltaX;
                }

                if (deltaX == 0F)
                {   // (nearly) aligned with upper stem
                    testDeltaX = upperHeadRightStemX - lowerHeadLeftStemX;
                    if ((upperHM[upperHM.Count - 1].Bottom > lowerHM[0].Top && upperHM[upperHM.Count - 1].Top < lowerHM[0].Top) &&
                        NoNoteheadCollisions(testDeltaX + iota, upperHM, lowerHM))
                    {
                        // position 3: The lowest note of the upper chord is a half space above the
                        // highest notehead in the lower chord, so the stems should align exactly.
                        deltaX = testDeltaX - stemThickness; // Strange, but effective!
                    }
                    if (deltaX == 0)
                    {
                        if (lowerHM[0].OriginY > ((upperHM[upperHM.Count - 1].Top + upperHM[upperHM.Count - 1].OriginY) / 2) &&
                            NoNoteheadCollisions(testDeltaX + iota, upperHM, lowerHM))
                        {
                            // position 4: The lowest note of the upper chord is at the same height as
                            // highest notehead in the lower chord, so the stems should be slightly separated.
                            deltaX = testDeltaX + (stemThickness * 0.6F); // Strange, but effective!
                        }
                    }
                    if (deltaX == 0F)
                    {
                        testDeltaX += (stemThickness * 1.8F);
                        if (NoNoteheadCollisions(testDeltaX + iota, upperHM, lowerHM))
                        {
                            // position 5: The lowest note of the upper chord is below the highest notehead
                            // in the lower chord, so the stems should be separated slightly more.
                            if (NoHeadStemCollisions(testDeltaX + iota, upperHM, lowerChordStemMetrics)) // stem metrics can be null...
                            {
                                deltaX = testDeltaX;
                            }
                        }
                    }
                }

                if (deltaX == 0F && HasSidewaysShiftedNotehead(upperHM) && HasSidewaysShiftedNotehead(lowerHM))
                {
                    // position 6: align the lower stem a hairline right of a right-shifted notehead on the upper chord
                    testDeltaX = ((upperHeadRightStemX - lowerHeadLeftStemX) * 2) + (stemThickness * 1.8F);
                    if (NoNoteheadCollisions(testDeltaX + iota, upperHM, lowerHM))
                    {
                        deltaX = testDeltaX;
                    }
                }

                if (deltaX == 0F)
                {
                    // position 7: align lower stem a head width left of its original position
                    deltaX = lowerHeadLeftStemX - lowerHM[0].RightStemX;
                }
            }

            return(deltaX);
        }
示例#6
0
        private void SetStemAndFlags(ChordSymbol chord, List<HeadMetrics> topDownHeadsMetrics, float stemThickness)
        {
            DurationClass durationClass = chord.DurationClass;
            _flagsBlockMetrics = null;
            if(chord.BeamBlock == null
            && (durationClass == DurationClass.quaver
                || durationClass == DurationClass.semiquaver
                || durationClass == DurationClass.threeFlags
                || durationClass == DurationClass.fourFlags
                || durationClass == DurationClass.fiveFlags))
            {
                _flagsBlockMetrics = GetFlagsBlockMetrics(topDownHeadsMetrics,
                                                                durationClass,
                                                                chord.FontHeight,
                                                                chord.Stem.Direction,
                                                                stemThickness);
            }

            if(durationClass == DurationClass.minim
            || durationClass == DurationClass.crotchet
            || durationClass == DurationClass.quaver
            || durationClass == DurationClass.semiquaver
            || durationClass == DurationClass.threeFlags
            || durationClass == DurationClass.fourFlags
            || durationClass == DurationClass.fiveFlags)
            {
                _stemMetrics = NewStemMetrics(topDownHeadsMetrics, chord, _flagsBlockMetrics, stemThickness);
            }
        }
示例#7
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;
        }
示例#8
0
        /// <summary>
        /// The accidental is at the correct height (accidental.OriginY == head.OriginY), 
        /// but it has not yet been added to this.MetricsList, or used to set this chord's Boundary.
        /// The accidental is now moved left, such that it does not overlap noteheads, stem, ledgerlines or accidentals.
        /// It is added to this.MetricsList after this function returns.
        /// </summary>
        private void MoveAccidentalLeft(AccidentalMetrics accidentalMetrics, List<HeadMetrics> topDownHeadsMetrics,
            StemMetrics stemMetrics,
            LedgerlineBlockMetrics upperLedgerlineBlockMetrics, LedgerlineBlockMetrics lowerLedgerlineBlockMetrics,
            List<AccidentalMetrics> existingAccidentalsMetrics)
        {
            #region move left of ledgerline block
            if(upperLedgerlineBlockMetrics != null)
            {
                MoveAccidentalLeftOfLedgerlineBlock(accidentalMetrics, upperLedgerlineBlockMetrics);
            }
            if(lowerLedgerlineBlockMetrics != null)
            {
                MoveAccidentalLeftOfLedgerlineBlock(accidentalMetrics, lowerLedgerlineBlockMetrics);
            }
            #endregion
            #region move left of noteheads
            float topRange = accidentalMetrics.OriginY - (_gap * 1.51F);
            float bottomRange = accidentalMetrics.OriginY + (_gap * 1.51F);
            foreach(HeadMetrics head in topDownHeadsMetrics)
            {
                if(head.OriginY > topRange && head.OriginY < bottomRange && head.Overlaps(accidentalMetrics))
                {
                    float extraHorizontalSpace = 0;
                    if(accidentalMetrics.ID_Type == "b")
                        extraHorizontalSpace = accidentalMetrics.FontHeight * -0.03F;

                    accidentalMetrics.Move(head.Left - extraHorizontalSpace - accidentalMetrics.Right, 0);
                }
            }
            #endregion
            #region move left of stem (can be in another chord)
            if(stemMetrics != null)
            {
                // Note that the length of the stem is ignored here.
                float maxRight = stemMetrics.Left - stemMetrics.StrokeWidth;
                if(maxRight < accidentalMetrics.Right)
                    accidentalMetrics.Move(maxRight - accidentalMetrics.Right, 0F);
            }
            #endregion
            #region move accidental left of existing accidentals
            MoveLeftOfExistingAccidentals(existingAccidentalsMetrics, 0, accidentalMetrics);
            #endregion
        }
示例#9
0
文件: Metrics.cs 项目: notator/Moritz
        /// <summary>
        /// Notehead metrics.Left and metrics.Right include horizontal padding,
        /// so head overlaps cannot be checked using the standard Metrics.Overlaps function.
        /// </summary>
        public bool OverlapsStem(StemMetrics stemMetrics)
        {
            // See the above constructor. Sorry, I didnt want to save the value in every Head!
            float thisHorizontalPadding = this._fontHeight * 0.04F;
            float thisRealLeft = _left + thisHorizontalPadding;
            float thisRealRight = _right - thisHorizontalPadding;

            bool verticalOverlap = this.Bottom >= stemMetrics.Top && this.Top <= stemMetrics.Bottom;
            bool horizontalOverlap = thisRealRight >= stemMetrics.Left && thisRealLeft <= stemMetrics.Right;

            return verticalOverlap && horizontalOverlap;
        }