]> git.street.me.uk Git - andy/gpx.git/blob - src/libgpx/point.php
Bugfix: Timestamps not converted to UTC when writing GPX
[andy/gpx.git] / src / libgpx / point.php
1 <?php
2 /**
3  * point.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 \DomainException;
28 use \DateTimeInterface;
29
30 /**
31  * A geographic point.
32  *
33  * @see https://www.topografix.com/GPX/1/1/#type_wptType
34  *
35  * @author Andy Street <andy@street.me.uk>
36  */
37 class Point extends DataType implements Geographic
38 {
39
40   /**
41    * The latitude of the point.
42    *
43    * @var float
44    */
45   protected $lat;
46
47   /**
48    * The longitude of the point.
49    *
50    * @var float
51    */
52   protected $lon;
53
54   /**
55    * Elevation (in meters) of the point.
56    *
57    * @var float
58    */
59   protected $ele;
60
61   /**
62    * Creation/modification timestamp for element.
63    *
64    * Date and time in are in Univeral Coordinated Time (UTC), not local time!
65    * Conforms to ISO 8601 specification for date/time representation.
66    * Fractional seconds are allowed for millisecond timing in tracklogs.
67    *
68    * @var DateTimeInterface
69    */
70   protected $time;
71
72   /**
73    * Magnetic variation (in degrees) at the point.
74    *
75    * @var float
76    */
77   protected $magvar;
78
79   /**
80    * Height (in meters) of geoid (mean sea level) above WGS84 earth ellipsoid.
81    * As defined in NMEA GGA message.
82    *
83    * @var float
84    */
85   protected $geoidheight;
86
87   /**
88    * Text of GPS symbol name.
89    *
90    * For interchange with other programs, use the exact spelling of the symbol
91    * as displayed on the GPS. If the GPS abbreviates words, spell them out.
92    *
93    * @var string
94    */
95   protected $symbol;
96
97   /**
98    * Type of GPS fix.
99    *
100    * "none", "2d", "3d", "dgps" or "pps".
101    *
102    * None means GPS had no fix. To signify "the fix info is unknown, leave out
103    * fixType entirely. pps = military signal used.
104    *
105    * @var string
106    */
107   protected $fix;
108
109   /**
110    * Number of satellites used to calculate the GPX fix.
111    *
112    * @var int
113    */
114   protected $satellites;
115
116   /**
117    * Horizontal dilution of precision.
118    *
119    * @var float
120    */
121   protected $hdop;
122
123   /**
124    * Vertical dilution of precision.
125    *
126    * @var float
127    */
128   protected $vdop;
129
130   /**
131    * Position dilution of precision.
132    *
133    * @var float
134    */
135   protected $pdop;
136
137   /**
138    * Number of seconds since last DGPS update.
139    *
140    * @var float
141    */
142   protected $ageofdgpsdata;
143
144   /**
145    * ID of DGPS station used in differential correction.
146    *
147    * @var int
148    */
149   protected $dgpsid;
150
151   /**
152    * Create a new point.
153    *
154    * @param float $lat Latitude
155    * @param float $lon Longitude
156    * @throws DomainException If not a valid latitude or longitude.
157    */
158   public function __construct(float $lat, float $lon)
159   {
160     $this->setLatitude($lat);
161     $this->setLongitude($lon);
162   }
163
164   /**
165    * Fetch the latitude of the point.
166    *
167    * @return float
168    */
169   public function getLatitude()
170   {
171     return $this->lat;
172   }
173
174   /**
175    * Set the latitude of the point.
176    *
177    * @param float $lat Latitude
178    * @return void
179    * @throws DomainException If not a valid latitude.
180    */
181   public function setLatitude(float $lat)
182   {
183     if ($lat < -90 || $lat > 90)
184       throw new DomainException(
185         sprintf('Value %s is not in the range -90-+90.', $lat)
186       );
187     $this->lat = $lat;
188   }
189
190   /**
191    * Fetch the longitude of the point.
192    *
193    * @return float
194    */
195   public function getLongitude()
196   {
197     return $this->lon;
198   }
199
200   /**
201    * Set the longitude of the point.
202    *
203    * @param float $lon Longitude
204    * @return void
205    * @throws DomainException If not a valid longitude.
206    */
207   public function setLongitude(float $lon)
208   {
209     if ($lon < -180 || $lon > 180)
210       throw new DomainException(
211         sprintf('Value %s is not in the range -180-+180.', $lon)
212       );
213     $this->lon = $lon;
214   }
215
216   /**
217    * Fetch the elevation of the point.
218    *
219    * @return float|null The elevation in meters or null if not set.
220    */
221   public function getEle()
222   {
223     return $this->ele;
224   }
225
226   /**
227    * Set the elevation of the point.
228    *
229    * @param float $ele The elevation in meters or null to delete.
230    * @return void
231    */
232   public function setEle(float $ele = null)
233   {
234     $this->ele = $ele;
235   }
236
237   /**
238    * Fetch the creation time of the point.
239    *
240    * @return DateTimeInterface|null The time or null if not set.
241    */
242   public function getTime()
243   {
244     return $this->time;
245   }
246
247   /**
248    * Set the creation time of the point.
249    *
250    * @param DateTimeInterface $time The creation time or null to delete.
251    * @return void
252    */
253   public function setTime(DateTimeInterface $time = null)
254   {
255     $this->time = $time;
256   }
257
258   /**
259    * Fetch the magnetic variation.
260    *
261    * @return float|null The magnetic variation in degrees or null if not set.
262    */
263   public function getMagvar()
264   {
265     return $this->magvar;
266   }
267
268   /**
269    * Set the magnetic variation.
270    *
271    * @param float $magvar The magnetic variation in degrees or null to delete.
272    * @return void
273    * @throws DomainException if not in range 0 <= value < 360
274    */
275   public function setMagvar(float $magvar = null)
276   {
277     if (
278       $magvar !== null
279       && ($magvar < 0 || $magvar >= 360)
280     ) {
281       throw new DomainException(
282         sprintf('Value %s is not in the range 0 <= value < 360.', $lon)
283       );
284     }
285     $this->magvar = $magvar;
286   }
287
288   /**
289    * Fetch the geoid height at the point.
290    *
291    * @return float The geoid height in meters.
292    */
293   public function getGeoidHeight()
294   {
295     return $this->geoidheight;
296   }
297
298   /**
299    * Set the geoid height at the point.
300    *
301    * @param float $geoidheight The geoid height in meters.
302    * @return void
303    */
304   public function setGeoidHeight(float $geoidheight = null)
305   {
306     $this->geoidheight = $geoidheight;
307   }
308
309   /**
310    * Fetch the waypoint symbol.
311    *
312    * @return string|null The symbol or null if not set.
313    */
314   public function getSymbol()
315   {
316     return $this->symbol;
317   }
318
319   /**
320    * Set the symbol representing this point.
321    *
322    * @param string $symbol The name of the symbol or null to delete.
323    * @return void
324    */
325   public function setSymbol(string $symbol = null)
326   {
327     $this->symbol = $symbol;
328   }
329
330   /**
331    * Fetch the fix type for this point.
332    *
333    * @return string|null The fix type or null if not set.
334    */
335   public function getFix()
336   {
337     return $this->fix;
338   }
339
340   /**
341    * Set the fix type.
342    *
343    * @param string $fix "none", "2d", "3d", "dgps", "pps" or null to delete.
344    * @return void
345    * @throws DomainException If an invalid fix type is passed.
346    */
347   public function setFix(string $fix = null)
348   {
349     if ($fix !== null && !in_array($fix, ['none', '2d', '3d', 'dgps', 'pps']))
350       throw new DomainException(sprintf('Unknown fix type "%s"', $fix));
351     $this->fix = $fix;
352   }
353
354   /**
355    * Fetch the number of satellites used to calculate the fix.
356    *
357    * @return int The number of satellites or null if not set.
358    */
359   public function getSatellites()
360   {
361     return $this->satellites;
362   }
363
364   /**
365    * Set the number of satellites used to calculate the fix.
366    *
367    * @param int $satellites The number if satellites or null to delete.
368    * @return void
369    * @throws DomainException If $satellites < 0
370    */
371   public function setSatellites(int $satellites = null)
372   {
373     if ($satellites !== null && $satellites < 0)
374       throw new DomainException(
375         sprintf('Satellites must be >= 0 but got %s', $satellites)
376       );
377     $this->satellites = $satellites;
378   }
379
380   /**
381    * Fetch the hdop of the point.
382    *
383    * @return float|null The hdop or null if not set.
384    */
385   public function getHdop()
386   {
387     return $this->hdop;
388   }
389
390   /**
391    * Set the hdop of the point.
392    *
393    * @param float $hdop The hdop or null to delete.
394    * @return void
395    */
396   public function setHdop(float $hdop = null)
397   {
398     $this->hdop = $hdop;
399   }
400
401   /**
402    * Fetch the vdop of the point.
403    *
404    * @return float|null The vdop or null if not set.
405    */
406   public function getVdop()
407   {
408     return $this->vdop;
409   }
410
411   /**
412    * Set the vdop of the point.
413    *
414    * @param float $vdop The vdop or null to delete.
415    * @return void
416    */
417   public function setVdop(float $vdop = null)
418   {
419     $this->vdop = $vdop;
420   }
421
422   /**
423    * Fetch the pdop of the point.
424    *
425    * @return float|null The pdop or null if not set.
426    */
427   public function getPdop()
428   {
429     return $this->pdop;
430   }
431
432   /**
433    * Set the pdop of the point.
434    *
435    * @param float $pdop The pdop or null to delete.
436    * @return void
437    */
438   public function setPdop(float $pdop = null)
439   {
440     $this->pdop = $pdop;
441   }
442
443   /**
444    * Fetch the age of the DGPS data.
445    *
446    * @return float The age of DGPS data in seconds or null if not set.
447    */
448   public function getAgeOfDGPSData()
449   {
450     return $this->ageofdgpsdata;
451   }
452
453   /**
454    * Set the age of the DGPS data.
455    *
456    * @param float $ageofdgpsdata The age in seconds or null to delete.
457    * @return void
458    */
459   public function setAgeOfDGPSData(float $ageofdgpsdata = null)
460   {
461     $this->ageofdgpsdata = $ageofdgpsdata;
462   }
463
464   /**
465    * Fetch the id of the DGPS station.
466    *
467    * @return int The DGPS id or null if not set.
468    */
469   public function getDGPSId()
470   {
471     return $this->dgpsid;
472   }
473
474   /**
475    * Set the id of the DGPS station.
476    *
477    * @param int $dgpsid The station id.
478    * @return void
479    * @throws DomainException If the station id < 0 or > 1023.
480    */
481   public function setDGPSId(int $dgpsid = null)
482   {
483     if ($dgpsid !== null && ($dgpsid < 0 || $dgpsid > 1023))
484       throw new DomainException(
485         sprintf('DGPS id must be >= 0 and <= 1023 but got %s', $dgpsid)
486       );
487     return $this->dgpsid = $dgpsid;
488   }
489
490   /**
491    * Fetch a bounding box that covers the feature.
492    *
493    * @return Bounds|null A bounding box covering the extent of the feature or
494    *         null if not applicable.
495    */
496   public function getBounds()
497   {
498     return new Bounds($this->lat, $this->lon, $this->lat, $this->lon);
499   }
500
501   /**
502    * Fetch the length of a point.
503    *
504    * Note: Length is the distance between two points so calling this function
505    *       on a single point makes little sense. It is implemented to complete
506    *       the `Geographic` interface and will always return a value of 0.
507    *
508    * @return float The length in meters.
509    */
510   public function getLength()
511   {
512     return 0.0;
513   }
514
515   /**
516    * Find the distance to another point.
517    *
518    * @param Point $point The point to find the distance to.
519    * @return float The distance in meters.
520    */
521   public function distanceTo(Point $point)
522   {
523     return libgpx::distance(
524       $this->lat,
525       $this->lon,
526       $point->getLatitude(),
527       $point->getLongitude()
528     );
529   }
530
531 }