在数组中存储可变数量的点

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&lt;Point&gt; 并在将其传递给绘图方法时调用 .ToArray() 对不起,我如何存储多个点?如果我画三角形,它有三个点。所以将这三个点存储在 List 中。如果我画 Pengatogn,它有 5 个点,所以我将这 5 个点再次存储在 List 中。我如何从该列表中调用三角形的点,以便可以在无效和五边形的 5 点上重绘它。谢谢 一般来说,如果你有一些代码,你应该提供你现有的代码,以表明你确实尝试了一些东西。 每个形状应该有一个点数组(因此数组的大小是需要按顺序链接的正确点数。如果您可以有多个形状,那么您应该存储点数组。(形状数组) 你能给我一些形状数组的例子吗?谢谢 【参考方案1】:

您应该基本上将一个形状表示为点数组System.Drawing.Point[](或列表List&lt;System.Drawing.Point&gt;,这样更容易修改)。

然后,您可以将所有形状重新组合到形状列表中,以使它们清晰分开。

所以,你所有的形状一起应该形成一个点数组List&lt;System.Drawing.Point[]&gt;或点列表List&lt;List&lt;System.Drawing.Point&gt;&gt;


更进一步,正如我对您的问题所评论的那样,从“代码工程”和面向对象的角度来看,将您的形状表示为自己的类 Shape 将是有益的。

这是有道理的,因为您的形状可以代表的不仅仅是一个简单的“点列表”。它们可以有颜色、名称、线条样式等......

此类将点列表作为属性之一,与前面提到的类型相同。

也有利于清晰:形状列表很简单......代码中的List&lt;Shape&gt;

【讨论】:

以上是关于在数组中存储可变数量的点的主要内容,如果未能解决你的问题,请参考以下文章

C – 将可变数量的参数传递给 main

如何在 MySQL 存储过程中选择与可变数量参数匹配的值

是否可以将可变数量的参数传递给redshift中的存储过程?

array_intersect 可变数量的数组

在excel中生成可变数量工作表的PDF并通过电子邮件发送

编写高质量代码改善C#程序的157个建议——建议16:元素数量可变的情况下不应使用数组