1

I'm using bitmaps to create custom images in my WinForm. I have a class that represents a truss and want to visualize it. Right now this is my code for drawing the truss:

    public void DrawAnsComponent()
    {
        Pen pen = new Pen(Color.Black);
        maxWidth = 0;
        maxHeight = 0;
        //Getting size of bitmap
        foreach (AnsJoint joint in this.AnsToShow.AnsJoints)
        {
            if (joint.Location.X.Length > maxWidth)
            {
                maxWidth = (int)joint.Location.X.Length;
            }
            if (joint.Location.Y.Length > maxHeight)
            {
                maxHeight = (int)joint.Location.Y.Length;
            }
        }
        maxHeight += 55; maxWidth += 5;
        Bitmap bm = new Bitmap(maxWidth, maxHeight); //Creating Bitmap
        gr = Graphics.FromImage(bm); //Creating graphic to project onto bitmap
        gr.SmoothingMode = SmoothingMode.HighQuality;
        foreach (AnsJoint joint in this.AnsToShow.AnsJoints)
        {
            PointF jointPoint = this.ToCartesian(new PointF((float)joint.Location.X.Length - 4f, (float)joint.Location.Y.Length + 10f), maxHeight);
            gr.DrawString(joint.JointID.ToString(), new Font(FontFamily.GenericMonospace, 6f, FontStyle.Regular, GraphicsUnit.Point, 1, false), Brushes.Black, jointPoint);
        }
        foreach (AnsMember member in this.AnsToShow.AnsMembers) //Drawing each member
        {
            List<AnsPanel> panels = member.Panels; //Drawing the panels

            foreach (AnsPanel pan in panels)
            {
                pen.Color = Color.Red;
                PointF p1 = this.ToCartesian(new PointF((float)pan.I.Location.X.Length, (float)pan.I.Location.Y.Length), maxHeight);
                PointF p2 = this.ToCartesian(new PointF((float)pan.J.Location.X.Length, (float)pan.J.Location.Y.Length), maxHeight);

                gr.DrawEllipse(pen, p1.X - 2.5f, p1.Y - 2.5f, 5, 5);
                gr.DrawEllipse(pen, p2.X - 2.5f, p2.Y - 2.5f, 5, 5);
                /*
                gr.DrawEllipse(pen, p1.X - 3, p1.Y - 3.3f, 5, 5);
                gr.DrawEllipse(pen, p2.X - 3, p2.Y - 3.3f, 5, 5);
                pen.Color = Color.Black;
                gr.DrawLine(pen, p1, p2);
                */
            }
            List<AnsLink> links = member.Links; //Drawing the links
            foreach (AnsLink link in links)
            {
                PointF p1 = this.ToCartesian(new PointF((float)link.I.Location.X.Length, (float)link.I.Location.Y.Length), maxHeight);
                PointF p2 = this.ToCartesian(new PointF((float)link.J.Location.X.Length, (float)link.J.Location.Y.Length), maxHeight);
                gr.FillEllipse(Brushes.Green, p1.X - 1.5f, p1.Y - 1.5f, 3, 3);
                gr.FillEllipse(Brushes.Green, p2.X - 1.5f, p2.Y - 1.5f, 3, 3);
                gr.DrawLine(pen, p1, p2);
            }
        }
        pictureBox1.Image = bm;

    public PointF ToCartesian(PointF p, int maxHeight)
    {
        return new PointF(p.X, (p.Y - (maxHeight * .8f)) * -1);
    }

And here is the result

enter image description here

So it's working perfectly fine except the pixelation makes it look like a very low quality picture. Is there anything I can change about my code to make the image a higher quality?

Community
  • 1
  • 1
Nick Gilbert
  • 4,159
  • 8
  • 43
  • 90
  • Fixed the issue except scaling does not work properly. http://stackoverflow.com/questions/36628305/scaling-picturebox-does-not-change-image-at-all – Nick Gilbert Apr 14 '16 at 16:03

2 Answers2

1

The PictureBox is simply scaling up the small image you're drawing in the Bitmap. You are apparently determining the size, in pixels, of your drawing from the size, in "real world" coordinates, of your truss. You could, instead, apply a scale factor when calculating the screen coordinates of your geometry so that the drawing fills the visible space of the control. If you do that, though, I would recommend ditching the Bitmap and instead drawing directly on the PictureBox in its Paint event handler (or deriving a custom control and putting the drawing in the protected OnPaint method). That way you don't have to deal with keeping the Bitmap's size in sync with the PictureBox's size, which would be a real hassle, not to mention inefficient. Basically you don't want the PictureBox trying to resize the image, as it'll give you the sort of blurriness you're seeing when scaling up and weird artifacts when scaling down.

Hopefully this is clear and informative enough to get you started.

adv12
  • 8,443
  • 2
  • 24
  • 48
  • Thanks so much! I've pretty much fixed my issue except for one thing that I describe here http://stackoverflow.com/questions/36628305/scaling-picturebox-does-not-change-image-at-all – Nick Gilbert Apr 14 '16 at 16:02
0

Two thoughts:

1) There are a few other properties on the Graphics object that you will want to play with including SmoothingMode and InterpolationMode

Graphics.SmoothingMode = SmoothingMode.AntiAlias
Graphics.InterpolationMode = InterpolationMode.Bicubic

2) You are likely making the bitmap much smaller than you actually want. One idea which would allow you to make the bitmap larger without appreciably changing your code would be to use a scaling factor such as

var scale = 2;
Bitmap bm = new Bitmap(maxWidth * scale, maxHeight * scale); //Creating Bitmap
using (var gr = Graphics.FromImage(bm)) //Creating graphic to project onto bitmap
{
  gr.Transform.Scale(scale, scale)
  // continue as before
}

Also, don't forget to dispose disposable objects (such as the Graphics object). In this example, the using keyword deals with that for you.

erdomke
  • 4,980
  • 1
  • 24
  • 30