如何在任何线条周围绘制轮廓

时间:2011-04-12 21:19:09

标签: math vector geometry outline

enter image description here

所以我有一个由n点组成的任意线(参见图1所示的例子)

我想围绕这条线绘制一个轮廓(见图2),所以我需要计算周围多边形的点。

我开始在线上进行扩张,但这不起作用 - 见图3

有关如何执行此操作的任何建议?

我怀疑计算每个线段的法线用于平移下面的新线和在当前位置上方的新线,然后将每个新线延伸到无穷大并将这些点定义为交叉点?

5 个答案:

答案 0 :(得分:5)

首先复制每一行两次,每边一次,距离每条原始线的宽度的一半。这为您提供了图像中的绿线。然后你需要按顺序(编号)访问它们并处理松散的目的。

line outlining

如果线条不符合(2-3,6-7和12-13),则添加线条连接(蓝色)。线连接可以是斜面连接(2-3),只需连接点,或斜接连接,通过扩展直到它们相遇(6-7)或通过制作曲线来圆形连接

当线条相遇时,只需取交点(蓝点)。

在行结束时,您需要添加端盖(也是蓝色)。端盖可以是对接盖(8-9),通过连接点,突出盖(1-16),在连接它们之前稍微延伸线,或圆帽(未显示)。

最终结果是一个多边形(或路径,如果它包含圆形连接),然后你可以描边或填充。

答案 1 :(得分:3)

我想出了一种计算直线轮廓点的方法。对于原始线的每个点,您必须为轮廓计算2个点:

  1. 对于原始线的每个线段(2点之间),您必须计算其法线向量(红色)
  2. 对于每个点,添加上一个和下一个线段的法线。这会产生一个新的矢量(绿色)
  3. 将新向量除以值:k l + 1,其中k l是法向量的点积。你会得到蓝色的矢量。然后在当前点及其相反向量上添加此向量,您将获得当前点的2个轮廓点
  4. 上面的颜色对应this imageenter image description here

    我已经在C中编写了这个函数,但是我使用了Accelerate Framework,所以它不是很容易阅读。您可以找到源代码here和运行演示here的视频。

答案 2 :(得分:0)

在渲染之前创建所有行。

当你这样做时,它们应该重叠,如下所示:enter image description here

我所画的那些,显然是那些会被修剪掉的,可以显示轮廓。

答案 3 :(得分:0)

如果您有线段的点,您可以轻松地为每个线段创建两条平行线,并计算它们与下一条线相交的连接点(如果它们是线(而不是线段))。该网站应该为您提供计算超快交叉点所需的所有

http://www.math.niu.edu/~rusin/known-math/95/line_segs

答案 4 :(得分:0)

以下是我在Objective-C中的一些代码(即使它有时有问题,我不知道为什么,让我知道它是怎么回事......):

  • 它采用折线的每条边,然后在当前边的垂线上创建第一个数组,在右边(与折线,CCW或CW相同),然后在左边创建第二个数组。
  • 对于每个边缘,它测试2条无限直线(因为边缘是线段)应该相交的点。
  • 最后,它按所需顺序添加每个点以制作多边形

    - (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/