基本信息
源码名称:等高线的绘制
源码大小:3.54KB
文件格式:.zip
开发语言:C#
更新时间:2021-03-05
   友情提示:(无需注册或充值,赞助后即可获取资源下载链接)

     嘿,亲!知识可是无价之宝呢,但咱这精心整理的资料也耗费了不少心血呀。小小地破费一下,绝对物超所值哦!如有下载和支付问题,请联系我们QQ(微信同号):78630559

本次赞助数额为: 2 元 
   源码介绍


using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media.Imaging;

namespace WPFCtrlLib
{
    /// <summary>
    /// 等高线图控件
    /// </summary>
    public partial class IsoHeightCtrl : UserControl
    {
        private const int grid_w = 10;
        private const int grid_h = 10;

        private double w;
        private double h;
        private int bitmap_w;
        private int bitmap_h;

        private int x_num;
        private int y_num;
        private float[,] data;

        private float min;
        private float max;

        private byte[] Rs, Gs, Bs;

        private Bitmap bitmap;
        private Graphics graphics;

        public IsoHeightCtrl()
        {
            InitializeComponent();
        }

        private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Draw();
        }

        /// <summary>
        /// 离散高度点列表
        /// XY总长为单位1
        /// </summary>
        public MeasureData[] HeightDots
        {
            get { return (MeasureData[])GetValue(HeightDotsProperty); }
            set { SetValue(HeightDotsProperty, value); }
        }
        public static readonly DependencyProperty HeightDotsProperty =
            DependencyProperty.Register("HeightDots", typeof(MeasureData[]), typeof(IsoHeightCtrl), new PropertyMetadata(null, (s, e) =>
            {
                IsoHeightCtrl ihc = s as IsoHeightCtrl;
                ihc.Draw();
            }));

        /// <summary>
        /// 颜色列表
        /// 其数量决定了等高线的层数
        /// </summary>
        public string ColorList
        {
            get { return (string)GetValue(ColorListProperty); }
            set { SetValue(ColorListProperty, value); }
        }
        public static readonly DependencyProperty ColorListProperty =
            DependencyProperty.Register("ColorList", typeof(string), typeof(IsoHeightCtrl), new PropertyMetadata("#072FFA,#0779FA,#07C4FA,#07DFD0,#07FAA7,#79FA57,#ECFA07,#F3D307,#FAAD07,#F67207,#FA1207", (s, e) =>
            {
                IsoHeightCtrl ihc = s as IsoHeightCtrl;
                ihc.ParseColor();
            }));

        /// <summary>
        /// 绘制图形
        /// </summary>
        private void Draw()
        {
            if (HeightDots == null)
            {
                return;
            }

            w = this.ActualWidth;
            h = this.ActualHeight;
            if (w <= 0 || h <= 0)
            {
                return;
            }

            if (Rs == null)
            {
                ParseColor();
            }

            InitData();
            CreateBitmap();

            float gap = (max - min) / Rs.Length;
            for (int i = 0; i < Rs.Length; i )
            {
                List<List<PointF>> shapes = CreateMapData(min i * gap);
                DrawMap(shapes, i);
            }

            FinishDraw();
        }

        /// <summary>
        /// 数据插值
        /// </summary>
        private void InitData()
        {
            x_num = (int)(w / grid_w);
            y_num = (int)(h / grid_h);
            data = new float[x_num, y_num];

            IntMeasureData[] measure_data = new IntMeasureData[HeightDots.Length];
            for (int i = HeightDots.Length - 1; i >= 0; i--)
            {
                measure_data[i] = new IntMeasureData(HeightDots[i], x_num, y_num);
            }

            min = float.MaxValue;
            max = float.MinValue;
            for (int i = 0; i < x_num; i )
            {
                for (int j = 0; j < y_num; j )
                {
                    float value = 0;
                    bool find = false;
                    foreach (IntMeasureData imd in measure_data)
                    {
                        if (i == imd.X && j == imd.Y)
                        {
                            value = imd.Z;
                            find = true;
                            break;
                        }
                    }

                    if (!find)
                    {
                        double D = 0;
                        double DV = 0;
                        foreach (IntMeasureData imd in measure_data)
                        {
                            double d = 1.0 / ((imd.X - i) * (imd.X - i) (imd.Y - j) * (imd.Y - j));
                            D = d;
                            DV = imd.Z * d;
                        }
                        value = (float)(DV / D);
                    }

                    data[i, j] = value;
                    min = Math.Min(min, value);
                    max = Math.Max(max, value);
                }
            }
        }

