判断两个点是否在javascript中的一条线的同一侧

发布于 2024-11-07 04:58:32 字数 3201 浏览 0 评论 0原文

假设我有两个点代表一条线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 中可用的东西。

编辑:这是我实际的六边形函数,给出了以下答案。这个问题的答案就在 update 函数中。

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 的结果相乘,如果结果 > ,则将 B 和 C 的结果相乘。 0 则它们要么都是正值,要么都是负值。我正在使用 setInterval 将六边形渲染并更新到画布中。

Suppose I have two points representing a line A, such as:

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

And I have two other points B and C such as:

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

How would I determine if B and C are both on the same side of line A? To add a little context, I am trying to do hit testing for a hexagon, where B is the center point of the hexagon, C is the current mouse position and A is each line of the hexagon. All of these points are essentially pixel coordinates where 0,0 is the upper left hand corner.

I don't need this to be blazing fast I am just trying to create the simplest possible hexagon hit test algorithm I can. My theory is that if I can determine that C is on the same side of each line of the hexagon as B then the hit test is successful. I have read several mathematical algorithms for doing this but they always seem to be in a different type of coordinate system and I'm struggling to translate it into something usable in javascript.

EDIT: here is my actual Hexagon function given the answer below. The answer to this question is in the update function.

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)
}

To determine same-sidedness I multiplied the results of B and C and if the result is > 0 then they are either both positive or both negative. I'm rendering and updating the hexagon into a canvas on a loop using setInterval.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一页 2024-11-14 04:58:32

代表 A 的直线由向量 v = { x: 420 - 385, y: 400 - 380 } = { x: 35, y: 20 } 和起点 P = 描述{x:385,y:380}。给定一个 2d 向量 (x, y),向量 (y, -x) 始终与其成直角。因此向量 w = { x: 20, y: -35 }v 成直角。线性代数告诉我们,(B - P) 点 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 的起点并且面向终点,则两个点都将位于您的左侧。 (左边为负,右边为正。)

The line representing A is described by the vector v = { x: 420 - 385, y: 400 - 380 } = { x: 35, y: 20 } and the starting point P = { x: 385, y: 380 }. Given a vector (x, y) in 2d, the vector (y, -x) is always at right angles to it. So the vector w = { x: 20, y: -35 } is at right angles to v. Linear algebra tells us that the sign of (B - P) dot w tells us which side of the line you are on where dot is the standard dot product. (The line itself is at zero.)

Therefore in your example the calculation we need to do is this:

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

Since the sign is the same, they are on the same side.

In fact we can say more. If you are at the starting point of A and are facing the ending point, both points will be on your left hand side. (The left side will be negative, the right side will be positive.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文