2016-05-17 81 views
0

我正在使用此函数来获取不规则形状多边形的质心,但是当多边形是L形时,点位于外部。在不规则形状多边形内获取纬度/深度

function get_polygon_centroid(pts) { 
    var first = pts[0], last = pts[pts.length-1]; 
    if (first.x != last.x || first.y != last.y) pts.push(first); 
     var twicearea=0, 
     x=0, y=0, 
     nPts = pts.length, 
     p1, p2, f; 
     for (var i=0, j=nPts-1 ; i<nPts ; j=i++) { 
      p1 = pts[i]; p2 = pts[j]; 
      f = p1.x*p2.y - p2.x*p1.y; 
      twicearea += f;   
      x += (p1.x + p2.x) * f; 
      y += (p1.y + p2.y) * f; 
     } 
     f = twicearea * 3; 
    return { x:x/f, y:y/f }; 
} 

我的要点是:

(-37.81418,145.13025000000002), 
(-37.814330000000005,145.13022), 
(-37.813970000000005,145.12727), 
(-37.813750000000006,145.12543000000002), 
(-37.813680000000005,145.12478000000002), 
(-37.81152,145.12517000000003), 
(-37.809380000000004,145.12558), 
(-37.80951,145.12675000000002), 
(-37.80953,145.12685000000002), 
(-37.810590000000005,145.12667000000002), 
(-37.812630000000006,145.12631000000002), 
(-37.81275,145.12628), 
(-37.81324,145.13026000000002), 
(-37.81326,145.13044000000002), 
(-37.81418,145.13025000000002) 

我想获得这远远不够关闭边界,如果可能的多边形内部的一个点。

+0

看看这个链接,一个很好的例子 http://code.google.com/apis/ajax/playground/#polygons_complex_v3 –

+0

尝试像这样https://codepen.io/jhawes/pen/ujdgK –

+0

我不明白这是什么。你能解释一下吗? – puks1978

回答

0

一个选项:

  1. 找到你的心,如果不是多边形

    • 计算全部计算出的质心和多边形的顶点之间的中间点内

    • 消除不在多边形内的任何东西。

有了您的一组数据,这导致7个候选点。

proof of concept fiddle

map with markers inside polygon

代码片断:

var geocoder; 
 
var map; 
 

 
function initialize() { 
 
    var map = new google.maps.Map(
 
    document.getElementById("map_canvas"), { 
 
     center: new google.maps.LatLng(37.4419, -122.1419), 
 
     zoom: 13, 
 
     mapTypeId: google.maps.MapTypeId.ROADMAP 
 
    }); 
 
    var polygon = new google.maps.Polygon({ 
 
    map: map, 
 
    paths: data 
 
    }); 
 
    var bounds = new google.maps.LatLngBounds(); 
 
    for (var i = 0; i < polygon.getPaths().getAt(0).getLength(); i++) { 
 
    bounds.extend(polygon.getPaths().getAt(0).getAt(i)); 
 
    } 
 
    map.fitBounds(bounds); 
 
    var marker = new google.maps.Marker({ 
 
    map: map, 
 
    position: get_polygon_centroid(data) 
 
    }); 
 
    for (var i = 0; i < polygon.getPaths().getAt(0).getLength(); i++) { 
 
    var polyline = new google.maps.Polyline({ 
 
     map: map, 
 
     path: [marker.getPosition(), polygon.getPaths().getAt(0).getAt(i)] 
 
    }); 
 
    var length = google.maps.geometry.spherical.computeLength(polyline.getPath()); 
 
    var pt = google.maps.geometry.spherical.computeOffset(marker.getPosition(), length/2, 
 
     google.maps.geometry.spherical.computeHeading(marker.getPosition(), polygon.getPaths().getAt(0).getAt(i))); 
 
    if (google.maps.geometry.poly.containsLocation(pt, polygon)) { 
 
     var candidateMarker = new google.maps.Marker({ 
 
     map: map, 
 
     position: pt, 
 
     icon: "http://maps.google.com/mapfiles/ms/micons/blue.png" 
 
     }); 
 
    } 
 
    } 
 
} 
 
