Зная две точки прямоугольника, как я могу понять две другие?

Привет, ребята, я изучаю обработку.js, и я столкнулся с математической проблемой, которую я не могу решить с моими ограниченными знаниями геометрии и тригонометрии или с помощью Википедии.

Мне нужно нарисовать прямоугольник. Чтобы нарисовать этот прямоугольник, мне нужно знать координаты точек каждого угла. Все, что я знаю, это x и y для средних точек верхней и нижней частей коробки и длины всех четырех сторон.

никакая гарантия на ориентации коробка.

помочь? Кажется, это должно быть легко, но это действительно ставит меня в тупик.

9 ответов


если этот четырехугольник является прямоугольником (все четыре угла 90 градусов), то его можно решить. (если это может быть любой четырехугольник, то он не разрешим)

если точки (x1, y1) и (x2, y2), и если две точки не являются идеально вертикальными (x1 = x2) или горизонтальными (y1 = y2), то наклон одного края прямоугольника

m1 = (y2-y1) / (x2-x1) 

и наклон другого края:

m2 = - 1 / m1

если вы знаете длины сторон, и средние точки двух противоположных сторон, то точки corrner легко определяются путем добавления dx, dy к средним точкам: (если L-длина сторон, на которых находятся средние точки)

dx = Sqrt( L^2 / (1 + m2^2) ) / 2

и

dy = m2 * dx

Примечание: Если точки вертикально или горизонтально выровнены, этот метод не будет работать, хотя очевидное решение для этих дегенеративных случаев намного проще.


если вы знаете, что ваш четырехугольник прямоугольник, то вы можете использовать некоторые простые векторные математики, чтобы найти координаты углов. Известно:

  • (x1,y1) - координата средней точки На верхней линии
  • (x2,y2) - координата средней точки в нижней строке
  • l1 - длина верхней и нижней строк
  • l2 - длина двух других строк

во-первых, мы найти вектор между двумя известными точками. Этот вектор параллелен боковым линиям:

(vx, vy) = (x2 - x1, y2 - y1)

нам нужно нормализовать этот вектор (т. е. сделать его длиной 1), чтобы мы могли использовать его позже в качестве основы для поиска наших координат.

vlen = sqrt(vx*vx + vy*vy)

(v1x, v1y) = (vx / vlen, vy / vlen)

далее поворачиваем этот вектор против часовой стрелки на 90 градусов. Повернутый вектор будет параллелен верхней и нижней линий. Поворот на 90 градусов оказывается меняю координаты и отрицаю одну из них. Вы можете увидеть это, просто попробовав это на бумаге. Или взгляните на уравнения для 2D вращения и замените в 90 градусах.

(u1x, u1y) = (-v1y, v1x)

теперь у нас есть достаточно информации, чтобы найти верхний левый уголок. Мы просто начинаем с нашей точки (x1, y1) и отойдите назад вдоль этой стороны на половину длины стороны:

(p1x, p1y) = (x1 - u1x * l1 / 2, y1 - u1y * l1 / 2)

отсюда мы можем найти остальные точки просто путем добавления соответствующих кратных наших базисных векторов. При реализации этого вы можете, очевидно, ускорить его, только вычисляя каждое уникальное умножение один раз:

(p2x, p2y) = (p1x + u1x * l1, p1y + u1y * l1)

(p3x, p3y) = (p1x + v1x * l2, p1y + v1y * l2)

(p4x, p4y) = (p3x + u1x * l1, p3y + u1y * l1)


  function getFirstPoint(x1,y1,x2,y2,l1,l2)
    distanceV = {x2 - x1, y2 - y1}
    vlen = math.sqrt(distanceV[1]^2 + distanceV[2]^2)
    normalized = {distanceV[1] / vlen, distanceV[2] / vlen}
    rotated = {-normalized[2], normalized[1]}
    p1 = {x1 - rotated[1] * l1 / 2, y1 - rotated[2] * l1 / 2}
    p2 = {p1[1] + rotated[1] * l1, p1[2] + rotated[2] * l1}
    p3 = {p1[1] + normalized[1] * l2, p1[2] + normalized[2] * l2}
    p4 = {p3[1] + rotated[1] * l1, p3[2] + rotated[2] * l1}
    points = { p1 , p2 , p3 , p4}
    return p1
end

Это определенно прямоугольник? Тогда вы знаете ориентацию коротких сторон (они параллельны линии между вашими точками) и, следовательно, ориентацию длинных сторон.

вы знаете ориентацию и длину длинных сторон, и вы знаете их средние точки, поэтому легко найти углы оттуда.

