点的基本操作

点的基本操作

要求
提供空间点数据文本文件,包含ID、name、X、Y四个字段信息,

1)读取数据,并且在窗口中显示点的具体位置,用实心圆绘制。
2)鼠标任意点击三个点,将点连线,用黑色笔刷绘制线。
3)鼠标点击选中其中一条线,将线颜色变为黄色。
4)移动任意一点,将新的坐标信息修改后保存到文本文件中。

思路:1、定义一个点类,存点;定义一个线类,存线数据

​ 2、定义一个服务类,用于处理先关点操作

​ 3、窗口实现

首先是一个点

public  class Point
    {
        public int ID { get; set; }
        public string Name { get;set; }
        public float X { get; set; }
        public float Y { get; set; }

        public Point(int id, string name, float x, float y)
        {
            ID = id;
            Name = name;
            X = x;
            Y = y;
        }
    }

再是一个线

 public   class Line
    {
       
        public List<Point> Coordinates { get; set; }
        public double k{ get; set; }
        public double b{ get; set; }
        public bool isselect { get; set; }
        public Line(List<Point> coords)
        {
            var pt1 = coords[0];
            var pt2 = coords[1];
            Coordinates = coords;
            this.k = (pt2.Y - pt1.Y) / (pt2.X - pt1.X);
            this.b = pt1.Y - k * pt1.X;
            isselect = false;
        }
    }

再是相关服务类

public class PointService
    {
         //读取数据
        public List<Point> ReadToFile(string filepath)
        {
            List<Point> pts = new List<Point>();
            StreamReader sr = new StreamReader(filepath);
            while (!sr.EndOfStream)
            {
                var str = sr.ReadLine();
                var str1 = str.Split(',');
                pts.Add(new Point(Int32.Parse(str1[0]), str1[1], float.Parse(str1[2]), float.Parse(str1[3])));
            }

            return pts;
        }
			//保存数据
        public void SaveToFile(List<Point> pts, string filepath)
        {
            StreamWriter sw = new StreamWriter(filepath);
            foreach (var pt in pts)
            {
                sw.WriteLine(pt.ID+","+pt.Name+","+pt.X+","+pt.Y);
            }
            sw.Close();
        }
		//获取选择点
        public Point getPoint(List<Point> pts, float x, float y)
        {
            Point nearestPoint = null;
            float minDistance = float.MaxValue;

            foreach (var point in pts)
            {
                //这里用float.parse会报错,该方法将string转化为float,不可以在这里用
                float distance = (float)(Math.Sqrt(Math.Pow(x-point.X,2) + Math.Pow(y - point.Y, 2)));
                if (distance < minDistance)
                {
                    minDistance = distance;
                    nearestPoint = point;
                }
            }

            // 可能需要增加一定的阈值来确认点击有效
            return minDistance <=4.5  ? nearestPoint : null;

          
        }

        // 根据给定点查找最近的线要素
        public Line FindNearestLineFeature(List<Line> lines, Point point)
        {
            Line nearestLine = null;
            double minDistance = float.MaxValue;

            // 遍历所有线要素,计算每条线与指定点的距离
            foreach (var line in lines)
            {
                double distance = CalculateDistance(line, point); // 假设存在一个计算距离的方法

                // 如果当前线距指定点的距离小于已找到的最近距离,则更新结果
                if (distance < minDistance)
                {
                    minDistance = distance;
                    nearestLine = line;
                }
            }

            return nearestLine;
        }
        // 计算线要素与点之间的最小距离(实际项目中需使用GIS相关的空间分析算法)
        private double CalculateDistance(Line line, Point point)
        {
            var pt1 = line.Coordinates[0];
            var pt2 = line.Coordinates[1];
            // 这里仅作占位符,实际应实现点到线段的最短距离算法
            return Math.Abs(line.k * point.X - point.Y + line.b) / Math.Sqrt(line.k * line.k + 1);
        }
        
    }

