Используя CubicTo для рисования кривой Безье

Следующий код генерирует BezierCurves и создает объект Path для рисования на холсте. Я преобразовал этот код из C#.Net для Android.

Проблема: когда я рисую точки, точки не образуют непрерывную кривую. оно разрывается посередине и продолжается снова. Я думаю, что проблемы с AddBeziersгде я использовал cubicTo генерировать кривую. Который может не совпадать с GraphicsPath.AddBeziersМетод в.Net.

Как я могу решить это?

Точки, которые сгенерированы

  • координаты х - [0, 55, -44, -54, -44, 55, 0]
  • координаты y - [0, -189, -20, -125, -230, -59, -250]

Это фигура, которая должна быть нарисована на холсте.

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

Метод AddBeziers для 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 для 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;
   }
}

1 ответ

Решение

Из документации Android о cubicTo (),

Добавьте кубический Безье из последней точки, приближаясь к контрольным точкам (x1,y1) и (x2,y2) и заканчивая в (x3,y3). Если для этого контура не было выполнено никакого вызова moveTo(), для первой точки автоматически устанавливается значение (0,0).

Похоже, вам просто нужно добавить вызов moveTo() перед вторым вызовом path.cubicTo ().

Другие вопросы по тегам