基于Winform开发的逐点比较法直线插补小程序
  azautmtV2Ctp 2023年11月02日 43 0

项目使用VS2019,采用三层架构,UI层,绘图层,插补算法层 。(本人为机械专业初学者,为数控编程课开发的辅助教学小程序,存在诸多不足,请各位大佬多多指正)

基于Winform开发的逐点比较法直线插补小程序_C#

一.UI设计

根据扩展需求,设计若干子窗体嵌入进主窗体中,主窗体只负责打开子窗体

基于Winform开发的逐点比较法直线插补小程序_C#_02

附:打开子窗体的代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace InterpolationDemo
{
    public partial class FrmMain : Form
    {
        public FrmMain()
        {
            InitializeComponent();
        }
        /// <summary>
        /// 通用打开子窗体方法
        /// </summary>
        /// <param name="frm"></param>
        public void OpenForm(Form frm)
        {
            foreach (Control item in this.panel1.Controls)
            {
                if(item is Form)
                {
                    Form currentFrm = (Form)item;
                    currentFrm.Close();
                }
            }
            frm.TopLevel = false;
            frm.FormBorderStyle = FormBorderStyle.None;
            frm.Parent = this.panel1;
            frm.Dock = DockStyle.Fill;
            frm.Show();
        }
        private void 圆弧插补ToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void 直线插补LToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenForm(new FrmLinearInterpolation());
        }
    }
}

直线插补子窗体代码,主要是获取UI输入信息,然后调用自己写的绘图类的方法进行绘制。

因为实现了分层架构,对象职责明确,UI中的代码不涉及算法与具体的GDI功能,只负责调用与绘制

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using DrawingByGDI;
namespace InterpolationDemo
{
    public partial class FrmLinearInterpolation : Form
    {
        private DrawingCoordinate drawingCoordinate = new DrawingCoordinate();
        private DrawingGraph drawingGraph = new DrawingGraph();
        Thread thread = null;
        public FrmLinearInterpolation()
        {
            InitializeComponent();
            btnViewCoordinate_Click(null, null);

            //ViewCoordinate();
        }

        private void ViewCoordinate()
        {
            int maxValue1 = Math.Abs(
                Math.Max(
                    Math.Abs(Convert.ToInt32(txtDestinationX.Text)), Math.Abs(Convert.ToInt32(this.txtDestinationY.Text))
                    )
                );
            int maxValue2 = Math.Abs(
                 Math.Max(
                     Math.Abs(Convert.ToInt32(txtStartX.Text)), Math.Abs(Convert.ToInt32(this.txtStartY.Text))
                     )
                 );
            int maxValue = Math.Max(maxValue1, maxValue2);
            drawingCoordinate.DrawCoordinate(this.panelGraphics, maxValue, 10);
        }
        
        private void btnView_Click(object sender, EventArgs e)
        {
            #region 数据验证
            if (this.txtDestinationX.Text.Trim().Length == 0)
            {
                MessageBox.Show("输入不能为空!");
                this.txtDestinationX.Focus();
                return;
            }
            if (this.txtDestinationY.Text.Trim().Length == 0)
            {
                MessageBox.Show("输入不能为空!");
                this.txtDestinationY.Focus();
                return;
            }
            if (this.txtStartX.Text.Trim().Length == 0)
            {
                MessageBox.Show("输入不能为空!");
                this.txtStartX.Focus();
                return;
            }
            if (this.txtStartY.Text.Trim().Length == 0)
            {
                MessageBox.Show("输入不能为空!");
                this.txtStartY.Focus();
                return;
            }
            if (!IsInteger(this.txtDestinationX.Text.Trim()))
            {
                MessageBox.Show("必须输入一个整数");
                this.txtDestinationX.Focus();
                return;
            }
            if (!IsInteger(this.txtDestinationY.Text.Trim()))
            {
                MessageBox.Show("必须输入一个整数");
                this.txtDestinationY.Focus();
                return;
            }
            if (!IsInteger(this.txtStartX.Text.Trim()))
            {
                MessageBox.Show("必须输入一个整数");
                this.txtStartX.Focus();
                return;
            }
            if (!IsInteger(this.txtStartY.Text.Trim()))
            {
                MessageBox.Show("必须输入一个整数");
                this.txtStartY.Focus();
                return;
            }
            #endregion
            try
            {
                ViewCoordinate();
                Point pi = new Point(Convert.ToInt32(this.txtStartX.Text), Convert.ToInt32(this.txtStartY.Text));
                Point pe = new Point(Convert.ToInt32(this.txtDestinationX.Text), Convert.ToInt32(this.txtDestinationY.Text));
                
                
                thread = new Thread(()=>
                {
                    drawingCoordinate.DrawPoint(this.panelGraphics, pe, pi);
                }
                );
                thread.IsBackground = false;
                thread.Start();
                
            }
            catch (Exception ex)
            {

                throw ex;
            }
         
        }
        private static bool IsInteger(string txt)
        {
            Regex objReg = new Regex("^-?[0-9]+[0-9]*$");
            return objReg.IsMatch(txt);
        }

