2013-10-21 205 views

回答

1

您应该查看三次贝塞尔曲线(样条曲线)。简单地使用Canvas就没有简单的方法。这里有一个概述:

贝塞尔曲线使用2点(P0-原点&P1-目的地)和2个矢量(V0-曲线离开的方向P0,V1-曲线进入P1的方向)。对于我们的目的,P0,P1,V0,V1应该都是PointF类型。

我们将用t来表示路径上的位置。当t = 0时,位置在P0处,当t = 1时,位置在P1处。任何值在0和1之间的值都将沿着路径。 0 < = t < = 1.

现在,举一个例子,让我们看看连接“无人完美”节点和“稍后整理”节点的曲线。

在这种情况下,P0将是“无人完美”的右侧中间,P1将是“稍后整理”的底部中间侧。

我们将使这两个矢量垂直于它们要离开/进入的节点,因此V0的值将为{P1.x - P0.x,0}。这个向量将指向右侧,并且将具有与两个节点之间的距离相等的强度。以类似的方式,我们将构建指向节点的V1矢量:{0,P0.y - P1.y}

现在您已经获得了矢量和点,您将需要开始绘制曲线。要做到这一点,你可以使用一个小的步进值来迭代t,例如0.1,0.025,0.001等等。我们称这个值为“step”每次迭代都会在曲线上产生一个点,而你将要在这些点之间连接一条线。

下面是这部分代码示例:

PointF start, end; 
for (float t = 0; t < 1; t += step) 
{ 
    start = getBezierPosition(t); 
    end = getBezierPosition(t + step) 
    canvas.drawLine(start.x, start.y, end.x, end.y, paint); 
} 

现在,硬的部分 - 计算在位置t的贝塞尔曲线的位置:

private PointF getBezierPosition(float t) 
{ 
    PointF result = new PointF(); 

    float oneMinusT, x, y; 

    oneMinusT = 1 - t; 
    x = oneMinusT * oneMinusT * oneMinusT * P0.x + 
       3 * oneMinusT * oneMinusT * t * V0.x + 
       3 * oneMinusT * t * t * V1.x + 
       t * t * t * P1.x; 
    y = oneMinusT * oneMinusT * oneMinusT * P0.y + 
       3 * oneMinusT * oneMinusT * t * V0.y + 
       3 * oneMinusT * t * t * V1.y + 
       t * t * t * P1.y; 

    result.set(x, y); 

    return result; 
} 

这是一个立方体式贝塞尔曲线。你可以了解更多关于它here

我会让你实施确定P1的位置和V1的方向的逻辑V1(请记住,它们应该始终垂直于它们要离开/进入的节点以获得最佳结果)。您需要充分利用逻辑来确定P所处的节点的哪一侧,并且最有可能与您将节点定位到第一位时应用的逻辑相关联。

此外,为了获得最佳效果,请尝试使用您正在绘制的颜料的描边宽度。例如,当t = 0时,使用大小为5的笔画宽度,当t = 1时,使用笔画大小为3.确保在它们之间平滑地迭代(所以如果t = 0.5,笔画宽度将为4) 。

我承认,这个东西在数学上有点沉重,可能不在初学者的舒适区,但如果你想要达到像你在这张图片中展现的动态曲线,恐怕你会弄脏你的手。

祝你好运!让我知道这是怎么一回事:)