/** * Generate clustered GEOJSON from incidents * * @param ORM_Iterator|Database_Result|array $incidents collection of incidents * @param int $category_id * @param string $color * @param string $icon * @return array $json_features geojson features array **/ protected function clusters_geojson($incidents, $category_id, $color, $icon) { $json_features = array(); // Extra params for clustering // Start date $start_date = (isset($_GET['s']) and intval($_GET['s']) > 0) ? intval($_GET['s']) : NULL; // End date $end_date = (isset($_GET['e']) and intval($_GET['e']) > 0) ? intval($_GET['e']) : NULL; // Get Zoom Level $zoomLevel = (isset($_GET['z']) and !empty($_GET['z'])) ? (int) $_GET['z'] : 8; $distance = (10000000 >> $zoomLevel) / 100000; // Get markers array if ($incidents instanceof ORM_Iterator) { $markers = $incidents->as_array(); } elseif ($incidents instanceof Database_Result) { $markers = $incidents->result_array(); } else { $markers = $incidents; } $clusters = array(); // Clustered $singles = array(); // Non Clustered // Loop until all markers have been compared while (count($markers)) { $marker = array_pop($markers); $cluster = array(); // Handle both reports::fetch_incidents() response and actual ORM objects $marker->id = isset($marker->incident_id) ? $marker->incident_id : $marker->id; if (isset($marker->latitude) and isset($marker->longitude)) { $marker_latitude = $marker->latitude; $marker_longitude = $marker->longitude; } elseif (isset($marker->location) and isset($marker->location->latitude) and isset($marker->location->longitude)) { $marker_latitude = $marker->location->latitude; $marker_longitude = $marker->location->longitude; } else { // No location - skip this report continue; } // Compare marker against all remaining markers. foreach ($markers as $key => $target) { // Handle both reports::fetch_incidents() response and actual ORM objects if (isset($target->latitude) and isset($target->longitude)) { $target_latitude = $target->latitude; $target_longitude = $target->longitude; } elseif (isset($target->location) and isset($target->location->latitude) and isset($target->location->longitude)) { $target_latitude = $target->location->latitude; $target_longitude = $target->location->longitude; } else { // No location - skip this report continue; } // This function returns the distance between two markers, at a defined zoom level. // $pixels = $this->_pixelDistance($marker['latitude'], $marker['longitude'], // $target['latitude'], $target['longitude'], $zoomLevel); $pixels = abs($marker_longitude - $target_longitude) + abs($marker_latitude - $target_latitude); // If two markers are closer than defined distance, remove compareMarker from array and add to cluster. if ($pixels < $distance) { unset($markers[$key]); $cluster[] = $target; } } // If a marker was added to cluster, also add the marker we were comparing to. if (count($cluster) > 0) { $cluster[] = $marker; $clusters[] = $cluster; } else { $singles[] = $marker; } } // Create Json foreach ($clusters as $cluster) { // Calculate cluster center $bounds = $this->calculate_center($cluster); $cluster_center = array_values($bounds['center']); $southwest = $bounds['sw']['longitude'] . ',' . $bounds['sw']['latitude']; $northeast = $bounds['ne']['longitude'] . ',' . $bounds['ne']['latitude']; // Number of Items in Cluster $cluster_count = count($cluster); // Get the time filter $time_filter = (!empty($start_date) and !empty($end_date)) ? "&s=" . $start_date . "&e=" . $end_date : ""; // Build query string for title link, passing through any GET params // This allows plugins to extend more easily $query = http_build_query(array_merge(array('sw' => $southwest, 'ne' => $northeast), $_GET)); // Build out the JSON string $link = url::site("reports/index/?{$query}"); $item_name = $this->get_title(Kohana::lang('ui_main.reports_count', $cluster_count), $link); $json_item = array(); $json_item['type'] = 'Feature'; $json_item['properties'] = array('name' => $item_name, 'link' => $link, 'category' => array($category_id), 'color' => $color, 'icon' => $icon, 'thumb' => '', 'timestamp' => 0, 'count' => $cluster_count); $json_item['geometry'] = array('type' => 'Point', 'coordinates' => $cluster_center); array_push($json_features, $json_item); } // Pass single points to standard markers json $json_features = array_merge($json_features, $this->markers_geojson($singles, $category_id, $color, $icon, FALSE)); // // E.Kala July 27, 2011 // @todo Parking this geometry business for review // /* //Get Incident Geometries $geometry = $this->_get_geometry($marker->incident_id, $marker->incident_title, $marker->incident_date); if (count($geometry)) { foreach ($geometry as $g) { array_push($json_features, $g); } } */ Event::run('ushahidi_filter.json_cluster_features', $json_features); return $json_features; }