我有一张包含很多多边形的地图,其中一个有一个点,如下所示:
多边形边缘的x和y坐标保存在这样的数据库中(例如):
Polygon(Point(11824, 10756), Point(11822, 10618), Point(11912, 10517), Point(12060, 10529), Point(12158, 10604), Point(12133, 10713), Point(12027, 10812), Point(11902, 10902)),
Polygon(Point(11077, 13610), Point(10949, 13642), Point(10828, 13584), Point(10772, 13480), Point(10756, 13353), Point(10849, 13256), Point(10976, 13224), Point(11103, 13294), Point(11171, 13414), Point(11135, 13558)),
Polygon(Point(11051.801757813, 11373.985351563), Point(11165.717773438, 11275.469726563), Point(11281.733398438, 11255.646484375), Point(11381.07421875, 11333.15625), Point(11440.202148438, 11467.706054688), Point(11404.73046875, 11584.534179688), Point(11301.662109375, 11643.852539063), Point(11169.486328125, 11644.079101563), Point(11067.555664063, 11579.676757813), Point(11018.21484375, 11454.750976563)),
Polygon(Point(12145, 13013), Point(12069.065429688, 13014.67578125), Point(12012.672851563, 12953.833984375), Point(11973.942382813, 12910.14453125), Point(11958.610351563, 12853.736328125), Point(11988.58203125, 12780.668945313), Point(12046.806640625, 12735.046875), Point(12117.080078125, 12729.838867188), Point(12185.567382813, 12743.389648438), Point(12225.575195313, 12803.530273438), Point(12255.934570313, 12859.2109375), Point(12263.861328125, 12914.166992188), Point(12221.2578125, 12978.983398438)),
它们稍后被绘制,我无法访问它,只能访问此坐标。 所以我有多边形边的x / y和红点的x / y。现在我必须知道红点是哪个多边形。
然后我需要的最重要的是:
我有红点的x和y坐标以及边缘的x y坐标。 我需要绿点的x和y坐标。(多边形外最近的位置)
我在lua中需要它,但我可以用任何语言回答,我可以翻译它。
答案 0 :(得分:4)
要知道该点在哪个多边形,您可以使用Ray Casting algorithm。
为了找到最近的边缘,您可以使用简单的方法计算distance to each edge,然后采用最小值。只需记住检查边缘的交点是否在边缘之外(检查this)。如果它在外面,则距离边缘最近的极端。
更好用一些伪代码解释直觉:
dot(u,v) --> ((u).x * (v).x + (u).y * (v).y)
norm(v) --> sqrt(dot(v,v)) // norm = length of vector
dist(u,v)--> norm(u-v) // distance = norm of difference
// Vector contains x and y
// Point contains x and y
// Segment contains P0 and P1 of type Point
// Point = Point ± Vector
// Vector = Point - Point
// Vector = Scalar * Vector
Point closest_Point_in_Segment_to(Point P, Segment S)
{
Vector v = S.P1 - S.P0;
Vector w = P - S.P0;
double c1 = dot(w,v);
if ( c1 <= 0 ) // the closest point is outside the segment and nearer to P0
return S.P0;
double c2 = dot(v,v);
if ( c2 <= c1 ) // the closest point is outside the segment and nearer to P1
return S.P1;
double b = c1 / c2;
Point Pb = S.P0 + b * v;
return Pb;
}
[Point, Segment] get_closest_border_point_to(Point point, Polygon poly) {
double bestDistance = MAX_DOUBLE;
Segment bestSegment;
Point bestPoint;
foreach s in poly.segments {
Point closestInS = closest_Point_in_Segment_to(point, s);
double d = dist(point, closestInS);
if (d < bestDistance) {
bestDistance = d;
bestSegment = s;
bestPoint = closestInS;
}
}
return [bestPoint, bestSegment];
}
我认为这个伪代码应该让你去,当然,一旦你有了多边形,你的观点就在了!。
答案 1 :(得分:1)
我的PolyCollisions
课程:
public class PolyCollisions {
// Call this function...
public static Vector2 doCollisions (Vector2[] polygon, Vector2 point) {
if(!pointIsInPoly(polygon, point)) {
// The point is not colliding with the polygon, so it does not need to change location
return point;
}
// Get the closest point of the polygon
return closestPointOutsidePolygon(polygon, point);
}
// Check if the given point is within the given polygon (Vertexes)
//
// If so, call on collision if required, and move the point to the
// closest point outside of the polygon
public static boolean pointIsInPoly(Vector2[] verts, Vector2 p) {
int nvert = verts.length;
double[] vertx = new double[nvert];
double[] verty = new double[nvert];
for(int i = 0; i < nvert; i++) {
Vector2 vert = verts[i];
vertx[i] = vert.x;
verty[i] = vert.y;
}
double testx = p.x;
double testy = p.y;
int i, j;
boolean c = false;
for (i = 0, j = nvert-1; i < nvert; j = i++) {
if ( ((verty[i]>testy) != (verty[j]>testy)) &&
(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
c = !c;
}
return c;
}
// Gets the closed point that isn't inside the polygon...
public static Vector2 closestPointOutsidePolygon (Vector2[] poly, Vector2 point) {
return getClosestPointInSegment(closestSegment(poly, point), point);
}
public static Vector2 getClosestPointInSegment (Vector2[] segment, Vector2 point) {
return newPointFromCollision(segment[0], segment[1], point);
}
public static Vector2 newPointFromCollision (Vector2 aLine, Vector2 bLine, Vector2 p) {
return nearestPointOnLine(aLine.x, aLine.y, bLine.x, bLine.y, p.x, p.y);
}
public static Vector2 nearestPointOnLine(double ax, double ay, double bx, double by, double px, double py) {
// https://stackoverflow.com/questions/1459368/snap-point-to-a-line-java
double apx = px - ax;
double apy = py - ay;
double abx = bx - ax;
double aby = by - ay;
double ab2 = abx * abx + aby * aby;
double ap_ab = apx * abx + apy * aby;
double t = ap_ab / ab2;
if (t < 0) {
t = 0;
} else if (t > 1) {
t = 1;
}
return new Vector2(ax + abx * t, ay + aby * t);
}
public static Vector2[] closestSegment (Vector2[] points, Vector2 point) {
Vector2[] returns = new Vector2[2];
int index = closestPointIndex(points, point);
returns[0] = points[index];
Vector2[] neighbors = new Vector2[] {
points[(index+1+points.length)%points.length],
points[(index-1+points.length)%points.length]
};
double[] neighborAngles = new double[] {
getAngle(new Vector2[] {point, returns[0], neighbors[0]}),
getAngle(new Vector2[] {point, returns[0], neighbors[1]})
};
// The neighbor with the lower angle is the one to use
if(neighborAngles[0] < neighborAngles[1]) {
returns[1] = neighbors[0];
} else {
returns[1] = neighbors[1];
}
return returns;
}
public static double getAngle (Vector2[] abc) {
// https://stackoverflow.com/questions/1211212/how-to-calculate-an-angle-from-three-points
// atan2(P2.y - P1.y, P2.x - P1.x) - atan2(P3.y - P1.y, P3.x - P1.x)
return Math.atan2(abc[2].y - abc[0].y, abc[2].x - abc[0].x) - Math.atan2(abc[1].y - abc[0].y, abc[1].x - abc[0].x);
}
public static int closestPointIndex (Vector2[] points, Vector2 point) {
int leastDistanceIndex = 0;
double leastDistance = Double.MAX_VALUE;
for(int i = 0; i < points.length; i++) {
double dist = distance(points[i], point);
if(dist < leastDistance) {
leastDistanceIndex = i;
leastDistance = dist;
}
}
return leastDistanceIndex;
}
public static double distance (Vector2 a, Vector2 b) {
return Math.sqrt(Math.pow(Math.abs(a.x-b.x), 2)+Math.pow(Math.abs(a.y-b.y), 2));
}
}
这里有一个小小的解释(有趣的事实:这是我发布的第一个图像堆栈溢出!)
对不起,它太乱了......
恭喜!你幸免于糟糕的教程!希望它有帮助:) +感谢所有评论链接到答案,帮助我帮助你!
答案 2 :(得分:0)
这是答案@nathanfranke的C#版本
using System;
using Windows.Foundation;
using Windows.UI.Xaml.Shapes;
using System.Numerics;
public class PolyCollisions
{
// Call this function...
public static Vector2 DoCollisions(Vector2[] polygon, Vector2 point)
{
if (!PointIsInPoly(polygon, point))
{
// The point is not colliding with the polygon, so it does not need to change location
return point;
}
// Get the closest point of the polygon
return ClosestPointOutsidePolygon(polygon, point);
}
// Check if the given point is within the given polygon (Vertexes)
//
// If so, call on collision if required, and move the point to the
// closest point outside of the polygon
public static bool PointIsInPoly(Vector2[] verts, Vector2 p)
{
int nvert = verts.Length;
double[] vertx = new double[nvert];
double[] verty = new double[nvert];
for (int d = 0; d < nvert; d++)
{
Vector2 vert = verts[d];
vertx[d] = vert.X;
verty[d] = vert.Y;
}
double testx = p.X;
double testy = p.Y;
int i, j;
bool c = false;
for (i = 0, j = nvert - 1; i < nvert; j = i++)
{
if (((verty[i] > testy) != (verty[j] > testy)) && (testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i]))
c = !c;
}
return c;
}
// Gets the closed point that isn't inside the polygon...
public static Vector2 ClosestPointOutsidePolygon(Vector2[] poly, Vector2 point)
{
return GetClosestPointInSegment(ClosestSegment(poly, point), point);
}
public static Vector2 GetClosestPointInSegment(Vector2[] segment, Vector2 point)
{
return NewPointFromCollision(segment[0], segment[1], point);
}
public static Vector2 NewPointFromCollision(Vector2 aLine, Vector2 bLine, Vector2 p)
{
return NearestPointOnLine(aLine.X, aLine.Y, bLine.X, bLine.Y, p.X, p.Y);
}
public static Vector2 NearestPointOnLine(double ax, double ay, double bx, double by, double px, double py)
{
// https://stackoverflow.com/questions/1459368/snap-point-to-a-line-java
double apx = px - ax;
double apy = py - ay;
double abx = bx - ax;
double aby = by - ay;
double ab2 = abx * abx + aby * aby;
double ap_ab = apx * abx + apy * aby;
double t = ap_ab / ab2;
if (t < 0)
{
t = 0;
}
else if (t > 1)
{
t = 1;
}
return new Vector2((float)(ax + (abx * t)), (float)(ay + aby * t));
}
public static Vector2[] ClosestSegment(Vector2[] points, Vector2 point)
{
Vector2[] returns = new Vector2[2];
int index = ClosestPointIndex(points, point);
returns[0] = points[index];
Vector2[] neighbors = new Vector2[] {
points[(index+1+points.Length)%points.Length],
points[(index-1+points.Length)%points.Length]
};
double[] neighborAngles = new double[] {
GetAngle(new Vector2[] {point, returns[0], neighbors[0]}),
GetAngle(new Vector2[] {point, returns[0], neighbors[1]})
};
// The neighbor with the lower angle is the one to use
if (neighborAngles[0] < neighborAngles[1])
{
returns[1] = neighbors[0];
}
else
{
returns[1] = neighbors[1];
}
return returns;
}
public static double GetAngle(Vector2[] abc)
{
// https://stackoverflow.com/questions/1211212/how-to-calculate-an-angle-from-three-points
// atan2(P2.y - P1.y, P2.x - P1.x) - atan2(P3.y - P1.y, P3.x - P1.x)
return Math.Atan2(abc[2].X - abc[0].Y, abc[2].X - abc[0].X) - Math.Atan2(abc[1].Y - abc[0].Y, abc[1].X - abc[0].X);
}
public static int ClosestPointIndex(Vector2[] points, Vector2 point)
{
int leastDistanceIndex = 0;
double leastDistance = Double.MaxValue;
for (int i = 0; i < points.Length; i++)
{
double dist = Distance(points[i], point);
if (dist < leastDistance)
{
leastDistanceIndex = i;
leastDistance = dist;
}
}
return leastDistanceIndex;
}
public static double Distance(Vector2 a, Vector2 b)
{
return Math.Sqrt(Math.Pow(Math.Abs(a.X - b.X), 2) + Math.Pow(Math.Abs(a.Y - b.Y), 2));
}
}