Как получить 4 координаты прямоугольника из 3 координат?

Я хочу создать функцию, которая позволяет пользователю рисовать прямоугольник из 3 точек (синие точки):

  • Первые две точки будут формировать ребро (ширину).
  • Третья точка будет определять высоту.

Мне нужна эта пользовательская функция рисования в листовке, однако прямоугольник листовки по умолчанию создается с двумя диагональными точками: https://leafletjs.com/reference-1.5.0.html#прямоугольник.

Мне нужно вычислить одну из зеленых точек, но мой маленький мозг не может этого понять :P

PS/EDIT: прямоугольник может быть расположен под углом, это усложняет задачу.

Как получить 4 координаты прямоугольника из 3 координат?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
3 370
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Предполагая, что координаты этих трех точек предоставлены, - 2, 5 (первая точка) - 5, 5 (вторая точка) - х, 8 (третья точка)

первый зеленый возьмет x из одной из первых двух точек, скажем, из первой => 2, а y из третьей точки => 8 так что первая зеленая точка находится на 2,8

второй возьмет x из второй точки => 5, а y из третьей точки => 8 значит вторая зеленая точка на 5,8

Я не уверен, правильно ли я понимаю ответ.

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

Christabella Adelina 04.06.2019 11:07

Ааа, я вижу, это намного сложнее. Теперь я тоже хочу знать ответ.

clumsy.kitten 04.06.2019 11:18

предполагая, что ребро1 = [x1,y1] , ребро2 = [x2,y2]

def calculate_edges (edge1,edge2,height)
    edge3 [0] = edge1[0]          //x3
    edge3 [1] = edge1[1] + height //y3
    edge4 [0] = edge2[0]          //x4
    edge4 [1] = edge2[1] + height //y4
return edge3,edge4

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

Christabella Adelina 04.06.2019 11:09

здесь вам нужно сделать преобразование ориентира (1-предположим, что ребро1 является вашим новым ориентиром, 2-вычислите координаты других ребер, используя алгоритм, который я реализовал, 3-вычислите матрицу преобразования (от нового ориентира к исходному) и '-наконец найти координаты разных ребер в исходном ориентире)[imgur.com/a/WNwIMJB]

Saif Faidi 04.06.2019 11:36
Ответ принят как подходящий

Leaflet's default rectangle is created with 2 diagonal points

[...]

The rectangle might be angled, this is what makes it challenging

Имейте в виду, что L.Rectangle в Leaflet создан из L.LatLngBounds ограничивающей рамки в котором края неявно выровнены по координатной сетке. Не используйте ограничивающие рамки и вместо этого полагайтесь на L.Polygon, предоставляя все четыре точки.


Пусть A и B — точки основания прямоугольника, а C — точка вершины. Предполагая, что все точки являются структурами Javascript формы {x: Number, y: Number}, и предполагая, что вы работаете в евклидовой плоскости (т.е. не на поверхности геоида),

Во-первых, рассчитать расстояние от точки до линии, определяемой двумя другими точками, т.е. расстояние от C до линии, определяемой AB. Пусть это будет distance (обратите внимание, что это равно «высоте» на вашей диаграмме):

var distance = Math.abs( 
    (A.y - B.y) * C.x  -  (A.x - B-x) * C.y  +  B.x * A.y  -  B.y * A.x ) 
  ) / Math.sqrt(
    Math.pow(B.y - A.y, 2) + Math.pow(B.x - A.x, 2)
  );

Тогда пусть AB будет вектором из A в B

var AB = {  x: B.x - A.x,   y: B.y - A.y };

(Обратите внимание, что длина AB равна «ширине» на вашей диаграмме)

Рассчитайте единичный вектор перпендикулярно AB:

var perpendicular = {x: -AB.y, y: AB.x}
var perpendicularSize = Math.sqrt(AB.x * AB.x + AB.y * AB.y);
var unit = {x: perpendicular.x / perpendicularSize, y: perpendicular.y / perpendicularSize};

Умножьте этот единичный вектор на расстояние от C до AB, чтобы получить векторы для «сторон» вашего прямоугольника:

var sideVector = { x: unit.x * distance, y: unit.y * distance };

...и создайте новые точки D и E, сместив A и B на вектор сторон прямоугольника:

var D = { x: A.x + sideVector.x, y: A.y + sideVector.y };
var E = { x: B.x + sideVector.x, y: B.y + sideVector.y };

...И ваш прямоугольник теперь определяется точками ABDE. Обратите внимание, что C находится на линии, определяемой точками DE.

Потрясающий! Большое спасибо, теперь, когда я прочитал ваш ответ, я смутно помню, как делал это в школе давным-давно, хахаха. У меня есть еще вопрос, если вы не возражаете. Поскольку я в конечном итоге хочу нарисовать прямоугольник на карте листовки, повлияет ли проекция на форму? Мне нужно, чтобы окончательная форма была прямоугольником с 4 прямыми углами. Мой вариант использования — нарисовать угловой прямоугольник; Первоначально я использовал двухэтапный метод: рисовал прямоугольник, затем поворачивал, но плагины поворота, которые я мог найти, искажали прямоугольник из-за проекции. Вот почему я хотел использовать границы, что вы предлагаете?

Christabella Adelina 04.06.2019 12:23

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

IvanSanchez 04.06.2019 12:32

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

IvanSanchez 04.06.2019 12:40

Понимаю. Теперь я понимаю. Большое спасибо за объяснение! Это интересно и поучительно.

Christabella Adelina 05.06.2019 10:29

Для Питона:

#Given three points fit a rectangle

import math 
a,b,c=[1,4],[3,4],[3,10] #Sample numbers

#Distance from dot C to line AB (https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Line_defined_by_two_points)
distance= abs((b[1]-a[1])*c[0] - (b[0]-a[0])*c[1] + b[0]*a[1] - b[1]*a[0] ) / math.sqrt((b[1]-a[1])**2 + (b[0]-a[0])**2)
print(distance)
#let AB be the vector from A to B
ab=[b[0]-a[0],b[1]-a[1]]

#unit vector perpendicular to AB (https://en.wikipedia.org/wiki/Unit_vector)
perpendicularSize = math.sqrt(ab[0]**2+ab[1]**2)
unit = [-ab[1]/perpendicularSize ,ab[0]/perpendicularSize]

#Multiply that unit vector by the distance from C to AB to get the vectors for the "sides" of your rectangle
sideVector = [unit[0]*distance,unit[1]*distance]

#create new points D and E by offsetting A and B by the vector for the sides of the rectangle
d=[a[0]+sideVector[0],a[1]+sideVector[1]]
e=[b[0]+sideVector[0],b[1]+sideVector[1]]

print(e,d)  #[3.0, 10.0] [1.0, 10.0]

Другие вопросы по теме