本例子是简单的在WinForm程序中实现在坐标系中绘制直线方程,抛物线方程,点。重新学习解析几何方面的知识。
涉及到知识点:
----------------------------------------------------------------------------------------------------------------------
效果图如下:
主要代码如下:
【方程类】
class="code_img_closed" src="/Upload/Images/2017011805/0015B68B3C38AA5B.gif" alt="">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 }logs_code_collapse">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