Initial Commit
This commit is contained in:
255
Charts/Isolines/IsolineTrackingGraph.xaml.cs
Normal file
255
Charts/Isolines/IsolineTrackingGraph.xaml.cs
Normal file
@@ -0,0 +1,255 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
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 Microsoft.Research.DynamicDataDisplay.Charts.Isolines;
|
||||
using Microsoft.Research.DynamicDataDisplay;
|
||||
using Microsoft.Research.DynamicDataDisplay.Common;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Charts
|
||||
{
|
||||
/// <summary>
|
||||
/// Draws one isoline line through mouse position.
|
||||
/// </summary>
|
||||
public partial class IsolineTrackingGraph : IsolineGraphBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="IsolineTrackingGraph"/> class.
|
||||
/// </summary>
|
||||
public IsolineTrackingGraph()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private Style pathStyle = null;
|
||||
/// <summary>
|
||||
/// Gets or sets style, applied to line path.
|
||||
/// </summary>
|
||||
/// <value>The path style.</value>
|
||||
public Style PathStyle
|
||||
{
|
||||
get { return pathStyle; }
|
||||
set
|
||||
{
|
||||
pathStyle = value;
|
||||
foreach (var path in addedPaths)
|
||||
{
|
||||
path.Style = pathStyle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Point prevMousePos;
|
||||
|
||||
protected override void OnPlotterAttached()
|
||||
{
|
||||
UIElement parent = (UIElement)Parent;
|
||||
parent.MouseMove += parent_MouseMove;
|
||||
|
||||
UpdateUIRepresentation();
|
||||
}
|
||||
|
||||
protected override void OnPlotterDetaching()
|
||||
{
|
||||
UIElement parent = (UIElement)Parent;
|
||||
parent.MouseMove -= parent_MouseMove;
|
||||
}
|
||||
|
||||
private void parent_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
Point mousePos = e.GetPosition(this);
|
||||
if (mousePos != prevMousePos)
|
||||
{
|
||||
prevMousePos = mousePos;
|
||||
|
||||
UpdateUIRepresentation();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void UpdateDataSource()
|
||||
{
|
||||
IsolineBuilder.DataSource = DataSource;
|
||||
|
||||
UpdateUIRepresentation();
|
||||
}
|
||||
|
||||
protected override void OnViewportPropertyChanged(ExtendedPropertyChangedEventArgs e)
|
||||
{
|
||||
UpdateUIRepresentation();
|
||||
}
|
||||
|
||||
private readonly List<Path> addedPaths = new List<Path>();
|
||||
private Vector labelShift = new Vector(3, 3);
|
||||
private void UpdateUIRepresentation()
|
||||
{
|
||||
if (Plotter2D == null)
|
||||
return;
|
||||
|
||||
foreach (var path in addedPaths)
|
||||
{
|
||||
content.Children.Remove(path);
|
||||
}
|
||||
addedPaths.Clear();
|
||||
|
||||
if (DataSource == null)
|
||||
{
|
||||
labelGrid.Visibility = Visibility.Hidden;
|
||||
return;
|
||||
}
|
||||
|
||||
Rect output = Plotter2D.Viewport.Output;
|
||||
|
||||
Point mousePos = Mouse.GetPosition(this);
|
||||
if (!output.Contains(mousePos)) return;
|
||||
|
||||
var transform = Plotter2D.Viewport.Transform;
|
||||
Point visiblePoint = mousePos.ScreenToData(transform);
|
||||
DataRect visible = Plotter2D.Viewport.Visible;
|
||||
|
||||
double isolineLevel;
|
||||
if (Search(visiblePoint, out isolineLevel))
|
||||
{
|
||||
var collection = IsolineBuilder.BuildIsoline(isolineLevel);
|
||||
|
||||
string format = "G3";
|
||||
if (Math.Abs(isolineLevel) < 1000)
|
||||
format = "F";
|
||||
|
||||
textBlock.Text = isolineLevel.ToString(format);
|
||||
|
||||
double x = mousePos.X + labelShift.X;
|
||||
if (x + labelGrid.ActualWidth > output.Right)
|
||||
x = mousePos.X - labelShift.X - labelGrid.ActualWidth;
|
||||
double y = mousePos.Y - labelShift.Y - labelGrid.ActualHeight;
|
||||
if (y < output.Top)
|
||||
y = mousePos.Y + labelShift.Y;
|
||||
|
||||
Canvas.SetLeft(labelGrid, x);
|
||||
Canvas.SetTop(labelGrid, y);
|
||||
|
||||
foreach (LevelLine segment in collection.Lines)
|
||||
{
|
||||
StreamGeometry streamGeom = new StreamGeometry();
|
||||
using (StreamGeometryContext context = streamGeom.Open())
|
||||
{
|
||||
Point startPoint = segment.StartPoint.DataToScreen(transform);
|
||||
var otherPoints = segment.OtherPoints.DataToScreenAsList(transform);
|
||||
context.BeginFigure(startPoint, false, false);
|
||||
context.PolyLineTo(otherPoints, true, true);
|
||||
}
|
||||
|
||||
Path path = new Path
|
||||
{
|
||||
Stroke = new SolidColorBrush(Palette.GetColor(segment.Value01)),
|
||||
Data = streamGeom,
|
||||
Style = pathStyle
|
||||
};
|
||||
content.Children.Add(path);
|
||||
addedPaths.Add(path);
|
||||
|
||||
labelGrid.Visibility = Visibility.Visible;
|
||||
|
||||
Binding pathBinding = new Binding { Path = new PropertyPath("StrokeThickness"), Source = this };
|
||||
path.SetBinding(Path.StrokeThicknessProperty, pathBinding);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
labelGrid.Visibility = Visibility.Hidden;
|
||||
}
|
||||
}
|
||||
|
||||
int foundI = 0;
|
||||
int foundJ = 0;
|
||||
Quad foundQuad = null;
|
||||
private bool Search(Point pt, out double foundVal)
|
||||
{
|
||||
var grid = DataSource.Grid;
|
||||
|
||||
foundVal = 0;
|
||||
|
||||
int width = DataSource.Width;
|
||||
int height = DataSource.Height;
|
||||
bool found = false;
|
||||
int i = 0, j = 0;
|
||||
for (i = 0; i < width - 1; i++)
|
||||
{
|
||||
for (j = 0; j < height - 1; j++)
|
||||
{
|
||||
Quad quad = new Quad(
|
||||
grid[i, j],
|
||||
grid[i, j + 1],
|
||||
grid[i + 1, j + 1],
|
||||
grid[i + 1, j]);
|
||||
if (quad.Contains(pt))
|
||||
{
|
||||
found = true;
|
||||
foundQuad = quad;
|
||||
foundI = i;
|
||||
foundJ = j;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) break;
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
foundQuad = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var data = DataSource.Data;
|
||||
|
||||
double x = pt.X;
|
||||
double y = pt.Y;
|
||||
Vector A = grid[i, j + 1].ToVector(); // @TODO: in common case add a sorting of points:
|
||||
Vector B = grid[i + 1, j + 1].ToVector(); // maxA ___K___ B
|
||||
Vector C = grid[i + 1, j].ToVector(); // | |
|
||||
Vector D = grid[i, j].ToVector(); // M P N
|
||||
double a = data[i, j + 1]; // | |
|
||||
double b = data[i + 1, j + 1]; // В ___L____Сmin
|
||||
double c = data[i + 1, j];
|
||||
double d = data[i, j];
|
||||
|
||||
Vector K, L;
|
||||
double k, l;
|
||||
if (x >= A.X)
|
||||
k = Interpolate(A, B, a, b, K = new Vector(x, GetY(A, B, x)));
|
||||
else
|
||||
k = Interpolate(D, A, d, a, K = new Vector(x, GetY(D, A, x)));
|
||||
|
||||
if (x >= C.X)
|
||||
l = Interpolate(C, B, c, b, L = new Vector(x, GetY(C, B, x)));
|
||||
else
|
||||
l = Interpolate(D, C, d, c, L = new Vector(x, GetY(D, C, x)));
|
||||
|
||||
foundVal = Interpolate(L, K, l, k, new Vector(x, y));
|
||||
return !Double.IsNaN(foundVal);
|
||||
}
|
||||
|
||||
private double Interpolate(Vector v0, Vector v1, double u0, double u1, Vector a)
|
||||
{
|
||||
Vector l1 = a - v0;
|
||||
Vector l = v1 - v0;
|
||||
|
||||
double res = (u1 - u0) / l.Length * l1.Length + u0;
|
||||
return res;
|
||||
}
|
||||
|
||||
private double GetY(Vector v0, Vector v1, double x)
|
||||
{
|
||||
double res = v0.Y + (v1.Y - v0.Y) / (v1.X - v0.X) * (x - v0.X);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user