簡體   English   中英

谷歌地圖兩圈交點

[英]Google Maps Two Circles Intersection Points

是否有一種簡單的方法可以獲取Google Maps API V3中兩個的交點(如果可用)的lat / lng 還是我應該走艱難的路?

編輯:在我的問題中,圓總是具有相同的半徑,以防使解決方案更容易。

是的,對於相等的圓,可以詳細說明相當簡單的解決方案:
讓我們第一個圓心是A點,第二個圓心是F,中點是C,交點是B,D。 ABC是直角球面三角形,角為C。

在此處輸入圖片說明

我們想找到角度 A - 這是與 AF 方向的偏差角。 球面三角學(納皮爾對球面三角形的規則)給了我們公式:

cos(A)= tg(AC) * ctg(AB)其中一個符號表示球面角,雙符號表示大圓弧的角度(AB,AC)。 我們可以看到 AB = 圓半徑(當然是以弧度為單位),AC = 大圓弧上 A 和 F 之間的半距離。 找到 AC(和其他值) - 我將使用這個優秀頁面中的代碼

var R = 6371; // km
var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad();
var lat1 = lat1.toRad();
var lat2 = lat2.toRad();

var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
        Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); 
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 

和我們的

AC = c/2

如果給定的圓半徑 Rd 是公里,那么

AB = Rd / R = Rd / 6371

現在我們可以找到角度

A = arccos(tg(AC) * ctg(AB))

起始方位(AF方向):

var y = Math.sin(dLon) * Math.cos(lat2);
var x = Math.cos(lat1)*Math.sin(lat2) -
        Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
var brng = Math.atan2(y, x);

交點的方位:

B_bearing = brng - A
D_bearing = brng + A

交點坐標:

var latB = Math.asin( Math.sin(lat1)*Math.cos(Rd/R) + 
              Math.cos(lat1)*Math.sin(Rd/R)*Math.cos(B_bearing) );
var lonB = lon1.toRad() + Math.atan2(Math.sin(B_bearing)*Math.sin(Rd/R)*Math.cos(lat1), 
                     Math.cos(Rd/R)-Math.sin(lat1)*Math.sin(lat2));

和 D_bearing 相同

latB, lonB 以弧度表示

對於 r1 = r2 =: r 的情況,可以簡化“硬”方式計算 我們仍然首先必須將圓心 P1,P2 從 (lat,lng) 轉換為笛卡爾坐標 (x,y,z)。

var DEG2RAD = Math.PI/180;
function LatLng2Cartesian(lat_deg,lng_deg)
{
  var lat_rad = lat_deg*DEG2RAD;
  var lng_rad = lng_deg*DEG2RAD;
  var cos_lat = Math.cos(lat_rad);
  return {x: Math.cos(lng_rad)*cos_lat,
          y: Math.sin(lng_rad)*cos_lat,
          z: Math.sin(lat_rad)};
}

var P1 = LatLng2Cartesian(lat1, lng1);
var P2 = LatLng2Cartesian(lat2, lng2);

但是可以更容易地計算包含圓的平面的相交線。 d為實際圓心(在平面內)到表面上對應點 P1 或 P2 的距離。 一個簡單的推導顯示(用 R 表示地球的半徑):

var R = 6371; // earth radius in km
var r = 100; // the direct distance (in km) of the given points to the intersections points
// if the value rs for the distance along the surface is known, it has to be converted:
// var r = 2*R*Math.sin(rs/(2*R*Math.PI));
var d = r*r/(2*R);

現在讓 S1 和 S2 是交點,S 是它們的中點。 隨着s = |OS| 並且t = |SS1| = |SS2| t = |SS1| = |SS2| (其中 O = (0,0,0) 是地球的中心)我們從簡單的推導中得到:

var a = Math.acos(P1.x*P2.x + P1.y*P2.y + P1.z*P2.z); // the angle P1OP2
var s = (R-d)/Math.cos(a/2);
var t = Math.sqrt(R*R - s*s);