google.maps.event.addDomListener(window, "load", initialize); 
 

 
function get_polygon_centroid(pts) { 
 
    var first = pts[0], 
 
    last = pts[pts.length - 1]; 
 
    if (first.lat != last.lat || first.lng != last.lng) pts.push(first); 
 
    var twicearea = 0, 
 
    x = 0, 
 
    y = 0, 
 
    nPts = pts.length, 
 
    p1, p2, f; 
 
    for (var i = 0, j = nPts - 1; i < nPts; j = i++) { 
 
    p1 = pts[i]; 
 
    p2 = pts[j]; 
 
    f = p1.lng * p2.lat - p2.lng * p1.lat; 
 
    twicearea += f; 
 
    x += (p1.lng + p2.lng) * f; 
 
    y += (p1.lat + p2.lat) * f; 
 
    } 
 
    f = twicearea * 3; 
 
    return { 
 
    lng: x/f, 
 
    lat: y/f 
 
    }; 
 
} 
 

 
var data = [{ 
 
    lat: -37.81418, 
 
    lng: 145.13025000000002 
 
}, { 
 
    lat: -37.814330000000005, 
 
    lng: 145.13022 
 
}, { 
 
    lat: -37.813970000000005, 
 
    lng: 145.12727 
 
}, { 
 
    lat: -37.813750000000006, 
 
    lng: 145.12543000000002 
 
}, { 
 
    lat: -37.813680000000005, 
 
    lng: 145.12478000000002 
 
}, { 
 
    lat: -37.81152, 
 
    lng: 145.12517000000003 
 
}, { 
 
    lat: -37.809380000000004, 
 
    lng: 145.12558 
 
}, { 
 
    lat: -37.80951, 
 
    lng: 145.12675000000002 
 
}, { 
 
    lat: -37.80953, 
 
    lng: 145.12685000000002 
 
}, { 
 
    lat: -37.810590000000005, 
 
    lng: 145.12667000000002 
 
}, { 
 
    lat: -37.812630000000006, 
 
    lng: 145.12631000000002 
 
}, { 
 
    lat: -37.81275, 
 
    lng: 145.12628 
 
}, { 
 
    lat: -37.81324, 
 
    lng: 145.13026000000002 
 
}, { 
 
    lat: -37.81326, 
 
    lng: 145.13044000000002 
 
}, { 
 
    lat: -37.81418, 
 
    lng: 145.13025000000002 
 
}]
html, 
 
body, 
 
#map_canvas { 
 
    height: 100%; 
 
    width: 100%; 
 
    margin: 0px; 
 
    padding: 0px 
 
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry"></script> 
 
<div id="map_canvas"></div>

+0

很棒。谢谢 – puks1978

-1

另一种选择:

  • 简化使用像道格拉斯 - 普克(现在你有一个会产生大量的可能分的加分)
  • 计算所有每一套独特的多边形的不相邻顶点之间的中间点的多边形
  • 消除不在多边形内的任何东西。

使用您的数据集,可得到5个候选点。

proof of concept fiddle

map with markers inside polygon

function initialize() { 
 
    var map = new google.maps.Map(
 
    document.getElementById("map_canvas"), { 
 
     center: new google.maps.LatLng(37.4419, -122.1419), 
 
     zoom: 13, 
 
     mapTypeId: google.maps.MapTypeId.ROADMAP 
 
    }); 
 
    var path = []; 
 
    for (var i = 0; i < data.length; i++) { 
 
    path.push(new google.maps.LatLng(data[i].lat, data[i].lng)); 
 
    } 
 
    var simplifiedPath = GDouglasPeucker(path, 20); 
 

 
    var polygon = new google.maps.Polygon({ 
 
    map: map, 
 
    paths: simplifiedPath 
 
    }); 
 
    var bounds = new google.maps.LatLngBounds(); 
 
    for (var i = 0; i < polygon.getPaths().getAt(0).getLength(); i++) { 
 
    bounds.extend(polygon.getPaths().getAt(0).getAt(i)); 
 
    } 
 
    map.fitBounds(bounds); 
 
    var marker = new google.maps.Marker({ 
 
    map: map, 
 
    position: get_polygon_centroid(data) 
 
    }); 
 
    // check each pair of non-adjacent points 
 
    for (var i = 0; i < polygon.getPaths().getAt(0).getLength() - 2; i++) { 
 
    for (var j = i + 2; j < polygon.getPaths().getAt(0).getLength(); j++) { 
 
     var polyline = new google.maps.Polyline({ 
 
     map: map, 
 
     path: [polygon.getPaths().getAt(0).getAt(i), polygon.getPaths().getAt(0).getAt(j)], 
 
     strokeColor: 'blue' 
 
     }); 
 
     var length = google.maps.geometry.spherical.computeLength(polyline.getPath()); 
 
     var pt = google.maps.geometry.spherical.computeOffset(polygon.getPaths().getAt(0).getAt(i), length/2, 
 
     google.maps.geometry.spherical.computeHeading(polygon.getPaths().getAt(0).getAt(i), polygon.getPaths().getAt(0).getAt(j))); 
 
     console.log("[i=" + i + ",j=" + j + "] abs(diff)=" + Math.abs(i - j) + " coords:" + pt.toUrlValue(6)); 
 
     if (google.maps.geometry.poly.containsLocation(pt, polygon) && 
 
     !google.maps.geometry.poly.isLocationOnEdge(pt, polygon, 10e-8)) { 
 
     var candidateMarker = new google.maps.Marker({ 
 
      map: map, 
 
      position: pt, 
 
      icon: "http://maps.google.com/mapfiles/ms/micons/blue.png", 
 
      title: "[i=" + i + ",j=" + j + "] " + pt.toUrlValue(6) 
 
     }); 
 
     } else polyline.setMap(null); 
 
    } 
 
    } 
 
} 
 
