Определите, находятся ли две точки на одной стороне линии в JavaScript - PullRequest
1 голос
/ 12 мая 2011

Предположим, у меня есть две точки, представляющие линию 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.

EDIT: Вот моя фактическая функция шестиугольника, учитывая ответ ниже.Ответ на этот вопрос находится в функции обновления.

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.

1 Ответ

6 голосов
/ 12 мая 2011

Линия, представляющая A, описывается вектором v = { x: 420 - 385, y: 400 - 380 } = { x: 35, y: 20 } и начальной точкой P = { x: 385, y: 380 }. Учитывая вектор (x, y) в 2d, вектор (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 и находитесь перед конечной точкой, обе точки будут с левой стороны. (Левая сторона будет отрицательной, правая сторона будет положительной.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...