Fixing plots, now they scale properly
This commit is contained in:
parent
05c7d4710c
commit
8adac8b915
5 changed files with 454 additions and 46 deletions
|
@ -31,23 +31,21 @@
|
||||||
<of:OverlayImage x:Name="video" />
|
<of:OverlayImage x:Name="video" />
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<local:AxesBorder NumVertGrid="7" MinVal="-1" MaxVal="1" MinHeight="180" Grid.Row="4" Grid.Column="0" Padding="60 20 30 40" RangeLabel="Head pose" Orientation="Horizontal">
|
<local:AxesTimeSeriesPlot NumVertGrid="5" x:Name="headPosePlot" ShowLegend="True" MinVal="-1" MaxVal="1" MinHeight="180" Grid.Row="4" Grid.Column="0" Padding="60 20 30 40" RangeLabel="Head pose" Orientation="Horizontal">
|
||||||
<local:TimeSeriesPlot ShowLegend="True" x:Name="headPosePlot" Orientation="Horizontal"/>
|
</local:AxesTimeSeriesPlot>
|
||||||
</local:AxesBorder>
|
|
||||||
|
|
||||||
<local:AxesBorder MinHeight="180" Grid.Row="4" Grid.Column="1" Padding="60 20 30 40" RangeLabel="Eye gaze" Orientation="Horizontal" MinVal="-1" MaxVal="1" NumVertGrid="5">
|
<local:AxesTimeSeriesPlot MinHeight="180" Grid.Row="4" Grid.Column="1" Padding="60 20 30 40" x:Name="gazePlot" ShowLegend="True" RangeLabel="Eye gaze" Orientation="Horizontal" MinVal="-1" MaxVal="1" NumVertGrid="5">
|
||||||
<local:TimeSeriesPlot x:Name="gazePlot" Orientation="Horizontal" ShowLegend="True"/>
|
</local:AxesTimeSeriesPlot>
|
||||||
</local:AxesBorder>
|
|
||||||
|
<local:AxesTimeSeriesPlot Grid.Column="2" Grid.Row="1" MinHeight="130" ShowXLabel="False" Padding="60 20 30 10" x:Name="smilePlot" ShowLegend="True" XTicks="False" RangeLabel="Lips" Orientation="Horizontal" MinVal="0" MaxVal="1" NumVertGrid="5">
|
||||||
|
</local:AxesTimeSeriesPlot>
|
||||||
|
|
||||||
|
<local:AxesTimeSeriesPlot Grid.Column="2" Grid.Row="2" MinHeight="130" ShowXLabel="False" Padding="60 20 30 10" x:Name="browPlot" ShowLegend="True" XTicks="False" RangeLabel="Brows" Orientation="Horizontal" MinVal="0" MaxVal="1" NumVertGrid="5">
|
||||||
|
</local:AxesTimeSeriesPlot>
|
||||||
|
|
||||||
|
<local:AxesTimeSeriesPlot Grid.Column="2" Grid.Row="3" MinHeight="130" ShowXLabel="False" x:Name="eyePlot" ShowLegend="True" Padding="60 20 30 10" XTicks="False" RangeLabel="Other" Orientation="Horizontal" MinVal="0" MaxVal="1" NumVertGrid="5">
|
||||||
|
</local:AxesTimeSeriesPlot>
|
||||||
|
|
||||||
<local:AxesBorder Grid.Column="2" Grid.Row="1" MinHeight="130" ShowXLabel="False" Padding="60 20 30 10" XTicks="False" RangeLabel="Lips" Orientation="Horizontal" MinVal="0" MaxVal="1" NumVertGrid="5">
|
|
||||||
<local:TimeSeriesPlot x:Name="smilePlot" Orientation="Horizontal" ShowLegend="True"/>
|
|
||||||
</local:AxesBorder>
|
|
||||||
<local:AxesBorder Grid.Column="2" Grid.Row="2" MinHeight="130" ShowXLabel="False" Padding="60 20 30 10" XTicks="False" RangeLabel="Brows" Orientation="Horizontal" MinVal="0" MaxVal="1" NumVertGrid="5">
|
|
||||||
<local:TimeSeriesPlot x:Name="browPlot" Orientation="Horizontal" ShowLegend="True"/>
|
|
||||||
</local:AxesBorder>
|
|
||||||
<local:AxesBorder Grid.Column="2" Grid.Row="3" MinHeight="130" ShowXLabel="False" Padding="60 20 30 10" XTicks="False" RangeLabel="Other" Orientation="Horizontal" MinVal="0" MaxVal="1" NumVertGrid="5">
|
|
||||||
<local:TimeSeriesPlot x:Name="eyePlot" Orientation="Horizontal" ShowLegend="True"/>
|
|
||||||
</local:AxesBorder>
|
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
|
|
|
@ -268,8 +268,14 @@ namespace OpenFaceDemo
|
||||||
List<Tuple<double, double>> landmarks = null;
|
List<Tuple<double, double>> landmarks = null;
|
||||||
List<Tuple<Point, Point>> gaze_lines = null;
|
List<Tuple<Point, Point>> gaze_lines = null;
|
||||||
var gaze = face_analyser.GetGazeCamera();
|
var gaze = face_analyser.GetGazeCamera();
|
||||||
double x_gaze = (gaze.Item1.Item1 + gaze.Item2.Item1) / 2.0;
|
|
||||||
double y_gaze = (gaze.Item1.Item2 + gaze.Item2.Item2) / 2.0;
|
// Get the rough gaze angle
|
||||||
|
double x_gaze = (Math.Atan2(gaze.Item1.Item1, -gaze.Item1.Item3) + Math.Atan2(gaze.Item2.Item1, -gaze.Item2.Item3))/2.0;
|
||||||
|
double y_gaze = (Math.Atan2(gaze.Item1.Item2, -gaze.Item1.Item3) + Math.Atan2(gaze.Item2.Item2, -gaze.Item2.Item3)) / 2.0;
|
||||||
|
|
||||||
|
// Scaling for clearer vis.
|
||||||
|
x_gaze *= 2;
|
||||||
|
y_gaze *= 2;
|
||||||
|
|
||||||
if (detectionSucceeding)
|
if (detectionSucceeding)
|
||||||
{
|
{
|
||||||
|
@ -284,29 +290,29 @@ namespace OpenFaceDemo
|
||||||
|
|
||||||
var au_regs = face_analyser.GetCurrentAUsReg();
|
var au_regs = face_analyser.GetCurrentAUsReg();
|
||||||
|
|
||||||
double smile = (au_regs["AU12"] + au_regs["AU06"]) / 7.5 + 0.05;
|
double smile = (au_regs["AU12"] + au_regs["AU06"] + au_regs["AU25"]) / 13.0;
|
||||||
double frown = (au_regs["AU15"] + au_regs["AU17"] + au_regs["AU04"]) / 10.0 + 0.05;
|
double frown = (au_regs["AU15"] + au_regs["AU17"]) / 12.0;
|
||||||
|
|
||||||
double brow_up = (au_regs["AU01"] + au_regs["AU02"]) / 7.5 + 0.05;
|
double brow_up = (au_regs["AU01"] + au_regs["AU02"]) / 10.0;
|
||||||
double brow_down = au_regs["AU04"] / 5.0 + 0.05;
|
double brow_down = au_regs["AU04"] / 5.0;
|
||||||
|
|
||||||
double eye_widen = au_regs["AU05"] / 2.5 + 0.05;
|
double eye_widen = au_regs["AU05"] / 3.0;
|
||||||
double nose_wrinkle = au_regs["AU09"] / 4.0 + 0.05;
|
double nose_wrinkle = au_regs["AU09"] / 4.0;
|
||||||
|
|
||||||
Dictionary<int, double> smileDict = new Dictionary<int, double>();
|
Dictionary<int, double> smileDict = new Dictionary<int, double>();
|
||||||
smileDict[0] = 0.6 * smile_cumm + 0.4 * smile;
|
smileDict[0] = 0.7 * smile_cumm + 0.3 * smile;
|
||||||
smileDict[1] = 0.6 * frown_cumm + 0.4 * frown;
|
smileDict[1] = 0.7 * frown_cumm + 0.3 * frown;
|
||||||
smilePlot.AddDataPoint(new DataPoint() { Time = CurrentTime, values = smileDict, Confidence = confidence });
|
smilePlot.AddDataPoint(new DataPointGraph() { Time = CurrentTime, values = smileDict, Confidence = confidence });
|
||||||
|
|
||||||
Dictionary<int, double> browDict = new Dictionary<int, double>();
|
Dictionary<int, double> browDict = new Dictionary<int, double>();
|
||||||
browDict[0] = 0.5 * brow_up_cumm + 0.5 * brow_up;
|
browDict[0] = 0.7 * brow_up_cumm + 0.3 * brow_up;
|
||||||
browDict[1] = 0.5 * brow_down_cumm + 0.5 * brow_down;
|
browDict[1] = 0.7 * brow_down_cumm + 0.3 * brow_down;
|
||||||
browPlot.AddDataPoint(new DataPoint() { Time = CurrentTime, values = browDict, Confidence = confidence });
|
browPlot.AddDataPoint(new DataPointGraph() { Time = CurrentTime, values = browDict, Confidence = confidence });
|
||||||
|
|
||||||
Dictionary<int, double> eyeDict = new Dictionary<int, double>();
|
Dictionary<int, double> eyeDict = new Dictionary<int, double>();
|
||||||
eyeDict[0] = 0.7 * widen_cumm + 0.3 * eye_widen;
|
eyeDict[0] = 0.7 * widen_cumm + 0.3 * eye_widen;
|
||||||
eyeDict[1] = 0.7 * wrinkle_cumm + 0.3 * nose_wrinkle;
|
eyeDict[1] = 0.7 * wrinkle_cumm + 0.3 * nose_wrinkle;
|
||||||
eyePlot.AddDataPoint(new DataPoint() { Time = CurrentTime, values = eyeDict, Confidence = confidence });
|
eyePlot.AddDataPoint(new DataPointGraph() { Time = CurrentTime, values = eyeDict, Confidence = confidence });
|
||||||
|
|
||||||
smile_cumm = smileDict[0];
|
smile_cumm = smileDict[0];
|
||||||
frown_cumm = smileDict[1];
|
frown_cumm = smileDict[1];
|
||||||
|
@ -316,22 +322,20 @@ namespace OpenFaceDemo
|
||||||
wrinkle_cumm = eyeDict[1];
|
wrinkle_cumm = eyeDict[1];
|
||||||
|
|
||||||
Dictionary<int, double> poseDict = new Dictionary<int, double>();
|
Dictionary<int, double> poseDict = new Dictionary<int, double>();
|
||||||
poseDict[0] = -pose[3] / 2.0 + 0.5;// (face_analyser.GetRapport() - 1.0) / 6.5;
|
poseDict[0] = -pose[3];
|
||||||
poseDict[1] = pose[4] / 2.0 + 0.5;// (rapport_fixed - 1.0) / 6.0;
|
poseDict[1] = pose[4];
|
||||||
poseDict[2] = pose[5] / 2.0 + 0.5;
|
poseDict[2] = pose[5];
|
||||||
headPosePlot.AddDataPoint(new DataPoint() { Time = CurrentTime, values = poseDict, Confidence = confidence });
|
headPosePlot.AddDataPoint(new DataPointGraph() { Time = CurrentTime, values = poseDict, Confidence = confidence });
|
||||||
|
|
||||||
Dictionary<int, double> gazeDict = new Dictionary<int, double>();
|
Dictionary<int, double> gazeDict = new Dictionary<int, double>();
|
||||||
gazeDict[0] = x_gaze * 2.5;
|
gazeDict[0] = x_gaze;
|
||||||
gazeDict[0] = 0.5 * old_gaze_x + 0.5 * gazeDict[0] + 0.5;
|
gazeDict[0] = 0.5 * old_gaze_x + 0.5 * gazeDict[0];
|
||||||
gazeDict[1] = -y_gaze * 2.0;
|
gazeDict[1] = -y_gaze;
|
||||||
gazeDict[1] = 0.5 * old_gaze_y + 0.5 * gazeDict[1] + 0.5;
|
gazeDict[1] = 0.5 * old_gaze_y + 0.5 * gazeDict[1];
|
||||||
//gazeDict[2] = face_analyser.GetEyeAttention();
|
gazePlot.AddDataPoint(new DataPointGraph() { Time = CurrentTime, values = gazeDict, Confidence = confidence });
|
||||||
//Console.WriteLine("{0}, {1}", x_gaze, y_gaze);
|
|
||||||
gazePlot.AddDataPoint(new DataPoint() { Time = CurrentTime, values = gazeDict, Confidence = confidence });
|
|
||||||
|
|
||||||
old_gaze_x = gazeDict[0] - 0.5;
|
old_gaze_x = gazeDict[0];
|
||||||
old_gaze_y = gazeDict[1] - 0.5;
|
old_gaze_y = gazeDict[1];
|
||||||
|
|
||||||
//Dictionary<int, double> valenceDict = new Dictionary<int, double>();
|
//Dictionary<int, double> valenceDict = new Dictionary<int, double>();
|
||||||
//valenceDict[0] = (face_analyser.GetValence() - 1.0) / 6.5;
|
//valenceDict[0] = (face_analyser.GetValence() - 1.0) / 6.5;
|
||||||
|
|
|
@ -79,6 +79,9 @@
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</ApplicationDefinition>
|
</ApplicationDefinition>
|
||||||
<Compile Include="UI_items\AxesBorder.cs" />
|
<Compile Include="UI_items\AxesBorder.cs" />
|
||||||
|
<Compile Include="UI_items\AxesTimeSeriesPlot.xaml.cs">
|
||||||
|
<DependentUpon>AxesTimeSeriesPlot.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="UI_items\CameraSelection.xaml.cs">
|
<Compile Include="UI_items\CameraSelection.xaml.cs">
|
||||||
<DependentUpon>CameraSelection.xaml</DependentUpon>
|
<DependentUpon>CameraSelection.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -97,6 +100,10 @@
|
||||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Page Include="UI_items\AxesTimeSeriesPlot.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
<Page Include="UI_items\CameraSelection.xaml">
|
<Page Include="UI_items\CameraSelection.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
|
8
gui/OpenFaceDemo/UI_items/AxesTimeSeriesPlot.xaml
Normal file
8
gui/OpenFaceDemo/UI_items/AxesTimeSeriesPlot.xaml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<UserControl x:Class="OpenFaceDemo.AxesTimeSeriesPlot"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="200" d:DesignWidth="900">
|
||||||
|
</UserControl>
|
391
gui/OpenFaceDemo/UI_items/AxesTimeSeriesPlot.xaml.cs
Normal file
391
gui/OpenFaceDemo/UI_items/AxesTimeSeriesPlot.xaml.cs
Normal file
|
@ -0,0 +1,391 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
|
||||||
|
namespace OpenFaceDemo
|
||||||
|
{
|
||||||
|
public class DataPointGraph
|
||||||
|
{
|
||||||
|
public DataPointGraph()
|
||||||
|
{
|
||||||
|
Time = TimeSeriesPlot.CurrentTime;
|
||||||
|
|
||||||
|
}
|
||||||
|
public DateTime Time { get; set; }
|
||||||
|
|
||||||
|
public Dictionary<int, double> values = new Dictionary<int, double>();
|
||||||
|
|
||||||
|
public double Confidence { get; set; }
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for AxesTimeSeriesPlot.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class AxesTimeSeriesPlot : UserControl
|
||||||
|
{
|
||||||
|
|
||||||
|
#region High-Resolution Timing
|
||||||
|
static DateTime startTime;
|
||||||
|
static Stopwatch sw = new Stopwatch();
|
||||||
|
|
||||||
|
public double MinVal { get; set; }
|
||||||
|
public double MaxVal { get; set; }
|
||||||
|
public int NumVertGrid { get; set; }
|
||||||
|
|
||||||
|
public bool ShowXLabel { get; set; }
|
||||||
|
public bool ShowYLabel { get; set; }
|
||||||
|
|
||||||
|
public string RangeLabel { get; set; }
|
||||||
|
|
||||||
|
public bool XTicks { get; set; }
|
||||||
|
|
||||||
|
static AxesTimeSeriesPlot()
|
||||||
|
{
|
||||||
|
startTime = DateTime.Now;
|
||||||
|
sw.Start();
|
||||||
|
|
||||||
|
}
|
||||||
|
public static DateTime CurrentTime
|
||||||
|
{
|
||||||
|
get { return startTime + sw.Elapsed; }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
public Orientation Orientation { get; set; }
|
||||||
|
|
||||||
|
public bool ShowLegend { get; set; }
|
||||||
|
|
||||||
|
Queue<DataPointGraph> dataPoints = new Queue<DataPointGraph>();
|
||||||
|
TimeSpan historyLength = TimeSpan.FromSeconds(10);
|
||||||
|
Dictionary<int, Brush> brushes = new Dictionary<int, Brush>();
|
||||||
|
Dictionary<int, int> brush_thicknesses = new Dictionary<int, int>();
|
||||||
|
Dictionary<int, String> line_names = new Dictionary<int, String>();
|
||||||
|
Dictionary<int, Color> brush_colors = new Dictionary<int, Color>();
|
||||||
|
|
||||||
|
// Knowing where to draw things
|
||||||
|
private double MinAxesX { get; set; }
|
||||||
|
private double MinAxesY { get; set; }
|
||||||
|
private double MaxAxesX { get; set; }
|
||||||
|
private double MaxAxesY { get; set; }
|
||||||
|
|
||||||
|
public AxesTimeSeriesPlot()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
ShowLegend = false;
|
||||||
|
ClipToBounds = true;
|
||||||
|
DispatcherTimer dt = new DispatcherTimer(TimeSpan.FromMilliseconds(20), DispatcherPriority.Background, Timer_Tick, Dispatcher);
|
||||||
|
|
||||||
|
MinVal = -1;
|
||||||
|
MaxVal = 1;
|
||||||
|
NumVertGrid = 5;
|
||||||
|
ShowXLabel = true;
|
||||||
|
ShowYLabel = true;
|
||||||
|
XTicks = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PruneData()
|
||||||
|
{
|
||||||
|
lock (dataPoints)
|
||||||
|
{
|
||||||
|
while (dataPoints.Count > 0 && dataPoints.Peek().Time < CurrentTime - historyLength - TimeSpan.FromSeconds(2))
|
||||||
|
dataPoints.Dequeue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddDataPoint(DataPointGraph dp)
|
||||||
|
{
|
||||||
|
lock (dataPoints)
|
||||||
|
dataPoints.Enqueue(dp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Timer_Tick(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
PruneData();
|
||||||
|
|
||||||
|
if (this.IsVisible)
|
||||||
|
InvalidateVisual();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AssocColor(int seriesId, Color b)
|
||||||
|
{
|
||||||
|
Color bTransparent = b;
|
||||||
|
bTransparent.A = 0;
|
||||||
|
|
||||||
|
GradientStopCollection gs = new GradientStopCollection();
|
||||||
|
gs.Add(new GradientStop(bTransparent, 0));
|
||||||
|
gs.Add(new GradientStop(b, 0.2));
|
||||||
|
LinearGradientBrush g = new LinearGradientBrush(gs, new Point(0, 0), Orientation == System.Windows.Controls.Orientation.Horizontal ? new Point(ActualWidth, 0) : new Point(0, ActualHeight));
|
||||||
|
g.MappingMode = BrushMappingMode.Absolute;
|
||||||
|
g.Freeze();
|
||||||
|
brushes[seriesId] = g;
|
||||||
|
|
||||||
|
brush_colors[seriesId] = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AssocThickness(int seriesId, int thickness)
|
||||||
|
{
|
||||||
|
brush_thicknesses[seriesId] = thickness;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AssocName(int seriesId, String name)
|
||||||
|
{
|
||||||
|
line_names[seriesId] = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnRender(DrawingContext dc)
|
||||||
|
{
|
||||||
|
base.OnRender(dc);
|
||||||
|
|
||||||
|
if (Orientation == System.Windows.Controls.Orientation.Horizontal)
|
||||||
|
RenderHorizontal(dc);
|
||||||
|
else
|
||||||
|
RenderVertical(dc);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grid rendering
|
||||||
|
private void RenderHorizontal(DrawingContext dc)
|
||||||
|
{
|
||||||
|
Pen p = new Pen(Brushes.Black, 1);
|
||||||
|
Pen q = new Pen(Brushes.LightGray, 1);
|
||||||
|
|
||||||
|
double padLeft = Padding.Left;
|
||||||
|
double padBottom = Padding.Bottom - 2 + 10;
|
||||||
|
double padTop = Padding.Top;
|
||||||
|
double padRight = Padding.Right;
|
||||||
|
|
||||||
|
// Draw horizontal gridlines
|
||||||
|
|
||||||
|
double step_size = (MaxVal - MinVal) / (NumVertGrid - 1.0);
|
||||||
|
|
||||||
|
for (int i = 0; i < NumVertGrid; i++)
|
||||||
|
{
|
||||||
|
double y = (int)(padTop + ((NumVertGrid - 1.0) - i) * ((ActualHeight - padBottom - padTop) / (NumVertGrid - 1.0))) - 0.5;
|
||||||
|
|
||||||
|
|
||||||
|
double y_val = MinVal + i * step_size;
|
||||||
|
|
||||||
|
if (y_val != 0)
|
||||||
|
dc.DrawLine(q, new Point(padLeft, y), new Point(ActualWidth - padRight, y));
|
||||||
|
else
|
||||||
|
dc.DrawLine(p, new Point(padLeft, y), new Point(ActualWidth - padRight, y));
|
||||||
|
|
||||||
|
dc.DrawLine(p, new Point(padLeft - 10, y), new Point(padLeft, y));
|
||||||
|
|
||||||
|
var t = FormT((MinVal + i * step_size).ToString("0.0"), 10);
|
||||||
|
dc.DrawText(t, new Point(padLeft - t.Width - 12, y - t.Height / 2));
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
MinAxesY = y;
|
||||||
|
if (i == NumVertGrid - 1)
|
||||||
|
MaxAxesY = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw vertical gridlines
|
||||||
|
|
||||||
|
for (int i = 0; i < 11; i++)
|
||||||
|
{
|
||||||
|
double x = (int)(padLeft + (10 - i) * ((ActualWidth - padLeft - padRight) / 10.0)) - 0.5;
|
||||||
|
if (i < 10)
|
||||||
|
dc.DrawLine(q, new Point(x, ActualHeight - padBottom), new Point(x, padTop));
|
||||||
|
dc.DrawLine(p, new Point(x, ActualHeight - padBottom + 10), new Point(x, ActualHeight - padBottom));
|
||||||
|
|
||||||
|
if (XTicks)
|
||||||
|
{
|
||||||
|
var t = FormT(i.ToString(), 10);
|
||||||
|
dc.DrawText(t, new Point(x - t.Width / 2, ActualHeight - padBottom + t.Height));
|
||||||
|
}
|
||||||
|
if (i == 0)
|
||||||
|
MaxAxesX = x;
|
||||||
|
if (i == (11 - 1))
|
||||||
|
MinAxesX = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw y axis
|
||||||
|
dc.DrawLine(p, new Point(((int)padLeft) - 0.5, padTop), new Point(((int)padLeft) - 0.5, ActualHeight - padBottom));
|
||||||
|
|
||||||
|
//dc.DrawLine(p, new Point(MinAxesX, MinAxesY), new Point(MaxAxesX, MaxAxesY));
|
||||||
|
//dc.DrawLine(p, new Point(MaxAxesX, padTop), new Point(MaxAxesX, ActualHeight - padBottom));
|
||||||
|
|
||||||
|
// Draw x axis label
|
||||||
|
if (ShowXLabel)
|
||||||
|
{
|
||||||
|
FormattedText ft = FormT("History (seconds)", 20);
|
||||||
|
dc.DrawText(ft, new Point(padLeft + (ActualWidth - padLeft - padRight) / 2 - ft.Width / 2, ActualHeight - ft.Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw y axis label
|
||||||
|
if (ShowYLabel)
|
||||||
|
{
|
||||||
|
FormattedText ft = FormT(RangeLabel, 20);
|
||||||
|
dc.PushTransform(new RotateTransform(-90));
|
||||||
|
dc.DrawText(ft, new Point(-ft.Width - ActualHeight / 2 + ft.Width / 2, 0));
|
||||||
|
dc.Pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
DataPointGraph[] localPoints;
|
||||||
|
lock (dataPoints)
|
||||||
|
localPoints = dataPoints.ToArray();
|
||||||
|
|
||||||
|
var pfs = new Dictionary<int, PathFigure>();
|
||||||
|
|
||||||
|
for (int i = 0; i < localPoints.Length; i++)
|
||||||
|
{
|
||||||
|
var ptTime = localPoints[i].Time;
|
||||||
|
var ptAge = (DateTime.Now - ptTime).TotalSeconds;
|
||||||
|
|
||||||
|
foreach (var kvp in localPoints[i].values)
|
||||||
|
{
|
||||||
|
var seriesId = kvp.Key;
|
||||||
|
|
||||||
|
double v = (kvp.Value - MinVal) / (MaxVal - MinVal);
|
||||||
|
|
||||||
|
// X starts here MinAxesX
|
||||||
|
// X ends here MaxAxesX
|
||||||
|
|
||||||
|
double y = MinAxesY - (MinAxesY - MaxAxesY) * v;
|
||||||
|
double x = MaxAxesX - (CurrentTime - localPoints[i].Time).TotalMilliseconds * ((MaxAxesX-MinAxesX) / historyLength.TotalMilliseconds);
|
||||||
|
|
||||||
|
// Make sure everything is within bounds
|
||||||
|
if (x < MinAxesX)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
y = Math.Min(MinAxesY, Math.Max(MaxAxesY, y));
|
||||||
|
|
||||||
|
if (!pfs.ContainsKey(seriesId))
|
||||||
|
{
|
||||||
|
pfs[seriesId] = new PathFigure();
|
||||||
|
pfs[seriesId].IsClosed = false;
|
||||||
|
pfs[seriesId].StartPoint = new Point(x, y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pfs[seriesId].Segments.Add(new LineSegment(new Point(x, y), true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var kvp in pfs)
|
||||||
|
{
|
||||||
|
var seriesId = kvp.Key;
|
||||||
|
var pf = kvp.Value;
|
||||||
|
|
||||||
|
Brush b = brushes.ContainsKey(seriesId) ? brushes[seriesId] : Brushes.Black;
|
||||||
|
|
||||||
|
int thickness = brush_thicknesses.ContainsKey(seriesId) ? brush_thicknesses[seriesId] : 2;
|
||||||
|
|
||||||
|
PathGeometry pg = new PathGeometry(new PathFigure[] { pf });
|
||||||
|
|
||||||
|
Pen p2 = new Pen(b, thickness);
|
||||||
|
|
||||||
|
dc.DrawGeometry(null, p2, pg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ShowLegend && line_names.Count > 0)
|
||||||
|
{
|
||||||
|
int height_one = 18;
|
||||||
|
int height = height_one * line_names.Count;
|
||||||
|
|
||||||
|
Pen p2 = new Pen(Brushes.Black, 1);
|
||||||
|
Brush legend_b = new SolidColorBrush(Color.FromRgb(255, 255, 255));
|
||||||
|
|
||||||
|
dc.DrawRectangle(legend_b, p2, new Rect(MinAxesX, MaxAxesY, 100, height));
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
foreach (var key_name_pair in line_names)
|
||||||
|
{
|
||||||
|
var line_name = key_name_pair.Value;
|
||||||
|
FormattedText ft = FormT(line_name, 11);
|
||||||
|
|
||||||
|
// Draw the text
|
||||||
|
dc.DrawText(ft, new Point(MinAxesX + 15, MaxAxesY + 1 + height_one * i));
|
||||||
|
// Draw example lines
|
||||||
|
|
||||||
|
Brush legend_c = new SolidColorBrush(brush_colors[key_name_pair.Key]);
|
||||||
|
Pen p_line = new Pen(legend_c, brush_thicknesses[key_name_pair.Key]);
|
||||||
|
dc.DrawLine(p_line, new Point(MinAxesX, MaxAxesY + height_one * i - 1 + height_one / 2), new Point(MinAxesX + 14, MaxAxesY -1 + height_one * i + height_one / 2));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenderVertical(DrawingContext dc)
|
||||||
|
{
|
||||||
|
Pen p = new Pen(Brushes.Black, 1);
|
||||||
|
Pen q = new Pen(Brushes.LightGray, 1);
|
||||||
|
|
||||||
|
double padLeft = Padding.Left;
|
||||||
|
double padBottom = Padding.Bottom - 2 + 10;
|
||||||
|
double padTop = Padding.Top;
|
||||||
|
double padRight = Padding.Right;
|
||||||
|
|
||||||
|
// Draw horizontal gridlines
|
||||||
|
|
||||||
|
for (int i = 0; i < 11; i++)
|
||||||
|
{
|
||||||
|
double y = (int)(padTop + (10 - i) * ((ActualHeight - padBottom - padTop) / 10.0)) - 0.5;
|
||||||
|
if (i > 0)
|
||||||
|
dc.DrawLine(q, new Point(padLeft, y), new Point(ActualWidth - padRight, y));
|
||||||
|
dc.DrawLine(p, new Point(padLeft - 10, y), new Point(padLeft, y));
|
||||||
|
var t = FormT(i.ToString(), 10);
|
||||||
|
dc.DrawText(t, new Point(padLeft - t.Width - 12, y - t.Height / 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw vertical gridlines
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
double x = (int)(padLeft + (4 - i) * ((ActualWidth - padLeft - padRight) / 4.0)) - 0.5;
|
||||||
|
if (i < 10)
|
||||||
|
dc.DrawLine(q, new Point(x, ActualHeight - padBottom), new Point(x, padTop));
|
||||||
|
dc.DrawLine(p, new Point(x, ActualHeight - padBottom + 10), new Point(x, ActualHeight - padBottom));
|
||||||
|
|
||||||
|
var t = FormT(((4 - i) / 2.0 - 1).ToString("0.0"), 10);
|
||||||
|
dc.DrawText(t, new Point(x - t.Width / 2, ActualHeight - padBottom + t.Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw y axis
|
||||||
|
|
||||||
|
dc.DrawLine(p, new Point(((int)((ActualWidth - padRight - padLeft) / 2 + padLeft)) - 0.5, padTop), new Point(((int)((ActualWidth - padRight - padLeft) / 2 + padLeft)) - 0.5, ActualHeight - padBottom));
|
||||||
|
|
||||||
|
// Draw x axis
|
||||||
|
dc.DrawLine(p, new Point(padLeft, ((int)((ActualHeight - padBottom))) - 0.5), new Point(ActualWidth - padRight, ((int)((ActualHeight - padBottom))) - 0.5));
|
||||||
|
|
||||||
|
// Draw x axis label
|
||||||
|
|
||||||
|
FormattedText ft = FormT(RangeLabel, 20);
|
||||||
|
dc.DrawText(ft, new Point(padLeft + (ActualWidth - padLeft - padRight) / 2 - ft.Width / 2, ActualHeight - ft.Height));
|
||||||
|
|
||||||
|
// Draw y axis label
|
||||||
|
|
||||||
|
ft = FormT("History (seconds)", 20);
|
||||||
|
dc.PushTransform(new RotateTransform(-90));
|
||||||
|
dc.DrawText(ft, new Point(-ft.Width - ActualHeight / 2 + ft.Width / 2, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private FormattedText FormT(string text, int size)
|
||||||
|
{
|
||||||
|
return new FormattedText(text, CultureInfo.CurrentCulture, System.Windows.FlowDirection.LeftToRight, new Typeface("Verdana"), size, Brushes.Black);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue