我如何“膨胀”一个多边形?也就是说,我想做一些类似的事情:
要求是,新的(膨胀的)多边形的边/点与旧的(原始的)多边形的边/点的距离都是相同的(在示例图片上,它们不是,因为这样它就必须使用弧来膨胀顶点,但让我们暂时忘记这一点;))。
我要找的数学术语实际上是向内/向外多边形偏移。balint指出这一点+1。另一种命名是多边形缓冲。
我的搜索结果:
以下是一些链接:
多边形偏移策略综述 多边形偏移,问题 缓冲多边形数据
我如何“膨胀”一个多边形?也就是说,我想做一些类似的事情:
要求是,新的(膨胀的)多边形的边/点与旧的(原始的)多边形的边/点的距离都是相同的(在示例图片上,它们不是,因为这样它就必须使用弧来膨胀顶点,但让我们暂时忘记这一点;))。
我要找的数学术语实际上是向内/向外多边形偏移。balint指出这一点+1。另一种命名是多边形缓冲。
我的搜索结果:
以下是一些链接:
多边形偏移策略综述 多边形偏移,问题 缓冲多边形数据
当前回答
听起来你想要的是
Starting at a vertex, face anti-clockwise along an adjacent edge. Replace the edge with a new, parallel edge placed at distance d to the "left" of the old one. Repeat for all edges. Find the intersections of the new edges to get the new vertices. Detect if you've become a crossed polygon and decide what to do about it. Probably add a new vertex at the crossing-point and get rid of some old ones. I'm not sure whether there's a better way to detect this than just to compare every pair of non-adjacent edges to see if their intersection lies between both pairs of vertices.
生成的多边形位于所需的距离上,与旧多边形距离顶点“足够远”。在一个顶点附近,距离旧多边形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
对于这些类型的事情,我通常使用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坐标,其他一切都是相同的。例子:
这是这里解释的算法的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;
}
非常感谢安格斯·约翰逊的快船库。 在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;
}
根据@JoshO'Brian的建议,R语言中的rGeos包实现了这个算法。参见rGeos::gBuffer。