1

I have problem to implement code for drawing bezier Curve which is working perfect in iOS.

I want to this effect. but with Touch Points.

But I am getting something wrong. Problem at this line

previousCenterPoint = CenterPointOf(new PointF(points.get(0).x,points.get(0).y), previousPoint);

in iOS, using currentPoint we can get current point.

Please Suggest me how to get current contour point of path....

Here is my code..

public void makeBezierCurve(ArrayList<PointF> points) {
    if (points.size() > 0) {

        if (points.size() < 3) {

            switch (points.size()) {

                case 1:
                    lineTo(points.get(0).x, points.get(0).y);
                case 2:
                    lineTo(points.get(1).x, points.get(1).y);
                default:
                    break;
            }
        } else {


            PointF previousPoint = new PointF(0, 0);
            PointF previousCenterPoint = new PointF(0, 0);
            PointF centerPoint = new PointF(0, 0);
            double centerPointDistance = 0;
            double obliqueAngle = 0;
            PointF previousControlPoint1 = new PointF(0, 0);
            PointF previousControlPoint2 = new PointF(0, 0);
            PointF controlPoint1 = new PointF(0, 0);
            float contractionFactor = 0.7f;

            for (int i = 0; i < points.size(); i++) {

                PointF pointI = points.get(i);

                if (i > 0) {

                    previousCenterPoint = CenterPointOf(new PointF(points.get(0).x, points.get(0).y), previousPoint);
                    centerPoint = CenterPointOf(previousPoint, pointI);

                    centerPointDistance = DistanceBetween(previousCenterPoint, centerPoint);

                    obliqueAngle = ObliqueAngleOfStraightThrough(centerPoint, previousCenterPoint);

                    previousControlPoint2 = new PointF((float) (previousPoint.x - 0.5 * contractionFactor * centerPointDistance * Math.cos(obliqueAngle)), (float) (previousPoint.y - 0.5 * contractionFactor * centerPointDistance * Math.sin(obliqueAngle)));
                    controlPoint1 = new PointF((float) (previousPoint.x + 0.5 * contractionFactor * centerPointDistance * Math.cos(obliqueAngle)), (float) (previousPoint.y + 0.5 * contractionFactor * centerPointDistance * Math.sin(obliqueAngle)));
                }

                if (i == 1) {
                    quadTo(previousControlPoint2.x, previousControlPoint2.y, previousPoint.x, previousPoint.y);
                } else if (i >= 2 && i < points.size() - 1) {
                    cubicTo(previousControlPoint1.x, previousControlPoint1.y, previousControlPoint2.x, previousControlPoint2.y, previousPoint.x, previousPoint.y);
                } else if (i == points.size() - 1) {
                    cubicTo(previousControlPoint1.x, previousControlPoint1.y, previousControlPoint2.x, previousControlPoint2.y, previousPoint.x, previousPoint.y);
                    quadTo(controlPoint1.x, controlPoint1.y, pointI.x, pointI.y);
                }


                previousControlPoint1.set(controlPoint1);
                previousPoint.set(pointI);
            }
        }

    } else {
        logger.e("BezierHelper", "makeBezierCurve: error");
    }
}
Abhay Koradiya
  • 2,068
  • 2
  • 15
  • 40
  • @Mike'Pomax'Kamermans I have edited my Question, please review it suggest me. – Abhay Koradiya May 03 '18 at 09:03
  • 1
    Given your edit, before looking at code: did you look for packages for Android that give you curve-through-point similar to the library you link to for iOS? Because I would be very surprised if after a decade of Android, no one's ever needed that and no one wrote one. – Mike 'Pomax' Kamermans May 03 '18 at 10:02
  • So, How to get this effect in android? Because I have searched a lot, But I can't get Enough stuff. – Abhay Koradiya May 03 '18 at 10:12
  • The effect comes from drawing a Catmull-Rom curve, and changing the "tightness" value that is inherent to that curve type. I've written you an answer for that. – Mike 'Pomax' Kamermans May 05 '18 at 08:27

1 Answers1

0

To implement the effect from the link you show, you need to implement Catmull-Rom curves. Thankfully, those are trivial to implement if you are working with code that can already draw cubic Beziers, because they're the same curve, just using a different representation, and converting from one to the other is incredibly easy.

Take your points list, and invent tangents for each point that are aligned with the line from the points before and after the one you're looking at. Generic code for getting all your CR points set up:

points = ...
initialpoint = points[0] - (points[1] - points[0]) // invent a 'virtual' -1th point
finalpoint = points[last] + (points[last] - points[last-1]) // invent a 'virtual' (last+1)th point
points = initialpoint + points + finalpoint
foreach ((point,i) in points) {
  try {
    p = points[i-1]
    n = points[i+1]
  } catch { continue } 
  diff = n-p 
  point.tangent = diff/2 // let's be reasonable 
}
points = points.slice(1,last-1) // throw those virtual points away

Then draw the catmull-rom curve (by converting the coordinates for each CR section to Bezier coordinates and drawing the corresponding Bezier curve), with the slider from the page you show controlling the "tightness" factor before you convert to Bezier coordinates.

Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153