2012-07-10 77 views
0

我有一個包含多個「區域」的地圖,每個地圖都創建爲多邊形疊加層。我還允許用戶定義路線並使用DirectionsService,我將路線呈現爲同一地圖http://i.stack.imgur.com/DDZI1.png上的多段線。您可以看到兩個區域,一個爲綠色,另一個爲藍色,路線爲紅色。在最終版本中會定義多達30個區域。查找多邊形內Polyline線段的總距離

我需要做的是計算折線(路線)在每個區域中的距離。路線可能會多次進入和退出一個區域,具體取決於道路曲折和轉彎的方式,路線也可能完全存在於一個區域中,而不與區域的邊界相交。

我該怎麼辦?

這是我目前擁有的代碼,它只是將兩個區域添加到地圖並繪製線條。我還在'contains'方法中添加了一個方法,該方法允許我確定一個座標是否位於一個多邊形內,我使用該多邊形在地圖上繪製一條新的多段線(黑色),用於位於區域「a」中的多段。然而,這並不足以知道它何時首次進入區域,這可能發生在頂點之間。

// Functions =============== 
// ========================= 

var calcRoute = function (start, end) { 

var request = { 
    origin: start, 
    destination: end, 
    travelMode: google.maps.TravelMode.DRIVING, 
    provideRouteAlternatives: false, 
    avoidHighways: false, 
    avoidTolls: false, 
    optimizeWaypoints: false 
}; 

// Load directions 
directions.service.route(request, function (result, status) { 

    if (status == google.maps.DirectionsStatus.OK) { 

     // Iterate through each route, adding it to th map 
     $(result.routes).each(function onEach(index, route) { 

      // Create a new Polyline, set its path to the route path 
      var line = new google.maps.Polyline({ 
       path: route.overview_path, 
       strokeColor: "#FF0000", 
       strokeOpacity: 1, 
       strokeWeight: 2 
      }); 

      // Add line to the map 
      line.setMap(map); 

      // Find individual line segments 
      var inside = []; 
      var vertices = line.getPath(); 
      for (var i = 0; i < vertices.length; i++) { 

       var vertix = vertices.getAt(i); 

       // Check to see if the vertix exists within a specified Polygon 
       if (zones.a.polygon.contains(vertix)) { 
        inside.push(vertix); 
       } 

      } 

      // Add another Polyline for the segments inside the polygon 
      var line = new google.maps.Polyline({ 
       path: inside, 
       strokeColor: "#000000", 
       strokeOpacity: 1, 
       strokeWeight: 4 
      }); 

      // Add line to the map 
      line.setMap(map); 

     }); 

    } 

}); 

} 

// ray casting alogrithm http://rosettacode.org/wiki/Ray-casting_algorithm 
google.maps.Polygon.prototype.contains = function(point) { 

var crossings = 0, 
    path = this.getPath(); 

// for each edge 
for (var i=0; i < path.getLength(); i++) { 
    var a = path.getAt(i), 
     j = i + 1; 
    if (j >= path.getLength()) { 
     j = 0; 
    } 
    var b = path.getAt(j); 
    if (rayCrossesSegment(point, a, b)) { 
     crossings++; 
    } 
} 

// odd number of crossings? 
return (crossings % 2 == 1); 

function rayCrossesSegment(point, a, b) { 
    var px = point.lng(), 
     py = point.lat(), 
     ax = a.lng(), 
     ay = a.lat(), 
     bx = b.lng(), 
     by = b.lat(); 
    if (ay > by) { 
     ax = b.lng(); 
     ay = b.lat(); 
     bx = a.lng(); 
     by = a.lat(); 
    } 
    // alter longitude to cater for 180 degree crossings 
    if (px < 0) { px += 360 }; 
    if (ax < 0) { ax += 360 }; 
    if (bx < 0) { bx += 360 }; 

    if (py == ay || py == by) py += 0.00000001; 
    if ((py > by || py < ay) || (px > Math.max(ax, bx))) return false; 
    if (px < Math.min(ax, bx)) return true; 

    var red = (ax != bx) ? ((by - ay)/(bx - ax)) : Infinity; 
    var blue = (ax != px) ? ((py - ay)/(px - ax)) : Infinity; 
    return (blue >= red); 

} 

}; 


