Added some comments
This commit is contained in:
parent
184e981aac
commit
af690f4213
|
|
@ -1,15 +1,15 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
namespace FrontEnd
|
namespace FrontEnd
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class to represent the JSON cam object returned by the central web service.
|
||||||
|
/// </summary>
|
||||||
public class Cam
|
public class Cam
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
@ -29,6 +29,9 @@ namespace FrontEnd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Class to represent the JSON client object returned by the central web service.
|
||||||
|
/// </summary>
|
||||||
public class Client
|
public class Client
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
@ -46,6 +49,13 @@ namespace FrontEnd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Class to communicate with the central web service:
|
||||||
|
/// <list type="bullet">
|
||||||
|
/// <item><description>retrieves and deserializes JSON objects to <seealso cref="Client"/> and <seealso cref="Cam"/> objects,</description></item>
|
||||||
|
/// <item><description>retrieves images</description></item>
|
||||||
|
/// </list>
|
||||||
|
/// </summary>
|
||||||
class Communicator
|
class Communicator
|
||||||
{
|
{
|
||||||
static private HttpClient client = new HttpClient();
|
static private HttpClient client = new HttpClient();
|
||||||
|
|
@ -92,11 +102,19 @@ namespace FrontEnd
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the url to the processed camera stream.
|
||||||
|
/// </summary>
|
||||||
public static string GetProcessedCameraAddress(Cam cam)
|
public static string GetProcessedCameraAddress(Cam cam)
|
||||||
{
|
{
|
||||||
return $"{client.BaseAddress.AbsoluteUri}cam/{cam.Id}/processed";
|
return $"{client.BaseAddress.AbsoluteUri}cam/{cam.Id}/processed";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a byte array to a bitmap image.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">byte array representing an image</param>
|
||||||
|
/// <returns>converted Image</returns>
|
||||||
public static BitmapImage BytesToImage(byte[] array)
|
public static BitmapImage BytesToImage(byte[] array)
|
||||||
{
|
{
|
||||||
using (var ms = new System.IO.MemoryStream(array))
|
using (var ms = new System.IO.MemoryStream(array))
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:FrontEnd"
|
xmlns:local="clr-namespace:FrontEnd"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="MainWindow" Height="517.5" Width="800"
|
Title="Client" Height="517.5" Width="800"
|
||||||
Loaded="Window_Loaded">
|
Loaded="Window_Loaded">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,12 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Documents;
|
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Navigation;
|
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
namespace FrontEnd
|
namespace FrontEnd
|
||||||
|
|
@ -23,12 +19,18 @@ namespace FrontEnd
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
// Load and set canvas background image.
|
||||||
var img = new BitmapImage(new Uri(@"pack://application:,,,/Images/map.png"));
|
var img = new BitmapImage(new Uri(@"pack://application:,,,/Images/map.png"));
|
||||||
imgMap.Source = img;
|
imgMap.Source = img;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a camera marker on the map.
|
||||||
|
/// </summary>
|
||||||
private void CreateCameraMarker(Point pos, Cam cam)
|
private void CreateCameraMarker(Point pos, Cam cam)
|
||||||
{
|
{
|
||||||
|
// Represent the client with a custom images.
|
||||||
|
// Load the green camera image from the resources when it's active and the red one when not.
|
||||||
var img = new Image
|
var img = new Image
|
||||||
{
|
{
|
||||||
Source = new BitmapImage(new Uri($@"pack://application:,,,/Images/cam_{(cam.Status ? "green" : "red")}.png")),
|
Source = new BitmapImage(new Uri($@"pack://application:,,,/Images/cam_{(cam.Status ? "green" : "red")}.png")),
|
||||||
|
|
@ -39,13 +41,20 @@ namespace FrontEnd
|
||||||
Tag = cam,
|
Tag = cam,
|
||||||
ToolTip = cam.Label
|
ToolTip = cam.Label
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Set mouse event handlers.
|
||||||
img.MouseDown += Cam_MouseDown;
|
img.MouseDown += Cam_MouseDown;
|
||||||
img.MouseEnter += Img_MouseEnter;
|
img.MouseEnter += Img_MouseEnter;
|
||||||
|
|
||||||
|
// Place the camera image on the canvas.
|
||||||
cnvMap.Children.Add(img);
|
cnvMap.Children.Add(img);
|
||||||
Canvas.SetLeft(img, pos.X - img.Width / 2);
|
Canvas.SetLeft(img, pos.X - img.Width / 2);
|
||||||
Canvas.SetTop(img, pos.Y - img.Height / 2);
|
Canvas.SetTop(img, pos.Y - img.Height / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Select the corresponding list item of the hovered camera marker.
|
||||||
|
/// </summary>
|
||||||
private void Img_MouseEnter(object sender, MouseEventArgs e)
|
private void Img_MouseEnter(object sender, MouseEventArgs e)
|
||||||
{
|
{
|
||||||
var cam = (Cam)((Image)sender).Tag;
|
var cam = (Cam)((Image)sender).Tag;
|
||||||
|
|
@ -56,6 +65,9 @@ namespace FrontEnd
|
||||||
lstDevices.SelectedItem = newSelection.First();
|
lstDevices.SelectedItem = newSelection.First();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Show the stream of the hovered camera marker. (LMB = original stream, LMB = processed stream)
|
||||||
|
/// </summary>
|
||||||
private void Cam_MouseDown(object sender, MouseButtonEventArgs e)
|
private void Cam_MouseDown(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
var cam = (Cam)((Image)sender).Tag;
|
var cam = (Cam)((Image)sender).Tag;
|
||||||
|
|
@ -65,8 +77,13 @@ namespace FrontEnd
|
||||||
new StreamWindow(cam, true).ShowDialog();
|
new StreamWindow(cam, true).ShowDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a client marker on the map.
|
||||||
|
/// </summary>
|
||||||
private void CreateClientMarker(Point pos, Client client)
|
private void CreateClientMarker(Point pos, Client client)
|
||||||
{
|
{
|
||||||
|
// Represent the client with a colored ellipse.
|
||||||
|
// The color is green when active and red when not.
|
||||||
var ellipse = new Ellipse
|
var ellipse = new Ellipse
|
||||||
{
|
{
|
||||||
Width = 20,
|
Width = 20,
|
||||||
|
|
@ -77,12 +94,19 @@ namespace FrontEnd
|
||||||
ToolTip = client.Label,
|
ToolTip = client.Label,
|
||||||
Tag = client
|
Tag = client
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Set mouse event handlers.
|
||||||
ellipse.MouseEnter += Ellipse_MouseEnter;
|
ellipse.MouseEnter += Ellipse_MouseEnter;
|
||||||
|
|
||||||
|
// Place the ellipse on the canvas.
|
||||||
cnvMap.Children.Add(ellipse);
|
cnvMap.Children.Add(ellipse);
|
||||||
Canvas.SetLeft(ellipse, pos.X - ellipse.Width / 2);
|
Canvas.SetLeft(ellipse, pos.X - ellipse.Width / 2);
|
||||||
Canvas.SetTop(ellipse, pos.Y - ellipse.Height / 2);
|
Canvas.SetTop(ellipse, pos.Y - ellipse.Height / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Select the corresponding list item of the hovered client marker.
|
||||||
|
/// </summary>
|
||||||
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
|
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
|
||||||
{
|
{
|
||||||
var client = (Client)((Ellipse)sender).Tag;
|
var client = (Client)((Ellipse)sender).Tag;
|
||||||
|
|
@ -96,6 +120,8 @@ namespace FrontEnd
|
||||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
LoadInformation();
|
LoadInformation();
|
||||||
|
|
||||||
|
// Set a timer to periodically reload shown information.
|
||||||
System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
|
System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
|
||||||
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
|
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
|
||||||
dispatcherTimer.Interval = new TimeSpan(0, 0, 5);
|
dispatcherTimer.Interval = new TimeSpan(0, 0, 5);
|
||||||
|
|
@ -104,6 +130,7 @@ namespace FrontEnd
|
||||||
|
|
||||||
private void dispatcherTimer_Tick(object sender, EventArgs e)
|
private void dispatcherTimer_Tick(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
// Get the current selected list item to restore the selection after refresh.
|
||||||
var selectedItem = (ListBoxItem)lstDevices.SelectedItem;
|
var selectedItem = (ListBoxItem)lstDevices.SelectedItem;
|
||||||
LoadInformation();
|
LoadInformation();
|
||||||
if (selectedItem != null)
|
if (selectedItem != null)
|
||||||
|
|
@ -116,17 +143,25 @@ namespace FrontEnd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Populates the canvas map and device list.
|
||||||
|
/// </summary>
|
||||||
private void LoadInformation()
|
private void LoadInformation()
|
||||||
{
|
{
|
||||||
|
// Retrieve cam and client objects.
|
||||||
List<Cam> cams = Task.Run(async () => { return await Communicator.GetCamsAsync(); }).Result;
|
List<Cam> cams = Task.Run(async () => { return await Communicator.GetCamsAsync(); }).Result;
|
||||||
List<Client> clients = Task.Run(async () => { return await Communicator.GetClientsAsync(); }).Result;
|
List<Client> clients = Task.Run(async () => { return await Communicator.GetClientsAsync(); }).Result;
|
||||||
|
|
||||||
|
// Clear canvas map and properly set it's size.
|
||||||
cnvMap.Children.Clear();
|
cnvMap.Children.Clear();
|
||||||
cnvMap.Width = imgMap.ActualWidth;
|
cnvMap.Width = imgMap.ActualWidth;
|
||||||
cnvMap.Height = imgMap.ActualHeight;
|
cnvMap.Height = imgMap.ActualHeight;
|
||||||
|
|
||||||
|
// Also clear the list and description textbox.
|
||||||
lstDevices.Items.Clear();
|
lstDevices.Items.Clear();
|
||||||
txtInfo.Clear();
|
txtInfo.Clear();
|
||||||
|
|
||||||
|
// Create client markers on canvas map.
|
||||||
foreach (var client in clients)
|
foreach (var client in clients)
|
||||||
{
|
{
|
||||||
CreateClientMarker(new Point(cnvMap.Width * client.X, cnvMap.Height * client.Y), client);
|
CreateClientMarker(new Point(cnvMap.Width * client.X, cnvMap.Height * client.Y), client);
|
||||||
|
|
@ -134,8 +169,10 @@ namespace FrontEnd
|
||||||
|
|
||||||
foreach (var cam in cams)
|
foreach (var cam in cams)
|
||||||
{
|
{
|
||||||
|
// Create a cam marker on the canvas map...
|
||||||
CreateCameraMarker(new Point(cnvMap.Width * cam.X, cnvMap.Height * cam.Y), cam);
|
CreateCameraMarker(new Point(cnvMap.Width * cam.X, cnvMap.Height * cam.Y), cam);
|
||||||
|
|
||||||
|
// ...and create a correspondig list item...
|
||||||
ListBoxItem item = new ListBoxItem
|
ListBoxItem item = new ListBoxItem
|
||||||
{
|
{
|
||||||
Tag = cam,
|
Tag = cam,
|
||||||
|
|
@ -144,6 +181,7 @@ namespace FrontEnd
|
||||||
};
|
};
|
||||||
lstDevices.Items.Add(item);
|
lstDevices.Items.Add(item);
|
||||||
|
|
||||||
|
// ...with associated clients as subitems.
|
||||||
foreach (var client in clients.Where(c => c.Id == cam.Client_Id))
|
foreach (var client in clients.Where(c => c.Id == cam.Client_Id))
|
||||||
{
|
{
|
||||||
ListBoxItem subitem = new ListBoxItem
|
ListBoxItem subitem = new ListBoxItem
|
||||||
|
|
@ -158,6 +196,7 @@ namespace FrontEnd
|
||||||
|
|
||||||
private void LstDevices_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
private void LstDevices_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
|
// Show device properties in textbox.
|
||||||
var selectedItem = lstDevices.SelectedItem as ListBoxItem;
|
var selectedItem = lstDevices.SelectedItem as ListBoxItem;
|
||||||
if (selectedItem != null)
|
if (selectedItem != null)
|
||||||
{
|
{
|
||||||
|
|
@ -174,6 +213,7 @@ namespace FrontEnd
|
||||||
|
|
||||||
private void BtnRefresh_Click(object sender, RoutedEventArgs e)
|
private void BtnRefresh_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
// Reload information on button click.
|
||||||
LoadInformation();
|
LoadInformation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:FrontEnd"
|
xmlns:local="clr-namespace:FrontEnd"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="StreamWindow" Height="450" Width="800" Loaded="Window_Loaded">
|
Title="Stream" Height="450" Width="800" Loaded="Window_Loaded">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Image x:Name="imgStream" HorizontalAlignment="Left" Height="399" Margin="10,10,0,0" VerticalAlignment="Top" Width="772"/>
|
<Image x:Name="imgStream" HorizontalAlignment="Left" Height="399" Margin="10,10,0,0" VerticalAlignment="Top" Width="772"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ namespace FrontEnd
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public StreamWindow(Cam cam, bool processed) : this()
|
public StreamWindow(Cam cam, bool processed) : this()
|
||||||
{
|
{
|
||||||
_cam = cam;
|
_cam = cam;
|
||||||
|
|
@ -35,8 +34,10 @@ namespace FrontEnd
|
||||||
|
|
||||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
// Check if we want the original or processed stream.
|
||||||
string steamAddr = _processed ? Communicator.GetProcessedCameraAddress(_cam) : _cam.Ip;
|
string steamAddr = _processed ? Communicator.GetProcessedCameraAddress(_cam) : _cam.Ip;
|
||||||
|
|
||||||
|
// // retrieve single image
|
||||||
//if (_processed)
|
//if (_processed)
|
||||||
//{
|
//{
|
||||||
// _ = Task.Run(async () =>
|
// _ = Task.Run(async () =>
|
||||||
|
|
@ -47,6 +48,7 @@ namespace FrontEnd
|
||||||
//}
|
//}
|
||||||
//else
|
//else
|
||||||
|
|
||||||
|
// Show stream in image control.
|
||||||
_ = SimpleMJPEGDecoder.StartAsync((BitmapImage img) =>
|
_ = SimpleMJPEGDecoder.StartAsync((BitmapImage img) =>
|
||||||
{
|
{
|
||||||
imgStream.Dispatcher.Invoke(() => { imgStream.Source = img; });
|
imgStream.Dispatcher.Invoke(() => { imgStream.Source = img; });
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue