user2943193
user2943193

Reputation: 41

using CubicTo to draw Bezier curve

The following code generates BezierCurves and creates a Path object to be drawn on the canvas. I converted this code from C#.Net to Android.

Issue : When I draw the points the points do not formulate a continuous curve. it breaks in the middle and continues again. I think the issues is with the AddBeziers, where I have used cubicTo generate the curve. Which may not be matching with GraphicsPath.AddBeziersMethod in .Net.

How can I resolve this?

The points that generated

This is figure that has to be drawn on the canvas.

Path figure = new Path();
BezierCurve verticalCurvex = BezierCurve.CreateVertical(250);
verticalCurvex.FlipVertical();                  
verticalCurvex.FlipHorizontal();
AddBeziers(figure, verticalCurvex.Points);

AddBeziers Method for Android

private Path AddBeziers(Path path, Point[] points) {

        int index = 1;
        if (points.length > 3) {
            path.moveTo(points[0].X, points[0].Y);
            path.cubicTo(points[index].X, points[index].Y, points[index + 1].X,
                    points[index + 1].Y, points[index + 2].X,
                    points[index + 2].Y);
        }

        index = index + 3;
        if (points.length > 5) {
            path.cubicTo(points[index].X, points[index].Y, points[index + 1].X,
                    points[index + 1].Y, points[index + 2].X,
                    points[index + 2].Y);
        }

        return path;
    }

BezierCurve Class for android

package com.example.newone;

public class BezierCurve {

    // NOTE : A point's x and y positions are measured from bottom-left corner of the piece.
    // X~RATIO  =     point's x position / piece's width
    // Y~RATIO  =     point's y position / piece's height
    private static final double X2RATIO = 0.760869565217391;
    private static final double Y2RATIO = 0.183946488294314;

    private static final double X3RATIO = 0.0802675585284281;
    private static final double Y3RATIO = 0.150501672240803;

    private static final double X4RATIO = 0.5;
    private static final double Y4RATIO = Y2RATIO;

    private static final double X6RATIO = X2RATIO;
    private static final double Y6RATIO = Y2RATIO;

    private static final double X5RATIO = X3RATIO;
    private static final double Y5RATIO = Y3RATIO;

    private static final double CURVE_TENSION = 1.2;

    public Point[] Points ;

    public static BezierCurve CreateHorizontal(int length)
    {
        double curvature = length * CURVE_TENSION;

        int x1, y1;     // First curve's starting point
        int x2, y2;     // First curve's first control point
        int x3, y3;     // First curve's second control point
        int x4, y4;     // First curve's ending point, second curve's starting point
        int x5, y5;     // Second curve's first control point
        int x6, y6;     // Second curve's second control point
        int x7, y7;     // Second curve's ending point

        // First curve (first curve's ending point is (X4, Y4), which is also second curve's end point      
        x1 = 0;
        y1 = 0;

        x2 = x1 + (int)(length * X2RATIO);
        y2 = y1 + (int)(curvature * Y2RATIO);

        x3 = x1 + (int)(length * X3RATIO);
        y3 = y1 - (int)(curvature * Y3RATIO);

        x4 = x1 + (int)(length * X4RATIO);
        y4 = y1 - (int)(curvature * Y4RATIO);

        // Second curve (second curve's ending point is (X4, Y4) )      
        x7 = x1 + length;
        y7 = y1;

        x6 = x7 - (int)(length * X6RATIO);
        y6 = y7 + (int)(curvature * Y6RATIO);

        x5 = x7 - (int)(length * X5RATIO);
        y5 = y7 - (int)(curvature * Y5RATIO);

        BezierCurve curve = new BezierCurve();

        curve.Points  = new Point[] 
            {
                new Point(x1, y1), 
                new Point(x2, y2),
                new Point(x3, y3), 
                new Point(x4, y4),
                new Point(x5, y5), 
                new Point(x6, y6),
                new Point(x7, y7)
            } ;


        return curve;
    }

    public static BezierCurve CreateVertical(int length)
    {
        BezierCurve curve = CreateHorizontal(length);
        curve.Rotate(90);

        int offsetX = 0 - curve.Points[0].X;
        int offsetY = 0 - curve.Points[0].Y;

        return curve.Translate(offsetX, offsetY);            
    }

    public BezierCurve Translate(int transX, int transY)
    {            
        for (int i = 0; i < this.Points.length; i++)
        {
            this.Points[i].X += transX;
            this.Points[i].Y += transY;
        }

        return this;
    }

    public BezierCurve FlipHorizontal()
    {
        for (int i = 0; i < this.Points.length; i++)
        {
            this.Points[i].X *= -1;                
        }

        return this;
    }

    public BezierCurve FlipVertical()
    {
        for (int i = 0; i < this.Points.length; i++)
        {
            this.Points[i].Y *= -1;
        }

        return this;
    }

    // ===============================================
    // Transformation code adapted from C++ source code in the book
    // Direct3D Programming (Kickstart) by Clayton Walnum
    // ===============================================
    public BezierCurve Rotate(int degrees)
    {
        double radians = 6.283185308 / (360 / degrees);
        double cosine = Math.cos(radians);
        double sine = Math.sin(radians);

        for (int i = 0; i < this.Points.length; i++)
        {
            int rotatedX = (int)(this.Points[i].X * cosine - this.Points[i].Y * sine);
            int rotatedY = (int)(this.Points[i].Y * cosine + this.Points[i].X * sine);

            this.Points[i].X = rotatedX;
            this.Points[i].Y = rotatedY;
        }

        return this;
    }
}

Point Class

package com.example.newone;

public class Point {

        public int X;
        public int Y;

   public Point(int x , int y)
   {
       X= x;
       Y= y;
   }
}

Upvotes: 1

Views: 9039

Answers (1)

fang
fang

Reputation: 3633

From the Android documentation about cubicTo(),

Add a cubic bezier from the last point, approaching control points (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been made for this contour, the first point is automatically set to (0,0).

It looks like you just need to add a call to moveTo() before the 2nd call to path.cubicTo().

Upvotes: 3

Related Questions