2
votes

I want to split a bezier curve into two. For example, if there is a bezier curve between points (100,100) and (200, 100) with control points (150,150) and (175, 150), the curve should be colored in two different colors (say red and green), one color from (100,100) to (150, 100) say red and another color from (150,100) to (200,100) say green.

This is my code for drawing a bezier spline:

void Form1_Paint(object sender, PaintEventArgs e)
        {
            Point startPoint = new Point(100, 100);
            Point endPoint = new Point(200, 100);
            Point ctPoint1 = new Point(150, 150);
            Point ctPoint2 = new Point(175, 150);
            GraphicsPath gp = new GraphicsPath();
            gp.AddLine(new Point(100, 0), new Point(100, 100));
            gp.AddBezier(startPoint, ctPoint1, ctPoint2, endPoint);
            gp.AddLine(new Point(200, 100), new Point(200, 0));
            gp.AddLine(new Point(100, 0), new Point(200, 0));
            e.Graphics.FillPath(Brushes.Aqua, gp);
}

I want to fill it with two colors like I explained above.

Result

Desired result: Desired Result

How can I achieve this

Edit:

I have checked a few links for splitting bezier curve enter link description here but it tells me about finding the midpoint of the curve which is not my scenario, I'm looking for drawing half bezier curves.

Values known: two points and their control points to draw a bezier curve between the two points

Expected result: Draw one part of the bezier curve from starting point to the midpoint and another part from midpoint to ending point.

2
Your best bet is probably to create a custom brush that draws the first half in color 1 and the second half in color 2.Nico Schertler
I think you didn't read carefully the link. The two half curves are generated by the sets of control points P0P4P7P9 and P9P8P6P3. This is a wonderful property of the Beziers.Yves Daoust
The link is very interesting but I think you are right: Depending on the shape of your bezier the midpoint will not split the shape in the middle. Instead of going through much more complicated math maybe you can use a simple trick: Find the split point on the bezier curve at (150,?), draw a line up to (150,0) and floodfill one half of your shape. FloodFill is not really hard to do - there is a nice non-recursive algorithm in wikipedia..TaW

2 Answers

1
votes

If the "midpoint" of the Bezier curve in your mind is actually the point on the Bezier curve where x=150, then it is still possible to compute it analytically. Since the Bezier curve is of degree 3 only, we can compute the parameter 't' corresponding to the midpoint (for example, using the Cardano formula). Once you have the midpoint parameter, you can use the de Cateljau algorithm to find the control points for the two split curves. Once you have the two split curves as Bezier curve, you can draw the two areas as you desired.

Here is the resulting control points of the split curves:

The first split curve: (100, 100) (120.196418101, 120.196418101), (136.313883161, 132.234930120) and (150.000000000, 136.115536056).

The 2nd split curve: (150.000000000, 136.115536056), (170.196418101, 141.842093918), (185.098209050, 129.803581899) and (200, 100).

BTW, the parameter t at the "midpoint" is approximately 0.403928.

For a cubic Bezier curve with control points P0, P1, P2 and p3, given the split parameter t, the control points for the split curves are computed as follows (using De Casteljau algorithm)

1) compute Q0, Q1 and Q2 as
Q0 = (1-t)*P0 + t*P1
Q1 = (1-t)*P1 + t*P2
Q2 = (1-t)*P2 + t*P3

2) compute R0 and R1 as
R0 = (1-t)*Q0 + t*Q1
R1 = (1-t)*Q1 + t*Q2

3) compute S0 as S0 = (1-t)*R0 + t*R1. This will be the split point on the curve

4) The control points for the first split curve are P0, Q0, R0 and S0 and the control points for the 2nd split curve are S0, R1, Q2 and P3.

-1
votes

I have used Region.Exclude method and GraphicsPath.GetBounds methods

Code:

    //Creating graphics path for drawing bezier spline
    GraphicsPath gp = new GraphicsPath();
    gp.AddLine(new Point(100, 0), new Point(100, 100));
    gp.AddBezier(startPoint, ctPoint1, ctPoint2, endPoint);
    gp.AddLine(new Point(200, 100), new Point(200, 0));
    gp.AddLine(new Point(100, 0), new Point(200, 0));

    //Dividing the path into two regions
    Rectangle bounds=Rectangle.Round(gp.GetBounds());
    Region left = new Region(gp);
    left.Exclude(new Rectangle(bounds.Left, bounds.Top, (int)(bounds.Width / 2), bounds.Height));

    Region right = new Region(gp);
    right.Exclude(new Rectangle((int)(bounds.Left + bounds.Width / 2), bounds.Top, (int)(bounds.Width / 2), bounds.Height));

    //Drawing divided regions
    e.Graphics.FillRegion(Brushes.Black, left);
    e.Graphics.FillRegion(Brushes.Aqua, right);

Explanation:

  1. Construct the path for drawing bezier spline
  2. Create a region for the path
  3. Split the path into two equal regions.
  4. Using e.Graphics.FillRegion method to fill the desired half of the bezier curve