@@ -39,6 +39,8 @@ public partial class MainWindow : Window
39
39
MapPolyline currentFlight ;
40
40
MavlinkLog currentFlightLog ;
41
41
long lastAttitudeMessage ;
42
+ List < LogEntry > mappedLogEntries ;
43
+ MapLayer annotationLayer ;
42
44
43
45
public MainWindow ( )
44
46
{
@@ -829,6 +831,7 @@ void ShowMap()
829
831
line . StrokeThickness = 4 ;
830
832
line . Stroke = new SolidColorBrush ( GetRandomColor ( ) ) ;
831
833
LocationCollection points = new LocationCollection ( ) ;
834
+ mappedLogEntries = new List < Model . LogEntry > ( ) ;
832
835
833
836
//Debug.WriteLine("time,\t\tlat,\t\tlong,\t\t\tnsat,\talt,\thdop,\tfix");
834
837
foreach ( var row in log . GetRows ( "GPS" , flight . StartTime , flight . Duration ) )
@@ -844,6 +847,7 @@ void ShowMap()
844
847
alt = 0 ;
845
848
}
846
849
mapData . Add ( gps ) ;
850
+ mappedLogEntries . Add ( row ) ;
847
851
var pos = new Location ( ) { Altitude = alt , Latitude = gps . Lat , Longitude = gps . Lon } ;
848
852
points . Add ( pos ) ;
849
853
ulong time = ( ulong ) gps . GPSTime ;
@@ -953,8 +957,6 @@ private void OnChildListItemSelected(object sender, SelectionChangedEventArgs e)
953
957
954
958
IEnumerable < DataValue > GetSelectedDataValues ( LogItemSchema schema )
955
959
{
956
- List < DataValue > combined = new List < DataValue > ( ) ;
957
-
958
960
List < Flight > selected = GetSelectedFlights ( ) ;
959
961
if ( selected . Count == 0 )
960
962
{
@@ -970,13 +972,14 @@ IEnumerable<DataValue> GetSelectedDataValues(LogItemSchema schema)
970
972
{
971
973
if ( flight . Log == null || flight . Log == log )
972
974
{
973
- combined . AddRange ( log . GetDataValues ( schema , flight . StartTime , flight . Duration ) ) ;
975
+ foreach ( var dv in log . GetDataValues ( schema , flight . StartTime , flight . Duration ) )
976
+ {
977
+ yield return dv ;
978
+ }
974
979
}
975
980
}
976
981
}
977
- }
978
-
979
- return combined ;
982
+ }
980
983
}
981
984
982
985
Thickness defaultChartMargin = new Thickness ( 0 , 10 , 0 , 10 ) ;
@@ -1100,22 +1103,184 @@ private void GraphItem(LogItemSchema schema)
1100
1103
else
1101
1104
{
1102
1105
StringBuilder sb = new StringBuilder ( ) ;
1106
+ string previous = null ;
1107
+ List < DataValue > unique = new List < Model . DataValue > ( ) ;
1103
1108
foreach ( var value in GetSelectedDataValues ( schema ) )
1104
1109
{
1105
1110
if ( ! string . IsNullOrEmpty ( value . Label ) )
1106
1111
{
1107
- sb . AppendLine ( value . Label ) ;
1112
+ if ( previous != value . Label )
1113
+ {
1114
+ unique . Add ( value ) ;
1115
+ sb . Append ( ( ( ulong ) value . X ) . ToString ( ) ) ;
1116
+ sb . Append ( ": " ) ;
1117
+ sb . AppendLine ( value . Label ) ;
1118
+ previous = value . Label ;
1119
+ }
1120
+ }
1121
+ }
1122
+ SystemConsole . Write ( sb . ToString ( ) ) ;
1123
+ ConsoleButton . IsChecked = true ;
1124
+ SystemConsole . Show ( ) ;
1125
+ }
1126
+ }
1127
+
1128
+ private void AnnotateMap ( LogItemSchema schema )
1129
+ {
1130
+ List < DataValue > unique = new List < Model . DataValue > ( ) ;
1131
+ if ( schema . IsNumeric )
1132
+ {
1133
+ var data = GetSelectedDataValues ( schema ) ;
1134
+ ShowStatus ( string . Format ( "Found {0} data values" , data . Count ( ) ) ) ;
1135
+ if ( data . Count ( ) > 0 )
1136
+ {
1137
+ double previous = 0 ;
1138
+ {
1139
+ // uniquify it.
1140
+ foreach ( var value in data )
1141
+ {
1142
+ if ( value . Y != previous )
1143
+ {
1144
+ unique . Add ( value ) ;
1145
+ previous = value . Y ;
1146
+ }
1147
+ }
1148
+ }
1149
+ }
1150
+ }
1151
+ else
1152
+ {
1153
+ StringBuilder sb = new StringBuilder ( ) ;
1154
+ string previous = null ;
1155
+ foreach ( var value in GetSelectedDataValues ( schema ) )
1156
+ {
1157
+ if ( ! string . IsNullOrEmpty ( value . Label ) )
1158
+ {
1159
+ if ( previous != value . Label )
1160
+ {
1161
+ unique . Add ( value ) ;
1162
+ sb . Append ( value . X . ToString ( ) ) ;
1163
+ sb . Append ( ": " ) ;
1164
+ sb . AppendLine ( value . Label ) ;
1165
+ previous = value . Label ;
1166
+ }
1167
+ }
1168
+ }
1169
+ }
1170
+
1171
+ // if there are too many values, then limit it to an even spread of 100 items.
1172
+ if ( unique . Count > 100 )
1173
+ {
1174
+ var summary = new List < Model . DataValue > ( ) ;
1175
+ double skip = ( unique . Count / 100 ) ;
1176
+ for ( int i = 0 , n = unique . Count ; i < n ; i ++ )
1177
+ {
1178
+ var value = unique [ i ] ;
1179
+ if ( i >= summary . Count * unique . Count / 100 )
1180
+ {
1181
+ summary . Add ( value ) ;
1182
+ }
1183
+ }
1184
+ unique = summary ;
1185
+ }
1186
+ AnnotateMap ( unique ) ;
1187
+ }
1188
+
1189
+ private void AnnotateMap ( List < DataValue > unique )
1190
+ {
1191
+ if ( this . mappedLogEntries == null || this . mappedLogEntries . Count == 0 )
1192
+ {
1193
+ ShowMap ( ) ;
1194
+ }
1195
+
1196
+ if ( this . mappedLogEntries == null || this . mappedLogEntries . Count == 0 )
1197
+ {
1198
+ MessageBox . Show ( "Sorry, could not find GPS map info, so cannot annotate data on the map" ,
1199
+ "GPS info is missing" , MessageBoxButton . OK , MessageBoxImage . Exclamation ) ;
1200
+ return ;
1201
+ }
1202
+
1203
+ if ( annotationLayer != null )
1204
+ {
1205
+ myMap . Children . Remove ( annotationLayer ) ;
1206
+ }
1207
+ annotationLayer = new MapLayer ( ) ;
1208
+
1209
+ SolidColorBrush annotationBrush = new SolidColorBrush ( Color . FromArgb ( 0x80 , 0xff , 0xff , 0xB0 ) ) ;
1210
+
1211
+ foreach ( var dv in unique )
1212
+ {
1213
+ LogEntry closest = null ;
1214
+ LogField field = dv . UserData as LogField ;
1215
+ if ( field != null )
1216
+ {
1217
+ // csv log
1218
+ LogEntry e = field . Parent ;
1219
+ closest = FindNearestMappedItem ( e . Timestamp ) ;
1220
+ }
1221
+ else
1222
+ {
1223
+ // px4 log?
1224
+ Message msg = dv . UserData as Message ;
1225
+ if ( msg != null )
1226
+ {
1227
+ closest = FindNearestMappedItem ( msg . GetTimestamp ( ) ) ;
1108
1228
}
1109
1229
else
1110
1230
{
1111
- sb . AppendLine ( value . Y . ToString ( ) ) ;
1231
+ // mavlink
1232
+ MavlinkLog . Message mavmsg = dv . UserData as MavlinkLog . Message ;
1233
+ if ( mavmsg != null )
1234
+ {
1235
+ closest = FindNearestMappedItem ( mavmsg . Timestamp . Ticks / 10 ) ;
1236
+ }
1112
1237
}
1113
1238
}
1114
1239
1115
- SystemConsole . Write ( sb . ToString ( ) ) ;
1116
- ConsoleButton . IsChecked = true ;
1117
- SystemConsole . Show ( ) ;
1240
+ if ( closest != null )
1241
+ {
1242
+ LogEntryGPS gps = new LogEntryGPS ( closest ) ;
1243
+ // map doesn't like negative altitudes.
1244
+ double alt = gps . Alt ;
1245
+ if ( alt < 0 )
1246
+ {
1247
+ alt = 0 ;
1248
+ }
1249
+ var pos = new Location ( ) { Altitude = alt , Latitude = gps . Lat , Longitude = gps . Lon } ;
1250
+ string label = dv . Label ;
1251
+ if ( string . IsNullOrEmpty ( label ) )
1252
+ {
1253
+ label = dv . Y . ToString ( ) ;
1254
+ }
1255
+ annotationLayer . AddChild ( new TextBlock ( new Run ( label ) { Background = annotationBrush } ) , pos , PositionOrigin . BottomLeft ) ;
1256
+ }
1257
+
1118
1258
}
1259
+ myMap . Children . Add ( annotationLayer ) ;
1260
+
1261
+ SystemConsole . Hide ( ) ;
1262
+ ChartStack . Visibility = Visibility . Collapsed ;
1263
+ myMap . Visibility = Visibility . Visible ;
1264
+ myMap . UpdateLayout ( ) ;
1265
+ }
1266
+
1267
+ private LogEntry FindNearestMappedItem ( double t )
1268
+ {
1269
+ LogEntry closest = null ;
1270
+ double bestDiff = 0 ;
1271
+ // find nearest mapped location (nearest in time).
1272
+ foreach ( var mapped in this . mappedLogEntries )
1273
+ {
1274
+ var time = mapped . Timestamp ;
1275
+ var diff = Math . Abs ( ( double ) time - t ) ;
1276
+
1277
+ if ( closest == null || diff < bestDiff )
1278
+ {
1279
+ closest = mapped ;
1280
+ bestDiff = diff ;
1281
+ }
1282
+ }
1283
+ return closest ;
1119
1284
}
1120
1285
1121
1286
private void OnNewChartGenerated ( object sender , List < DataValue > e )
@@ -1178,6 +1343,10 @@ private void LayoutCharts()
1178
1343
double height = ChartStack . ActualHeight ;
1179
1344
double count = ChartStack . ChartCount ;
1180
1345
height -= ( count * ( defaultChartMargin . Top + defaultChartMargin . Bottom ) ) ; // remove margins
1346
+ if ( height < 0 )
1347
+ {
1348
+ height = 0 ;
1349
+ }
1181
1350
double chartHeight = Math . Min ( MaxChartHeight , height / count ) ;
1182
1351
bool found = false ;
1183
1352
foreach ( FrameworkElement c in ChartStack . Charts )
@@ -1250,6 +1419,7 @@ private void UnselectCategory(LogItemSchema item)
1250
1419
}
1251
1420
}
1252
1421
1422
+
1253
1423
private void OnClear ( object sender , RoutedEventArgs e )
1254
1424
{
1255
1425
ChartStack . ClearCharts ( ) ;
@@ -1294,15 +1464,7 @@ private void OnFlightSelected(object sender, SelectionChangedEventArgs e)
1294
1464
}
1295
1465
} ) ;
1296
1466
}
1297
-
1298
- //private void OnMapPointerMoved(object sender, PointerRoutedEventArgs e)
1299
- //{
1300
- // Point mapPos = e.GetCurrentPoint(myMap).Position;
1301
- // Geopoint location;
1302
- // myMap.GetLocationFromOffset(mapPos, out location);
1303
- // StatusText.Text = location.Position.Latitude + ", " + location.Position.Longitude;
1304
- //}
1305
-
1467
+
1306
1468
private void OnFlightViewKeyDown ( object sender , KeyEventArgs e )
1307
1469
{
1308
1470
if ( e . Key == Key . Delete )
@@ -1487,6 +1649,8 @@ struct IncomingImage
1487
1649
1488
1650
IncomingImage incoming_image = new IncomingImage ( ) ;
1489
1651
1652
+ public LogItemSchema rightClickedItem { get ; private set ; }
1653
+
1490
1654
private void OnShowConsole ( object sender , RoutedEventArgs e )
1491
1655
{
1492
1656
SystemConsole . Show ( ) ;
@@ -1583,7 +1747,6 @@ private void DrawVectors(double[,] xmag, double[,] ymag)
1583
1747
// find guassian lines in the map and draw them so it looks like this:
1584
1748
// https://www.ngdc.noaa.gov/geomag/WMM/data/WMM2015/WMM2015_D_MERC.pdf
1585
1749
1586
-
1587
1750
for ( int i = 0 ; i < 180 ; i ++ )
1588
1751
{
1589
1752
for ( int j = 0 ; j < 360 ; j ++ )
@@ -1619,6 +1782,31 @@ private void OnPaste(object sender, ExecutedRoutedEventArgs e)
1619
1782
CameraPanel . Visibility = Visibility . Visible ;
1620
1783
}
1621
1784
}
1785
+
1786
+ private void OnAnnotateItem ( object sender , RoutedEventArgs e )
1787
+ {
1788
+ LogItemSchema item = this . rightClickedItem ;
1789
+ if ( item != null )
1790
+ {
1791
+ AnnotateMap ( item ) ;
1792
+ }
1793
+ }
1794
+
1795
+ private void OnRightClickCategoryList ( object sender , MouseButtonEventArgs e )
1796
+ {
1797
+ this . rightClickedItem = null ;
1798
+ Point pos = e . GetPosition ( CategoryList ) ;
1799
+ DependencyObject dep = ( DependencyObject ) e . OriginalSource ;
1800
+ while ( ( dep != null ) && ! ( dep is ListViewItem ) )
1801
+ {
1802
+ dep = VisualTreeHelper . GetParent ( dep ) ;
1803
+ }
1804
+ if ( dep == null )
1805
+ return ;
1806
+ ListViewItem listitem = ( ListViewItem ) dep ;
1807
+ LogItemSchema item = listitem . DataContext as LogItemSchema ;
1808
+ this . rightClickedItem = item ;
1809
+ }
1622
1810
}
1623
1811
}
1624
1812
0 commit comments