|
|
@@ -188,60 +188,8 @@ public static class MapControlEx
|
|
|
else if (e.SelectedObject is MapDot mapDot)
|
|
|
{
|
|
|
if (mapDot == null) return;
|
|
|
- var posItem = mapDot.Tag as PosData;
|
|
|
+ var posItem = mapDot.Tag as FlightInfo;
|
|
|
if (mapDot == null || posItem == null) return;
|
|
|
- if (posItem.ClusterCount == 1)
|
|
|
- {
|
|
|
- var props = posItem.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList();
|
|
|
- var list = new List<(int Index, string Name, string Format, object Value)>();
|
|
|
- foreach (var prop in props)
|
|
|
- {
|
|
|
- var attrToolTip = prop.GetCustomAttribute<ToolTipAttribute>();
|
|
|
- if (attrToolTip == null) continue;
|
|
|
- string toolTipFormat = attrToolTip.Format;
|
|
|
-
|
|
|
-
|
|
|
- var val = prop.GetValue(posItem);
|
|
|
-
|
|
|
- string displayName = prop.Name;
|
|
|
- var attrDisplay = prop.GetCustomAttribute<DisplayAttribute>();
|
|
|
- if (attrDisplay != null && !string.IsNullOrWhiteSpace(attrDisplay.Name))
|
|
|
- displayName = attrDisplay.Name;
|
|
|
-
|
|
|
- int index = attrToolTip.Index;
|
|
|
- list.Add((index, displayName, toolTipFormat, val));
|
|
|
- }
|
|
|
- list = list.OrderBy(p => p.Index).ToList();
|
|
|
- foreach ((int Index, string Name, string Format, object val) in list)
|
|
|
- {
|
|
|
- string f = null;
|
|
|
- if (val is DateTime)
|
|
|
- {
|
|
|
- f = "yyyy-MM-dd HH:mm:ss";
|
|
|
-
|
|
|
- }
|
|
|
- else if (val is float || val is double || val is decimal)
|
|
|
- {
|
|
|
- f = "f4";
|
|
|
- }
|
|
|
- if (!string.IsNullOrWhiteSpace(Format))
|
|
|
- f = Format;
|
|
|
- string valStr;
|
|
|
- if (!string.IsNullOrWhiteSpace(f))
|
|
|
- valStr = ((dynamic)val).ToString(f);
|
|
|
- else
|
|
|
- valStr = val.ToString();
|
|
|
- ToolTipItem tipItem = new ToolTipItem();
|
|
|
- tipItem.Text = $"{Name}:{valStr}";
|
|
|
- superToolTip.Items.Add(tipItem);
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- ToolTipItem tipItem = new ToolTipItem();
|
|
|
- tipItem.Text = $"当前位置附近有{posItem.ClusterCount}个定位点,放大可查看";
|
|
|
- superToolTip.Items.Add(tipItem);
|
|
|
- }
|
|
|
e.SuperTip = superToolTip;
|
|
|
}
|
|
|
else if (e.SelectedObject is MapCustomElement ele)
|
|
|
@@ -268,17 +216,13 @@ public static class MapControlEx
|
|
|
{
|
|
|
rectMenu?.ShowPopup(Cursor.Position);
|
|
|
}
|
|
|
- else if (hitInfo.InMapDot && hitInfo.MapDot.Tag is PosData)
|
|
|
+ else if (hitInfo.InMapDot && hitInfo.MapDot.Tag is FlightInfo)
|
|
|
{
|
|
|
- var selectPos = (PosData)hitInfo.MapDot.Tag;
|
|
|
+ var selectPos = (FlightInfo)hitInfo.MapDot.Tag;
|
|
|
if (!selectPos.Selected)
|
|
|
{
|
|
|
selectPos.Selected = true;
|
|
|
- //ctrl.UpdatePosItem(selectPos);
|
|
|
- }
|
|
|
- if (selectPos.ClusterCount == 1)
|
|
|
- {
|
|
|
- posMenu?.ShowPopup(Cursor.Position);//选中了原始MapItem
|
|
|
+ ctrl.UpdateItem(selectPos);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
@@ -298,13 +242,13 @@ public static class MapControlEx
|
|
|
innerData.mouseLeftDown = true;
|
|
|
innerData.barM.CloseMenus();
|
|
|
var hitInfo = ctrl.CalcHitInfo(e.Location);
|
|
|
- if (hitInfo.InMapDot && hitInfo.MapDot.Tag is PosData)
|
|
|
+ if (hitInfo.InMapDot && hitInfo.MapDot.Tag is FlightInfo)
|
|
|
{
|
|
|
- var selectPos = hitInfo.MapDot.Tag as PosData;
|
|
|
+ var selectPos = hitInfo.MapDot.Tag as FlightInfo;
|
|
|
if (!selectPos.Selected)
|
|
|
{
|
|
|
selectPos.Selected = true;
|
|
|
- //ctrl.UpdatePosItem(selectPos);
|
|
|
+ ctrl.UpdateItem(selectPos);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -640,8 +584,10 @@ public static class MapControlEx
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
+ var flight= new FlightInfo();
|
|
|
+ flight.FlightName = fligthName;
|
|
|
+ flight.Speed = speed;
|
|
|
|
|
|
- string filghtName = $"DrawFlightLine_{fligthName}_{speed}";
|
|
|
ctrl.MapEditor.SetEditMode();
|
|
|
var items = innerData.flightStorge.Items.ToArray();
|
|
|
innerData.flightpath = new MapSpline()
|
|
|
@@ -653,11 +599,11 @@ public static class MapControlEx
|
|
|
CanRotate = true,
|
|
|
IsHitTestVisible = false,
|
|
|
CanMove = true,
|
|
|
- Tag = filghtName
|
|
|
+ Tag = flight
|
|
|
|
|
|
};
|
|
|
innerData.flightStorge.Items.Add(innerData.flightpath);
|
|
|
- innerData.hoverPoint = new MapDot() { CanResize = false, CanMove = false, Tag = filghtName, Size = 8 };
|
|
|
+ innerData.hoverPoint = new MapDot() { CanResize = false, CanMove = false, Tag = flight, Size = 8 };
|
|
|
innerData.hoverPoint.Fill = ColorHelper.GetColor(innerData.hoverPoint.Tag.ToString());
|
|
|
innerData.flightStorge.Items.Add(innerData.hoverPoint);
|
|
|
//提示框
|
|
|
@@ -712,7 +658,10 @@ public static class MapControlEx
|
|
|
innerData.distinctPath.Points.Clear();
|
|
|
}
|
|
|
|
|
|
- string filghtName = $"DrawFlightLine_{fligthName}_{speed}";
|
|
|
+ var flight = new FlightInfo();
|
|
|
+ flight.FlightName = fligthName;
|
|
|
+ flight.Speed = speed;
|
|
|
+
|
|
|
ctrl.MapEditor.SetEditMode();
|
|
|
innerData.flightpath = new MapSpline()
|
|
|
{
|
|
|
@@ -723,11 +672,11 @@ public static class MapControlEx
|
|
|
CanRotate = true,
|
|
|
IsHitTestVisible = false,
|
|
|
CanMove = true,
|
|
|
- Tag = filghtName
|
|
|
+ Tag = flight
|
|
|
|
|
|
};
|
|
|
innerData.flightStorge.Items.Add(innerData.flightpath);
|
|
|
- innerData.hoverPoint = new MapDot() { CanResize = false, CanMove = false, Tag = filghtName, Size = 8 };
|
|
|
+ innerData.hoverPoint = new MapDot() { CanResize = false, CanMove = false, Tag = flight, Size = 8 };
|
|
|
innerData.hoverPoint.Fill = ColorHelper.GetColor(innerData.hoverPoint.Tag.ToString());
|
|
|
innerData.flightStorge.Items.Add(innerData.hoverPoint);
|
|
|
//提示框
|
|
|
@@ -769,29 +718,68 @@ public static class MapControlEx
|
|
|
var ctrl = sender as MapControl;
|
|
|
|
|
|
var location = ctrl.ScreenPointToCoordPoint(e.Location);
|
|
|
- var strs = innerData.flightpath.Tag.ToString().Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries);
|
|
|
- string name = strs[1];
|
|
|
- double speed = Convert.ToDouble(strs[2]);
|
|
|
+ var strs = innerData.flightpath.Tag as FlightInfo;
|
|
|
+ string name = strs.FlightName;
|
|
|
+ double speed = strs.Speed;
|
|
|
double lon = Math.Round(location.GetX(), 3);
|
|
|
double lat = Math.Round(location.GetY(), 3);
|
|
|
+
|
|
|
+ var flight = new FlightInfo(name, speed, lon, lat);
|
|
|
innerData.hoverPoint = new MapDot()
|
|
|
{
|
|
|
CanResize = false,
|
|
|
CanMove = false,
|
|
|
- ToolTipPattern = $"航迹:{name}\r\n{lon},{lat}°",
|
|
|
- Tag = innerData.flightpath.Tag,
|
|
|
+ ToolTipPattern = flight.ToString(),
|
|
|
+ Tag = flight,
|
|
|
Size = 8
|
|
|
};
|
|
|
innerData.hoverPoint.Location = location;
|
|
|
innerData.hoverPoint.Fill = ColorHelper.GetColor(innerData.hoverPoint.Tag.ToString());
|
|
|
- innerData.flightStorge.Items.Add(innerData.hoverPoint);
|
|
|
- innerData.flightpath.Points.Add(innerData.hoverPoint.Location);
|
|
|
- if (!innerData._flightCache.Keys.Any(m => m.FlightLon == lon && m.FlightName == name && m.Speed == speed && m.FlightLat == lat))
|
|
|
+
|
|
|
+ if (!innerData._flightCache.Keys.Any(m => m.Equals(flight)))
|
|
|
{
|
|
|
- innerData._flightCache.Add(new FlightInfo(name, speed, lon, lat), innerData.hoverPoint);
|
|
|
+ innerData.flightStorge.Items.Add(innerData.hoverPoint);
|
|
|
+ innerData.flightpath.Points.Add(innerData.hoverPoint.Location);
|
|
|
+ innerData._flightCache.Add(flight, innerData.hoverPoint);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ public static void UpdateItem<T>(this MapControl ctrl, T item, bool setCenter = false) where T : FlightInfo, new()
|
|
|
+ {
|
|
|
+ if (item == null) return;
|
|
|
+ var innerData = ctrl.Tag as InnerData;
|
|
|
+ if (innerData._flightCache.ContainsKey(item))
|
|
|
+ {
|
|
|
+ var mapDot = innerData._flightCache[item] as MapDot;
|
|
|
+ mapDot.Location = new GeoPoint(item.FlightLat, item.FlightLon);//外部修改了位置
|
|
|
+ if (mapDot.Size != (item.Selected ? _selectedDotSize : _dotSize))//外部修改了选中状态
|
|
|
+ {
|
|
|
+ mapDot.Size = item.Selected ? _selectedDotSize : _dotSize;
|
|
|
+ mapDot.StrokeWidth = item.Selected ? 0 : 1;
|
|
|
+
|
|
|
+ if (mapDot.ClusteredItems.Any())
|
|
|
+ (mapDot.ClusteredItems[0] as MapDot).Size = _selectedDotSize;
|
|
|
+ if (item.Selected)
|
|
|
+ {
|
|
|
+ //让选中的Item在上层
|
|
|
+ var idx = innerData.flightStorge.Items.IndexOf(mapDot);
|
|
|
+ innerData.flightStorge.Items.Swap(idx, innerData.flightStorge.Items.Count - 1);
|
|
|
+ //innerData.posStorge.Items.Add(mapDot);
|
|
|
+
|
|
|
+ //需要将上次选中的点设置为未选中
|
|
|
+ if (innerData.preSelectedItem != null)
|
|
|
+ {
|
|
|
+ innerData.preSelectedItem.Size = _dotSize;
|
|
|
+ (innerData.preSelectedItem.Tag as FlightInfo).Selected = false;
|
|
|
+ }
|
|
|
+ innerData.preSelectedItem = mapDot;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (setCenter)
|
|
|
+ ctrl.SetCenterPoint(item.FlightLon, item.FlightLat, false);
|
|
|
+ }
|
|
|
+ }
|
|
|
public static void DelFlightItem<T>(this MapControl ctrl, IEnumerable<T> data) where T : FlightInfo, new()
|
|
|
{
|
|
|
var fs = data.ToList();
|
|
|
@@ -854,7 +842,7 @@ public static class MapControlEx
|
|
|
private static void ShowFlightLine<T>(this MapControl ctrl, InnerData innerData, List<T> points) where T : FlightInfo, new()
|
|
|
{
|
|
|
var first = points.First();
|
|
|
- string filghtName = $"DrawFlightLine_{first.FlightName}_{first.Speed}";
|
|
|
+ string filghtName = first.GetFilghtName();
|
|
|
var flightpath = new MapSpline()
|
|
|
{
|
|
|
Stroke = Color.FromArgb(127, 255, 0, 199),
|
|
|
@@ -885,10 +873,11 @@ public static class MapControlEx
|
|
|
|
|
|
var hoverPointj = new MapDot()
|
|
|
{
|
|
|
+
|
|
|
CanResize = false,
|
|
|
CanMove = true,
|
|
|
- ToolTipPattern = $"航迹:{finfo.FlightName}\r\n{finfo.FlightLon},{finfo.FlightLat}°",
|
|
|
- Tag = flightpath.Tag,
|
|
|
+ ToolTipPattern = finfo.ToString(),
|
|
|
+ Tag = finfo,
|
|
|
Size = 8
|
|
|
};
|
|
|
hoverPointj.Location = location;
|
|
|
@@ -1071,7 +1060,6 @@ public static class MapControlEx
|
|
|
btnExportCsv.ItemClick += (sender, e) =>
|
|
|
{
|
|
|
if (!innerData._flightCache.Any()) return;
|
|
|
- bool exportSigTime = false;
|
|
|
Dictionary<string, string> cellFormats = new Dictionary<string, string>();//单元格的format
|
|
|
var props = innerData._flightCache.Keys.GetType().GetGenericArguments().First().GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
|
|
List<(int ColumnIndex, PropertyInfo Prop, string Header)> listPorps = new List<(int, PropertyInfo, string)>();
|
|
|
@@ -1079,8 +1067,7 @@ public static class MapControlEx
|
|
|
{
|
|
|
ExportCellAttribute attrExport = prop.GetCustomAttribute<ExportCellAttribute>();
|
|
|
if (attrExport == null) continue;
|
|
|
- if (prop.Name == nameof(PosData.SigTime))
|
|
|
- exportSigTime = true;
|
|
|
+
|
|
|
if (!string.IsNullOrWhiteSpace(attrExport.Format))
|
|
|
{
|
|
|
cellFormats.Add(prop.Name, attrExport.Format);
|
|
|
@@ -1187,16 +1174,12 @@ public static class MapControlEx
|
|
|
gc.MainView = view;
|
|
|
gc.ViewCollection.Add(view);
|
|
|
view.OptionsPrint.ShowPrintExportProgress = false;
|
|
|
- bool exportSigTime = false;
|
|
|
Dictionary<string, string> cellFormats = new Dictionary<string, string>();//单元格的format
|
|
|
var props = innerData._flightCache.Keys.GetType().GetGenericArguments().First().GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
|
|
foreach (var prop in props)
|
|
|
{
|
|
|
ExportCellAttribute attrExport = prop.GetCustomAttribute<ExportCellAttribute>();
|
|
|
if (attrExport == null) continue;
|
|
|
- if (prop.Name == nameof(PosData.SigTime))
|
|
|
- exportSigTime = true;
|
|
|
-
|
|
|
if (!string.IsNullOrWhiteSpace(attrExport.Format))
|
|
|
{
|
|
|
cellFormats.Add(prop.Name, attrExport.Format);
|
|
|
@@ -2627,106 +2610,5 @@ public static class MapControlEx
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
- //定位点聚合器
|
|
|
- class PosClusterer : IClusterer
|
|
|
- {
|
|
|
- private MapControl ctrl;
|
|
|
- private IMapDataAdapter owner;
|
|
|
- private MapViewport preViewPoint;
|
|
|
- private DebounceDispatcher dispatcher = new DebounceDispatcher();
|
|
|
-
|
|
|
- public bool IsBusy { get; private set; }
|
|
|
-
|
|
|
- public MapItemCollection Items { get; private set; }
|
|
|
- public PosClusterer(MapControl ctrl)
|
|
|
- {
|
|
|
- this.ctrl = ctrl;
|
|
|
|
|
|
- }
|
|
|
- public void SetOwner(IMapDataAdapter owner)
|
|
|
- {
|
|
|
- this.owner = owner;
|
|
|
- Items = new MapItemCollection(owner);
|
|
|
- }
|
|
|
-
|
|
|
- public void Clusterize(IEnumerable<MapItem> sourceItems, MapViewport viewport, bool sourceChanged)
|
|
|
- {
|
|
|
- IsBusy = true;
|
|
|
- if (sourceChanged)
|
|
|
- DoClusterize(sourceItems, viewport, sourceChanged);
|
|
|
- else
|
|
|
- dispatcher.Debounce(100, () => DoClusterize(sourceItems, viewport, sourceChanged));
|
|
|
- }
|
|
|
-
|
|
|
- private void DoClusterize(IEnumerable<MapItem> sourceItems, MapViewport viewport, bool sourceChanged)
|
|
|
- {
|
|
|
- if (preViewPoint == null)
|
|
|
- {
|
|
|
- preViewPoint = viewport;
|
|
|
- return;
|
|
|
- }
|
|
|
- if (!sourceChanged && preViewPoint.ZoomLevel == viewport.ZoomLevel)//地图移动或者MapControl大小发生了改变时直接操作Items避免闪烁
|
|
|
- {
|
|
|
- preViewPoint = viewport;
|
|
|
- }
|
|
|
- else//地图进行了缩放
|
|
|
- {
|
|
|
- Items.Clear();
|
|
|
- var cache = new Dictionary<int, List<MapItem>>();
|
|
|
- foreach (MapDot item in sourceItems)
|
|
|
- {
|
|
|
- var point = ctrl.CoordPointToScreenPoint(item.Location);
|
|
|
- int pointX = (int)point.X;
|
|
|
- int pointY = (int)point.Y;
|
|
|
- bool visible = true;
|
|
|
- if (pointX <= _dotSize || pointX > ctrl.Width - _dotSize)
|
|
|
- visible = false;
|
|
|
- else if (pointY <= _dotSize || pointY > ctrl.Height - _dotSize)
|
|
|
- visible = false;
|
|
|
- pointX /= (_dotSize * 2);
|
|
|
- pointY /= (_dotSize * 2);
|
|
|
- var key = pointX << 16 | pointY;
|
|
|
- if (!visible)
|
|
|
- key = -key;
|
|
|
- if (!cache.ContainsKey(key))
|
|
|
- cache.Add(key, new List<MapItem>());
|
|
|
- cache[key].Add(item);
|
|
|
- }
|
|
|
- var innerData = ctrl.Tag as InnerData;
|
|
|
- innerData._clusterCache.Clear();
|
|
|
- LinkedList<MapItem> temp = new LinkedList<MapItem>();
|
|
|
- foreach (var kv in cache)
|
|
|
- {
|
|
|
- var firstDot = kv.Value[0] as MapDot;
|
|
|
- var firstObj = firstDot.Tag as PosData;
|
|
|
- firstDot.Size = kv.Value.Count > 1 ? _dotSize + 2 : _dotSize;
|
|
|
- firstObj.ClusterCount = kv.Value.Count;
|
|
|
- firstObj.ClusterKey = kv.Key;
|
|
|
- innerData._clusterCache.Add(kv.Key, firstDot);
|
|
|
- temp.AddLast(firstDot);
|
|
|
- }
|
|
|
- Items.AddRange(temp);
|
|
|
-
|
|
|
- cache.Clear();
|
|
|
- preViewPoint = viewport;
|
|
|
- owner.OnClustered();
|
|
|
- }
|
|
|
- this.IsBusy = false;
|
|
|
- }
|
|
|
- //计算多个坐标的中心位置
|
|
|
- public GeoPoint GetCenterPointFromListOfCoordinates(List<MapItem> geoCoordinateList)
|
|
|
- {
|
|
|
- int total = geoCoordinateList.Count;
|
|
|
- double lat = 0, lon = 0;
|
|
|
- foreach (MapDot g in geoCoordinateList)
|
|
|
- {
|
|
|
- lat += (g.Location as GeoPoint).Latitude * Math.PI / 180;
|
|
|
- lon += (g.Location as GeoPoint).Longitude * Math.PI / 180;
|
|
|
- }
|
|
|
- lat /= total;
|
|
|
- lon /= total;
|
|
|
- return new GeoPoint(lat * 180 / Math.PI, lon * 180 / Math.PI);
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
}
|