        /// <summary>
        /// 创建位图
        /// </summary>
        private void CreateBitmap()
        {
            bitmap_w = (x_num - 1) * grid_w;
            bitmap_h = (y_num - 1) * grid_h;

            bitmap = new Bitmap(bitmap_w, bitmap_h, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            graphics = Graphics.FromImage(bitmap);
        }

        /// <summary>
        /// 获取某个阈值下的图形数据
        /// </summary>
        /// <param name="threshold">阈值</param>
        /// <returns>图形数据</returns>
        private List<List<PointF>> CreateMapData(float threshold)
        {
            byte[,] binary_data = new byte[x_num, y_num];
            for (int i = 0; i < x_num; i )
            {
                for (int j = 0; j < y_num; j )
                {
                    binary_data[i, j] = (byte)((data[i, j] >= threshold) ? 1 : 0);
                }
            }

            List<List<PointF>> shapes = new List<List<PointF>>();
            for (int i = 1; i < x_num; i )
            {
                for (int j = 1; j < y_num; j )
                {
                    int num = (binary_data[i - 1, j - 1] << 3) (binary_data[i, j - 1] << 2) (binary_data[i, j] << 1) binary_data[i - 1, j];
                    List<PointF> points = new List<PointF>();
                    switch (num)
                    {
                        case 0:
                            break;
                        case 1:
                            AddLeft(points, i, j, threshold);
                            AddLeftBottom(points, i, j);
                            AddBottom(points, i, j, threshold);
                            break;
                        case 2:
                            AddRight(points, i, j, threshold);
                            AddRightBottom(points, i, j);
                            AddBottom(points, i, j, threshold);
                            break;
                        case 3:
                            AddLeft(points, i, j, threshold);
                            AddLeftBottom(points, i, j);
                            AddRightBottom(points, i, j);
                            AddRight(points, i, j, threshold);
                            break;
                        case 4:
                            AddTop(points, i, j, threshold);
                            AddRightTop(points, i, j);
                            AddRight(points, i, j, threshold);
                            break;
                        case 5:
                            AddLeft(points, i, j, threshold);
                            AddRightTop(points, i, j);
                            AddRight(points, i, j, threshold);
                            AddBottom(points, i, j, threshold);
                            AddLeftBottom(points, i, j);
                            AddLeft(points, i, j, threshold);
                            break;
                        case 6:
                            AddTop(points, i, j, threshold);
                            AddRightTop(points, i, j);
                            AddRightBottom(points, i, j);
                            AddBottom(points, i, j, threshold);
                            break;
                        case 7:
                            AddTop(points, i, j, threshold);
                            AddRightTop(points, i, j);
                            AddRightBottom(points, i, j);
                            AddLeftBottom(points, i, j);
                            AddLeft(points, i, j, threshold);
                            break;
                        case 8:
                            AddTop(points, i, j, threshold);
                            AddLeftTop(points, i, j);
                            AddLeft(points, i, j, threshold);
                            break;
                        case 9:
                            AddTop(points, i, j, threshold);
                            AddLeftTop(points, i, j);
                            AddLeftBottom(points, i, j);
                            AddBottom(points, i, j, threshold);
                            break;
                        case 10:
                            AddTop(points, i, j, threshold);
                            AddLeftTop(points, i, j);
                            AddLeft(points, i, j, threshold);
                            AddBottom(points, i, j, threshold);
                            AddRightBottom(points, i, j);
                            AddRight(points, i, j, threshold);
                            break;
                        case 11:
                            AddTop(points, i, j, threshold);
                            AddLeftTop(points, i, j);
                            AddLeftBottom(points, i, j);
                            AddRightBottom(points, i, j);
                            AddRight(points, i, j, threshold);
                            break;
                        case 12:
                            AddLeft(points, i, j, threshold);
                            AddRight(points, i, j, threshold);
                            AddRightTop(points, i, j);
                            AddLeftTop(points, i, j);
                            break;
                        case 13:
                            AddRight(points, i, j, threshold);
                            AddRightTop(points, i, j);
                            AddLeftTop(points, i, j);
                            AddLeftBottom(points, i, j);
                            AddBottom(points, i, j, threshold);
                            break;
                        case 14:
                            AddLeft(points, i, j, threshold);
                            AddBottom(points, i, j, threshold);
                            AddRightBottom(points, i, j);
                            AddRightTop(points, i, j);
                            AddLeftTop(points, i, j);
                            break;
                        case 15:
                            AddLeftTop(points, i, j);
                            AddRightTop(points, i, j);
                            AddRightBottom(points, i, j);
                            AddLeftBottom(points, i, j);
                            break;
                    }
                    if (num != 0)
                    {
                        shapes.Add(points);
                    }
                }
            }

            return shapes;
        }

        /// <summary>
        /// 绘制图形
        /// </summary>
        /// <param name="shapes">图形数据</param>
        /// <param name="color_index">颜色索引</param>
        private void DrawMap(List<List<PointF>> shapes, int color_index)
        {
            System.Drawing.Brush brush = new SolidBrush(Color.FromArgb(Rs[color_index], Gs[color_index], Bs[color_index]));
            foreach (List<PointF> shape in shapes)
            {
                graphics.FillPolygon(brush, shape.ToArray());
            }
        }

        /// <summary>
        /// 完成绘制
        /// </summary>
        private void FinishDraw()
        {
            graphics.Dispose();

            Container.Width = bitmap_w;
            Container.Height = bitmap_h;
            Container.Source = BitmapToBitmapSource(bitmap);

            bitmap.Dispose();
        }

        private void AddLeft(List<PointF> list, int x, int y, float threshold)
        {
            list.Add(new PointF((x - 1) * grid_w, (y - 1 V(data[x - 1, y - 1], data[x - 1, y], threshold)) * grid_h));
        }

        private void AddRight(List<PointF> list, int x, int y, float threshold)
        {
            list.Add(new PointF(x * grid_w, (y - 1 V(data[x, y - 1], data[x, y], threshold)) * grid_h));
        }

        private void AddTop(List<PointF> list, int x, int y, float threshold)
        {
            list.Add(new PointF((x - 1 V(data[x - 1, y - 1], data[x, y - 1], threshold)) * grid_w, (y - 1) * grid_h));
        }

        private void AddBottom(List<PointF> list, int x, int y, float threshold)
        {
            list.Add(new PointF((x - 1 V(data[x - 1, y], data[x, y], threshold)) * grid_w, y * grid_h));
        }

        private void AddLeftTop(List<PointF> list, int x, int y)
        {
            list.Add(new PointF((x - 1) * grid_w, (y - 1) * grid_h));
        }

        private void AddRightTop(List<PointF> list, int x, int y)
        {
            list.Add(new PointF(x * grid_w, (y - 1) * grid_h));
        }

        private void AddLeftBottom(List<PointF> list, int x, int y)
        {
            list.Add(new PointF((x - 1) * grid_w, y * grid_h));
        }

        private void AddRightBottom(List<PointF> list, int x, int y)
        {
            list.Add(new PointF(x * grid_w, y * grid_h));
        }

        private float V(float min, float max, float threshold)
        {
            return (threshold - min) / (max - min);
        }

        /// <summary>
        /// 转换颜色列表
        /// </summary>
        private void ParseColor()
        {
            string[] colors = ColorList.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            int color_len = colors.Length;
            Rs = new byte[color_len];
            Gs = new byte[color_len];
            Bs = new byte[color_len];
            for (int i = color_len - 1; i >= 0; i--)
            {
                ParseColor(colors[i], out byte R, out byte G, out byte B);
                Rs[i] = R;
                Gs[i] = G;
                Bs[i] = B;
            }
        }

        private void ParseColor(string str, out byte R, out byte G, out byte B)
        {
            R = Convert.ToByte(str.Substring(1, 2), 16);
            G = Convert.ToByte(str.Substring(3, 2), 16);
            B = Convert.ToByte(str.Substring(5, 2), 16);
        }

        [DllImport("gdi32.dll")]
        private static extern bool DeleteObject(IntPtr hObject);
        /// <summary>
        /// Bitmap转BitmapSource
        /// </summary>
        private BitmapSource BitmapToBitmapSource(Bitmap bitmap)
        {
            IntPtr ptr = bitmap.GetHbitmap();
            BitmapSource result = Imaging.CreateBitmapSourceFromHBitmap(
                ptr, IntPtr.Zero, Int32Rect.Empty,
                BitmapSizeOptions.FromEmptyOptions());
            DeleteObject(ptr);

            return result;
        }
    }

    /// <summary>
    /// 测量数据
    /// </summary>
    public struct MeasureData
    {
        /// <summary>
        /// 初始化测量数据
        /// </summary>
        /// <param name="x">坐标x</param>
        /// <param name="y">坐标y</param>
        /// <param name="z">高度</param>
        public MeasureData(float x, float y, float z)
        {
            X = x;
            Y = y;
            Z = z;
        }

        /// <summary>
        /// 坐标X
        /// </summary>
        public float X;

        /// <summary>
        /// 坐标Y
        /// </summary>
        public float Y;

        /// <summary>
        /// 高度
        /// </summary>
        public float Z;
    }

    internal struct IntMeasureData
    {
        public IntMeasureData(MeasureData md, int x_num, int y_num)
        {
            X = (int)(md.X * x_num);
            if (X >= x_num)
            {
                X = x_num - 1;
            }
            Y = (int)(md.Y * y_num);
            if (Y >= y_num)
            {
                Y = y_num - 1;
            }
            Z = md.Z;
        }

        public int X;
        public int Y;
        public float Z;
    }
}