Search code examples
androidandroid-canvasbeziercubic

Find new control point when endpoint change in cubic bezier curve


I'm implementing cubic bezier curve logic in my one of Android Application.

I've implemented cubic bezier curve code on canvas in onDraw of custom view.

// Path to draw cubic bezier curve
Path cubePath = new Path();

// Move to startPoint(200,200) (P0)
cubePath.moveTo(200,200);

// Cubic to with ControlPoint1(200,100) (C1), ControlPoint2(300,100) (C2) , EndPoint(300,200) (P1)
cubePath.cubicTo(200,100,300,100,300,200);

// Draw on Canvas
canvas.drawPath(cubePath, paint);

I visualize above code in following image.

Output of above code

[Updated]

Logic for selecting first control points, I've taken ,
baseX = 200 , baseY = 200 and curve_size = X of Endpoint - X of Start Point

Start Point     : x = baseX and y = baseY
Control Point 1 : x = baseX and y =  baseY - curve_size
Control Point 2 : x = baseX + curve_size and y =  baseY - curve_size
End Point       : x = baseX + curve_size and y = baseY

I want to allow user to change EndPoint of above curve, and based on the new End points, I invalidate the canvas.

But problem is that, Curve maintain by two control points, which needs to be recalculate upon the change in EndPoint.

Like, I just want to find new Control Points when EndPoint change from (300,200) to (250,250)

Like in following image :

New Image

Please help me to calculate two new Control Points based on new End Point that curve shape will maintain same as previous end point.

I refer following reference links during searching:

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

http://jsfiddle.net/hitesh24by365/jHbVE/3/

http://en.wikipedia.org/wiki/B%C3%A9zier_curve

http://cubic-bezier.com/

Any reference link also appreciated in answer of this question.


Solution

  • changing the endpoint means two things, a rotation along P1 and a scaling factor.

    The scaling factor (lets call it s) is len(p1 - p0) / len(p2 - p0)

    For the rotation factor (lets call it r) i defer you to Calculating the angle between three points in android , which also gives a platform specific implementation, but you can check correctness by scaling/rotationg p1 in relation to p0, and you should get p2 as a result.

    next, apply scaling and rotation with respect to p0 to c1 and c2. for convenience i will call the new c1 'd1' and the new d2.

    d1 = rot(c1 - p0, factor) * s + p0
    d2 = rot(c2 - p0, factor) * s + p0
    

    to define some pseudocode for rot() (rotation http://en.wikipedia.org/wiki/Rotation_%28mathematics%29)

    rot(point p, double angle){
      point q;
      q.x = p.x * cos(angle) - p.y * sin(angle);
      q.y = p.x * sin(angle) + p.y * cos(angle);
    }
    

    Your bezier curve is now scaled and rotated in relation to p0, with p1 changed to p2,