4条回答 默认 最新
- hxycsdn9159 2019-08-20 17:46关注
GDI+的接口足够用了,你这张图里面的元素无非就是“实线”,“虚线”,“文字”还有实际值(可以画成单位像素的矩形),这些GDI的接口足够实现。第一步画表格,就是几条实线和虚线,无非就是计算这些线的起点和终点的坐标直接调用GDI画线的接口。第二步无非是根据横纵坐标值计算某个点的值应该是什么颜色的,然后把它对象的颜色画成一个单位像素的矩形就行了。 总之这个没有什么难度,有的只是复杂度,问题的核心无非是计算坐标,计算值调用GDI的画线,画矩形等接口。
我已经帮你实现了个大概:
核心类代码:using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; namespace SummaryGraph { public class GrainYieldMap { public class Distribution { /// <summary> /// 纬度 /// </summary> public float Latitude { get; set; } /// <summary> /// 经度 /// </summary> public float Longitude { get; set; } /// <summary> /// 值 /// </summary> public float Value { get; set; } /// <summary> /// 根据值计算颜色 /// </summary> public Color Color { get { if (Value < 0.08f) { return Color.Red; } else if (Value >= 0.08f && Value < 0.4f) { return Color.OrangeRed; } else if (Value >= 0.4f && Value < 0.6f) { return Color.Orange; } else if (Value >= 0.6f && Value < 0.8f) { return Color.Yellow; } else if (Value >= 0.8f && Value < 1f) { return Color.LightGreen; } else { return Color.Green; } } } } /// <summary> /// 在这里考虑可能上万条数据插入比较慢所以加上同步锁,防止分布点的时候修改分布点数据的集合 /// </summary> private readonly object SyncRoot = new object(); /// <summary> /// x方向单元格个数 /// </summary> public int XCount { get; set; } /// <summary> /// y方向单元格个数 /// </summary> public int YCount { get; set; } /// <summary> /// 每个x方向单元格经度跨度 /// </summary> public float UnitX { get; set; } /// <summary> /// 每个y单元格纬度跨度 /// </summary> public float UnitY { get; set; } /// <summary> /// 每个x方向单元格所占实际像素(像素) /// </summary> public float UnitXLength { get; set; } /// <summary> /// 每个y方向单元格所占实际像素(像素) /// </summary> public float UnitYLength { get; set; } /// <summary> /// 整张图上边距(像素) /// </summary> public float MarginTop { get; set; } /// <summary> /// 整张图下边距(像素) /// </summary> public float MarginLeft { get; set; } private float originLatitude; /// <summary> /// 坐标原点维度值 /// </summary> public float OriginLatitude { get { return originLatitude; } set { if (value < -90f || value > 90) throw new ArgumentOutOfRangeException("纬度取值范围为-90°到90°"); originLatitude = value; } } private float originLongitude; /// <summary> /// 坐标原点经度值 /// </summary> public float OriginLongitude { get { return originLongitude; } set { if (value < -180f || value > 180) throw new ArgumentOutOfRangeException("经度取值范围为-180°到180°"); originLongitude = value; } } /// <summary> /// 整张图的宽度(像素) /// </summary> public float MapWidth { get { return XCount * UnitXLength; } } /// <summary> /// 整张图的高度(像素) /// </summary> public float MapHeight { get { return YCount * UnitYLength; } } /// <summary> /// 坐标轴原点x(像素) /// </summary> public float AxisX { get { return MarginLeft; } } /// <summary> /// 坐标轴原点y(像素) /// </summary> public float AxisY { get { return MarginTop + MapHeight; } } /// <summary> /// 分布图的数据集合 /// </summary> public List<Distribution> DistributionData { get; private set; } public GrainYieldMap() { DistributionData = new List<Distribution>(); } /// <summary> /// 增加一条分布数据 /// </summary> /// <param name="data"></param> public void AddDistributionData(Distribution data) { lock (SyncRoot) { DistributionData.Add(data); } } /// <summary> /// 画分布图 /// </summary> /// <param name="e"></param> public void DrawMap(Graphics e) { DrawBackground(e); DrawDistribution(e); DrawAxis(e); } /// <summary> /// 画坐标轴 /// </summary> /// <param name="e"></param> private void DrawAxis(Graphics e) { //画坐标轴边框(4条实线) PointF[] VertexArray = new PointF[] { new PointF(MarginLeft, MarginTop), new PointF(MarginLeft+ MapWidth, MarginTop), new PointF(MarginLeft+ MapWidth, MarginTop + MapHeight), new PointF(MarginLeft, MarginTop + MapHeight), new PointF(MarginLeft, MarginTop) }; e.DrawLines(new Pen(Color.Black), VertexArray); Pen pen = new Pen(Color.Black, 1); pen.DashStyle = DashStyle.Dash; Font font = new Font("宋体", 10f, FontStyle.Bold); //画所有竖向虚线 for (int x = 1; x < XCount; x++) { e.DrawLine(pen, new PointF(MarginLeft + x * UnitXLength, MarginTop), new PointF(MarginLeft + x * UnitXLength, MarginTop + MapHeight)); //每隔一个单元显示x坐标值 if (x % 2 == 0) { string content = (OriginLongitude + UnitX * x).ToString(); SizeF strSize = e.MeasureString(content, font); e.DrawString(content, font, new SolidBrush(Color.Black), MarginLeft + x * UnitXLength - strSize.Width / 2f, MarginTop + MapHeight + 10f); } } //画所有横向虚线 for (int y = 1; y < YCount; y++) { e.DrawLine(pen, new PointF(MarginLeft, MarginTop + y * UnitYLength), new PointF(MarginLeft + MapWidth, MarginTop + y * UnitYLength)); //每隔一个单元显示y坐标值 if (y % 2 == 0) { string content = (OriginLatitude + UnitY * y).ToString(); SizeF strSize = e.MeasureString(content, font); e.DrawString(content, font, new SolidBrush(Color.Black), MarginLeft - strSize.Width - 10f, MarginTop + MapHeight - y * UnitYLength - strSize.Height / 2); } } } /// <summary> /// 画分布点 /// </summary> /// <param name="e"></param> private void DrawDistribution(Graphics e) { lock (SyncRoot) { for (int i = 0; i < DistributionData.Count; i++) { //计算当前经纬点相对坐标轴原点的偏移坐标 // //在这里计算真实坐标的时候注意f(x,y)=>f(x + MarginLeft,-y + MarginTop + MapHeight)的坐标系变换 // float offsetLatitude = MarginTop + MapHeight - (DistributionData[i].Latitude - OriginLatitude) * (UnitYLength / UnitY); float offsetLongitude = (DistributionData[i].Longitude - OriginLongitude) * (UnitXLength / UnitX) + MarginLeft; //画分布点 e.FillRectangle(new SolidBrush(DistributionData[i].Color), offsetLongitude, offsetLatitude, 2f, 2f); } } } /// <summary> /// 画图的背景色 /// </summary> /// <param name="e"></param> private void DrawBackground(Graphics e) { e.FillRectangle(new SolidBrush(Color.White), MarginLeft, MarginTop, MapWidth, MapHeight); } } }
调用代码:
using System; using System.Windows.Forms; namespace SummaryGraph { public partial class Form1 : Form { GrainYieldMap Map; public Form1() { InitializeComponent(); //测试代码 Map = new GrainYieldMap(); Map.UnitX = 0.001f; Map.UnitY = 0.00142f; Map.OriginLatitude = 40.16219f; Map.OriginLongitude = 116.27573f; Map.MarginLeft = 100f; Map.MarginTop = 100f; Map.UnitXLength = 80f; Map.UnitYLength = 50f; Map.XCount = 10; Map.YCount = 10; //在这里随机生成3万个分布点的数据,由于Random是白噪声随机函数完全随机,所以生成的效果可能比较散 //按你的需求应该改成从文件中读取经纬度信息以及值是多少 Random random = new Random(); for (int i = 0; i < 30000; i++) { GrainYieldMap.Distribution point = new GrainYieldMap.Distribution(); point.Value = (float)random.NextDouble() * 1.2f; point.Latitude = Map.OriginLatitude + (float)random.NextDouble() / 100f; point.Longitude = Map.OriginLongitude + (float)random.NextDouble() / 100f; Map.AddDistributionData(point); } } private void Form1_Paint(object sender, PaintEventArgs e) { Map.DrawMap(e.Graphics); } } }
其他说明:
图之所以和你的不一样是因为我测试的数据都是生成的白噪声随机数,所以比较散,用你真实的数据应该就比较接近你截图的效果了本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 3无用
悬赏问题
- ¥15 javaweb项目无法正常跳转
- ¥15 VMBox虚拟机无法访问
- ¥15 skd显示找不到头文件
- ¥15 机器视觉中图片中长度与真实长度的关系
- ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
- ¥15 R语言卸载之后无法重装,显示电脑存在下载某些较大二进制文件行为,怎么办
- ¥15 java 的protected权限 ,问题在注释里
- ¥15 这个是哪里有问题啊?
- ¥15 关于#vue.js#的问题:修改用户信息功能图片无法回显,数据库中只存了一张图片(相关搜索:字符串)
- ¥15 texstudio的问题,