Рассчитать координаты точки, зная координаты трех других и расстояние
Суть задания в следующем: в произвольной точке взрывается бомба, взрывная волна распространяется со скоростью 1 клетка в секунду. Зеленые точки - это датчики, которые фиксируют время попадания в зону поражения. Необходимо рассчитать координаты точки взрыва, зная координаты датчиков и расстояния от эпицентра до датчиков. Функция getBombCoordinates() на данный момент только считает расстояния.
let canvas = document.querySelector('canvas')
let ctx = canvas.getContext('2d')
let w = canvas.width = 400
let h = canvas.height = 400
let colNum = 50
let rowNum = 50
let cell_w = w / colNum
let cell_h = h / rowNum
let isExploding = false
let probeTime1 = 0
let probeTime2 = 0
let probeTime3 = 0
let button = document.getElementById("button")
button.onclick = function () {
document.getElementById("result").innerHTML = "Результат: " + getBombCoordinates(probeTime1,probeTime2,probeTime3)
}
canvas.addEventListener('click', setBomb)
drawNet()
function drawNet() {
for (let x = 0; x < w +1; x += 8) {
ctx.moveTo(x, 0)
ctx.lineTo(x, 400)
}
for (let y = 0; y < h+1; y += 8) {
ctx.moveTo(0, y)
ctx.lineTo(400, y)
}
ctx.stroke()
ctx.beginPath()
}
function explode(x, y, blowRadius) {
isExploding = true
let probe1 = ctx.getImageData(128, 32, 8, 8).data
let probe2 = ctx.getImageData(80, 336, 8, 8).data
let probe3 = ctx.getImageData(344, 296, 8, 8).data
let top_left = ctx.getImageData(1, 1, 1, 1).data
let top_right = ctx.getImageData(399, 1, 1, 1).data
let bot_left = ctx.getImageData(1, 399, 1, 1).data
let bot_right = ctx.getImageData(399, 399, 1, 1).data
ctx.fillStyle = 'red'
ctx.arc(x, y, blowRadius, 0, getRadians(360))
ctx.fill()
function getRadians(degrees) {
return (Math.PI / 180) * degrees
}
if(probe1[0] !== 255){
probeTime1++
}
if(probe2[0] !== 255){
probeTime2++
}
if(probe3[0] !== 255){
probeTime3++
}
if((top_left[0] !== 255) || (top_right[0] !== 255) || (bot_left[0] !== 255) || (bot_right[0] !== 255)) {
blowRadius += 4
setTimeout(() => explode(x, y, blowRadius), 1000)
} else {
isExploding = false
setTimeout(() => {
ctx.clearRect(0, 0, w, h)
ctx.beginPath()
drawNet()
}, 2000)
}
}
function setBomb(e) {
probeTime1 = 0
probeTime2 = 0
probeTime3 = 0
if (!isExploding) {
let x = e.offsetX
let y = e.offsetY
let c_x = Math.floor(x / cell_w)
let c_y = Math.floor(y / cell_h)
let f_x = c_x * cell_w + 4
let f_y = c_y * cell_h + 4
ctx.clearRect(0, 0, w, h)
ctx.beginPath()
drawNet()
ctx.fillStyle = 'green'
ctx.fillRect(128, 32, 8, 8)
ctx.fillRect(80, 336, 8, 8)
ctx.fillRect(344, 296, 8, 8)
console.log(c_x)
console.log(c_y)
explode(f_x, f_y, 4)
}
}
function getBombCoordinates(probeTime1,probeTime2, probeTime3){
let distance1 = probeTime1 * 0.5
let distance2 = probeTime2 * 0.5
let distance3 = probeTime3 * 0.5
let probe1X = Math.floor(128 / cell_w)
let probe1Y = Math.floor(32 / cell_h)
let probe2X = Math.floor(80 / cell_w)
let probe2Y = Math.floor(336 / cell_h)
let probe3X = Math.floor(344 / cell_w)
let probe3Y = Math.floor(296 / cell_h)
let distance = [distance1,distance2,distance3,probe1X,probe1Y,probe2X,probe2Y,probe3X,probe3Y]
return distance
}
Ответы (1 шт):
Если вам известны расстояния, то берёте два датчика А и B, находите расстояние между ними L, вектор направления AB = B-A = (B.x-A.x, B.y-A.y), нормализуете его uAB = AB/L и находите перпендикулярный единичный вектор p = (-uAB.y, uAB.x) - всё это делается один раз для заданного расположения датчиков.
Затем считаете для расстояний от взрыва до датчиков dA, dB:
t = (dA^2 - dB^2 + L^2) / (2*L)
u = sqrt(dA^2 - t^2)
И находите две возможные точки
P1 = A + uAB*t + p*u
P2 = A + uAB*t - p*u
И узнаёте, какая подходит, проверив расстояние до датчика C
(описано в вики для расположения датчиков в нуле и на оси OX)
Для справки код на Python, пяток примеров вычислений на валидных данных, картинки для второго и последнего расположений
import math
def explo(ax,ay,bx,by,cx,cy,da,db,dc):
abx = bx - ax
aby = by - ay
l = math.hypot(abx, aby)
#Здесь предусмотреть случаи if da + db < L и т.д.
abx /= l
aby /= l
nx = -aby
ny = abx
t = 0.5*(da*da - db*db + l*l)/l
u = math.sqrt(da*da - t*t)
px = ax + abx * t + nx * u
py = ay + aby * t + ny * u
if abs(math.hypot(px-cx, py-cy) - dc) < 0.1:
return [px, py]
px = ax + abx * t - nx * u
py = ay + aby * t - ny * u
if abs(math.hypot(px-cx, py-cy) - dc) < 0.1:
return [px, py]
print(explo(0, 0, 10, 0, 4, 7, 4, 6, 7))
print(explo(1, 1, 8, 1, 3, 8, 5.83, 6.4, 2.24))
print(explo(1, 1, 8, 1, 3, 8, 6.71, 3.16, 10.77))
print(explo(1, 1, 5, 5, 3, 8, 6.71, 7.28, 10.77))
print(explo(10, 8, 5, 5, 12, 2, 10.44, 7.28, 6.4))
[4.0, 0.0]
[4.002064285714285, 5.997650450405549]
[7.00275, -1.998515038731672]
[7.002409363885446, -1.9991968638854467]
[7.0003512133137935, -1.9997853555229836]
Если же известны не расстояния, а относительные времена срабатывания при неизвестном времени взрыва, то придётся считать настоящую трилатерацию, как я описывал здесь


