给出四个(x,y)对代表2d空间中任意多边形(四边形)的四个角,我想确定:
我正在将此作为图像处理程序的一部分,因此假设Y轴被翻转(即正值从顶部向下移动)。
我的第一个想法是获取多边形的边界框,然后测量每个顶点距边界框角落的距离。然后,对于多边形的每个顶点,确定它最接近的边界框的哪个角并相应地标记它。这对多边形不起作用,例如:
http://matt.bridges.name/polygon.png
多边形的左上角顶点最靠近边界框的右上角。它也不是最接近边界框左上角的顶点。
答案 0 :(得分:4)
为了确定多边形是否是凸的,你可以使用与Graham scan中使用的类似的东西,并通过这些点,检查你是否每次都有一个右转(或左转)。
为了确定哪个角落在哪里,你可以看看哪个点的x和y最小;并选择其中一个作为左下角。他们可能会合作,这很好,但如果没有,那么,并不总是很容易分辨出应该在左下角,例如:
"Bottom left corner" is quite ambiguous http://a.imagehost.org/0894/bottomleftiswhich.png
一旦你确定了你的左下角哪一个,你可以简单地按顺序浏览角落并相应地标记它们。要了解他们的订单,只需检查您是否通过上述检查做出了正确或全部左转。
答案 1 :(得分:1)
现在我已经明确地说明了这个问题了另一个解决方案:
有更简单的方法吗?
答案 2 :(得分:1)
如果两个对角线都在四边形内并因此相交,则四边形是凸的。左下角是交叉点下方和左侧的点。模拟条件适用于其他三个角落。
如果您事先不知道点的顺序,则不知道对角,因此对角线。在这种情况下,您必须计算所有可能的六个段的交叉点。如果多边形是凸的,您将获得一个交叉点,您可以使用它来确定四个角。如果多边形不是凸面,则没有交点。
<强>更新强>
我创建了一个小型的C#程序来测试我的建议。凸凹检测的工作方式与预期相同,但仍存在角点检测失败的情况(参见代码中的测试用例3)。但解决这个问题应该很简单。
<强> CODE 强>
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
namespace Quadrilaterals
{
public class Program
{
public static void Main()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
Int32[,] tests = { { 0, 1, 2, 3 }, { 0, 2, 1, 3 }, { 0, 3, 1, 2 } };
PointF[] points = { new PointF(4, -2), new PointF(2, 5), new PointF(8, -6), new PointF(10, 7) };
//PointF[] points = { new PointF(0, 0), new PointF(10, 0), new PointF(5, 10), new PointF(5, 3) };
//PointF[] points = { new PointF(4, -2), new PointF(3, -1), new PointF(0, 0), new PointF(1, 0) };
PointF? p = null;
for (Int32 i = 0; i < 3; i++)
{
Console.WriteLine("Intersecting segments ({0}|{1}) and ({2}|{3}).", tests[i, 0], tests[i, 1], tests[i, 2], tests[i, 3]);
Single? f1 = IntersectLines(points[tests[i, 0]], points[tests[i, 1]], points[tests[i, 2]], points[tests[i, 3]]);
Single? f2 = IntersectLines(points[tests[i, 2]], points[tests[i, 3]], points[tests[i, 0]], points[tests[i, 1]]);
if ((f1 != null) && (f2 != null))
{
PointF pp = PointOnLine(points[tests[i, 0]], points[tests[i, 1]], f1.Value);
Console.WriteLine(" Lines intersect at ({0}|{1}) with factors {2} and {3}.", pp.X, pp.Y, f1, f2);
if ((f1 > 0) && (f1 < 1) && (f2 > 0) && (f2 < 1))
{
Console.WriteLine(" Segments intersect.");
p = pp;
}
else
{
Console.WriteLine(" Segments do not intersect.");
}
}
else
{
Console.WriteLine(" Lines are parallel.");
}
}
if (p == null)
{
Console.WriteLine("The quadrilateral is concave.");
}
else
{
Console.WriteLine("The quadrilateral is convex.");
for (Int32 j = 0; j < 4; j++)
{
Console.WriteLine(" Point {0} ({3}|{4}) is the {1} {2} corner.", j, (points[j].Y < p.Value.Y) ? "bottom" : "top", (points[j].X < p.Value.X) ? "left" : "right", points[j].X, points[j].Y);
}
}
Console.ReadLine();
}
private static Single? IntersectLines(PointF a1, PointF a2, PointF b1, PointF b2)
{
PointF r = Difference(a1, b1);
PointF a = Difference(a2, a1);
PointF b = Difference(b2, b1);
Single p = r.X * b.Y - r.Y * b.X;
Single q = a.Y * b.X - a.X * b.Y;
return (Math.Abs(q) > Single.Epsilon) ? (p / q) : (Single?)null;
}
private static PointF Difference(PointF a, PointF b)
{
return new PointF(a.X - b.X, a.Y - b.Y);
}
private static PointF PointOnLine(PointF a, PointF b, Single f)
{
return new PointF(a.X + f * (b.X - a.X), a.Y + f * (b.Y - a.Y));
}
}
}
<强>输出强>
Intersecting segments (0|1) and (2|3).
Lines intersect at (7|-12.5) with factors -1.5 and -0.5.
Segments do not intersect.
Intersecting segments (0|2) and (1|3).
Lines intersect at (-2|4) with factors -1.5 and -0.5.
Segments do not intersect.
Intersecting segments (0|3) and (1|2).
Lines intersect at (5|-0.4999999) with factors 0.1666667 and 0.5.
Segments intersect.
The quadrilateral is convex.
Point 0 (4|-2) is the bottom left corner.
Point 1 (2|5) is the top left corner.
Point 2 (8|-6) is the bottom right corner.
Point 3 (10|7) is the top right corner.