990 lines
No EOL
37 KiB
C#
990 lines
No EOL
37 KiB
C#
using System;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Windows.Forms;
|
|
using System.IO;
|
|
using System.Xml.Linq;
|
|
using System.Collections.Generic;
|
|
using System.Drawing.Drawing2D;
|
|
|
|
namespace PleoLab
|
|
{
|
|
public partial class PleoLabForm : Form
|
|
{
|
|
#region GENERAL
|
|
string m_currentDragFilePath = "";
|
|
|
|
private const int m_drawEllipseSize = 10;
|
|
private const int m_curvePenSize = 2;
|
|
private const int m_starvePenSize = 5;
|
|
private const int EDITOR_INDEX = 0;
|
|
private const int REPORT_INDEX = 1;
|
|
|
|
public PleoLabForm()
|
|
{
|
|
InitializeComponent();
|
|
|
|
InitEditor();
|
|
InitReport();
|
|
}
|
|
|
|
private void StartSimulationMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
StartSimulationForm infos = new StartSimulationForm(
|
|
new Point(Left + Width / 2, Top + Height / 2));
|
|
|
|
infos.Show(this);
|
|
}
|
|
|
|
private void HelpMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
ToolHelpForm form = new ToolHelpForm(
|
|
new Point(Left + Width / 2, Top + Height / 2));
|
|
form.Show();
|
|
}
|
|
|
|
private void PopupMessage(string _header, string _message)
|
|
{
|
|
MessageBox.Show(_message, _header, MessageBoxButtons.OK);
|
|
}
|
|
|
|
private void PleoSimulatorTool_FormClosing(object sender, FormClosingEventArgs e)
|
|
{
|
|
if (m_editorFileNeedsSaving)
|
|
{
|
|
DialogResult msgBoxResult = EditorAskForSave();
|
|
if (msgBoxResult == DialogResult.Yes)
|
|
{
|
|
EditorSave();
|
|
}
|
|
else if (msgBoxResult == DialogResult.Cancel)
|
|
{
|
|
e.Cancel = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void PleoSimulatorToolForm_DragEnter(object sender, DragEventArgs e)
|
|
{
|
|
string[] FileList = (string[])e.Data.GetData(DataFormats.FileDrop, false);
|
|
if (FileList.Count() == 1 && Path.GetExtension(FileList.First()) == ".xml")
|
|
{
|
|
m_currentDragFilePath = FileList.First();
|
|
e.Effect = DragDropEffects.Move;
|
|
}
|
|
else
|
|
{
|
|
m_currentDragFilePath = "";
|
|
e.Effect = DragDropEffects.None;
|
|
}
|
|
}
|
|
|
|
private void PleoSimulatorToolForm_DragDrop(object sender, DragEventArgs e)
|
|
{
|
|
if (m_currentDragFilePath != "")
|
|
{
|
|
XDocument doc = XDocument.Load(m_currentDragFilePath);
|
|
XElement simulationElem = doc.Element("Simulation");
|
|
|
|
if (doc.Element("Simulation") != null)
|
|
{
|
|
SimulationReadFile(m_currentDragFilePath);
|
|
}
|
|
else if(doc.Element("BandwidthCurves") != null)
|
|
{
|
|
if (m_editorFileNeedsSaving)
|
|
{
|
|
DialogResult msgBoxResult = EditorAskForSave();
|
|
if (msgBoxResult == DialogResult.Yes)
|
|
{
|
|
EditorSave();
|
|
}
|
|
else if (msgBoxResult == DialogResult.Cancel)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
EditorReadFile(m_currentDragFilePath);
|
|
}
|
|
}
|
|
}
|
|
private void DrawGrid(PaintEventArgs e, double _width, double _height)
|
|
{
|
|
double cellCount = 20.0;
|
|
double cellSizeX = _width / cellCount;
|
|
double cellSizeY = _height / cellCount;
|
|
Pen pen2 = new Pen(Color.FromArgb(50, 0, 0, 0), 1)
|
|
{
|
|
Alignment = PenAlignment.Center
|
|
};
|
|
for (int y = 0; y <= cellCount; ++y)
|
|
{
|
|
e.Graphics.DrawLine(pen2, 0, (int)(y * cellSizeY), (int)(cellCount * cellSizeX), (int)(y * cellSizeY));
|
|
}
|
|
|
|
for (int x = 0; x <= cellCount; ++x)
|
|
{
|
|
e.Graphics.DrawLine(pen2, (int)(x * cellSizeX), 0, (int)(x * cellSizeX), (int)(cellCount * cellSizeY));
|
|
}
|
|
}
|
|
|
|
private string GetMouseLocationString(double posX, double posY, double maxX, double maxY)
|
|
{
|
|
double percentageX = posX / maxX * 100.0;
|
|
double percentageY = (maxY - posY) / maxY * 100.0;
|
|
return "(" + Math.Round(percentageX, 2) + ", " + Math.Round(percentageY, 2) + ")";
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region EDITOR VARIABLES
|
|
private int m_editorDrawAreaWidth;
|
|
private int m_editorDrawAreaHeight;
|
|
private CurveSet m_editorCurveSet = new CurveSet();
|
|
private string m_editorCurrentCurveName = "";
|
|
private Curve m_editorCurrentCurvePoints = new Curve();
|
|
private int m_editorCurrentPointIndex = -1;
|
|
private bool m_editorFileNeedsSaving = false;
|
|
|
|
#endregion
|
|
|
|
#region EDITOR FORM
|
|
|
|
private void EditorDrawArea_Paint(object sender, PaintEventArgs e)
|
|
{
|
|
base.OnPaint(e);
|
|
|
|
DrawGrid(e, m_editorDrawAreaWidth, m_editorDrawAreaHeight);
|
|
|
|
if (m_editorCurrentCurvePoints.Count > 0)
|
|
{
|
|
m_editorCurrentCurvePoints.Sort();
|
|
m_editorCurrentCurvePoints.RemoveAt(0);
|
|
m_editorCurrentCurvePoints.RemoveAt(m_editorCurrentCurvePoints.Count - 1);
|
|
|
|
if (m_editorCurrentCurvePoints.Count > 0)
|
|
{
|
|
m_editorCurrentCurvePoints.Insert(0, new Point(0, m_editorCurrentCurvePoints[0].Y));
|
|
m_editorCurrentCurvePoints.Add(new Point(m_editorDrawAreaWidth, m_editorCurrentCurvePoints[m_editorCurrentCurvePoints.Count - 1].Y));
|
|
}
|
|
}
|
|
|
|
if (m_editorCurrentCurvePoints.Count > 0)
|
|
{
|
|
// draw lines
|
|
Pen pen = new Pen(Color.Black)
|
|
{
|
|
Width = m_curvePenSize,
|
|
Alignment = PenAlignment.Center
|
|
};
|
|
e.Graphics.DrawLines(pen, m_editorCurrentCurvePoints.ToArray());
|
|
|
|
// draw points
|
|
SolidBrush brush = new SolidBrush(Color.Red);
|
|
|
|
for (int i = 0; i < m_editorCurrentCurvePoints.Count; ++i)
|
|
{
|
|
brush.Color = (i == m_editorCurrentPointIndex) ?
|
|
Color.Red
|
|
: Color.Black;
|
|
|
|
e.Graphics.FillEllipse(
|
|
brush,
|
|
new Rectangle(
|
|
new Point(m_editorCurrentCurvePoints[i].X - m_drawEllipseSize / 2, m_editorCurrentCurvePoints[i].Y - m_drawEllipseSize / 2),
|
|
new Size(m_drawEllipseSize, m_drawEllipseSize)));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void EditorDrawArea_MouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
if (m_editorCurrentCurveName != "")
|
|
{
|
|
if (e.Button == MouseButtons.Right)
|
|
{
|
|
if (m_editorCurrentCurvePoints.Count > 0)
|
|
{
|
|
m_editorFileNeedsSaving = true;
|
|
Point clickPoint = new Point(e.X, e.Y);
|
|
int indexToRemove = m_editorCurrentCurvePoints.FindClosestPointIndex(clickPoint);
|
|
m_editorCurrentCurvePoints.RemoveAt(indexToRemove);
|
|
}
|
|
}
|
|
else if (e.Button == MouseButtons.Left && !ModifierKeys.HasFlag(Keys.Control))
|
|
{
|
|
m_editorFileNeedsSaving = true;
|
|
m_editorCurrentCurvePoints.Add(new Point(e.X, e.Y));
|
|
m_editorCurrentCurvePoints.PreventXDuplicates();
|
|
m_editorCurrentCurvePoints.Sort();
|
|
|
|
if (m_editorCurrentCurvePoints.Count == 1)
|
|
{
|
|
m_editorCurrentCurvePoints.Insert(0, new Point(0, m_editorCurrentCurvePoints.First().Y));
|
|
m_editorCurrentCurvePoints.Add(new Point(m_editorDrawAreaWidth, m_editorCurrentCurvePoints.Last().Y));
|
|
}
|
|
}
|
|
|
|
Refresh();
|
|
}
|
|
}
|
|
|
|
private void EditorDrawArea_MouseMove(object sender, MouseEventArgs e)
|
|
{
|
|
bool doRefresh = false;
|
|
|
|
editorMousePositionTextBox.Text = GetMouseLocationString(
|
|
(double)e.Location.X,
|
|
(double)e.Location.Y,
|
|
(double)m_editorDrawAreaWidth,
|
|
(double)m_editorDrawAreaHeight);
|
|
|
|
if (m_editorCurrentCurveName != "")
|
|
{
|
|
int lastIndex = m_editorCurrentPointIndex;
|
|
Point clickPoint = new Point(e.X, e.Y);
|
|
|
|
m_editorCurrentPointIndex = m_editorCurrentCurvePoints.FindClosestPointIndex(clickPoint);
|
|
|
|
// refresh if the user is moving a point
|
|
if (m_editorCurrentPointIndex > 0
|
|
&& m_editorCurrentPointIndex < m_editorCurrentCurvePoints.Count - 1
|
|
&& Control.MouseButtons == MouseButtons.Left && ModifierKeys.HasFlag(Keys.Control))
|
|
{
|
|
m_editorFileNeedsSaving = true;
|
|
m_editorCurrentCurvePoints[m_editorCurrentPointIndex] = clickPoint;
|
|
m_editorCurrentCurvePoints.PreventXDuplicates();
|
|
m_editorCurrentCurvePoints.Sort();
|
|
doRefresh = true;
|
|
}
|
|
|
|
// refresh if the closest point to the cursor has changed
|
|
if (lastIndex != m_editorCurrentPointIndex)
|
|
{
|
|
doRefresh = true;
|
|
}
|
|
}
|
|
|
|
if (doRefresh)
|
|
{
|
|
Refresh();
|
|
}
|
|
}
|
|
|
|
private void EditorDrawArea_MouseLeave(object sender, EventArgs e)
|
|
{
|
|
m_editorCurrentPointIndex = -1;
|
|
Refresh();
|
|
}
|
|
|
|
private void EditorDrawPanelEditor_Resize(object sender, EventArgs e)
|
|
{
|
|
Control control = sender as Control;
|
|
if (control.Height > 0 && control.Width > 0)
|
|
{
|
|
for (int i = 0; i < m_editorCurrentCurvePoints.Count; ++i)
|
|
{
|
|
int newX = (int)((double)m_editorCurrentCurvePoints[i].X / (double)m_editorDrawAreaWidth * (double)control.Width);
|
|
int newY = (int)((double)m_editorCurrentCurvePoints[i].Y / (double)m_editorDrawAreaHeight * (double)control.Height);
|
|
m_editorCurrentCurvePoints[i] = new Point(newX, newY);
|
|
}
|
|
|
|
m_editorDrawAreaWidth = control.Width;
|
|
m_editorDrawAreaHeight = control.Height;
|
|
Refresh();
|
|
}
|
|
}
|
|
|
|
private void EditorButtonNewCurve_Click(object sender, EventArgs e)
|
|
{
|
|
if (m_editorCurrentCurveName != "")
|
|
{
|
|
EditorUpdateCurveSet();
|
|
}
|
|
m_editorFileNeedsSaving = true;
|
|
m_editorCurrentCurvePoints = new Curve();
|
|
|
|
int newNameNumber = 1;
|
|
string newCurveNamePre = "New Curve";
|
|
string newCurveName = newCurveNamePre;
|
|
|
|
while (m_editorCurveSet.Curves.ContainsKey(newCurveName))
|
|
{
|
|
newCurveName = newCurveNamePre + " " + (++newNameNumber);
|
|
}
|
|
|
|
m_editorCurrentCurveName = newCurveName;
|
|
|
|
m_editorCurveSet.Curves.Add(m_editorCurrentCurveName, new List<Vector2>());
|
|
|
|
foreach (ListViewItem item in curvesListView.Items)
|
|
{
|
|
item.Selected = false;
|
|
}
|
|
ListViewItem newCurve = new ListViewItem()
|
|
{
|
|
Text = m_editorCurrentCurveName,
|
|
Selected = true
|
|
};
|
|
curvesListView.Items.Add(newCurve);
|
|
curvesListView.Select();
|
|
Refresh();
|
|
}
|
|
|
|
private void EditorClearButton_Click(object sender, EventArgs e)
|
|
{
|
|
m_editorFileNeedsSaving = true;
|
|
m_editorCurrentCurvePoints.Clear();
|
|
Refresh();
|
|
}
|
|
|
|
private void EditorDeleteCurveButton_Click(object sender, EventArgs e)
|
|
{
|
|
if (m_editorCurveSet.Curves.ContainsKey(m_editorCurrentCurveName))
|
|
{
|
|
m_editorFileNeedsSaving = true;
|
|
m_editorCurveSet.Curves.Remove(m_editorCurrentCurveName);
|
|
|
|
// it is necessary to save the current curve name to a temporary and setting it to "" before removing it from the curvesListView
|
|
// because the removal triggers a curvesListView selectedIndexChanged callback, which saves the current curve if it's name is not ""
|
|
string currentCurveName = m_editorCurrentCurveName;
|
|
m_editorCurrentCurveName = "";
|
|
m_editorCurrentCurvePoints.Clear();
|
|
curvesListView.Items.Remove(curvesListView.Items.OfType<ListViewItem>().FirstOrDefault(i => i.Text == currentCurveName));
|
|
|
|
if (curvesListView.Items.Count > 0)
|
|
{
|
|
curvesListView.Items[0].Selected = true;
|
|
curvesListView.Select();
|
|
}
|
|
Refresh();
|
|
}
|
|
}
|
|
|
|
private void EditorCurvesListBox_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
EditorUpdateCurveSet();
|
|
if (curvesListView.SelectedIndices.Count > 0)
|
|
{
|
|
m_editorCurrentCurveName = curvesListView.SelectedItems[0].Text;
|
|
m_editorCurrentCurvePoints = new Curve(m_editorCurveSet.Curves[m_editorCurrentCurveName], m_editorDrawAreaWidth, m_editorDrawAreaHeight);
|
|
|
|
Refresh();
|
|
}
|
|
}
|
|
|
|
private void EditorOpenMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
if (m_editorFileNeedsSaving)
|
|
{
|
|
DialogResult saveIsNeeded = EditorAskForSave();
|
|
if (saveIsNeeded == DialogResult.Yes)
|
|
{
|
|
EditorSave();
|
|
}
|
|
else if (saveIsNeeded == DialogResult.Cancel)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
|
{
|
|
EditorReadFile(openFileDialog.FileName);
|
|
m_editorFileNeedsSaving = false;
|
|
}
|
|
}
|
|
|
|
private void EditorSaveAsMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
EditorSave(true);
|
|
}
|
|
|
|
private void EditorSaveMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
EditorSave();
|
|
}
|
|
|
|
private void EditorCurvesListBox_KeyDown(object sender, KeyEventArgs e)
|
|
{
|
|
if (e.KeyData == Keys.F2 && curvesListView.SelectedItems.Count > 0)
|
|
{
|
|
curvesListView.SelectedItems[0].BeginEdit();
|
|
}
|
|
}
|
|
|
|
private void EditorCurvesListBox_MouseDoubleClick(object sender, MouseEventArgs e)
|
|
{
|
|
if (curvesListView.SelectedItems.Count > 0)
|
|
{
|
|
curvesListView.SelectedItems[0].BeginEdit();
|
|
}
|
|
}
|
|
|
|
private void EditorCurvesListBox_AfterLabelEdit(object sender, LabelEditEventArgs e)
|
|
{
|
|
if (e.Label == null || e.Label == "" || m_editorCurveSet.Curves.ContainsKey(e.Label.ToString()))
|
|
{
|
|
e.CancelEdit = true;
|
|
}
|
|
else
|
|
{
|
|
m_editorCurveSet.Curves.Remove(m_editorCurrentCurveName);
|
|
m_editorCurrentCurveName = e.Label.ToString();
|
|
m_editorCurveSet.Curves[m_editorCurrentCurveName] = m_editorCurrentCurvePoints.GetNormalizedCurve(m_editorDrawAreaWidth, m_editorDrawAreaHeight);
|
|
}
|
|
}
|
|
|
|
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
|
|
{
|
|
if (keyData == Keys.D1)
|
|
{
|
|
editorButtonNew.PerformClick();
|
|
return true;
|
|
}
|
|
if (keyData == Keys.D2)
|
|
{
|
|
editorButtonClear.PerformClick();
|
|
return true;
|
|
}
|
|
if (keyData == Keys.D3)
|
|
{
|
|
editorButtonDelete.PerformClick();
|
|
return true;
|
|
}
|
|
return base.ProcessCmdKey(ref msg, keyData);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region EDITOR UTILS
|
|
|
|
private void InitEditor()
|
|
{
|
|
m_editorDrawAreaWidth = drawPanelEditor.Width;
|
|
m_editorDrawAreaHeight = drawPanelEditor.Height;
|
|
labelFileName.Text = "";
|
|
}
|
|
|
|
private void EditorReadFile(string _filePath)
|
|
{
|
|
curvesListView.Items.Clear();
|
|
|
|
try
|
|
{
|
|
m_editorCurveSet.ReadFile(_filePath);
|
|
|
|
foreach (string name in m_editorCurveSet.Curves.Keys)
|
|
{
|
|
curvesListView.Items.Add(name);
|
|
}
|
|
|
|
labelFileName.Text = m_editorCurveSet.FileName;
|
|
if (m_editorCurveSet.Curves.Count > 0)
|
|
{
|
|
m_editorCurrentCurveName = m_editorCurveSet.Curves.First().Key;
|
|
m_editorCurrentCurvePoints = new Curve(m_editorCurveSet.Curves.First().Value, m_editorDrawAreaWidth, m_editorDrawAreaHeight);
|
|
curvesListView.Items.OfType<ListViewItem>().FirstOrDefault(i => i.Text == m_editorCurrentCurveName).Selected = true;
|
|
curvesListView.Select();
|
|
}
|
|
tabControlPleoLab.SelectedIndex = EDITOR_INDEX;
|
|
Refresh();
|
|
}
|
|
catch (FileNotFoundException exception)
|
|
{
|
|
PopupMessage("Error when opening the file", "Are you sure the path (" + exception.FileName + ") exists ?");
|
|
m_editorCurveSet.Curves.Clear();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
PopupMessage("Error while parsing the file", "Are you sure your xml file is in a valid format ?");
|
|
m_editorCurveSet.Curves.Clear();
|
|
}
|
|
}
|
|
|
|
private void EditorUpdateCurveSet()
|
|
{
|
|
if (m_editorCurrentCurveName != "")
|
|
{
|
|
m_editorCurrentCurvePoints.Sort();
|
|
m_editorCurveSet.Curves[m_editorCurrentCurveName] = m_editorCurrentCurvePoints.GetNormalizedCurve(m_editorDrawAreaWidth, m_editorDrawAreaHeight);
|
|
return;
|
|
}
|
|
}
|
|
|
|
private void EditorSave(bool _saveAs = false)
|
|
{
|
|
EditorUpdateCurveSet();
|
|
|
|
bool canSave = true;
|
|
if (m_editorCurveSet.Curves.Count == 0)
|
|
{
|
|
PopupMessage("Error !", "You need curves to save !");
|
|
canSave = false;
|
|
}
|
|
else if (m_editorCurveSet.Curves.Values.Any(pointList => pointList.Count == 0))
|
|
{
|
|
PopupMessage("Error !", "You cannot save a file with empty curves !");
|
|
canSave = false;
|
|
}
|
|
|
|
if (canSave)
|
|
{
|
|
// save as new file
|
|
if (m_editorCurveSet.FileName == "" || _saveAs)
|
|
{
|
|
canSave = CreateFile();
|
|
}
|
|
|
|
if (canSave)
|
|
{
|
|
m_editorCurveSet.WriteToFile();
|
|
m_editorFileNeedsSaving = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool CreateFile()
|
|
{
|
|
bool fileCreated = false;
|
|
|
|
saveFileDialog.Filter = "xml files (*.xml)|*.xml";
|
|
saveFileDialog.FilterIndex = 2;
|
|
saveFileDialog.RestoreDirectory = true;
|
|
|
|
if (saveFileDialog.ShowDialog() == DialogResult.OK)
|
|
{
|
|
m_editorCurveSet.CreateFile(saveFileDialog.FileName);
|
|
labelFileName.Text = m_editorCurveSet.FileName;
|
|
fileCreated = true;
|
|
}
|
|
return fileCreated;
|
|
}
|
|
|
|
private DialogResult EditorAskForSave()
|
|
{
|
|
MessageBoxButtons buttons = MessageBoxButtons.YesNoCancel;
|
|
return MessageBox.Show("Would you like to save first ?", "", buttons);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SIMULATION VARIABLES
|
|
private SimulationReport m_simulation;
|
|
|
|
private int m_simulationDrawAreaWidth;
|
|
private int m_simulationDrawAreaHeight;
|
|
|
|
private Curve m_simulationCurve = new Curve();
|
|
private List<RepresentationEvent> m_simulationRepresentationChanges = new List<RepresentationEvent>();
|
|
private List<RepresentationEvent> m_simulationRepresentationAdditions = new List<RepresentationEvent>();
|
|
private List<Curve> m_simulationStarvings = new List<Curve>();
|
|
private List<Point> m_simulationBufferTimeChanges = new List<Point>();
|
|
|
|
private Color m_simulationQualityColorLow = Color.FromArgb(150, 242, 41, 41); // red
|
|
private Color m_simulationQualityColorMid = Color.FromArgb(150, 242, 149, 29); // orange
|
|
private Color m_simulationQualityColorHigh = Color.FromArgb(150, 239, 209, 16); // yellow
|
|
private Color m_simulationQualityColorUltra = Color.FromArgb(150, 146, 239, 15); // green
|
|
|
|
private Pen m_simulationCurvePen = new Pen(Color.Black, m_curvePenSize);
|
|
private Pen m_simulationBufferPen = new Pen(Color.Blue, m_curvePenSize);
|
|
private Pen m_simulationStarvePen = new Pen(Color.Red, m_starvePenSize);
|
|
#endregion
|
|
|
|
|
|
#region SIMULATOR REPORT FORM
|
|
|
|
private void SimulationDrawPanel_Paint(object sender, PaintEventArgs e)
|
|
{
|
|
base.OnPaint(e);
|
|
|
|
DrawGrid(e, m_simulationDrawAreaWidth, m_simulationDrawAreaHeight);
|
|
|
|
if (m_simulationCurve.Count != 0)
|
|
{
|
|
// draw curve lines
|
|
e.Graphics.DrawLines(m_simulationCurvePen, m_simulationCurve.ToArray());
|
|
}
|
|
|
|
if (m_simulationBufferTimeChanges.Count != 0 && checkBoxShowBufferTime.Checked)
|
|
{
|
|
// draw curve lines
|
|
e.Graphics.DrawLines(m_simulationBufferPen, m_simulationBufferTimeChanges.ToArray());
|
|
}
|
|
|
|
if (buttonRepresentationChanges.Checked)
|
|
{
|
|
// draw representation changes
|
|
DrawRepresentation(m_simulationRepresentationChanges, e);
|
|
}
|
|
else if (buttonRepresentationAdditions.Checked)
|
|
{
|
|
// draw representation additions
|
|
DrawRepresentation(m_simulationRepresentationAdditions, e);
|
|
}
|
|
|
|
if (m_simulationStarvings.Count != 0)
|
|
{
|
|
// draw starving lines
|
|
SolidBrush brush = new SolidBrush(Color.Red);
|
|
for (int i = 0; i < m_simulationStarvings.Count; ++i)
|
|
{
|
|
e.Graphics.DrawLines(m_simulationStarvePen, m_simulationStarvings[i].ToArray());
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SimulationDrawPanel_Resize(object sender, EventArgs e)
|
|
{
|
|
Control control = sender as Control;
|
|
m_simulationDrawAreaWidth = control.Width;
|
|
m_simulationDrawAreaHeight = control.Height;
|
|
|
|
UpdateDrawnSimulation();
|
|
|
|
Refresh();
|
|
}
|
|
|
|
private void SimulationOpenMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
|
{
|
|
SimulationReadFile(openFileDialog.FileName);
|
|
}
|
|
}
|
|
|
|
private void SimulationListBoxCurves_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
UpdateDrawnSimulation();
|
|
}
|
|
|
|
private void SimulationListBoxMaps_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
UpdateDrawnSimulation();
|
|
}
|
|
|
|
private void SimulationListBoxAlgos_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
UpdateDrawnSimulation();
|
|
}
|
|
|
|
private void SimulationButtonColorLow_Click(object sender, EventArgs e)
|
|
{
|
|
UpdateColor(ref m_simulationQualityColorLow, buttonColorLow);
|
|
}
|
|
|
|
private void SimulationButtonColorMid_Click(object sender, EventArgs e)
|
|
{
|
|
UpdateColor(ref m_simulationQualityColorMid, buttonColorMid);
|
|
}
|
|
|
|
private void SimulationButtonColorHigh_Click(object sender, EventArgs e)
|
|
{
|
|
UpdateColor(ref m_simulationQualityColorHigh, buttonColorHigh);
|
|
}
|
|
|
|
private void SimulationButtonColorUltra_Click(object sender, EventArgs e)
|
|
{
|
|
UpdateColor(ref m_simulationQualityColorUltra, buttonColorUltra);
|
|
}
|
|
|
|
private void ButtonRepresentationChanges_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
UpdateDrawnSimulation();
|
|
}
|
|
|
|
private void ButtonRepresentationAdditions_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
UpdateDrawnSimulation();
|
|
}
|
|
|
|
private void CheckBoxShowBufferTime_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
UpdateDrawnSimulation();
|
|
}
|
|
private void SimulatorDrawArea_MouseMove(object sender, MouseEventArgs e)
|
|
{
|
|
reportMousePositionTextBox.Text = GetMouseLocationString(
|
|
(double)e.Location.X,
|
|
(double)e.Location.Y,
|
|
(double)m_simulationDrawAreaWidth,
|
|
(double)m_simulationDrawAreaHeight);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SIMULATION RESULTS UTILS
|
|
|
|
private void InitReport()
|
|
{
|
|
m_simulationDrawAreaWidth = drawPanelSimulation.Width;
|
|
m_simulationDrawAreaHeight = drawPanelSimulation.Height;
|
|
|
|
totalRunStarveDuration.Text = "";
|
|
labelRunDuration.Text = "";
|
|
labelMaxBandwidth.Text = "";
|
|
|
|
buttonColorLow.BackColor = m_simulationQualityColorLow;
|
|
buttonColorMid.BackColor = m_simulationQualityColorMid;
|
|
buttonColorHigh.BackColor = m_simulationQualityColorHigh;
|
|
buttonColorUltra.BackColor = m_simulationQualityColorUltra;
|
|
|
|
m_simulationCurvePen.Alignment = PenAlignment.Center;
|
|
m_simulationBufferPen.Alignment = PenAlignment.Center;
|
|
m_simulationStarvePen.Alignment = PenAlignment.Center;
|
|
}
|
|
List<RepresentationEvent> GetScaledRepresentationEvents(List<RepresentationEvent> _representations, double _clipDuration)
|
|
{
|
|
List<RepresentationEvent> scaledList = new List<RepresentationEvent>();
|
|
|
|
foreach (RepresentationEvent rep in _representations)
|
|
{
|
|
double xPos = (int)(rep.timeStamp / _clipDuration * m_simulationDrawAreaWidth);
|
|
RepresentationEvent scaledRep = new RepresentationEvent(rep.name, xPos);
|
|
scaledList.Add(scaledRep);
|
|
}
|
|
return scaledList;
|
|
}
|
|
|
|
List<Point> GetScaledBufferTimeChanges(List<BufferTimeChange> _bufferTimeChanges, double _clipDuration)
|
|
{
|
|
List<Point> scaledList = new List<Point>();
|
|
|
|
double maxTime = _bufferTimeChanges.Max(b => b.bufferTime);
|
|
foreach (var buffer in _bufferTimeChanges)
|
|
{
|
|
scaledList.Add(
|
|
new Point((int)(
|
|
buffer.timeStamp / _clipDuration * m_simulationDrawAreaWidth),
|
|
m_simulationDrawAreaHeight - (int)(buffer.bufferTime / maxTime * (double)m_simulationDrawAreaHeight)));
|
|
}
|
|
return scaledList;
|
|
}
|
|
|
|
private Tuple<int, int> GetSurroundingPointsIndexes(Point _point)
|
|
{
|
|
int previousIndex = Math.Max(m_simulationCurve.points.FindLastIndex(point => point.X <= _point.X), 0);
|
|
int nextIndex = Math.Min(m_simulationCurve.points.FindIndex(previousIndex, point => point.X > _point.X), m_simulationCurve.Count - 1);
|
|
|
|
return new Tuple<int, int>(previousIndex, nextIndex);
|
|
}
|
|
|
|
private Point ProjectOnCurve(Point _point, int _previousIndex, int _nextIndex)
|
|
{
|
|
int y = (int)EditorUtils.Lerp(
|
|
m_simulationCurve[_previousIndex].Y,
|
|
m_simulationCurve[_nextIndex].Y,
|
|
(double)(_point.X - m_simulationCurve[_previousIndex].X) / (double)(m_simulationCurve[_nextIndex].X - m_simulationCurve[_previousIndex].X));
|
|
|
|
return new Point(_point.X, y);
|
|
}
|
|
|
|
List<Curve> ComputeSimulationStarveSegments(List<Starve> _starves, double _runDuration)
|
|
{
|
|
List<Curve> starveCurves = new List<Curve>();
|
|
|
|
|
|
foreach (Starve starve in _starves)
|
|
{
|
|
// scaling starving points to the screen width and height
|
|
Curve starving = new Curve();
|
|
Point startPoint = new Point((int)(starve.start / _runDuration * m_simulationDrawAreaWidth), m_simulationDrawAreaHeight / 2);
|
|
Point endPoint = new Point((int)(starve.end / _runDuration * m_simulationDrawAreaWidth), m_simulationDrawAreaHeight / 2);
|
|
|
|
if (m_simulationCurve.Count > 0)
|
|
{
|
|
/*
|
|
* This part enables starving segments to be drawn on the simulation curve
|
|
* We look in the simulation curve for the closest 2 points (previous and next) from start and end points of each starve segments.
|
|
* We then scale start and end points of the starve segments with the previous and next points
|
|
*
|
|
* We then look for points in the simulation curve between start and end points of each starve curves
|
|
* If points are found, they are added to the starve segment
|
|
* */
|
|
var startIndexes = GetSurroundingPointsIndexes(startPoint);
|
|
var endIndexes = GetSurroundingPointsIndexes(endPoint);
|
|
|
|
startPoint = ProjectOnCurve(startPoint, startIndexes.Item1, startIndexes.Item2);
|
|
endPoint = ProjectOnCurve(endPoint, endIndexes.Item1, endIndexes.Item2);
|
|
|
|
starving.Add(startPoint);
|
|
starving.points.AddRange(m_simulationCurve.points.GetRange(startIndexes.Item2, endIndexes.Item2 - startIndexes.Item2));
|
|
starving.Add(endPoint);
|
|
}
|
|
else
|
|
{
|
|
starving.Add(startPoint);
|
|
starving.Add(endPoint);
|
|
}
|
|
|
|
starveCurves.Add(starving);
|
|
}
|
|
|
|
return starveCurves;
|
|
}
|
|
|
|
private double GetTotalStarveTime(double _runDuration)
|
|
{
|
|
double totalStarveTime = 0;
|
|
foreach (Curve starve in m_simulationStarvings)
|
|
{
|
|
totalStarveTime += (starve.Last().X - starve.First().X) * _runDuration / m_simulationDrawAreaWidth;
|
|
}
|
|
return totalStarveTime;
|
|
}
|
|
|
|
private void UpdateDrawnSimulation()
|
|
{
|
|
if (listBoxMaps.Text == "" || listBoxAlgos.Text == "")
|
|
{
|
|
return;
|
|
}
|
|
|
|
string selectedCurve = listBoxCurves.Text;
|
|
string selectedMap = listBoxMaps.Text;
|
|
string selectedAlgo = listBoxAlgos.Text;
|
|
|
|
RunStats selectedRunStats = null;
|
|
VideoStatistics videoStat = m_simulation.GetVideoStatistics(selectedMap);
|
|
selectedRunStats = videoStat.GetRunStats(selectedCurve, selectedAlgo);
|
|
|
|
// getting simulation curve and scaling it
|
|
m_simulationCurve = new Curve(
|
|
m_simulation.GetBandwidthCurve(selectedCurve),
|
|
(int)((double)m_simulationDrawAreaWidth * (double)videoStat.Duration / (double)selectedRunStats.Duration),
|
|
m_simulationDrawAreaHeight);
|
|
|
|
if (m_simulationCurve.Count > 0)
|
|
{
|
|
m_simulationCurve.Add(new Point(m_simulationDrawAreaWidth, m_simulationCurve.points.Last().Y));
|
|
}
|
|
|
|
// getting representation changes and scaling them
|
|
m_simulationRepresentationChanges = GetScaledRepresentationEvents(selectedRunStats.RepresentationChangeTimeStamps, videoStat.Duration);
|
|
m_simulationRepresentationAdditions = GetScaledRepresentationEvents(selectedRunStats.RepresentationAdditionTimeStamps, videoStat.Duration);
|
|
|
|
// getting buffer time changes and scaling them
|
|
m_simulationBufferTimeChanges = GetScaledBufferTimeChanges(selectedRunStats.BufferTimeChanges, videoStat.Duration);
|
|
|
|
// getting starve timings changes and scaling them
|
|
m_simulationStarvings = ComputeSimulationStarveSegments(selectedRunStats.StarveTimeStamps, selectedRunStats.Duration);
|
|
|
|
// getting general informations about the run
|
|
double totalStarveTime = GetTotalStarveTime(selectedRunStats.Duration);
|
|
|
|
totalRunStarveDuration.Text = "Total run starve duration : " + Math.Round(totalStarveTime, 2);
|
|
labelRunDuration.Text = "Run Duration : " + Math.Round(selectedRunStats.Duration, 2) + " s";
|
|
labelMaxBandwidth.Text = "Max Bandwidth : " + m_simulation.MaxBandwidthSpeed + " bps";
|
|
Refresh();
|
|
}
|
|
|
|
public void SimulationReadFile(string _fileName)
|
|
{
|
|
m_simulationCurve.Clear();
|
|
m_simulationRepresentationChanges.Clear();
|
|
m_simulationRepresentationAdditions.Clear();
|
|
m_simulationBufferTimeChanges.Clear();
|
|
m_simulationStarvings.Clear();
|
|
|
|
listBoxCurves.Items.Clear();
|
|
listBoxMaps.Items.Clear();
|
|
listBoxAlgos.Items.Clear();
|
|
|
|
m_simulation = new SimulationReport();
|
|
try
|
|
{
|
|
m_simulation.ReadReportFile(_fileName, m_simulationDrawAreaWidth, m_simulationDrawAreaHeight);
|
|
listBoxCurves.Items.AddRange(m_simulation.CurveSet.ToArray());
|
|
listBoxMaps.Items.AddRange(m_simulation.MapSet.ToArray());
|
|
listBoxAlgos.Items.AddRange(m_simulation.AlgoSet.ToArray());
|
|
|
|
if (listBoxCurves.Items.Count > 0)
|
|
{
|
|
listBoxCurves.SelectedIndex = 0;
|
|
}
|
|
if (listBoxMaps.Items.Count > 0)
|
|
{
|
|
listBoxMaps.SelectedIndex = 0;
|
|
}
|
|
if (listBoxAlgos.Items.Count > 0)
|
|
{
|
|
listBoxAlgos.SelectedIndex = 0;
|
|
}
|
|
tabControlPleoLab.SelectedIndex = REPORT_INDEX;
|
|
UpdateDrawnSimulation();
|
|
}
|
|
catch (FileNotFoundException exception)
|
|
{
|
|
PopupMessage("Error when trying opening the file", "Are you sure the path " + exception.FileName + " exists ?");
|
|
return;
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
PopupMessage("Error while parsing file", "Are you sure your xml file is in a valid format ?\n" + exception.Message);
|
|
return;
|
|
}
|
|
}
|
|
|
|
Color GetQualityColor(string _quality)
|
|
{
|
|
Color retval = Color.Black;
|
|
if (_quality == "VideoRepresentationID_LOW")
|
|
{
|
|
retval = m_simulationQualityColorLow;
|
|
}
|
|
else if (_quality == "VideoRepresentationID_MID")
|
|
{
|
|
retval = m_simulationQualityColorMid;
|
|
}
|
|
else if (_quality == "VideoRepresentationID_HIGH")
|
|
{
|
|
retval = m_simulationQualityColorHigh;
|
|
}
|
|
else if (_quality == "VideoRepresentationID_ULTRA")
|
|
{
|
|
retval = m_simulationQualityColorUltra;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
private void DrawRepresentation(List<RepresentationEvent> representation, PaintEventArgs e)
|
|
{
|
|
Rectangle rect;
|
|
// draw representation changes lines
|
|
for (int i = 0; i < representation.Count; ++i)
|
|
{
|
|
|
|
SolidBrush brush = new SolidBrush(GetQualityColor(representation[i].name));
|
|
if (i == representation.Count - 1)
|
|
{
|
|
rect = new Rectangle(
|
|
(int)representation[representation.Count - 1].timeStamp,
|
|
0,
|
|
(int)(m_simulationDrawAreaWidth - representation[representation.Count - 1].timeStamp),
|
|
m_simulationDrawAreaHeight);
|
|
}
|
|
else
|
|
{
|
|
rect = new Rectangle(
|
|
(int)representation[i].timeStamp,
|
|
0,
|
|
(int)(representation[i + 1].timeStamp - representation[i].timeStamp),
|
|
m_simulationDrawAreaHeight);
|
|
}
|
|
e.Graphics.FillRectangle(brush, rect);
|
|
}
|
|
}
|
|
|
|
private void UpdateColor(ref Color _simulationColor, Button _button)
|
|
{
|
|
if (colorDialog1.ShowDialog() == DialogResult.OK)
|
|
{
|
|
_simulationColor = Color.FromArgb(150, colorDialog1.Color);
|
|
_button.BackColor = _simulationColor;
|
|
UpdateDrawnSimulation();
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
} |