点的基本操作

点的基本操作

要求
提供空间点数据文本文件,包含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("保存成功!!!");}}}

实现效果如下

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/541105.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

误分区酿苦果,数据恢复有妙方

一、误操作引发分区混乱 在数字化时代的浪潮中&#xff0c;硬盘分区成为我们管理和存储数据的重要手段。然而&#xff0c;误分区这一操作失误&#xff0c;却时常给许多用户带来不小的困扰。误分区&#xff0c;简单来说&#xff0c;就是在对硬盘进行分区操作时&#xff0c;由于…

[云原生] Prometheus之部署 Alertmanager 发送告警

一、Alertmanager 发送告警的介绍 Prometheus 对指标的收集、存储与告警能力分属于 Prometheus Server 和 AlertManager 两个独立的组件&#xff0c;前者仅负责定义告警规则生成告警通知&#xff0c; 具体的告警操作则由后者完成。 Alertmanager 负责处理由 Prometheus Serve…

807补充(十一)(鞍论与随机逼近理论篇)

807补充&#xff08;十一&#xff09;&#xff08;鞍论与随机逼近理论篇&#xff09; 一.高等概率论初步 Theorem: σ − \sigma- σ− 代数,如果样本空间 Ω \Omega Ω 的一系列子集的集合 F \mathcal{F} F 满足: (1) ∅ ∈ F \emptyset \in \mathcal{F} ∅∈F (2) 若 A …

AVCE - AV Evasion Craft Online 更新 8 种加载方式 - 过 WD 等

免责声明&#xff1a;本工具仅供安全研究和教学目的使用&#xff0c;用户须自行承担因使用该工具而引起的一切法律及相关责任。作者概不对任何法律责任承担责任&#xff0c;且保留随时中止、修改或终止本工具的权利。使用者应当遵循当地法律法规&#xff0c;并理解并同意本声明…

LeetCode 热题 100 | 回溯(二)

目录 1 39. 组合总和 2 22. 括号生成 3 79. 单词搜索 菜鸟做题&#xff0c;语言是 C&#xff0c;感冒快好版 关于对回溯算法的理解请参照我的上一篇博客&#xff1b; 在之后的博客中&#xff0c;我将只分析回溯算法中的 for 循环。 1 39. 组合总和 题眼&#xff1a;c…

网站被挂马劫持的解决办法

首先&#xff0c;应该检查网站的DNS记录&#xff0c;以确定是否有人修改了DNS记录。如果发现有人修改了DNS记录&#xff0c;应该立即更改DNS记录&#xff0c;以恢复网站的正常访问。此外&#xff0c;应该检查网站的源代码&#xff0c;以确定是否有人植入了恶意代码。如果发现有…

【Web】浅聊Java反序列化之玩转Hessian反序列化的前置知识

目录 序列化 反序列化 Hessian1.0 Hessian2.0 Hessian反序列化核心&#xff1a;MapDeserializer#readMap的利用 总结 序列化 HessianOutput&Hessian2Output都是抽象类AbstractHessianOutput的实现类 HessianOutput#writeObject和Hessian2Output#writeObject的写法是…

Rocketmq专题-01 v5版单机部署篇

Rocketmq专题 注&#xff1a; 本教程由羞涩梦整理同步发布&#xff0c;本人技术分享站点&#xff1a;blog.hukanfa.com 转发本文请备注原文链接&#xff0c;本文内容整理日期&#xff1a;2024-01-28 csdn 博客名称&#xff1a;五维空间-影子&#xff0c;欢迎关注 说明 地址…

通过spring boot/redis/aspect 防止表单重复提交【防抖】

一、啥是防抖 所谓防抖&#xff0c;一是防用户手抖&#xff0c;二是防网络抖动。在Web系统中&#xff0c;表单提交是一个非常常见的功能&#xff0c;如果不加控制&#xff0c;容易因为用户的误操作或网络延迟导致同一请求被发送多次&#xff0c;进而生成重复的数据记录。要针…

分布式思想

1、单体架构设计存在的问题 传统项目采用单体架构设计,虽然可以在一定的程度上解决企业问题,但是如果功能模块众多,并且将来需要二次开发.由于模块都是部署到同一台tomcat服务器中,如果其中某个模块代码出现了问题,将直接影响整个tomcat服务器运行. 这样的设计耦合性太高.不便…

1335:【例2-4】连通块

【算法分析】 设数组vis&#xff0c;vis[i][j]表示(i,j)位置已经访问过。遍历地图中的每个位置&#xff0c;尝试从每个位置开始进行搜索。如果该位置不是0且没有访问过&#xff0c;那么访问该位置&#xff0c;并尝试从其上下左右四个位置开始搜索。在看一个新的位置时&#xff…

C++ //练习 10.34 使用reverse_iterator逆序打印一个vector。

C Primer&#xff08;第5版&#xff09; 练习 10.34 练习 10.34 使用reverse_iterator逆序打印一个vector。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 代码块 /**************************************************************…