google.maps.event.addDomListener(window, "load", initialize); 
 

 
function get_polygon_centroid(pts) { 
 
    var first = pts[0], 
 
    last = pts[pts.length - 1]; 
 
    if (first.lat != last.lat || first.lng != last.lng) pts.push(first); 
 
    var twicearea = 0, 
 
    x = 0, 
 
    y = 0, 
 
    nPts = pts.length, 
 
    p1, p2, f; 
 
    for (var i = 0, j = nPts - 1; i < nPts; j = i++) { 
 
    p1 = pts[i]; 
 
    p2 = pts[j]; 
 
    f = p1.lng * p2.lat - p2.lng * p1.lat; 
 
    twicearea += f; 
 
    x += (p1.lng + p2.lng) * f; 
 
    y += (p1.lat + p2.lat) * f; 
 
    } 
 
    f = twicearea * 3; 
 
    return { 
 
    lng: x/f, 
 
    lat: y/f 
 
    }; 
 
} 
 

 
var data = [{ 
 
    lat: -37.81418, 
 
    lng: 145.13025000000002 
 
    }, { 
 
    lat: -37.814330000000005, 
 
    lng: 145.13022 
 
    }, { 
 
    lat: -37.813970000000005, 
 
    lng: 145.12727 
 
    }, { 
 
    lat: -37.813750000000006, 
 
    lng: 145.12543000000002 
 
    }, { 
 
    lat: -37.813680000000005, 
 
    lng: 145.12478000000002 
 
    }, { 
 
    lat: -37.81152, 
 
    lng: 145.12517000000003 
 
    }, { 
 
    lat: -37.809380000000004, 
 
    lng: 145.12558 
 
    }, { 
 
    lat: -37.80951, 
 
    lng: 145.12675000000002 
 
    }, { 
 
    lat: -37.80953, 
 
    lng: 145.12685000000002 
 
    }, { 
 
    lat: -37.810590000000005, 
 
    lng: 145.12667000000002 
 
    }, { 
 
    lat: -37.812630000000006, 
 
    lng: 145.12631000000002 
 
    }, { 
 
    lat: -37.81275, 
 
    lng: 145.12628 
 
    }, { 
 
    lat: -37.81324, 
 
    lng: 145.13026000000002 
 
    }, { 
 
    lat: -37.81326, 
 
    lng: 145.13044000000002 
 
    }, { 
 
    lat: -37.81418, 
 
    lng: 145.13025000000002 
 
    }] 
 
    /* Stack-based Douglas Peucker line simplification routine 
 
    returned is a reduced GLatLng array 
 
    After code by Dr. Gary J. Robinson, 
 
    Environmental Systems Science Centre, 
 
    University of Reading, Reading, UK 
 
    */ 
 

 
