Merge pull request #322 from nabeelio/fix-unit-classes

Cleanup SI Unit classes; METAR fixes
This commit is contained in:
Nabeel S
2019-07-15 15:36:54 -04:00
committed by GitHub
33 changed files with 399 additions and 228 deletions

View File

@@ -2,11 +2,7 @@
namespace App\Http\Resources; namespace App\Http\Resources;
use App\Support\Units\Distance; class Acars extends Response
use App\Support\Units\Fuel;
use Illuminate\Http\Resources\Json\Resource;
class Acars extends Resource
{ {
/** /**
* Transform the resource into an array. * Transform the resource into an array.
@@ -17,16 +13,13 @@ class Acars extends Resource
*/ */
public function toArray($request) public function toArray($request)
{ {
$obj = parent::toArray($request); $res = parent::toArray($request);
if ($this->distance instanceof Distance) { $this->checkUnitFields($res, [
$obj['distance'] = $this->distance->units; 'distance',
} 'fuel',
]);
if ($this->fuel instanceof Fuel) { return $res;
$obj['fuel'] = $this->fuel->units;
}
return $obj;
} }
} }

View File

@@ -2,12 +2,10 @@
namespace App\Http\Resources; namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
/** /**
* ACARS table but only include the fields for the routes * ACARS table but only include the fields for the routes
* Class AcarsRoute * Class AcarsRoute
*/ */
class AcarsLog extends Resource class AcarsLog extends Response
{ {
} }

View File

@@ -2,12 +2,10 @@
namespace App\Http\Resources; namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
/** /**
* ACARS table but only include the fields for the routes * ACARS table but only include the fields for the routes
* Class AcarsRoute * Class AcarsRoute
*/ */
class AcarsRoute extends Resource class AcarsRoute extends Response
{ {
} }

View File

@@ -2,8 +2,6 @@
namespace App\Http\Resources; namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource; class Aircraft extends Response
class Aircraft extends Resource
{ {
} }

View File

