Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ADS-B] Add emitter category support & HTTP endpoint for retrieving ADS-B data #3428

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
23 changes: 12 additions & 11 deletions ExtLibs/ArduPilot/Mavlink/MAVLinkInterface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5166,25 +5166,26 @@ public async Task<MAVLinkMessage> readPacketAsync()
// adsb packets are forwarded and can be from any sysid/compid
if (msgid == (byte)MAVLINK_MSG_ID.ADSB_VEHICLE)
{
var adsb = message.ToStructure<mavlink_adsb_vehicle_t>();
var adsbMessage = message.ToStructure<mavlink_adsb_vehicle_t>();

var id = adsb.ICAO_address.ToString("X5");
var id = adsbMessage.ICAO_address.ToString("X5");

if (_UpdateADSBPlanePosition != null)
_UpdateADSBPlanePosition(this, new adsb.PointLatLngAltHdg(
adsb.lat / 1e7,
adsb.lon / 1e7,
adsb.altitude / 1000,
adsb.heading * 0.01f,
adsb.hor_velocity,
adsbMessage.lat / 1e7,
adsbMessage.lon / 1e7,
adsbMessage.altitude / 1000,
adsbMessage.heading * 0.01f,
adsbMessage.hor_velocity,
id,
DateTime.Now
)
{
CallSign = Encoding.UTF8.GetString(adsb.callsign),
Squawk = adsb.squawk,
Raw = adsb,
VerticalSpeed = adsb.ver_velocity,
CallSign = Encoding.UTF8.GetString(adsbMessage.callsign),
Squawk = adsbMessage.squawk,
Raw = adsbMessage,
VerticalSpeed = adsbMessage.ver_velocity,
Category = adsb.GetEmitterCategoryShort((ADSB_EMITTER_TYPE)adsbMessage.emitter_type),
}
);
}
Expand Down
153 changes: 143 additions & 10 deletions ExtLibs/Maps/GMapMarkerADSBPlane.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,48 @@
using System;
using System.Drawing;
using GMap.NET;
using GMap.NET.Drawing.Properties;
using GMap.NET.WindowsForms;

