获取垂直于AB的坐标

Getting coordinates perpendicular to AB

我已经发布了这个问题here

感谢 Fang,我得到了解决方案,但问题是我需要使用的坐标是 GPS 坐标,显然 GPS 需要与笛卡尔坐标不同的公式。

所以我正在使用 Google Maps APIv3 多边形并具有 AB 坐标(通过使用多边形工具绘制它们)我单击位置 C,我需要将其移动到垂直于 AB 的 D CD 平行于 AB

所以问题是:

Having
A = 50.88269282423443,6.0036662220954895
B = 50.882753744583226,6.003803014755249
C = 50.88252571592428, 6.003832183778286

- D is perpendicular to AB
- CD is parallel to AB

求D的公式是什么

我已经尝试了很长时间来解决这个问题,但到目前为止没有成功。

所以 A,B,C 是已知的 'D' 是未知的。

CD

  • cd(t1)=C+(B-A)*t1
  • 其中:
  • cd(t1)CD
  • 上的任意一点
  • t1 是区间 <-inf,+inf>
  • 的参数

BD

  • bd(t2)=B+Q*t2
  • 其中:
  • bd(t2)BD
  • 上的任意一点
  • t2 是区间 <-inf,+inf>
  • 的参数
  • Q 是垂直于 B-A
  • 的向量
  • 在2D中你可以这样获取:
  • Q.x=+(B-A).y
  • Q.y=-(B-A).x
  • 在 3D 中使用叉积,但您的示例暗示 2D 情况...

D点

  • BDCD
  • 的交集
  • 所以只要代数求解这个:
  • I. cd(t1)=C+(B-A)*t1
  • II. bd(t2)=B+Q*t2
  • III. cd(t1)=bd(t2)
  • 在 2D 中,这 (III.) 导致具有 2 个变量的 2 个线性方程 ...
  • C.x+(B.x-A.x)*t1=B.x+(B.y-A.y)*t2
  • C.y+(B.y-A.y)*t1=B.y-(B.x-A.x)*t2
  • 找到参数t1然后计算D=cd(t1)
  • t2然后计算D=bd(t2)
  • 你应该推导两种解决方案并使用精度更高的解决方案
  • 两者都会使用一些除法A1/A2所以选择一个更大的|A2|

如果你的D点也能锁到A点

  • 然后找到两个位置D1锁定到AD2锁定到B
  • 并选择了离点C (min(|D1-C|,|D2-C|))
  • 较近的一个
  • 为了简化这一点,您可以使用 D1+(B-A)=D2 ...

[edit2] 我确实在 edit1 的某个地方犯了一些错误所以这里是工作版本

    double ax,ay,bx,by,cx,cy,dx,dy; // points
    double bdx,bdy,cdx,cdy;         // directions
    double t1,t2;                   // parameters
/*
    //--- intersection equations ----------------
    1. cx+cdx*t1=bx+bdx*t2;
    2. cy+cdy*t1=by+bdy*t2;

    //--- separate t1 ---------------------------
    1. t1=(bx-cx+(bdx*t2)/cdx;
    //--- substitute t1 and separate t2 ---------
    2. t2=(cy-by+((bx-cx)*cdy/cdx))/(bdy-(bdx*cdy/cdx));
    //-------------------------------------------

    //--- separate t2 ---------------------------
    1. t2=(cx-bx+cdx*t1)/bdx;
    //--- substitute t2 and separate t1 ---------
    2. t1=(by-cy+((cx-bx)*bdy/bdx))/(cdy-(cdx*bdy/bdx));
    //-------------------------------------------
*/
    // common
    cdx=bx-ax;
    cdy=by-ay;
    bdx=+cdy;
    bdy=-cdx;
    //solution 1
    t2=(cy-by+((bx-cx)*cdy/cdx))/(bdy-(bdx*cdy/cdx));
    dx=bx+bdx*t2;
    dy=by+bdy*t2;
    //solution 2
    t1=(by-cy+((cx-bx)*bdy/bdx))/(cdy-(cdx*bdy/bdx));
    dx=cx+cdx*t1;
    dy=cy+cdy*t1;
  • 只使用不除以零的解...

在你之前关于多边形的问题之后,我开始制作一些东西,一个 javascript 对象。它将在这里展示它的用途。 我在那里 post 编辑了它(我在这里跳过了 post 中的文档,请阅读那里的文档):Mercator Projection slightly off

我先post代码,我稍后解释。


<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 
*/
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>

我做了什么:

  • 首先我将数据从坐标转换为米

  • 我找到E点:C在AB上的投影

  • CE的距离和角度和BD一样,所以我可以用Earth.setHeading(),从B.


注意: 您的问题中没有矩形,但仍然请注意: 曲面上没有矩形这样的东西;完全准确地制作那个矩形是不可能的。如果你向前走 x 距离,然后向右转 90° 并重复 4 次,你将不会(准确地)回到你开始的地方。

在球体上,矩形的内角和大于360°;三角形的内角和将大于 180°。 简单示例:取点 (lat, lng) 0,0 ; 0,90 ; 90,0(赤道两点+北极);那是一个内角和 = 270° 的三角形。

因此,无论您寻找什么答案,都将是一个近似值。距离越大,结果越不准确(不管是什么天才解决的问题);

您不能简单地假设图表上的每个直角在地球表面都是直角。

感谢 Emmanuel,我找到了球形函数,这对我制作函数有很大帮助。我也喜欢他的回答,但我最终做出的代码少了很多。

this.makeRightAngle = function(polygon, e, A, B, C){
    var heading_AB = google.maps.geometry.spherical.computeHeading(
      new google.maps.LatLng(A.lat, A.lng), 
      new google.maps.LatLng(B.lat, B.lng)
    );

    var heading_AC = google.maps.geometry.spherical.computeHeading(
      new google.maps.LatLng(A.lat, A.lng), 
      new google.maps.LatLng(C.lat, C.lng)
    );

    var heading_BC = google.maps.geometry.spherical.computeHeading(
      new google.maps.LatLng(A.lat, A.lng), 
      new google.maps.LatLng(C.lat, C.lng)
    );

    var distanceBC = google.maps.geometry.spherical.computeDistanceBetween(
      new google.maps.LatLng(B.lat, B.lng), 
      new google.maps.LatLng(C.lat, C.lng)
    );

    var heading_C_AB = heading_AC - heading_AB;

    if((heading_C_AB < 0 && heading_C_AB > -200) || (heading_C_AB > 200)){
        var new_heading = heading_AB - 90;
    }
    else{
        var new_heading = heading_AB + 90;
    }

    var D = google.maps.geometry.spherical.computeOffset(
      new google.maps.LatLng(B.lat, B.lng), //From LatLng
      distanceBC, //Get distance BC
      new_heading //Heading of AB + or - 90 degrees
    );

    var p = {x: D.lat(), y: D.lng()};

    var latlng = new google.maps.LatLng(p.x, p.y);

    return latlng;  
}

仍然非常感谢您的回答!