多边形扩展或收缩算法

如下图所示,黑色多边形是原多边形,绿色多边形是扩展多边形,红色多边形是收缩多边形。算法要实现的效果就是这样。

首先,我们用一个点的数组表示多边形,形如Point[] points。接下来是数学公式的推导,我们用向量法解决这个问题。

对于每一个点,它都有两个邻点,如下图所示,点P的邻点是P1和P2。那我们要求的,其实就是点Q。Q到PP1和PP2的距离都是L。

如图所示,明显向量PQ就是向量v1+v2,而v1的方向由PP1确定,v2的方向由PP2确定。易证明,v1、v2的长度是相等的。

向量PP1是(x1-x,y1-y),我们用(v1x,v1y)表示,

向量PP2是(x2-x,y2-y),我们用(v2x,v2y)表示。

我们把v1的长度归一化,设n1=norm(v1x,v2y),则v1为(v1x/n1,v1y/n1)。v2同理,不赘述。

那么向量PQ就是v1+v2,即(v1x/n1+v2x/n2+v1y/n1+v2y/n2),我们设其为(vx,vy)。

我们这里还要对PQ进行长度归一化,设n=norm(vx,vy),向量PQ为(vx/n,vy/n)。

好了,到现在为止,向量PQ的方向已经确定,剩下就是长度的问题了。

我们先求v1、v2的夹角。使用余弦公式,cosθ=(v1x*v2x+v1y*v2y)/(n1*n2)。

那|PQ|=L/sin(θ/2)。

根据半角公式,我们还能对上式进行化简,省去三角函数的计算。

|PQ|=L/sqrt(1-(v1x*v2x+v1y*v2y)/2)

经过上面的计算,我们已经求出了完整的PQ向量,现加上P点坐标,就得到了Q点的坐标。

C#完整代码如下:

/// <summary>
/// 扩展或收缩
/// </summary>
/// <param name="polygon">多边形顶点</param>
/// <param name="expand">扩展大小,为负则收缩</param>
/// <returns>扩展或收缩后的多边形</returns>
public static Point2D[] Expand(Point2D[] polygon, double expand)
{
    Point2D[] new_polygon = new Point2D[polygon.Length];

    int len = polygon.Length;
    for (int i = 0; i < len; i++)
    {
        Point2D p = polygon[i];
        Point2D p1 = polygon[i == 0 ? len - 1 : i - 1];
        Point2D p2 = polygon[i == len - 1 ? 0 : i + 1];

        double v1x = p1.X - p.X;
        double v1y = p1.Y - p.Y;
        double n1 = norm(v1x, v1y);
        v1x /= n1;
        v1y /= n1;

        double v2x = p2.X - p.X;
        double v2y = p2.Y - p.Y;
        double n2 = norm(v2x, v2y);
        v2x /= n2;
        v2y /= n2;

        double l = -expand / Math.Sqrt((1 - (v1x * v2x + v1y * v2y)) / 2);

        double vx = v1x + v2x;
        double vy = v1y + v2y;
        double n = l / norm(vx, vy);
        vx *= n;
        vy *= n;

        new_polygon[i] = new Point2D(vx + p.X, vy + p.Y);
    }

    return new_polygon;
}

private static double norm(double x, double y)
{
    return Math.Sqrt(x * x + y * y);
}

 

  • 8
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 18
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值