android - 使用CubicTo绘制贝塞尔曲线

标签 android android-canvas android-drawable bezier cubic-spline

以下代码生成 BezierCurves 并创建要在 Canvas 上绘制的 Path 对象。 我转换了this code从 C#.Net 到 Android。

问题: 当我绘制点时,这些点没有形成连续曲线。它在中间中断并再次继续。我认为问题出在 AddBeziers 上,我在其中使用了 cubicTo 生成曲线。这可能与 GraphicsPath.AddBeziers.Net 中的方法不匹配。

我该如何解决?

生成的点数

  • x 坐标 - [0, 55, -44, -54, -44, 55, 0]
  • y 坐标 - [0, -189, -20, -125, -230, -59, -250]

这是必须在 Canvas 上绘制的图形。

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

Android 的 AddBeziers 方法

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;
    }

Android 的 BezierCurve 类

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;
    }
}

积分等级

package com.example.newone;

public class Point {

        public int X;
        public int Y;

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

最佳答案

来自关于 cubicTo() 的 Android 文档,

从最后一个点添加一个立方贝塞尔曲线,接近控制点 (x1,y1) 和 (x2,y2),并在 (x3,y3) 结束。如果没有为此轮廓进行 moveTo() 调用,则第一个点自动设置为 (0,0)。

看起来您只需要在第二次调用 path.cubicTo() 之前添加对 moveTo() 的调用。

关于android - 使用CubicTo绘制贝塞尔曲线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25218674/

相关文章:

android - 适用于 Android 的 Facebook API : how to get extended info regarding user`s friends?

java - 如何在Android中每天的特定时间发送本地通知(API > 26)

安卓游戏 Canvas

android - 默认的 Android 窗口格式

android - 使用多个 RadioButton(自定义 RadioGroup)创建 android RadioGroup

Android之字形布局

Android SQLite 删除表实际上并没有删除行

java - 从 ActiveAndroid 切换到 GreenDao

android - 在主屏幕小部件上使用 Canvas 绘制

android - 所选 View 的默认选择器