在 Direct2D 中绘制贝塞尔曲线

问题描述 投票:0回答:1

如何在 Direct2D 中绘制接受 N 个点作为控制点的贝塞尔曲线?据我了解,只能绘制经过4个点的贝塞尔曲线。如果我错了,请纠正。我想要做的是绘制一条以任意数量的点作为控制点的贝塞尔曲线。这可能吗?我是 Direct2D 新手。我正在使用 C# 工作,但是如果您能给出一个 C# 或 C++ 示例,那就太好了。

这就是我目前正在尝试的。画完后无法得到平滑的曲线

using System; 
using System.Windows.Forms;
using JeremyAnsel.DirectX.D2D1;

namespace ShakeAlgorithm
{
    public class Form1 : Form
    {
        public Form1()
        {
            SetStyle(ControlStyles.Opaque, true);
            for (int i = 0; i < count; i++)
            {
                points[i] = new D2D1Point2F(0, 0);
            }
        }
        [STAThread]
        static void Main()
        {
            Application.Run(new Form1());
        }
        private D2D1Factory factory;
        private D2D1HwndRenderTarget hwndRenderTarget;
        private D2D1SolidColorBrush d2D1Brush;
        private D2D1PathGeometry d2D1Geometry;
        private D2D1GeometrySink d2D1GeometrySink;
        private const int count = 10;
        private D2D1Point2F[] points = new D2D1Point2F[count];
        protected override void OnHandleCreated(EventArgs e)
        { 
            factory = D2D1Factory.Create(D2D1FactoryType.SingleThreaded);
            D2D1RenderTargetProperties renderTargetProperties = new D2D1RenderTargetProperties();
            renderTargetProperties.RenderTargetType = D2D1RenderTargetType.Hardware;
            renderTargetProperties.Usage = D2D1RenderTargetUsages.None;
            renderTargetProperties.PixelFormat = new D2D1PixelFormat() { AlphaMode = D2D1AlphaMode.Premultiplied, Format = JeremyAnsel.DirectX.Dxgi.DxgiFormat.B8G8R8A8UNorm };

            D2D1HwndRenderTargetProperties hwndRenderTargetProperties = new D2D1HwndRenderTargetProperties();
            hwndRenderTargetProperties.Hwnd = Handle;
            hwndRenderTargetProperties.PixelSize = new D2D1SizeU((uint)ClientSize.Width, (uint)ClientSize.Height);
            hwndRenderTargetProperties.PresentOptions = D2D1PresentOptions.Immediately;

            hwndRenderTarget = factory.CreateHwndRenderTarget(renderTargetProperties, hwndRenderTargetProperties);
            hwndRenderTarget.AntialiasMode = D2D1AntialiasMode.PerPrimitive;
            d2D1Brush = hwndRenderTarget.CreateSolidColorBrush(new D2D1ColorF(D2D1KnownColor.Yellow));

            base.OnHandleCreated(e);
        }

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            Invalidate();
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            hwndRenderTarget.BeginDraw();
            hwndRenderTarget.Clear(new D2D1ColorF(D2D1KnownColor.White));

            if (points != null)
                if (index < count)
                {
                    d2D1Brush.Color = new D2D1ColorF(D2D1KnownColor.Blue);
                    for (int i = 0; i < index - 1; i++)
                    {
                        D2D1Point2F p1 = points[i];
                        D2D1Point2F p2 = points[i + 1];
                        hwndRenderTarget.DrawLine(p1, p2, d2D1Brush);
                    }
                }
                else
                {
                    d2D1Brush.Color = new D2D1ColorF(D2D1KnownColor.Red);
                    d2D1Geometry = factory.CreatePathGeometry();
                    d2D1GeometrySink = d2D1Geometry.Open();

                    for (int i = 0; i < count - 3; i += 3)
                    {
                        D2D1Point2F p1 = points[i];
                        D2D1Point2F p2 = points[i + 1];
                        D2D1Point2F p3 = points[i + 2];
                        D2D1Point2F p4 = points[i + 3];
                        d2D1GeometrySink.BeginFigure(p1, D2D1FigureBegin.Hollow);

                        d2D1GeometrySink.AddBezier(new D2D1BezierSegment(p2, p3, p4));

                        d2D1GeometrySink.EndFigure(D2D1FigureEnd.Open);

                    }
                    d2D1GeometrySink.Close();
                    hwndRenderTarget.DrawGeometry(d2D1Geometry, d2D1Brush, 3f);


                    d2D1GeometrySink.Dispose();
                    d2D1Geometry.Dispose();
                    d2D1Brush.Color = new D2D1ColorF(D2D1KnownColor.Black);
                    for (int i = 0; i < count; i++)
                    {
                        D2D1Point2F p1 = points[i];


                        hwndRenderTarget.FillEllipse(new D2D1Ellipse(p1, 2, 2), d2D1Brush);
                    }
                }
            hwndRenderTarget.EndDraw();
        } 
        private int index = 0;
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (e.Button == MouseButtons.Left)
            {
                if (index < count && points != null)
                {
                    points[index++] = new D2D1Point2F(e.X, e.Y);
                }
                else
                {
                    index = 0;
                    points[index++] = new D2D1Point2F(e.X, e.Y);
                }
            }
            Invalidate();
        }
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            if (IsHandleCreated)
            {
                hwndRenderTarget.Resize(new D2D1SizeU((uint)ClientSize.Width, (uint)ClientSize.Height));
                Invalidate();
            }
        }
    }
}

这是演示的屏幕截图。

enter image description here

c# c++ direct2d
1个回答
0
投票

您需要将每个贝塞尔线段端点左侧和右侧的切线约束为等于它们的邻居。 这意味着您不能为每个段选取任意控制点 (p1,p2)。

如果您只想创建贝塞尔多项式集来创建平滑曲线而不指定控制点,请查看https://www.codeproject.com/Articles/31859/Draw-a-Smooth-Curve-通过二维点集。 这展示了如何从相邻点计算每个段的 (p1,p2)。

© www.soinside.com 2019 - 2024. All rights reserved.