        private void btnRecover_Click(object sender, EventArgs e)
        {
            thread.Abort();
            drawingCoordinate.DrawClear(this.panelGraphics);
            ViewCoordinate();
        }

        private void FrmLinearInterpolation_Load(object sender, EventArgs e)
        {
            ViewCoordinate();
        }

        private void btnViewCoordinate_Click(object sender, EventArgs e)
        {
            ViewCoordinate();
        }
    }
}

二、逐点比较法算法层

算法简单,主要是四个节拍,网上有大佬解析,这里只粘贴代码。

基本原理,是根据起点和终点利用算法得到中途的点的集合,并返回给GDI,让GDI根据点集进行绘制

这里只做了直线算法的类,圆弧算法还没做

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace AlgorithmInterpolation
{
    public class LinearInterpolation
    {
        public enum Quadrant
        {
            一,
            二,
            三,
            四,
            X正,
            X负,
            Y正,
            Y负,
            原点
        }
        /// <summary>
        /// 只关心从原点开始,通过坐标平移的方式将原直线平移至原点,最后平移回去
        /// </summary>
        /// <param name="pe">终点</param>
        /// <param name="pi">原点</param>
        /// <returns></returns>
        public List<Point> DisEquation(Point peBefore,Point piBefore)
        {
            //1将直线平移到原点
            Point pStart = piBefore;
            Point pe = Translation(peBefore, pStart, 0);
            Point pi = Translation(piBefore, pStart, 0);
            List<Point> pList = new List<Point>();

            pList.Add(pi);

            //终点判别计数器      
            int totalCount = Math.Abs(pe.X) + Math.Abs(pe.Y);
            int f = pi.Y * pe.X - pi.X * pe.Y;
            Quadrant quadrant = JudgeQuadrant(pe, pi);
            switch (quadrant)
            {
                case Quadrant.一:
                    for (int i = 0; i < totalCount; i++)
                    {
                        if (f >= 0)
                        {
                            pi.X++;
                            f -= pe.Y;
                            pList.Add(pi);
                            continue;
                        }
                        else if (f < 0)
                        {
                            pi.Y++;
                            f += pe.X;
                            pList.Add(pi);
                            continue;
                        }

                    }
                    break;
                case Quadrant.二:
                    for (int i = 0; i < totalCount; i++)
                    {
                        if (f >= 0)
                        {
                            pi.X--;
                            f -= pe.Y;
                            pList.Add(pi);
                            continue;
                        }
                        else if (f < 0)
                        {
                            pi.Y++;
                            f -= pe.X;
                            pList.Add(pi);
                            continue;
                        }

                    }
                    break;
                case Quadrant.三:
                    for (int i = 0; i < totalCount; i++)
                    {
                        if (f >= 0)
                        {
                            pi.X--;
                            f += pe.Y;
                            pList.Add(pi);
                            continue;
                        }
                        else if (f < 0)
                        {
                            pi.Y--;
                            f -= pe.X;
                            pList.Add(pi);
                            continue;
                        }

                    }
                    break;
                case Quadrant.四:
                    for (int i = 0; i < totalCount; i++)
                    {
                        if (f >= 0)
                        {
                            pi.X++;
                            f += pe.Y;
                            pList.Add(pi);
                            continue;
                        }
                        else if (f < 0)
                        {
                            pi.Y--;
                            f += pe.X;
                            pList.Add(pi);
                            continue;
                        }

                    }
                    break;
                case Quadrant.X正:
                    for (int i = 0; i < totalCount; i++)
                    {
                        pi.X++;
                        pList.Add(pi);
                    }
                    break;
                case Quadrant.X负:
                    for (int i = 0; i < totalCount; i++)
                    {
                        pi.X--;
                        pList.Add(pi);
                    }
                    break;
                case Quadrant.Y正:
                    for (int i = 0; i < totalCount; i++)
                    {
                        pi.Y++;
                        pList.Add(pi);
                    }
                    break;
                case Quadrant.Y负:
                    for (int i = 0; i < totalCount; i++)
                    {
                        pi.Y--;
                        pList.Add(pi);
                    }
                    break;
                case Quadrant.原点:
                    break;
                default:
                    break;
            }
            //2将直线平移回去
            for (int i = 0; i < pList.Count; i++)
            {
                pList[i] = Translation(pList[i], pStart, 1);
            }
            return pList;
        }

        private Quadrant JudgeQuadrant(Point pe,Point pi)
        {
            //集合的嵌套与多分支哪个算法更好
            if (pe.X > pi.X && pe.Y > pi.Y)
            {
                return Quadrant.一;
            }
             else if (pe.X < pi.X && pe.Y > pi.Y)
            {
                return Quadrant.二;
            }
            else if (pe.X < pi.X && pe.Y < pi.Y)
            {
                return Quadrant.三;
            }
            else if (pe.X > pi.X && pe.Y < pi.Y)
            {
                return Quadrant.四;
            }
            else if (pe.X == pi.X)
            {
                if (pe.Y > pi.Y)
                {
                    return Quadrant.Y正;
                }
                else
                {
                    return Quadrant.Y负;
                }
            }
            else if (pe.Y == pi.Y)
            {
                if (pe.X > pi.X)
                {
                    return Quadrant.X正;
                }
                else
                {
                    return Quadrant.X负;
                }
            }
            else
            {
                return Quadrant.原点;
            }
        }
     /// <summary>
     /// 单个点的平移
     /// </summary>
     /// <param name="pBefore">平移之前的点</param>
     /// <param name="pStart">起始点坐标</param>
     /// <param name="plusOrMinus">正平移或负平移</param>
     /// <returns></returns>
        private Point Translation(Point pBefore,Point pStart,int plusOrMinus)
        {
            Point pLater = new Point();
            if (plusOrMinus == 0)
            {
                pLater.X = pBefore.X - pStart.X;
                pLater.Y = pBefore.Y - pStart.Y;
            }
            else
            {
                pLater.X = pBefore.X + pStart.X;
                pLater.Y = pBefore.Y + pStart.Y;
            }
            return pLater;
        }
    }
}