@@ -2,9 +2,7 @@
namespace App\Http\Resources; namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource; class Airline extends Response
class Airline extends Resource
{ {
public function toArray($request) public function toArray($request)
{ {

View File

@@ -2,8 +2,6 @@
namespace App\Http\Resources; namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource; class Airport extends Response
class Airport extends Resource
{ {
} }

View File

@@ -2,9 +2,7 @@
namespace App\Http\Resources; namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource; class Award extends Response
class Award extends Resource
{ {
public function toArray($request) public function toArray($request)
{ {

View File

@@ -2,15 +2,13 @@
namespace App\Http\Resources; namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource; class Bid extends Response
class Bid extends Resource
{ {
public function toArray($request) public function toArray($request)
{ {
$bid = parent::toArray($request); $res = parent::toArray($request);
$bid['flight'] = new Flight($this->flight); $res['flight'] = new Flight($this->flight);
return $bid; return $res;
} }
} }

View File

@@ -2,10 +2,7 @@
namespace App\Http\Resources; namespace App\Http\Resources;
use App\Support\Units\Distance; class Flight extends Response
use Illuminate\Http\Resources\Json\Resource;
class Flight extends Resource
{ {
/** /**
* Set the fields on the flight object * Set the fields on the flight object
@@ -24,19 +21,19 @@ class Flight extends Resource
public function toArray($request) public function toArray($request)
{ {
$flight = parent::toArray($request); $res = parent::toArray($request);
$flight['ident'] = $this->ident; $res['ident'] = $this->ident;
// Return multiple measures so the client can pick what they want // Return multiple measures so the client can pick what they want
if ($this->distance instanceof Distance) { $this->checkUnitFields($res, [
$flight['distance'] = $this->distance->units; 'distance',
} ]);
$flight['airline'] = new Airline($this->airline); $res['airline'] = new Airline($this->airline);
$flight['subfleets'] = Subfleet::collection($this->subfleets); $res['subfleets'] = Subfleet::collection($this->subfleets);
$flight['fields'] = $this->setFields(); $res['fields'] = $this->setFields();
return $flight; return $res;
} }
} }

View File

@@ -2,9 +2,7 @@
namespace App\Http\Resources; namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource; class JournalTransaction extends Response
class JournalTransaction extends Resource
{ {
public function toArray($request) public function toArray($request)
{ {

View File

@@ -9,16 +9,16 @@ class Navdata extends Resource
{ {
public function toArray($request) public function toArray($request)
{ {
$point = parent::toArray($request); $res = parent::toArray($request);
// Some details about the navaid type // Some details about the navaid type
$type = [ $type = [
'type' => $point['type'], 'type' => $res['type'],
'name' => NavaidType::label($point['type']), 'name' => NavaidType::label($res['type']),
]; ];
$point['type'] = $type; $res['type'] = $type;
return $point; return $res;
} }
} }

View File

@@ -18,12 +18,12 @@ class News extends Resource
*/ */
public function toArray($request) public function toArray($request)
{ {
$resp = parent::toArray($request); $res = parent::toArray($request);
$resp['user'] = [ $res['user'] = [
'id' => $this->user->id, 'id' => $this->user->id,
'name' => $this->user->name, 'name' => $this->user->name,
]; ];
return $resp; return $res;
} }
} }

View File

@@ -3,11 +3,8 @@
namespace App\Http\Resources; namespace App\Http\Resources;
use App\Models\Enums\PirepStatus; use App\Models\Enums\PirepStatus;
use App\Support\Units\Distance;
use App\Support\Units\Fuel;
use Illuminate\Http\Resources\Json\Resource;
class Pirep extends Resource class Pirep extends Response
{ {
/** /**
* Transform the resource into an array. * Transform the resource into an array.
@@ -18,43 +15,36 @@ class Pirep extends Resource
*/ */
public function toArray($request) public function toArray($request)
{ {
$pirep = parent::toArray($request); $res = parent::toArray($request);
$res['ident'] = $this->ident;
$pirep['ident'] = $this->ident; $this->checkUnitFields($res, [
'distance',
if ($this->distance instanceof Distance) { 'fuel_used',
$pirep['distance'] = $this->distance->units; 'planned_distance',
} ]);
if ($this->fuel_used instanceof Fuel) {
$pirep['fuel_used'] = $this->fuel_used->units;
}
if ($this->planned_distance instanceof Distance) {
$pirep['planned_distance'] = $this->planned_distance->units;
}
/* /*
* Relationship fields * Relationship fields
*/ */
if ($this->block_on_time) { if ($this->block_on_time) {
$pirep['block_on_time'] = $this->block_on_time->toIso8601ZuluString(); $res['block_on_time'] = $this->block_on_time->toIso8601ZuluString();
} }
if ($this->block_off_time) { if ($this->block_off_time) {
$pirep['block_off_time'] = $this->block_off_time->toIso8601ZuluString(); $res['block_off_time'] = $this->block_off_time->toIso8601ZuluString();
} }
$pirep['status_text'] = PirepStatus::label($this->status); $res['status_text'] = PirepStatus::label($this->status);
$pirep['airline'] = new Airline($this->airline); $res['airline'] = new Airline($this->airline);
$pirep['dpt_airport'] = new Airport($this->dpt_airport); $res['dpt_airport'] = new Airport($this->dpt_airport);
$pirep['arr_airport'] = new Airport($this->arr_airport); $res['arr_airport'] = new Airport($this->arr_airport);
$pirep['position'] = new Acars($this->position); $res['position'] = new Acars($this->position);
$pirep['comments'] = PirepComment::collection($this->comments); $res['comments'] = PirepComment::collection($this->comments);
$pirep['user'] = [ $res['user'] = [
'id' => $this->user->id, 'id' => $this->user->id,
'name' => $this->user->name, 'name' => $this->user->name,
'home_airport_id' => $this->user->home_airport_id, 'home_airport_id' => $this->user->home_airport_id,
@@ -62,8 +52,8 @@ class Pirep extends Resource
]; ];
// format to kvp // format to kvp
$pirep['fields'] = new PirepFieldCollection($this->fields); $res['fields'] = new PirepFieldCollection($this->fields);
return $pirep; return $res;
} }
} }

View File

@@ -11,11 +11,11 @@ class PirepFieldCollection extends ResourceCollection
{ {
public function toArray($request) public function toArray($request)
{ {
$obj = []; $res = [];
foreach ($this->collection as $field) { foreach ($this->collection as $field) {
$obj[$field->name] = $field->value; $res[$field->name] = $field->value;
} }
return $obj; return $res;
} }
} }

View File

@@ -2,6 +2,7 @@
namespace App\Http\Resources; namespace App\Http\Resources;
use App\Interfaces\Unit;
use Illuminate\Http\Resources\Json\Resource; use Illuminate\Http\Resources\Json\Resource;
/** /**
@@ -9,4 +10,21 @@ use Illuminate\Http\Resources\Json\Resource;
*/ */
class Response extends Resource class Response extends Resource
{ {
/**
* Iterate through the list of $fields and check if they're a "Unit"
* If they are, then add the response
*
* @param $response
* @param array $fields
*/
public function checkUnitFields(&$response, array $fields): void
{
foreach ($fields as $f) {
if ($this->{$f} instanceof Unit) {
$response[$f] = $this->{$f}->getResponseUnits();
} else {
$response[$f] = $this->{$f};
}
}
}
} }

View File

@@ -8,9 +8,9 @@ class Subfleet extends Resource
{ {
public function toArray($request) public function toArray($request)
{ {
$arr = parent::toArray($request); $res = parent::toArray($request);
$arr['aircraft'] = Aircraft::collection($this->aircraft); $res['aircraft'] = Aircraft::collection($this->aircraft);
return $arr; return $res;
} }
} }

View File

@@ -20,18 +20,19 @@ class Unit implements ArrayAccess
/** /**
* All of the units of this class * All of the units of this class
*
* @var array
*/ */
public $units; public $units;
/** /**
* Holds an instance of the PhpUnit type * Holds an instance of the PhpUnit type
*
* @var
*/ */
protected $instance; protected $instance;
/**
* Units that are included as part of the REST response
*/
public $responseUnits = [];
/** /**
* @return mixed * @return mixed
*/ */
@@ -40,6 +41,31 @@ class Unit implements ArrayAccess
return $this->__toString(); return $this->__toString();
} }
/**
* Just call toUnit() on the PhpUnitOfMeasure instance
*
* @param string $unit
*
* @return mixed
*/
public function toUnit($unit)
{
return $this->instance->toUnit($unit);
}
/**
* Return all of the units that get sent back in a response
*/
public function getResponseUnits(): array
{
$response = [];
foreach ($this->responseUnits as $unit) {
$response[$unit] = $this[$unit];
}
return $response;
}
/** /**
* Implements ArrayAccess * Implements ArrayAccess
* *
@@ -61,7 +87,7 @@ class Unit implements ArrayAccess
*/ */
public function offsetGet($offset) public function offsetGet($offset)
{ {
return $this->units[$offset]; return round($this->instance->toUnit($offset), 2);
} }
/** /**
@@ -72,7 +98,7 @@ class Unit implements ArrayAccess
*/ */
public function offsetSet($offset, $value) public function offsetSet($offset, $value)
{ {
$this->units[$offset] = $value; // $this->units[$offset] = $value;
} }
/** /**
@@ -82,7 +108,7 @@ class Unit implements ArrayAccess
*/ */
public function offsetUnset($offset) public function offsetUnset($offset)
{ {
$this->units[$offset] = null; // $this->units[$offset] = null;
} }
/** /**

View File

@@ -133,9 +133,9 @@ class Flight extends Model
} }
/** /**
* Return a new Length unit so conversions can be made * Return a new Distance unit so conversions can be made
* *
* @return int|Distance * @return Distance
*/ */
public function getDistanceAttribute() public function getDistanceAttribute()
{ {
@@ -148,9 +148,9 @@ class Flight extends Model
return new Distance($distance, config('phpvms.internal_units.distance')); return new Distance($distance, config('phpvms.internal_units.distance'));
} catch (NonNumericValue $e) { } catch (NonNumericValue $e) {
return 0; return new Distance(0, config('phpvms.internal_units.distance', 'nmi'));
} catch (NonStringUnitName $e) { } catch (NonStringUnitName $e) {
return 0; return new Distance(0, config('phpvms.internal_units.distance', 'nmi'));
} }
} }

View File

@@ -0,0 +1,40 @@
<?php
namespace App\Providers;
use Exception;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\ServiceProvider;
use PhpUnitsOfMeasure\Exception\NonStringUnitName;
use PhpUnitsOfMeasure\Exception\UnknownUnitOfMeasure;
use PhpUnitsOfMeasure\PhysicalQuantity\Temperature;
/**
* Add new measurement units to PhpUnitsOfMeasure
*/
class MeasurementsProvider extends ServiceProvider
{
public function boot(): void
{
try {
$this->addTemperatures();
} catch (Exception $e) {
Log::error($e);
}
}
/**
* Add lowercase temperature units
*
* @throws NonStringUnitName
* @throws UnknownUnitOfMeasure
*/
protected function addTemperatures()
{
$fUnit = Temperature::getUnit('F');
$fUnit->addAlias('f');
$cUnit = Temperature::getUnit('C');
$cUnit->addAlias('c');
}
}

View File

@@ -4,7 +4,12 @@ namespace App\Support;
use App\Support\Units\Altitude; use App\Support\Units\Altitude;
use App\Support\Units\Distance; use App\Support\Units\Distance;
use App\Support\Units\Pressure;
use App\Support\Units\Temperature; use App\Support\Units\Temperature;
use App\Support\Units\Velocity;
use function count;
use PhpUnitsOfMeasure\Exception\NonNumericValue;
use PhpUnitsOfMeasure\Exception\NonStringUnitName;
/** /**
* Class Metar * Class Metar
@@ -390,6 +395,86 @@ class Metar implements \ArrayAccess
} }
} }
/**
* Return an Altitude value or object
*
* @param int|float $value
* @param string $unit "feet" or "meters"
*
* @throws NonStringUnitName
* @throws NonNumericValue
*
* @return Altitude
*/
protected function createAltitude($value, $unit)
{
return new Altitude($value, $unit);
}
/**
* Return a Distance value or object
*
* @param int|float $value
* @param string $unit "m" (meters) or "mi" (miles)
*
* @throws NonNumericValue
* @throws NonStringUnitName
*
* @return Distance
*/
protected function createDistance($value, $unit)
{
return new Distance($value, $unit);
}
/**
* Return a Pressure value or object
*
* @param int|float $value
* @param string $unit "F" or "C"
*
* @throws NonNumericValue
* @throws NonStringUnitName
*
* @return Pressure
*/
protected function createPressure($value, $unit)
{
return new Pressure($value, $unit);
}
/**
* Return a Temperature value or object
*
* @param int|float $value
* @param string $unit "F" or "C"
*
* @throws NonNumericValue
* @throws NonStringUnitName
*
* @return Temperature
*/
protected function createTemperature($value, $unit)
{
return new Temperature($value, $unit);
}
/**
* Create a new velocity unit
*
* @param int|float $value
* @param string $unit "knots", "km/hour", "m/s"
*
* @throws NonStringUnitName
* @throws NonNumericValue
*
* @return Velocity
*/
protected function createVelocity($value, $unit)
{
return new Velocity($value, $unit);
}
/** /**
* Parses the METAR or TAF information and returns result array. * Parses the METAR or TAF information and returns result array.
*/ */
@@ -398,8 +483,8 @@ class Metar implements \ArrayAccess
$this->raw_parts = explode(' ', $this->raw); $this->raw_parts = explode(' ', $this->raw);
$current_method = 0; $current_method = 0;
$raw_part_count = \count($this->raw_parts); $raw_part_count = count($this->raw_parts);
$method_name_count = \count(static::$method_names); $method_name_count = count(static::$method_names);
while ($this->part < $raw_part_count) { while ($this->part < $raw_part_count) {
$this->method = $current_method; $this->method = $current_method;
@@ -591,6 +676,8 @@ class Metar implements \ArrayAccess
* Decodes station code. * Decodes station code.
* *
* @param mixed $part * @param mixed $part
*
* @return bool
*/ */
private function get_station($part) private function get_station($part)
{ {
@@ -609,6 +696,8 @@ class Metar implements \ArrayAccess
* Format is ddhhmmZ where dd = day, hh = hours, mm = minutes in UTC time. * Format is ddhhmmZ where dd = day, hh = hours, mm = minutes in UTC time.
* *
* @param mixed $part * @param mixed $part
*
* @return bool
*/ */
private function get_time($part) private function get_time($part)
{ {
@@ -648,6 +737,8 @@ class Metar implements \ArrayAccess
* Ignore station type if present. * Ignore station type if present.
* *
* @param mixed $part * @param mixed $part
*
* @return bool
*/ */
private function get_station_type($part) private function get_station_type($part)
{ {
@@ -750,8 +841,8 @@ class Metar implements \ArrayAccess
* *
* @param mixed $part * @param mixed $part
* *
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName * @throws NonStringUnitName
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue * @throws NonNumericValue
* *
* @return bool * @return bool
*/ */
@@ -772,7 +863,7 @@ class Metar implements \ArrayAccess
// Cloud and visibilty OK or ICAO visibilty greater than 10 km // Cloud and visibilty OK or ICAO visibilty greater than 10 km
if ($found[1] === 'CAVOK' || $found[1] === '9999') { if ($found[1] === 'CAVOK' || $found[1] === '9999') {
$this->set_result_value('visibility', new Distance(10000, 'm')); $this->set_result_value('visibility', $this->createDistance(10000, 'm'));
$this->set_result_value('visibility_report', 'Greater than 10 km'); $this->set_result_value('visibility_report', 'Greater than 10 km');
/* @noinspection NotOptimalIfConditionsInspection */ /* @noinspection NotOptimalIfConditionsInspection */
if ($found[1] === 'CAVOK') { if ($found[1] === 'CAVOK') {
@@ -787,7 +878,7 @@ class Metar implements \ArrayAccess
// ICAO visibility (in meters) // ICAO visibility (in meters)
if (isset($found[2]) && !empty($found[2])) { if (isset($found[2]) && !empty($found[2])) {
$visibility = new Distance((int) $found[2], 'm'); $visibility = $this->createDistance((int) $found[2], 'm');
} // US visibility (in miles) } // US visibility (in miles)
else { else {
if (isset($found[3]) && !empty($found[3])) { if (isset($found[3]) && !empty($found[3])) {
@@ -800,7 +891,7 @@ class Metar implements \ArrayAccess
$visibility = (int) $found[4]; $visibility = (int) $found[4];
} }
$visibility = new Distance($visibility, 'mi'); $visibility = $this->createDistance($visibility, 'mi');
} }
$unit = ' meters'; $unit = ' meters';
@@ -824,9 +915,9 @@ class Metar implements \ArrayAccess
* *
* @param $part * @param $part
* *
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName * @throws NonStringUnitName
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue * @throws NonNumericValue
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName * @throws NonStringUnitName
* *
* @return bool * @return bool
*/ */
@@ -836,7 +927,7 @@ class Metar implements \ArrayAccess
return false; return false;
} }
$meters = new Distance((int) $found[1], 'm'); $meters = $this->createDistance((int) $found[1], 'm');
$this->set_result_value('visibility_min', $meters); $this->set_result_value('visibility_min', $meters);
if (isset($found[2]) && !empty($found[2])) { if (isset($found[2]) && !empty($found[2])) {
@@ -854,8 +945,8 @@ class Metar implements \ArrayAccess
* *
* @param $part * @param $part
* *
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName * @throws NonStringUnitName
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue * @throws NonNumericValue
* *
* @return bool * @return bool
*/ */
@@ -899,13 +990,13 @@ class Metar implements \ArrayAccess
// Runway visual range // Runway visual range
if (isset($found[6])) { if (isset($found[6])) {
if (!empty($found[4])) { if (!empty($found[4])) {
$observed['interval_min'] = new Distance($found[4], $unit); $observed['interval_min'] = $this->createDistance($found[4], $unit);
$observed['interval_max'] = new Distance($found[6], $unit); $observed['interval_max'] = $this->createDistance($found[6], $unit);
if (!empty($found[5])) { if (!empty($found[5])) {
$observed['variable_prefix'] = $found[5]; $observed['variable_prefix'] = $found[5];
} }
} else { } else {
$observed['variable'] = new Distance($found[6], $unit); $observed['variable'] = $this->createDistance($found[6], $unit);
} }
} }
@@ -960,8 +1051,8 @@ class Metar implements \ArrayAccess
* *
* @param $part * @param $part
* *
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName * @throws NonStringUnitName
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue * @throws NonNumericValue
* *
* @return bool * @return bool
*/ */
@@ -990,7 +1081,7 @@ class Metar implements \ArrayAccess
} }
} // Cloud cover observed } // Cloud cover observed
elseif (isset($found[5]) && !empty($found[5]) && is_numeric($found[5])) { elseif (isset($found[5]) && !empty($found[5]) && is_numeric($found[5])) {
$observed['height'] = new Altitude($found[5] * 100, 'feet'); $observed['height'] = $this->createAltitude($found[5] * 100, 'feet');
// Cloud height // Cloud height
if (null === $this->result['cloud_height']['m'] || $observed['height']['m'] < $this->result['cloud_height']['m']) { if (null === $this->result['cloud_height']['m'] || $observed['height']['m'] < $this->result['cloud_height']['m']) {
@@ -1047,8 +1138,10 @@ class Metar implements \ArrayAccess
* *
* @param mixed $part * @param mixed $part
* *
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName * @throws NonNumericValue
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue * @throws NonStringUnitName
*
* @return bool
*/ */
private function get_temperature($part) private function get_temperature($part)
{ {
@@ -1065,20 +1158,20 @@ class Metar implements \ArrayAccess
// Temperature // Temperature
$temperature_c = (int) str_replace('M', '-', $found[1]); $temperature_c = (int) str_replace('M', '-', $found[1]);
$temperature = new Temperature($temperature_c, 'C'); $temperature = $this->createTemperature($temperature_c, 'C');
$this->set_result_value('temperature', $temperature); $this->set_result_value('temperature', $temperature);
$this->calculate_wind_chill($temperature['f']); $this->calculate_wind_chill($temperature['F']);
// Dew point // Dew point
if (isset($found[2]) && '' !== $found[2] && $found[2] !== 'XX') { if (isset($found[2]) && '' !== $found[2] && $found[2] !== 'XX') {
$dew_point_c = (int) str_replace('M', '-', $found[2]); $dew_point_c = (int) str_replace('M', '-', $found[2]);
$dew_point = new Temperature($dew_point_c, 'C'); $dew_point = $this->createTemperature($dew_point_c, 'C');
$rh = round(100 * (((112 - (0.1 * $temperature_c) + $dew_point_c) / (112 + (0.9 * $temperature_c))) ** 8)); $rh = round(100 * (((112 - (0.1 * $temperature_c) + $dew_point_c) / (112 + (0.9 * $temperature_c))) ** 8));
$this->set_result_value('dew_point', $dew_point); $this->set_result_value('dew_point', $dew_point);
$this->set_result_value('humidity', $rh); $this->set_result_value('humidity', $rh);
$this->calculate_heat_index($temperature['f'], $rh); $this->calculate_heat_index($temperature['F'], $rh);
} }
$this->method++; $this->method++;
@@ -1096,21 +1189,26 @@ class Metar implements \ArrayAccess
* 1 lb/sq in = 0.491154 in Hg = 0.014504 hPa * 1 lb/sq in = 0.491154 in Hg = 0.014504 hPa
* 1 atm = 0.33421 in Hg = 0.0009869 hPa * 1 atm = 0.33421 in Hg = 0.0009869 hPa
* *
*
* @param mixed $part * @param mixed $part
*
* @throws NonNumericValue
* @throws NonStringUnitName
*
* @return bool
*/ */
private function get_pressure($part) private function get_pressure($part)
{ {
if (!preg_match('@^(Q|A)(////|[\d]{4})@', $part, $found)) { if (!preg_match('@^(Q|A)(////|[\d]{4})@', $part, $found)) {
return false; return false;
} }
$pressure = (int) $found[2]; $pressure = (int) $found[2];
if ($found[1] === 'A') { if ($found[1] === 'A') {
$pressure /= 100; $pressure /= 100;
} }
$this->set_result_value('barometer', $pressure); // units are hPa $this->set_result_value('barometer', $this->createPressure($pressure, 'hPa'));
$this->set_result_value('barometer_mb', $pressure); // units are hPa
$this->set_result_value('barometer_in', round(0.02953 * $pressure, 2)); // convert to in Hg
$this->method++; $this->method++;
return true; return true;
@@ -1121,6 +1219,8 @@ class Metar implements \ArrayAccess
* Format is REww where ww = Weather phenomenon code (see get_present_weather above). * Format is REww where ww = Weather phenomenon code (see get_present_weather above).
* *
* @param mixed $part * @param mixed $part
*
* @return bool
*/ */
private function get_recent_weather($part) private function get_recent_weather($part)
{ {
@@ -1133,6 +1233,8 @@ class Metar implements \ArrayAccess
* C = extent of deposit, ee = depth of deposit, BB = friction coefficient. * C = extent of deposit, ee = depth of deposit, BB = friction coefficient.
* *
* @param mixed $part * @param mixed $part
*
* @return bool
*/ */
private function get_runways_report($part) private function get_runways_report($part)
{ {
@@ -1241,6 +1343,8 @@ class Metar implements \ArrayAccess
* Format is 'WS ALL RWY' or 'WS RWYdd' where dd = Runway designator (see get_runway_vr above). * Format is 'WS ALL RWY' or 'WS RWYdd' where dd = Runway designator (see get_runway_vr above).
* *
* @param mixed $part * @param mixed $part
*
* @return bool
*/ */
private function get_wind_shear($part) private function get_wind_shear($part)
{ {
@@ -1289,8 +1393,8 @@ class Metar implements \ArrayAccess
* HH - Forecast hour, i.e. the time(hour) when the temperature is expected * HH - Forecast hour, i.e. the time(hour) when the temperature is expected
* Z - Time Zone indicator, Z=GMT. * Z - Time Zone indicator, Z=GMT.
* *
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName * @throws NonStringUnitName
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue * @throws NonNumericValue
* *
* @return bool * @return bool
*/ */
@@ -1307,7 +1411,7 @@ class Metar implements \ArrayAccess
// Temperature // Temperature
$temperature_c = (int) str_replace('M', '-', $found[2]); $temperature_c = (int) str_replace('M', '-', $found[2]);
$temperture = new Temperature($temperature_c, 'C'); $temperture = $this->createTemperature($temperature_c, 'C');
$forecast = [ $forecast = [
'value' => $temperture, 'value' => $temperture,
@@ -1336,6 +1440,8 @@ class Metar implements \ArrayAccess
* LTDDhhmm or DDhh/DDhh, where hh = hours, mm = minutes, DD = day of month. * LTDDhhmm or DDhh/DDhh, where hh = hours, mm = minutes, DD = day of month.
* *
* @param mixed $part * @param mixed $part
*
* @return bool
*/ */
private function get_trends($part) private function get_trends($part)
{ {
@@ -1382,7 +1488,7 @@ class Metar implements \ArrayAccess
$raw_parts = []; $raw_parts = [];
// Get all parts after trend part // Get all parts after trend part
while ($this->part < \count($this->raw_parts)) { while ($this->part < count($this->raw_parts)) {
if (preg_match($r, $this->raw_parts[$this->part], $found)) { if (preg_match($r, $this->raw_parts[$this->part], $found)) {
// Get trend flag // Get trend flag
if (isset($found[2], static::$trends_flag_codes[$found[2]])) { if (isset($found[2], static::$trends_flag_codes[$found[2]])) {
@@ -1512,7 +1618,7 @@ class Metar implements \ArrayAccess
$remarks = []; $remarks = [];
// Get all parts after // Get all parts after
while ($this->part < \count($this->raw_parts)) { while ($this->part < count($this->raw_parts)) {
if (isset($this->raw_parts[$this->part])) { if (isset($this->raw_parts[$this->part])) {
$remarks[] = $this->raw_parts[$this->part]; $remarks[] = $this->raw_parts[$this->part];
} }
@@ -1608,8 +1714,8 @@ class Metar implements \ArrayAccess
* @param $temperature_f * @param $temperature_f
* @param $rh * @param $rh
* *
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue * @throws NonNumericValue
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName * @throws NonStringUnitName
*/ */
private function calculate_heat_index($temperature_f, $rh): void private function calculate_heat_index($temperature_f, $rh): void
{ {
@@ -1621,7 +1727,7 @@ class Metar implements \ArrayAccess
$hi_f = round($hi_f); $hi_f = round($hi_f);
$hi_c = round(($hi_f - 32) / 1.8); $hi_c = round(($hi_f - 32) / 1.8);
$this->set_result_value('heat_index', new Temperature($hi_c, 'C')); $this->set_result_value('heat_index', $this->createTemperature($hi_c, 'C'));
} }
} }
@@ -1631,20 +1737,20 @@ class Metar implements \ArrayAccess
* *
* @param $temperature_f * @param $temperature_f
* *
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue * @throws NonNumericValue
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName * @throws NonStringUnitName
*/ */
private function calculate_wind_chill($temperature_f): void private function calculate_wind_chill($temperature_f): void
{ {
if ($temperature_f < 51 && $this->result['wind_speed'] !== 0) { if ($temperature_f < 51 && $this->result['wind_speed'] !== 0) {
$windspeed = round(2.23694 * $this->result['wind_speed']); // convert m/s to mi/h $windspeed = $this->result['wind_speed']->toUnit('mph');
if ($windspeed > 3) { if ($windspeed > 3) {
$chill_f = 35.74 + 0.6215 * $temperature_f - 35.75 * ($windspeed ** 0.16); $chill_f = 35.74 + 0.6215 * $temperature_f - 35.75 * ($windspeed ** 0.16);
$chill_f += 0.4275 * $temperature_f * ($windspeed ** 0.16); $chill_f += 0.4275 * $temperature_f * ($windspeed ** 0.16);
$chill_f = round($chill_f); $chill_f = round($chill_f);
$chill_c = round(($chill_f - 32) / 1.8); $chill_c = round(($chill_f - 32) / 1.8);
$this->set_result_value('wind_chill', new Temperature($chill_c, 'C')); $this->set_result_value('wind_chill', $this->createTemperature($chill_c, 'C'));
} }
} }
} }
@@ -1661,7 +1767,10 @@ class Metar implements \ArrayAccess
* @param $speed * @param $speed
* @param $unit * @param $unit
* *
* @return float|null * @throws NonStringUnitName
* @throws NonNumericValue
*
* @return Velocity
*/ */
private function convert_speed($speed, $unit) private function convert_speed($speed, $unit)
{ {
@@ -1669,36 +1778,11 @@ class Metar implements \ArrayAccess
switch ($unit) { switch ($unit) {
case 'KT': case 'KT':
return round(0.514444 * $speed, 2); // from knots return $this->createVelocity($speed, 'knots');
case 'KPH': case 'KPH':
return round(0.277778 * $speed, 2); // from km/h return $this->createVelocity($speed, 'km/hour');
case 'MPS': default:
return round($speed, 2); // m/s return $this->createVelocity($speed, 'm/s');
}
}
/**
* Convert distance into meters.
* Some other common conversion factors:
* 1 m = 3.28084 ft = 0.00062 mi
* 1 ft = 0.3048 m = 0.00019 mi
* 1 mi = 5279.99 ft = 1609.34 m
*
* @param $distance
* @param $unit
*
* @return float|null
*/
private function convert_distance($distance, $unit)
{
// TODO: return dict w/ multiple units - NS
switch ($unit) {
case 'FT':
return round(0.3048 * $distance); // from ft.
case 'SM':
return round(1609.34 * $distance); // from miles
case 'M':
return round($distance); // meters
} }
} }
@@ -1706,12 +1790,16 @@ class Metar implements \ArrayAccess
* Convert direction degrees to compass label. * Convert direction degrees to compass label.
* *
* @param mixed $direction * @param mixed $direction
*
* @return string Direction string
*/ */
private function convert_direction_label($direction) private function convert_direction_label($direction): string
{ {
if ($direction >= 0 && $direction <= 360) { if ($direction >= 0 && $direction <= 360) {
return static::$direction_codes[round($direction / 22.5) % 16]; return static::$direction_codes[round($direction / 22.5) % 16];
} }
return 'N';
} }
/** /**

View File

@@ -7,6 +7,12 @@ use PhpUnitsOfMeasure\PhysicalQuantity\Length;
class Altitude extends Unit class Altitude extends Unit
{ {
public $responseUnits = [
'ft',
'km',
'm',
];
/** /**
* @param float $value * @param float $value
* @param string $unit * @param string $unit
@@ -18,11 +24,5 @@ class Altitude extends Unit
{ {
$this->unit = setting('units.altitude'); $this->unit = setting('units.altitude');
$this->instance = new Length($value, $unit); $this->instance = new Length($value, $unit);
$this->units = [
'm' => round($this->instance->toUnit('meters'), 2),
'km' => round($this->instance->toUnit('meters') / 1000, 2),
'ft' => round($this->instance->toUnit('feet'), 2),
];
} }
} }

View File

@@ -7,6 +7,12 @@ use PhpUnitsOfMeasure\PhysicalQuantity\Length;
class Distance extends Unit class Distance extends Unit
{ {
public $responseUnits = [
'km',
'mi',
'nmi',
];
/** /**
* Distance constructor. * Distance constructor.
* *
@@ -20,12 +26,5 @@ class Distance extends Unit
{ {
$this->unit = setting('units.distance'); $this->unit = setting('units.distance');
$this->instance = new Length($value, $unit); $this->instance = new Length($value, $unit);
$this->units = [
'mi' => round($this->instance->toUnit('miles'), 2),
'nmi' => round($this->instance->toUnit('nmi'), 2),
'm' => round($this->instance->toUnit('meters'), 2),
'km' => round($this->instance->toUnit('meters') / 1000, 2),
];
} }
} }

View File

@@ -7,6 +7,11 @@ use PhpUnitsOfMeasure\PhysicalQuantity\Mass;
class Fuel extends Unit class Fuel extends Unit
{ {
public $responseUnits = [
'kg',
'lbs',
];
/** /**
* @param float $value * @param float $value
* @param string $unit * @param string $unit
@@ -18,10 +23,5 @@ class Fuel extends Unit
{ {
$this->unit = setting('units.fuel'); $this->unit = setting('units.fuel');
$this->instance = new Mass($value, $unit); $this->instance = new Mass($value, $unit);
$this->units = [
'kg' => round($this->instance->toUnit('kg'), 2),
'lbs' => round($this->instance->toUnit('lbs'), 2),
];
} }
} }

View File

@@ -7,6 +7,11 @@ use PhpUnitsOfMeasure\PhysicalQuantity\Mass as MassUnit;
class Mass extends Unit class Mass extends Unit
{ {
public $responseUnits = [
'kg',
'lbs',
];
/** /**
* @param float $value * @param float $value
* @param string $unit * @param string $unit
@@ -18,10 +23,5 @@ class Mass extends Unit
{ {
$this->unit = setting('units.weight'); $this->unit = setting('units.weight');
$this->instance = new MassUnit($value, $unit); $this->instance = new MassUnit($value, $unit);
$this->units = [
'kg' => round($this->instance->toUnit('kg'), 2),
'lbs' => round($this->instance->toUnit('lbs'), 2),
];
} }
} }

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Support\Units;
use App\Interfaces\Unit;
use PhpUnitsOfMeasure\PhysicalQuantity\Pressure as PressureUnit;
/**
* Composition for the converter
*/
class Pressure extends Unit
{
public $responseUnits = [
'atm',
'hPa',
];
/**
* @param float $value
* @param string $unit
*
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName
*/
public function __construct(float $value, string $unit)
{
$this->unit = setting('units.temperature');
$this->instance = new PressureUnit($value, $unit);
}
}

View File

@@ -10,6 +10,11 @@ use PhpUnitsOfMeasure\PhysicalQuantity\Temperature as TemperatureUnit;
*/ */
class Temperature extends Unit class Temperature extends Unit
{ {
public $responseUnits = [
'C',
'F',
];
/** /**
* @param float $value * @param float $value
* @param string $unit * @param string $unit
@@ -21,12 +26,5 @@ class Temperature extends Unit
{ {
$this->unit = setting('units.temperature'); $this->unit = setting('units.temperature');
$this->instance = new TemperatureUnit($value, $unit); $this->instance = new TemperatureUnit($value, $unit);
$this->units = [
'F' => round($this->instance->toUnit('F'), 2),
'f' => round($this->instance->toUnit('F'), 2),
'C' => round($this->instance->toUnit('C'), 2),
'c' => round($this->instance->toUnit('C'), 2),
];
} }
} }

View File

@@ -10,6 +10,11 @@ use PhpUnitsOfMeasure\PhysicalQuantity\Velocity as VelocityUnit;
*/ */
class Velocity extends Unit class Velocity extends Unit
{ {
public $responseUnits = [
'km/h',
'knots',
];
/** /**
* @param float $value * @param float $value
* @param string $unit * @param string $unit
@@ -21,10 +26,5 @@ class Velocity extends Unit
{ {
$this->unit = setting('units.speed'); $this->unit = setting('units.speed');
$this->instance = new VelocityUnit($value, $unit); $this->instance = new VelocityUnit($value, $unit);
$this->units = [
'knots' => round($this->instance->toUnit('knots'), 2),
'km/h' => round($this->instance->toUnit('km/h'), 2),
];
} }
} }

View File

@@ -10,6 +10,11 @@ use PhpUnitsOfMeasure\PhysicalQuantity\Volume as VolumeUnit;
*/ */
class Volume extends Unit class Volume extends Unit
{ {
public $responseUnits = [
'gal',
'liters',
];
/** /**
* @param float $value * @param float $value
* @param string $unit * @param string $unit
@@ -21,10 +26,5 @@ class Volume extends Unit
{ {
$this->unit = setting('units.volume'); $this->unit = setting('units.volume');
$this->instance = new VolumeUnit($value, $unit); $this->instance = new VolumeUnit($value, $unit);
$this->units = [
'gal' => round($this->instance->toUnit('gal'), 2),
'liters' => round($this->instance->toUnit('liters'), 2),
];
} }
} }

View File

@@ -86,6 +86,7 @@ return [
App\Providers\RouteServiceProvider::class, App\Providers\RouteServiceProvider::class,
App\Providers\vaCentralServiceProvider::class, App\Providers\vaCentralServiceProvider::class,
App\Providers\ExtendedTimezonelistProvider::class, App\Providers\ExtendedTimezonelistProvider::class,
App\Providers\MeasurementsProvider::class,
], ],
'aliases' => [ 'aliases' => [

View File

@@ -277,7 +277,7 @@ class AcarsTest extends TestCase
$aircraft = $subfleet['aircraft']->random(); $aircraft = $subfleet['aircraft']->random();
$uri = '/api/pireps/prefile'; $uri = '/api/pireps/prefile';
$pirep = [ $pirep_create = [
'airline_id' => $airline->id, 'airline_id' => $airline->id,
'aircraft_id' => $aircraft->id, 'aircraft_id' => $aircraft->id,
'dpt_airport_id' => $airport->icao, 'dpt_airport_id' => $airport->icao,
@@ -293,7 +293,7 @@ class AcarsTest extends TestCase
], ],
]; ];
$response = $this->post($uri, $pirep); $response = $this->post($uri, $pirep_create);
$response->assertStatus(201); $response->assertStatus(201);
// Get the PIREP ID // Get the PIREP ID
@@ -314,7 +314,7 @@ class AcarsTest extends TestCase
*/ */
$this->assertHasKeys($pirep, ['fields']); $this->assertHasKeys($pirep, ['fields']);
$this->assertEquals('custom_value', $pirep['fields']['custom_field']); $this->assertEquals('custom_value', $pirep['fields']['custom_field']);
$this->assertEquals($pirep_create['planned_distance'], $pirep['planned_distance']['nmi']);
$this->assertHasKeys($pirep['planned_distance'], ['mi', 'nmi', 'km']); $this->assertHasKeys($pirep['planned_distance'], ['mi', 'nmi', 'km']);
/** /**

View File

@@ -466,7 +466,7 @@ class ImporterTest extends TestCase
$this->assertEquals('0810 CST', $flight->dpt_time); $this->assertEquals('0810 CST', $flight->dpt_time);
$this->assertEquals('1235 EST', $flight->arr_time); $this->assertEquals('1235 EST', $flight->arr_time);
$this->assertEquals('350', $flight->level); $this->assertEquals('350', $flight->level);
$this->assertEquals('1477', $flight->distance); $this->assertEquals(1477, $flight->distance['nmi']);
$this->assertEquals('207', $flight->flight_time); $this->assertEquals('207', $flight->flight_time);
$this->assertEquals(FlightType::SCHED_PAX, $flight->flight_type); $this->assertEquals(FlightType::SCHED_PAX, $flight->flight_type);
$this->assertEquals('ILEXY2 ZENZI LFK ELD J29 MEM Q29 JHW J70 STENT J70 MAGIO J70 LVZ LENDY6', $flight->route); $this->assertEquals('ILEXY2 ZENZI LFK ELD J29 MEM Q29 JHW J70 STENT J70 MAGIO J70 LVZ LENDY6', $flight->route);

View File

@@ -1,6 +1,7 @@
<?php <?php
use App\Support\Math; use App\Support\Math;
use App\Support\Units\Distance;
class MathTest extends TestCase class MathTest extends TestCase
{ {
@@ -26,4 +27,11 @@ class MathTest extends TestCase
$this->assertEquals($test['expected'], $test['fn']); $this->assertEquals($test['expected'], $test['fn']);
} }
} }
public function testDistanceMeasurement()
{
$dist = new Distance(1, 'mi');
$this->assertEquals(1609.34, $dist['m']);
$this->assertEquals(1.61, $dist['km']);
}
} }

View File

@@ -50,8 +50,8 @@ class MetarTest extends TestCase
$this->assertEquals('KJFK', $parsed['station']); $this->assertEquals('KJFK', $parsed['station']);
$this->assertEquals(4, $parsed['observed_day']); $this->assertEquals(4, $parsed['observed_day']);
$this->assertEquals('21:51 UTC', $parsed['observed_time']); $this->assertEquals('21:51 UTC', $parsed['observed_time']);
$this->assertEquals(13.38, $parsed['wind_speed']); $this->assertEquals(26, $parsed['wind_speed']['knots']);
$this->assertEquals(20.06, $parsed['wind_gust_speed']); $this->assertEquals(39, $parsed['wind_gust_speed']['knots']);
$this->assertEquals(280, $parsed['wind_direction']); $this->assertEquals(280, $parsed['wind_direction']);
$this->assertEquals('W', $parsed['wind_direction_label']); $this->assertEquals('W', $parsed['wind_direction_label']);
$this->assertEquals(false, $parsed['wind_direction_varies']); $this->assertEquals(false, $parsed['wind_direction_varies']);
@@ -72,8 +72,7 @@ class MetarTest extends TestCase
$this->assertEquals(24.8, $parsed['dew_point']['f']); $this->assertEquals(24.8, $parsed['dew_point']['f']);
$this->assertEquals(33, $parsed['humidity']); $this->assertEquals(33, $parsed['humidity']);
$this->assertEquals(29.58, $parsed['barometer']); $this->assertEquals(29.58, $parsed['barometer']['hPa']);
$this->assertEquals(0.87, $parsed['barometer_in']);
$this->assertEquals('AO2 PK WND 27045/2128 PRESRR SLP018 T01221044', $parsed['remarks']); $this->assertEquals('AO2 PK WND 27045/2128 PRESRR SLP018 T01221044', $parsed['remarks']);
} }
@@ -121,7 +120,7 @@ class MetarTest extends TestCase
$parsed = Metar::parse($metar); $parsed = Metar::parse($metar);
$this->assertEquals('VFR', $parsed['category']); $this->assertEquals('VFR', $parsed['category']);
$this->assertEquals(9.26, $parsed['wind_speed']); $this->assertEquals(18, $parsed['wind_speed']['knots']);
$this->assertEquals(8, $parsed['visibility']['mi']); $this->assertEquals(8, $parsed['visibility']['mi']);
$this->assertEquals( $this->assertEquals(
'Scattered at 4500 feet, cumulonimbus; broken sky at 6000 feet; overcast sky at 8000 feet', 'Scattered at 4500 feet, cumulonimbus; broken sky at 6000 feet; overcast sky at 8000 feet',