Horde_Service_Weather::convertDistance PHP Method

convertDistance() public static method

Convert distance between m, km, ft and sm
public static convertDistance ( double $distance, string $from, string $to ) : double
$distance double The distance in $from units.
$from string The units to convert from.
$to string The units to convert to.
return double
    public static function convertDistance($distance, $from, $to)
    {
        $factor = array('m' => array('m' => 1, 'km' => 1000, 'ft' => 3.280839895, 'sm' => 0.0006213699), 'km' => array('m' => 0.001, 'km' => 1, 'ft' => 3280.839895, 'sm' => 0.6213699), 'ft' => array('m' => 0.3048, 'km' => 0.0003048, 'ft' => 1, 'sm' => 0.0001894), 'sm' => array('m' => 0.0016093472, 'km' => 1.6093472, 'ft' => 5280.0106, 'sm' => 1));
        $to = strtolower($to);
        $from = strtolower($from);
        return round($distance * $factor[$from][$to]);
    }

Usage Example

Exemplo n.º 1
0
 /**
  * Parses METAR
  *
  * @param array $data  An array of METAR data lines.
  *
  * @return array  An array of weather data. Possible keys include:
  *  - station:
  *  - dataRaw:
  *  - update:
  *  - updateRaw:
  *  - wind:
  *  - windDegrees:
  *  - windDirection:
  *  - windGust:
  *  - windVariability:
  *  - visibility:
  *  - visQualifier:
  *  - clouds:
  *    - amount
  *    - height
  *    - type
  *  - temperature
  *  - dewpoint
  *  - humidity
  *  - felttemperature
  *  - pressure
  *  - trend
  *    - type
  *    - from
  *    - to
  *    - at
  *  - remark
  *    - autostation
  *    - seapressure
  *    - presschg
  *    - snowdepth
  *    - snowequiv
  *    - cloudtypes
  *    - sunduration
  *    - 1hrtemp
  *    - 1hrdew
  *    - 6hmaxtemp
  *    - 6hmintemp
  *    - 24hmaxtemp
  *    - 24hmintemp
  *    - 3hpresstrend
  *    - nospeci
  *    - sensors
  *    - maintain
  *  - precipitation
  *    - amount
  *    - hours
  */
 protected function _parse(array $data)
 {
     // Eliminate trailing information
     for ($i = 0; $i < sizeof($data); $i++) {
         if (strpos($data[$i], '=') !== false) {
             $data[$i] = substr($data[$i], 0, strpos($data[$i], '='));
             $data = array_slice($data, 0, $i + 1);
             break;
         }
     }
     // Start with parsing the first line for the last update
     $weatherData = array();
     $weatherData['station'] = '';
     $weatherData['dataRaw'] = implode(' ', $data);
     $weatherData['update'] = strtotime(trim($data[0]) . ' GMT');
     $weatherData['updateRaw'] = trim($data[0]);
     if (empty($weatherData['update'])) {
         throw new Horde_Service_Weather_Exception('Unable to parse data.');
     }
     // and prepare the rest for stepping through
     array_shift($data);
     $metar = explode(' ', preg_replace('/\\s{2,}/', ' ', implode(' ', $data)));
     // Trend handling
     $trendCount = 0;
     // Pointer to the array we add the data to. Needed for handling trends.
     $pointer =& $weatherData;
     // Load the metar codes for this go around.
     $metarCode = $this->_getMetarCodes();
     for ($i = 0; $i < sizeof($metar); $i++) {
         $metar[$i] = trim($metar[$i]);
         if (!strlen($metar[$i])) {
             continue;
         }
         $result = array();
         $resultVF = array();
         $lresult = array();
         $found = false;
         foreach ($metarCode as $key => $regexp) {
             // Check if current code matches current metar snippet
             if (($found = preg_match('/^' . $regexp . '$/i', $metar[$i], $result)) == true) {
                 switch ($key) {
                     case 'station':
                         $pointer['station'] = $result[0];
                         unset($metarCode['station']);
                         break;
                     case 'wind':
                         $pointer['wind'] = round(Horde_Service_Weather::convertSpeed($result[2], $result[5], $this->_unitMap[self::UNIT_KEY_SPEED]));
                         $wind_mph = Horde_Service_Weather::convertSpeed($result[2], $result[5], 'mph', $this->_unitMap[self::UNIT_KEY_SPEED]);
                         if ($result[1] == 'VAR' || $result[1] == 'VRB') {
                             // Variable winds
                             $pointer['windDegrees'] = round(Horde_Service_Weather_Translation::t('Variable'));
                             $pointer['windDirection'] = Horde_Service_Weather_Translation::t('Variable');
                         } else {
                             // Save wind degree and calc direction
                             $pointer['windDegrees'] = intval($result[1]);
                             $pointer['windDirection'] = Horde_Service_Weather::degToDirection($result[1]);
                         }
                         if (is_numeric($result[4])) {
                             // Wind with gusts...
                             $pointer['windGust'] = round(Horde_Service_Weather::convertSpeed($result[4], $result[5], $this->_unitMap[self::UNIT_KEY_SPEED]));
                         }
                         break;
                     case 'windVar':
                         // Once more wind, now variability around the current wind-direction
                         $pointer['windVariability'] = array('from' => intval($result[1]), 'to' => intval($result[2]));
                         break;
                     case 'visFrac':
                         // Possible fractional visibility here. Check if it matches with the next METAR piece for visibility
                         if (!isset($metar[$i + 1]) || !preg_match('/^' . $metarCode['visibility'] . '$/i', $result[1] . ' ' . $metar[$i + 1], $resultVF)) {
                             // No next METAR piece available or not matching.
                             $found = false;
                             break;
                         } else {
                             // Match. Hand over result and advance METAR
                             $key = 'visibility';
                             $result = $resultVF;
                             $i++;
                         }
                     case 'visibility':
                         $pointer['visQualifier'] = Horde_Service_Weather_Translation::t('AT');
                         if (is_numeric($result[1]) && $result[1] == 9999) {
                             // Upper limit of visibility range is 10KM.
                             $visibility = Horde_Service_Weather::convertDistance(10, 'km', $this->_unitMap[self::UNIT_KEY_DISTANCE]);
                             $pointer['visQualifier'] = Horde_Service_Weather_Translation::t('BEYOND');
                         } elseif (is_numeric($result[1])) {
                             // 4-digit visibility in m
                             $visibility = Horde_Service_Weather::convertDistance($result[1], 'm', $this->_unitMap[self::UNIT_KEY_DISTANCE]);
                         } elseif (!isset($result[11]) || $result[11] != 'CAVOK') {
                             if ($result[3] == 'M') {
                                 $pointer['visQualifier'] = Horde_Service_Weather_Translation::t('BELOW');
                             } elseif ($result[3] == 'P') {
                                 $pointer['visQualifier'] = Horde_Service_Weather_Translation::t('BEYOND');
                             }
                             if (is_numeric($result[5])) {
                                 // visibility as one/two-digit number
                                 $visibility = Horde_Service_Weather::convertDistance($result[5], $result[10], $this->_unitMap[self::UNIT_KEY_DISTANCE]);
                             } else {
                                 // the y/z part, add if we had a x part (see visibility1)
                                 if (is_numeric($result[7])) {
                                     $visibility = Horde_Service_Weather::convertDistance($result[7] + $result[8] / $result[9], $result[10], $this->_unitMap[self::UNIT_KEY_DISTANCE]);
                                 } else {
                                     $visibility = Horde_Service_Weather::convertDistance($result[8] / $result[9], $result[10], $this->_unitMap[self::UNIT_KEY_DISTANCE]);
                                 }
                             }
                         } else {
                             $pointer['visQualifier'] = Horde_Service_Weather_Translation::t('BEYOND');
                             $visibility = Horde_Service_Weather::convertDistance(10, 'km', $this->_unitMap[self::UNIT_KEY_DISTANCE]);
                             $pointer['clouds'] = array(array('amount' => Horde_Service_Weather_Translation::t('Clear below'), 'height' => 5000));
                             $pointer['condition'] = Horde_Service_Weather_Translation::t('no significant weather');
                         }
                         $pointer['visibility'] = $visibility;
                         break;
                     case 'condition':
                         if (!isset($pointer['condition'])) {
                             $pointer['condition'] = '';
                         } elseif (strlen($pointer['condition']) > 0) {
                             $pointer['condition'] .= ',';
                         }
                         if (in_array(strtolower($result[0]), $this->_conditions)) {
                             // First try matching the complete string
                             $pointer['condition'] .= ' ' . $this->_conditions[strtolower($result[0])];
                         } else {
                             // No luck, match part by part
                             array_shift($result);
                             $result = array_unique($result);
                             foreach ($result as $condition) {
                                 if (strlen($condition) > 0) {
                                     $pointer['condition'] .= ' ' . $this->_conditions[strtolower($condition)];
                                 }
                             }
                         }
                         $pointer['condition'] = trim($pointer['condition']);
                         break;
                     case 'clouds':
                         if (!isset($pointer['clouds'])) {
                             $pointer['clouds'] = array();
                         }
                         if (sizeof($result) == 5) {
                             // Only amount and height
                             $cloud = array('amount' => $this->_clouds[strtolower($result[3])]);
                             if ($result[4] == '///') {
                                 $cloud['height'] = Horde_Service_Weather_Translation::t('station level or below');
                             } else {
                                 $cloud['height'] = $result[4] * 100;
                             }
                         } elseif (sizeof($result) == 6) {
                             // Amount, height and type
                             $cloud = array('amount' => $this->_clouds[strtolower($result[3])], 'type' => $this->_clouds[strtolower($result[5])]);
                             if ($result[4] == '///') {
                                 $cloud['height'] = Horde_Service_Weather_Translation::t('station level or below');
                             } else {
                                 $cloud['height'] = $result[4] * 100;
                             }
                         } else {
                             // SKC or CLR or NSC
                             $cloud = array('amount' => $this->_clouds[strtolower($result[0])]);
                         }
                         $pointer['clouds'][] = $cloud;
                         break;
                     case 'temperature':
                         // normal temperature in first part
                         // negative value
                         if ($result[1] == 'M') {
                             $result[2] *= -1;
                         }
                         $pointer['temperature'] = round(Horde_Service_Weather::convertTemperature($result[2], 'c', $this->_unitMap[self::UNIT_KEY_TEMP]));
                         $temp_f = Horde_Service_Weather::convertTemperature($result[2], 'c', 'f');
                         if (sizeof($result) > 4) {
                             // same for dewpoint
                             if ($result[4] == 'M') {
                                 $result[5] *= -1;
                             }
                             $pointer['dewPoint'] = round(Horde_Service_Weather::convertTemperature($result[5], 'c', $this->_unitMap[self::UNIT_KEY_TEMP]));
                             $pointer['humidity'] = round(Horde_Service_Weather::calculateHumidity($result[2], $result[5])) . '%';
                         }
                         if (isset($pointer['wind'])) {
                             // Now calculate windchill from temperature and windspeed
                             // Note these must be in F and MPH.
                             $pointer['feltTemperature'] = round(Horde_Service_Weather::convertTemperature(Horde_Service_Weather::calculateWindChill($temp_f, $wind_mph), 'f', $this->_unitMap[self::UNIT_KEY_TEMP]));
                         }
                         break;
                     case 'pressure':
                         if ($result[1] == 'A') {
                             // Pressure provided in inches
                             $pointer['pressure'] = round(Horde_Service_Weather::convertPressure($result[2] / 100, 'in', $this->_unitMap[self::UNIT_KEY_PRESSURE]), 2);
                         } elseif ($result[3] == 'Q') {
                             // ... in hectopascal
                             $pointer['pressure'] = round(Horde_Service_Weather::convertPressure($result[4], 'hpa', $this->_unitMap[self::UNIT_KEY_PRESSURE]), 2);
                         }
                         break;
                     case 'trend':
                         // We may have a trend here... extract type and set pointer on
                         // created new array
                         if (!isset($weatherData['trend'])) {
                             $weatherData['trend'] = array();
                             $weatherData['trend'][$trendCount] = array();
                         }
                         $pointer =& $weatherData['trend'][$trendCount];
                         $trendCount++;
                         $pointer['type'] = $result[0];
                         while (isset($metar[$i + 1]) && preg_match('/^(FM|TL|AT)(\\d{2})(\\d{2})$/i', $metar[$i + 1], $lresult)) {
                             if ($lresult[1] == 'FM') {
                                 $pointer['from'] = $lresult[2] . ':' . $lresult[3];
                             } elseif ($lresult[1] == 'TL') {
                                 $pointer['to'] = $lresult[2] . ':' . $lresult[3];
                             } else {
                                 $pointer['at'] = $lresult[2] . ':' . $lresult[3];
                             }
                             // As we have just extracted the time for this trend
                             // from our METAR, increase field-counter
                             $i++;
                         }
                         break;
                     case 'remark':
                         // Remark part begins
                         $metarCode = $this->_getRemarks();
                         $weatherData['remark'] = array();
                         break;
                     case 'autostation':
                         // Which autostation do we have here?
                         if ($result[1] == 0) {
                             $weatherData['remark']['autostation'] = Horde_Service_Weather_Translation::t('Automatic weatherstation w/o precipitation discriminator');
                         } else {
                             $weatherData['remark']['autostation'] = Horde_Service_Weather_Translation::t('Automatic weatherstation w/ precipitation discriminator');
                         }
                         unset($metarCode['autostation']);
                         break;
                     case 'presschg':
                         // Decoding for rapid pressure changes
                         if (strtolower($result[1]) == 'r') {
                             $weatherData['remark']['presschg'] = Horde_Service_Weather_Translation::t('Pressure rising rapidly');
                         } else {
                             $weatherData['remark']['presschg'] = Horde_Service_Weather_Translation::t('Pressure falling rapidly');
                         }
                         unset($metarCode['presschg']);
                         break;
                     case 'seapressure':
                         // Pressure at sea level (delivered in hpa)
                         // Decoding is a bit obscure as 982 gets 998.2
                         // whereas 113 becomes 1113 -> no real rule here
                         if (strtolower($result[1]) != 'no') {
                             if ($result[1] > 500) {
                                 $press = 900 + round($result[1] / 100, 1);
                             } else {
                                 $press = 1000 + $result[1];
                             }
                             $weatherData['remark']['seapressure'] = Horde_Service_Weather::convertPressure($press, 'hpa', $this->_unitMap[self::UNIT_KEY_PRESSURE]);
                         }
                         unset($metarCode['seapressure']);
                         break;
                     case 'precip':
                         // Precipitation in inches
                         if (!isset($weatherData['precipitation'])) {
                             $weatherData['precipitation'] = array();
                         }
                         if (!is_numeric($result[2])) {
                             $precip = 'indeterminable';
                         } elseif ($result[2] == '0000') {
                             $precip = 'traceable';
                         } else {
                             $precip = $result[2] / 100;
                         }
                         $weatherData['precipitation'][] = array('amount' => $precip, 'hours' => $this->_hours[$result[1]]);
                         break;
                     case 'snowdepth':
                         // Snow depth in inches
                         // @todo convert to metric
                         $weatherData['remark']['snowdepth'] = $result[1];
                         unset($metarCode['snowdepth']);
                         break;
                     case 'snowequiv':
                         // Same for equivalent in Water... (inches)
                         // @todo convert
                         $weatherData['remark']['snowequiv'] = $result[1] / 10;
                         unset($metarCode['snowequiv']);
                         break;
                     case 'cloudtypes':
                         // Cloud types
                         $weatherData['remark']['cloudtypes'] = array('low' => $this->_cloudTypes['low'][$result[1]], 'middle' => $this->_cloudTypes['middle'][$result[2]], 'high' => $this->_cloudTypes['high'][$result[3]]);
                         unset($metarCode['cloudtypes']);
                         break;
                     case 'sunduration':
                         // Duration of sunshine (in minutes)
                         $weatherData['remark']['sunduration'] = sprintf(Horde_Service_Weather_Translation::t('Total minutes of sunshine: %s'), $result[1]);
                         unset($metarCode['sunduration']);
                         break;
                     case '1htempdew':
                         // Temperatures in the last hour in C
                         if ($result[1] == '1') {
                             $result[2] *= -1;
                         }
                         $weatherData['remark']['1htemp'] = Horde_Service_Weather::convertTemperature($result[2] / 10, 'c', $this->_unitMap[self::UNIT_KEY_TEMP]);
                         if (sizeof($result) > 3) {
                             // same for dewpoint
                             if ($result[4] == '1') {
                                 $result[5] *= -1;
                             }
                             $weatherData['remark']['1hdew'] = Horde_Service_Weather::convertTemperature($result[5] / 10, 'c', $this->_unitMap[self::UNIT_KEY_TEMP]);
                         }
                         unset($metarCode['1htempdew']);
                         break;
                     case '6hmaxtemp':
                         // Max temperature in the last 6 hours in C
                         if ($result[1] == '1') {
                             $result[2] *= -1;
                         }
                         $weatherData['remark']['6hmaxtemp'] = Horde_Service_Weather::convertTemperature($result[2] / 10, 'c', $this->_unitMap[self::UNIT_KEY_TEMP]);
                         unset($metarCode['6hmaxtemp']);
                         break;
                     case '6hmintemp':
                         // Min temperature in the last 6 hours in C
                         if ($result[1] == '1') {
                             $result[2] *= -1;
                         }
                         $weatherData['remark']['6hmintemp'] = Horde_Service_Weather::convertTemperature($result[2] / 10, 'c', $this->_unitMap[self::UNIT_KEY_TEMP]);
                         unset($metarCode['6hmintemp']);
                         break;
                     case '24htemp':
                         // Max/Min temperatures in the last 24 hours in C
                         if ($result[1] == '1') {
                             $result[2] *= -1;
                         }
                         $weatherData['remark']['24hmaxtemp'] = Horde_Service_Weather::convertTemperature($result[2] / 10, 'c', $this->_unitMap[self::UNIT_KEY_TEMP]);
                         if ($result[3] == '1') {
                             $result[4] *= -1;
                         }
                         $weatherData['remark']['24hmintemp'] = Horde_Service_Weather::convertTemperature($result[4] / 10, 'c', $this->_unitMap[self::UNIT_KEY_TEMP]);
                         unset($metarCode['24htemp']);
                         break;
                     case '3hpresstend':
                         // Pressure tendency of the last 3 hours
                         // no special processing, just passing the data
                         $weatherData['remark']['3hpresstend'] = array('presscode' => $result[1], 'presschng' => Horde_Service_Weather::convertPressure($result[2] / 10, 'hpa', $this->_unitMap[self::UNIT_KEY_PRESSURE]), 'description' => $result[1] >= 0 && $result[1] <= 3 ? Horde_Service_Weather_Translation::t('Rising') : $result[1] == 4 ? Horde_Service_Weather_Translation::t('Steady') : $result[1] > 4 ? Horde_Service_Weather_Translation::t('Falling') : '');
                         unset($metarCode['3hpresstend']);
                         break;
                     case 'nospeci':
                         // No change during the last hour
                         $weatherData['remark']['nospeci'] = Horde_Service_Weather_Translation::t('No changes in weather conditions');
                         unset($metarCode['nospeci']);
                         break;
                     case 'sensors':
                         // We may have multiple broken sensors, so do not unset
                         if (!isset($weatherData['remark']['sensors'])) {
                             $weatherData['remark']['sensors'] = array();
                         }
                         $weatherData['remark']['sensors'][strtolower($result[0])] = $this->_sensors[strtolower($result[0])];
                         break;
                     case 'maintain':
                         $weatherData['remark']['maintain'] = Horde_Service_Weather_Translation::t('Maintainance needed');
                         unset($metarCode['maintain']);
                         break;
                     default:
                         // Do nothing, just prevent further matching
                         unset($metarCode[$key]);
                         break;
                 }
                 if ($found) {
                     break;
                 }
             }
         }
     }
     return $weatherData;
 }
All Usage Examples Of Horde_Service_Weather::convertDistance