Browse Source

Add CustomUnit for arithmetic methods and more stats

Joachim M. Giæver 5 years ago
parent
commit
96be81232b

+ 9 - 1
index.php

@@ -6,11 +6,11 @@ $url = 'https://www.yr.no/place/Norway/Troms/Tromsø/Tromsø/forecast_hour_by_ho
 
 $forecast = new App\Yr\Forecast($url);
 
-echo '<pre>';
 $range = $forecast->getTabular()->getBetween(
     $forecast->getSunset(), $forecast->getSunrise()->add(new \DateInterval('P1D'))
 );
 
+echo '<pre>';
 foreach ($range as $time)
     echo $time . "\n";
 
@@ -18,6 +18,14 @@ echo "\n<hr />\n";
 foreach ($range->getVariations()->getData() as $data) 
     echo sprintf("%s: %s\n", $data['time']->getFrom()->format("H:i"), join(", ", $data['entities']));
 
+$f = current(iterator_to_array($range->getIterator()));
+echo $f->getWindSpeed()->convertTo('ft/s');
+
+$stat = $range->getStatistics();
+
+echo $stat->getAverageTemperature();
+echo $stat->getAverageWindSpeed();
+
 echo "\n";
 foreach ($forecast->getCredit() as $c)
     echo $c . "\n";

+ 1 - 1
sami.conf.php

@@ -27,7 +27,7 @@ $s =  new Sami($iterator, array(
     'theme'                => 'markdown',
     'template_dirs'        => array( __DIR__ . '/'),
     //'versions'             => $versions,
-    'title'                => 'Sami Markdown Extension',
+    'title'                => 'Yr Forecast',
     'build_dir'            => __DIR__.'/build/%version%',
     'cache_dir'            => __DIR__.'/cache/%version%',
 ));

+ 36 - 4
src/Yr/Forecast/Tabular/Statistics.php

@@ -3,6 +3,7 @@
 namespace App\Yr\Forecast\Tabular;
 
 use App\Yr\Forecast\Tabular\Time\AbstractUnit;
+use App\Yr\Forecast\Tabular\Time\CustomUnit;
 use App\Yr\Forecast\Tabular\Time\Temperature;
 use App\Yr\Forecast\Tabular\Time\WindSpeed;
 
