| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568 |
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.ComponentModel;
- using System.Drawing;
- using System.Globalization;
- using System.Linq;
- using System.Runtime.CompilerServices;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Input;
- using System.Windows.Media.Imaging;
- using Comal.Classes;
- using ExCSS;
- using InABox.Clients;
- using InABox.Configuration;
- using InABox.Core;
- using InABox.DynamicGrid;
- using InABox.Wpf;
- using InABox.WPF;
- using Syncfusion.UI.Xaml.Diagram;
- using Syncfusion.UI.Xaml.Maps;
- using GeoFence = Comal.Classes.GeoFence;
- using Point = System.Windows.Point;
- namespace PRSDesktop;
- public abstract class AbstractMapMarker
- {
- public string Label { get; set; } = "";
- public string Longitude { get; set; }
- public string Latitude { get; set; }
- }
- public class SiteMapMarker : AbstractMapMarker
- {
- }
- public class AssetMapMarker : AbstractMapMarker { }
- public class GeoFenceImageConverter : AbstractConverter<GPSLocationType, BitmapImage?>
- {
- private Dictionary<GPSLocationType, BitmapImage?> _images = new()
- {
- { GPSLocationType.Office, PRSDesktop.Resources.mapmarker.AsBitmapImage() },
- { GPSLocationType.Supplier, PRSDesktop.Resources.supplier.AsBitmapImage() },
- { GPSLocationType.Employee, PRSDesktop.Resources.employee.AsBitmapImage() },
- { GPSLocationType.Job, PRSDesktop.Resources.project.AsBitmapImage() },
- };
- public override BitmapImage? Convert(GPSLocationType value)
- {
- if (_images.TryGetValue(value, out var image))
- return image;
- return null;
- }
- }
- public class LiveMapsPanelViewModel : DependencyObject, INotifyPropertyChanged
- {
- private EquipmentGroup[]? _equipmentGroups;
- private Equipment[]? _equipment;
- private EquipmentGroup? _selectedEquipmentGroup;
- private System.Tuple<GPSLocationType?, string> _selectedSiteType;
- private GeoFence? _selectedSite;
- private string? _equipmentSearch;
- private DateTime _date = DateTime.Today;
- private Equipment? _selectedEquipment;
- private ObservableCollection<Point>? _waypoints;
- private Point _center;
- private double _radius;
- private GeoFence[]? _sites;
- private ObservableCollection<MapElement> _elements;
- private ObservableCollection<AbstractMapMarker>? _markers;
-
- #region Equipment
-
- public EquipmentGroup[]? EquipmentGroups
- {
- get => _equipmentGroups;
- set => SetField(ref _equipmentGroups, value);
- }
-
- public EquipmentGroup? SelectedEquipmentGroup
- {
- get => _selectedEquipmentGroup;
- set
- {
- if (value == _selectedEquipmentGroup)
- return;
- SetField(ref _selectedEquipmentGroup, value);
- SelectedEquipment = null;
- SaveSettings();
- OnPropertyChanged(nameof(VisibleEquipment));
- ReloadLocations();
- }
- }
- public Equipment[]? Equipment
- {
- get => _equipment;
- set => SetField(ref _equipment, value);
- }
-
- public string? EquipmentSearch
- {
- get => _equipmentSearch;
- set
- {
- SetField(ref _equipmentSearch, value);
- OnPropertyChanged(nameof(VisibleEquipment));
- }
- }
-
- public Equipment[]? VisibleEquipment => Equipment?.Where(x =>
- (
- (Equals(SelectedEquipmentGroup?.ID,CoreUtils.FullGuid)
- || Equals(x.GroupLink.ID,SelectedEquipmentGroup?.ID)
- ) && (
- string.IsNullOrEmpty(EquipmentSearch)
- || x.Code.Contains(EquipmentSearch,StringComparison.CurrentCultureIgnoreCase)
- || x.Description.Contains(EquipmentSearch,StringComparison.CurrentCultureIgnoreCase)
- )
- )).ToArray();
-
- public Equipment? SelectedEquipment
- {
- get => _selectedEquipment;
- set
- {
- SetField(ref _selectedEquipment, value);
- if (value != null)
- {
- SelectedSite = null;
- ReloadLocations();
- }
- }
- }
- #endregion
-
- #region Sites
-
- public System.Tuple<GPSLocationType?, string>[] SiteTypes =>
- [
- new System.Tuple<GPSLocationType?, string>(null, "All Sites"),
- new System.Tuple<GPSLocationType?, string>(GPSLocationType.Office, "Office Location"),
- new System.Tuple<GPSLocationType?, string>(GPSLocationType.Job, "Job Sites"),
- new System.Tuple<GPSLocationType?, string>(GPSLocationType.Supplier, "Suppliers")
- ];
-
- public System.Tuple<GPSLocationType?, string> SelectedSiteType
- {
- get => _selectedSiteType;
- set
- {
- SetField(ref _selectedSiteType, value);
- SaveSettings();
- OnPropertyChanged(nameof(VisibleSites));
- SelectedSite = null;
- }
- }
-
- public GeoFence[]? Sites
- {
- get => _sites;
- set
- {
- _sitesMap.Clear();
- if (value is not null)
- {
- foreach (var site in value ?? [])
- _sitesMap[site] = Serialization.Deserialize<GeoFenceDefinition>(site.Geofence) ?? new GeoFenceDefinition();
- }
- SetField(ref _sites, value);
- }
- }
- public GeoFence[]? VisibleSites => Sites?
- .Where(x => (_selectedSiteType?.Item1 == null) || Equals(x.Type, _selectedSiteType?.Item1))
- .ToArray();
-
- private Dictionary<GeoFence,GeoFenceDefinition> _sitesMap = new();
- public GeoFence? SelectedSite
- {
- get => _selectedSite;
- set
- {
- SetField(ref _selectedSite, value);
- if (value != null)
- {
- SelectedEquipment = null;
- CenterMap(value, null);
- }
- }
- }
-
- #endregion
-
- public DateTime Date
- {
- get => _date;
- set
- {
- SetField(ref _date, value);
- ReloadLocations();
- }
- }
-
- private void CenterMap(GeoFence? site, IEnumerable<Point>? points)
- {
- var nwLon = double.MaxValue;
- var nwLat = double.MinValue;
- var seLon = double.MinValue;
- var seLat = double.MaxValue;
-
- var allpoints = new List<Point>();
-
- if (points != null)
- allpoints.AddRange(points);
-
- if (site != null)
- {
- foreach (var fence in _sitesMap.Where(x=>x.Key == site))
- allpoints.AddRange(fence.Value.Coordinates.Select(x => new Point(x.Latitude, x.Longitude)));
- }
-
- foreach (var point in allpoints)
- {
- var lat = point.X;
- var lon = point.Y;
- if (lat != 0.0F && lon != 0.00)
- {
- nwLat = lat > nwLat ? lat : nwLat;
- seLat = lat < seLat ? lat : seLat;
- nwLon = lon < nwLon ? lon : nwLon;
- seLon = lon > seLon ? lon : seLon;
- }
- }
-
- var cLat = (nwLat + seLat) / 2.0F;
- var cLon = (nwLon + seLon) / 2.0F;
- //Center = new Point(-33.0 + new Random(DateTime.Now.Millisecond).NextDouble(), 115.0 + new Random(DateTime.Now.Millisecond).NextDouble());
- Center = new Point(cLat, cLon);
- var c = new Location { Latitude = cLat, Longitude = cLon };
- var nw = new Location { Latitude = nwLat, Longitude = nwLon };
- Radius = Math.Max(0.25, c.DistanceTo(nw, UnitOfLength.Kilometers) / 2.0F);
-
- }
- private void ReloadLocations()
- {
- var trackerids = VisibleEquipment?.Select(x => x.TrackerLink.ID).ToArray() ?? [];
- var selected = SelectedEquipment?.TrackerLink.ID ?? CoreUtils.FullGuid;
-
- Client.Query(
- new Filter<GPSTrackerLocation>(x=>x.Tracker.ID).InList(trackerids)
- .And(x => x.Location.Timestamp).IsGreaterThanOrEqualTo(Date.Date)
- .And(x => x.Location.Timestamp).IsLessThan(Date.Date.AddDays(1)),
- Columns.None<GPSTrackerLocation>()
- .Add(x=>x.Tracker.ID)
- .Add(x=>x.Location.Latitude)
- .Add(x=>x.Location.Longitude)
- .Add(x=>x.Location.Address)
- .Add(x=>x.Location.Timestamp),
- new SortOrder<GPSTrackerLocation>(x=>x.Location.Timestamp,SortDirection.Ascending),
- (data, _) =>
- {
- Dispatcher.BeginInvoke(() =>
- {
- GPSTrackerLocation[] pings = [];
- if (data is null)
- {
- EquipmentColorConverter.Pings = pings;
- Waypoints = null;
- Markers = null;
- }
- else
- {
- List<AbstractMapMarker> markers = new();
-
- pings = data.ToArray<GPSTrackerLocation>();
- EquipmentColorConverter.Pings = pings;
- var otherassets = pings
- .Where(x=>x.Tracker.ID != selected)
- .GroupBy(x => x.Tracker.ID)
- .Where(x=>x.Any())
- .Select(x=>x.Last()
- );
- var assetmarkers = new List<AssetMapMarker>();
- foreach (var asset in otherassets)
- {
- var eq = _equipment?.FirstOrDefault(e=>e.TrackerLink.ID == asset.Tracker.ID);
- if (eq != null)
- {
- var marker = new AssetMapMarker()
- {
- Latitude = $"{asset.Location.Latitude}",
- Longitude = $"{asset.Location.Longitude}",
- Label = $"{eq.Code}\n{eq.Description}\nLast seen: {asset.Location.Timestamp}"
- };
- markers.Add(marker);
- }
- }
-
- var waypoints = pings
- .Where(x => x.Tracker.ID == selected)
- .ToArray();
-
- Waypoints = new ObservableCollection<Point>(waypoints.Select(x => new Point(x.Location.Latitude, x.Location.Longitude)));
-
- var sites = new Dictionary<GeoFence, SiteMapMarker>();
- GeoFence? curFence = null;
-
- foreach (var waypoint in waypoints)
- {
- var time = $"{waypoint.Location.Timestamp:h:mm tt}";
- var geopoint = new GeoPoint(waypoint.Location.Latitude, waypoint.Location.Longitude);
- bool bFound = false;
-
- foreach (var geofence in _sitesMap)
- {
-
- if (geofence.Value.Contains(geopoint))
- {
- if (!sites.ContainsKey(geofence.Key))
- sites[geofence.Key] = new SiteMapMarker()
- {
- Latitude = $"{geopoint.Latitude}",
- Longitude = $"{geopoint.Longitude}"
- };
-
- var timelist = sites[geofence.Key].Label.Split('\n').Where(x=>!string.IsNullOrWhiteSpace(x)).ToList();
-
- var first = timelist.FirstOrDefault() ?? "";
- if (!string.Equals(first,geofence.Key.Name))
- timelist.Insert(0,geofence.Key.Name);
-
- if ((geofence.Key == curFence) && timelist.Any())
- {
- var lasttime = timelist.Last().Split(" - ").ToList();
- timelist.Remove(timelist.Last());
- timelist.Add($"{lasttime.First()} - {time}");
- }
- else
- timelist.Add($"{time} - {time}");
-
- sites[geofence.Key].Label = string.Join("\n", timelist);
- curFence = geofence.Key;
- bFound = true;
- break;
- }
- }
- if (!bFound)
- curFence = null;
- }
- markers.AddRange(sites.Values);
- Markers = new ObservableCollection<AbstractMapMarker>(markers);
- }
- OnPropertyChanged(nameof(VisibleEquipment));
- RecalculateLayers();
- CenterMap(_sites?.FirstOrDefault(x=>x.Type == GPSLocationType.Office), pings.Select(x=>new Point(x.Location.Latitude, x.Location.Longitude)));
- });
- }
- );
- }
- public ObservableCollection<MapElement> Elements
- {
- get => _elements;
- set => SetField(ref _elements, value);
- }
- private void RecalculateLayers()
- {
- var elements = new ObservableCollection<MapElement>();
- if (_sites?.Any() == true)
- {
- foreach (var geofence in _sites)
- {
- var definition = Serialization.Deserialize<GeoFenceDefinition>(geofence.Geofence) ?? new GeoFenceDefinition();
- var polygon = new MapPolygon()
- {
- Fill = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.LightSalmon)
- { Opacity = 0.5 },
- Stroke = System.Windows.Media.Brushes.Firebrick,
- StrokeThickness = 0.75,
- Points = new ObservableCollection<Point>(
- definition.Coordinates.Select(x => new Point(x.Latitude, x.Longitude))),
- };
- elements.Add(polygon);
- }
- }
-
- if (_waypoints?.Any( ) == true)
- {
- var line = new MapPolyline()
- {
- Points = new ObservableCollection<Point>(new ObservableCollection<Point>(_waypoints)),
- Fill = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Navy) { Opacity = 0.5 },
- Stroke = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Navy) { Opacity = 0.5 },
- StrokeThickness = 4
- };
- elements.Add(line);
- if (_waypoints.Count > 1)
- {
- var start = new MapCircle()
- {
- Center = _waypoints.First(),
- Fill = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.LightGreen) { Opacity = 0.9 },
- Stroke = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Black),
- StrokeThickness = 0.5,
- Radius = 10
- };
- elements.Add(start);
- }
- var end = new MapCircle()
- {
- Center = _waypoints.Last(),
- Fill = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Red) { Opacity = 0.9 },
- Stroke = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Black),
- StrokeThickness = 0.5,
- Radius = 10
- };
- elements.Add(end);
- }
- Elements = elements;
- }
-
- public ICommand RefreshCommand { get; set; }
-
- public ObservableCollection<AbstractMapMarker>? Markers
- {
- get => _markers;
- set => SetField(ref _markers, value);
- }
- public ObservableCollection<Point>? Waypoints
- {
- get => _waypoints;
- set => SetField(ref _waypoints, value);
- }
- public Point Center
- {
- get => _center;
- set => SetField(ref _center, value);
- }
- public double Radius
- {
- get => _radius;
- set => SetField(ref _radius, value);
- }
- public LiveMapsSettings Settings { get; private set; }
- public LiveMapsPanelViewModel()
- {
- Settings = new UserConfiguration<LiveMapsSettings>().Load();
- }
- public void SaveSettings()
- {
- if (bRefreshing)
- return;
- Settings.GeofenceType = _selectedSiteType.Item1;
- Settings.GroupID = _selectedEquipmentGroup?.ID ?? Guid.Empty;
- new UserConfiguration<LiveMapsSettings>().Save(Settings);
- }
-
- private bool bRefreshing = false;
-
- public void Refresh()
- {
-
- MultiQuery query = new MultiQuery();
- query.Add(new Filter<GeoFence>().All());
-
- query.Add(new Filter<EquipmentGroup>().All(),
- Columns.None<EquipmentGroup>()
- .Add(x => x.ID)
- .Add(x => x.Description)
- .Add(x=>x.Thumbnail.ID)
- );
-
- query.Add(
- new Filter<Document>(x=>x.ID).InQuery(new Filter<EquipmentGroup>().All(),x=>x.Thumbnail.ID));
- query.Add(
- new Filter<Equipment>(x => x.TrackerLink.ID).IsNotEqualTo(Guid.Empty),
- Columns.None<Equipment>()
- .Add(x => x.ID)
- .Add(x => x.Code)
- .Add(x => x.Description)
- .Add(x=>x.GroupLink.ID)
- .Add(x=>x.GroupLink.Thumbnail.ID)
- .Add(x=>x.TrackerLink.ID)
- .Add(x=>x.TrackerLink.Location.Timestamp)
- .Add(x=>x.TrackerLink.Location.Address)
- .Add(x=>x.TrackerLink.DeviceID)
- .Add(x=>x.TrackerLink.BatteryLevel)
- );
- query.Query( _ =>
- {
- Dispatcher.BeginInvoke(() =>
- {
- bRefreshing = true;
- foreach (var row in query.Get<Document>().Rows)
- {
- var img = ImageUtils.LoadImage(row.Get<Document, byte[]>(x => x.Data));
- EquipmentThumbnailConverter.Cache[row.Get<Document, Guid>(x => x.ID)] = img;
- }
- // EquipmentThumbnailConverter.Cache = query.Get<Document>()
- // .ToDictionary<Document, Guid, BitmapImage?>(x => x.ID,
- // x => ImageUtils.LoadImage(x.Data));
- Sites = query.Get<GeoFence>().ToArray<GeoFence>();
- SelectedSiteType = SiteTypes.FirstOrDefault(x => x.Item1 == Settings.GeofenceType) ?? SiteTypes.First();
- SelectedSite = null;
-
- var groups = query.Get<EquipmentGroup>().ToList<EquipmentGroup>();
- groups.Insert(0,new EquipmentGroup() { ID = CoreUtils.FullGuid, Description="(All Groups)"});
- EquipmentGroups = groups.ToArray();
- SelectedEquipmentGroup = EquipmentGroups?.FirstOrDefault(x=>x.ID == Settings.GroupID);
-
- Equipment = query.Get<Equipment>().ToArray<Equipment>();
- SelectedEquipment = null;
-
- bRefreshing = false;
- ReloadLocations();
- });
- });
- }
-
- public event PropertyChangedEventHandler? PropertyChanged;
- protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
- {
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
- }
- protected bool SetField<T>(ref T field, T value, [CallerMemberName] string? propertyName = null)
- {
- if (EqualityComparer<T>.Default.Equals(field, value)) return false;
- field = value;
- OnPropertyChanged(propertyName);
- return true;
- }
- }
|