三.绘图层

绘制一个四象限坐标系,并且根据输入的极限值自动缩放

根据点的集合绘制插补路径

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Windows.Forms;
using AlgorithmInterpolation;
using System.Threading;

namespace DrawingByGDI
{
    public class DrawingCoordinate
    {
        //整体内缩50像素,边距,边距可以用来写字,先保留,不是没有意义
        //定义成静态字段,全局使用
       private  float move = 30f;
        private LinearInterpolation linear = new LinearInterpolation();
        List<Point> pList = null;
        float multipleX = 0;
        float multipleY = 0;

        /// <summary>
        /// 绘制坐标轴
        /// </summary>
        /// <param name="panel">画的容器,画布</param>
        private void DrawXY(Panel panel)
        {
            Graphics g = panel.CreateGraphics();
            //原点坐标
            float newX = panel.Width/2 ;
            float newY = panel.Height/2 ;
            //坐标轴长度
            float lenX = panel.Width - 2 * move;
            float lenY = panel.Height - 2 * move;

            //绘制X轴 ,注意WinForm的坐标系方向
            PointF px1 = new PointF(move, newY);
            PointF px2 = new PointF(panel.Width-move, newY);
            g.DrawLine(new Pen(Brushes.Black, 1), px1, px2);

            //绘制Y轴
            PointF py1 = new PointF(newX, move);
            PointF py2 = new PointF(newX, panel.Height-move);
            g.DrawLine(new Pen(Brushes.Black, 1), py1, py2);

            g.DrawRectangle(new Pen(Brushes.Gray, 0.5f), 1, 1, panel.Width-2, panel.Height-2);

        }
        /// <summary>
        /// 绘制X轴的分值线
        /// </summary>
        /// <param name="panel">容器</param>
        /// <param name="maxX">最大值</param>
        /// <param name="deivide">单侧几等分</param>
        private void DrawXline(Panel panel,float maxValue,int divide)
        {
            //原点坐标
            float newX = panel.Width / 2 ;
            float newY = panel.Height / 2 ;
            //坐标轴长度
            float lenX = panel.Width - 2 * move;
            float lenY = panel.Height - 2 * move;
            multipleX = lenX / 2 / maxValue;
            Graphics g = panel.CreateGraphics();
            Pen penG1 = new Pen(Color.Gray, 1);
            Pen penB1 = new Pen(Color.Black, 1.5f);
            ///绘制正x,原点使用另外的方法绘制
            for (int i = 1; i<=divide; i++)
            {
                PointF p1 = new PointF(lenX/2 * i / divide  + newX, newY-2);
                PointF p2 = new PointF(lenX/2 * i / divide + newX, newY + 2);
                g.DrawLine(penG1, p1, p2);
                string xValue = (maxValue * i/ divide).ToString();
                g.DrawString(xValue, new Font("宋体", 8f), Brushes.Black,
                    new PointF(lenX/2 / divide * i + newX+2, newY+8));
            }
            ///绘制负x,原点使用另外的方法绘制
            for (int i = 1; i <= divide; i++)
            {
                PointF p1 = new PointF(newX-lenX / 2 / divide * i , newY - 2);
                PointF p2 = new PointF(newX - lenX / 2 / divide * i, newY + 2);
                g.DrawLine(penG1, p1, p2);
                string xValue = (maxValue * (-i) / divide).ToString();
                g.DrawString(xValue, new Font("宋体", 8f), Brushes.Black,
                    new PointF(newX - lenX / 2 / divide * i + 2, newY + 8));
            }
            //绘制坐标正值箭头
            
            PointF arrows1 = new PointF(move +lenX,newY);
            PointF arrows2 = new PointF(move + lenX-15, newY+5);
            PointF arrows3 = new PointF(move + lenX-15, newY-5);
            g.DrawLine(penB1, arrows1, arrows2);
            g.DrawLine(penB1, arrows1, arrows3);
            g.DrawString("X", new Font("宋体", 10f), Brushes.Black,
                  new PointF(move + lenX, newY - 20));

        }
        /// <summary>
        /// 绘制Y轴的分值线
        /// </summary>
        /// <param name="panel">容器</param>
        /// <param name="maxY">最大值</param>
        /// <param name="deivide">单侧几等分</param>
        private void DrawYline(Panel panel, float maxValue, int divide)
        {
            //原点坐标
            float newX = panel.Width / 2;
            float newY = panel.Height / 2;
            //坐标轴长度
            float lenX = panel.Width - 2 * move;
            float lenY = panel.Height - 2 * move;
            multipleY = lenY / 2 / maxValue;
            Graphics g = panel.CreateGraphics();
            Pen penG1 = new Pen(Color.Gray, 1);
            Pen penB1 = new Pen(Color.Black, 1.5f);
            ///绘制负Y,原点使用另外的方法绘制(坐标轴相反)
            for (int i = 1; i <= divide; i++)
            {
                PointF p1 = new PointF(newX-2, lenY/2 / divide * i + newY);
                PointF p2 = new PointF(newX+2, lenY/2 / divide * i + newY);
                g.DrawLine(penG1, p1, p2);
                string yValue = (maxValue * -i / divide).ToString();
                g.DrawString(yValue, new Font("宋体", 8f), Brushes.Black,
                    new PointF(newX + 2, lenY/2 / divide * i + newY+4));
            }
            ///绘制正Y,原点使用另外的方法绘制
            for (int i = 1; i <= divide; i++)
            {
                PointF p1 = new PointF(newX - 2, newY-lenY / 2/ divide * i);
                PointF p2 = new PointF(newX + 2, newY-lenY / 2 / divide * i );
                g.DrawLine(penG1, p1, p2);
                string yValue = (maxValue * i / divide).ToString();
                g.DrawString(yValue, new Font("宋体", 8f), Brushes.Black,
                    new PointF(newX + 2, newY - lenY / 2 / divide * i+4));
            }
            //绘制坐标正值箭头

            PointF arrows1 = new PointF(newX, move);
            PointF arrows2 = new PointF(newX-5, move+15);
            PointF arrows3 = new PointF(newX+5, move+15);
            g.DrawLine(penB1, arrows1, arrows2);
            g.DrawLine(penB1, arrows1, arrows3);
            g.DrawString("Y", new Font("宋体", 10f), Brushes.Black,
                  new PointF(newX-20, move));

        }
      
