Drawing Beziers In Direct2D

How can I draw a bezier curve in Direct2D that accepts N points as control points? As far as I understand, only bezier curves that pass through 4 points can be drawn. If I'm wrong, please correct it. What I want to do is draw a Bezier curve that takes an arbitrary number of points as control points. Is this possible or not? I'm new to Direct2D. I am working in C# but, it would be nice if you can give an example in C# or C++.

This is what I am currently trying. I can't get a smooth curve after the drawing is finished.

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

This is a screenshot of the demo.

enter image description here

Upvotes: 0

Views: 712

Answers (1)

J Brad
J Brad

Reputation: 11

You need to constrain the tangents at the left and right side of each Bezier segments endpoints to be equal to their neighbors. This means you can't just pick arbitrary control points (p1,p2) for each segment.

If you just want to create the set of Bezier polynomials to create a smooth curve without specifying the control points, take a look at https://www.codeproject.com/Articles/31859/Draw-a-Smooth-Curve-through-a-Set-of-2D-Points-wit . This shows how to compute (p1,p2) for each segment from from the neighboring points.

Upvotes: 1

Related Questions