我正在使用此函数来获取不规则形状多边形的质心,但是当多边形是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 :(得分:0)
一个选项:
找到你的质心,如果它不在多边形内
计算计算出的质心和多边形顶点之间的所有点
消除多边形内的任何内容。
使用您的数据集,这将产生7个候选点。
代码段
type
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
}
答案 1 :(得分:-1)
另一种选择:
使用您的数据集,这会产生5个候选点。
enabled
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 */
/* kink 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
}