查找多边形内Polyline线段的总距离 [英] Find the total distance of a Polyline segment within a Polygon

查看:110
本文介绍了查找多边形内Polyline线段的总距离的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含多个区域的地图,每个区域都创建为多边形叠加层。我还允许用户定义路线并使用DirectionsService,我将路线呈现为同一地图上的多段线 http://i.stack.imgur.com/DDZI1.png 。您可以看到两个区域,一个为绿色,另一个为蓝色,路线为红色。在最终版本中,最多会定义30个区域。

I have a map which will consist of multiple 'zones', each of which are created as polygon overlays. I also allow a user to define a route and using the DirectionsService, I render the route as a polyline on the same map http://i.stack.imgur.com/DDZI1.png. You can see two zones, one in green and another in blue and the route in red. In the final version there will be up to 30 zones defined.

我需要做的是计算多段线(路线)在每个区域中的距离。这条路线可能会多次进入和退出一个区域,具体取决于道路的曲折和转弯,也可能路线完全存在于一个区域中,而不与区域的边界相交。

What I need to do, is calculate the distance the polyline (route) spends in each zone. The route could possibly enter and exit a zone multiple times depending on how the road twists and turns, and it is also possible that the route exists entirely in a zone without intersecting with the boundaries of a zone.

我怎样才能解决这个问题?

How can I go about this?

这是我现在的代码,它只是在地图上添加两个区域并绘制线条。我还在'contains'方法中添加了一个方法,该方法允许我确定一个坐标是否位于一个多边形内,我使用该多边形在地图上绘制一条新的多段线(黑色),用于位于区域a中的多段。然而,这并不足以知道它何时进入区域,这可能发生在顶点之间。

This is the code I currently have, which simply adds two zones to the map and plots the line. I also added at 'contains' method which allows me to determine if a coordinate lies within a polygon which I use to draw a new polyline on the map (in black) for the segments which lie in zone 'a'. This however isn't specific enough to know when it first enters the zone, which could occur between vertices.

// 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'
);


推荐答案


  • 搜索线条多边形交叉点

  • 选择您理解的算法或在JavaScript中找到您可以移植到API的实现

  • 使用它找到路线与多边形的交点

  • 使用几何库来确定每个多边形内段的长度

    • Search for line polygon intersection
    • pick an algorithm you understand or find an implementation in javascript you can port to the API
    • use it to find the intersections of your route with your polygons
    • use the geometry library to determine the length of the segments inside each polygon
    • 这篇关于查找多边形内Polyline线段的总距离的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