Я хочу создать функцию, которая позволяет пользователю рисовать прямоугольник из 3 точек (синие точки):
Мне нужна эта пользовательская функция рисования в листовке, однако прямоугольник листовки по умолчанию создается с двумя диагональными точками: https://leafletjs.com/reference-1.5.0.html#прямоугольник.
Мне нужно вычислить одну из зеленых точек, но мой маленький мозг не может этого понять :P
PS/EDIT: прямоугольник может быть расположен под углом, это усложняет задачу.





Предполагая, что координаты этих трех точек предоставлены, - 2, 5 (первая точка) - 5, 5 (вторая точка) - х, 8 (третья точка)
первый зеленый возьмет x из одной из первых двух точек, скажем, из первой => 2, а y из третьей точки => 8 так что первая зеленая точка находится на 2,8
второй возьмет x из второй точки => 5, а y из третьей точки => 8 значит вторая зеленая точка на 5,8
Я не уверен, правильно ли я понимаю ответ.
Ааа, я вижу, это намного сложнее. Теперь я тоже хочу знать ответ.
предполагая, что ребро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). Однако прямоугольник может быть расположен под углом. Так что будет немного сложнее
здесь вам нужно сделать преобразование ориентира (1-предположим, что ребро1 является вашим новым ориентиром, 2-вычислите координаты других ребер, используя алгоритм, который я реализовал, 3-вычислите матрицу преобразования (от нового ориентира к исходному) и '-наконец найти координаты разных ребер в исходном ориентире)[imgur.com/a/WNwIMJB]
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 прямыми углами. Мой вариант использования — нарисовать угловой прямоугольник; Первоначально я использовал двухэтапный метод: рисовал прямоугольник, затем поворачивал, но плагины поворота, которые я мог найти, искажали прямоугольник из-за проекции. Вот почему я хотел использовать границы, что вы предлагаете?
Да, прогнозы могут испортить ваши расчеты. Вот почему я добавил бит «предполагая, что вы работаете в евклидовой плоскости». Геометрия на поверхности геоида (или на поверхности сферы, если уж на то пошло) сильно отличается от евклидовой геометрии, т.е. сумма углов треугольника может составлять более 180° (представьте себе треугольник с вершинами на северном полюсе, экватором на нулевом меридиане, экватором на 90° меридиане), поэтому у вас не может быть прямоугольника с четырьмя углами по 90°.
С практической точки зрения, вы должны либо переопределить свою задачу с точки зрения геодезической геометрии, либо спроецировать данные на известную АСБ (предпочтительно на основе конформная проекция, подходящей для ваших данных) и работать с этой CRS, как если бы это была евклидова плоскость.
Понимаю. Теперь я понимаю. Большое спасибо за объяснение! Это интересно и поучительно.
Для Питона:
#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]
Привет, спасибо за ответ. Да, это базовый случай, но он будет работать только в том случае, если прямоугольник не находится под углом (край, образованный точками 1 и 2, параллелен оси x). Однако прямоугольник может быть расположен под углом. Так что будет немного сложнее.