/**
  * Tests of the geohash::quarter() function.
  *
  * @dataProvider geohashProvider
  * @param string $geohash
  */
 public function testQuarter($geohash)
 {
     $north = geohash::neighbor($geohash, geohash::north);
     $south = geohash::neighbor($geohash, geohash::south);
     $east = geohash::neighbor($geohash, geohash::east);
     $west = geohash::neighbor($geohash, geohash::west);
     $outside_tests = array(geohash::decode($east), geohash::decode($west));
     if ($north) {
         $outside_tests[] = geohash::decode($north);
     }
     if ($south) {
         $outside_tests[] = geohash::decode($south);
     }
     $northwest = geohash::quarter($geohash, geohash::northwest);
     $northeast = geohash::quarter($geohash, geohash::northeast);
     $southwest = geohash::quarter($geohash, geohash::southwest);
     $southeast = geohash::quarter($geohash, geohash::southeast);
     // do the obvious outside tests
     foreach ($outside_tests as $test) {
         $this->assertFalse($northwest->contains($test));
         $this->assertFalse($northeast->contains($test));
         $this->assertFalse($southwest->contains($test));
         $this->assertFalse($southeast->contains($test));
     }
     // test points from the four quadrants
     $box = geohash::decode_box($geohash);
     $dlat = $box->north - $box->south;
     $dlon = $box->east - $box->west;
     $northwest_point = new geopoint($box->north - $dlat / 4, $box->west + $dlon / 4);
     $northeast_point = new geopoint($box->north - $dlat / 4, $box->east - $dlon / 4);
     $southwest_point = new geopoint($box->south + $dlat / 4, $box->west + $dlon / 4);
     $southeast_point = new geopoint($box->south + $dlat / 4, $box->east - $dlon / 4);
     $this->assertTrue($northwest->contains($northwest_point));
     $this->assertFalse($northwest->contains($northeast_point));
     $this->assertFalse($northwest->contains($southwest_point));
     $this->assertFalse($northwest->contains($southeast_point));
     $this->assertFalse($northeast->contains($northwest_point));
     $this->assertTrue($northeast->contains($northeast_point));
     $this->assertFalse($northeast->contains($southwest_point));
     $this->assertFalse($northeast->contains($southeast_point));
     $this->assertFalse($southwest->contains($northwest_point));
     $this->assertFalse($southwest->contains($northeast_point));
     $this->assertTrue($southwest->contains($southwest_point));
     $this->assertFalse($southwest->contains($southeast_point));
     $this->assertFalse($southeast->contains($northwest_point));
     $this->assertFalse($southeast->contains($northeast_point));
     $this->assertFalse($southeast->contains($southwest_point));
     $this->assertTrue($southeast->contains($southeast_point));
     // test the corners
     $northwest_point = new geopoint($box->north, $box->west);
     $northeast_point = new geopoint($box->north, $box->east);
     $southwest_point = new geopoint($box->south, $box->west);
     $southeast_point = new geopoint($box->south, $box->east);
     $this->assertTrue($northwest->contains($northwest_point));
     $this->assertFalse($northwest->contains($northeast_point));
     $this->assertFalse($northwest->contains($southwest_point));
     $this->assertFalse($northwest->contains($southeast_point));
     $this->assertFalse($northeast->contains($northwest_point));
     $this->assertTrue($northeast->contains($northeast_point));
     $this->assertFalse($northeast->contains($southwest_point));
     $this->assertFalse($northeast->contains($southeast_point));
     $this->assertFalse($southwest->contains($northwest_point));
     $this->assertFalse($southwest->contains($northeast_point));
     $this->assertTrue($southwest->contains($southwest_point));
     $this->assertFalse($southwest->contains($southeast_point));
     $this->assertFalse($southeast->contains($northwest_point));
     $this->assertFalse($southeast->contains($northeast_point));
     $this->assertFalse($southeast->contains($southwest_point));
     $this->assertTrue($southeast->contains($southeast_point));
     // test the center
     $center_point = new geopoint($box->north - $dlat / 2, $box->west + $dlon / 2);
     $this->assertTrue($northwest->contains($center_point));
     $this->assertTrue($northeast->contains($center_point));
     $this->assertTrue($southwest->contains($center_point));
     $this->assertTrue($southeast->contains($center_point));
 }
 /**
  * Increase the size the of the circle.
  * @param int $amount
  * @return boolean success|failure
  */
 public function expand($amount = 1)
 {
     if ($this->precision == 1) {
         // currently unwilling to expand to cover the entire globe
         return false;
     }
     $this->precision = max($this->precision - $amount, 1);
     // shrink the geohash, grow the box
     $center = substr($this->center_geohash, 0, $this->precision);
     $box = geohash::decode_box($center);
     $dlat = $box->north - $box->south;
     $dlon = $box->east - $box->west;
     $set = new geohash_set();
     $set->add($center);
     $quadrant = geohash::quadrant($this->center_geohash, $this->precision);
     if ($quadrant == geohash::northeast || $quadrant == geohash::northwest) {
         // north side
         $north = geohash::neighbor($center, geohash::north);
         if ($north) {
             $set->add_set(geohash::halve($north, geohash::south));
             if ($quadrant == geohash::northeast) {
                 $set->add_set(geohash::quarter(geohash::neighbor($north, geohash::east), geohash::southwest));
             } else {
                 // northwest
                 $set->add_set(geohash::quarter(geohash::neighbor($north, geohash::west), geohash::southeast));
             }
             $box->north += $dlat / 2;
         }
     } else {
         // south side
         $south = geohash::neighbor($center, geohash::south);
         if ($south) {
             $set->add_set(geohash::halve($south, geohash::north));
             if ($quadrant == geohash::southeast) {
                 $set->add_set(geohash::quarter(geohash::neighbor($south, geohash::east), geohash::northwest));
             } else {
                 // southwest
                 $set->add_set(geohash::quarter(geohash::neighbor($south, geohash::west), geohash::northeast));
             }
             $box->south -= $dlat / 2;
         }
     }
     if ($quadrant == geohash::northeast || $quadrant == geohash::southeast) {
         // east side
         $set->add_set(geohash::halve(geohash::neighbor($center, geohash::east), geohash::west));
         $box->east += $dlon / 2;
     } else {
         // west side
         $set->add_set(geohash::halve(geohash::neighbor($center, geohash::west), geohash::east));
         $box->west -= $dlon / 2;
     }
     $this->geohash_set = $set;
     $this->max_radius = min($this->center->distance_to_longitude($box->east), $this->center->distance_to_longitude($box->west));
     if ($box->north < 90) {
         $this->max_radius = min($this->center->distance_to_latitude(min($box->north, 90)), $this->max_radius);
     }
     if ($box->south > -90) {
         $this->max_radius = min($this->center->distance_to_latitude(max($box->south, -90)), $this->max_radius);
     }
     return true;
 }