我如何“膨胀”一个多边形?也就是说,我想做一些类似的事情:
要求是,新的(膨胀的)多边形的边/点与旧的(原始的)多边形的边/点的距离都是相同的(在示例图片上,它们不是,因为这样它就必须使用弧来膨胀顶点,但让我们暂时忘记这一点;))。
我要找的数学术语实际上是向内/向外多边形偏移。balint指出这一点+1。另一种命名是多边形缓冲。
我的搜索结果:
以下是一些链接:
多边形偏移策略综述 多边形偏移,问题 缓冲多边形数据
我如何“膨胀”一个多边形?也就是说,我想做一些类似的事情:
要求是,新的(膨胀的)多边形的边/点与旧的(原始的)多边形的边/点的距离都是相同的(在示例图片上,它们不是,因为这样它就必须使用弧来膨胀顶点,但让我们暂时忘记这一点;))。
我要找的数学术语实际上是向内/向外多边形偏移。balint指出这一点+1。另一种命名是多边形缓冲。
我的搜索结果:
以下是一些链接:
多边形偏移策略综述 多边形偏移,问题 缓冲多边形数据
当前回答
这是这里解释的算法的c#实现。它也使用Unity数学库和集合包。
public static NativeArray<float2> ExpandPoly(NativeArray<float2> oldPoints, float offset, int outer_ccw = 1)
{
int num_points = oldPoints.Length;
NativeArray<float2> newPoints = new NativeArray<float2>(num_points, Allocator.Temp);
for (int curr = 0; curr < num_points; curr++)
{
int prev = (curr + num_points - 1) % num_points;
int next = (curr + 1) % num_points;
float2 vn = oldPoints[next] - oldPoints[curr];
float2 vnn = math.normalize(vn);
float nnnX = vnn.y;
float nnnY = -vnn.x;
float2 vp = oldPoints[curr] - oldPoints[prev];
float2 vpn = math.normalize(vp);
float npnX = vpn.y * outer_ccw;
float npnY = -vpn.x * outer_ccw;
float bisX = (nnnX + npnX) * outer_ccw;
float bisY = (nnnY + npnY) * outer_ccw;
float2 bisn = math.normalize(new float2(bisX, bisY));
float bislen = offset / math.sqrt((1 + nnnX * npnX + nnnY * npnY) / 2);
newPoints[curr] = new float2(oldPoints[curr].x + bislen * bisn.x, oldPoints[curr].y + bislen * bisn.y);
}
return newPoints;
}
其他回答
这是另一个解决方案,看看你是否更喜欢这个。
做一个三角测量,不一定是delaunay,任何三角测量都可以。 膨胀每个三角形——这应该是微不足道的。如果你以逆时针的顺序存储三角形,只要将线移动到右手边并做交点。 使用改进的Weiler-Atherton裁剪算法合并它们
在GIS世界中,我们使用负缓冲来完成这个任务: http://www-users.cs.umn.edu/~npramod/enc_pdf.pdf
JTS库应该为您完成这项工作。请参阅缓冲区操作的文档:http://tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/operation/buffer/package-summary.html
有关粗略的概述,请参阅开发人员指南: http://www.vividsolutions.com/jts/bin/JTS%20Developer%20Guide.pdf
对于这些类型的事情,我通常使用JTS。出于演示目的,我创建了这个使用JSTS (JTS的JavaScript端口)的jsFiddle。你只需要将坐标转换为JSTS坐标:
function vectorCoordinates2JTS (polygon) {
var coordinates = [];
for (var i = 0; i < polygon.length; i++) {
coordinates.push(new jsts.geom.Coordinate(polygon[i].x, polygon[i].y));
}
return coordinates;
}
结果是这样的:
附加信息:我通常使用这种类型的膨胀/收缩(为我的目的做了一点修改)在地图上绘制的多边形上设置半径边界(使用传单或谷歌地图)。您只需将(lat,lng)对转换为JSTS坐标,其他一切都是相同的。例子:
每条线都应该将平面分割为“内部”和“轮廓”;你可以用常用的内积法求出来。
将所有的线向外移动一段距离。
考虑所有相邻直线对(直线,不是线段),求交点。这些是新的顶点。
清除新顶点通过删除任何交叉部分。我们这里有几个案子
(a)个案一:
0--7 4--3
| | | |
| 6--5 |
| |
1--------2
如果你把它除以1,你会得到这个:
0----a----3
| | |
| | |
| b |
| |
| |
1---------2
7和4重叠。如果你看到这个,你去掉这个点和中间的所有点。
(b)情况2
0--7 4--3
| | | |
| 6--5 |
| |
1--------2
如果你把它乘以2,你会得到这个:
0----47----3
| || |
| || |
| || |
| 56 |
| |
| |
| |
1----------2
为了解决这个问题,对于直线的每一段,你必须检查它是否与后面的段重叠。
(c)情况3
4--3
0--X9 | |
| 78 | |
| 6--5 |
| |
1--------2
除以1。这是情况1的一般情况。
(d)情况4
与case3相同,但支出2。
实际上,如果你能处理情况4。所有其他的情况都是一些特殊的情况有一些直线或顶点重叠。
在情况4中,你保留一个顶点的堆栈。当你发现与后一条线重叠的线时,你就推,当你得到后一条线时,就弹出。就像你在凸船体中做的一样。
你要找的多边形在计算几何中称为内/外偏移多边形,它与直骨架密切相关。
这是一个复杂多边形的几个偏移多边形:
这是另一个多边形的直骨架:
正如在其他评论中指出的那样,取决于你计划“膨胀/收缩”你的多边形的程度,你最终可以得到不同的输出连接。
从计算的角度来看:一旦你有了直线骨架,你应该能够相对容易地构建偏移多边形。开源的CGAL库(非商业免费)有一个实现这些结构的包。请参阅此代码示例使用CGAL计算偏移多边形。
包手册应该给你一个很好的起点,即使你不打算使用CGAL,如何构造这些结构,并包含参考文献的数学定义和属性:
CGAL手册:2D直骨架和多边形偏移