реализация остается в качестве упражнения для читателя.


Это означает, что будут две линии, параллельные линии между двумя точками, которые у вас есть. Получите углы, переведя линию, у вас есть 1/2 длины верхней стороны в каждом направлении, перпендикулярном линии у вас есть.


Если вы знаете среднюю точку для вершины и длину вершины, то вы знаете, что y останется одинаковым для обоих верхних углов, а x будет средней точкой плюс/минус ширина прямоугольника. Это будет справедливо и для низов.

Как только у вас есть четыре угла, нет необходимости беспокоиться о длинах сторон, так как их точки такие же, как те, которые используются для верхней и нижней.

                         midpoint
     x,10                 10,10                   x,10
      *--------------------------------------------*
                         width = 30

    mx = midpoint x.
    top left corner = (w/2) - mx  or 15 - 10
    top left corner coords = -5,10

    mx = midpoint x.
    top right corner = (w/2) + mx  or 15 + 10
    top left corner coords = 25,10

существует разница между" четырехугольником "и"прямоугольником".

Если у вас есть средняя точка верхней и нижней, а также длины сторон, остальное просто.

дано:

(x1, y1) -- (top_middle_x, top_middle_y) -- (x2, y1)

(x1, y2) -- (btm_middle_x, btm_middle_y) -- (x2, y2)

и верхняя / нижняя длина вместе с правой / левой длиной.

x1 = top_middle_x-top/bottom_length / 2; x2 = x1 + top/bottom_length;

y1 = top_middle_y y2 = bottom_middle_y

очевидно, что это самый простой случай и предполагающий что линия (tmx, tmy) (bmx, bmy) находится исключительно вдоль оси Y.

мы назовем эту линию "средней линией".

следующий трюк-взять среднюю линию и вычислить ее смещение вращения от оси Y.

теперь мой триггер супер ржавый.

dx = tmx-bmx, dy = tmy - bmy.

Итак, тангенс угла равен dy / dx. Арктангенс (dy / dx) - это угол линии.

от этого вы можете получить ориентация.

если у вас есть ориентация, вы можете "повернуть" линию к оси Y. Посмотрите 2D-графику для математики, это прямо вперед.

это дает вам вашу нормальную ориентацию. Затем вычислите точки прямоугольников в этой новой нормальной форме и, наконец, поверните их обратно.

Виола. Прямоугольник.

другие вещи, которые вы можете сделать, это "поверните" линию в половину длины "сверху" линии на 90 град середины линии. Допустим, у вас средняя линия 45 градусов. Вы начнете эту линию с tmx, tmy и повернете эту линию на 135 градусов (90 + 45). Эта точка будет вашим "верхним левым" углом. Поверните его -45 (45 - 90), чтобы получить "верхнюю правую" точку. Затем проделайте нечто подобное с нижними точками.


вычислите угол линии, соединяющей две средние точки, используя функцию arc-tangent, примененную к вектору, который вы получаете между ними.

вычесть 90 градусов от этого угла, чтобы получить направление верхнего края

начиная с верхней центральной точки, переместите относительную (1/2 верхней ширины X sin(угол), 1/2 верхней ширины x cos (угол)) - это получает верхнюю правую угловую точку.

продолжайте вокруг прямоугольника, используя sin и cos углов и ширины, как соответствующий

в качестве теста: проверьте, что вы вернулись к начальной точке


/* rcx = center x rectangle, rcy = center y rectangle, rw = width rectangle, rh = height rectangle, rr = rotation in radian from the rectangle (around it's center point) */

function toRectObjectFromCenter(rcx, rcy, rw, rh, rr){
    var a = {
        x: rcx+(Math.sin((rr-degToRad(90))+Math.asin(rh/(Math.sqrt(rh*rh+rw*rw)))) * (Math.sqrt(rh*rh+rw*rw)/2)), 
        y: rcy-(Math.cos((rr-degToRad(90))+Math.asin(rh/(Math.sqrt(rh*rh+rw*rw)))) * (Math.sqrt(rh*rh+rw*rw)/2))
    };
    var b = {
        x: a.x+Math.cos(rr)*rw,
        y: a.y+Math.sin(rr)*rw
    };
    var c = {
        x: b.x+Math.cos(degToRad(radToDeg(rr)+90))*rh,
        y: b.y+Math.sin(degToRad(radToDeg(rr)+90))*rh
    };
    var d = {
        x: a.x+Math.cos(degToRad(radToDeg(rr)+90))*rh,
        y: a.y+Math.sin(degToRad(radToDeg(rr)+90))*rh
    };
    return {a:a,b:b,c:c,d:d};
}