function GDouglasPeucker(source, kink) 
 
    /* source[] Input coordinates in GLatLngs \t */ 
 
    /* kink \t in metres, kinks above this depth kept */ 
 
    /* kink depth is the height of the triangle abc where a-b and b-c are two consecutive line segments */ 
 
    { 
 
    var n_source, n_stack, n_dest, start, end, i, sig; 
 
    var dev_sqr, max_dev_sqr, band_sqr; 
 
    var x12, y12, d12, x13, y13, d13, x23, y23, d23; 
 
    var F = ((Math.PI/180.0) * 0.5); 
 
    var index = new Array(); /* aray of indexes of source points to include in the reduced line */ 
 
    var sig_start = new Array(); /* indices of start & end of working section */ 
 
    var sig_end = new Array(); 
 

 
    /* check for simple cases */ 
 

 
    if (source.length < 3) 
 
     return (source); /* one or two points */ 
 

 
    /* more complex case. initialize stack */ 
 

 
    n_source = source.length; 
 
    band_sqr = kink * 360.0/(2.0 * Math.PI * 6378137.0); /* Now in degrees */ 
 
    band_sqr *= band_sqr; 
 
    n_dest = 0; 
 
    sig_start[0] = 0; 
 
    sig_end[0] = n_source - 1; 
 
    n_stack = 1; 
 

 
    /* while the stack is not empty ... */ 
 
    while (n_stack > 0) { 
 

 
     /* ... pop the top-most entries off the stacks */ 
 

 
     start = sig_start[n_stack - 1]; 
 
     end = sig_end[n_stack - 1]; 
 
     n_stack--; 
 

 
     if ((end - start) > 1) { /* any intermediate points ? */ 
 

 
     /* ... yes, so find most deviant intermediate point to 
 
       either side of line joining start & end points */ 
 

 
     x12 = (source[end].lng() - source[start].lng()); 
 
     y12 = (source[end].lat() - source[start].lat()); 
 
     if (Math.abs(x12) > 180.0) 
 
      x12 = 360.0 - Math.abs(x12); 
 
     x12 *= Math.cos(F * (source[end].lat() + source[start].lat())); /* use avg lat to reduce lng */ 
 
     d12 = (x12 * x12) + (y12 * y12); 
 

 
     for (i = start + 1, sig = start, max_dev_sqr = -1.0; i < end; i++) { 
 

 
      x13 = (source[i].lng() - source[start].lng()); 
 
      y13 = (source[i].lat() - source[start].lat()); 
 
      if (Math.abs(x13) > 180.0) 
 
      x13 = 360.0 - Math.abs(x13); 
 
      x13 *= Math.cos(F * (source[i].lat() + source[start].lat())); 
 
      d13 = (x13 * x13) + (y13 * y13); 
 

 
      x23 = (source[i].lng() - source[end].lng()); 
 
      y23 = (source[i].lat() - source[end].lat()); 
 
      if (Math.abs(x23) > 180.0) 
 
      x23 = 360.0 - Math.abs(x23); 
 
      x23 *= Math.cos(F * (source[i].lat() + source[end].lat())); 
 
      d23 = (x23 * x23) + (y23 * y23); 
 

 
      if (d13 >= (d12 + d23)) 
 
      dev_sqr = d23; 
 
      else if (d23 >= (d12 + d13)) 
 
      dev_sqr = d13; 
 
      else 
 
      dev_sqr = (x13 * y12 - y13 * x12) * (x13 * y12 - y13 * x12)/d12; // solve triangle 
 

 
      if (dev_sqr > max_dev_sqr) { 
 
      sig = i; 
 
      max_dev_sqr = dev_sqr; 
 
      } 
 
     } 
 

 
     if (max_dev_sqr < band_sqr) { /* is there a sig. intermediate point ? */ 
 
      /* ... no, so transfer current start point */ 
 
      index[n_dest] = start; 
 
      n_dest++; 
 
     } else { 
 
      /* ... yes, so push two sub-sections on stack for further processing */ 
 
      n_stack++; 
 
      sig_start[n_stack - 1] = sig; 
 
      sig_end[n_stack - 1] = end; 
 
      n_stack++; 
 
      sig_start[n_stack - 1] = start; 
 
      sig_end[n_stack - 1] = sig; 
 
     } 
 
     } else { 
 
     /* ... no intermediate points, so transfer current start point */ 
 
     index[n_dest] = start; 
 
     n_dest++; 
 
     } 
 
    } 
 

 
    /* transfer last point */ 
 
    index[n_dest] = n_source - 1; 
 
    n_dest++; 
 

 
    /* make return array */ 
 
    var r = new Array(); 
 
    for (var i = 0; i < n_dest; i++) 
 
     r.push(source[index[i]]); 
 
    return r; 
 

 
    }
html, 
 
body, 
 
#map_canvas { 
 
    height: 100%; 
 
    width: 100%; 
 
    margin: 0px; 
 
    padding: 0px 
 
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry"></script> 
 
<div id="map_canvas"></div>