/// <summary>
        /// Calculates slur height trying to avoid collisions with stems
        /// </summary>
        /// <param name="note"></param>
        /// <param name="endPoint"></param>
        /// <returns></returns>
        private double DetermineSlurHeight(Note note, Slur slur, SlurInfo slurStartInfo, Point endPoint)
        {
            var notesUnderSlur = note.Staff.EnumerateUntilConditionMet <Note>(note, n => n.Slurs.FirstOrDefault(s => s.Number == slur.Number)?.Type == NoteSlurType.Start, true).ToArray();

            if (notesUnderSlur.Length < 3)
            {
                return(10);
            }

            var notesUnderSlurExclusive = notesUnderSlur.Take(notesUnderSlur.Length - 1).Skip(1);
            var mostExtremePoint        = GetMostExtremePoint(notesUnderSlurExclusive, slurStartInfo.StartPlacement);

            var angle = UsefulMath.BeamAngle(slurStartInfo.StartPoint.X, slurStartInfo.StartPoint.Y, endPoint.X, endPoint.Y);
            var slurYPositionInMostExtremePoint = slurStartInfo.StartPoint.TranslateHorizontallyAndMaintainAngle(angle, mostExtremePoint.X - slurStartInfo.StartPoint.X).Y;
            var mostExtremeYPosition            = mostExtremePoint.Y;

            if (slurStartInfo.StartPlacement == VerticalPlacement.Above && mostExtremeYPosition < slurYPositionInMostExtremePoint)
            {
                return(Math.Abs(mostExtremeYPosition - slurYPositionInMostExtremePoint) + 10);
            }
            if (slurStartInfo.StartPlacement == VerticalPlacement.Below && mostExtremeYPosition > slurYPositionInMostExtremePoint)
            {
                return(Math.Abs(slurYPositionInMostExtremePoint - mostExtremeYPosition) + 10);
            }

            return(10);
        }
Exemple #2
0
 /// <summary>
 /// Draws of performs additional logic at slur end
 /// </summary>
 /// <param name="renderer">Score renderer</param>
 /// <param name="slur">Slur</param>
 /// <param name="element">Element with a slur</param>
 /// <param name="notePositionY">Y position of element with a slur</param>
 /// <param name="slurStartInfo">Information about slur start point</param>
 /// <param name="slurPlacement">Information about slur placement</param>
 protected abstract void ProcessSlurEnd(ScoreRendererBase renderer, Slur slur, Note element, double notePositionY, SlurInfo slurStartInfo, VerticalPlacement slurPlacement);
 /// <summary>
 /// Draws or performs additional logic at slur start
 /// </summary>
 /// <param name="renderer">Score renderer</param>
 /// <param name="slur">Slur</param>
 /// <param name="element">Element with a slur</param>
 /// <param name="notePositionY"></param>
 /// <param name="slurStartInfo">Information about slur start point</param>
 /// <param name="slurPlacement">Information about slur placement</param>
 protected override void ProcessSlurStart(ScoreRendererBase renderer, Slur slur, Note element, double notePositionY, SlurInfo slurStartInfo, VerticalPlacement slurPlacement)
 {
     slurStartInfo.StartPoint = RelativeToAbsolute(renderer, renderer.TenthsToPixels(slur.BezierControlPoint), notePositionY);
     slurStartInfo.BezierStartControlPoint = RelativeToAbsolute(renderer, renderer.TenthsToPixels(slur.BezierStartOrEndPoint), notePositionY);
 }
        /// <summary>
        /// Draws of performs additional logic at slur end
        /// </summary>
        /// <param name="renderer">Score renderer</param>
        /// <param name="slur">Slur</param>
        /// <param name="element">Element with a slur</param>
        /// <param name="notePositionY">Y position of element with a slur</param>
        /// <param name="slurStartInfo">Information about slur start point</param>
        /// <param name="slurPlacement">Information about slur placement</param>
        protected override void ProcessSlurEnd(ScoreRendererBase renderer, Slur slur, Note element, double notePositionY, SlurInfo slurStartInfo, VerticalPlacement slurPlacement)
        {
            Point endPoint;
            var   noteheadWidth = element.GetNoteheadWidthPx(renderer);

            if (slurStartInfo.StartPlacement == VerticalPlacement.Above)
            {
                var  xShiftConcerningStemDirectionEnd = noteheadWidth / 2;
                bool hasFlagOrBeam = element.BaseDuration.Denominator > 4;
                endPoint = new Point(scoreService.CursorPositionX + xShiftConcerningStemDirectionEnd,
                                     (element.StemDirection == VerticalDirection.Up ? element.StemEndLocation.Y + (hasFlagOrBeam ? -2 : 0) : notePositionY - 7));
            }
            else if (slurStartInfo.StartPlacement == VerticalPlacement.Below)
            {
                var xShiftConcerningStemDirectionEnd = noteheadWidth / 2;
                endPoint = new Point(scoreService.CursorPositionX + xShiftConcerningStemDirectionEnd, notePositionY + 5);
            }
            else
            {
                throw new Exception("Unsupported placement type.");
            }

            var slurHeight = DetermineSlurHeight(element, slur, slurStartInfo, endPoint);

            for (int i = 0; i < 3; i++) //Draw a few curves one by one to simulate a curve with variable thickness. It will be replaced by a path in future releases.
            {
                var controlPoints = GetBezierControlPoints(slurStartInfo.StartPoint, endPoint, slurStartInfo.StartPlacement, slurHeight + i);
                renderer.DrawBezier(slurStartInfo.StartPoint, controlPoints.Item1, controlPoints.Item2, endPoint, element);
            }

            //DrawSlurFrame(renderer, startPoint, controlPoints.Item1, controlPoints.Item2, endPoint, element);
        }
        /// <summary>
        /// Draws or performs additional logic at slur start
        /// </summary>
        /// <param name="renderer">Score renderer</param>
        /// <param name="slur">Slur</param>
        /// <param name="element">Element with a slur</param>
        /// <param name="notePositionY"></param>
        /// <param name="slurStartInfo">Information about slur start point</param>
        /// <param name="slurPlacement">Information about slur placement</param>
        protected override void ProcessSlurStart(ScoreRendererBase renderer, Slur slur, Note element, double notePositionY, SlurInfo slurStartInfo, VerticalPlacement slurPlacement)
        {
            slurStartInfo.StartPlacement          = slurPlacement;
            slurStartInfo.StartPointStemDirection = element.StemDirection;
            var polihymniaFix = renderer.LinespacesToPixels(element.GetNoteheadWidthLs(renderer) * 0.5);

            if (slurPlacement == VerticalPlacement.Above)
            {
                bool hasFlagOrBeam = element.BaseDuration.Denominator > 4;  //If note has a flag or beam start the slur above the note. If not, start a bit to the right and down.
                var  xShiftConcerningStemDirectionStart = slurStartInfo.StartPointStemDirection == VerticalDirection.Up ? (hasFlagOrBeam ? 5 : 10) : 1;
                slurStartInfo.StartPoint = new Point(scoreService.CursorPositionX + xShiftConcerningStemDirectionStart + polihymniaFix, element.StemDirection == VerticalDirection.Down ? notePositionY - 7 : element.StemEndLocation.Y + (hasFlagOrBeam ? -3 : 8));
            }
            else
            {
                slurStartInfo.StartPoint = new Point(scoreService.CursorPositionX + 3 + polihymniaFix, notePositionY + 5);
            }
        }