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

StackOverflow https://stackoverflow.com/questions/2219108

Вопрос

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

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

Нет никакой гарантии относительно ориентации коробки.

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

Это было полезно?

Решение

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

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

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

а наклон другого края равен:

m2 = - 1 / m1

Если вы знаете длины сторон и середины двух противоположных сторон, то точки пересечения легко определить, добавив 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 градусов, оказывается, просто меняет местами координаты и сводит на нет одну из них.Вы можете убедиться в этом, просто попробовав это на бумаге.Или взгляните на уравнения для двумерных вращений и подставьте под 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 - длина верха/низа / 2;x2 = x1 + длина верха/низа;

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};
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top