siverlight中绘制温度云图,倒腾了好一段时间。
silverlight中的控件比较少,选择了OxyPlot控件中的heatmap曲线来画温度曲线
但是Oxyplot绘制的温度场不能满足要求。只能根据算法计算其中温度值。
1、初始化OxyPlot控件
2、根据传入的温度值计算温度无向图的最短路径
3、计算最短路径上的所有点的温度值。
4、计算温度值(以计算坐标周围8个点的值进行计算:大于等于3个点的坐标有温度值,求平均值作为计算坐标的温度值)
5、遍历二位数组,计算所有温度值。
结果:此算法不是完美算法。
1、无向图最短路径,存在点-点的超长跨度线。
2、插值算法不能完整计算所有点。
3、当插值算法遍历计算次数不同时,温度值会有明显的边界区分。
public partial class UieHeatMap : UserControl, UieBase
{
//Color Palette Area
protected static int PALETTE_STEP = 100;
public int MAX_X = 1400;
public int MAX_Y = 700;
//无向温度图最短路径
List<HeatMapPoint> ShortestPath = new List<HeatMapPoint>();
//温度场页面所有温度点
protected List<HeatMapPoint> heatMapPoints;
protected PlotModel plotModel;
protected LinearColorAxis linearColorAxis;
protected HeatMapSeries heatMapSeries;
/// <summary>
/// 初始化函数
/// </summary>
/// <param name="x">heatMapSeries x pixel</param>
/// <param name="y">heatMapSeries y pixel</param>
public UieHeatMap()
{
InitializeComponent();
plotModel = new PlotModel(); ;
linearColorAxis = new LinearColorAxis();
heatMapSeries = new HeatMapSeries();
heatMapPoints = new List<HeatMapPoint>();
plotModel.Axes.Clear();
}
public void InitData(List<HeatMapPoint> heatMapPoints)
{
heatMapSeries.X1 = MAX_X;
heatMapSeries.Y1 = MAX_Y;
foreach (var hmp in heatMapPoints)
{
// deal with edge
hmp.X = hmp.X > MAX_X ? MAX_X : hmp.X;
hmp.Y = hmp.Y > MAX_X ? MAX_Y : hmp.Y;
hmp.Y = MAX_Y - hmp.Y;
this.heatMapPoints.Add(hmp);
}
GetShortestPath(heatMapPoints);
InitPlotModel();
}
private void GetShortestPath(List<HeatMapPoint> heatMapPoints)
{
HeatMapPoint startSearchKey = heatMapPoints[0].Copy();
ShortestPath.Add(heatMapPoints[0].Copy());
heatMapPoints.RemoveAt(0);
List<int> hmpPath = new List<int>();
while (heatMapPoints.Count > 1)
{
List<double> tempPath = new List<double>();
for (int i = 0; i < heatMapPoints.Count; i++)
{
double distance = Math.Sqrt((startSearchKey.X - heatMapPoints[i].X) * (startSearchKey.X - heatMapPoints[i].X) + (startSearchKey.Y - heatMapPoints[i].Y) * (startSearchKey.Y - heatMapPoints[i].Y));
tempPath.Add(distance);
}
var a = tempPath.Select((m, index) => new double[2] { index, m }).OrderBy(n => n[1]).Take(1).ToList();
startSearchKey = heatMapPoints[(int)a[0][0]].Copy();
ShortestPath.Add(heatMapPoints[(int)a[0][0]].Copy());
heatMapPoints.RemoveAt((int)a[0][0]);
}
}
/// <summary>
/// 更新数据
/// </summary>
/// <param name="rtds"></param>
public void SetRtValue(List<RealTimeData> rtds)
{
RefreshData(rtds);
}
/// <summary>
/// 是否显示标题
/// </summary>
/// <param name="isShow"></param>
/// <param name="title"></param>
/// <param name="fontSize"></param>
public void SetIsShowTitle(bool isShow, string title, int fontSize)
{
//
}
/// <summary>
/// 绑定别名
/// </summary>
public int BindRtdNo
{
get;
set;
}
/// <summary>
/// 设置控件大小
/// </summary>
/// <param name="isLockScale"></param>
/// <param name="width"></param>
/// <param name="height"></param>
public void SetUieSize(bool isLockScale, double width, double height)
{
heatmap.Width = width;
if (!isLockScale)
{
heatmap.Height = height;
}
}
/// <summary>
/// 初始化图表
/// </summary>
public void InitPlotModel()
{
//调色板
linearColorAxis.Position = AxisPosition.Right;
linearColorAxis.Maximum = 60;
linearColorAxis.Minimum = 5;
linearColorAxis.Palette = new OxyPalette(InitPalette());
plotModel.Axes.Add(linearColorAxis);
//数据
heatMapSeries.CoordinateDefinition = HeatMapCoordinateDefinition.Edge;
heatMapSeries.Interpolate = false;
heatMapSeries.Data = new Double[Convert.ToInt32(MAX_X), Convert.ToInt32(MAX_Y)];
//AssignSeriesBaseData();
TraversalData();
plotModel.Series.Add(heatMapSeries);
heatmap.Model = plotModel;
plotModel.InvalidatePlot(true);
}
private void TraversalData()
{
for (int a = 0; a < MAX_X; a++)
{
for (int b = 0; b < MAX_Y; b++)
{
heatMapSeries.Data[a, b] = 0;
}
}
//初始化基本点温度值
foreach (var htm in ShortestPath)
{
heatMapSeries.Data[(int)htm.X, (int)htm.Y] = htm.Temperature;
}
//初始化线性温度值
for (int i = 0; i < ShortestPath.Count - 1; i++)
{
HeatMapPoint start = ShortestPath[i];
HeatMapPoint end = ShortestPath[i + 1];
if (start.X > end.X)
{
start = ShortestPath[i + 1];
end = ShortestPath[i];
}
bool YisPlus = start.Y > end.Y ? true : false;
try
{
for (int j = 0; j < Math.Abs(start.X - end.X); j++)
{
int tempX = (int)(start.X + j);
int tempY = 0;
double xxxx = (start.Temperature - end.Temperature) * j / (start.X - end.X);
if (YisPlus)
{
tempY = (int)(start.Y - j / (start.X - end.X) * (start.Y + end.Y));
heatMapSeries.Data[(int)(start.X - j), (int)(start.Y - j / Math.Abs((start.X - end.X)) * (start.Y - end.Y))] = start.Temperature - (start.Temperature - end.Temperature) * j / (start.X - end.X);
}
else
{
tempY = (int)(start.Y + j / (start.X - end.X) * (start.Y + end.Y));
heatMapSeries.Data[(int)(start.X - j), (int)(start.Y - j / Math.Abs((start.X - end.X)) * (start.Y - end.Y))] = start.Temperature - (start.Temperature - end.Temperature) * j / (start.X - end.X);
}
}
}
catch (Exception)
{
throw;
}
}
int blankPointInt = 0;
//以八个方向填充温度值
for (int x = 1; x < MAX_X - 1; x++)
{
for (int y = 1; y < MAX_Y - 1; y++)
{
if (heatMapSeries.Data[x, y] == 0)
{
List<double> aroudTemperature = new List<double>();
aroudTemperature.Add(heatMapSeries.Data[x, y - 1]);
aroudTemperature.Add(heatMapSeries.Data[x, y + 1]);
aroudTemperature.Add(heatMapSeries.Data[x - 1, y]);
aroudTemperature.Add(heatMapSeries.Data[x - 1, y + 1]);
aroudTemperature.Add(heatMapSeries.Data[x - 1, y - 1]);
aroudTemperature.Add(heatMapSeries.Data[x + 1, y]);
aroudTemperature.Add(heatMapSeries.Data[x + 1, y + 1]);
aroudTemperature.Add(heatMapSeries.Data[x + 1, y - 1]);
int existCount = aroudTemperature.Where(o => o > 0).ToList().Count;
if (existCount >= 3)
{
heatMapSeries.Data[x, y] = aroudTemperature.Sum(o => o) / existCount;
}
else
{
blankPointInt++;
}
}
}
}
int CirlcleCount = 0;
while (blankPointInt > 100 && CirlcleCount <1)
{
CirlcleCount++;
blankPointInt = 0;
//blankPoints.Clear();
for (int x = 1; x < MAX_X - 1; x++)
{
for (int y = 1; y < MAX_Y - 1; y++)
{
if (heatMapSeries.Data[x, y] == 0)
{
List<double> aroudTemperature = new List<double>();
aroudTemperature.Add(heatMapSeries.Data[x, y - 1]);
aroudTemperature.Add(heatMapSeries.Data[x, y + 1]);
aroudTemperature.Add(heatMapSeries.Data[x - 1, y]);
aroudTemperature.Add(heatMapSeries.Data[x - 1, y + 1]);
aroudTemperature.Add(heatMapSeries.Data[x - 1, y - 1]);
aroudTemperature.Add(heatMapSeries.Data[x + 1, y]);
aroudTemperature.Add(heatMapSeries.Data[x + 1, y + 1]);
aroudTemperature.Add(heatMapSeries.Data[x + 1, y - 1]);
int existCount = aroudTemperature.Where(o => o > 0).ToList().Count;
if (existCount >= 3)
{
heatMapSeries.Data[x, y] = aroudTemperature.Sum(o => o) / existCount;
}
else
{
//blankPoints.Add(new TempPoint { X = x, Y = y });
blankPointInt++;
}
}
}
}
}
}
/// <summary>
/// Init Palette
/// </summary>
/// <returns></returns>
private List<OxyColor> InitPalette()
{
List<OxyColor> result = new List<OxyColor>();
OxyColor temp = OxyColor.FromArgb((byte)0, (byte)1, (byte)1, (byte)1);
result.Add(temp);
result.AddRange(GetStepColors(Colors.Blue, Colors.Green));
result.AddRange(GetStepColors(Colors.Green, Colors.Yellow));
result.AddRange(GetStepColors(Colors.Yellow, Colors.Orange));
result.AddRange(GetStepColors(Colors.Orange, Colors.Red));
return result;
}
/// <summary>
/// 获得从开始颜色到结束颜色的颜色表
/// </summary>
/// <param name="startColor"></param>
/// <param name="endColor"></param>
/// <returns></returns>
private List<OxyColor> GetStepColors(Color startColor, Color endColor)
{
List<OxyColor> result = new List<OxyColor>();
int r = 0;
int g = 0;
int b = 0;
for (int i = 0; i < PALETTE_STEP; i++)
{
r = startColor.R + (endColor.R - startColor.R) * i / PALETTE_STEP;
g = startColor.G + (endColor.G - startColor.G) * i / PALETTE_STEP;
b = startColor.B + (endColor.B - startColor.B) * i / PALETTE_STEP;
OxyColor temp = OxyColor.FromArgb((byte)255, (byte)r, (byte)g, (byte)b);
result.Add(temp);
}
return result;
}
/// <summary>
/// 将实时数据赋值给热点列表
/// </summary>
/// <param name="rtds">实时数据</param>
private void ConvertRtdToHeatMapPoints(List<RealTimeData> rtds)
{
foreach (var rtd in rtds)
{
foreach (var hmp in ShortestPath)
//foreach (var hmp in heatMapPoints)
{
if (rtd.DevAlias == hmp.DevAlias && rtd.Name == "温度")
{
if (LJD.IMS.Ria.Utility.StringHelper.IsNumber(rtd.RtValue))
hmp.Temperature = double.Parse(rtd.RtValue);
}
}
}
}
/// <summary>
/// 刷新数据
/// </summary>
/// <param name="rtds">传入实时数据</param>
public void RefreshData(List<RealTimeData> rtds)
{
if (rtds.Count > 0)
{
ConvertRtdToHeatMapPoints(rtds);
plotModel.Series.Clear();
// AssignSeriesBaseData();
TraversalData();
//InitNewData();
plotModel.Series.Add(heatMapSeries);
plotModel.InvalidatePlot(true);
heatmap.InvalidatePlot(true);
heatmap.Model.InvalidatePlot(true);
}
}
}