CodeGo.net>如何判断一个点是在林的右侧还是左侧

我有几点要点。 我想将它们分为2个不同的集合。 为此,我选择两个点(a和b)并在它们之间画一条假想线。 现在,我要使一组中的该行剩余的点和另一组中的该行右边的点。

如何确定给定点z是在左侧还是右侧? 我尝试计算a-z-b之间的角度-小于180度的角度在右侧,大于180度的左侧-但由于ArcCos的定义,计算出的角度始终小于180°。 是否存在用于计算大于180°的角度的公式(或用于选择右侧或左侧的任何其他公式)?

Aaginor asked 2019-11-15T13:32:43Z
13个解决方案
200 votes

尝试使用交叉产品的以下代码:

public bool isLeft(Point a, Point b, Point c){
     return ((b.X - a.X)*(c.Y - a.Y) - (b.Y - a.Y)*(c.X - a.X)) > 0;
}

其中a =线点1; b =线点2; c =要检查的点。

如果公式等于0,则这些点是共线的。

如果线是水平的,则如果该点在线的上方,则返回true。

jethro answered 2019-11-15T13:34:12Z
180 votes

使用向量行列式0的符号,其中+1是查询点:

position = sign((Bx - Ax) * (Y - Ay) - (By - Ay) * (X - Ax))

在线上为0,一侧为+1,另一侧为-1

Eric Bainville answered 2019-11-15T13:33:18Z
40 votes

你看一下行列式的符号

| x2-x1  x3-x1 |
| y2-y1  y3-y1 |

一侧的点为正,另一侧的点为负(线本身的点为零)。

AVB answered 2019-11-15T13:34:48Z
9 votes

向量(x3 - x1, y3 - y1)与该线垂直,并且始终指向右(如果平面方向与我的方向不同,则始终指向左)。

然后,您可以计算该向量与(x3 - x1, y3 - y1)的点积,以确定该点是否位于与垂直向量相同的直线的一侧(点积> 0)。

Victor Nicollet answered 2019-11-15T13:35:25Z
5 votes

我在Java中实现了这一点,并进行了单元测试(下面的源代码)。 以上解决方案均无效。 此代码通过了单元测试。 如果有人发现未通过的单元测试,请告诉我。

代码:注意:如果两个数字非常接近,则nearlyEqual(double,double)返回true。

/*
 * @return integer code for which side of the line ab c is on.  1 means
 * left turn, -1 means right turn.  Returns
 * 0 if all three are on a line
 */
public static int findSide(
        double ax, double ay, 
        double bx, double by,
        double cx, double cy) {
    if (nearlyEqual(bx-ax,0)) { // vertical line
        if (cx < bx) {
            return by > ay ? 1 : -1;
        }
        if (cx > bx) {
            return by > ay ? -1 : 1;
        } 
        return 0;
    }
    if (nearlyEqual(by-ay,0)) { // horizontal line
        if (cy < by) {
            return bx > ax ? -1 : 1;
        }
        if (cy > by) {
            return bx > ax ? 1 : -1;
        } 
        return 0;
    }
    double slope = (by - ay) / (bx - ax);
    double yIntercept = ay - ax * slope;
    double cSolution = (slope*cx) + yIntercept;
    if (slope != 0) {
        if (cy > cSolution) {
            return bx > ax ? 1 : -1;
        }
        if (cy < cSolution) {
            return bx > ax ? -1 : 1;
        }
        return 0;
    }
    return 0;
}

这是单元测试:

