// Copyright (c) 2022 - schick Informatik // bsmd.AIS2Service [MonitorZone.cs]: %UserDisplayName% // Description: Represents a geographical area that should be checked against // ship positions using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.UI.WebControls; using System.Xml.Linq; using log4net; namespace bsmd.AIS2Service { #region DBEntity public class DBEntity { protected long _id; // PK from database public DBEntity(long id) { _id = id; } public long Id { get { return _id; } set { _id = value; } } } #endregion #region class MonitorGroup public class MonitorGroup : DBEntity { private static ILog _log = LogManager.GetLogger(typeof(MonitorGroup)); #region fields private string _name; private readonly List _zones = new List(); #endregion #region Construction public MonitorGroup(long id, string name) : base( id ) { _name = name; } #endregion #region Properties public List Zones { get { return _zones; } } public string Name { get { return _name; } set { _name = value; } } #endregion #region public static methods /// /// Da Basti nun eine Datei mit allen Elementen exportiert gibt es eine einzelne Funktion, die alles /// importiert /// /// /// public static List LoadGroups(string filename) { List groups = new List(); try { if (File.Exists(filename)) { XDocument kml = XDocument.Load(filename); XNamespace ns = "http://www.opengis.net/kml/2.2"; foreach(XElement rootFolderNode in kml.Root.Element(ns + "Document").Element(ns + "Folder").Elements(ns + "Folder")) { MonitorGroup mg = new MonitorGroup(-1, rootFolderNode.Element(ns + "name").Value); int sequence = 1; foreach(XElement placemark in rootFolderNode.Elements(ns + "Placemark")) { MonitorZone mz = new MonitorZone(-1, placemark.Element(ns + "name").Value); mz.Active = true; mz.Sequence = sequence; // now add all vertices string[] vertices = placemark.Element(ns + "Polygon").Element(ns + "outerBoundaryIs").Element(ns + "LinearRing").Element(ns + "coordinates").Value.Split(' '); for (int i = 0; i < vertices.Length - 1; i++) { string[] pointElems = vertices[i].Trim().Split(','); if (pointElems.Length != 3) continue; GeoPoint gp = new GeoPoint(-1); gp.Lon = Double.Parse(pointElems[0], System.Globalization.NumberFormatInfo.InvariantInfo); gp.Lat = Double.Parse(pointElems[1], System.Globalization.NumberFormatInfo.InvariantInfo); mz.Vertices.Add(gp); } mg.Zones.Add(mz); sequence++; } groups.Add(mg); } } } catch(Exception ex) { _log.Error(ex.ToString()); } return groups; } #endregion #region public methods public override string ToString() { return this.Name; } #endregion } #endregion #region class MonitorZone public class MonitorZone : DBEntity, IComparable { #region fields private readonly List _vertices = new List(); private readonly List _assignments = new List(); private readonly string _name; #endregion #region Construction public MonitorZone(long id, string name) : base (id) { _name = name; } #endregion #region Properties public string Name { get { return _name; } } public List Vertices { get { return _vertices; } } public List Assignments { get { return _assignments; } } public bool Active { get; set; } public int Sequence { get; set; } public long MonitorGroupId { get; set; } #endregion #region public static methods public static MonitorZone ImportFromKML(string filename) { MonitorZone result = null; if (File.Exists(filename)) { XDocument kml = XDocument.Load(filename); XNamespace ns = "http://www.opengis.net/kml/2.2"; string name = kml.Root.Element(ns + "Document").Element(ns + "name").Value; if (name.EndsWith(".kml")) name = name.Substring(0, name.Length - 4); result = new MonitorZone(-1, name); // now find all vertices string[] vertices = kml.Root.Element(ns + "Document").Element(ns + "Placemark").Element(ns + "Polygon").Element(ns + "outerBoundaryIs").Element(ns + "LinearRing").Element(ns + "coordinates").Value.Split(' '); for (int i = 0; i < vertices.Length - 1; i++) { string[] pointElems = vertices[i].Trim().Split(','); if (pointElems.Length != 3) continue; GeoPoint gp = new GeoPoint(-1); gp.Lon = Double.Parse(pointElems[0], System.Globalization.NumberFormatInfo.InvariantInfo); gp.Lat = Double.Parse(pointElems[1], System.Globalization.NumberFormatInfo.InvariantInfo); result.Vertices.Add(gp); } } return result; } #endregion #region public methods public bool IsPointInPolygon4(GeoPoint testPoint) { bool result = false; int j = _vertices.Count() - 1; for (int i = 0; i < _vertices.Count(); i++) { if (_vertices[i].Lat < testPoint.Lat && _vertices[j].Lat >= testPoint.Lat || _vertices[j].Lat < testPoint.Lat && _vertices[i].Lat >= testPoint.Lat) { if (_vertices[i].Lon + (testPoint.Lat - _vertices[i].Lat) / (_vertices[j].Lat - _vertices[i].Lat) * (_vertices[j].Lon - _vertices[i].Lon) < testPoint.Lon) { result = !result; } } j = i; } return result; } public int CompareTo(MonitorZone other) { return this.Sequence.CompareTo(other.Sequence); } public override string ToString() { return String.Format("{0} (Seq.:{1} #Vert.:{2}", this.Name, this.Sequence, this.Vertices.Count); } #endregion } #endregion #region class GeoPoint public class GeoPoint : DBEntity { public GeoPoint(long id) : base (id) {} public double Lat { get; set; } public double Lon { get; set; } public long MonitorZoneId { get; set; } } #endregion #region class MonitorAssignment public class MonitorAssignment : DBEntity { public MonitorAssignment(long id) : base(id) {} [Flags] public enum ZoneMonitorType { INACTIVE = 0, ENTER = 1, EXIT = 2, PASSTHROUGH = 4, // outside - enter - inside - exit - outside LEAVE_AND_RETURN = 8 // inside - exit - outside - enter - inside } public int MMSI { get; set; } public ZoneMonitorType MonitorType { get; set; } = ZoneMonitorType.INACTIVE; } #endregion #region class Alarm public class Alarm : DBEntity { private readonly MonitorAssignment _assignment; public Alarm(long id, MonitorAssignment assignment) : base(id) { _assignment = assignment; } public MonitorAssignment Assignment { get { return _assignment; } } public DateTime Timestamp { get; set; } public DateTime? Acknowledged { get; set; } public MonitorAssignment.ZoneMonitorType ZoneMonitorType { get; set; } } #endregion }