首页 > Windows开发 > 详细

C# 简单实现直线方程,抛物线方程

时间:2017-01-17 23:09:01      阅读:401      评论:0      收藏:0      [点我收藏+]

本例子是简单的在WinForm程序中实现在坐标系中绘制直线方程,抛物线方程,点。重新学习解析几何方面的知识。

涉及到知识点:

  • 直线方程的表达方式:一般表达式Ax+By+C=0
  • 抛物线表达式:y=Ax2+Bx+C
  • 坐标转换:由于WinForm中的坐标原点是左上角,数学二维坐标系的原点是在中间,所以需要转换
  • 单位转换:WinForm的单位是Pixls,但坐标系的单位不是,需要进行缩放。
  • 画图方法:程序中使用GDI+进行画图。

----------------------------------------------------------------------------------------------------------------------

效果图如下:

技术分享

主要代码如下:

【方程类】

技术分享
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 
  6 namespace DemoGeometry
  7 {
  8     /// <summary>
  9     /// 方程基类
 10     /// </summary>
 11     public abstract class Equation
 12     {
 13         public int A { get; set; }
 14         public int B { get; set; }
 15         public int C { get; set; }
 16 
 17         /// <summary>
 18         /// 判断是否有效
 19         /// </summary>
 20         /// <returns></returns>
 21         public abstract bool IsValid();
 22 
 23         /// <summary>
 24         /// 通过Y值获取x值
 25         /// </summary>
 26         /// <param name="y"></param>
 27         /// <returns></returns>
 28         public abstract float GetValueFromY(float y);
 29         /// <summary>
 30         /// 通过X获取Y值
 31         /// </summary>
 32         /// <param name="x"></param>
 33         /// <returns></returns>
 34         public abstract float GetValueFromX(float x);
 35     }
 36 
 37     /// <summary>
 38     /// 直线方程类一般式:Ax+By+C=0(A、B不同时为0)【适用于所有直线】
 39     /// </summary>
 40     public class LinearEquation:Equation
 41     {
 42         /// <summary>
 43         /// 通过X值得到Y值
 44         /// </summary>
 45         /// <param name="x"></param>
 46         /// <returns></returns>
 47         public override float GetValueFromX(float x)
 48         {
 49             if (B == 0)
 50             {
 51                 return float.MaxValue;
 52             }
 53             return -A * x * 1.0f / B - C * 1.0f / B;
 54         }
 55 
 56         public override float GetValueFromY(float y)
 57         {
 58             if (A == 0)
 59             {
 60                 return float.MaxValue;
 61             }
 62             return -B * y * 1.0f / A - C * 1.0f / A;
 63         }
 64 
 65         /// <summary>
 66         /// 判断是否有效方程
 67         /// </summary>
 68         /// <returns></returns>
 69         public override bool IsValid()
 70         {
 71             bool flag = true;
 72             if (A == 0 && B == 0)
 73             {
 74                 flag = false;
 75             }
 76             return flag;
 77         }
 78 
 79         public override string ToString()
 80         {
 81             return string.Format("{0}x+{1}y+{2}=0", A, B, C);
 82         }
 83     }
 84 
 85     /// <summary>
 86     /// 抛物线方程表达式 y=ax2+bx+c
 87     /// </summary>
 88     public class ParabolicEquation:Equation
 89     {
 90 
 91         /// <summary>
 92         /// 判断是否有效的方程
 93         /// </summary>
 94         /// <returns></returns>
 95         public override bool IsValid()
 96         {
 97             //A 不得等于0
 98             return A != 0;
 99         }
100 
101         /// <summary>
102         /// 通过X值得到Y值
103         /// </summary>
104         /// <param name="x"></param>
105         /// <returns></returns>
106         public override float GetValueFromX(float x)
107         {
108             double y = A * Math.Pow(x, 2) + B * x + C;
109             return float.Parse(y.ToString());
110         }
111 
112         public override float GetValueFromY(float y)
113         {
114             return 0.0f;
115         }
116     }
117 }
View Code

【控件类】

技术分享
  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Drawing;
  5 using System.Data;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Windows.Forms;
  9 
 10 namespace DemoGeometry
 11 {
 12     /// <summary>
 13     /// 坐标系控件
 14     /// </summary>
 15     public partial class AxisControl : UserControl
 16     {
 17         #region 属性
 18 
 19         private Axis _AxisX = new Axis() {  XName = "x" };
 20         /// <summary>
 21         /// X轴
 22         /// </summary>
 23         public Axis AxisX { get { return this._AxisX; }  }
 24 
 25         private Axis _AxisY = new Axis() { XName = "y" };
 26         /// <summary>
 27         /// Y轴
 28         /// </summary>
 29         public Axis AxisY { get { return this._AxisY; } }
 30 
 31         /// <summary>
 32         /// 边界留空白
 33         /// </summary>
 34         private int bound = 10;
 35 
 36         public int Bound
 37         {
 38             get { return bound; }
 39             set { bound = value; }
 40         }
 41 
 42         /// <summary>
 43         /// 表示单位,10个像素表示1
 44         /// </summary>
 45         private int unit = 30;
 46 
 47         public int Unit
 48         {
 49             get { return unit; }
 50             set { unit = value; }
 51         }
 52 
 53         /// <summary>
 54         /// 文本字体
 55         /// </summary>
 56         private Font t_Font = new Font("Arial", 10F);
 57 
 58         private PointF center;
 59 
 60         private int index = 0;
 61 
 62         private int lineWidth = 2;
 63 
 64         #endregion
 65 
 66         public AxisControl()
 67         {
 68             InitializeComponent();
 69         }
 70 
 71         private void InitInfo() {
 72             //绘制坐标轴
 73             var width = this.Width * 1.0f;
 74             var height = this.Height * 1.0f;
 75             center = new PointF(width / 2, height / 2);
 76         }
 77 
 78         /// <summary>
 79         /// 重绘界面函数
 80         /// </summary>
 81         /// <param name="e"></param>
 82         protected override void OnPaint(PaintEventArgs e)
 83         {
 84             base.OnPaint(e);
 85             InitInfo();
 86             Graphics g = e.Graphics;
 87             var width = this.Width * 1.0f;
 88             var height = this.Height * 1.0f;
 89             Pen pen = new Pen(Color.Black);
 90             var left = new PointF(bound,center.Y);//
 91             var right = new PointF(width - bound, center.Y);
 92             var bottom = new PointF(center.X, height - bound);
 93             var top = new PointF(center.X, bound);
 94             g.DrawString("0", t_Font, Brushes.Black, new PointF(center.X + bound/2, center.Y+bound/2));
 95             //画X轴,X轴的箭头
 96             g.DrawLine(pen, left, right);
 97             g.DrawLine(pen, new PointF(right.X - bound/2, right.Y - bound/2), right);
 98             g.DrawLine(pen, new PointF(right.X - bound/2, right.Y + bound/2), right);
 99             var xName = string.IsNullOrEmpty(this._AxisX.XName) ? "x" : this._AxisX.XName;
100             g.DrawString(xName, t_Font, Brushes.Black, new PointF(right.X - bound, right.Y + 2 * bound));
101             //绘制X轴的刻度
102             var xMax = Math.Floor((right.X - left.X) / (2*unit));//
103             this._AxisX.Max = int.Parse( xMax.ToString());
104             for (var i = 0; i < xMax; i++) {
105                 //正刻度
106                 g.DrawLine(pen, new PointF(center.X + (i + 1) * unit, center.Y), new PointF(center.X + (i + 1) * unit, center.Y - 2));
107                 g.DrawString((i + 1).ToString(), t_Font, Brushes.Black, new PointF(center.X + (i + 1) * unit, center.Y+2));
108                 //负刻度
109                 g.DrawLine(pen, new PointF(center.X - (i + 1) * unit, center.Y), new PointF(center.X - (i + 1) * unit, center.Y - 2));
110                 g.DrawString("-"+(i + 1).ToString(), t_Font, Brushes.Black, new PointF(center.X - (i + 1) * unit, center.Y + 2));
111             }
112             //画Y轴,Y轴的箭头
113             g.DrawLine(pen, bottom, top);
114             g.DrawLine(pen, new PointF(top.X - bound/2, top.Y + bound/2), top);
115             g.DrawLine(pen, new PointF(top.X + bound/2, top.Y + bound/2), top);
116             var yName = string.IsNullOrEmpty(_AxisY.XName) ? "y" : _AxisY.XName;
117             g.DrawString(AxisY.XName, t_Font, Brushes.Black, new PointF(top.X + 2 * bound, top.Y - bound));
118             //绘制Y轴的刻度
119             var yMax = Math.Floor((bottom.Y - top.Y) / (2 * unit));//
120             this._AxisY.Max = int.Parse(yMax.ToString());
121             for (var i = 0; i < yMax; i++)
122             {
123                 //正刻度
124                 g.DrawLine(pen, new PointF(center.X , center.Y- (i + 1) * unit), new PointF(center.X+ 2 , center.Y- (i + 1) * unit ));
125                 g.DrawString((i + 1).ToString(), t_Font, Brushes.Black, new PointF(center.X+ 2 , center.Y- (i + 1) * unit));
126                 //负刻度
127                 g.DrawLine(pen, new PointF(center.X, center.Y + (i + 1) * unit), new PointF(center.X+ 2, center.Y + (i + 1) * unit ));
128                 g.DrawString("-" + (i + 1).ToString(), t_Font, Brushes.Black, new PointF(center.X+ 2 , center.Y+ (i + 1) * unit ));
129             }
130         }
131 
132         /// <summary>
133         /// 判断直线方程是否在坐标轴范围内
134         /// </summary>
135         /// <param name="linear"></param>
136         /// <returns></returns>
137         public bool CheckLineIsValid(LinearEquation linear)
138         {
139             bool flagX = false;
140             bool flagY = false;
141             var y = linear.GetValueFromX(0f);
142 
143             //判断y坐标的值有没有越界
144             if (y == float.MaxValue)
145             {
146                 //表示是垂直于x轴的直线
147                 var x0 = -linear.C*1.0f / linear.A;
148                 if (x0 >= 0 - this._AxisX.Max && x0 < this._AxisX.Max)
149                 {
150                     flagY = true;
151                 }
152                 else
153                 {
154                     flagY = false;
155                 }
156                 
157             }
158             else
159             {
160                 if (y <= this._AxisY.Max && y >= 0 - this._AxisY.Max)
161                 {
162                     flagY = true;
163                 }
164                 else
165                 {
166                     flagY = false;
167                 }
168             }
169             //判断x坐标的值
170             var x = linear.GetValueFromY(0f);
171             if (x == float.MaxValue)
172             {
173                 var y0 = -linear.C*1.0f / linear.B;
174 
175                 if (y0 <= this._AxisY.Max && y0 >= 0 - this._AxisY.Max)
176                 {
177                     flagX = true;
178                 }
179                 else
180                 {
181                     flagX = false;
182                 }
183             }
184             else
185             {
186                 if (x <= this._AxisX.Max && x >= 0 - this._AxisX.Max)
187                 {
188                     flagX = true;
189                 }
190                 else
191                 {
192                     flagX = false;
193                 }
194             }
195 
196             return flagX && flagY;//只有x,y都满足条件,才是有效的
197         }
198 
199         /// <summary>
200         /// 判断点是否在坐标轴范围内
201         /// </summary>
202         /// <returns></returns>
203         public bool CheckPointIsValid(PointF point)
204         {
205             bool flagX = false;
206             bool flagY = false;
207             if (point.X <= this._AxisX.Max && point.X >= 0 - this._AxisX.Max)
208             {
209                 flagX = true;
210             }
211             if (point.Y <= this._AxisY.Max && point.Y >= 0 - this._AxisY.Max)
212             {
213                 flagY = true;
214             }
215             return flagX && flagY;
216         }
217 
218         /// <summary>
219         /// 检查抛物线方程是否有效
220         /// </summary>
221         /// <param name="parabolic"></param>
222         /// <returns></returns>
223         public bool CheckParabolicIsValid(ParabolicEquation parabolic) {
224             List<PointF> lstPoint = GetPointFromEquation(parabolic);
225             if (lstPoint.Count > 2)
226             {
227                 return true;
228             }
229             else {
230                 return false;
231             }
232         }
233 
234         /// <summary>
235         /// 将刻度转换成像素
236         /// </summary>
237         public List<PointF> ConvertScaleToPixls(List<PointF> lstScale)
238         {
239             List<PointF> lstPixls = new List<PointF>();
240             if (lstScale != null && lstScale.Count > 0) {
241                 var p = lstScale.Select(s => new PointF(center.X + s.X * unit, center.Y - s.Y * unit));
242                 lstPixls = p.ToList();
243             }
244             return lstPixls;
245         }
246 
247         /// <summary>
248         /// 转换刻度到像素
249         /// </summary>
250         /// <param name="s"></param>
251         /// <returns></returns>
252         public PointF ConvertScaleToPixls(PointF s)
253         {
254             return new PointF(center.X + s.X * unit, center.Y - s.Y * unit);
255         }
256 
257         /// <summary>
258         /// 生成直线
259         /// </summary>
260         /// <param name="linear"></param>
261         public bool GenerateLinear(LinearEquation linear) {
262 
263             Color lineColor = Color.Blue;//线条的颜色
264             Graphics g = this.CreateGraphics();
265             //分别获取两个端点的值,连成线即可
266             var x1 = this._AxisX.Max;
267             var y2 = this._AxisY.Max;
268             var x3 = 0 - this._AxisX.Max;
269             var y4 = 0 - this._AxisY.Max;
270             var y1 = linear.GetValueFromX(x1);
271             var x2 = linear.GetValueFromY(y2);
272             var y3 = linear.GetValueFromX(x3);
273             var x4 = linear.GetValueFromY(y4);
274             var point1 = new PointF(x1, y1);
275             var point2 = new PointF(x2, y2);
276             var point3 = new PointF(x3, y3);
277             var point4 = new PointF(x4, y4);
278             List<PointF> lstTmp = new List<PointF>() { point1, point2, point3, point4 };
279             List<PointF> lstPoint=new List<PointF>();
280             foreach (PointF point in lstTmp)
281             {
282                 //判断点是否合理
283                 if (CheckPointIsValid(point))
284                 {
285                     lstPoint.Add(point);
286                 }
287             }
288             if (lstPoint.Count() < 2) {
289                 //如果点的个数小于2,不能绘制直线
290                 return false;
291             }
292             //将刻度点,转换成像素点
293             List<PointF> lstPixlsPoint = ConvertScaleToPixls(lstPoint);
294             g.DrawLine(new Pen(lineColor,lineWidth),lstPixlsPoint[0],lstPixlsPoint[1]);
295             g.DrawString(string.Format("L{0}", index), t_Font, Brushes.Black, new PointF(lstPixlsPoint[1].X + 2, lstPixlsPoint[1].Y - 2));
296             this.lblInfo.Text += string.Format("L{0}:{1}x+{2}y+{3}=0 ; ", index, linear.A, linear.B, linear.C);
297             index++;
298             return true;
299         }
300 
301         /// <summary>
302         /// 生成点
303         /// </summary>
304         /// <param name="point"></param>
305         /// <returns></returns>
306         public bool GeneratePoint(PointF point)
307         {
308             Graphics g = this.CreateGraphics();
309             PointF p = ConvertScaleToPixls(point);
310             g.FillEllipse(Brushes.Red, p.X, p.Y, 4, 4);
311             g.DrawString(string.Format("P{0}", index), t_Font, Brushes.Black, new PointF(p.X + 4, p.Y - 4));
312             this.lblInfo.Text += string.Format("P{0}:({1},{2}) ; ", index, point.X, point.Y);
313             index++;
314             return true;
315         }
316 
317         public bool GenerateParabolic(ParabolicEquation parabolic)
318         {
319             List<PointF> lstPoint = GetPointFromEquation(parabolic);
320             //将刻度点,转换成像素点
321             List<PointF> lstPixlsPoint = ConvertScaleToPixls(lstPoint);
322             Color lineColor = Color.SeaGreen;//线条的颜色
323             Graphics g = this.CreateGraphics();
324             g.DrawCurve(new Pen(lineColor,lineWidth), lstPixlsPoint.ToArray());
325             g.DrawString(string.Format("P{0}", index), t_Font, Brushes.Black, new PointF(lstPixlsPoint[1].X + 2, lstPixlsPoint[1].Y - 2));
326             this.lblInfo.Text += string.Format("P{0}:y={1}x2+{2}x+{3} ; ", index, parabolic.A, parabolic.B, parabolic.C);
327             index++;
328             return true;
329         }
330 
331         /// <summary>
332         /// 从抛物线方程中取点值
333         /// </summary>
334         /// <param name="parabolic"></param>
335         /// <returns></returns>
336         public List<PointF> GetPointFromEquation(ParabolicEquation parabolic) {
337             List<PointF> lstPoint = new List<PointF>();
338             //从坐标轴最小值开始,隔0.5 取一个
339             int j=0;
340             for (float i = 0 - this._AxisX.Max; i <= this._AxisX.Max; i = i + 0.5f)
341             {
342                 PointF p = new PointF(i, parabolic.GetValueFromX(i));
343                 //再判断点是否在坐标轴内
344                 if (CheckPointIsValid(p) && (j==0 || lstPoint[j-1].X==i-0.5f))
345                 {
346                     lstPoint.Add(p);//抛物线内的点应该是连续的
347                     j++;
348                 }
349             }
350             return lstPoint;
351         }
352 
353         /// <summary>
354         /// 清除已经画上去的线条
355         /// </summary>
356         /// <returns></returns>
357         public bool Clear() {
358             Graphics g = this.CreateGraphics();
359             g.Clear(Color.White);
360             this.lblInfo.Text = "";
361             this.Refresh();//重新刷新界面,清除已经画上去的线条
362             index = 0;
363             return true;
364         }
365     }
366 
367     /// <summary>
368     /// 坐标轴描述
369     /// </summary>
370     public class Axis{
371 
372         /// <summary>
373         /// 刻度表示最大值
374         /// </summary>
375         public int Max { get; set; }
376 
377         /// <summary>
378         /// 名称
379         /// </summary>
380         public string XName{get;set;}
381 
382         ///// <summary>
383         ///// 间隔
384         ///// </summary>
385         //public int Interval{get;set;}
386     }
387 }
View Code

