1

UPDATE Final code I have to make it work based on the answers below:

public static byte[] Test(List<TestRange> ranges, int value)
        {
            var min = ranges.Min(t => t.MinValue);
            var max = ranges.Max(t => t.MaxValue);
            var rangeTotal = max - min;
            var valueAngle = ((((float)value-min) / (float)rangeTotal) * (float)270) + (float)135;
            using (var bmp = new Bitmap(500, 500))
            {
                using (var g = Graphics.FromImage(bmp))
                {
                    g.SmoothingMode = SmoothingMode.AntiAlias;
                    var rec = new Rectangle(0, 0, 500, 500);
                    g.FillPie(new SolidBrush(Color.White), rec, 45, 90);
                    var startDeg = 135f;
                    foreach (var item in ranges.OrderBy(o => o.MinValue))
                    {
                        g.FillPie(new SolidBrush(ColorTranslator.FromHtml(item.Color)), rec, startDeg,
                            ((item.MaxValue - (float) item.MinValue)/rangeTotal)*270);
                        startDeg = startDeg + (((item.MaxValue - (float) item.MinValue)/rangeTotal)*270);
                    }
                    g.FillEllipse(new SolidBrush(Color.White), new Rectangle(100, 100, 300, 300));

                    using (var needle = Graphics.FromImage(bmp))
                    {
                        needle.TranslateTransform(250, 250);
                        needle.RotateTransform(valueAngle);
                        needle.TranslateTransform(-68, -39);
                        needle.DrawImage(Image.FromFile(@"C:\temp\needle.png"), new PointF(0,0));
                    }

                    g.FillRectangle(new SolidBrush(Color.Black), new RectangleF(new PointF(150,375), new SizeF(200,72)));
                    var sf = new StringFormat
                    {
                        Alignment = StringAlignment.Center,
                        LineAlignment = StringAlignment.Center
                    };
                    g.DrawString(value.ToString(), new Font(FontFamily.GenericSansSerif, 40), Brushes.White, new PointF(250, 415), sf);

                }
                using (var ms = new MemoryStream())
                {
                    bmp.Save(ms, ImageFormat.Png);
                    return ms.ToArray();
                }

            }
        }

I am trying to make a custom GDI+ gauge chart. I have everything working except the needle rotation. I have read as many articles as I can find but cannot figure out how to do it successfully. I can calculate the angles on my own, but I need to rotate the needle from a point within the needle image. 68px, 39px (X,Y from left top). Any help would be appreciated. Here is the code:

public static void Test(List<TestRange> ranges, int value)
        {
            var min = ranges.Min(t => t.MinValue);
            var max = ranges.Max(t => t.MaxValue);
            var rangeTotal = max - min;
            using (var bmp = new Bitmap(500, 500))
            {
                using (var g = Graphics.FromImage(bmp))
                {
                    g.SmoothingMode = SmoothingMode.AntiAlias;
                    var rec = new Rectangle(0, 0, 500, 500);
                    g.FillPie(new SolidBrush(Color.White), rec, 45, 90);
                    var startDeg = 135f;
                    foreach (var item in ranges.OrderBy(o => o.MinValue))
                    {
                        g.FillPie(new SolidBrush(ColorTranslator.FromHtml(item.Color)), rec, startDeg,
                            ((item.MaxValue - (float) item.MinValue)/rangeTotal)*270);
                        startDeg = startDeg + (((item.MaxValue - (float) item.MinValue)/rangeTotal)*270);
                    }
                    g.FillEllipse(new SolidBrush(Color.White), new Rectangle(100, 100, 300, 300));

                    //Needle logic
                    using (var needle = Graphics.FromImage(bmp))
                    {
                        //var m = new Matrix();
                        //m.RotateAt(180, new PointF(68,39));
                        //needle.Transform = m;
                        //needle.TranslateTransform(250, 250);
                        //needle.RotateTransform(180);
                        needle.DrawImage(Image.FromFile(@"C:\temp\needle.png"), new PointF(182, 211));
                    }

                    g.FillRectangle(new SolidBrush(Color.Black), new RectangleF(new PointF(150,375), new SizeF(200,72)));
                    var sf = new StringFormat
                    {
                        Alignment = StringAlignment.Center,
                        LineAlignment = StringAlignment.Center
                    };
                    g.DrawString(value.ToString(), new Font(FontFamily.GenericSansSerif, 40), Brushes.White, new PointF(250, 415), sf);

                }
                bmp.Save("C:\\temp\\Test.png", ImageFormat.Png);
            }
        }

Here is the image it outputs: enter image description here

Here is the needle.png file: enter image description here

Cyberdrew
  • 1,832
  • 1
  • 19
  • 39
  • "I have read as many articles as I could find" doesn't tell us anything about your specific difficulties. Did you read this one? http://stackoverflow.com/a/3809854 The GDI Graphics object apparently has a `RotateTransform()` method, which you do not appear to be using. – Robert Harvey Feb 19 '15 at 20:02
  • That's great if I want to rotate the whole image but doesn't tell me much about rotating an image within an image from a fixed point within the image. – Cyberdrew Feb 19 '15 at 20:05
  • Now we're getting somewhere. – Robert Harvey Feb 19 '15 at 20:05
  • 1
    Draw your rotation, then call ResetTransform to not affect other parts of the drawing. See [Using a matrix to rotate rectangles individually](http://stackoverflow.com/a/10210639/719186) – LarsTech Feb 19 '15 at 20:07
  • Lars, this looks like a great example but how can I do this with the external image as opposed to a rectangle drawing? – Cyberdrew Feb 19 '15 at 20:09
  • 1
    Images are rectangles last I checked. – LarsTech Feb 19 '15 at 20:10
  • I tried something similar in the commented out code above, but it didn't even show the needle when I did it. – Cyberdrew Feb 19 '15 at 20:12
  • I guess you need to figure out why. That other post seems like it's what you want to be doing. – Robert Harvey Feb 19 '15 at 20:16
  • 1
    Remember that you are rotating around `0,0` coordinates. Draw your image at `-Image.Width/2, -Image.Height/2`, using a combination of `RotateTransform` and `TranslateTransform` to first rotate it the amount you need and then move it to the center of your gauge. It sounds like you have rotated it outside the visible area of your image. – Jens Feb 19 '15 at 20:17

2 Answers2

1

You need to combine the rotation with a translation transformation and actually draw the image around the origin point.

public void DrawImageRotated(Graphics g, Image Image, Point Location, Single Angle)
{
    g.ResetTransform();
    g.RotateTransform(Angle);
    g.TranslateTransform(Location.X, Location.Y, Drawing2D.MatrixOrder.Append);
    g.DrawImageUnscaled(Image, -Image.Width / 2, -Image.Height / 2);
    g.ResetTransform();
}

enter image description here

Jens
  • 6,275
  • 2
  • 25
  • 51
  • Thank you for the answer, this works but the need is off center a bit. I tested at 180 degrees and 210 degrees. – Cyberdrew Feb 19 '15 at 21:21
  • When I move the object to world coordinates, I need to center it based on the pivot point of the needle. – Cyberdrew Feb 19 '15 at 21:24
1

The trick is to translate the coordinate system so that your desired pivot point is at the origin, and then draw the image at 0,0:

using (var needle = Graphics.FromImage(bmp))
{
    needle.TranslateTransform(182, 211);
    needle.RotateTransform(angle);
    needle.TranslateTransform(-68, -39);
    needle.DrawImage(Image.FromFile(@"C:\temp\needle.png"), new PointF(0, 0));
}
RogerN
  • 3,761
  • 11
  • 18