Search code examples
c#winformsdrawingpicturebox

Resize graphics to fit in PictureBox


I need to draw a Fermat spiral in C#. I did it, but I want my drawing to be filled in PictureBox, no matter how big real size is.

  public void DrawSpiral(double delta, double numCycles, int oX, int oY, SpiralType spiralType, Color color, Graphics g)
  {
        double a = Convert.ToInt32(textBox1.Text);
        Pen p = new Pen(color, 1);
        double prevX = oX;
        double prevY = oY;
        double X = oX;
        double Y = oY;
        double fi = Convert.ToInt32(textBox2.Text); 
        double radius = 0;

        while (fi <= (numCycles * 360))
        {
            fi += delta;
            if (spiralType == SpiralType.FermaPlus)
            {
                radius = a * Math.Sqrt(fi); 
            }
            else if (spiralType == SpiralType.FermaMinus)
            {
                radius = -a * Math.Sqrt(fi);
            }
            prevX = X;
            prevY = Y;
            X = (radius * Math.Cos(fi / 180 * Math.PI)) + oX;
            Y = (radius * Math.Sin(fi / 180 * Math.PI)) + oY;
            g.DrawLine(p, (float)prevX, (float)prevY, (float)X, (float)Y);
        }
    }

 private void DrawButton_Click(object sender, EventArgs e)
 {
        pictureBox1.Refresh();
        Graphics g = pictureBox1.CreateGraphics();
        DrawSpiral(2, 5, 150, 150, SpiralType.FermaPlus, Color.Blue, g);
        DrawSpiral(2, 5, 150, 150, SpiralType.FermaMinus, Color.Red, g);
  }

So, what should I do to have my drawing to be full filled in the PictureBox.


Solution

  • Here is one way to do it:

    Change the signature of the DrawSpiral to include the ClientSize of the PictureBox instead of some center coordinates:

    public void DrawSpiral(double delta, double numCycles, int spiralType, 
                                                           Color color, Graphics g, Size sz)
    

    Then calculate the center dynamically:

     int oX = sz.Width / 2;
     int oY = sz.Height / 2;
     double prevX = oX;
     double prevY = oY;
     double X = oX;
     double Y = oY;
    

    Next calculate the factor a :

     a = sz.Width / 2 / Math.Sqrt( numCycles * 360);
    

    Finally call the method only from the Paint event, passing out the valid Graphics object:

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        Size sz = pictureBox1.ClientSize;
        DrawSpiral(2, 5, SpiralType.FermaPlus, Color.Blue, g, sz);
        DrawSpiral(2, 5, SpiralType.FermaMinus, Color.Red, g, sz);
    }
    

    Upon resizing the PictureBox it will still fill the area with the same number of loops..:

    enter image description here

    A few notes:

    • The quality and performance could be improved by first collecting the data in a List<Point> pointsand then using DrawLines(pen, points.ToArray())

    • I used just the width when I calculated the factor a. Use Math.Min(sz.Width, sz.Height) to always fit it into a non-square box!

    • I left your offset calculation in place; but you could instead do a g.TranslateTransform()..

    • The PictureBox will Invalidate/Refresh itself upon resizing. If you change any parameters do call Invalidate to pick them up!