带圆角的多边形

时间:2014-11-18 13:46:54

标签: java processing rounded-corners bezier

我正在使用Processing尝试绘制类似于下图的内容:

enter image description here

我已经看到一些使用bezierVertex作为常规形状的示例,例如this one,但我想建立一个简单的绘图方法,我可以在其中指定我的形状的顶点和然后转角半径。像myRoundedShape(x1, y1, x2, y2, x3, y3... xn, yn, cornerRadius)之类的东西 有什么想法吗?

2 个答案:

答案 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 == p2lc2 == 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,以及图片,这个:

enter image description here

和比率0,0.25,0.5,0.75和1:

之间差异的简单演示

enter image description here