I want to create a function that allows user to draw rectangle from 3 points (blue points):
I need this custom draw function in leaflet, however leaflet's default rectangle is created with 2 diagonal points: https://leafletjs.com/reference-1.5.0.html#rectangle.
I need to calculate one of the green points but my small brain can't seem to figure it out :P
PS/EDIT: The rectangle might be angled, this is what makes it challenging
Leaflet's default rectangle is created with 2 diagonal points
[...]
The rectangle might be angled, this is what makes it challenging
Be aware that Leaflet's L.Rectangle
is created from a L.LatLngBounds
, a bounding box in which the edges are implicitly aligned to the coordinate grid. Don't use bounding boxes, and rely on L.Polygon
instead, providing all four points.
Let A and B be the points of the base of the rectangle, and C be the point on the top. Assuming all points are Javascript structures of the form {x: Number, y: Number}
, and assuming that you're working in an euclidean plane (i.e. not on the surface of a geoid),
First, calculate the distance from a point to a line defined by the other two points, i.e. the distance from C to the line defined by AB. Let that be distance
(note that it's equal to "height" in your diagram):
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)
);
Then, let AB be the vector from A to B
var AB = { x: B.x - A.x, y: B.y - A.y };
(Note that the length of AB is equal to "width" in your diagram)
Calculate a unit vector perpendicular to 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};
Multiply that unit vector by the distance from C to AB to get the vectors for the "sides" of your rectangle:
var sideVector = { x: unit.x * distance, y: unit.y * distance };
...and create new points D and E by offsetting A and B by the vector for the sides of the rectangle:
var D = { x: A.x + sideVector.x, y: A.y + sideVector.y };
var E = { x: B.x + sideVector.x, y: B.y + sideVector.y };
...And your rectangle is now defined by the points ABDE. Note that C is in the line defined by points DE.