public void Paint(bool recomputeView = false)
{
graph.Children.Clear();
LinkedList<CurvePoint> points = SelectedCurve.CurvePoints;
if (points.Count > 0 && recomputeView)
{
float timeSpan = points.Last().InVal - points.First().InVal;
timeSpan = timeSpan > 0 ? timeSpan : 2;
HorizontalOffset = Math.Round(points.First().InVal - (timeSpan * 0.2));
double hSpan = Math.Ceiling(timeSpan * 1.2);
if (hSpan + HorizontalOffset <= timeSpan)
{
hSpan += 1;
}
HorizontalScale = graph.ActualWidth / hSpan;
if (HorizontalOffset >= points.First().InVal - (hSpan / 10))
{
HorizontalOffset = points.First().InVal - (hSpan / 10);
}
else if (HorizontalOffset + hSpan <= points.Last().InVal + (hSpan / 10))
{
HorizontalOffset += hSpan / 10;
}
float max = points.Max(x => x.OutVal);
float min = points.Min(x => x.OutVal);
float valSpan = max - min;
valSpan = valSpan > 0 ? valSpan : 2;
VerticalOffset = Math.Round(min - Math.Ceiling(valSpan * 0.1));
double vSpan = Math.Ceiling(valSpan * 1.2);
if (vSpan + VerticalOffset <= max)
{
vSpan += 1;
}
VerticalScale = graph.ActualHeight / vSpan;
}
int numXLines = Convert.ToInt32(Math.Ceiling(ActualWidth / LINE_SPACING));
int numYLines = Convert.ToInt32(Math.Ceiling(ActualHeight / LINE_SPACING));
double upperXBound = unrealX(ActualWidth);
double upperYBound = unrealY(ActualHeight);
double lineXSpacing = (upperXBound - HorizontalOffset) / numXLines;
int xGranularity = lineXSpacing > 0.75 ? 1 : (lineXSpacing > 0.25 ? 2 : 10);
lineXSpacing = Math.Ceiling(lineXSpacing * xGranularity) / xGranularity;
double lineYSpacing = (upperYBound - VerticalOffset) / numYLines;
int yGranularity = lineYSpacing > 0.75 ? 1 : (lineYSpacing > 0.25 ? 2 : 10);
lineYSpacing = Math.Ceiling(lineYSpacing * yGranularity) / yGranularity;
Line line;
Label label;
double linepos;
for (int i = 0; i < numXLines; i++)
{
linepos = HorizontalOffset + (lineXSpacing * (i + 1));
line = new Line();
Canvas.SetLeft(line, localX(linepos));
line.Style = FindResource("VerticalLine") as Style;
graph.Children.Add(line);
label = new Label();
Canvas.SetLeft(label, localX(linepos));
Canvas.SetBottom(label, 0);
label.Content = linepos.ToString("0.00");
graph.Children.Add(label);
}
for (int i = 0; i < numYLines; i++)
{
linepos = VerticalOffset + (lineYSpacing * (i + 1));
line = new Line();
Canvas.SetBottom(line, localY(linepos));
line.Style = FindResource("HorizontalLine") as Style;
graph.Children.Add(line);
label = new Label();
Canvas.SetBottom(label, localY(linepos));
label.Content = linepos.ToString("0.00");
graph.Children.Add(label);
}
Anchor lastAnchor = null;
for (LinkedListNode<CurvePoint> node = points.First; node != null; node = node.Next)
{
switch (node.Value.InterpMode)
{
case CurveMode.CIM_CurveAuto:
case CurveMode.CIM_CurveUser:
node.Value.LeaveTangent = node.Value.ArriveTangent;
break;
case CurveMode.CIM_CurveAutoClamped:
node.Value.ArriveTangent = node.Value.LeaveTangent = 0f;
break;
case CurveMode.CIM_CurveBreak:
case CurveMode.CIM_Constant:
case CurveMode.CIM_Linear:
default:
break;
}
Anchor a = new Anchor(this, node);
if (node.Value == SelectedPoint)
{
a.IsSelected = true;
}
graph.Children.Add(a);
if (node.Previous == null)
{
line = new Line();
line.X1 = -10;
line.bind(Line.Y1Property, a, "Y", new YConverter(), ActualHeight);
line.bind(Line.X2Property, a, "X");
line.bind(Line.Y2Property, a, "Y", new YConverter(), ActualHeight);
graph.Children.Add(line);
}
else
{
PathBetween(lastAnchor, a, node.Previous.Value.InterpMode);
}
if (node.Next == null)
{
line = new Line();
line.bind(Line.X1Property, a, "X");
line.bind(Line.Y1Property, a, "Y", new YConverter(), ActualHeight);
line.X2 = ActualWidth + 10;
line.bind(Line.Y2Property, a, "Y", new YConverter(), ActualHeight);
graph.Children.Add(line);
}
lastAnchor = a;
}
}