Files
Fishing2/Assets/Infinity Code/Real World Terrain/Scripts/Utils/RealWorldTerrainGPXObject.cs
2025-06-09 00:11:54 +08:00

961 lines
35 KiB
C#

/* INFINITY CODE */
/* https://infinity-code.com */
using System;
using System.Collections.Generic;
using InfinityCode.RealWorldTerrain.XML;
using UnityEngine;
namespace InfinityCode.RealWorldTerrain.Utils
{
/// <summary>
/// Class for working with GPX.
/// </summary>
public class RealWorldTerrainGPXObject
{
/// <summary>
/// GPX document version.
/// </summary>
public string version = "1.1";
/// <summary>
/// Name or URL of the software that created your GPX document. \n
/// This allows others to inform the creator of a GPX instance document that fails to validate.
/// </summary>
public string creator = "RealWorldTerrain";
/// <summary>
/// Metadata about the gpx.
/// </summary>
public Meta metadata;
/// <summary>
/// A list of waypoints.
/// </summary>
public List<Waypoint> waypoints;
/// <summary>
/// A list of routes.
/// </summary>
public List<Route> routes;
/// <summary>
/// A list of tracks.
/// </summary>
public List<Track> tracks;
/// <summary>
/// You can add extend GPX by adding your own elements from another schema here.
/// </summary>
public RealWorldTerrainXML extensions;
private RealWorldTerrainGPXObject()
{
waypoints = new List<Waypoint>();
routes = new List<Route>();
tracks = new List<Track>();
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="creator">Name or URL of the software that created your GPX document.</param>
/// <param name="version">GPX document version.</param>
public RealWorldTerrainGPXObject(string creator, string version = "1.1") : this()
{
this.creator = creator;
this.version = version;
}
/// <summary>
/// Load GPX Object from string.
/// </summary>
/// <param name="content">A string containing GPX content.</param>
/// <returns>Instance of GPX Object</returns>
public static RealWorldTerrainGPXObject Load(string content)
{
RealWorldTerrainGPXObject instance = new RealWorldTerrainGPXObject();
try
{
RealWorldTerrainXML xml = RealWorldTerrainXML.Load(content);
instance.version = xml.A("version");
instance.creator = xml.A("creator");
foreach (RealWorldTerrainXML n in xml)
{
if (n.name == "wpt") instance.waypoints.Add(new Waypoint(n));
else if (n.name == "rte") instance.routes.Add(new Route(n));
else if (n.name == "trk") instance.tracks.Add(new Track(n));
else if (n.name == "metadata") instance.metadata = new Meta(n);
else if (n.name == "extensions") instance.extensions = n;
else Debug.Log(n.name);
}
}
catch (Exception exception)
{
Debug.Log(exception.Message + "\n" + exception.StackTrace);
}
return instance;
}
/// <summary>
/// Returns RealWorldTerrainXML, contains full information about GPX Object.
/// </summary>
/// <returns>Instance of RealWorldTerrainXML.</returns>
public RealWorldTerrainXML ToXML()
{
RealWorldTerrainXML xml = new RealWorldTerrainXML("gpx");
xml.A("version", version);
xml.A("creator", creator);
if (metadata != null) metadata.AppendToNode(xml.Create("metadata"));
if (waypoints != null) foreach (Waypoint i in waypoints) i.AppendToNode(xml.Create("wpt"));
if (routes != null) foreach (Route i in routes) i.AppendToNode(xml.Create("rte"));
if (tracks != null) foreach (Track i in tracks) i.AppendToNode(xml.Create("trk"));
if (extensions != null) xml.AppendChild(extensions);
return xml;
}
public override string ToString()
{
return ToXML().outerXml;
}
/// <summary>
/// Information about the copyright holder and any license governing use of this file.
/// By linking to an appropriate license, you may place your data into the public domain or grant additional usage rights.
/// </summary>
public class Copyright
{
/// <summary>
/// Copyright holder
/// </summary>
public string author;
/// <summary>
/// Year of copyright.
/// </summary>
public int? year;
/// <summary>
/// Link to external file containing license text.
/// </summary>
public string license;
/// <summary>
/// Constructor
/// </summary>
/// <param name="author">Copyright holder</param>
public Copyright(string author)
{
this.author = author;
}
/// <summary>
/// Creates instance and loads the data from the node.
/// </summary>
/// <param name="node">Copyright node</param>
public Copyright(RealWorldTerrainXML node)
{
author = node.A("author");
foreach (RealWorldTerrainXML n in node)
{
if (n.name == "year") year = n.Value<int>();
else if (n.name == "license") license = n.Value();
else Debug.Log(n.name);
}
}
public void AppendToNode(RealWorldTerrainXML node)
{
node.A("author", author);
if (year.HasValue) node.Create("year", year.Value);
if (!string.IsNullOrEmpty(license)) node.Create("license", license);
}
}
/// <summary>
/// Two lat/lon pairs defining the extent of an element.
/// </summary>
public class Bounds
{
/// <summary>
/// The minimum latitude.
/// </summary>
public double minlat
{
get { return _minlat; }
set { _minlat = RealWorldTerrainMath.Clip(value, -90, 90); }
}
/// <summary>
/// The minimum longitude.
/// </summary>
public double minlon
{
get { return _minlon; }
set { _minlon = RealWorldTerrainMath.Repeat(value, -180, 180); }
}
/// <summary>
/// The maximum latitude.
/// </summary>
public double maxlat
{
get { return _maxlat; }
set { _maxlat = RealWorldTerrainMath.Clip(value, -90, 90); }
}
/// <summary>
/// The maximum longitude.
/// </summary>
public double maxlon
{
get { return _maxlon; }
set { _maxlon = RealWorldTerrainMath.Repeat(value, -180, 180); }
}
private double _minlat;
private double _minlon;
private double _maxlat;
private double _maxlon;
/// <summary>
/// Creates instance and loads the data from the node.
/// </summary>
/// <param name="node">Bounds node</param>
public Bounds(RealWorldTerrainXML node)
{
minlat = node.A<double>("minlat");
minlon = node.A<double>("minlon");
maxlat = node.A<double>("maxlat");
maxlon = node.A<double>("maxlon");
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="minlon">The minimum longitude.</param>
/// <param name="minlat">The minimum latitude.</param>
/// <param name="maxlon">The maximum longitude.</param>
/// <param name="maxlat">The maximum latitude.</param>
public Bounds(double minlon, double minlat, double maxlon, double maxlat)
{
this.minlat = minlat;
this.minlon = minlon;
this.maxlat = maxlat;
this.maxlon = maxlon;
}
public void AppendToNode(RealWorldTerrainXML node)
{
node.A("minlat", minlat);
node.A("minlon", minlon);
node.A("maxlat", maxlat);
node.A("maxlon", maxlon);
}
}
/// <summary>
/// An email address. Broken into two parts (id and domain) to help prevent email harvesting.
/// </summary>
public class EMail
{
/// <summary>
/// ID half of email address
/// </summary>
public string id;
/// <summary>
/// Domain half of email address
/// </summary>
public string domain;
/// <summary>
/// Constructor
/// </summary>
/// <param name="id">ID half of email address</param>
/// <param name="domain">Domain half of email address</param>
public EMail(string id, string domain)
{
this.id = id;
this.domain = domain;
}
/// <summary>
/// Creates instance and loads the data from the node.
/// </summary>
/// <param name="node">EMail node</param>
public EMail(RealWorldTerrainXML node)
{
id = node.A("id");
domain = node.A("domain");
}
public void AppendToNode(RealWorldTerrainXML node)
{
node.A("id", id);
node.A("domain", domain);
}
}
/// <summary>
/// A link to an external resource (Web page, digital photo, video clip, etc) with additional information.
/// </summary>
public class Link
{
/// <summary>
/// URL of hyperlink.
/// </summary>
public string href;
/// <summary>
/// Text of hyperlink.
/// </summary>
public string text;
/// <summary>
/// Mime type of content (image/jpeg)
/// </summary>
public string type;
/// <summary>
/// Constructor
/// </summary>
/// <param name="href">URL of hyperlink.</param>
public Link(string href)
{
this.href = href;
}
/// <summary>
/// Creates instance and loads the data from the node.
/// </summary>
/// <param name="node">Link node</param>
public Link(RealWorldTerrainXML node)
{
href = node.A("href");
foreach (RealWorldTerrainXML n in node)
{
if (n.name == "text") text = n.Value();
else if (n.name == "type") type = n.Value();
else Debug.Log(n.name);
}
}
public void AppendToNode(RealWorldTerrainXML node)
{
node.A("href", href);
if (!string.IsNullOrEmpty(text)) node.Create("text", text);
if (!string.IsNullOrEmpty(type)) node.Create("type", type);
}
}
/// <summary>
/// Information about the GPX file, author, and copyright restrictions goes in the metadata section. \n
/// Providing rich, meaningful information about your GPX files allows others to search for and use your GPS data.
/// </summary>
public class Meta
{
/// <summary>
/// The name of the GPX file.
/// </summary>
public string name;
/// <summary>
/// A description of the contents of the GPX file.
/// </summary>
public string description;
/// <summary>
/// The person or organization who created the GPX file.
/// </summary>
public Person author;
/// <summary>
/// Copyright and license information governing use of the file.
/// </summary>
public Copyright copyright;
/// <summary>
/// URLs associated with the location described in the file.
/// </summary>
public List<Link> links;
/// <summary>
/// The creation date of the file.
/// </summary>
public DateTime? time;
/// <summary>
/// Keywords associated with the file. Search engines or databases can use this information to classify the data.
/// </summary>
public string keywords;
/// <summary>
/// Minimum and maximum coordinates which describe the extent of the coordinates in the file.
/// </summary>
public Bounds bounds;
/// <summary>
/// You can add extend GPX by adding your own elements from another schema here.
/// </summary>
public RealWorldTerrainXML extensions;
/// <summary>
/// Constructor
/// </summary>
public Meta()
{
links = new List<Link>();
}
/// <summary>
/// Creates instance and loads the data from the node.
/// </summary>
/// <param name="node">Meta node</param>
public Meta(RealWorldTerrainXML node) : this()
{
foreach (RealWorldTerrainXML n in node)
{
if (n.name == "name") name = n.Value();
else if (n.name == "desc") description = n.Value();
else if (n.name == "author") author = new Person(n);
else if (n.name == "copyright") copyright = new Copyright(n);
else if (n.name == "link") links.Add(new Link(n));
else if (n.name == "time") time = DateTime.Parse(n.Value());
else if (n.name == "keywords") keywords = n.Value();
else if (n.name == "bounds") bounds = new Bounds(n);
else if (n.name == "extensions") extensions = n;
else Debug.Log(n.name);
}
}
public void AppendToNode(RealWorldTerrainXML node)
{
if (!string.IsNullOrEmpty(name)) node.Create("name", name);
if (!string.IsNullOrEmpty(description)) node.Create("desc", description);
if (author != null) author.AppendToNode(node);
if (copyright != null) copyright.AppendToNode(node.Create("copyright"));
if (links != null && links.Count > 0) foreach (Link l in links) l.AppendToNode(node.Create("link"));
if (time.HasValue) node.Create("time", time.Value.ToUniversalTime().ToString("s") + "Z");
if (!string.IsNullOrEmpty(keywords)) node.Create("keywords", keywords);
if (bounds != null) bounds.AppendToNode(node.Create("bounds"));
if (extensions != null) node.AppendChild(extensions);
}
}
/// <summary>
/// A person or organization.
/// </summary>
public class Person
{
/// <summary>
/// Name of person or organization.
/// </summary>
public string name;
/// <summary>
/// Email address.
/// </summary>
public EMail email;
/// <summary>
/// Link to Web site or other external information about person.
/// </summary>
public Link link;
/// <summary>
/// Constructor
/// </summary>
public Person()
{
}
/// <summary>
/// Creates instance and loads the data from the node.
/// </summary>
/// <param name="node">Person node</param>
public Person(RealWorldTerrainXML node)
{
foreach (RealWorldTerrainXML n in node)
{
if (n.name == "name") name = n.Value();
else if (n.name == "email") email = new EMail(n);
else if (n.name == "link") link = new Link(n);
else Debug.Log(n.name);
}
}
public void AppendToNode(RealWorldTerrainXML node)
{
if (!string.IsNullOrEmpty(name)) node.Create("name", name);
if (email != null) email.AppendToNode(node.Create("email"));
if (link != null) link.AppendToNode(node.Create("link"));
}
}
/// <summary>
/// Route - an ordered list of waypoints representing a series of turn points leading to a destination.
/// </summary>
public class Route
{
/// <summary>
/// GPS name of route.
/// </summary>
public string name;
/// <summary>
/// GPS comment for route.
/// </summary>
public string comment;
/// <summary>
/// Text description of route for user. Not sent to GPS.
/// </summary>
public string description;
/// <summary>
/// Source of data. Included to give user some idea of reliability and accuracy of data.
/// </summary>
public string source;
/// <summary>
/// Links to external information about the route.
/// </summary>
public List<Link> links;
/// <summary>
/// GPS route number.
/// </summary>
public uint? number;
/// <summary>
/// Type (classification) of route.
/// </summary>
public string type;
/// <summary>
/// A list of route points.
/// </summary>
public List<Waypoint> points;
/// <summary>
/// You can add extend GPX by adding your own elements from another schema here.
/// </summary>
public RealWorldTerrainXML extensions;
/// <summary>
/// Constructor
/// </summary>
public Route()
{
links = new List<Link>();
points = new List<Waypoint>();
}
/// <summary>
/// Creates instance and loads the data from the node.
/// </summary>
/// <param name="node">Route node</param>
public Route(RealWorldTerrainXML node) : this()
{
foreach (RealWorldTerrainXML n in node)
{
if (n.name == "name") name = n.Value();
else if (n.name == "cmt") comment = n.Value();
else if (n.name == "desc") description = n.Value();
else if (n.name == "src") source = n.Value();
else if (n.name == "link") links.Add(new Link(n));
else if (n.name == "number") number = n.Value<uint>();
else if (n.name == "type") type = n.Value();
else if (n.name == "rtept") points.Add(new Waypoint(n));
else if (n.name == "extensions") extensions = n;
else Debug.Log(n.name);
}
}
public void AppendToNode(RealWorldTerrainXML node)
{
if (!string.IsNullOrEmpty(name)) node.Create("name", name);
if (!string.IsNullOrEmpty(comment)) node.Create("cmt", comment);
if (!string.IsNullOrEmpty(description)) node.Create("desc", description);
if (!string.IsNullOrEmpty(source)) node.Create("src", source);
if (links != null) foreach (Link l in links) l.AppendToNode(node.Create("link"));
if (number.HasValue) node.Create("number", number.Value);
if (!string.IsNullOrEmpty(type)) node.Create("type", type);
foreach (Waypoint p in points) p.AppendToNode(node.Create("rtept"));
if (extensions != null) node.AppendChild(extensions);
}
}
/// <summary>
/// Track - an ordered list of points describing a path.
/// </summary>
public class Track
{
/// <summary>
/// GPS name of track.
/// </summary>
public string name;
/// <summary>
/// GPS comment for track.
/// </summary>
public string comment;
/// <summary>
/// User description of track.
/// </summary>
public string description;
/// <summary>
/// Source of data. Included to give user some idea of reliability and accuracy of data.
/// </summary>
public string source;
/// <summary>
/// Links to external information about track.
/// </summary>
public List<Link> links;
/// <summary>
/// GPS track number.
/// </summary>
public uint? number;
/// <summary>
/// Type (classification) of track.
/// </summary>
public string type;
/// <summary>
/// A Track Segment holds a list of Track Points which are logically connected in order. \n
/// 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.
/// </summary>
public List<TrackSegment> segments;
/// <summary>
/// You can add extend GPX by adding your own elements from another schema here.
/// </summary>
public RealWorldTerrainXML extensions;
/// <summary>
/// Constructor
/// </summary>
public Track()
{
links = new List<Link>();
segments = new List<TrackSegment>();
}
/// <summary>
/// Creates instance and loads the data from the node.
/// </summary>
/// <param name="node">Track node</param>
public Track(RealWorldTerrainXML node) : this()
{
foreach (RealWorldTerrainXML n in node)
{
if (n.name == "name") name = n.Value();
else if (n.name == "cmt") comment = n.Value();
else if (n.name == "desc") description = n.Value();
else if (n.name == "src") source = n.Value();
else if (n.name == "link") links.Add(new Link(n));
else if (n.name == "number") number = n.Value<uint>();
else if (n.name == "type") type = n.Value();
else if (n.name == "trkseg") segments.Add(new TrackSegment(n));
else if (n.name == "extensions") extensions = n;
else Debug.Log(n.name);
}
}
public void AppendToNode(RealWorldTerrainXML node)
{
if (!string.IsNullOrEmpty(name)) node.Create("name", name);
if (!string.IsNullOrEmpty(comment)) node.Create("cmt", comment);
if (!string.IsNullOrEmpty(description)) node.Create("desc", description);
if (!string.IsNullOrEmpty(source)) node.Create("src", source);
if (links != null) foreach (Link l in links) l.AppendToNode(node.Create("link"));
if (number.HasValue) node.Create("number", number.Value);
if (!string.IsNullOrEmpty(type)) node.Create("type", type);
foreach (TrackSegment p in segments) p.AppendToNode(node.Create("trkseg"));
if (extensions != null) node.AppendChild(extensions);
}
}
/// <summary>
/// A Track Segment holds a list of Track Points which are logically connected in order. \n
/// 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.
/// </summary>
public class TrackSegment
{
/// <summary>
/// A Track Point holds the coordinates, elevation, timestamp, and metadata for a single point in a track.
/// </summary>
public List<Waypoint> points;
/// <summary>
/// You can add extend GPX by adding your own elements from another schema here.
/// </summary>
public RealWorldTerrainXML extensions;
/// <summary>
/// Constructor
/// </summary>
public TrackSegment()
{
points = new List<Waypoint>();
}
/// <summary>
/// Creates instance and loads the data from the node.
/// </summary>
/// <param name="node">TrackSegment node</param>
public TrackSegment(RealWorldTerrainXML node) : this()
{
foreach (RealWorldTerrainXML n in node)
{
if (n.name == "trkpt") points.Add(new Waypoint(n));
else if (n.name == "extensions") extensions = n;
else Debug.Log(n.name);
}
}
public void AppendToNode(RealWorldTerrainXML node)
{
foreach (Waypoint p in points) p.AppendToNode(node.Create("trkpt"));
if (extensions != null) node.AppendChild(extensions);
}
}
/// <summary>
/// Waypoint, point of interest, or named feature on a map.
/// </summary>
public class Waypoint
{
/// <summary>
/// Elevation (in meters) of the point.
/// </summary>
public double? elevation;
/// <summary>
/// Creation/modification timestamp for element. \n
/// Date and time in are in Univeral Coordinated Time (UTC), not local time! \n
/// Conforms to ISO 8601 specification for date/time representation. \n
/// Fractional seconds are allowed for millisecond timing in tracklogs.
/// </summary>
public DateTime? time;
/// <summary>
/// Height (in meters) of geoid (mean sea level) above WGS84 earth ellipsoid. As defined in NMEA GGA message.
/// </summary>
public double? geoidheight;
/// <summary>
/// The GPS name of the waypoint. This field will be transferred to and from the GPS. \n
/// GPX does not place restrictions on the length of this field or the characters contained in it. \n
/// It is up to the receiving application to validate the field before sending it to the GPS.
/// </summary>
public string name;
/// <summary>
/// GPS waypoint comment. Sent to GPS as comment.
/// </summary>
public string comment;
/// <summary>
/// A text description of the element. Holds additional information about the element intended for the user, not the GPS.
/// </summary>
public string description;
/// <summary>
/// Source of data. Included to give user some idea of reliability and accuracy of data. "Garmin eTrex", "USGS quad Boston North", e.g.
/// </summary>
public string source;
/// <summary>
/// Link to additional information about the waypoint.
/// </summary>
public List<Link> links;
/// <summary>
/// Text of GPS symbol name. For interchange with other programs, use the exact spelling of the symbol as displayed on the GPS. If the GPS abbreviates words, spell them out.
/// </summary>
public string symbol;
/// <summary>
/// Type (classification) of the waypoint.
/// </summary>
public string type;
/// <summary>
/// Type of GPX fix.
/// </summary>
public string fix;
/// <summary>
/// Number of satellites used to calculate the GPX fix.
/// </summary>
public uint? sat;
/// <summary>
/// Horizontal dilution of precision.
/// </summary>
public double? hdop;
/// <summary>
/// Vertical dilution of precision.
/// </summary>
public double? vdop;
/// <summary>
/// Position dilution of precision.
/// </summary>
public double? pdop;
/// <summary>
/// Number of seconds since last DGPS update.
/// </summary>
public double? ageofdgpsdata;
/// <summary>
/// You can add extend GPX by adding your own elements from another schema here.
/// </summary>
public RealWorldTerrainXML extensions;
private double _lat;
private double _lon;
private double? _magvar;
private short? _dgpsid;
/// <summary>
/// The latitude of the point. Decimal degrees, WGS84 datum.
/// </summary>
public double lat
{
get { return _lat; }
set { _lat = RealWorldTerrainMath.Clip(value, -90, 90); }
}
/// <summary>
/// The longitude of the point. Decimal degrees, WGS84 datum.
/// </summary>
public double lon
{
get { return _lon; }
set { _lon = RealWorldTerrainMath.Repeat(value, -180, 180); }
}
/// <summary>
/// Magnetic variation (in degrees) at the point
/// </summary>
public double? magvar
{
get { return _magvar; }
set
{
if (value.HasValue) _magvar = RealWorldTerrainMath.Clip(value.Value, 0, 360);
else _magvar = null;
}
}
/// <summary>
/// ID of DGPS station used in differential correction.
/// </summary>
public short? dgpsid
{
get { return _dgpsid; }
set
{
if (value.HasValue)
{
if (value.Value < 0) _dgpsid = 0;
else if (value.Value > 1023) _dgpsid = 1023;
else _dgpsid = value.Value;
}
else _dgpsid = null;
}
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="lon">The longitude of the point.</param>
/// <param name="lat">The latitude of the point.</param>
public Waypoint(double lon, double lat)
{
links = new List<Link>();
this.lat = lat;
this.lon = lon;
}
/// <summary>
/// Creates instance and loads the data from the node.
/// </summary>
/// <param name="node">Waypoint node</param>
public Waypoint(RealWorldTerrainXML node)
{
links = new List<Link>();
lat = node.A<double>("lat");
lon = node.A<double>("lon");
foreach (RealWorldTerrainXML n in node)
{
if (n.name == "ele") elevation = n.Value<double>();
else if (n.name == "time") time = DateTime.Parse(n.Value());
else if (n.name == "magvar") magvar = n.Value<double>();
else if (n.name == "geoidheight") geoidheight = n.Value<double>();
else if (n.name == "name") name = n.Value();
else if (n.name == "cmt") comment = n.Value();
else if (n.name == "desc") description = n.Value();
else if (n.name == "src") source = n.Value();
else if (n.name == "link") links.Add(new Link(n));
else if (n.name == "sym") symbol = n.Value();
else if (n.name == "type") type = n.Value();
else if (n.name == "fix") fix = n.Value();
else if (n.name == "sat") sat = n.Value<uint>();
else if (n.name == "hdop") hdop = n.Value<double>();
else if (n.name == "vdop") vdop = n.Value<double>();
else if (n.name == "pdop") pdop = n.Value<double>();
else if (n.name == "ageofdgpsdata") ageofdgpsdata = n.Value<double>();
else if (n.name == "dgpsid") dgpsid = n.Value<short>();
else if (n.name == "extensions") extensions = n;
else Debug.Log(n.name);
}
}
public void AppendToNode(RealWorldTerrainXML node)
{
node.A("lat", lat);
node.A("lon", lon);
if (elevation.HasValue) node.Create("ele", elevation.Value);
if (time.HasValue) node.Create("time", time.Value.ToUniversalTime().ToString("s") + "Z");
if (magvar.HasValue) node.Create("magvar", magvar.Value);
if (geoidheight.HasValue) node.Create("geoidheight", geoidheight.Value);
if (!string.IsNullOrEmpty(name)) node.Create("name", name);
if (!string.IsNullOrEmpty(comment)) node.Create("cmt", comment);
if (!string.IsNullOrEmpty(description)) node.Create("desc", description);
if (!string.IsNullOrEmpty(source)) node.Create("src", source);
if (links != null) foreach (Link l in links) l.AppendToNode(node.Create("link"));
if (!string.IsNullOrEmpty(symbol)) node.Create("sym", symbol);
if (!string.IsNullOrEmpty(type)) node.Create("type", type);
if (!string.IsNullOrEmpty(fix)) node.Create("fix", fix);
if (sat.HasValue) node.Create("sat", sat.Value);
if (hdop.HasValue) node.Create("hdop", hdop.Value);
if (vdop.HasValue) node.Create("vdop", vdop.Value);
if (pdop.HasValue) node.Create("pdop", pdop.Value);
if (ageofdgpsdata.HasValue) node.Create("ageofdgpsdata", ageofdgpsdata.Value);
if (dgpsid.HasValue) node.Create("dgpsid", dgpsid.Value);
if (extensions != null) node.AppendChild(extensions);
}
}
}
}