After your previous question about the polygons, I started making something, a javascript object. It will show its use here.
I posted it there (I skipped the documentation in this post here, please read the documentation there): Mercator Projection slightly off
I first post the code, I explain later.
<title>Getting coordinates perpendicular to AB</title>
<div id="log"></div>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry"></script>
<script>
Earth = {
// @see http://www.space.com/17638-how-big-is-earth.html for the data
// along the equator
circumference_equator: 40075000,
// throught both poles.
// Note: this is basically the original definition of the meter; they were 2km off on a distance from pole to equator ( http://en.wikipedia.org/wiki/History_of_the_metre )
circumference_poles: 40008000,
// given a change in latitude, how many meters did you move?
lat2Y: function(dLat) {
return this.circumference_poles / 360 * dLat;
},
// given a change in longitude and a given latitude, how many meters did you move?
lng2X: function(dLng, lat) {
return Math.cos( this.deg2rad(lat) ) * (this.circumference_poles / 360 * dLng);
},
// given a distance you move due North (or South), what's the new coordinates?
// returns a change in latitude
y2Lat: function(y) {
return y * 360 / this.circumference_poles;
},
// given a distance you move due East (or West) and a given latitude, what's the new coordinates?
// returns a change in longitude
x2Lng: function(x, lat) {
return x * 360 / ( Math.cos( this.deg2rad(lat) ) * this.circumference_poles);
},
// (360°) degrees to radials
deg2rad: function(deg) {
return deg * Math.PI / 180;
},
// returns a change in position
xy2LatLng: function(y, x, lat) {
return {
lat: this.y2Lat(y),
lng: this.x2Lng(x, lat)
};
},
// @param heading: North = 0; east = 90°; ...
setHeading: function(lat, lng, dist, heading) {
var latDestination = lat + this.y2Lat(dist * Math.cos(this.deg2rad(heading)));
var lngDestination = lng + this.x2Lng(dist * Math.sin(this.deg2rad(heading)), lat);
return {
lat: latDestination,
lng: lngDestination
};
},
// returns the absolute position
moveByXY: function(lat, lng, x, y) {
var dLatLng = Earth.xy2LatLng(x, y, lat);
latLng = [dLatLng.lat, dLatLng.lng ];
return {
lat: lat + latLng[0],
lng: lng + latLng[1]
}
}
}
/**
* returns the shortest distance between a point p and a line segment (u,v).
* based on https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
*/
function distToSegment(p, v, w) {
return Math.sqrt(distToSegmentSquared(p, v, w));
function distToSegmentSquared(p, v, w) {
var l2 = dist2(v, w);
if (l2 == 0) {return dist2(p, v);}
var t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2;
if (t < 0) {return dist2(p, v);}
if (t > 1) {return dist2(p, w);}
return dist2(p,
{x: v.x + t * (w.x - v.x),
y: v.y + t * (w.y - v.y)}
);
}
function sqr(x) {
return x * x ;
}
function dist2(v, w) {
return sqr(v.x - w.x) + sqr(v.y - w.y);
}
}
</script>
<script>
var A = {lat: 50.88269282423443, lng: 6.0036662220954895};
var B = {lat: 50.882753744583226, lng: 6.003803014755249};
var C = {lat: 50.88252571592428, lng: 6.003832183778286};
// get the angle of AB (let Google calculate it)
var angle_ab = google.maps.geometry.spherical.computeHeading(
new google.maps.LatLng(A.lat, A.lng),
new google.maps.LatLng(B.lat, B.lng)
);
// we convert these coordinates to metric units. lat goes along y; lng goes along x
// so this tells us that from A to B there are X metres eastwards, Y metres northwards.
var a = {x:0, y:0};
var b = {
x: Earth.lng2X(B.lng - A.lng, A.lat),
y: Earth.lat2Y(B.lat - A.lat),
};
var c = {
x: Earth.lng2X(C.lng - A.lng, A.lat),
y: Earth.lat2Y(C.lat - A.lat),
};
// second, we look for point E, being the projection of C on AB
var dist_E = distToSegment(c, a, b);
// Now we know this: if we move from B, distance "dist_E" on an angle 90° to the right (anti-clockwise) of AB
var D = Earth.setHeading(B.lat, B.lng, dist_E, angle_ab + 90);
log('distance of E (= projection of C on AB) to AB: <b>' + dist_E +'</b>m');
log('Point D: <b>' + D.lat +','+ D.lng +'</b>');
function log(text) {
document.getElementById('log').innerHTML += text + '<br>';
}
</script>
What I did:
first I convert the data from coordinates to metres
I find point E: the projection of C on AB
The distane and angle of CE is the same as BD, so I can use Earth.setHeading(), from B.
NOTICE:
There is no rectangle in your question, but still, notice:
there is no such thing as a rectangle on a curved surface; it is impossible make that rectangle completely accuratly. If you go x distance forward, then turn 90° to the right hand side and repeat that 4 times, you will not get back (exactly) on the point where you started.
On a sphere, the sum of the angles of a rectangle will be greater than 360°; the sum of the angles of a triangle will be greater than 180°.
Simple example: take points (lat, lng) 0,0 ; 0,90 ; 90,0 (two points on the equator + the North Pole); that's a triangle with a sum of angles = 270°.
So, what ever answer you seek, will be an approximation. The bigger the distances, the less accurate the result will be (no matter what genius solves the problem);
You cannot simply assume every right angle on your diagram will be a right angle on the earth's surface.