Find the total distance of a Polyline segment within a Polygon

生来就可爱ヽ(ⅴ<●) 提交于 2020-01-06 12:27:41

问题


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?

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

回答1:


depending on what distance increment you're using (feet, meters, km, miles), here's what I'd do...

var increment = 0;
var zone = initial_zone;

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

etc...etc




回答2:


  • 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


来源:https://stackoverflow.com/questions/11405264/find-the-total-distance-of-a-polyline-segment-within-a-polygon

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!