简体   繁体   English

带圆角的多边形

[英]Polygon with rounded corners

I'm using Processing to try to draw something similar to the image below: 我正在使用Processing尝试绘制类似于下图的内容:

在此输入图像描述

I've seen some examples using bezierVertex for regular shapes, like this one , but I would like to build a simple drawing method where I can specify my shape's vertex and then the corner radius. 我已经看到一些使用bezierVertex作为常规形状的例子,比如这个 ,但是我想建立一个简单的绘图方法,我可以指定我的形状的顶点然后指定角半径。 Something like myRoundedShape(x1, y1, x2, y2, x3, y3... xn, yn, cornerRadius) Any ideas? 类似于myRoundedShape(x1, y1, x2, y2, x3, y3... xn, yn, cornerRadius)任何想法?

If you need rounded corners for arbitrary angles, Bezier curves are pretty much the worst possible choice, because the maths is stupidly complex. 如果你需要任意角度的圆角,贝塞尔曲线几乎是最糟糕的选择,因为数学是非常复杂的。 instead, let's use Catmull-Rom curves, because they're defined as "the curve goes through the following points: ..." instead of being simply controlled by points. 相反,让我们使用Catmull-Rom曲线,因为它们被定义为“曲线经过以下几点:......”而不是简单地用点控制

For any 2 edges between 3 points, p1, p2 and p3, we can create new points p2l and p2r on the left and right of p2, along the edges p1--p2 and p2--p3, at a fixed distances "radius" from p2: 对于3个点,p1,p2和p3之间的任何2个边,我们可以在p2的左侧和右侧创建新的点p2l和p2r,沿着边缘p1-p2和p2-p3,在固定距离“半径”处来自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}

and

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}

now our edges will look like p1--p2l and p2r--p3, and the trick is to "connect" p2l and p2r in a nice, arc-ish way. 现在我们的边缘看起来像p1 - p2l和p2r - p3,诀窍是以一种漂亮的弧形方式“连接”p2l和p2r。 So let's use the curveVertex : 那么让我们使用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();

Of course, you're dealing with lots of edge pairs, so you'll need to preprocess your list of coordinates to become lists of tubles {p2l_guide,p2l,p2r,p2r_guide} instead, and then connect those as straight line p2r(n)--p2l(n+1) and then add the connection curve from p2l to p2r guided by the ..._guide points. 当然,你正在处理大量的边缘对,所以你需要预先处理你的坐标列表,而不是将这些坐标列为{p2l_guide,p2l,p2r,p2r_guide},然后将它们作为直线p2r(n)连接起来。 ) - p2l(n + 1)然后在......引导点的引导下添加从p2l到p2r的连接曲线。 In code: http://jsfiddle.net/drzp6L0g/3 在代码中: http//jsfiddle.net/drzp6L0g/3

This solution does leave us with the mystery variable f that controls the guide strength, so to solve that we would need bezier curves, and we'd need to determine the same p2l and p2r points, and then apply some trigonometry to figure out what our control points would need to be in order to effect an approximation a of circular arc. 该解决方案确实给我们留下了神秘的变量f控制引导力量,因此要解决,我们需要贝塞尔曲线,我们就需要确定相同P2L和P2R点,然后应用一些三角找出我们控制点需要是为了实现圆弧的近似a。 It'd be more accurate, but also more work. 它更准确,但也更多的工作。

The ideal solution, of course, would be to simply use an arcTo command, but Processing doesn't actually have one. 当然,理想的解决方案是简单地使用arcTo命令,但Processing实际上并没有。 It has an arc() command, detached from creating shapes (so if you just need outlines... that might do just fine for you!) but if you need a filled shape, no luck. 它有一个arc()命令,与创建形状分离(所以如果你只需要轮廓......这可能对你很好!)但如果你需要一个填充的形状,没有运气。

Revisiting this, when we want rounded corners with "a radius" we don't actually want circular connections, we just want the isosceles triangle "tip" to be rounded off. 重新审视这一点,当我们想要带有“半径”的圆角时,我们实际上并不想要圆形连接,我们只想要将等腰三角形“尖端”四舍五入。 That's actually really easy with Bezier curves, so here goes. Bezier曲线实际上非常简单,所以这里就是这样。

We still need our offset points p2l and p2r, because we're going to round off the triangle p2l--p2--p2r: 我们仍然需要我们的偏移点p2l和p2r,因为我们要舍入三角形p2l - p2 - p2r:

For any 2 edges between 3 points, p1, p2 and p3, we can create new points p2l and p2r on the left and right of p2, along the edges p1--p2 and p2--p3, at a fixed distances "radius" from p2: 对于3个点,p1,p2和p3之间的任何2个边,我们可以在p2的左侧和右侧创建新的点p2l和p2r,沿着边缘p1-p2和p2-p3,在固定距离“半径”处来自p2:

dx = p2.x-p1.x
dy = p2.y-p1.y
p2l = {x: p2.x - radius * dx, y: p2.y - radius * dy}

and

dx = p3.x-p2.x
dy = p3.y-p2.y
p2r = {x: p2.x + radius * dx, y: p2.y + radius * dy}

(Note that we don't need any additional guide points). (请注意,我们不需要任何其他指导)。 We can now define the rounding operation as: 我们现在可以将舍入操作定义为:

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

If we pick a ratio distance of 0, then c1 == p2l and c2 == p2r , and we get a straight line. 如果我们选择比率距离为0,那么c1 == p2l c2 == p2rc2 == p2r ,我们得到一条直线。 If we pick ratio distance 1, then c1 == c2 == p2 , and we have the most pointy curve possible. 如果我们选择比率距离1,那么c1 == c2 == p2 ,我们可能有最尖的曲线。 For decent looking curves, a value of 0.5 or 0.75 will do the trick just fine. 对于看起来不错的曲线,0.5或0.75的值就可以了。 So first, let's define that c1/c2 abstracting function: 首先,让我们定义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 };
} 

And now we can create out proper shape, based on the closed list of points: 现在我们可以基于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);

And done. 并做了。 What's the result? 结果是什么? As running code, this: http://jsfiddle.net/drzp6L0g/13 , and as picture, this: 作为运行代码,这个: http//jsfiddle.net/drzp6L0g/13 ,如图所示:

在此输入图像描述

And a simple demonstrator of the difference between ratios 0, 0.25, 0.5, 0.75 and 1: 以及比率0,0.25,0.5,0.75和1之间差异的简单演示:

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM