Il mio codice corrente è piuttosto veloce, ma ho bisogno di renderlo ancora più veloce in modo da poter ospitare anche più marcatori. Eventuali suggerimenti?Map Clustering Algorithm
Note:
- il codice viene eseguito più veloce quando l'istruzione SQL è ordinato in base al nome marker - che a sua volta fa un lavoro molto parziale il clustering dei marcatori (i nomi dei marcatori nella stessa posizione sono spesso, ma non sempre simile).
- Non è possibile eseguire il pre-cluster dei marcatori, perché possono essere ricercati e filtrati dinamicamente.
- Ho provato il clustering basato su griglia, ma i risultati spesso non sono molto piacevoli.
- So che i grappoli sono leggermente inclinati su una proiezione di Mercatore.
- Non sono interessato a un servizio di clustering commerciale.
Il codice:
$singleMarkers = array();
$clusterMarkers = array();
while (count($markers)) {
$marker = array_pop($markers);
$cluster = array();
// Compare marker against all remaining markers.
foreach ($markers as $key => $compareMarker) {
// This function returns the distance between two markers, at a defined zoom level.
$pixels = pixelDistance($marker['lat'], $marker['lng'], $compareMarker['lat'], $compareMarker['lng'], $zoomLevel);
// If two markers are closer than defined distance, remove compareMarker from array and add to cluster.
if ($pixels < $distance) {
unset($markers[$key]);
$cluster[] = $compareMarker;
}
}
// If a marker was added to cluster, also add the marker we were comparing to.
if (count($cluster) > 0) {
$cluster[] = $marker;
$clusterMarkers[] = $cluster;
} else {
$singleMarkers[] = $marker;
}
}
function pixelDistance($lat1, $lon1, $lat2, $lon2, $zoom) {
$x1 = $lon1*10000000; //This is what I did to compensate for using lat/lon values instead of pixels.
$y1 = $lat1*10000000;
$x2 = $lon2*10000000;
$y2 = $lat2*10000000;
return sqrt(pow(($x1-$x2),2) + pow(($y1-$y2),2)) >> (21 - $zoom); //21 is the max zoom level
}
UPDATE
Ecco il codice corrente:
$singleMarkers = array();
$clusterMarkers = array();
// Minimum distance between markers to be included in a cluster, at diff. zoom levels
$DISTANCE = (10000000 >> $ZOOM)/100000;
// Loop until all markers have been compared.
while (count($markers)) {
$marker = array_pop($markers);
$cluster = array();
// Compare against all markers which are left.
foreach ($markers as $key => $target) {
$pixels = abs($marker['lat']-$target['lat']) + abs($marker['lng']-$target['lng']);
// If the two markers are closer than given distance remove target marker from array and add it to cluster.
if ($pixels < $DISTANCE) {
unset($markers[$key]);
$cluster[] = $target;
}
}
// If a marker has been added to cluster, add also the one we were comparing to.
if (count($cluster) > 0) {
$cluster[] = $marker;
$clusterMarkers[] = $cluster;
} else {
$singleMarkers[] = $marker;
}
}
Questo ha funzionato alla grande. Il >> (21 - $ zoom) è il modo in cui ho lavorato il livello di zoom nell'equazione - ma ho deciso che sarebbe stato più veloce eliminarlo nell'algoritmo e calcolare la distanza $ qualificante in base allo zoom - quindi ho solo per farlo una volta Grazie! –
Inoltre, l'equazione deve utilizzare il valore assoluto: $ pixel = abs ($ x1- $ x2) + abs ($ y1- $ y2); –