判断两个点是否在javascript中的一条线的同一侧
假设我有两个点代表一条线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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
代表 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
是标准点积。 (线本身为零。)因此,在您的示例中,我们需要执行的计算是这样的:
由于符号相同,因此它们位于同一侧。
其实我们还可以说更多。如果您位于
A
的起点并且面向终点,则两个点都将位于您的左侧。 (左边为负,右边为正。)The line representing A is described by the vector
v = { x: 420 - 385, y: 400 - 380 } = { x: 35, y: 20 }
and the starting pointP = { x: 385, y: 380 }
. Given a vector(x, y)
in 2d, the vector(y, -x)
is always at right angles to it. So the vectorw = { x: 20, y: -35 }
is at right angles tov
. Linear algebra tells us that the sign of(B - P) dot w
tells us which side of the line you are on wheredot
is the standard dot product. (The line itself is at zero.)Therefore in your example the calculation we need to do is this:
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.)