窗口类

  public partial class Form1 : Form
    {
        public List<Point> pts = new List<Point>();//存所有点
        public PointService P = new PointService();//点相关服务初始化
        public List<Point> selectedPoints = new List<Point>();//存用于连成线的点
        List<Line> lines = new List<Line>(); // 存储线条对应的点集合,这个用法是真牛逼,但感觉没有
        Dictionary<int, bool> highlightedLines = new Dictionary<int, bool>(); // 用于记录被高亮的线条
        Pen blackPen = new Pen(Color.Black);
        Pen yellowPen = new Pen(Color.Yellow);
		//这里三个参数通过按钮控制,来控制picturebox中点击事件触发对象
        public bool isSelectPoint = false;//是否选择点
        public bool isSelectLine = false;//是否选择线
        public bool isMovePoint = false;//是否移动线
          //临时存点
        public Point CPoint=null;//选择的移动点
        public Form1()
        {
            InitializeComponent();
        }

        public void drawpicture()
        {

        }
        private void button1_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                pts = P.ReadToFile(openFileDialog1.FileName);
                foreach (var pt in pts)
                {
                    richTextBox1.Text += pt.ID + "\t" + pt.Name + "\t" + pt.X + "\t" + pt.Y + "\n";
                }
                // 触发PictureBox的重绘
                pictureBox1.Invalidate();

            }
            else
            {
                MessageBox.Show("读取失败");
            }
        }

        private void pictureBox1_Click(object sender, EventArgs e)
        {
           
        }
        //这个是picture自带的事件,该事件触发需要调用对应函数,否则不会主动刷新
        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            foreach (var point in pts)
            {
                e.Graphics.FillEllipse(Brushes.Black, new RectangleF(point.X, point.Y, 5, 5));
            }

            foreach (var line in lines)
            {
                var start = line.Coordinates[0];
                        var end = line.Coordinates[1];
                        DrawLine(e.Graphics, start, end, line.isselect? yellowPen : blackPen);//这个用法可以记录一下
            }
        }
          
        private void DrawLine(Graphics g, Point start, Point end, Pen pen)
        {
            g.DrawLine(pen, new PointF(start.X, start.Y), new PointF(end.X, end.Y));
        }
          
     

        private void button2_Click(object sender, EventArgs e)
        {
            isSelectPoint = true;
            isSelectLine = false;
            isMovePoint = false;
        }

        private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
        {
            try
            {
                //启动找点
                if (isSelectPoint && !isSelectLine)
                {
                    var pt = P.getPoint(pts, e.X, e.Y);
                    if (pt != null)
                    {
                        selectedPoints.Add(pt);
                    }

                    if (selectedPoints.Count == 3)
                    {
                        for (int i = 0; i < selectedPoints.Count; i++)
                        {
                            List<Point> ptsList = new List<Point>();
                            ptsList.Add(selectedPoints[i]);
                            ptsList.Add(selectedPoints[(i + 1) % 3]);
                            Line line = new Line(ptsList);
                            lines.Add(line);
                        }

                    }
                    pictureBox1.Invalidate();
                }
                //找线
                if (!isSelectPoint && isSelectLine)
                {
                   int i= lines.IndexOf(P.FindNearestLineFeature(lines, new Point(0, "t", e.X, e.Y)));
                   lines[i].isselect = true;
                   pictureBox1.Invalidate();
                }

            }
            catch (Exception exception)
            {
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            isSelectPoint = false;
            isSelectLine = true;
            isMovePoint = false;
        }

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (isMovePoint)
            {
                CPoint = P.getPoint(pts, e.X, e.Y);
            }
        }

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (isMovePoint)
            {
                if (CPoint != null)
                {
                    CPoint.Y = e.Y;
                    CPoint.X = e.X;
                    pts[pts.IndexOf(CPoint)] = CPoint;
                    pictureBox1.Invalidate();
                }
            }
        }

        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            if (isMovePoint)
            {
                CPoint = null;
            }
        }

        private void button4_Click(object sender, EventArgs e)
        {
            isSelectPoint = false;
            isSelectLine = false;
            isMovePoint = true;
        }

        private void button5_Click(object sender, EventArgs e)
        {
            if (saveFileDialog1.ShowDialog()==DialogResult.OK)
            {
                P.SaveToFile(pts,saveFileDialog1.FileName);
                MessageBox.Show("保存成功!!!");
            }
        }
    }

实现效果如下

在这里插入图片描述

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雲墨知秋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值