// Variables =============== 
// ========================= 
var $map = document.getElementById('map_canvas'), 
defaultLocation = new google.maps.LatLng(-37.813553, 144.96341899999993), // Melbourne CBD 
directions = { 
    display: new google.maps.DirectionsRenderer(), 
    service: new google.maps.DirectionsService() 
}, 
initialLocation = defaultLocation, 
map = null, 
options = { 
    center: initialLocation, 
    mapTypeId: google.maps.MapTypeId.ROADMAP, 
    zoom: 13 
}, 
zones = { 
    a: { 
     options: { 
      path: [ 
       new google.maps.LatLng(-37.839848,144.916192), 
       new google.maps.LatLng(-37.831374,144.911557), 
       new google.maps.LatLng(-37.822358,144.911128), 
       new google.maps.LatLng(-37.806627,144.908038), 
       new google.maps.LatLng(-37.794148,144.914218), 
       new google.maps.LatLng(-37.787636,144.924518), 
       new google.maps.LatLng(-37.788586,144.947520), 
       new google.maps.LatLng(-37.787365,144.950953), 
       new google.maps.LatLng(-37.789536,144.958507), 
       new google.maps.LatLng(-37.793063,144.966060), 
       new google.maps.LatLng(-37.792656,144.975501), 
       new google.maps.LatLng(-37.807983,144.972239), 
       new google.maps.LatLng(-37.815035,144.975158), 
       new google.maps.LatLng(-37.833069,144.971210), 
       new google.maps.LatLng(-37.836594,144.968463), 
       new google.maps.LatLng(-37.849066,144.950438), 
       new google.maps.LatLng(-37.839848,144.916192) 
      ], 
      fillColor: "#00FF00", 
      fillOpacity: 0.35, 
      strokeColor: "#00FF00", 
      strokeOpacity: 1, 
      strokeWeight: 2 
     }, 
     polygon: null 
    }, // End zone a 
    b: { 
     options: { 
      path: [ 
       new google.maps.LatLng(-37.840119,144.915591), 
       new google.maps.LatLng(-37.865465,144.914561), 
       new google.maps.LatLng(-37.867905,144.908467), 
       new google.maps.LatLng(-37.871970,144.902974), 
       new google.maps.LatLng(-37.859096,144.873277), 
       new google.maps.LatLng(-37.867498,144.843064), 
       new google.maps.LatLng(-37.870208,144.838944), 
       new google.maps.LatLng(-37.815984,144.849587), 
       new google.maps.LatLng(-37.812187,144.860230), 
       new google.maps.LatLng(-37.781531,144.864350), 
       new google.maps.LatLng(-37.770134,144.865724), 
       new google.maps.LatLng(-37.757378,144.859544), 
       new google.maps.LatLng(-37.728872,144.867097), 
       new google.maps.LatLng(-37.734574,144.904176), 
       new google.maps.LatLng(-37.732673,144.920999), 
       new google.maps.LatLng(-37.746791,145.022622), 
       new google.maps.LatLng(-37.764706,145.020562), 
       new google.maps.LatLng(-37.764435,145.027085), 
       new google.maps.LatLng(-37.790485,145.027429), 
       new google.maps.LatLng(-37.792927,145.031205), 
       new google.maps.LatLng(-37.826561,145.025369), 
       new google.maps.LatLng(-37.837136,145.026742), 
       new google.maps.LatLng(-37.836865,145.037042), 
       new google.maps.LatLng(-37.845812,145.039445), 
       new google.maps.LatLng(-37.847710,145.042535), 
       new google.maps.LatLng(-37.871292,145.038415), 
       new google.maps.LatLng(-37.879693,145.034295), 
       new google.maps.LatLng(-37.884571,145.038758), 
       new google.maps.LatLng(-37.903807,145.035325), 
       new google.maps.LatLng(-37.927371,145.029145), 
       new google.maps.LatLng(-37.931433,145.025712), 
       new google.maps.LatLng(-37.975560,145.015412), 
       new google.maps.LatLng(-37.969606,145.008546), 
       new google.maps.LatLng(-37.961485,145.011292), 
       new google.maps.LatLng(-37.944701,144.995843), 
       new google.maps.LatLng(-37.937932,144.996873), 
       new google.maps.LatLng(-37.925476,144.984857), 
       new google.maps.LatLng(-37.911392,144.984857), 
       new google.maps.LatLng(-37.894054,144.985200), 
       new google.maps.LatLng(-37.881861,144.977647), 
       new google.maps.LatLng(-37.856927,144.966660), 
       new google.maps.LatLng(-37.849066,144.951554), 
       new google.maps.LatLng(-37.837136,144.969064), 
       new google.maps.LatLng(-37.833340,144.971810), 
       new google.maps.LatLng(-37.814899,144.976274), 
       new google.maps.LatLng(-37.807847,144.973527), 
       new google.maps.LatLng(-37.792384,144.976274), 
       new google.maps.LatLng(-37.791299,144.967004), 
       new google.maps.LatLng(-37.785873,144.952584), 
       new google.maps.LatLng(-37.786958,144.947434), 
       new google.maps.LatLng(-37.786144,144.924088), 
       new google.maps.LatLng(-37.791842,144.915162), 
       new google.maps.LatLng(-37.805135,144.906236), 
       new google.maps.LatLng(-37.820052,144.908982), 
       new google.maps.LatLng(-37.831171,144.910012), 
       new google.maps.LatLng(-37.840119,144.915591) 
      ], 
      fillColor: "#0000FF", 
      fillOpacity: 0.35, 
      strokeColor: "#0000FF", 
      strokeOpacity: 1, 
      strokeWeight: 2 
     } 
    } // End zone b 
}; 


// Load reference to map 
map = new google.maps.Map($map, options); 

// Load zones 
zones.a.polygon = new google.maps.Polygon(zones.a.options); 
zones.a.polygon.setMap(map); 

zones.b.polygon = new google.maps.Polygon(zones.b.options); 
zones.b.polygon.setMap(map); 

// Load route 
calcRoute(
    'Dandenong', 
    'South Melbourne' 
); 

回答

0

這取決於距離增量你使用(英尺,米,公里,英里),這裏就是我會做...

var increment = 0; 
var zone = initial_zone; 

//loop structure 
if(current zone == zone){ 
    increment = increment + 1; 
} 
else{ 
    zone = zone_2; 
} 

等...等

+0

對不起,我不知道你的意思。 – tmcinerney 2012-07-10 02:16:46

+0

如果您仍在區域1中,則增加計數器變量....如果區域發生更改,則保存最後一個計數器,然後更改區域。如果你需要更多的幫助......發佈一些代碼,所以我可以給你一個具體的例子。 – reagan 2012-07-10 02:20:26

+0

我不確定當區域更改時我可以檢測到的方式/位置。我應該有什麼東西跟隨多段線,按固定增量向上移動?我剛剛發佈了我目前擁有的代碼。 – tmcinerney 2012-07-10 02:51:16

0
  • 搜索line polygon intersection
  • 挑你瞭解的算法或者找到一個實現在JavaScript中,你可以移植到API
  • 用它來尋找路線的交叉點與多邊形
  • 使用幾何庫,以確定每個多邊形內部的線段的長度
相關問題