我正在寻找有关最佳方法的建议。我试图找出给定点A:(a,b)是否在正六边形内,用中心O定义:( x,y)和外接圆的直径。
对于这样一个简单的情况,使用Ray-casting或Winding-number来确定这个似乎有点过分了,我现在正在寻找找到OA线的角度(从水平方向)的选项,以及将它标准化(可能不是正确的单词)到6个等边三角形中的一个,看看这个新点是否在这个三角形内。
我感觉我错过了一些简单的东西,并且有一种简单方法(或者如果我真的很幸运,一个Java API)来简单有效地完成这项工作。
感谢您的帮助。
编辑:六边形的方向使得其中一边与水平面平齐。
答案 0 :(得分:8)
如果您将问题缩小到检查单个象限中的{x = 0, y = 0, d = 1}
,则可以非常简单。
public boolean IsInsideHexagon(float x0, float y0, float d, float x, float y) {
float dx = Math.abs(x - x0)/d;
float dy = Math.abs(y - y0)/d;
float a = 0.25 * Math.sqrt(3.0);
return (dy <= a) && (a*dx + 0.25*dy <= 0.5*a);
}
dy <= a
检查该点是否低于水平边缘。a*dx + 0.25*dy <= 0.5*a
检查该点位于倾斜右边缘的左侧。对于{x0 = 0, y0 = 0, d = 1}
,角点为(±0.25, ±0.43)
和(±0.5, 0.0)
。
答案 1 :(得分:6)
您可以使用六边形的每个边的方程式;通过它们,您可以了解给定点是否与六边形的中心位于同一半平面中。
例如,右上角有等式:
-sqrt(3)x - y + sqrt(3)/2 = 0
您可以插入点的坐标,然后插入中心的坐标。如果结果具有相同的符号,则该点位于左下半平面中(因此它可能位于六边形内)。
然后使用其他方面的方程式重复 请注意,此算法适用于任何凸多边形。
答案 2 :(得分:6)
这就是我一直在使用的:
public bool InsideHexagon(float x, float y)
{
// Check length (squared) against inner and outer radius
float l2 = x * x + y * y;
if (l2 > 1.0f) return false;
if (l2 < 0.75f) return true; // (sqrt(3)/2)^2 = 3/4
// Check against borders
float px = x * 1.15470053838f; // 2/sqrt(3)
if (px > 1.0f || px < -1.0f) return false;
float py = 0.5f * px + y;
if (py > 1.0f || py < -1.0f) return false;
if (px - py > 1.0f || px - py < -1.0f) return false;
return true;
}
px
和py
是投射到坐标系上的x
和y
的坐标,可以更容易地检查边界。
答案 3 :(得分:4)
看起来你知道一般解决方案:“使用......似乎有些过分了”。所以这是我的想法:
计算从点到中心的距离,我们称之为l
。
然后你可以将它与inradius(r
)和circumradius(R
)进行比较。如果l < r
则点在六边形内,如果l > R
则在外面。如果r < l < R
那么你必须分别检查每一方,但由于R - r
非常小(十六进制边长的13%),所以你必须进行复杂计算的可能性很小。
答案 4 :(得分:1)
我首先检查点是否在内切圆内(您可以轻松计算内切圆半径)或外接圆(您已经拥有)之外。
第一个意味着该点在,后者意味着它已经出局。
据统计,大多数输入点应该允许您根据上述简单测试来决定。
对于最坏的情况(点位于内切圆和外接圆之间),我认为你可以找到最接近该点的两个顶点,然后看到该点V1V2的哪一侧(内部或外部,相对于O中心)。 特殊情况:点等于其中一个顶点=&gt;它在。
如果我有一个更聪明的想法(或者我将开始真正学习三角学),我会编辑答案让你知道:)
答案 5 :(得分:0)
从点P中减去六边形中心的位置,得到一个向量V.然后,用下面的向量取V的点积,这对应于三对相对的六边形边缘:
[0,1] ; the edges that are flat with the horizontal
[cos(30),sin(30)] ; the upper-right and lower-left edges
[cos(-30),sin(-30)] ; the lower-right and upper-left edges
如果任何点积的幅度大于从六边形中心到其中一个边缘的距离,则该点不在六边形内。
作为参考,矢量[a,b]和[c,d]的点积为a * c + b * d。
上面的角度“30”以度为单位;)
答案 6 :(得分:0)
你想要的是找出一个点是否在凸多边形内的代码,六边形是一个特殊情况。
这是一个很好的答案: https://stackoverflow.com/a/34689268/516188
我确实修改了该功能供我使用,我发现我的版本更清晰。这是打字稿(你只是斜视和它的javascript):
function vectorX(v: Vector): number {
return v[1].x - v[0].x;
}
function vectorY(v: Vector): number {
return v[1].y - v[0].y;
}
function crossProduct(v1: Vector, v2: Vector): number {
return vectorX(v1)*vectorY(v2) - vectorY(v1)*vectorX(v2);
}
function isInConvexPolygon(testPoint: Point, polygon: Polygon): boolean {
// https://stackoverflow.com/a/34689268/516188
if (polygon.length < 3) {
throw "Only supporting polygons of length at least 3";
}
// going through all the edges around the polygon. compute the
// vector cross-product http://allenchou.net/2013/07/cross-product-of-2d-vectors/
// to find out for each edge on which side of the edge is the point.
// if the point is on the same side for all the edges, it's inside
let initCrossIsPositive = undefined;
for (var i=0;i<polygon.length;i++) {
if (polygon[i].x === testPoint.x &&
polygon[i].y === testPoint.y) {
// testPoint is an edge of the polygon
return true;
}
const curPointOnEdge = polygon[i];
const nextPointOnEdge = polygon[(i+1)%polygon.length];
const vector1 = <[Point,Point]>[curPointOnEdge, nextPointOnEdge];
const vector2 = <[Point,Point]>[curPointOnEdge, testPoint];
const cross = crossProduct(vector1, vector2);
if (initCrossIsPositive === undefined) {
initCrossIsPositive = cross > 0;
} else {
if (initCrossIsPositive !== (cross > 0)) {
return false;
}
}
}
// all the cross-products have the same sign: we're inside
return true;
}
答案 7 :(得分:0)
使用均质坐标对十六进制晶格有一个很好的概括,将晶格表示为与平面 x + y + z = 0相交的立方晶格,请参见https://www.redblobgames.com/grids/hexagons/#coordinates < / p>