Sibyx/phpGPX

View on GitHub
src/phpGPX/Models/Segment.php

Summary

Maintainability
B
6 hrs
Test Coverage
<?php
/**
 * Created            26/08/16 15:26
 * @author            Jakub Dubec <jakub.dubec@gmail.com>
 */

namespace phpGPX\Models;

use phpGPX\Helpers\BoundsCalculator;
use phpGPX\Helpers\DistanceCalculator;
use phpGPX\Helpers\ElevationGainLossCalculator;
use phpGPX\Helpers\GeoHelper;
use phpGPX\Helpers\SerializationHelper;
use phpGPX\phpGPX;

/**
 * Class Segment
 * A Track Segment holds a list of Track Points which are logically connected in order.
 * To represent a single GPS track where GPS reception was lost, or the GPS receiver was turned off,
 * start a new Track Segment for each continuous span of track data.
 * @package phpGPX\Models
 */
class Segment implements Summarizable, StatsCalculator
{
    /**
     * Array of segment points
     * @var Point[]
     */
    public $points;

    /**
     * You can add extend GPX by adding your own elements from another schema here.
     * @var Extensions|null
     */
    public $extensions;

    /**
     * @var Stats|null
     */
    public $stats;

    /**
     * Segment constructor.
     */
    public function __construct()
    {
        $this->points = [];
        $this->extensions = null;
        $this->stats = null;
    }


    /**
     * Serialize object to array
     * @return array
     */
    public function toArray()
    {
        return [
            'points' => SerializationHelper::serialize($this->points),
            'extensions' => SerializationHelper::serialize($this->extensions),
            'stats' => SerializationHelper::serialize($this->stats)
        ];
    }

    /**
     * @return array|Point[]
     */
    public function getPoints()
    {
        return $this->points;
    }

    /**
     * Recalculate stats objects.
     * @return void
     */
    public function recalculateStats()
    {
        if (empty($this->stats)) {
            $this->stats = new Stats();
        }

        $count = count($this->points);
        $this->stats->reset();

        if (empty($this->points)) {
            return;
        }

        $firstPoint = &$this->points[0];
        $lastPoint = end($this->points);

        $this->stats->startedAt = $firstPoint->time;
        $this->stats->startedAtCoords = ["lat" => $firstPoint->latitude, "lng" => $firstPoint->longitude];
        $this->stats->finishedAt = $lastPoint->time;
        $this->stats->finishedAtCoords = ["lat" => $lastPoint->latitude, "lng" => $lastPoint->longitude];
        $this->stats->minAltitude = $firstPoint->elevation;
        $this->stats->minAltitudeCoords = ["lat" => $firstPoint->latitude, "lng" => $firstPoint->longitude];

        list($this->stats->cumulativeElevationGain, $this->stats->cumulativeElevationLoss) =
            ElevationGainLossCalculator::calculate($this->getPoints());

        $calculator = new DistanceCalculator($this->getPoints());
        $this->stats->distance = $calculator->getRawDistance();
        $this->stats->realDistance = $calculator->getRealDistance();

        for ($i = 0; $i < $count; $i++) {
            if ($this->stats->maxAltitude < $this->points[$i]->elevation) {
                $this->stats->maxAltitude = $this->points[$i]->elevation;
                $this->stats->maxAltitudeCoords = ["lat" => $this->points[$i]->latitude, "lng" => $this->points[$i]->longitude];
            }

            if ((phpGPX::$IGNORE_ELEVATION_0 === false || $this->points[$i]->elevation > 0) && $this->stats->minAltitude > $this->points[$i]->elevation) {
                $this->stats->minAltitude = $this->points[$i]->elevation;
                $this->stats->minAltitudeCoords = ["lat" => $this->points[$i]->latitude, "lng" => $this->points[$i]->longitude];
            }
        }

        if (isset($firstPoint->time) && isset($lastPoint->time) && $firstPoint->time instanceof \DateTime && $lastPoint->time instanceof \DateTime) {
            $this->stats->duration = $lastPoint->time->getTimestamp() - $firstPoint->time->getTimestamp();

            if ($this->stats->duration != 0) {
                $this->stats->averageSpeed = $this->stats->distance / $this->stats->duration;
            }

            if ($this->stats->distance != 0) {
                $this->stats->averagePace = $this->stats->duration / ($this->stats->distance / 1000);
            }
        }

        list($northWest, $southEast) = BoundsCalculator::calculate($this->getPoints());
        $this->stats->bounds = [$northWest, $southEast];
    }
}