Question

I need to draw a bucket and fill it with two different liquid colours (yellow and red).

I have got so far in a hard coded version but I need to be able to specify the % of the bucket filled, so for instance 50% yellow then 10% red.

I have never done graphics in C# so any and all help on this is appreciated. I also need a cleaner way of doing the bottom of the bucket as it draws a black line ontop of the yellow in the below example. Current output of code

private Bitmap drawBucket2()
    {
        Bitmap img = new Bitmap(200, 200);


        using (Graphics g = Graphics.FromImage(img))
        {
            try
            {
                Pen penBlack = new Pen(Color.Black, 1);                    
                Pen penYellow = new Pen(Color.Yellow, 1);
                Brush brushYellow = new SolidBrush(Color.Yellow);
                Brush brushRed = new SolidBrush(Color.Red);
                Point[] pts = new Point[4];
                pts[0] = new Point(11, 115);
                pts[1] = new Point(170, 115);
                pts[2] = new Point(162, 180);
                pts[3] = new Point(21, 180); 

                g.FillEllipse(brushYellow, 11, 90, 160, 50);
                g.FillPolygon(brushYellow, pts);

                pts = new Point[3];
                pts[0] = new Point(21, 180);
                pts[1] = new Point(91, 195);
                pts[2] = new Point(162, 180);
                g.FillClosedCurve(brushYellow, pts);

                /*outline */
                g.DrawEllipse(penBlack, 2, 10, 180, 50);
                g.DrawLine(penBlack, 1, 35, 21, 180);
                g.DrawLine(penBlack, 182, 35, 162, 180);
                pts = new Point[3];
                pts[0] = new Point(21, 180);
                pts[1] = new Point(91, 195);
                pts[2] = new Point(162, 180);
                g.DrawClosedCurve(penBlack, pts);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }
        return img;
    }
Was it helpful?

Solution 3

I have manged to solve this one, I am posting the code here to see if anyone can still improve it before I accept this as the answer.

private int[] getPoints(int perc)
    {
        int[] pts;// = new int[4];
        double x_offset_left = (35 - 21);
        x_offset_left = x_offset_left / 100;
        double height = 135;
        double width = 178;
        double x1, x2, y1, y2;

        int margin_top = 66;//68
        int margin_left = 21;

        y1 = ((height / 100) * perc) + margin_top;
        y2 = y1;

        x1 = margin_left + (x_offset_left * perc);
        x2 = width - (x_offset_left * perc);

        pts = new int[4] { Convert.ToInt32(x1), Convert.ToInt32(y1), Convert.ToInt32(x2), Convert.ToInt32(y2) };
        return pts;
    }
    private Bitmap drawBucket2(int yellowval, int redval, int overval)
    {
        Bitmap img = new Bitmap(200, 221);
        using (Graphics g = Graphics.FromImage(img))
        {
            Brush bRed = new SolidBrush(Color.FromArgb(50, Color.DarkRed));
            Brush bYellow = new SolidBrush(Color.FromArgb(75, Color.Gold));
            Brush bBlue = new SolidBrush(Color.FromArgb(50, Color.Blue));

            GraphicsPath gp = new GraphicsPath();
            Region r;
            Point[] points_yellow;
            Point[] points_red;

            int percentage = 0;
            int[] pts;
            int[] pts_full = getPoints(100);
            int[] pts_min = getPoints(1);

            #region "Yellow Region"
            // bottom curve
            percentage = yellowval;
            pts = getPoints(100 - percentage);

            points_yellow = new Point[3];
            points_yellow[0] = new Point(pts_full[0], pts_full[3]);
            points_yellow[1] = new Point(((pts_full[2] - pts_full[0]) / 2 + pts_full[0]), (pts_full[1] + 15));
            points_yellow[2] = new Point(pts_full[2], pts_full[3]);
            gp.AddCurve(points_yellow, 0.7f);
            //Console.WriteLine("curve : (" + points_yellow[0].X + ", " + points_yellow[0].Y + "), " + " (" + points_yellow[1].X + ", " + points_yellow[1].Y + "), " + " (" + points_yellow[2].X + ", " + points_yellow[2].Y + ")");

            //polygon
            points_yellow = new Point[4];
            points_yellow[0] = new Point(pts[0], pts[1]);
            points_yellow[1] = new Point(pts[2], pts[1]);
            points_yellow[2] = new Point(pts_full[2], pts_full[1]);
            points_yellow[3] = new Point(pts_full[0], pts_full[1]);
            gp.AddPolygon(points_yellow);
            //Console.WriteLine("Poly : (" + points_yellow[0].X + ", " + points_yellow[0].Y + "), " + " (" + points_yellow[1].X + ", " + points_yellow[1].Y + "), " + " (" + points_yellow[2].X + ", " + points_yellow[2].Y + "), " + " (" + points_yellow[3].X + ", " + points_yellow[3].Y + ")");

            // top curve
            points_yellow = new Point[3];
            points_yellow[0] = new Point(pts[0], pts[1]);
            points_yellow[1] = new Point(((pts[2] - pts[0]) / 2 + pts[0]), (pts[1] + 15));
            points_yellow[2] = new Point(pts[2], pts[1]);
            gp.AddCurve(points_yellow, 0.7f);
            //Console.WriteLine("curve : (" + points_yellow[0].X + ", " + points_yellow[0].Y + "), " + " (" + points_yellow[1].X + ", " + points_yellow[1].Y + "), " + " (" + points_yellow[2].X + ", " + points_yellow[2].Y + ")");

            r = new Region(gp);
            g.FillRegion(bYellow, r);
            #endregion     

            #region "Red Region"
            gp = new GraphicsPath();
            percentage = yellowval + redval;

            // Bottom Curve
            gp.AddCurve(points_yellow, 0.7f);
            //Console.WriteLine("curve : (" + points_yellow[0].X + ", " + points_yellow[0].Y + "), " + " (" + points_yellow[1].X + ", " + points_yellow[1].Y + "), " + " (" + points_yellow[2].X + ", " + points_yellow[2].Y + ")");

            // polygon
            int[] pts_yel = new int[3]{pts[0], pts[1], pts[2]};
            pts = getPoints(100 - percentage);
            points_red = new Point[4];
            points_red[0] = new Point(pts[0], pts[1]);
            points_red[1] = new Point(pts[2], pts[1]);
            points_red[2] = new Point(pts_yel[2], pts_yel[1]);
            points_red[3] = new Point(pts_yel[0], pts_yel[1]);
            gp.AddPolygon(points_red);

            // Top Curve
            points_red = new Point[3];
            points_red[0] = new Point(pts[0], pts[1]);
            points_red[1] = new Point(((pts[2] - pts[0]) / 2 + pts[0]), (pts[1] + 12));
            points_red[2] = new Point(pts[2], pts[1]);
            gp.AddCurve(points_red, 0.7f);

            r = new Region(gp);
            g.FillRegion(bRed, r);
            #endregion

            #region "Overflow"
            if (overval > 0)
            {
                gp = new GraphicsPath();
                gp.AddEllipse(16, 10, 165, 32);
                r = new Region(gp);
                g.FillRegion(bBlue, r);
            }
            #endregion
            r.Dispose();
            gp.Dispose();
            bRed.Dispose();
            bYellow.Dispose();
            bBlue.Dispose();            
        }
        return img;
    }

    private void fillBucket(int Yellowperc, int Redperc, int Overperc)
    {
        pictureBox1.Image = null;
        pictureBox1.Image = drawBucket2(Yellowperc, Redperc, Overperc);
    }

OTHER TIPS

The "liquids" are two elipses with the space in between filled, so all you need to calculate is the heights and the left and right positions depending on the amount of liquid and draw from bottom to top (ie yellow then red)

// Upper Elipse and top Points for the filled center
y = HeightOfBottom + (FullHeight * (StartAmountFloat + AmountFloat))
x1 = Middle - (DiffenceOfDiameter * (StartAmountFloat + AmountFloat))
x2 = Middle + (DiffenceOfDiameter * (StartAmountFloat + AmountFloat))

// Lower Elipse and bottom Points for the filled center
y = HeightOfBottom + (FullHeight * StartAmountFloat)
x1 = Middle - (DiffenceOfDiameter * StartAmountFloat)
x2 = Middle + (DiffenceOfDiameter * StartAmountFloat)

The Bottom should be the lower half of an elipse, too.

Ok, don't have any code for you but I can give you an approximate workflow to achieve this. Basically you want to draw your objects back to front, so I would be drawing in this order

  1. Draw the bottom of the bucket as an ellipse
  2. Draw the bottom of the liquid as an ellpise of the same size, but one pixel higher
  3. Now draw ellipses at each Y-pixel above until the desired % has been reached, where the end number of pixels is computed by the (bottom of the bucket) + ((top of the bucket) - (bottom of the bucket) * (percentage / 100)). You will need to widen the ellipse at certain points. This will create an aliased effect but don't worry, we are going to draw over it next
  4. Finally draw the sides of the bucket and the top. If you choose a suitable line thickness you can cheekily hide the fact you hacked your way to glory :)

Last thing I'd suggest lots of trial and error. the more you do this the easier it will become! Good luck

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top