現在由於r1 = r2 ,點 S、S1、S2 位於 P1 和 P2 之間的中間平面中。 對於v_s = OS我們得到:

function vecLen(v)
{ return Math.sqrt(v.x*v.x + v.y*v.y + v.z*v.z); }
function vecScale(scale,v)
{ return {x: scale*v.x, y: scale*v.y, z: scale*v.z}; }

var v = {x: P1.x+P2.x, y: P1.y+P2.y, z:P1.z+P2.z}; // P1+P2 is in the middle of OP1 and OP2
var S = vecScale(s/vecLen(v), v);

function crossProd(v1,v2)
{
  return {x: v1.y*v2.z - v1.z*v2.y,
          y: v1.z*v2.x - v1.x*v2.z,
          z: v1.x*v2.y - v1.y*v2.x};
}
var n = crossProd(P1,P2); // normal vector to plane OP1P2 = vector along S1S2
var SS1 = vecScale(t/vecLen(n),n);

var S1 = {x: S.x+SS1.x, y: S.y+SS1.y, z: S.z+SS1.z}; // S + SS1
var S2 = {x: S.x-SS1.x, y: S.y-SS2.y, z: S.z-SS1.z}; // S - SS1

最后,我們必須轉換回 (lat,lng):

function Cartesian2LatLng(P)
{
  var P_xy = {x: P.x, y:P.y, z:0}
  return {lat: Math.atan2(P.y,P.x)/DEG2RAD, lng: Math.atan2(P.z,vecLen(P_xy))/DEG2RAD};
}
var S1_latlng = Cartesian2LatLng(S1);
var S2_latlng = Cartesian2LatLng(S2);

Yazanpro,抱歉回復晚了。

您可能對 MBo 方法的簡潔變體感興趣,它在兩個方面進行了簡化:

  • 首先,通過利用 google.maps API 的一些內置功能來避免很多困難的數學運算。
  • 其次,使用二維模型來計算夾角,代替 MBo 的球面模型。 我最初不確定這種簡化的有效性,但對MBo 小提琴的一個分支中的測試感到滿意,即錯誤根本不重要,但相對於地球的大小(例如,在低縮放級別)中是最大的圓圈。

這是功能:

function getIntersections(circleA, circleB) {
    /* 
     * Find the points of intersection of two google maps circles or equal radius
     * circleA: a google.maps.Circle object 
     * circleB: a google.maps.Circle object
     * returns: null if 
     *    the two radii are not equal 
     *    the two circles are coincident
     *    the two circles don't intersect
     * otherwise returns: array containing the two points of intersection of circleA and circleB
     */

    var R, centerA, centerB, D, h, h_;

    try {

        R = circleA.getRadius();
        centerA = circleA.getCenter();
        centerB = circleB.getCenter();

        if(R !== circleB.getRadius()) {
            throw( new Error("Radii are not equal.") );
        }
        if(centerA.equals(centerB)) {
            throw( new Error("Circle centres are coincident.") );
        }

        D = google.maps.geometry.spherical.computeDistanceBetween(centerA, centerB); //Distance between the two centres (in meters)

        // Check that the two circles intersect
        if(D > (2 * R)) {
            throw( new Error("Circles do not intersect.") );
        }

        h = google.maps.geometry.spherical.computeHeading(centerA, centerB); //Heading from centre of circle A to centre of circle B. (in degrees)
        h_ = Math.acos(D / 2 / R) * 180 / Math.PI; //Included angle between the intersections (for either of the two circles) (in degrees). This is trivial only because the two radii are equal.

        //Return an array containing the two points of intersection as google.maps.latLng objects
        return [
            google.maps.geometry.spherical.computeOffset(centerA, R, h + h_),
            google.maps.geometry.spherical.computeOffset(centerA, R, h - h_)
        ];
    }
    catch(e) {
        console.error("getIntersections() :: " + e.message);
        return null;
    }
}

順便說一句,沒有不尊重 MBo - 這是一個很好的答案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM