开发者

Determine if two points are on the same side of a line in javascript

开发者 https://www.devze.com 2023-03-05 19:44 出处:网络
Suppose I have two points representing a line A, such as: var A = [ { x: 385, y: 380 }, { x: 420, y: 400开发者_如何学Python }]

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

var A = [ { x: 385, y: 380 }, { x: 420, y: 400开发者_如何学Python }]

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.


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

0

精彩评论

暂无评论...
验证码 换一张
取 消