AirScout/OxyPlot/Source/Examples/ExampleLibrary/CustomSeries/MatrixSeries.cs

237 wiersze
7.8 KiB
C#

// --------------------------------------------------------------------------------------------------------------------
// <copyright file="MatrixSeries.cs" company="OxyPlot">
// Copyright (c) 2014 OxyPlot contributors
// </copyright>
// <summary>
// Provides a series that visualizes the structure of a matrix.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ExampleLibrary
{
using System;
using System.Collections.Generic;
using OxyPlot;
using OxyPlot.Series;
/// <summary>
/// Provides a series that visualizes the structure of a matrix.
/// </summary>
public class MatrixSeries : XYAxisSeries
{
/// <summary>
/// The image
/// </summary>
private OxyImage image;
/// <summary>
/// The matrix
/// </summary>
private double[,] matrix;
/// <summary>
/// Initializes a new instance of the <see cref="MatrixSeries" /> class.
/// </summary>
public MatrixSeries()
{
this.GridInterval = 1;
this.ShowDiagonal = false;
this.MinimumGridLineDistance = 4;
this.GridColor = OxyColors.LightGray;
this.BorderColor = OxyColors.Gray;
this.NotZeroColor = OxyColors.Black;
this.ZeroTolerance = 0;
this.TrackerFormatString = "{0}\r\n[{1},{2}] = {3}";
}
/// <summary>
/// Gets or sets the matrix.
/// </summary>
public double[,] Matrix
{
get
{
return this.matrix;
}
set
{
this.image = null;
this.matrix = value;
}
}
/// <summary>
/// Gets or sets the interval between the grid lines (the grid is hidden if value is 0).
/// </summary>
public int GridInterval { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to show the diagonal.
/// </summary>
/// <value><c>true</c> if the diagonal should be shown; otherwise, <c>false</c>.</value>
public bool ShowDiagonal { get; set; }
/// <summary>
/// Gets or sets the minimum grid line distance.
/// </summary>
public double MinimumGridLineDistance { get; set; }
/// <summary>
/// Gets or sets the color of the grid.
/// </summary>
/// <value>The color of the grid.</value>
public OxyColor GridColor { get; set; }
/// <summary>
/// Gets or sets the color of the border around the matrix.
/// </summary>
/// <value>The color of the border.</value>
public OxyColor BorderColor { get; set; }
/// <summary>
/// Gets or sets the color of the not zero elements of the matrix.
/// </summary>
public OxyColor NotZeroColor { get; set; }
/// <summary>
/// Gets or sets the zero tolerance (inclusive).
/// </summary>
/// <value>The zero tolerance.</value>
public double ZeroTolerance { get; set; }
/// <summary>
/// Gets the point on the series that is nearest the specified point.
/// </summary>
/// <param name="point">The point.</param>
/// <param name="interpolate">Interpolate the series if this flag is set to <c>true</c>.</param>
/// <returns>A TrackerHitResult for the current hit.</returns>
public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate)
{
var dp = this.InverseTransform(point);
int i = (int)dp.Y;
int j = (int)dp.X;
if (i >= 0 && i < this.matrix.GetLength(0) && j >= 0 && j < this.matrix.GetLength(1))
{
var value = this.matrix[i, j];
return new TrackerHitResult
{
Series = this,
DataPoint = dp,
Position = point,
Item = null,
Index = -1,
Text = StringHelper.Format(this.ActualCulture, this.TrackerFormatString, null, this.Title, i, j, value)
};
}
return null;
}
/// <summary>
/// Renders the series on the specified render context.
/// </summary>
/// <param name="rc">The rendering context.</param>
public override void Render(IRenderContext rc)
{
if (this.Matrix == null)
{
return;
}
int m = this.Matrix.GetLength(0);
int n = this.Matrix.GetLength(1);
var p0 = this.Transform(0, 0);
var p1 = this.Transform(n, m);
// note matrix index [i,j] maps to image index [j,i]
if (this.image == null)
{
var pixels = new OxyColor[n, m];
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
pixels[j, i] = Math.Abs(this.Matrix[i, j]) <= this.ZeroTolerance ? OxyColors.Transparent : this.NotZeroColor;
}
}
this.image = OxyImage.Create(pixels, ImageFormat.Png);
}
var clip = this.GetClippingRect();
var x0 = Math.Min(p0.X, p1.X);
var y0 = Math.Min(p0.Y, p1.Y);
var w = Math.Abs(p0.X - p1.X);
var h = Math.Abs(p0.Y - p1.Y);
rc.DrawClippedImage(clip, this.image, x0, y0, w, h, 1, false);
var points = new List<ScreenPoint>();
if (this.GridInterval > 0)
{
var p2 = this.Transform(this.GridInterval, this.GridInterval);
if (Math.Abs(p2.Y - p0.Y) > this.MinimumGridLineDistance)
{
for (int i = 1; i < n; i += this.GridInterval)
{
points.Add(this.Transform(0, i));
points.Add(this.Transform(n, i));
}
}
if (Math.Abs(p2.X - p0.X) > this.MinimumGridLineDistance)
{
for (int j = 1; j < m; j += this.GridInterval)
{
points.Add(this.Transform(j, 0));
points.Add(this.Transform(j, m));
}
}
}
if (this.ShowDiagonal)
{
points.Add(this.Transform(0, 0));
points.Add(this.Transform(n, m));
}
rc.DrawClippedLineSegments(clip, points, this.GridColor, 1, null, LineJoin.Miter, true);
if (this.BorderColor.IsVisible())
{
var borderPoints = new[]
{
this.Transform(0, 0),
this.Transform(m, 0),
this.Transform(0, n),
this.Transform(m, n),
this.Transform(0, 0),
this.Transform(0, n),
this.Transform(m, 0),
this.Transform(m, n)
};
rc.DrawClippedLineSegments(clip, borderPoints, this.BorderColor, 1, null, LineJoin.Miter, true);
}
}
/// <summary>
/// Updates the maximum and minimum values of the series.
/// </summary>
protected override void UpdateMaxMin()
{
base.UpdateMaxMin();
if (this.Matrix == null)
{
return;
}
this.MinX = 0;
this.MaxX = this.Matrix.GetLength(1);
this.MinY = 0;
this.MaxY = this.Matrix.GetLength(0);
}
}
}