        public void DrawCoordinate(Panel panel,float maxValue,int divide)
        {
            Graphics g = panel.CreateGraphics();
            g.Clear(Color.White);
            DrawXY(panel);
            DrawXline(panel, maxValue, divide);
            DrawYline(panel, maxValue, divide);
        }
        public void DrawPoint(Panel panel, Point pe, Point pi)
        {
           
            //原点坐标
            float newX = panel.Width / 2;
            float newY = panel.Height / 2;
            Graphics g = panel.CreateGraphics();
            

            Pen pen = new Pen(Brushes.Blue, 0.5f);
            Pen pen2 = new Pen(Brushes.Red,1f);
            Pen pen3 = new Pen(Brushes.Blue, 1f);
          
            g.DrawLine(pen2, pe.X * multipleX+ newX, -pe.Y * multipleY + newY, 
                pi.X * multipleX + newX, -pi.Y * multipleY + newY);
            pList = linear.DisEquation(pe, pi);
            foreach (Point item in pList)
            {

                g.DrawEllipse(pen, item.X * multipleX + newX-2, -item.Y * multipleY-2 + newY, 4, 4);
                
            }
            for (int i = 0; i <pList.Count-1; i++)
            {
                g.DrawLine(pen3, pList[i].X * multipleX + newX, -pList[i].Y * multipleY + newY
                    , pList[i + 1].X * multipleX + newX, -pList[i + 1].Y * multipleY + newY);
                Thread.Sleep(300);
            }
            
        }
        public void DrawClear(Panel panel)
        {
            Graphics g = panel.CreateGraphics();
            g.Clear(Color.White);
        }
    }
}


本人尚处学习过程,请大佬多多指正。


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  sX9JkgY3DY86   2023年11月13日   18   0   0 分割线ideText
  nQkVcpdWfLDr   2023年11月13日   35   0   0 DesktopSystem重启
  sX9JkgY3DY86   2023年11月13日   41   0   0 ideTextsed
  sX9JkgY3DY86   2023年11月13日   26   0   0 StackText点击事件
  sX9JkgY3DY86   2023年11月13日   28   0   0 ideTextList
  sX9JkgY3DY86   2023年11月13日   35   0   0 ci控件Text
  sX9JkgY3DY86   2023年11月13日   26   0   0 ideTextflutter
  sX9JkgY3DY86   2023年11月13日   37   0   0 Textsed
azautmtV2Ctp