]> git.street.me.uk Git - andy/gpx.git/blob - src/libgpx/route.php
Fix: PeakStream fails to function correctly after the first file
[andy/gpx.git] / src / libgpx / route.php
1 <?php
2 /**
3  * route.php
4  *
5  * Copyright 2018 Andy Street <andy@street.me.uk>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20  * MA 02110-1301, USA.
21  *
22  *
23  */
24
25 namespace libgpx;
26
27 use \ArrayAccess;
28 use \Countable;
29 use \DomainException;
30 use \IteratorAggregate;
31
32 /**
33  * The GPX route type.
34  *
35  * @see https://www.topografix.com/GPX/1/1/#type_rteType
36  *
37  * @author Andy Street <andy@street.me.uk>
38  */
39 class Route extends DataType
40   implements Geographic, ArrayAccess, Countable, IteratorAggregate
41 {
42
43   /**
44    * GPS route number.
45    *
46    * @var int
47    */
48   protected $number;
49
50   /**
51    * A list of route points.
52    *
53    * @var DoublyLinkedList (Point)
54    */
55   protected $points;
56
57   /**
58    * Fetch the route number.
59    *
60    * @return int|null The route number or null if not set.
61    */
62   public function getNumber()
63   {
64     return $this->number;
65   }
66
67   /**
68    * Set the number of the route.
69    *
70    * @param int $number The route number or null to delete.
71    * @return void
72    * @throws DomainException If the number is < 0
73    */
74   public function setNumber(int $number = null)
75   {
76     if ($number !== null && $number < 0)
77       throw new DomainException(
78         sprintf('Number must be >= 0 but got "%s"', $number)
79       );
80     $this->number = $number;
81   }
82
83   /**
84    * Fetch an ordered list of route points.
85    *
86    * @param boolean $create Create the list if it does not already exist.
87    * @return TypedDoublyLinkedList|null A list of route points.
88    */
89   public function getPoints(bool $create = true)
90   {
91     if ($create && $this->points === null)
92       $this->points = new TypedDoublyLinkedList('libgpx\Point');
93     return $this->points;
94   }
95
96   /**
97    * Fetch a bounding box that covers the feature.
98    *
99    * @return Bounds|null A bounding box covering the extent of the feature or
100    *         null if not applicable.
101    */
102   public function getBounds()
103   {
104     $result = null;
105     if ($this->points !== null) {
106       foreach ($this->points as $point) {
107         $bounds = $point->getBounds();
108         $result = ($result === null ? $bounds : $result->extend($bounds));
109       }
110     }
111     return $result;
112   }
113
114   /**
115    * Fetch the length of a route.
116    *
117    * @return float The length in meters.
118    */
119   public function getLength()
120   {
121     $length = 0;
122     $points = $this->getPoints(false);
123     if ($points !== null && !$points->isEmpty()) {
124       $last_point = null;
125       foreach ($points as $current_point) {
126         if ($last_point !== null)
127           $length += libgpx::distance(
128             $last_point->getLatitude(),
129             $last_point->getLongitude(),
130             $current_point->getLatitude(),
131             $current_point->getLongitude()
132           );
133         $last_point = $current_point;
134       }
135     }
136     return $length;
137   }
138
139   /**
140    * Check if an offset holds a value.
141    *
142    * @see ArrayAccess::offsetExists
143    *
144    * @param mixed $offset The offset to search
145    * @return boolean
146    */
147   public function offsetExists($offset)
148   {
149     return $this->getPoints()->offsetExists($offset);
150   }
151
152   /**
153    * Fetch a point from this route.
154    *
155    * @see ArrayAccess::offsetGet
156    *
157    * @param mixed $offset The offset to retrieve
158    * @return Point
159    */
160   public function offsetGet($offset)
161   {
162     return $this->getPoints()->offsetGet($offset);
163   }
164
165   /**
166    * Set the point at an offset.
167    *
168    * @see ArrayAccess::offsetSet
169    *
170    * @param mixed $offset Where to store the point.
171    * @param Point $value The point to store.
172    * @return void
173    */
174   public function offsetSet($offset, $value)
175   {
176     return $this->getPoints()->offsetSet($offset, $value);
177   }
178
179   /**
180    * Remove a point.
181    *
182    * @see ArrayAccess::offsetUnset
183    *
184    * @param mixed $offset Which point to remove
185    * @return void
186    */
187   public function offsetUnset($offset)
188   {
189     return $this->getPoints()->offsetUnset($offset);
190   }
191
192   /**
193    * Count the number of points in this route.
194    *
195    * @return int
196    */
197   public function count()
198   {
199     return ($this->points === null ? 0 : $this->points->count());
200   }
201
202   /**
203    * Fetch an iterator for the points contained in this route.
204    *
205    * @return \Iterator
206    */
207   public function getIterator() {
208     return $this->getPoints();
209   }
210
211 }