在数组中存储可变数量的点
Posted
技术标签:
【中文标题】在数组中存储可变数量的点【英文标题】:Store Variable number of points in an array 【发布时间】:2018-05-13 01:03:47 【问题描述】:我有一个图形程序,可以绘制基本图形形状并对其进行一些基本操作。在以前绘制的对象上创建新图形时,没有像您在图形中看到的问题,角度线绘制是可以的。
如果你看下面绘图结果中的黄色圆圈,圆角命令使线条按预期进行圆角,但是我怎样才能使黄色圆圈中的那些先前的线条消失?
一种解决方案可能是无效,但它会清除整个面板,从而清除具有测量角度的面板。
我可以将点存储在一个数组中,并在每次面板无效时调用它来重绘,但两条线有 3 个点。
如果我绘制一个多边形,它可能会超过三个并且会有所不同。
如何在单个数组中存储可变数量的点?
如有需要,我可以提供代码。
List<System.Drawing.Point> PointLine = new List<System.Drawing.Point>();
private void panel1_MouseDown(object sender, MouseEventArgs e)// On mouse down
Graphics g = this.panel1.CreateGraphics();
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
if (dist == false && circ == false)
if (e.Button == System.Windows.Forms.MouseButtons.Right)
mouseisdown = true;
DrawPoint(e.X, e.Y, Color.White);
if (e.Button == System.Windows.Forms.MouseButtons.Left)
leftdown = true;
g.DrawRectangle(RPen, e.X, e.Y, 0.5f, 0.5f);
PointLine.Add(new System.Drawing.Point(e.X, e.Y)); //Add points on each click
PointF[] pts = new PointF[] new PointF(e.X, e.Y) ;
gp.AddLines(pts);
if (PointLine.Count > 1)
DrawLineP(PointLine[PointLine.Count - 2].X, PointLine[PointLine.Count - 2].Y, e.X, e.Y);
else if (dist == true)
if (e.Button == System.Windows.Forms.MouseButtons.Left)
DsP1 = new PointF(e.X, e.Y);
label9.Font = font4;
label10.Font = font3;
g.DrawRectangle(RPen, new System.Drawing.Rectangle(e.X, e.Y, 1, 1));
if (e.Button == System.Windows.Forms.MouseButtons.Right)
DsP2 = new PointF(e.X, e.Y);
double x = DsP1.X - DsP2.X;
double y = DsP1.Y - DsP2.Y;
double d = Math.Abs(x + y);
float midX = (DsP1.X + DsP2.X) / 2;
float midY = (DsP1.Y + DsP2.Y) / 2;
DrawDist(DsP1, DsP2, d, midX, midY, Color.White);
if (circ == true)
if (e.Button == System.Windows.Forms.MouseButtons.Left)
DsP1 = new PointF(e.X, e.Y);
label9.Font = font4;
label10.Font = font3;
g.DrawRectangle(RPen, new System.Drawing.Rectangle(e.X, e.Y, 1, 1));
if (e.Button == System.Windows.Forms.MouseButtons.Right)
DsP2 = new PointF(e.X, e.Y);
double x = DsP1.X - DsP2.X;
double y = DsP1.Y - DsP2.Y;
double d = Math.Abs(x + y);
float midX = (DsP1.X + DsP2.X) / 2;
float midY = (DsP1.Y + DsP2.Y) / 2;
DrawCirc(DsP1, DsP2, Color.White);
if (ModifierKeys == Keys.Shift)
mouseisdown = false;
leftdown = false;
if (e.Button == System.Windows.Forms.MouseButtons.Left)
PointF[] pts = gp.PathPoints;
if (pts.Contains(new PointF(e.X, e.Y)))
MessageBox.Show("Line Selected");
public void DrawCirc(PointF p1, PointF p2, Color color)
Graphics g = this.panel1.CreateGraphics();
int width = (int)(DsP2.X - DsP1.X);
int height = (int)(DsP2.Y - DsP1.Y);
if (width > height || width < height)
width = height;
double radius = (DsP2.Y - DsP1.Y) / 2;
double xloc = (DsP2.X + DsP1.X) / 2;
double yloc = (DsP2.Y + DsP1.Y) / 2;
g.DrawEllipse(new Pen(Color.White, 2f), new System.Drawing.Rectangle((int)DsP1.X, (int)DsP1.Y, width, height));
g.DrawString("R<-- " + radius.ToString(), new System.Drawing.Font("Arial", 7), new SolidBrush(Color.White), new PointF((float)xloc - (DsP2.X - DsP1.X) / 4, (float)yloc - 5));
g.DrawRectangle(Pens.White, new System.Drawing.Rectangle((int)xloc - 5, (int)yloc, 1, 1));
circ = false;
label9.Text = "Radius= " + radius.ToString();
label10.Text = "";
PointLine.Clear();
public void DrawDist(PointF p1, PointF p2, double d, float midX, float midY, Color color)
Graphics g = this.panel1.CreateGraphics();
g.DrawLine(new Pen(Color.Blue, 2F), DsP1, DsP2);
g.DrawRectangle(RPen, new System.Drawing.Rectangle((int)DsP2.X, (int)DsP2.Y, 1, 1));
dist = false;
PointLine.Clear();
label9.Text = "Distance= " + d.ToString();
label10.Text = "";
g.DrawString(d.ToString(), new System.Drawing.Font("Arial", 7), new SolidBrush(Color.White), new PointF(midX + 5, midY));
GraphicsPath gp = new GraphicsPath();
public void DrawLineP(int x1, int y1, int x2, int y2)
Graphics g = this.panel1.CreateGraphics();
g.DrawLine(new Pen(Color.White, 2F), x1, y1, x2, y2);
private void btn_ctr_Click(object sender, EventArgs e)
// Area of Runtime Polygon
for (int i = 0; i < PointLine.Count - 1; i++)
area2 += (PointLine[i].X * PointLine[i + 1].Y) - (PointLine[i].Y * PointLine[i + 1].X);
area2 += (PointLine[PointLine.Count - 1].X * PointLine[0].Y) - (PointLine[PointLine.Count - 1].Y * PointLine[0].X);
label4.Text = "Area";
lbl_area.Text = Math.Abs(Math.Round(area2, 2)).ToString() + " Sq-m";
PointLine.Clear();
private void panel1_MouseUp(object sender, MouseEventArgs e)
mouseisdown = false;
private void DrawGrid()
Graphics g = this.panel1.CreateGraphics();
Pen pen = new Pen(Color.Gray, (float)0.1);
pen.DashStyle = DashStyle.Dash;
for(int i = 0; i <= 1020; i += 10)
for(int j = 0; j <= 645; j += 10)
System.Drawing.Rectangle rec = new System.Drawing.Rectangle(new System.Drawing.Point(i, j), new Size(1, 1));
g.FillRectangle(Brushes.Gray, rec);
// g.DrawLine(pen, new System.Drawing.Point(i, 10), new System.Drawing.Point(i, 640));
private void panel1_Paint(object sender, PaintEventArgs e)
Graphics grp = e.Graphics;
DrawPolygon(grp);
DrawAxes(grp);
DrawGrid();
private void btn_area_Click(object sender, EventArgs e)
area = 0.0f;
parameterY = 0.0f;
paramterX = 0.0f;
parameter_total = 0.0f;
area2 = 0.0f;
// Applying Irregular Polygon Area Algorithm
for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
area += ((float)Convert.ToDouble(dataGridView1.Rows[i].Cells[0].Value) * (float)Convert.ToDouble(dataGridView1.Rows[i + 1].Cells[1].Value)) - ((float)Convert.ToDouble(dataGridView1.Rows[i + 1].Cells[0].Value) * (float)Convert.ToDouble(dataGridView1.Rows[i].Cells[1].Value));
//Add last vertix with respect to start vertix
area += ((float)Convert.ToDouble(dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells[0].Value) * (float)Convert.ToDouble(dataGridView1.Rows[0].Cells[1].Value)) - ((float)Convert.ToDouble(dataGridView1.Rows[0].Cells[0].Value) * (float)Convert.ToDouble(dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells[1].Value));
area = area / 2.0f;
// Algorithm Ends..
//Parameter Length of Polygon
for (int i = 0; i < dataGridView1.Rows.Count - 2; i++)
paramterX += Math.Abs(((float)Convert.ToDouble(dataGridView1.Rows[i + 1].Cells[0].Value) - (float)Convert.ToDouble(dataGridView1.Rows[i].Cells[0].Value)));
parameterY += Math.Abs(((float)Convert.ToDouble(dataGridView1.Rows[i + 1].Cells[1].Value) - (float)Convert.ToDouble(dataGridView1.Rows[i].Cells[1].Value)));
parameter_total = paramterX + parameterY;
label4.Text = "Area";
label5.Text = "Perimeter";
lbl_param.Text = parameter_total.ToString() + " m";
lbl_area.Text = Math.Abs(Math.Round(area, 2)).ToString() + " Sq-m" + " " + Math.Abs(Math.Round(area / 4046, 2)).ToString() + " Acre";
private void panel1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
if (e.KeyCode == Keys.Enter)
Points.AddRange(PointLine);
private void button1_Click(object sender, EventArgs e)
//Change Drawing Color
colorDialog1.ShowDialog();
RPen = new Pen(colorDialog1.Color, 2);
private void btn_clr_Click(object sender, EventArgs e)
PointLine.Clear();
panel2.Hide();
label9.Text = "";
label10.Text = "";
this.panel1.CreateGraphics().Clear(panel1.BackColor);
panel1.Invalidate();
DrawGrid();
DrawAxes(g);
private void btn_angle_Click(object sender, EventArgs e)
// Angle between Lines
if (PointLine.Count >= 3)
angle_select = true;
double angle = Math.Atan2(PointLine[1].Y - PointLine[0].Y, PointLine[1].X - PointLine[0].X) - Math.Atan2(PointLine[2].Y - PointLine[1].Y, PointLine[2].X - PointLine[1].X);
angle = Math.Round((angle * 180) / Math.PI, 0);
angle = 180 - angle;
if (angle > 180)
angle = 360 - angle;
System.Drawing.Font font3 = new System.Drawing.Font("couriner new", 8);
lbl_area.Text = angle.ToString() + "°";
int MPX1 = (PointLine[1].X + PointLine[0].X) / 2;
int MPY1 = (PointLine[1].Y + PointLine[0].Y) / 2;
int MPX2 = (PointLine[2].X + PointLine[1].X) / 2;
int MPY2 = (PointLine[2].Y + PointLine[1].Y) / 2;
System.Drawing.Point MP1 = new System.Drawing.Point(MPX1, MPY1);
System.Drawing.Point MP2 = new System.Drawing.Point(MPX2, MPY2);
//Calculate Midpoint for angle
int MidPointX = (MPX1 + MPX2) / 2;
int MidPointY = (MPY1 + MPY2) / 2;
PointF[] parray = MP1, MP2 ;
RPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
Graphics g = this.panel1.CreateGraphics();
g.DrawString(angle.ToString() + "°", font3, Brushes.Yellow, new System.Drawing.Point(MidPointX - 3, MidPointY + 3));
// g.DrawCurve(new Pen(Color.Yellow), parray, 0.0f);
g.DrawBezier(new Pen(Color.Blue, 2), MP1, new PointF(MP1.X + 40, MP1.Y + 10), MP2, MP2);
panel2.Show();
label9.Text ="Angle: "+ angle.ToString() + "°";
PointLine.Clear();
System.Drawing.Font font3 = new System.Drawing.Font(DefaultFont, FontStyle.Bold);
System.Drawing.Font font4 = new System.Drawing.Font(DefaultFont, FontStyle.Regular);
private void btn_dist_Click(object sender, EventArgs e)
dist = true;
label9.Text = "Select First Point";
label10.Text = "Select Second Point";
label9.Font = font3;
private void button1_Click_1(object sender, EventArgs e)
circ = true;
panel2.Show();
timer1.Start();
label9.Text = "Select first point of Circle";
label9.Font = font3;
label10.Text = "Select Second Piont of Circle";
private void button2_Click(object sender, EventArgs e)
dataGridView1.DataSource = null; //Reset Values
dataGridView1.Rows.Clear();
area = 0.0f;
parameterY = 0.0f;
paramterX = 0.0f;
parameter_total = 0.0f;
label5.Text = "";
label4.Text = "";
lbl_area.Text = "";
lbl_param.Text = "";
/* Microsoft.Office.Interop.Excel.Workbook ExWorkbook; //Excel Object
Microsoft.Office.Interop.Excel.Worksheet ExWorksheet;
Microsoft.Office.Interop.Excel.Range ExRange;
Microsoft.Office.Interop.Excel.Application ExObj = new Microsoft.Office.Interop.Excel.Application();*/
System.Data.DataTable dt = new System.Data.DataTable();
dt.Columns.Add("Point");
openFileDialog1.Filter = "Excel Files|*.txt";
DialogResult result = openFileDialog1.ShowDialog();
if (result == DialogResult.OK) // Test result.
string[] ptText = System.IO.File.ReadAllLines("C:\\Users\\Point.txt");
for (int i = 0; i <= ptText.Length - 1; i++)
DataRow drow = dt.NewRow();
drow["Point"] = ptText[i];
dt.Rows.Add(drow);
dataGridView1.DataSource = dt;
label6.Text = openFileDialog1.FileName;
private void closeToolStripMenuItem_Click(object sender, EventArgs e)
this.Close();
private void linesFillet()
Graphics grp = this.panel1.CreateGraphics();
circ = false;
dist = false;
angle_select = false;
string rad = txt_cmd.Text.Substring(7, txt_cmd.Text.Length - 7);
float radius = (float)Convert.ToDouble(rad);
if (PointLine.Count >= 3)
Fillet(grp, PointLine[0], PointLine[1], PointLine[2], radius);
PointLine.Clear();
private void btn_filletOK_Click(object sender, EventArgs e)
private void angleToolStripMenuItem_Click(object sender, EventArgs e)
btn_angle.PerformClick();
private void enableToolStripMenuItem_Click(object sender, EventArgs e)
DrawGrid();
private void DisableGrid()
PointLine.Clear();
panel2.Hide();
label9.Text = "";
label10.Text = "";
this.panel1.CreateGraphics().Clear(panel1.BackColor);
panel1.Invalidate();
DrawAxes(g);
private void disableToolStripMenuItem_Click(object sender, EventArgs e)
private void SnapToGrid(System.Drawing.Point point)
/* int GridGap = 10;
int x = GridGap * (int)Math.Round((float)point.X / GridGap);
int y = GridGap * (int)Math.Round((float)point.Y / GridGap);
Cursor.Position = new System.Drawing.Point(x, y);*/
foreach (var rec in GridList)
if (rec.Contains(point))
Cursor.Position = new System.Drawing.Point(rec.X, rec.Y);
private void oNToolStripMenuItem_Click(object sender, EventArgs e)
snap = true;
private void snapToolStripMenuItem1_Click(object sender, EventArgs e)
snap = true;
private void button3_Click_2(object sender, EventArgs e)
this.Close();
private void button4_Click(object sender, EventArgs e)
this.WindowState = FormWindowState.Minimized;
private void txt_cmd_KeyDown(object sender, KeyEventArgs e)
if (e.KeyCode == Keys.Enter)
label13.Text += "\n" + txt_cmd.Text;
if (txt_cmd.Text == "angle")
btn_angle.PerformClick();
txt_cmd.Clear();
else if (txt_cmd.Text == "circle")
button1.PerformClick();
txt_cmd.Clear();
else if (txt_cmd.Text == "measure")
btn_dist.PerformClick();
txt_cmd.Clear();
else if (txt_cmd.Text == "polyarea")
btn_ctr.PerformClick();
txt_cmd.Clear();
else if (txt_cmd.Text == "clear")
btn_clr.PerformClick();
txt_cmd.Clear();
else if (txt_cmd.Text == "fillet")
txt_cmd.Text = "Radius:";
else if (txt_cmd.Text.Substring(0,6)=="Radius:")
linesFillet();
txt_cmd.Clear();
else if (txt_cmd.Text == "clear previous commands")
label13.Text = "";
txt_cmd.Clear();
else if (txt_cmd.Text == "exit")
this.Close();
private void textBox4_TextChanged(object sender, EventArgs e)
private void txt_cmd_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
private void Form1_Load(object sender, EventArgs e)
//Cursor CMD
CreateCaret(textBox1.Handle, IntPtr.Zero, 25, 5);
ShowCaret(txt_cmd.Handle);
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
txt_cmd.Focus();
//Fillet
public void Fillet(Graphics g, System.Drawing.Point p1, System.Drawing.Point p, System.Drawing.Point p2, float radius)
//Vector 1
double dx1 = p.X - p1.X;
double dy1 = p.Y - p1.Y;
//Vector 2
double dx2 = p.X - p2.X;
double dy2 = p.Y - p2.Y;
//Angle between vector 1 and vector 2 divided by 2
double angle = (Math.Atan2(dy1, dx1) - Math.Atan2(dy2, dx2)) / 2;
// The length of segment between angular point and the
// points of intersection with the circle of a given radius
double tan = Math.Abs(Math.Tan(angle));
double segment = radius / tan;
//Check the segment
double length1 = GetLength(dx1, dy1);
double length2 = GetLength(dx2, dy2);
double length = Math.Min(length1, length2);
if (segment > length)
segment = length;
radius = (float)(length * tan);
// Points of intersection are calculated by the proportion between
// the coordinates of the vector, length of vector and the length of the segment.
var p1Cross = GetProportionPoint(p, segment, length1, dx1, dy1);
var p2Cross = GetProportionPoint(p, segment, length2, dx2, dy2);
// Calculation of the coordinates of the circle
// center by the addition of angular vectors.
double dx = p.X * 2 - p1Cross.X - p2Cross.X;
double dy = p.Y * 2 - p1Cross.Y - p2Cross.Y;
double L = GetLength(dx, dy);
double d = GetLength(segment, radius);
var circlePoint = GetProportionPoint(p, d, L, dx, dy);
//StartAngle and EndAngle of arc
var startAngle = Math.Atan2(p1Cross.Y - circlePoint.Y, p1Cross.X - circlePoint.X);
var endAngle = Math.Atan2(p2Cross.Y - circlePoint.Y, p2Cross.X - circlePoint.X);
//Sweep angle
var sweepAngle = endAngle - startAngle;
//Some additional checks
if (sweepAngle < 0)
startAngle = endAngle;
sweepAngle = -sweepAngle;
if (sweepAngle > Math.PI)
sweepAngle = Math.PI - sweepAngle;
//Draw result using graphics
var pen = new Pen(Color.White);
g = this.panel1.CreateGraphics();
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.DrawLine(pen, p1, p1Cross);
g.DrawLine(pen, p2, p2Cross);
var left = circlePoint.X - radius;
var top = circlePoint.Y - radius;
var diameter = 2 * radius;
var degreeFactor = 180 / Math.PI;
g.DrawArc(pen, left, top, diameter, diameter,
(float)(startAngle * degreeFactor),
(float)(sweepAngle * degreeFactor));
private double GetLength(double dx, double dy)
return Math.Sqrt(dx * dx + dy * dy);
private PointF GetProportionPoint(PointF point, double segment,
double length, double dx, double dy)
double factor = segment / length;
return new PointF((float)(point.X - dx * factor),
(float)(point.Y - dy * factor));
private void btn_fillet_Click(object sender, EventArgs e)
linesFillet();
【问题讨论】:
使用List<Point>
并在将其传递给绘图方法时调用 .ToArray()
。
对不起,我如何存储多个点?如果我画三角形,它有三个点。所以将这三个点存储在 List您应该基本上将一个形状表示为点数组System.Drawing.Point[]
(或列表List<System.Drawing.Point>
,这样更容易修改)。
然后,您可以将所有形状重新组合到形状列表中,以使它们清晰分开。
所以,你所有的形状一起应该形成一个点数组List<System.Drawing.Point[]>
或点列表List<List<System.Drawing.Point>>
更进一步,正如我对您的问题所评论的那样,从“代码工程”和面向对象的角度来看,将您的形状表示为自己的类 Shape 将是有益的。
这是有道理的,因为您的形状可以代表的不仅仅是一个简单的“点列表”。它们可以有颜色、名称、线条样式等......
此类将点列表作为属性之一,与前面提到的类型相同。
也有利于清晰:形状列表很简单......代码中的List<Shape>
。
【讨论】:
以上是关于在数组中存储可变数量的点的主要内容,如果未能解决你的问题,请参考以下文章