画出平滑的曲线 [英] Drawing a smooth curve

查看:131
本文介绍了画出平滑的曲线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建更平滑的曲线,而不仅仅是线角度。这是我现在画的画面:

I want to create more a smooth curve, not only line angles. This is the picture how I draw at the moment:

这是我的代码:

case FREEHAND:
    float[] pts;
    float[] ptk;
    ptk = new float[2];
    imageMatrix.invert(inv);            
    if (mCurrentShape == null) {                
        mCurrentShape = new Line();
        pts = new float[2];
        ((Line) mCurrentShape).setBegin(mDownPoint);
        pts[0] = (float)((Line) mCurrentShape).getBegin().getX();
        pts[1] = (float)((Line) mCurrentShape).getBegin().getY();
        inv.mapPoints(pts);
        ((Line) mCurrentShape).getPath().moveTo(pts[0], pts[1]);
    }
    ptk[0] = (float)currentPoint.getX();
    ptk[1] = (float)currentPoint.getY();
    inv.mapPoints(ptk);
    ((Line) mCurrentShape).getPath().lineTo(ptk[0], ptk[1]);
    break;

手绘代码:

package aa.bb.cc;
import java.util.ArrayList;
import android.graphics.Path;

public class FreeHand extends Shape{
    private ArrayList<Path>_graphics;

    public FreeHand(){
        super();
        _graphics = new ArrayList<Path>();
    }

    public ArrayList<Path> getGraphicsPath(){
        return _graphics;
    }
}


推荐答案

我有一个代码使用二次贝塞尔线来平滑点。事实证明工作非常好。它也非常有效。使用以下类构建平滑路径。每次有新点时,使用 addPoint(x,y)添加它。完成后,您可以调用 constructPath()来获得平滑的路径。与评论中的解决方案相比,例如corner.squareup.com/2012/07/smoother-signatures.html,我的解决方案避免了原始路径尖角处的工件。

I have a code use quadratic Bezier line to smooth the points. Which turns out work really well. It is also very efficient. Use the following class the construct your smoothed path. Each time you have a new point, use addPoint(x, y) to add it. Once you are done, you can call constructPath() to get the smoothed path. Compare to the solutions in the comments, like "corner.squareup.com/2012/07/smoother-signatures.html", my solution avoids the artifacts at the very sharp corners of the original path.

public class BezierCurveConstructor {
Path path;

PointF previousPoint;
int pointCounter = 0;

public BezierCurveConstructor() {
    reset();
}


/**
 * reset the path
 */
public void reset() {
    path = new Path();
    pointCounter = 0;
}


public void addPoint(float x, float y) {

    pointCounter ++;
    if (pointCounter == 1) {
        path.moveTo(x, y);
        previousPoint = new PointF(x, y);
        return;
    }


    PointF mid = new PointF((x + previousPoint.x) / 2.0f, (y + previousPoint.y) / 2.0f);

    if (pointCounter < 3) {
        path.lineTo(mid.x, mid.y);
    } else {
        path.quadTo(previousPoint.x, previousPoint.y, mid.x, mid.y);
    }
    previousPoint = new PointF(x, y);
}

/**
 * construct path by points
 *
 * @return
 */
public Path constructPath() {
    return path;
}

}

此路径包含通过前一点的所有中间点和触摸的下一个点的二次贝塞尔曲线列表。请注意,此路径具有常量二阶导数,但第一个导数在胶点处匹配。我们可以通过以下推导来说明原因:

This path contains a list of quadratic Bezier curves going through all the middle points of the previous point and the next points of your touches. Note that this path has constant second derivatives but the first derivatives match at the glue points. We can show why it is so by the following derivation:

将点列表表示为p_0,p_1,... p_n,(这些可以是R ^ n)中的点
让c_i =(pi + p_ {i_1})/ 2作为pi的中间点和p_ {i-1}。
我们可以将二次Bezier线建模如下,这里t是一个介于0和1之间的数字:
G_i(t)=(1-t)^ 2c_i +2(1-t)tp_i + t ^ 2 c_ {i + 1}
考虑对t的导数:
G_i'(t)= -2(1-t)c_i + 2(1-tt)p_i + 2t c_ {i + 1},和
G_i''(t)= 2c_i -4p_i + 2c_ {i + 1} = 2p_ {i-1} + 2 p_ {i + 1}
因此二阶导数是常数。为了表明每个c_i的
一阶导数匹配,我们可以插入t = 0,并且t = 1。
G_i'(0)= 2p_i-2c_i = p_i - p_ {i-1}
G_ {i-1}'(1)= -2p_ {i-1} + 2c_i = p_i - p_ {i-1} = G_i'(0)

BTW,您可以查看维基以获得贝塞尔曲线的清晰定义 https://en.wikipedia.org/wiki/B%C3%A9zier_curve

BTW, you can have a look at wiki for a clear definition of a Bezier curve https://en.wikipedia.org/wiki/B%C3%A9zier_curve

查看此链接以获取原始代码:
https://github.com/lyang36/codeNotes/blob/master/BezierCurveConstructor.java

Checkout this link for the raw code: https://github.com/lyang36/codeNotes/blob/master/BezierCurveConstructor.java

这篇关于画出平滑的曲线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