public function test_bounding_box_for_radius() { // Helsinki-Malmi airport (EFHF) $efhf = new midgardmvc_helper_location_spot(60.254558, 25.042828); // Get 20km bounding box $bbox = midgardmvc_helper_location_utils::get_bounding_box_for_radius($efhf, 20); $this->assertTrue(is_array($bbox)); $this->assertEquals(count($bbox), 2); // Ensure the box limits are in right directions $this->assertEquals(midgardmvc_helper_location_utils::get_bearing($efhf, $bbox[0]), 'SW'); $this->assertEquals(midgardmvc_helper_location_utils::get_bearing($efhf, $bbox[1]), 'NE'); // Check that the distance to a corner is correct. // Note: using 2D trigonometry on 3D globe so numbers are not exact $distance1 = midgardmvc_helper_location_utils::get_distance($bbox[0], $efhf); $this->assertEquals(round($distance1), round(sqrt(pow(20, 2) + pow(20, 2)))); }
/** * Get closest items * * @param string $class MidCOM DBA class to query * @param midgardmvc_helper_location_spot $spot Center position * @param integer $limit How many results to return * @return Array Array of MidCOM DBA objects sorted by proximity */ static function get_closest($class, midgardmvc_helper_location_spot $spot, $limit, $modifier = 0.15) { $classname = midgardmvc_helper_location_utils::get_positioning_class($class); if ($classname != $class) { $direct = false; } else { $direct = true; } $qb = new midgard_query_builder($classname); if (!$direct) { // We're querying a regular DBA object through a location object $qb->add_constraint('parentclass', '=', $class); } static $rounds = 0; $rounds++; $from['latitude'] = $spot->latitude + $modifier; if ($from['latitude'] > 90) { $from['latitude'] = 90; } $from['longitude'] = $spot->longitude - $modifier; if ($from['longitude'] < -180) { $from['longitude'] = -180; } $to['latitude'] = $spot->latitude - $modifier; if ($to['latitude'] < -90) { $to['latitude'] = -90; } $to['longitude'] = $spot->longitude + $modifier; if ($to['longitude'] > 180) { $to['longitude'] = 180; } if (!isset($current_locale)) { $current_locale = setlocale(LC_NUMERIC, '0'); setlocale(LC_NUMERIC, 'C'); } $qb->begin_group('AND'); $qb->add_constraint('latitude', '<', (double) $from['latitude']); $qb->add_constraint('latitude', '>', (double) $to['latitude']); $qb->end_group(); $qb->begin_group('AND'); $qb->add_constraint('longitude', '>', (double) $from['longitude']); $qb->add_constraint('longitude', '<', (double) $to['longitude']); $qb->end_group(); $result_count = $qb->count(); //echo "<br />Round {$rounds}, lat1 {$from['latitude']} lon1 {$from['longitude']}, lat2 {$to['latitude']} lon2 {$to['longitude']}: {$result_count} results\n"; if ($result_count < $limit) { if ($from['latitude'] == 90 && $from['longitude'] == -180 && $to['latitude'] == -90 && $to['longitude'] == 180) { // We've queried the entire globe so we return whatever we got $results = $qb->execute(); $closest = array(); foreach ($results as $result) { $result_spot = new midgardmvc_helper_location_spot($result); $distance = sprintf("%05d", round(midgardmvc_helper_location_utils::get_distance($spot, $result_spot))); if (!$direct) { // Instantiate the real object as the result $result = new $class($result->parent); $result->spot = $result_spot; $result->latitude = $result_spot->latitude; $result->longitude = $result_spot->longitude; } $closest[$distance . $result->guid] = $result; } ksort($closest); reset($closest); return $closest; } $modifier = $modifier * 1.05; setlocale(LC_NUMERIC, $current_locale); return midgardmvc_helper_location_utils::get_closest($class, $spot, $limit, $modifier); } $results = $qb->execute(); $closest = array(); foreach ($results as $result) { $result_spot = new midgardmvc_helper_location_spot($result); $distance = sprintf("%05d", round(midgardmvc_helper_location_utils::get_distance($spot, $result_spot))); if (!$direct) { // Instantiate the real object as the result $result = new $class($result->parent); $result->spot = $result_spot; $result->latitude = $result_spot->latitude; $result->longitude = $result_spot->longitude; } $closest[$distance . $result->guid] = $result; } ksort($closest); reset($closest); while (count($closest) > $limit) { array_pop($closest); } setlocale(LC_NUMERIC, $current_locale); return $closest; }