I have a graphics program that draw basic graphical shapes and do some basic operation on it. When creating new graphics over previous drawn objects, there is no problem like you see in figure angle line drawn is OK.
If you look at the yellow circle in the below drawing result, the fillet command made the lines fillet as expected, but how can I make those previous lines in yellow circle disappear ?
One solution could be to invalidate but it clears the whole panel and thus the one with the measured angle.
I can store the points in an array and call it to redraw each time panel invalidate but two lines have 3 points.
If I draw a polygon, it may have more than three and varies.
How do I store a variable number of points in a single array?
I can provide the code, if necessary.
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();
}
}
}
You should basically represent one shape as an array of points System.Drawing.Point[]
(or a list List<System.Drawing.Point>
, that would be easier to modify).
Then, you can regroup all of your shapes in a list of shapes to keep them clearly separated.
So, all your shapes together should form a list of array of points List<System.Drawing.Point[]>
or a list of points list List<List<System.Drawing.Point>>
To go further, and as I commented on your question, on a 'code-engineering' and object-oriented point of view, it would be beneficial to represent your shapes as a their own class Shape.
It would make sense because your shapes could represent more than a simple "list of points". They could have a color, a name, a line style etc...
This class would have the list of points as one of the property, of the same type as mentionned before.
Also beneficial for clarity : the list of shapes would simple be... a List<Shape>
in your code.