RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 593607
Accepted
trydex
trydex
Asked:2020-11-21 04:26:20 +0000 UTC2020-11-21 04:26:20 +0000 UTC 2020-11-21 04:26:20 +0000 UTC

贝塞尔曲线上的箭头

  • 772

告诉我,如何在贝塞尔曲线的末端画一个箭头?有很多关于如何对直线(1、2、3)执行此操作的示例,但是对于我无法执行的曲线。

有这样的代码,但它像在 gif 上一样工作。

在此处输入图像描述

XML:

<Canvas>
  <Path x:Name="pathMain" Stroke="Blue" StrokeThickness="2"/>
</Canvas>

代码隐藏:

    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);,那么它的工作原理如下: 在此处输入图像描述

c#
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    VladD
    2020-11-23T05:45:59Z2020-11-23T05:45:59Z

    我在你的曲线上添加了锚点(动画中的红色多段线):

    动画

    事实是箭头正确显示:参考线最后一段的方向。箭头确实显示了极值点处的切线方向。但是你对中间点的计算产生了太多的扭结,所以曲线的表观方向与切线的方向相差太大。

    尝试更改选择中间点的算法,我认为问题出在其中。(我不能提供我自己的算法,因为我不知道你的问题是什么。)


    关于算法,这段代码表现得更好:

    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);
    

    另一个


    为了以防万一,这里有一个完整的例子:

    主窗口.xaml:

    <Canvas Background="Transparent"
            MouseLeftButtonDown="OnMouseLeftButtonDown"
            MouseLeftButtonUp="OnMouseLeftButtonUp"
            MouseMove="OnMouseMove">
        <Path x:Name="pathMain" Stroke="Blue" StrokeThickness="2"/>
    </Canvas>
    

    主窗口.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);
        }
    }
    
    • 23

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何停止编写糟糕的代码?

    • 3 个回答
  • Marko Smith

    onCreateView 方法重构

    • 1 个回答
  • Marko Smith

    通用还是非通用

    • 2 个回答
  • Marko Smith

    如何访问 jQuery 中的列

    • 1 个回答
  • Marko Smith

    *.tga 文件的组重命名(3620 个)

    • 1 个回答
  • Marko Smith

    内存分配列表C#

    • 1 个回答
  • Marko Smith

    常规赛适度贪婪

    • 1 个回答
  • Marko Smith

    如何制作自己的自动完成/自动更正?

    • 1 个回答
  • Marko Smith

    选择斐波那契数列

    • 2 个回答
  • Marko Smith

    所有 API 版本中的通用权限代码

    • 2 个回答
  • Martin Hope
    jfs *(星号)和 ** 双星号在 Python 中是什么意思? 2020-11-23 05:07:40 +0000 UTC
  • Martin Hope
    hwak 哪个孩子调用了父母的静态方法?还是不可能完成的任务? 2020-11-18 16:30:55 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    Arch ArrayList 与 LinkedList 的区别? 2020-09-20 02:42:49 +0000 UTC
  • Martin Hope
    iluxa1810 哪个更正确使用:if () 或 try-catch? 2020-08-23 18:56:13 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5