namespace MissionPlanner.Maps
{
[Serializable]
public class GMapMarkerADSBPlane : GMapMarker
{
private static readonly Bitmap icong = new Bitmap(global::MissionPlanner.Maps.Resources.FW_icons_2013_logos_01,
new Size(40, 40));
// The images we're using are 72x72, so we'll use that as the size
private static readonly Size size = new Size(72, 72);

private static readonly Bitmap iconr = new Bitmap(global::MissionPlanner.Maps.Resources.FW_icons_2013_logos_011,
new Size(40, 40));
// Images retrieved from tar1090 sprites: https://github.com/wiedehopf/tar1090/blob/master/html/images/sprites.png
private static readonly Bitmap adsb_unknown = new Bitmap(global::MissionPlanner.Maps.Resources.adsb_unknown, size);
private static readonly Bitmap adsb_light = new Bitmap(global::MissionPlanner.Maps.Resources.adsb_light, size);
private static readonly Bitmap adsb_small = new Bitmap(global::MissionPlanner.Maps.Resources.adsb_small, size);
private static readonly Bitmap adsb_large = new Bitmap(global::MissionPlanner.Maps.Resources.adsb_large, size);
private static readonly Bitmap adsb_heavy = new Bitmap(global::MissionPlanner.Maps.Resources.adsb_heavy, size);
private static readonly Bitmap adsb_highly_manuv = new Bitmap(global::MissionPlanner.Maps.Resources.adsb_highly_manuv, size);
private static readonly Bitmap adsb_rotocraft = new Bitmap(global::MissionPlanner.Maps.Resources.adsb_rotocraft, size);
//private static readonly Bitmap adsb_glider = new Bitmap(global::MissionPlanner.Maps.Resources.adsb_glider, size);
private static readonly Bitmap adsb_lighter_air = new Bitmap(global::MissionPlanner.Maps.Resources.adsb_balloon, size);
private static readonly Bitmap adsb_parachute = new Bitmap(global::MissionPlanner.Maps.Resources.adsb_parachute, size);
//private static readonly Bitmap adsb_ultralight = new Bitmap(global::MissionPlanner.Maps.Resources.adsb_ultralight, size);
private static readonly Bitmap adsb_uav = new Bitmap(global::MissionPlanner.Maps.Resources.adsb_uav, size);
private static readonly Bitmap adsb_emergency_surface = new Bitmap(global::MissionPlanner.Maps.Resources.adsb_emergency_surface, size);
private static readonly Bitmap adsb_service_surface = new Bitmap(global::MissionPlanner.Maps.Resources.adsb_service_surface, size);
private static readonly Bitmap adsb_point_obstacle = new Bitmap(global::MissionPlanner.Maps.Resources.adsb_balloon, size); // point obstacles are used for balloons

private static readonly Bitmap icono = new Bitmap(global::MissionPlanner.Maps.Resources.FW_icons_2013_logos_012,
new Size(40, 40));

public float heading = 0;
public AlertLevelOptions AlertLevel = AlertLevelOptions.Green;
public float DrawScale = 0.5f;

// Cache the last drawn data to avoid re-coloring every frame
private Bitmap lastDrawn = null;
// Store the last alert level to decide whether to redraw
private AlertLevelOptions lastAlertLevel = AlertLevelOptions.Green;
private MAVLink.ADSB_EMITTER_TYPE lastEmitterCategory = MAVLink.ADSB_EMITTER_TYPE.NO_INFO;
private bool lastIsOnGround = true;

public MAVLink.ADSB_EMITTER_TYPE EmitterCategory { get; set; }
public bool IsOnGround { get; set; }

public enum AlertLevelOptions
{
Expand All @@ -32,10 +56,33 @@ public GMapMarkerADSBPlane(PointLatLng p, float heading, AlertLevelOptions alert
{
this.AlertLevel = alert;
this.heading = heading;
Size = icong.Size;
Size = size;
Offset = new Point(Size.Width / -2, Size.Height / -2);
}

private static void ColorSprite(Bitmap bitmap, Color fillColor)
{
int width = bitmap.Width;
int height = bitmap.Height;

bool IsWhite(Color pixel) => pixel.R == 255 && pixel.G == 255 && pixel.B == 255 && pixel.A != 0;

// Iterate through every pixel in the image
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
Color pixel = bitmap.GetPixel(x, y);

// If the pixel is white, color it with the fill color
if (IsWhite(pixel))
{
bitmap.SetPixel(x, y, fillColor);
}
}
}
}

public override void OnRender(IGraphics g)
{
var temp = g.Transform;
Expand All @@ -51,18 +98,104 @@ public override void OnRender(IGraphics g)
{
}

bool needsRedraw = lastDrawn == null || lastAlertLevel != AlertLevel || lastEmitterCategory != EmitterCategory || lastIsOnGround != IsOnGround;
if (!needsRedraw)
{
g.ScaleTransform(DrawScale, DrawScale);
g.DrawImageUnscaled(lastDrawn, lastDrawn.Width / -2, lastDrawn.Height / -2);
g.Transform = temp;
return;
}

// Set the icon based on emitter category
Bitmap bitmap = adsb_unknown;
DrawScale = 0.5f;

switch (this.EmitterCategory)
{
case MAVLink.ADSB_EMITTER_TYPE.NO_INFO:
bitmap = adsb_unknown;
break;
case MAVLink.ADSB_EMITTER_TYPE.LIGHT:
bitmap = adsb_light;
break;
case MAVLink.ADSB_EMITTER_TYPE.SMALL:
bitmap = adsb_small;
break;
case MAVLink.ADSB_EMITTER_TYPE.LARGE:
bitmap = adsb_large;
DrawScale *= 1.25f;
break;
case MAVLink.ADSB_EMITTER_TYPE.HEAVY:
bitmap = adsb_heavy;
DrawScale *= 1.5f;
break;
case MAVLink.ADSB_EMITTER_TYPE.HIGH_VORTEX_LARGE:
bitmap = adsb_heavy;
DrawScale *= 1.5f;
break;
case MAVLink.ADSB_EMITTER_TYPE.HIGHLY_MANUV:
bitmap = adsb_highly_manuv;
break;
case MAVLink.ADSB_EMITTER_TYPE.ROTOCRAFT:
bitmap = adsb_rotocraft;
break;
case MAVLink.ADSB_EMITTER_TYPE.GLIDER:
bitmap = adsb_lighter_air;
break;
case MAVLink.ADSB_EMITTER_TYPE.PARACHUTE:
bitmap = adsb_parachute;
break;
case MAVLink.ADSB_EMITTER_TYPE.ULTRA_LIGHT:
bitmap = adsb_lighter_air;
break;
case MAVLink.ADSB_EMITTER_TYPE.UAV:
bitmap = adsb_uav;
break;
case MAVLink.ADSB_EMITTER_TYPE.SPACE:
//???
break;
case MAVLink.ADSB_EMITTER_TYPE.EMERGENCY_SURFACE:
bitmap = adsb_emergency_surface;
break;
case MAVLink.ADSB_EMITTER_TYPE.SERVICE_SURFACE:
bitmap = adsb_service_surface;
break;
case MAVLink.ADSB_EMITTER_TYPE.POINT_OBSTACLE:
bitmap = adsb_point_obstacle;
break;
}
lastEmitterCategory = EmitterCategory;
bitmap = (Bitmap)bitmap.Clone();
g.ScaleTransform(DrawScale, DrawScale);
// Set the color based on alert level
var fillColor = Color.Green;
switch (AlertLevel)
{
case AlertLevelOptions.Green:
g.DrawImageUnscaled(icong, icong.Width / -2, icong.Height / -2);
fillColor = Color.Green;
break;
case AlertLevelOptions.Orange:
g.DrawImageUnscaled(icono, icono.Width / -2, icono.Height / -2);
fillColor = Color.Orange;
break;
case AlertLevelOptions.Red:
g.DrawImageUnscaled(iconr, iconr.Width / -2, iconr.Height / -2);
fillColor = Color.Red;
break;
}
lastAlertLevel = AlertLevel;

if (IsOnGround)
{
fillColor = Color.DarkGray;
fillColor = Color.FromArgb(128, fillColor);
}
lastIsOnGround = IsOnGround;

ColorSprite(bitmap, fillColor);

g.DrawImageUnscaled(bitmap, bitmap.Width / -2, bitmap.Height / -2);

lastDrawn = (Bitmap)bitmap.Clone();

g.Transform = temp;
}
Expand Down
132 changes: 131 additions & 1 deletion ExtLibs/Maps/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading