如何将多边形“膨胀”?也就是说,我想做类似的事情:
要求是新的(膨胀的)多边形的边/点都与旧的(原始)多边形的边/点都具有相同的恒定距离(在示例图片中,它们不是,因为从那以后,它必须对膨胀的顶点使用圆弧,但是让我们暂时忘记这一点;))。
我要寻找的数学术语实际上是向内/向外多边形偏移。+1表示要指出这一点。另一种命名方式是多边形缓冲。
搜索结果:
以下是一些链接:
如何将多边形“膨胀”?也就是说,我想做类似的事情:
要求是新的(膨胀的)多边形的边/点都与旧的(原始)多边形的边/点都具有相同的恒定距离(在示例图片中,它们不是,因为从那以后,它必须对膨胀的顶点使用圆弧,但是让我们暂时忘记这一点;))。
我要寻找的数学术语实际上是向内/向外多边形偏移。+1表示要指出这一点。另一种命名方式是多边形缓冲。
搜索结果:
以下是一些链接:
Answers:
我想我可能提一提我自己的多边形裁剪和抵消库 - 快船。
尽管Clipper主要是为多边形裁剪操作而设计的,但它也可以进行多边形偏移。该库是用Delphi,C ++和C#编写的开源免费软件。它具有非常宽松的Boost许可证,因此可以免费用于免费软件和商业应用程序。
可以使用以下三种偏移样式之一执行多边形偏移:正方形,圆形和斜切。
对于这些类型的事情,我通常使用JTS。出于演示的目的,我创造了这个的jsfiddle使用JSTS(JTS的JavaScript的端口)。您只需要将必须的坐标转换为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;
}
结果是这样的:
附加信息:我通常使用这种类型的充气/放气(为我的目的稍作修改)来设置在地图上绘制的多边形上的半径边界(使用Leaflet或Google地图)。您只需将(lat,lng)对转换为JSTS坐标,其他所有操作都相同。例:
在我看来,您想要的是:
d
旧边的“左” 边的平行边替换边。生成的多边形位于距顶点“足够远”的旧多边形所需的距离处。d
正如您所说,在顶点附近,与旧多边形相隔一定距离的点集不是多边形,因此无法满足上述要求。
我不知道该算法是否具有名称,网络上的示例代码或恶意优化,但我认为它描述了您想要的内容。
在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
每条线应将平面分为“内侧”和“轮廓”;您可以使用常规的内积方法找出答案。
将所有线向外移动一定距离。
考虑所有成对的相邻线(线,而不是线段),找到交点。这些是新的顶点。
通过删除所有相交的部分来清理新顶点。-我们这里有一些情况
(a)情况1:
0--7 4--3
| | | |
| 6--5 |
| |
1--------2
如果您将其花费一倍,就会得到:
0----a----3
| | |
| | |
| b |
| |
| |
1---------2
7和4重叠..如果看到此点,则删除此点及其之间的所有点。
(b)情况2
0--7 4--3
| | | |
| 6--5 |
| |
1--------2
如果将其花费两倍,您将得到:
0----47----3
| || |
| || |
| || |
| 56 |
| |
| |
| |
1----------2
为了解决这个问题,对于每条线段,您必须检查它是否与后面的线段重叠。
(c)情况3
4--3
0--X9 | |
| 78 | |
| 6--5 |
| |
1--------2
支出1。这是情况1的更一般情况。
(d)情况4
与case3相同,但花费两个。
实际上,如果可以处理第4种情况,则所有其他情况仅是特殊情况,其中有些线或顶点重叠。
要进行第4种情况,您需要保留一堆顶点..当发现与后一条线重叠的线时按下,在获得后一条线时将其弹出。-就像您在凸包中所做的一样。
这是一个替代解决方案,请看您是否更喜欢它。
进行三角剖分,不一定要进行delaunay -任何三角剖分都可以。
给每个三角形充气-这应该是微不足道的。如果按逆时针顺序存储三角形,则只需将线移到右侧并进行相交即可。
使用改良的Weiler-Atherton裁剪算法合并它们
非常感谢Angus Johnson的Clipper库。在http://www.angusj.com/delphi/clipper.php#code上的clipper主页上有一些很好的代码示例可用于执行剪切操作, 但我没有看到多边形偏移的示例。所以我认为如果我发布代码,也许对某人有用:
public static List<Point> GetOffsetPolygon(List<Point> originalPath, double offset)
{
List<Point> resultOffsetPath = new List<Point>();
List<ClipperLib.IntPoint> polygon = new List<ClipperLib.IntPoint>();
foreach (var point in originalPath)
{
polygon.Add(new ClipperLib.IntPoint(point.X, point.Y));
}
ClipperLib.ClipperOffset co = new ClipperLib.ClipperOffset();
co.AddPath(polygon, ClipperLib.JoinType.jtRound, ClipperLib.EndType.etClosedPolygon);
List<List<ClipperLib.IntPoint>> solution = new List<List<ClipperLib.IntPoint>>();
co.Execute(ref solution, offset);
foreach (var offsetPath in solution)
{
foreach (var offsetPathPoint in offsetPath)
{
resultOffsetPath.Add(new Point(Convert.ToInt32(offsetPathPoint.X), Convert.ToInt32(offsetPathPoint.Y)));
}
}
return resultOffsetPath;
}
另一种选择是使用boost :: polygon-缺少文档,但是您应该发现实际上实现缓冲的方法resize
和bloat
以及重载+=
运算符。因此,例如,将某个多边形(或一组多边形)的大小增加某个值可以很简单:
poly += 2; // buffer polygon by 2
+=
多边形集,而不能使用单个多边形。尝试使用std :: vector多边形。(当然,向量只需要包含一个多边形)。
可以使用几个库(也可用于3D数据集)。
也可以找到这些库的相应出版物,以更详细地了解算法。
最后一个具有最低的依赖性,并且是自包含的,可以读取.obj文件。
最好的祝愿,斯蒂芬