From 9baf478c25bd8506899bca9faff48f8a4a433cf3 Mon Sep 17 00:00:00 2001 From: Kirill Blazhennov Date: Mon, 20 Feb 2017 05:32:19 -0800 Subject: [PATCH] initial sources commit --- LICENSE | 55 +--- Properties/AssemblyInfo.cs | 36 +++ TinyKML.cs | 521 +++++++++++++++++++++++++++++++++++++ UCNLKML.csproj | 51 ++++ 4 files changed, 609 insertions(+), 54 deletions(-) create mode 100644 Properties/AssemblyInfo.cs create mode 100644 TinyKML.cs create mode 100644 UCNLKML.csproj diff --git a/LICENSE b/LICENSE index 9cecc1d..e587591 100644 --- a/LICENSE +++ b/LICENSE @@ -618,57 +618,4 @@ an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {one line to give the program's name and a brief idea of what it does.} - Copyright (C) {year} {name of author} - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - {project} Copyright (C) {year} {fullname} - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f31be8f --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("UCNLKML")] +[assembly: AssemblyDescription("KML format conversion library")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Underwater communication & navigation laboratory, LLC")] +[assembly: AssemblyProduct("UCNLKML")] +[assembly: AssemblyCopyright("© 2015-2017, Underwater communication & navigation laboratory, LLC")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(true)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("048a9e13-43c1-4b12-b5db-8a1da9c042e3")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/TinyKML.cs b/TinyKML.cs new file mode 100644 index 0000000..4e06767 --- /dev/null +++ b/TinyKML.cs @@ -0,0 +1,521 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Xml; + +namespace UCNLKML +{ + public enum BoolEnum : int + { + unused = 0, + used = 1 + } + + public enum AltitudeMode + { + absolute, + relativeToGround + } + + public class KMLLocation + { + public double Longitude { get; set; } + public double Latitude { get; set; } + public double Altitude { get; set; } + + public KMLLocation() + : this(0, 0, 0) + { + } + + public KMLLocation(double longitude, double latitude, double altitude) + { + Longitude = longitude; + Latitude = latitude; + Altitude = altitude; + } + + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "{0:F08},{1:F08},{2:F08}", Longitude, Latitude, Altitude); + } + + public static List Parse(string src) + { + List result = new List(); + var c_splits = src.Split(new string[] { " ", "\r\n", "\t", "\n" }, System.StringSplitOptions.RemoveEmptyEntries); + + for (int i = 0; i < c_splits.Length; i++) + { + var l_splits = c_splits[i].Split(",".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries); + + double lon = double.NaN; + double lat = double.NaN; + double alt = 0; + + if (l_splits.Length > 1) + { + lon = double.Parse(l_splits[0]); + lat = double.Parse(l_splits[1]); + + if (l_splits.Length > 2) + alt = double.Parse(l_splits[2]); + } + else + { + throw new ArgumentException(string.Format("Error: missing parameters in string: {1}", c_splits[i])); + } + + result.Add(new KMLLocation(lon, lat, alt)); + } + + return result; + } + } + + public abstract class KMLPlacemarkItem + { + public bool Extrude { get; set; } + public bool Tessellate { get; set; } + protected List coordinates; + + public string CoordinatesToString() + { + StringBuilder sb = new StringBuilder(); + + sb.AppendLine(); + for (int i = 0; i < coordinates.Count - 1; i++) + sb.AppendFormat("{0} ", coordinates[i].ToString()); + sb.AppendFormat("{0}", coordinates[coordinates.Count - 1].ToString()); + sb.AppendLine(); + + return sb.ToString(); + } + } + + public class KMLPoint : KMLPlacemarkItem + { + #region Properties + + public KMLLocation Coordinate + { + get + { + return base.coordinates[0]; + } + set + { + base.coordinates[0] = value; + } + } + + #endregion + + #region Constructor + + public KMLPoint(double lon, double lat, double alt, bool isExtrude, bool isTessellate) + : this(new KMLLocation(lon, lat, alt), isExtrude, isTessellate) + { + } + + public KMLPoint(KMLLocation loc, bool isExtrude, bool isTessellate) + { + base.Extrude = isExtrude; + base.Tessellate = isTessellate; + base.coordinates = new List(); + base.coordinates.Add(loc); + } + + #endregion + } + + public class KMLLineString : KMLPlacemarkItem + { + #region Constructor + + public KMLLineString() + : this(false, true) + { + } + + public KMLLineString(KMLLocation[] points) + : this(false, true, points) + { + } + + public KMLLineString(bool extrude, bool tessellate) + { + base.coordinates = new List(); + base.Extrude = extrude; + base.Tessellate = tessellate; + } + + public KMLLineString(bool extrude, bool tessellate, KMLLocation[] points) + { + base.coordinates = new List(points); + base.Extrude = extrude; + base.Tessellate = tessellate; + } + + #endregion + } + + public class KMLPlacemark + { + #region Properties + + public string Name { get; set; } + public string Description { get; set; } + public KMLPlacemarkItem PlacemarkItem { get; set; } + + public KMLPlacemark(string name, string description, bool extrude, bool tessellate, KMLLocation point) + { + Name = name; + Description = description; + PlacemarkItem = new KMLPoint(point, extrude, tessellate); + } + + public KMLPlacemark(string name, string description, KMLLocation[] points) + { + Name = name; + Description = description; + PlacemarkItem = new KMLLineString(points); + } + + public KMLPlacemark(string name, string description, KMLPlacemarkItem item) + { + Name = name; + Description = description; + PlacemarkItem = item; + } + + #endregion + } + + public class KMLData : IList + { + #region Properties + + public string Name { get; set; } + public string Description { get; set; } + + List placemarks; + + #endregion + + #region Constructor + + public KMLData() + : this("", "") + { + } + + public KMLData(string name, string description) + { + Name = name; + Description = description; + placemarks = new List(); + } + + #endregion + + #region IList + + public int IndexOf(KMLPlacemark item) + { + return placemarks.IndexOf(item); + } + + public void Insert(int index, KMLPlacemark item) + { + placemarks.Insert(index, item); + } + + public void RemoveAt(int index) + { + placemarks.RemoveAt(index); + } + + public KMLPlacemark this[int index] + { + get + { + return placemarks[index]; + } + set + { + placemarks[index] = value; + } + } + + public void Add(KMLPlacemark item) + { + placemarks.Add(item); + } + + public void Clear() + { + placemarks.Clear(); + } + + public bool Contains(KMLPlacemark item) + { + return placemarks.Contains(item); + } + + public void CopyTo(KMLPlacemark[] array, int arrayIndex) + { + placemarks.CopyTo(array, arrayIndex); + } + + public int Count + { + get { return placemarks.Count; } + } + + public bool IsReadOnly + { + get { return false; } + } + + public bool Remove(KMLPlacemark item) + { + return placemarks.Remove(item); + } + + public IEnumerator GetEnumerator() + { + return placemarks.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + foreach (var item in placemarks) + yield return item; + } + + #endregion + } + + public static class TinyKML + { + #region Methods + + #region Public + + public static KMLData Read(string fileName) + { + KMLData result = new KMLData(); + + using (XmlReader reader = XmlReader.Create(fileName)) + { + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name.ToUpper()) + { + case "NAME": + { + result.Name = TinyKML.ReadString(reader); + break; + } + case "DESCRIPTION": + { + result.Name = TinyKML.ReadString(reader); + break; + } + case "PLACEMARK": + { + result.Add(TinyKML.ReadPlacemark(reader)); + break; + } + } + } + } + } + + return result; + } + + public static void Write(KMLData data, string fileName) + { + using (XmlWriter writer = XmlWriter.Create(fileName, new XmlWriterSettings { CloseOutput = true, Indent = true })) + { + writer.WriteStartDocument(false); + writer.WriteStartElement("kml", "http://www.opengis.net/kml/2.2"); + writer.WriteStartElement("Document"); + + if (!string.IsNullOrEmpty(data.Name)) writer.WriteElementString("name", data.Name); + if (!string.IsNullOrEmpty(data.Description)) writer.WriteElementString("description", data.Description); + + foreach (var item in data) + Write("Placemark", item, writer); + + writer.WriteEndElement(); + writer.WriteEndElement(); + writer.WriteEndDocument(); + } + } + + #endregion + + #region Private + + #region Write + + private static void Write(string tagName, KMLPlacemark placemark, XmlWriter writer) + { + writer.WriteStartElement("Placemark"); + + if (!string.IsNullOrEmpty(placemark.Name)) writer.WriteElementString("name", placemark.Name); + if (!string.IsNullOrEmpty(placemark.Description)) writer.WriteElementString("description", placemark.Description); + + if (placemark.PlacemarkItem is KMLPoint) + writer.WriteStartElement("Point"); + else if (placemark.PlacemarkItem is KMLLineString) + writer.WriteStartElement("LineString"); + + writer.WriteElementString("extrude", (Convert.ToInt32(placemark.PlacemarkItem.Extrude)).ToString()); + writer.WriteElementString("tessellate", (Convert.ToInt32(placemark.PlacemarkItem.Tessellate)).ToString()); + writer.WriteElementString("coordinates", placemark.PlacemarkItem.CoordinatesToString()); + + writer.WriteEndElement(); + + writer.WriteEndElement(); + } + + #endregion + + #region Read + + private static string ReadString(XmlReader reader) + { + if (reader.IsEmptyElement) throw new FormatException(reader.Name); + + string elementName = reader.Name; + string result = string.Empty; + + while (reader.Read()) + { + switch (reader.NodeType) + { + case XmlNodeType.Text: + result = reader.Value; + break; + + case XmlNodeType.EndElement: + return result; + + case XmlNodeType.Element: + throw new FormatException(elementName); + } + } + + throw new FormatException(elementName); + } + + private static int ReadInt(XmlReader reader) + { + string value = ReadString(reader); + return int.Parse(value, CultureInfo.InvariantCulture); + } + + private static KMLPlacemarkItem ReadPlacemarkItem(XmlReader reader) + { + bool isExtrude = false; + bool isTessallate = true; + List coordinates = null; + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name.ToUpper()) + { + case "EXTRUDE": + { + isExtrude = Convert.ToBoolean(TinyKML.ReadInt(reader)); + break; + } + case "TESSALLATE": + { + isTessallate = Convert.ToBoolean(TinyKML.ReadInt(reader)); + break; + } + case "COORDINATES": + { + coordinates = KMLLocation.Parse(TinyKML.ReadString(reader)); + + if (coordinates == null) + throw new FormatException(); + + if (coordinates.Count == 1) + return new KMLPoint(coordinates[0], isExtrude, isTessallate); + else + return new KMLLineString(isExtrude, isTessallate, coordinates.ToArray()); + } + } + } + } + + throw new FormatException(); + } + + private static KMLPlacemark ReadPlacemark(XmlReader reader) + { + string name = string.Empty; + string description = string.Empty; + + KMLPlacemarkItem item = null; + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name.ToUpper()) + { + case "NAME": + { + name = TinyKML.ReadString(reader); + break; + } + case "DESCRIPTION": + { + description = TinyKML.ReadString(reader); + break; + } + case "POINT": + { + item = (KMLPoint)TinyKML.ReadPlacemarkItem(reader); + + if (item != null) + return new KMLPlacemark(name, description, item); + else + throw new FormatException(); + } + case "LINESTRING": + { + item = (KMLLineString)TinyKML.ReadPlacemarkItem(reader); + + if (item != null) + return new KMLPlacemark(name, description, item); + else + throw new FormatException(); + } + } + } + } + + throw new FormatException(); + } + + #endregion + + #endregion + + #endregion + } +} diff --git a/UCNLKML.csproj b/UCNLKML.csproj new file mode 100644 index 0000000..bd0027a --- /dev/null +++ b/UCNLKML.csproj @@ -0,0 +1,51 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {B9728771-AD85-4732-B50D-8FEC17313077} + Library + Properties + UCNLKML + UCNLKML + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + \ No newline at end of file