@@ -17,12 +18,18 @@ class Statistics {
     private $temp = [];
     private $wind = [];
     private $count = 0;
+    private $symbol = [];
 
     public function __construct() {
-        $this->temp = $this->wind = [
+        $this->temp = $this->struct();
+        $this->wind = $this->struct();
+    }
+
+    private function struct(): array {
+        return [
             'high' => null,
             'low' => null,
-            'mean' => 0
+            'mean' => null
         ];
     }
 
@@ -35,11 +42,36 @@ class Statistics {
     public function analyse(Time $t): self {
         $this->analyseHihgLow($t->getTemperature());
         $this->analyseHihgLow($t->getWindSpeed());
-        $this->temp['mean'] += $t->getTemperature()->getValue();
-        $this->wind['mean'] += $t->getWindSpeed()->getValue();
+
+        $this->temp['mean'] = $this->temp['mean'] == null ? $t->getTemperature() : $this->temp['mean']->add($t->getTemperature());
+        $this->wind['mean'] = $this->wind['mean'] == null ? $t->getWindSpeed() : $this->wind['mean']->add($t->getWindSpeed());
+
+        $symboldId = $t->getSymbol()->getNumber();
+
+        if (!isset($this->symbol[$symboldId]))
+            $this->symbol[$symboldId] = [
+                'symbol' => $t->getSymbol()->getName(),
+                'count' => 1
+            ];
+        else
+            $this->symbol[$symboldId]['count']++;
+
+        $this->count++;
         return $this;
     }
 
+    public function getAverageTemperature(): AbstractUnit {
+        return $this->temp['mean']->div(
+            new CustomUnit($this->count, $this->temp['mean']->getUnit())
+        );
+    }
+
+    public function getAverageWindSpeed(): AbstractUnit {
+        return $this->wind['mean']->div(
+            new CustomUnit($this->count, $this->wind['mean']->getUnit())
+        );
+    }
+
     private function analyseHihgLow(AbstractUnit $au): self {
         $unit = null;
 

+ 64 - 1
src/Yr/Forecast/Tabular/Time/AbstractUnit.php

@@ -8,7 +8,7 @@ namespace App\Yr\Forecast\Tabular\Time;
 abstract class AbstractUnit implements DiffInterface {
     const DEFAULT_VARIANCE = 2;
 
-    private $value;
+    private $value = 0;
     private $unit;
 
     /**
@@ -20,6 +20,69 @@ abstract class AbstractUnit implements DiffInterface {
         $this->unit = $unit;
     }
 
+    private function canOperate(AbstractUnit $with, bool $throw = false): bool {
+        if ($with instanceof $this || $with instanceof CustomUnit)
+            return true;
+
+        if ($this instanceof CustomUnit && $with instanceof AbstractUnit)
+            return true;
+
+        if ($throw)
+            throw new \InvalidArgumentException(sprintf(
+                "Invalid type <%s>, expected of type \"%s\" or \"%s\"",
+                get_class($with), get_class($this), CustomUnit::class
+            )); 
+
+        return false;
+    }
+
+    protected function transformClass(CustomUnit $cu): self {
+        return unserialize(preg_replace(
+            '/^O:\d+:"[^"]++"/',
+            sprintf('O:%d:"%s"', strlen(static::class), static::class),
+            serialize($cu)
+        ));
+    }
+
+    /**
+     * Addition method
+     *
+     * @param AbstractUnit $with Unit to add with
+     * @thows \InvalidArgumentException
+     * */
+    public function add(AbstractUnit $with): self {
+        $this->canOperate($with, true);
+        return $this->transformClass(
+            new CustomUnit($this->getValue() + $with->getValue(), $with->getUnit())
+        );
+    }
+
+    /**
+     * Multiplication method
+     *
+     * @param AbstractUnit $with Unit to multiply with
+     * @thows \InvalidArgumentException
+     * */
+    public function mul(AbstractUnit $with): self {
+        $this->canOperate($with, true);
+        return $this->transformClass(
+            new CustomUnit($this->getValue() * $with->getValue(), $with->getUnit())
+        );
+    }
+
+    /**
+     * Divide method
+     *
+     * @param AbstractUnit $with Unit to divide with
+     * @thows \InvalidArgumentException
+     * */
+    public function div(AbstractUnit $with): self {
+        $this->canOperate($with, true);
+        return $this->transformClass(
+            new CustomUnit($this->getValue() / $with->getValue(), $with->getUnit())
+        );
+    }
+
     /**
      * Get the value
      *

+ 9 - 0
src/Yr/Forecast/Tabular/Time/CustomUnit.php

@@ -0,0 +1,9 @@
+<?php
+
+namespace App\Yr\Forecast\Tabular\Time;
+
+class CustomUnit extends AbstractUnit {
+
+}
+
+?>

+ 1 - 1
src/Yr/Forecast/Tabular/Time/Temperature.php

@@ -13,7 +13,7 @@ class Temperature extends AbstractUnit {
     /**
      * @param \SimpleXMLElement $xml XML containing the temperature
      */
-    public function __construct(\SimpleXMLElement $xml) {
+    public function __construct(?\SimpleXMLElement $xml) {
         parent::__construct(
             (float)$xml['value'],
             (string)$xml['unit']

+ 9 - 4
src/Yr/Forecast/Tabular/Time/WindSpeed.php

@@ -33,14 +33,14 @@ class WindSpeed extends AbstractUnit {
      *
      * @param string $unit The unit to convert to, eg UNIT_FTS
      */
-    public function convertTo(string $unit): int {
+    public function convertTo(string $unit): self {
         switch ($unit) {
         case self::UNIT_KNOTS:
-            return $this->getValue() * 1.9438445;
+            return $this->mul(new CustomUnit(1.9438445, $unit))->setName($this->getName());
         case self::UNIT_FTS:
-            return $this->getValue() * 3.28084;
+            return $this->mul(new CustomUnit(3.28084, $unit))->setName($this->getName());
         case self::UNIT_KMH:
-            return $this->getValue() * 3.6;
+            return $this->mul(new CustomUnit(3.6, $unit))->setName($this->getName());
         }
     }
 
@@ -51,6 +51,11 @@ class WindSpeed extends AbstractUnit {
         return $this->name;
     }
 
+    protected function setName(string $name): self {
+        $this->name = $name;
+        return $this;
+    }
+
     /**
      * {@inheritDoc}
      */