使坐标垂直于AB

时间:2015-01-06 08:31:55

标签: javascript math geometry 2d line

enter image description here

我已发布此问题here

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

所以我正在使用Google Maps APIv3多边形并且坐标为AB(通过使用多边形工具绘制它)我点击位置C,我需要将其移动到D垂直于AB并且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

的公式是什么?

我一直在努力解决这个问题,但到目前为止还没有成功。

3 个答案:

答案 0 :(得分:1)

所以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|

enter image description here

如果您的D点也可以锁定到A点

  • 然后发现两个位置D1已锁定为AD2已锁定为B
  • 并选择了一个更靠近Cmin(|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;
  • 只使用未除以零的解决方案......

答案 1 :(得分:1)

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

我首先发布代码,稍后会解释。


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

我做了什么:

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

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

  • CE的distane和角度与BD相同,所以我可以使用B中的Earth.setHeading()。


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

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

所以,你寻求的答案,将是一个近似值。距离越大,结果就越不准确(无论天才解决了什么问题);

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

答案 2 :(得分:1)

感谢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;  
}

还要多谢两个答案!