@Test public void testFindSide() {
    assertTrue("1", 1 == Utility.findSide(1, 0, 0, 0, -1, -1));
    assertTrue("1.1", 1 == Utility.findSide(25, 0, 0, 0, -1, -14));
    assertTrue("1.2", 1 == Utility.findSide(25, 20, 0, 20, -1, 6));
    assertTrue("1.3", 1 == Utility.findSide(24, 20, -1, 20, -2, 6));

    assertTrue("-1", -1 == Utility.findSide(1, 0, 0, 0, 1, 1));
    assertTrue("-1.1", -1 == Utility.findSide(12, 0, 0, 0, 2, 1));
    assertTrue("-1.2", -1 == Utility.findSide(-25, 0, 0, 0, -1, -14));
    assertTrue("-1.3", -1 == Utility.findSide(1, 0.5, 0, 0, 1, 1));

    assertTrue("2.1", -1 == Utility.findSide(0,5, 1,10, 10,20));
    assertTrue("2.2", 1 == Utility.findSide(0,9.1, 1,10, 10,20));
    assertTrue("2.3", -1 == Utility.findSide(0,5, 1,10, 20,10));
    assertTrue("2.4", -1 == Utility.findSide(0,9.1, 1,10, 20,10));

    assertTrue("vertical 1", 1 == Utility.findSide(1,1, 1,10, 0,0));
    assertTrue("vertical 2", -1 == Utility.findSide(1,10, 1,1, 0,0));
    assertTrue("vertical 3", -1 == Utility.findSide(1,1, 1,10, 5,0));
    assertTrue("vertical 3", 1 == Utility.findSide(1,10, 1,1, 5,0));

    assertTrue("horizontal 1", 1 == Utility.findSide(1,-1, 10,-1, 0,0));
    assertTrue("horizontal 2", -1 == Utility.findSide(10,-1, 1,-1, 0,0));
    assertTrue("horizontal 3", -1 == Utility.findSide(1,-1, 10,-1, 0,-9));
    assertTrue("horizontal 4", 1 == Utility.findSide(10,-1, 1,-1, 0,-9));

    assertTrue("positive slope 1", 1 == Utility.findSide(0,0, 10,10, 1,2));
    assertTrue("positive slope 2", -1 == Utility.findSide(10,10, 0,0, 1,2));
    assertTrue("positive slope 3", -1 == Utility.findSide(0,0, 10,10, 1,0));
    assertTrue("positive slope 4", 1 == Utility.findSide(10,10, 0,0, 1,0));

    assertTrue("negative slope 1", -1 == Utility.findSide(0,0, -10,10, 1,2));
    assertTrue("negative slope 2", -1 == Utility.findSide(0,0, -10,10, 1,2));
    assertTrue("negative slope 3", 1 == Utility.findSide(0,0, -10,10, -1,-2));
    assertTrue("negative slope 4", -1 == Utility.findSide(-10,10, 0,0, -1,-2));

    assertTrue("0", 0 == Utility.findSide(1, 0, 0, 0, -1, 0));
    assertTrue("1", 0 == Utility.findSide(0,0, 0, 0, 0, 0));
    assertTrue("2", 0 == Utility.findSide(0,0, 0,1, 0,2));
    assertTrue("3", 0 == Utility.findSide(0,0, 2,0, 1,0));
    assertTrue("4", 0 == Utility.findSide(1, -2, 0, 0, -1, 2));
}
Al Globus answered 2019-11-15T13:36:11Z
4 votes

使用直线ab的方程式,获得直线上的x坐标与要排序的点相同的y坐标。

  • 如果点的x>线的x,则该点在线的右侧。
  • 如果点的x <线的x,该点位于线的左侧。
  • 如果点的x ==线的x,则该点在该线上。
mbeckish answered 2019-11-15T13:37:02Z
4 votes

首先检查您是否有垂直线:

if (x2-x1) == 0
  if x3 < x2
     it's on the left
  if x3 > x2
     it's on the right
  else
     it's on the line

然后,计算斜率:(x3, y3)

然后,使用点斜率形式创建直线方程:(x3, y3)。为便于解释,将其简化为斜率截距形式(算法中不必要):x

现在为xy插入(x3, y3)。这是一些伪代码,详细说明了应该发生的情况:

if m > 0
  if y3 > m*x3 + b
    it's on the left
  else if y3 < m*x3 + b
    it's on the right
  else
    it's on the line
else if m < 0
  if y3 < m*x3 + b
    it's on the left
  if y3 > m*x3+b
    it's on the right
  else
    it's on the line
else
  horizontal line; up to you what you do
maksim answered 2019-11-15T13:37:57Z
1 votes

基本上,我认为对于任何给定的多边形,有一个简单且直接的解决方案,可以说由四个顶点(p1,p2,p3,p4)组成,在多边形中找到两个极端相反的顶点,在另一个多边形中 例如,找到最左上的顶点(让说p1)和位于最右下角的相反顶点(让说)。 因此,给定测试点C(x,y),现在您必须在C和p1之间以及C和p4之间进行仔细检查:

如果cx> p1x AND cy> p1y ==>表示C低于p1下一个如果cx <p2x AND cy <p2y ==>表示C在p4的上方和左侧

结论,C在矩形内。

谢谢 :)

Mohamed answered 2019-11-15T13:38:56Z
1 votes

假设点是(Ax,Ay)(Bx,By)和(Cx,Cy),则需要计算:

(Bx-Ax)*(Cy-Ay)-(By-Ay)*(Cx-Ax)

