【问题标题】:Determine if two points are on the same side of a line in javascript确定两个点是否在javascript中一条线的同一侧
【发布时间】:2011-05-12 04:41:36
【问题描述】:

假设我有两个点代表一条线A,如:

var A = [ { x: 385, y: 380 }, { x: 420, y: 400 }]

我还有另外两个点 B 和 C,例如:

var B = { x: 385, y: 420 }
var C = { x: 405, y: 423 }

如何确定 B 和 C 是否都在 A 线的同一侧?为了添加一点上下文,我正在尝试对六边形进行命中测试,其中 B 是六边形的中心点,C 是当前鼠标位置,A 是六边形的每一行。所有这些点本质上都是像素坐标,其中 0,0 是左上角。

我不需要这个速度很快,我只是想尽可能创建最简单的六边形命中测试算法。我的理论是,如果我可以确定 C 与 B 位于六边形每条线的同一侧,则命中测试成功。我已经阅读了几种用于执行此操作的数学算法,但它们似乎总是在不同类型的坐标系中,我正在努力将其转换为可在 javascript 中使用的东西。

编辑:这是我的实际 Hexagon 函数,给出的答案如下。这个问题的答案在更新函数中。

var TILE_WIDTH = 70
var TILE_HEIGHT = 80

function Hexagon(x, y) {
    var normalColor = 'rgb(207, 226, 243)'
    var hilightColor = 'rgb(204, 204, 204)'
    var currentColor = normalColor

    var coords = new TileCoordinates(x, y)
    var points = [
        { x: coords.x, y: coords.y - TILE_HEIGHT / 2 },
        { x: coords.x + TILE_WIDTH / 2, y: coords.y - TILE_HEIGHT / 4 },
        { x: coords.x + TILE_WIDTH / 2, y: coords.y + TILE_HEIGHT / 4 },
        { x: coords.x, y: coords.y + TILE_HEIGHT / 2 },
        { x: coords.x - TILE_WIDTH / 2, y: coords.y + TILE_HEIGHT / 4 },
        { x: coords.x - TILE_WIDTH / 2, y: coords.y - TILE_HEIGHT / 4 },
    ]

    var sides = [
        [points[0], points[1]],
        [points[1], points[2]],
        [points[2], points[3]],
        [points[3], points[4]],
        [points[4], points[5]],
        [points[5], points[0]]
    ]

    this.update = function (totalTime, updateTime) {

        var B = coords
        var C = Mouse.state
        var inside = C != null
        if (inside) {
            for (i in sides) {
                var A = sides[i]
                var w = { y: A[1].x - A[0].x, x: -(A[1].y - A[0].y) }
                var P = A[1]

                inside = ((B.x - P.x) * w.x + (B.y - P.y) * w.y) * ((C.x - P.x) * w.x + (C.y - P.y) * w.y) > 0
                if (!inside) break
            }
        }

        if (inside)
            currentColor = hilightColor
        else
            currentColor = normalColor
    }

    this.draw = function (ctx) {
        ctx.fillStyle = currentColor
        ctx.strokeStyle = 'rgb(11, 83, 148)'
        ctx.beginPath()
        ctx.moveTo(points[0].x, points[0].y)
        ctx.lineTo(points[1].x, points[1].y)
        ctx.lineTo(points[2].x, points[2].y)
        ctx.lineTo(points[3].x, points[3].y)
        ctx.lineTo(points[4].x, points[4].y)
        ctx.lineTo(points[5].x, points[5].y)
        ctx.lineTo(points[0].x, points[0].y)
        ctx.fill()
        ctx.stroke()

        ctx.fillStyle = '#000'
        var text = coords.pos_x + ',' + coords.pos_y
        var measure = ctx.measureText(text)
        ctx.fillText(text, coords.x - measure.width / 2, coords.y + 12 + (TILE_HEIGHT / 4))
    }
}

// this is in a separate function because other objects that render into the hex
// need the pixel coordinates of the tile also
function TileCoordinates(x, y) {
    this.pos_x = x
    this.pos_y = y
    this.x = x * TILE_WIDTH + ((y + 1) * TILE_WIDTH / 2)
    this.y = (y + 1) * (3 / 4 * TILE_HEIGHT)
}

为了确定同边性,我将 B 和 C 的结果相乘,如果结果 > 0,那么它们要么都是正的,要么都是负的。我正在使用 setInterval 在循环中将六边形渲染并更新到画布中。

【问题讨论】:

  • 如果您不打算发布您选择的算法,至少发布一些您找到的算法的链接。在我的头顶上,如果线是 AB 并且点是 C 和 D,那么如果角度 ABD 和 ABC 都大于 180 或都小于 180,则 D 和 C“在同一侧”。
  • 不完全回答您的问题,但stackoverflow.com/questions/217578/… 总体上对多边形命中测试有一些很好的答案。
  • 是的,我认为这非常接近。尽管我特意试图以我能理解的方式将其放入 javascript 术语中。谢谢。

标签: javascript math lines points hittest


【解决方案1】:

表示 A 的线由向量v = { x: 420 - 385, y: 400 - 380 } = { x: 35, y: 20 } 和起点P = { x: 385, y: 380 } 描述。给定二维向量(x, y),向量(y, -x) 总是与其成直角。所以向量w = { x: 20, y: -35 }v 成直角。线性代数告诉我们(B - P) dot w 的符号告诉我们你在直线的哪一边dot 是标准点积。 (线本身为零。)

因此,在您的示例中,我们需要做的计算是这样的:

For B:
(B - P) dot w
  = { x: 385 - 385, y: 420 - 380 } dot { x: 20, y: -35 }
  = { x: 0, y: 40} dot { x: 20, y: -35 }
  = (0 * 20) + (40 * (-35))
  = -1400

For C:
(C - P dot w
  = { x: 405 - 385, y: 423 - 380 } dot { x: 20, y: -35 }
  = { x: 20, y: 43} dot { x: 20, y: -35 }
  = (20 * 20) + (43 * (-35))
  = -1105

由于标志相同,所以它们在同一侧。

其实我们可以说更多。如果您位于A 的起点并面向终点,则两个点都在您的左侧。 (左边为负,右边为正。)

【讨论】:

  • 漂亮,OP只需要针对一般情况进行编程。有测量背景,我用角度解决了它,但你的解决方案要优雅得多。我希望你不介意我捏你的算法——当然是完整的归属。 :-)
  • 哦,还有一件额外的事情 - OP 真的应该测试任何一个点是否在线(或者考虑到 ECMAScript 数字中的小不准确,非常接近)并决定这意味着什么。如果有一点在直线上,结果应该是它们都在同一边,不在同一边,还是未定义?
  • @RobG - 随意捏它,不注明出处。这是一种标准技术。 :-)
  • 就像一个魅力!我现在将使用我的实际 Hexagon 函数更新我的原始帖子。
  • 我不知道这对你有什么用。应该是叉积,不是点积! (A x B = a1*b2 - a2*b1)我有超过 200 个不重叠三角形的大场,并测试了 30 个点。使用点积,点都在多个三角形中;使用叉积,每个点都在一个三角形中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-06
  • 1970-01-01
  • 1970-01-01
  • 2011-04-18
相关资源
最近更新 更多