【主界面类】

技术分享
  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Windows.Forms;
  9 
 10 namespace DemoGeometry
 11 {
 12     public partial class MainForm : Form
 13     {
 14         public MainForm()
 15         {
 16             InitializeComponent();
 17         }
 18 
 19         private void btnLine_Click(object sender, EventArgs e)
 20         {
 21             if (this.linearControl1.IsValid())
 22             {
 23                 var a = this.linearControl1.A;
 24                 var b = this.linearControl1.B;
 25                 var c = this.linearControl1.C;
 26                 //判断方程的参数,是否有效
 27                 LinearEquation linear = new LinearEquation() { A = a, B = b, C = c };
 28                 if (!linear.IsValid())
 29                 {
 30                     MessageBox.Show("输入的方程参数无效");
 31                     return;
 32                 }
 33                 if (!this.axisControl1.CheckLineIsValid(linear))
 34                 {
 35                     MessageBox.Show("输入的方程不在坐标轴内");
 36                     return;
 37                 }
 38                 bool flag = this.axisControl1.GenerateLinear(linear);
 39                 if (!flag)
 40                 {
 41                     MessageBox.Show("生成直线失败");
 42                     return;
 43                 }
 44             }
 45         }
 46 
 47         private void btnClear_Click(object sender, EventArgs e)
 48         {
 49             this.axisControl1.Clear();
 50         }
 51 
 52         private void btnPoint_Click(object sender, EventArgs e)
 53         {
 54             if (this.pointControl1.IsValid())
 55             {
 56                 float x = this.pointControl1.X;
 57                 float y = this.pointControl1.Y;
 58                 PointF point = new PointF(x, y);
 59                 if (!this.axisControl1.CheckPointIsValid(point)) {
 60                     MessageBox.Show("输入的点不在坐标轴内");
 61                     return;
 62                 }
 63                 bool flag = this.axisControl1.GeneratePoint(point);
 64                 if (!flag)
 65                 {
 66                     MessageBox.Show("生成点失败");
 67                     return;
 68                 }
 69             }
 70             
 71         }
 72 
 73         private void btnParabolic_Click(object sender, EventArgs e)
 74         {
 75             if (this.parabolicControl1.IsValid())
 76             {
 77                 var a = this.parabolicControl1.A;
 78                 var b = this.parabolicControl1.B;
 79                 var c = this.parabolicControl1.C;
 80                 //判断方程的参数,是否有效
 81                 ParabolicEquation parabolic = new ParabolicEquation() { A = a, B = b, C = c };
 82                 if (!parabolic.IsValid())
 83                 {
 84                     MessageBox.Show("输入的方程参数无效");
 85                     return;
 86                 }
 87                 if (!this.axisControl1.CheckParabolicIsValid(parabolic))
 88                 {
 89                     MessageBox.Show("输入的方程不在坐标轴内");
 90                     return;
 91                 }
 92                 bool flag = this.axisControl1.GenerateParabolic(parabolic);
 93                 if (!flag)
 94                 {
 95                     MessageBox.Show("生成抛物线失败");
 96                     return;
 97                 }
 98             }
 99         }
100     }
101 }
View Code

 

C# 简单实现直线方程,抛物线方程

原文:http://www.cnblogs.com/hsiang/p/6294864.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!