Стрелка на кривой Безье

1,00
р.
Подскажите, как можно нарисовать в конце кривой Безье стрелку? Есть множество примеров как это сделать для прямой линии (1 , 2 , 3), но именно для кривой у меня не получается это сделать.
Есть такой код, но отрабатывает он как на гифке.

xaml:

code-behind:
public PolyLineSegment DrawArrow(Point a, Point b) { double HeadWidth = 10 // Ширина между ребрами стрелки double HeadHeight = 5 // Длина ребер стрелки
double X1 = a.X double Y1 = a.Y
double X2 = b.X double Y2 = b.Y
double theta = Math.Atan2(Y1 - Y2, X1 - X2) double sint = Math.Sin(theta) double cost = Math.Cos(theta)
Point pt3 = new Point( X2 + (HeadWidth * cost - HeadHeight * sint), Y2 + (HeadWidth * sint + HeadHeight * cost))
Point pt4 = new Point( X2 + (HeadWidth * cost + HeadHeight * sint), Y2 - (HeadHeight * cost - HeadWidth * sint))
PolyLineSegment arrow = new PolyLineSegment() arrow.Points.Add(b) arrow.Points.Add(pt3) arrow.Points.Add(pt4) arrow.Points.Add(b)
return arrow }
private void DrawLine(MouseEventArgs e) { Point endPoint = e.GetPosition(this)
PathFigure pathFigure = new PathFigure { StartPoint = new Point(800, 500), IsClosed = false }
//Кривая Безье Vector vector = endPoint - pathFigure.StartPoint Point point1 = new Point(pathFigure.StartPoint.X + vector.X / 2, pathFigure.StartPoint.Y) Point point2 = new Point(pathFigure.StartPoint.X + vector.X / 1.5, pathFigure.StartPoint.Y + vector.Y/ 0.95) BezierSegment curve = new BezierSegment(point1, point2, endPoint, true)
PolyLineSegment arrow = DrawArrow(pathFigure.StartPoint, endPoint) PathGeometry path = new PathGeometry() path.Figures.Add(pathFigure) pathFigure.Segments.Add(curve) pathFigure.Segments.Add(arrow) pathMain.Data = path }
Если DrawArrow(point2, endPoint) вместо DrawArrow(pathFigure.StartPoint, endPoint) , то отрабатывает так:

Ответ
Я дорисовал опорные точки к вашей кривой (красная ломаная на анимации):

Дело в том, что стрелка показывает правильно: направление последнего сегмента опорной линии. Стрелка и правда показывает направление касательной в крайней точке. Но ваше вычисление промежуточных точек делает слишком большой излом, поэтому видимое направление кривой слишком отличается от направления касательной.
Попробуйте поменять алгоритм выбора промежуточных точек, проблема, думаю, в нём. (Не могу предложить свой алгоритм, потому что не знаю, какая ваша задача.)

По поводу алгоритма, вот такой код ведёт себя намного лучше:
var startPoint = pathFigure.StartPoint //Кривая Безье Vector vector = endPoint - startPoint Point point1 = new Point(startPoint.X + 3 * vector.X / 8, startPoint.Y + 1 * vector.Y / 8) Point point2 = new Point(startPoint.X + 5 * vector.X / 8, startPoint.Y + 7 * vector.Y / 8)


Вот на всякий случай полный пример:
MainWindow.xaml:

MainWindow.xaml.cs:
public partial class MainWindow : Window { public MainWindow() { InitializeComponent() }
public PolyLineSegment DrawArrow(Point a, Point b) { double HeadWidth = 10 // Ширина между ребрами стрелки double HeadHeight = 5 // Длина ребер стрелки
double X1 = a.X double Y1 = a.Y
double X2 = b.X double Y2 = b.Y
double theta = Math.Atan2(Y1 - Y2, X1 - X2) double sint = Math.Sin(theta) double cost = Math.Cos(theta)
Point pt3 = new Point( X2 + (HeadWidth * cost - HeadHeight * sint), Y2 + (HeadWidth * sint + HeadHeight * cost))
Point pt4 = new Point( X2 + (HeadWidth * cost + HeadHeight * sint), Y2 - (HeadHeight * cost - HeadWidth * sint))
PolyLineSegment arrow = new PolyLineSegment() arrow.Points.Add(b) arrow.Points.Add(pt3) arrow.Points.Add(pt4) arrow.Points.Add(b)
return arrow }
private void DrawLine(MouseEventArgs e, UIElement host) { PathFigure pathFigure = ((PathGeometry)pathMain.Data).Figures[0] Point startPoint = pathFigure.StartPoint Point endPoint = e.GetPosition(host)
//Кривая Безье Vector vector = endPoint - startPoint Point point1 = new Point(startPoint.X + 3 * vector.X / 8, startPoint.Y + 1 * vector.Y / 8) Point point2 = new Point(startPoint.X + 5 * vector.X / 8, startPoint.Y + 7 * vector.Y / 8)
BezierSegment curve = new BezierSegment(point1, point2, endPoint, true) PolyLineSegment arrow = DrawArrow(point2, endPoint)
pathFigure.Segments.Clear() pathFigure.Segments.Add(curve) pathFigure.Segments.Add(arrow) } private UIElement currentHost private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { var host = (UIElement)sender currentHost = host Mouse.Capture(host) Point startPoint = e.GetPosition(host) PathFigure pathFigure = new PathFigure { StartPoint = startPoint, IsClosed = false }
pathMain.Data = new PathGeometry() { Figures = { pathFigure } } DrawLine(e, currentHost) }
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e) { Mouse.Capture(null) DrawLine(e, currentHost) currentHost = null }
private void OnMouseMove(object sender, MouseEventArgs e) { if (currentHost != null) DrawLine(e, currentHost) } }