8

I have a function to draw Bezier Curve through three points. I have already 2 points (start and end) - A and B. How do I calculate middle point between those two points as middle point would be always a little higher or lower than linear function of those two points.

Example:

enter image description here

Any formulas, ideas would be great!

Christian Phillips
  • 18,399
  • 8
  • 53
  • 82
morad1n
  • 119
  • 1
  • 7
  • In case someone is using the cubic bezier with 2 control points, I found [this codepen post](https://codepen.io/enxaneta/post/how-to-add-a-point-to-an-svg-path) very helpful for finding the midpoint. – tkit May 16 '19 at 14:32

4 Answers4

7

I think this is what you're looking for:

http://blog.sklambert.com/finding-the-control-points-of-a-bezier-curve/

It goes into detail on calculating the various points on a Bezier curve.

You may also be interested in this more specific example for your application:

http://www.codeproject.com/Articles/223159/Midpoint-Algorithm-Divide-and-Conquer-Method-for-D

If you really want to get into it, then I suggest this Primer:

http://pomax.github.io/bezierinfo/

Bezier curves are a bit more complicated than simple arcs. For an arc, you can just use this formula:

R = H/2 + W^2/8H

...which definitely won't work for a Bezier curve. On a Quadratic Bezier curve, for example, to calculate a point, you must use:

enter image description here

Sources: http://en.wikipedia.org/wiki/B%C3%A9zier_curve, Quadratic Bezier Curve: Calculate Point

Community
  • 1
  • 1
B.K.
  • 9,982
  • 10
  • 73
  • 105
  • Thank for your time. Very interesting info but in my opinion it won't help me calculate point C. I mean i want to create program where i can make connection beetwen two points, not straight but curve (using bezier curve), so i need third point C calculating automatically from A and B. I want this to make space for second connection under that higher connection. All is happening on Canvas so, using Left, Top Property. Sry for english btw. :) – morad1n May 11 '14 at 20:01
  • @morad1n If it's not a simple arc, but rather a Bezier curve, then you'll need to read the information I've provided. You need to calculate the handle points locations. Primer goes into great detail on that. Are you sure that Bezier curve is what you're looking for? – B.K. May 11 '14 at 20:16
5

Below is what I use to get the control point of a quad bezier curve. It should work for your problem where the control point is on the curve. It's in Swift but you should be able to convert it to another language easily. Basically at the midpoint of the line (whose points are point1 and point2) I work out a perpendicular line with the given length. Clockwise parameter determines which side of the line the point should fall on.

func getControlPointWithPoint1(point1:CGPoint, point2:CGPoint, length:CGFloat, clockwise:Bool) -> CGPoint {
  let angle = getAngleWithPoint1(point1, point2:point2)
  let direction = clockwise ? 1 : -1
  let perpendicularAngle = angle + (CGFloat(direction) * CGFloat((M_PI / 2)))
  let midPoint = getMidPointWithPoint1(point1, point2:point2)
  return CGPointMake(midPoint.x + (cos(perpendicularAngle) * length), midPoint.y + (sin(perpendicularAngle) * length))
}

func getAngleWithPoint1(point1:CGPoint, point2:CGPoint) -> CGFloat {
  return atan2((point2.y - point1.y), (point2.x - point1.x))
}

func getMidPointWithPoint1(point1:CGPoint, point2:CGPoint) -> CGPoint {
  return CGPointMake((point1.x + point2.x) / 2, (point1.y + point2.y) / 2)
}

Below is how it would map to your diagram letters:

c = getControlPointWithPoint1(a, point2:b, length:h, clockwise:true)
Mark Horgan
  • 3,243
  • 4
  • 27
  • 28
0

following Mark's answer, here is the snippet in C#

public static Path DrawBezeireUsingTwoPoints(Point startPoint, Point endPoint)
{
  Path path = new Path();
  PathFigure pathFigure = new PathFigure();
  // Set up the Path to insert the segments
  PathGeometry pathGeometry = new PathGeometry();
  BezierSegment bezeireSeg;
  // Draw an ellipse passing by the 2 points and let the path cross it
  Point beziereMidPoint = CalculateBezierePoint(startPoint, endPoint, true);
  bezeireSeg = new BezierSegment(startPoint, beziereMidPoint, endPoint, true);

  pathFigure.StartPoint = startPoint;
  pathFigure.IsClosed = false;
  pathFigure.Segments.Add(bezeireSeg);

  pathGeometry.Figures.Add(pathFigure);
  path.Data = pathGeometry;
  path.Stroke = Brushes.Brown;
  path.StrokeThickness = 2;
  return path;
}
shakram02
  • 10,812
  • 4
  • 22
  • 21
0

I would be happy if help you.

It is my solution.

    Vector2 posA = sphereA.transform.position;
    Vector2 posB = sphereB.transform.position;

    Gizmos.color = Color.blue;
    Gizmos.DrawLine(posA, posB);

    float distance = Vector2.Distance(posA, posB);
    Vector2 direction = (posB - posA).normalized;

    Vector2 v2 = end - start;
    var angle = Mathf.Atan2(v2.y, v2.x) * Mathf.Rad2Deg;      

    var midStartPos = posA + direction * (distance / 2f);

    Gizmos.color = Color.red;
    Gizmos.DrawSphere(midStartPos, 0.02f);

    var height = 0.3f;

    height = Mathf.Clamp(height, 0f, Vector2.Distance(posA, posB) * 0.5f);

    angle = 90f + angle;

    var goalDirection = new Vector2(Mathf.Cos(angle * Mathf.Deg2Rad), Mathf.Sin(angle * Mathf.Deg2Rad));

    if (goalDirection.y < 0f)
    {
        goalDirection.x = -goalDirection.x;
        goalDirection.y = Mathf.Abs(goalDirection.y);
    }

    var midEndPos = midStartPos + goalDirection * height;

    Gizmos.color = Color.blue;
    Gizmos.DrawLine(midStartPos, midEndPos);

    Gizmos.color = Color.red;
    Gizmos.DrawSphere(midEndPos, 0.02f);
nomad
  • 1