我正在使用Processing尝试绘制类似于下图的内容:
我已经看到一些使用bezierVertex
作为常规形状的示例,例如this one,但我想建立一个简单的绘图方法,我可以在其中指定我的形状的顶点和然后转角半径。像myRoundedShape(x1, y1, x2, y2, x3, y3... xn, yn, cornerRadius)
之类的东西
有什么想法吗?
答案 0 :(得分:3)
如果你需要任意角度的圆角,贝塞尔曲线几乎是最糟糕的选择,因为数学是非常复杂的。相反,让我们使用Catmull-Rom曲线,因为它们被定义为"曲线通过以下几点:..."而不是简单地通过点控制。
对于3个点p1,p2和p3之间的任何2个边,我们可以在p2的左边和右边沿边缘p1-p2和p2-p3在固定距离处创建新的点p2l和p2r "半径"来自p2:
dx = p2.x-p1.x
dy = p2.y-p1.y
p2l = {x: p2.x - radius * dx, y: p2.y - radius * dy}
p2l_guide = {x: p2.x - 3 * radius * dx, y: p2.y - 3 * radius * dy}
和
dx = p3.x-p2.x
dy = p3.y-p2.y
p2r = {x: p2.x + radius * dx, y: p2.y + radius * dy}
p2r_guide = {x: p2.x + 3 * radius * dx, y: p2.y + 3 * radius * dy}
现在我们的边缘看起来像p1 - p2l和p2r - p3,诀窍是" connect" p2l和p2r以漂亮的弧形方式。因此,让我们使用curveVertex
:
beginShape();
curveVertex(p2l_guide.x,p2l_guide.y);
curveVertex(p2l.x,p2l.y);
curveVertex(p2r.x,p2r.y)
curveVertex(p2r_guide.x,p2r_guide.y);
endShape();
当然,您正在处理大量边缘对,因此您需要预先处理您的坐标列表,而不是成为列表{p2l_guide,p2l,p2r,p2r_guide},然后连接那些作为直线p2r(n) - p2l(n + 1)然后将由p2l到p2r的连接曲线添加到......导引点的引导下。在代码中:http://jsfiddle.net/drzp6L0g/3
这个解决方案确实给我们留下了控制指导强度的神秘变量f
,所以为了解决我们 需要贝塞尔曲线,我们需要确定相同的p2l和p2r点,然后应用some trigonometry来确定我们的控制点需要什么才能实现圆弧的近似a。它更准确,但也更有效。
理想的解决方案当然是简单地使用arcTo命令,但Processing实际上并没有。它有一个arc()
命令,与创建形状分开(所以如果你只需要轮廓......这对你来说可能就好了!)但是如果你需要一个填充的形状,那就没有运气了。
答案 1 :(得分:3)
重新审视这个问题,当我们想要使用"半径"我们实际上并不想要圆形连接,我们只想要等腰三角形" tip"四舍五入。对于Bezier曲线来说,这实际上非常简单,所以这里就是这样。
我们仍然需要我们的偏移点p2l和p2r,因为我们要对三角形p2l进行舍入 - p2 - p2r:
对于3个点p1,p2和p3之间的任何2个边,我们可以在p2的左边和右边沿边缘p1-p2和p2-p3在固定距离处创建新的点p2l和p2r "半径"来自p2:
dx = p2.x-p1.x
dy = p2.y-p1.y
p2l = {x: p2.x - radius * dx, y: p2.y - radius * dy}
和
dx = p3.x-p2.x
dy = p3.y-p2.y
p2r = {x: p2.x + radius * dx, y: p2.y + radius * dy}
(请注意,我们不需要任何其他指导)。我们现在可以将舍入操作定义为:
start = p2l
c1 = point somewhere on line p2l--p2, ratio distance `t` from p2l and `1-t` from p2
c2 = point somewhere on line p2r--p2, using same ratio distance
end = p2r
如果我们选择比率距离为0,那么c1 == p2l
和c2 == p2r
,我们得到一条直线。如果我们选择比率距离1,那么c1 == c2 == p2
,我们可能有最尖的曲线。对于看起来不错的曲线,0.5或0.75的值就可以了。首先,让我们定义c1 / c2抽象函数:
float[] roundIsosceles(Point p1, Point p2, Point p3, float t) {
float mt = 1-t,
c1x = (mt*p1.x + t*p2.x),
c1y = (mt*p1.y + t*p2.y),
c2x = (mt*p3.x + t*p2.x),
c2y = (mt*p3.y + t*p2.y);
return new float[]{ c1x, c1y, c2x, c2y };
}
现在我们可以根据closed
点列表创建合适的形状:
beginShape();
Point p1,p2,p3;
for(int i=0, last=closed.size(); i<last; i+=3) {
p1 = closed.get(i);
p2 = closed.get(i+1);
p3 = closed.get(i+2);
// rounded isosceles triangle connector values:
float[] c = roundIsosceles(p1, p2, p3, 0.75);
// tell Processing that we have points to add to our shape:
vertex(p1.x,p1.y);
bezierVertex(c[0], c[1], c[2], c[3], p3.x, p3.y);
}
endShape(CLOSE);
完成了。结果是什么?作为运行代码,这个:http://jsfiddle.net/drzp6L0g/13,以及图片,这个:
和比率0,0.25,0.5,0.75和1:
之间差异的简单演示