所以我有一条由 n 个点组成的任意线(参见图 1 中的示例)
我想围绕这条线画一个轮廓(见图 2),所以我需要计算周围多边形的点。
我首先在线上执行扩张,但这不起作用 - 见图 3
关于如何做到这一点的任何建议?
我怀疑计算每条线段的法线以用于翻译下面的新线和高于其当前位置的新线,然后将每条新线延伸到无穷大并将点定义为交点?
首先将每条线复制两次,每边复制一次,距离每条原始线所需宽度的一半。这会给你图像中的绿线。然后您需要按顺序(编号)访问它们并处理松散的末端。
当线不相遇(2-3、6-7 和 12-13)时,您添加线连接(蓝色)。线连接可以是仅通过连接点的斜角连接(2-3),也可以是通过延长线直到它们相遇 (6-7) 的斜接连接或通过制作曲线的圆形连接。
当线条相遇时,只需取交点(蓝点)。
在线路末端,您需要添加一个端盖(也是蓝色的)。通过连接点,端盖可以是对接盖(8-9),通过在连接它们之前稍微延长线的突出盖(1-16),或圆形盖(未显示)。
最终结果是一个多边形(或路径,如果它包括圆形连接),然后您可以对其进行描边或填充。
我想出了一种计算线条轮廓点的方法。对于原始线的每个点,您必须为轮廓计算 2 个点:
上面的颜色对应这张图片。
我已经用 C 编写了这个函数,但是我使用了 Accelerate Framework,所以它不是很容易阅读。您可以在此处找到源代码,并在此处找到运行演示的视频。
在渲染它们之前创建所有线条。
当你这样做时,它们应该重叠,如下所示:
很明显,我画的那些是被修剪过的,会露出轮廓的。
这是我在 Objective-C 中的一些代码(即使它有时是错误的,我不知道为什么,让我知道它对你有什么好处......):
最后它以所需的顺序添加每个点以制作多边形
- (hOzPolygon2D *) convertToPolygonWithWidth:(double) polyWidth
{
double shift = polyWidth / 2.;
NSMutableArray *tempEdgesRight = [[[NSMutableArray alloc] init] autorelease];
NSMutableArray *tempEdgesLeft = [[[NSMutableArray alloc] init] autorelease];
NSMutableArray *tempPolyPoints = [[[NSMutableArray alloc] init] autorelease];
// Move your points on the right by half the desired width
// My edges are already computed in a NSArray* called edges,
// but you can use pairs of vectors and adapt all this
for (hOzEdge2D *edge in edges) {
hOzVector2 v = hOzVector2([[edge pointB] x] - [[edge pointA] x], [[edge pointB] y] - [[edge pointA] y]);
double mag = sqrt (v.x * v.x + v.y * v.y);
v.x = v.x / mag;
v.y = v.y / mag;
double temp = v.x;
v.x = v.y;
v.y = -temp;
hOzPoint2D *newPointA = [[hOzPoint2D alloc] init];
[newPointA setX:([[edge pointA] x] + v.x * shift)];
[newPointA setY:([[edge pointA] y] + v.y * shift)];
hOzPoint2D *newPointB = [[hOzPoint2D alloc] init];
[newPointB setX:([[edge pointB] x] + v.x * shift)];
[newPointB setY:([[edge pointB] y] + v.y * shift)];
[tempEdgesRight addObject:[hOzEdge2D edge2DWithPointA:newPointA pointB:newPointB]];
}
// With the same polyline, move on the left
for (int j = [edges count] - 1; j >= 0; j--) {
hOzVector2 v = hOzVector2([[[edges objectAtIndex:j] pointB] x] - [[[edges objectAtIndex:j] pointA] x], [[[edges objectAtIndex:j] pointB] y] - [[[edges objectAtIndex:j] pointA] y]);
double mag = sqrt (v.x * v.x + v.y * v.y);
v.x = v.x / mag;
v.y = v.y / mag;
double temp = v.x;
v.x = v.y;
v.y = -temp;
hOzPoint2D *newPointA = [[hOzPoint2D alloc] init];
[newPointA setX:([[[edges objectAtIndex:j] pointB] x] - v.x * shift)];
[newPointA setY:([[[edges objectAtIndex:j] pointB] y] - v.y * shift)];
hOzPoint2D *newPointB = [[hOzPoint2D alloc] init];
[newPointB setX:([[[edges objectAtIndex:j] pointA] x] - v.x * shift)];
[newPointB setY:([[[edges objectAtIndex:j] pointA] y] - v.y * shift)];
[tempEdgesLeft addObject:[hOzEdge2D edge2DWithPointA:newPointA pointB:newPointB]];
}
// Add the static points and the intersection points to a points array that will define your polygon
[tempPolyPoints addObject:[[tempEdgesRight objectAtIndex:0] pointA]]; // The first point of the right array
for (int k = 0; k < [tempEdgesRight count] - 1; k++) {
// For this function, see the link below in the answer
hOzPoint2D *inter = [[tempEdgesRight objectAtIndex:k] getIntersectionWithStraight:[tempEdgesRight objectAtIndex:k+1]];
if (inter == nil) { // if the edges are parallel, we insert a known point
[tempPolyPoints addObject:[[tempEdgesRight objectAtIndex:k] pointB]];
} else {
[tempPolyPoints addObject:inter];
}
}
[tempPolyPoints addObject:[[tempEdgesRight lastObject] pointB]]; // The last point of the right array
[tempPolyPoints addObject:[[tempEdgesLeft objectAtIndex:0] pointA]];
// Then the left array, same thing
for (int k = 0; k < [tempEdgesLeft count] - 1; k++) {
hOzPoint2D *inter = [[tempEdgesLeft objectAtIndex:k] getIntersectionWithStraight:[tempEdgesLeft objectAtIndex:k+1]];
if (inter == nil) {
[tempPolyPoints addObject:[[tempEdgesLeft objectAtIndex:k] pointB]];
} else {
[tempPolyPoints addObject:inter];
}
}
[tempPolyPoints addObject:[[tempEdgesLeft lastObject] pointB]];
// Create your polygon with this new ordered points array.
hOzPolygon2D *poly = [hOzPolygon2D polygon2DWithArrayOfPoints:tempPolyPoints];
return poly;
}
以下是交点的一些解释,使用 C 代码:http ://alienryderflex.com/intersect/
如果您有线段的点,则可以轻松地为每个线段创建两条平行线,并计算它们与下一条线(而不是线段)相交的连接点。该站点应该为您提供计算超快速交叉口所需的一切: