Skip to content

Commit

Permalink
Optimizations and map display bug fixes (ArduPilot#3168)
Browse files Browse the repository at this point in the history
* Overlay features added in batch

* Remove redundant feature copy

* Warnings as errors

* Map cache as list

* Remove unused

* Optimize memory allocations

* Improve locking of map cache

* Settings optimization

* Reducing feature properties deserialized to reduce memory usage

---------

Co-authored-by: Rupert Benbrook <[email protected]>
  • Loading branch information
rupertbenbrook and rupertbenbrook-aa authored Sep 12, 2023
1 parent 90159ec commit 05efac1
Show file tree
Hide file tree
Showing 11 changed files with 265 additions and 323 deletions.
5 changes: 4 additions & 1 deletion ExtLibs/AltitudeAngelWings.Plugin/AASettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,10 @@ private void trv_MapLayers_AfterCheck(object sender, TreeViewEventArgs e)
{
var item = (FilterInfoDisplay)e.Node.Tag;
item.Visible = e.Node.Checked;
ProcessMapsFromCache();
if (trv_MapLayers.Visible && trv_MapLayers.Focused)
{
ProcessMapsFromCache();
}
}

private void txt_FlightPlanName_TextChanged(object sender, EventArgs e)
Expand Down
18 changes: 3 additions & 15 deletions ExtLibs/AltitudeAngelWings.Plugin/MapAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,6 @@ private Feature[] GetMapItemsOnMouseClick(Point point)
return mapItems.ToArray();
}

public LatLong GetCenter()
{
var pointLatLng = default(PointLatLng);
_context.Send(_ => pointLatLng = _mapControl.Position, null);
return new LatLong(pointLatLng.Lat, pointLatLng.Lng);
}

public BoundingLatLong GetViewArea()
{
var rectLatLng = default(RectLatLng);
Expand All @@ -170,9 +163,6 @@ public BoundingLatLong GetViewArea()
};
}

public void AddOverlay(string name)
=> _context.Send(state => _mapControl.Overlays.Add(new GMapOverlay(name)), null);

public void DeleteOverlay(string name)
=> _context.Send(_ =>
{
Expand All @@ -192,10 +182,8 @@ public IOverlay GetOverlay(string name, bool createIfNotExists = false)
if (overlay == null)
{
if (!createIfNotExists) throw new ArgumentException($"Overlay {name} not found.");
AddOverlay(name);
result = GetOverlay(name);
return;

overlay = new GMapOverlay(name);
_mapControl.Overlays.Add(overlay);
}

result = new OverlayAdapter(overlay);
Expand All @@ -208,7 +196,7 @@ public void Invalidate()
_mapControl.Invalidate();
}

protected void Dispose(bool isDisposing)
protected virtual void Dispose(bool isDisposing)
{
if (isDisposing)
{
Expand Down
140 changes: 63 additions & 77 deletions ExtLibs/AltitudeAngelWings.Plugin/OverlayAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using AltitudeAngelWings.Clients.Api.Model;
using GeoJSON.Net.Feature;
using GMap.NET;
using GMap.NET.WindowsForms;

Expand All @@ -21,99 +19,87 @@ public OverlayAdapter(GMapOverlay overlay)
_overlay = overlay;
}

public bool IsVisible
{
get
{
var value = false;
_context.Send(state =>
{
value = _overlay.IsVisibile;
}, null);
return value;
}
set
{
_context.Send(state =>
{
_overlay.IsVisibile = value;
}, null);
}
}

public void AddOrUpdatePolygon(string name, List<LatLong> points, ColorInfo colorInfo, Feature featureInfo)
public void SetFeatures(IReadOnlyList<OverlayFeature> features)
{
_context.Send(_ =>
{
var polygon = _overlay.Polygons.FirstOrDefault(p => p.Name == name);
if (polygon == null)
var existing = _overlay.Polygons.Union(_overlay.Routes.Cast<MapRoute>()).ToDictionary(i => i.Name, i => i);
var index = features.ToDictionary(f => f.Name, f => f);

// Remove polygons and routes not in features
foreach (var remove in existing.Keys.Except(index.Keys))
{
polygon = new GMapPolygon(points.ConvertAll(p => new PointLatLng(p.Latitude, p.Longitude)), name);
_overlay.Polygons.Add(polygon);
var item = existing[remove];
switch (item)
{
case GMapPolygon polygon:
_overlay.Polygons.Remove(polygon);
break;
case GMapRoute route:
_overlay.Routes.Remove(route);
break;
}
}
polygon.Fill = new SolidBrush(Color.FromArgb((int)colorInfo.FillColor));
polygon.Stroke = new Pen(Color.FromArgb((int)colorInfo.StrokeColor), colorInfo.StrokeWidth);
polygon.IsHitTestVisible = true;
polygon.Tag = featureInfo;
}, null);
}

public void RemovePolygonsExcept(List<string> names)
{
_context.Send(_ =>
{
var remove = _overlay.Polygons
.Where(p => !names.Contains(p.Name))
.ToArray();
foreach (var polygon in remove)
// Update polygons and routes already in features and remove from index as updated
foreach (var update in existing.Keys.Intersect(index.Keys))
{
_overlay.Polygons.Remove(polygon);
}
}, null);
}
var item = existing[update];
var feature = index[update];
switch (item)
{
case GMapPolygon polygon:
polygon.Points.Clear();
polygon.Points.AddRange(feature.Points.Select(p => new PointLatLng(p.Latitude, p.Longitude)));
SetPolygon(polygon, feature);
break;
case GMapRoute route:
route.Points.Clear();
route.Points.AddRange(feature.Points.Select(p => new PointLatLng(p.Latitude, p.Longitude)));
SetRoute(route, feature);
break;
}

public bool PolygonExists(string name)
{
var polygonExists = false;
_context.Send(_ => polygonExists = _overlay.Polygons.Any(i => i.Name == name), null);
return polygonExists;
}
index.Remove(update);
}

public void AddOrUpdateLine(string name, List<LatLong> points, ColorInfo colorInfo, Feature featureInfo)
{
_context.Send(_ =>
{
var route = _overlay.Routes.FirstOrDefault(r => r.Name == name);
if (route == null)
// Add polygons and routes that are left in the index
foreach (var item in index.Values)
{
route = new GMapRoute(points.ConvertAll(p => new PointLatLng(p.Latitude, p.Longitude)), name);
_overlay.Routes.Add(route);
switch (item.Type)
{
case OverlayFeatureType.Polygon:
var polygon = new GMapPolygon(
item.Points.Select(p => new PointLatLng(p.Latitude, p.Longitude)).ToList(),
item.Name);
SetPolygon(polygon, item);
_overlay.Polygons.Add(polygon);
break;
case OverlayFeatureType.Line:
var route = new GMapRoute(
item.Points.Select(p => new PointLatLng(p.Latitude, p.Longitude)).ToList(),
item.Name);
SetRoute(route, item);
_overlay.Routes.Add(route);
break;
}
}
route.Stroke = new Pen(Color.FromArgb((int)colorInfo.StrokeColor), colorInfo.StrokeWidth + 2);
route.IsHitTestVisible = true;
route.Tag = featureInfo;
}, null);
}

public void RemoveLinesExcept(List<string> names)
private static void SetRoute(GMapRoute route, OverlayFeature feature)
{
_context.Send(_ =>
{
var remove = _overlay.Routes
.Where(p => !names.Contains(p.Name))
.ToArray();
foreach (var route in remove)
{
_overlay.Routes.Remove(route);
}
}, null);
route.Stroke = new Pen(Color.FromArgb((int)feature.ColorInfo.StrokeColor), feature.ColorInfo.StrokeWidth);
route.IsHitTestVisible = true;
route.Tag = feature.FeatureInfo;
}

public bool LineExists(string name)
private static void SetPolygon(GMapPolygon polygon, OverlayFeature feature)
{
var exists = false;
_context.Send(_ => exists = _overlay.Routes.Any(i => i.Name == name), null);
return exists;
polygon.Fill = new SolidBrush(Color.FromArgb((int)feature.ColorInfo.FillColor));
polygon.Stroke = new Pen(Color.FromArgb((int)feature.ColorInfo.StrokeColor), feature.ColorInfo.StrokeWidth);
polygon.IsHitTestVisible = true;
polygon.Tag = feature.FeatureInfo;
}
}
}
10 changes: 10 additions & 0 deletions ExtLibs/AltitudeAngelWings/AltitudeAngelWings.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
<WarningLevel>9999</WarningLevel>
<NoWarn />
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.0|AnyCPU'">
<WarningLevel>9999</WarningLevel>
<NoWarn />
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MarkdownSharp" Version="2.0.5" />
<PackageReference Include="NetTopologySuite" Version="2.4.0" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
using System.Collections.Generic;
using System.Linq;
using GeoJSON.Net.Feature;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace AltitudeAngelWings.Clients.Api.Model
{
public static class FeatureExtensions
{
private static readonly char[] DefaultWhitespaceChars = { ' ', '\r', '\n', '\t' };

public static FeatureProperties GetFeatureProperties(this Feature feature)
=> JsonConvert.DeserializeObject<FeatureProperties>(new JObject(feature.Properties.Select(p => new JProperty(p.Key, p.Value))).ToString());
=> new JObject(feature.Properties.Select(p => new JProperty(p.Key, p.Value))).ToObject<FeatureProperties>();

public static IEnumerable<FilterInfoDisplay> GetFilterInfo(this Feature feature)
{
Expand All @@ -20,7 +17,7 @@ public static IEnumerable<FilterInfoDisplay> GetFilterInfo(this Feature feature)
yield break;
}

var filters = JsonConvert.DeserializeObject<List<FilterInfo>>(feature.Properties["filters"].ToString());
var filters = ((JArray)feature.Properties["filters"]).ToObject<IList<FilterInfo>>();
var visible = filters.All(f => f.Active);
foreach (var f in filters)
{
Expand Down Expand Up @@ -68,8 +65,5 @@ public static void UpdateFilterInfo(this IEnumerable<Feature> features, IList<Fi
}
}
}

public static DisplayInfo GetDisplayInfo(this Feature feature)
=> JsonConvert.DeserializeObject<DisplayInfo>(feature.Properties["display"].ToString());
}
}
60 changes: 0 additions & 60 deletions ExtLibs/AltitudeAngelWings/Clients/Api/Model/FeatureProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,51 +8,9 @@ public class FeatureProperties
[JsonProperty("detailedCategory")]
public string DetailedCategory { get; set; }

[JsonProperty("description")]
public string Description { get; set; }

[JsonProperty("fromUtc")]
public string FromUtc { get; set; }

[JsonProperty("toUtc")]
public string ToUtc { get; set; }

[JsonProperty("fromLocal")]
public string FromLocal { get; set; }

[JsonProperty("toLocal")]
public string ToLocal { get; set; }

[JsonProperty("timeZone")]
public string TimeZone { get; set; }

[JsonProperty("flightType")]
public string FlightType { get; set; }

[JsonProperty("radiusMeters")]
public string RadiusMeters { get; set; }

[JsonProperty("isOwner")]
public bool IsOwner { get; set; }

[JsonProperty("alertSummary")]
public string AlertSummary { get; set; }

[JsonProperty("name")]
public string Name { get; set; }

[JsonProperty("state")]
public string State { get; set; }

[JsonProperty("iconUrl")]
public string IconUrl { get; set; }

[JsonProperty("hazardFactor")]
public string HazardFactor { get; set; }

[JsonProperty("hazardFactorName")]
public string HazardFactorName { get; set; }

[JsonProperty("fillColor")]
public string FillColor { get; set; }

Expand All @@ -68,33 +26,15 @@ public class FeatureProperties
[JsonProperty("strokeWidth")]
public string StrokeWidth { get; set; }

[JsonProperty("borderColor")]
public string BorderColor { get; set; }

[JsonProperty("borderOpacity")]
public string BorderOpacity { get; set; }

[JsonProperty("borderWidth")]
public string BorderWidth { get; set; }

[JsonProperty("category")]
public string Category { get; set; }

[JsonProperty("radius")]
public string Radius { get; set; }

[JsonProperty("filters")]
public IList<FilterInfo> Filters { get; set; }

[JsonProperty("display")]
public DisplayInfo DisplayInfo { get; set; }

[JsonProperty("altitudeFloor")]
public AltitudeProperty AltitudeFloor { get; set; }

[JsonProperty("altitudeCeiling")]
public AltitudeProperty AltitudeCeiling { get; set; }

[JsonProperty("utmStatus")]
public UtmStatus UtmStatus { get; set; }

Expand Down
2 changes: 0 additions & 2 deletions ExtLibs/AltitudeAngelWings/IMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ namespace AltitudeAngelWings
public interface IMap
{
bool Enabled { get; }
LatLong GetCenter();
BoundingLatLong GetViewArea();
void AddOverlay(string name);
void DeleteOverlay(string name);
IOverlay GetOverlay(string name, bool createIfNotExists = false);
IObservable<Unit> MapChanged { get; }
Expand Down
10 changes: 1 addition & 9 deletions ExtLibs/AltitudeAngelWings/IOverlay.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
using System.Collections.Generic;
using AltitudeAngelWings.Clients.Api.Model;
using GeoJSON.Net.Feature;

namespace AltitudeAngelWings
{
public interface IOverlay
{
void AddOrUpdatePolygon(string name, List<LatLong> points, ColorInfo colorInfo, Feature featureInfo);
void AddOrUpdateLine(string name, List<LatLong> points, ColorInfo colorInfo, Feature featureInfo);
bool LineExists(string name);
bool PolygonExists(string name);
bool IsVisible { get; set; }
void RemovePolygonsExcept(List<string> names);
void RemoveLinesExcept(List<string> names);
void SetFeatures(IReadOnlyList<OverlayFeature> features);
}
}
Loading

0 comments on commit 05efac1

Please sign in to comment.