这是另一个多边形的直线骨架:
如其他评论所指出的那样,根据你计划“膨胀/收缩”多边形的程度,输出的连通性可能会有所不同。对于这些类型的事情,我通常使用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 Maps)。您只需将(纬度,经度)对转换为JSTS坐标,其余部分都是相同的。 示例:
d
。所得到的多边形距离旧多边形要求的距离“足够远”,远离顶点。在接近顶点的地方,与旧多边形距离为 d
的点集合,正如您所说,不是多边形,因此无法满足所述要求。
我不知道这个算法是否有名称、网络上的示例代码或者有没有更加巧妙的优化方式,但我认为这描述了您想要的内容。
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
0----47----3
| || |
| || |
| || |
| 56 |
| |
| |
| |
1----------2
4--3
0--X9 | |
| 78 | |
| 6--5 |
| |
1--------2
扩展1。这是第一种情况的更普遍情况。
(d) 第4种情况
与第3种情况相同,但是需要扩展两个。
实际上,如果您可以处理第4种情况,则所有其他情况都只是它的特殊情况,其中一些线或顶点重叠。
要处理第4种情况,您需要保留一个顶点堆栈。当您发现某些线与后面的线重叠时,请将其推入堆栈中;当您到达后面的线时,请将其弹出 - 就像在凸包中所做的那样。
感谢Angus Johnson提供的clipper库。 在clipper主页上有关于裁剪操作的良好代码示例,网址为http://www.angusj.com/delphi/clipper.php#code 但是我没有看到关于多边形偏移的示例。因此,我认为如果我发布我的代码可能对某些人有用:
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;
}
这里有一种替代方案,看看你是否喜欢这个更好。
进行三角剖分,不一定要是Delaunay-任何三角剖分都可以。
膨胀每个三角形-这应该很简单。如果你按逆时针顺序存储三角形,只需将线移动到右侧并进行交集。
使用修改后的Weiler-Atherton剪切算法合并它们
另一种选择是使用boost::polygon - 虽然文档有些缺失,但您会发现方法resize
和bloat
,以及重载的+=
运算符实际上实现了缓冲。例如,将多边形(或一组多边形)的大小增加某个值可以非常简单地完成:
poly += 2; // buffer polygon by 2