Example #1
0
 /**
  * @dataProvider getRectData
  */
 public function testRectWrapAround($lon)
 {
     $r = GeoMath::rectAround(20, $lon, 10000);
     $this->assertGreaterThan($r['maxLon'], $r['minLon']);
     $this->assertGreaterThanOrEqual(-180, $r['minLon']);
     $this->assertLessThanOrEqual(180, $r['maxLon']);
 }
 public function testRectAround()
 {
     for ($i = 0; $i < 90; $i += 5) {
         $r = GeoMath::rectAround($i, $i, 5000);
         $this->assertEquals(10000, GeoMath::distance($i, $r['minLon'], $i, $r['maxLon']), 'rectAround(): test longitude', 1);
         $this->assertEquals(10000, GeoMath::distance($r['minLat'], $i, $r['maxLat'], $i), 'rectAround(): test latitude', 1);
     }
 }
Example #3
0
 /**
  * @param ApiPageSet $resultPageSet
  * @return
  */
 private function run($resultPageSet = null)
 {
     $params = $this->extractRequestParams();
     $exclude = false;
     $this->requireOnlyOneParameter($params, 'coord', 'page');
     if (isset($params['coord'])) {
         $arr = explode('|', $params['coord']);
         if (count($arr) != 2 || !GeoData::validateCoord($arr[0], $arr[1], $params['globe'])) {
             $this->dieUsage('Invalid coordinate provided', '_invalid-coord');
         }
         $lat = $arr[0];
         $lon = $arr[1];
     } elseif (isset($params['page'])) {
         $t = Title::newFromText($params['page']);
         if (!$t || !$t->canExist()) {
             $this->dieUsage("Invalid page title ``{$params['page']}'' provided", '_invalid-page');
         }
         if (!$t->exists()) {
             $this->dieUsage("Page ``{$params['page']}'' does not exist", '_nonexistent-page');
         }
         $coord = GeoData::getPageCoordinates($t);
         if (!$coord) {
             $this->dieUsage('Page coordinates unknown', '_no-coordinates');
         }
         $lat = $coord->lat;
         $lon = $coord->lon;
         $exclude = $t->getArticleID();
     }
     $lat = floatval($lat);
     $lon = floatval($lon);
     $radius = intval($params['radius']);
     $rect = GeoMath::rectAround($lat, $lon, $radius);
     $dbr = wfGetDB(DB_SLAVE);
     $this->addTables(array('page', 'geo_tags'));
     $this->addFields(array('gt_lat', 'gt_lon', 'gt_primary'));
     // retrieve some fields only if page set needs them
     if (is_null($resultPageSet)) {
         $this->addFields(array('page_id', 'page_namespace', 'page_title'));
     } else {
         $this->addFields(WikiPage::selectFields());
     }
     foreach ($params['prop'] as $prop) {
         if (isset(Coord::$fieldMapping[$prop])) {
             $this->addFields(Coord::$fieldMapping[$prop]);
         }
     }
     $this->addWhereFld('gt_globe', $params['globe']);
     $this->addWhereFld('gt_lat_int', self::intRange($rect["minLat"], $rect["maxLat"]));
     $this->addWhereFld('gt_lon_int', self::intRange($rect["minLon"], $rect["maxLon"]));
     $this->addWhereRange('gt_lat', 'newer', $rect["minLat"], $rect["maxLat"], false);
     if ($rect["minLon"] > $rect["maxLon"]) {
         $this->addWhere("gt_lon < {$rect['maxLon']} OR gt_lon > {$rect['minLon']}");
     } else {
         $this->addWhereRange('gt_lon', 'newer', $rect["minLon"], $rect["maxLon"], false);
     }
     $this->addWhereFld('page_namespace', $params['namespace']);
     $this->addWhere('gt_page_id = page_id');
     if ($exclude) {
         $this->addWhere("gt_page_id <> {$exclude}");
     }
     if (isset($params['maxdim'])) {
         $this->addWhere('gt_dim < ' . intval($params['maxdim']));
     }
     $primary = array_flip($params['primary']);
     $this->addWhereIf(array('gt_primary' => 1), isset($primary['yes']) && !isset($primary['no']));
     $this->addWhereIf(array('gt_primary' => 0), !isset($primary['yes']) && isset($primary['no']));
     $this->addOption('USE INDEX', 'gt_spatial');
     $limit = $params['limit'];
     $res = $this->select(__METHOD__);
     $rows = array();
     foreach ($res as $row) {
         $row->dist = GeoMath::distance($lat, $lon, $row->gt_lat, $row->gt_lon);
         $rows[] = $row;
     }
     // sort in PHP because sorting via SQL involves a filesort
     usort($rows, 'ApiQueryGeoSearch::compareRows');
     $result = $this->getResult();
     foreach ($rows as $row) {
         if (!$limit--) {
             break;
         }
         if (is_null($resultPageSet)) {
             $title = Title::newFromRow($row);
             $vals = array('pageid' => intval($row->page_id), 'ns' => intval($title->getNamespace()), 'title' => $title->getPrefixedText(), 'lat' => floatval($row->gt_lat), 'lon' => floatval($row->gt_lon), 'dist' => round($row->dist, 1));
             if ($row->gt_primary) {
                 $vals['primary'] = '';
             }
             foreach ($params['prop'] as $prop) {
                 if (isset(Coord::$fieldMapping[$prop]) && isset($row->{Coord::$fieldMapping[$prop]})) {
                     $field = Coord::$fieldMapping[$prop];
                     $vals[$prop] = $row->{$field};
                 }
             }
             $fit = $result->addValue(array('query', $this->getModuleName()), null, $vals);
             if (!$fit) {
                 break;
             }
         } else {
             $resultPageSet->processDbRow($row);
         }
     }
     if (is_null($resultPageSet)) {
         $result->setIndexedTagName_internal(array('query', $this->getModuleName()), $this->getModulePrefix());
     }
 }
 private static function parseOneCoord($parts, $coordInfo)
 {
     global $wgContLang;
     $count = count($parts);
     $multiplier = 1;
     $value = 0;
     for ($i = 0; $i < $count; $i++) {
         $part = $parts[$i];
         if ($i > 0 && $i == $count - 1) {
             $suffix = self::parseSuffix($part, $coordInfo);
             if ($suffix) {
                 if ($value < 0) {
                     return false;
                     // "-60°S sounds weird, isn't it?
                 }
                 $value *= $suffix;
                 break;
             } elseif ($i == 3) {
                 return false;
             }
         }
         $part = $wgContLang->parseFormattedNumber($part);
         $min = $i == 0 ? $coordInfo['min'] : 0;
         $max = $i == 0 ? $coordInfo['max'] : 59.999999;
         if (!is_numeric($part) || $part < $min || $part > $max) {
             return false;
         }
         $value += $part * $multiplier * GeoMath::sign($value);
         $multiplier /= 60;
     }
     if ($coordInfo['wrap'] && $value < 0) {
         $value = $coordInfo['max'] + $value;
     }
     if ($value < $coordInfo['min'] || $value > $coordInfo['max']) {
         return false;
     }
     return $value;
 }
 /**
  * @param $resultPageSet ApiPageSet
  * @return
  */
 private function run($resultPageSet = null)
 {
     $params = $this->extractRequestParams();
     $exclude = false;
     $this->requireOnlyOneParameter($params, 'coord', 'page');
     if (isset($params['coord'])) {
         $arr = explode('|', $params['coord']);
         if (count($arr) != 2 || !GeoData::validateCoord($arr[0], $arr[1], $params['globe'])) {
             $this->dieUsage('Invalid coordinate provided', '_invalid-coord');
         }
         $lat = $arr[0];
         $lon = $arr[1];
     } elseif (isset($params['page'])) {
         $t = Title::newFromText($params['page']);
         if (!$t || !$t->canExist()) {
             $this->dieUsage("Invalid page title ``{$params['page']}'' provided", '_invalid-page');
         }
         if (!$t->exists()) {
             $this->dieUsage("Page ``{$params['page']}'' does not exist", '_nonexistent-page');
         }
         $coord = GeoData::getPageCoordinates($t);
         if (!$coord) {
             $this->dieUsage('Page coordinates unknown', '_no-coordinates');
         }
         $lat = $coord->lat;
         $lon = $coord->lon;
         $exclude = $t->getArticleID();
     }
     $lat = floatval($lat);
     $lon = floatval($lon);
     $radius = intval($params['radius']);
     $rect = GeoMath::rectAround($lat, $lon, $radius);
     $dbr = wfGetDB(DB_SLAVE);
     $this->addTables(array('geo_tags', 'page'));
     $this->addFields(array('gt_lat', 'gt_lon', 'gt_primary', "{$dbr->tablePrefix()}gd_distance( {$lat}, {$lon}, gt_lat, gt_lon ) AS dist"));
     // retrieve some fields only if page set needs them
     if (is_null($resultPageSet)) {
         $this->addFields(array('page_id', 'page_namespace', 'page_title'));
     } else {
         $this->addFields(array("{$dbr->tableName('page')}.*"));
     }
     foreach ($params['prop'] as $prop) {
         if (isset(Coord::$fieldMapping[$prop])) {
             $this->addFields(Coord::$fieldMapping[$prop]);
         }
     }
     $this->addWhereFld('gt_globe', $params['globe']);
     $this->addWhereRange('gt_lat', 'newer', $rect["minLat"], $rect["maxLat"], false);
     $this->addWhereRange('gt_lon', 'newer', $rect["minLon"], $rect["maxLon"], false);
     //$this->addWhere( 'dist < ' . intval( $radius ) ); hasta be in HAVING, not WHERE
     $this->addWhereFld('page_namespace', $params['namespace']);
     $this->addWhere('gt_page_id = page_id');
     if ($exclude) {
         $this->addWhere("gt_page_id <> {$exclude}");
     }
     if (isset($params['maxdim'])) {
         $this->addWhere('gt_dim < ' . intval($params['maxdim']));
     }
     $primary = array_flip($params['primary']);
     $this->addWhereIf(array('gt_primary' => 1), isset($primary['yes']) && !isset($primary['no']));
     $this->addWhereIf(array('gt_primary' => 0), !isset($primary['yes']) && isset($primary['no']));
     $this->addOption('ORDER BY', 'dist');
     $limit = $params['limit'];
     $this->addOption('LIMIT', $limit);
     $res = $this->select(__METHOD__);
     $result = $this->getResult();
     foreach ($res as $row) {
         if (is_null($resultPageSet)) {
             $title = Title::newFromRow($row);
             $vals = array('pageid' => intval($row->page_id), 'ns' => intval($title->getNamespace()), 'title' => $title->getPrefixedText(), 'lat' => floatval($row->gt_lat), 'lon' => floatval($row->gt_lon), 'dist' => round($row->dist, 1));
             if ($row->gt_primary) {
                 $vals['primary'] = '';
             }
             foreach ($params['prop'] as $prop) {
                 if (isset(Coord::$fieldMapping[$prop]) && isset($row->{$field})) {
                     $field = Coord::$fieldMapping[$prop];
                     $vals[$prop] = $row->{$field};
                 }
             }
             $fit = $result->addValue(array('query', $this->getModuleName()), null, $vals);
             if (!$fit) {
                 break;
             }
         } else {
             $resultPageSet->processDbRow($row);
         }
     }
 }
    private function order($dest_address)
    {
        $geo = GeoLookup::getLatLon($dest_address);
        $orders_by_name = $orders_by_id = [];
        echo "You want to create an order shipping to " . $geo[2];
        ?>

Enter one product name per line, empty line when order is done
Optionally, enter <product name>=<quantity> to add multiple

><?php 
        // allow user to enter the items for this order
        $stdin = fopen('php://stdin', 'r');
        while ($line = trim(fgets($stdin))) {
            // handle optional <product name>=<quantity>
            $tmp = strrpos($line, '=');
            if ($tmp !== false && ctype_digit(substr($line, $tmp + 1))) {
                $quantity = substr($line, $tmp + 1);
                $line = substr($line, 0, $tmp);
            } else {
                $quantity = 1;
            }
            // attempt to find product, add it to the order
            try {
                $product = Db\ProductApi::getProduct($this->mysqli, $line);
                echo "Product added to order (quantity=" . $quantity . ")\n>";
            } catch (\Exception $e) {
                echo "Cannot find the product -- please try again\n>";
                continue;
            }
            @($orders_by_name[$product->name] += $quantity);
            @($orders_by_id[$product->id] += $quantity);
        }
        fclose($stdin);
        echo "Order Summary:\n";
        foreach ($orders_by_name as $product => $quantity) {
            echo '  ' . substr($product . str_repeat('.', 30), 0, 30) . ' ' . $quantity . "\n";
        }
        // get all warehouses with the required inventory, then pick the closest one
        $warehouses = Db\WarehouseApi::getStockedWarehouses($this->mysqli, $orders_by_id);
        $closest = null;
        $best_dist = null;
        foreach ($warehouses as $i) {
            $this_dist = GeoMath::vincentyGreatCircleDistance($geo[0], $geo[1], $i->lat, $i->lon);
            if ($best_dist === null || $this_dist < $best_dist) {
                $closest = $i;
                $best_dist = $this_dist;
            }
        }
        // final results
        if ($closest === null) {
            echo "\nNo single warehouse has all of the items requested. Sorry\n";
        } else {
            echo "\nThis order will be fulfilled by this warehouse: " . $closest->name . "\n";
            echo "The order destination is " . number_format($best_dist, 1) . "km away from the warehouse.\n";
        }
    }