git_bsmd/AIS/bsmd.AIS2Service/MonitorZone.cs

314 lines
9.1 KiB
C#

// Copyright (c) 2022 - schick Informatik
// bsmd.AIS2Service [MonitorZone.cs]: %UserDisplayName%
// Description: Represents a geographical area that should be checked against
// ship positions
using log4net;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
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 readonly ILog _log = LogManager.GetLogger(typeof(MonitorGroup));
#region fields
private string _name;
private readonly List<MonitorZone> _zones = new List<MonitorZone>();
#endregion
#region Construction
public MonitorGroup(long id, string name) : base( id )
{
_name = name;
}
#endregion
#region Properties
public List<MonitorZone> Zones { get { return _zones; } }
public string Name { get { return _name; } set { _name = value; } }
#endregion
#region public static methods
/// <summary>
/// Da Basti nun eine Datei mit allen Elementen exportiert gibt es eine einzelne Funktion, die alles
/// importiert
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
public static List<MonitorGroup> LoadGroups(string filename)
{
List<MonitorGroup> groups = new List<MonitorGroup>();
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<MonitorZone>
{
#region fields
private readonly List<GeoPoint> _vertices = new List<GeoPoint>();
private readonly List<MonitorAssignment> _assignments = new List<MonitorAssignment>();
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<GeoPoint> Vertices { get { return _vertices; } }
public List<MonitorAssignment> 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;
public long MonitorZoneId { get; set; }
public List<Alarm> Alarms { get; } = new List<Alarm>();
public override string ToString()
{
return String.Format("{0} {1}", MMSI, MonitorType);
}
}
#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_First { get; set; }
public DateTime? Timestamp_Last { get; set; }
public DateTime? Acknowledged { get; set; }
public MonitorAssignment.ZoneMonitorType ZoneMonitorType { get; set; }
}
#endregion
}