如果点C在由点A和B形成的线上,则该值等于零,并且根据边的不同,其符号也不同。 这取决于哪一侧,取决于(x,y)坐标的方向,但是您可以将A,B和C的测试值插入此公式中,以确定负值在左侧还是右侧。

user2154342 answered 2019-11-15T13:39:48Z
1 votes

@AVB在红宝石中的答案

det = Matrix[
  [(x2 - x1), (x3 - x1)],
  [(y2 - y1), (y3 - y1)]
].determinant

如果det是正数,则为上方;如果负数,则为下方。 如果为0,则就行了。

boulder_ruby answered 2019-11-15T13:40:24Z
1 votes

这是一个版本,再次使用Clojure编写的叉积逻辑。

(defn is-left? [line point]
  (let [[[x1 y1] [x2 y2]] (sort line)
        [x-pt y-pt] point]
    (> (* (- x2 x1) (- y-pt y1)) (* (- y2 y1) (- x-pt x1)))))

用法示例:

(is-left? [[-3 -1] [3 1]] [0 10])
true

也就是说,点(0,10)位于由(-3,-1)和(3,1)确定的线的左侧。

注意:此实现解决了其他问题(到目前为止)都没有解决的问题! 给定确定线的点时,顺序很重要。 也就是说,从某种意义上说,它是“定向线”。 因此,使用上面的代码,此调用还会产生true的结果:

(is-left? [[3 1] [-3 -1]] [0 10])
true

这是因为以下代码段:

(sort line)

最后,与其他基于叉积的解决方案一样,此解决方案返回布尔值,并且没有给出共线性的第三个结果。 但这会给出有意义的结果,例如:

(is-left? [[1 1] [3 1]] [10 1])
false
Purplejacket answered 2019-11-15T13:41:37Z
0 votes

我想提供一个受物理学启发的解决方案。

想象一下沿线施加的力,您正在测量围绕该点的力的扭矩。 如果扭矩为正(逆时针),则该点位于直线的“左侧”,但是如果扭矩为负,则该点为直线的“右侧”。

因此,如果力矢量等于定义直线的两点的跨度

fx = x_2 - x_1
fy = y_2 - y_1

您根据以下测试的符号测试点的侧面(px,py)

var torque = fx*(py-y_1)-fy*(px-x_1)
if  torque>0  then
     "point on left side"
else if torque <0 then
     "point on right side"  
else
     "point on line"
end if
ja72 answered 2019-11-15T13:42:30Z
0 votes

体验netter提供的解决方案的另一种方法是了解一些几何含义。

令pqr = [P,Q,R]是形成平面的点,该平面被线[P,R]分成2个边。 我们要找出pqr平面上的两个点A,B是否在同一侧。

pqr平面上的任何点T都可以用2个矢量表示:v = P-Q和u = R-Q,如下所示:

T'= T-Q = i * v + j * u

现在的几何含义:

  1. i + j = 1:公关线上的T
  2. i + j <1:S上的T
  3. i + j> 1:Snq上的T
  4. i + j = 0:T = Q
  5. i + j <0:Sq上的T并超出Q。

sign(a1+a2+a3-1) = sign(b1+b2+b3-1)

一般来说,

  • i + j是T距Q或[P,R]线有多远的度量,并且
  • i + j-1的符号表示T的侧面。

i和j的其他几何意义(与该解决方案无关)是:

  • i,j是新坐标系中T的标量,其中v,u是新轴,Q是新原点;
  • i,j分别视为P,R的拉力。 i越大,T与R的距离就越远(与P的距离越大)。

i,j的值可以通过求解以下方程式获得:

i*vx + j*ux = T'x
i*vy + j*uy = T'y
i*vz + j*uz = T'z

因此,我们在飞机上得到2点A,B:

sign(a1+a2+a3-1) = sign(b1+b2+b3-1)

如果A,B在同一侧,则为true:

sign(a1+a2+a3-1) = sign(b1+b2+b3-1)

请注意,这也适用于以下问题:A,B是否位于平面[P,Q,R]的同一侧,其中:

T = i * P + j * Q + k * R

i + j + k = 1表示T在平面[P,Q,R]上,i + j + k-1的符号表示其侧面。 由此我们得到:

sign(a1+a2+a3-1) = sign(b1+b2+b3-1)

如果A和B在[P,Q,R]平面的同一侧,

sign(a1+a2+a3-1) = sign(b1+b2+b3-1)

runsun answered 2019-11-15T13:46:38Z
translate from https://stackoverflow.com:/questions/3461453/determine-which-side-of-a-line-a-point-lies