Search code examples
c#imagebitmapdrawingpen

Drawing lines to image from a txt file. Pen thickness is too large.


Let me describe an issue that is taking me more than one day to solve so far. I am inputting a series of lines from a text file and I want to draw a picture with them. The thing is that two of these lines are too close (1 pixel distance) which is a problem if a Pen of Thickness is=1 is used. See the problematic region below:

enter image description here

For information, the bounding rectangle of the lines in the text file representing the whole shape is as follows:

Rectangle(xmin, ymin, (xmax - xmin), (ymax - ymin)) =  761, 236, 298, 344

And I am trying to draw them to a Bitmap(20000, 15000) but the size of the Bitmap could be changed if necessary.

My questions are:

  • Is there a workaround to make the pen thickness smaller than 1 to avoid such overlap?
  • Would it be possible to modify the input coordinates a little bit (some sort of “dilatation”) so this issue does not happen?

Otherwise, can someone think about another solution to solve this issue?

Thank you very much,

My code:

using System;
using System.IO;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;


namespace DrawingLinesTest
{
class Program
{

    static void Main(string[] args)
    {
        //Define the input txt file
        System.IO.StreamReader file = new System.IO.StreamReader("input.txt");
        //Define the bmp
        Bitmap bmp = new Bitmap(20000, 15000); 
        Graphics g = Graphics.FromImage(bmp);
        Pen blackPen = new Pen(Color.FromArgb(255, 0, 0, 0), 1);


        // Read the file
        int counter = 0;
        string line;
        var listX1 = new List<int>();
        var listY1 = new List<int>();
        var listX2 = new List<int>();
        var listY2 = new List<int>();
        var allPoints = new List<Point>();


        while ((line = file.ReadLine()) != null)
        {
            string[] points = line.Split(',');
            int x1 = int.Parse(points[0]), y1 = int.Parse(points[1]), x2 = int.Parse(points[2]), y2 = int.Parse(points[3]);
            int[] pInt = new int[4] { x1, y1, x2, y2 };
            listX1.Add(x1); listY1.Add(y1); listX2.Add(x2); listY2.Add(y2);

            Point a = new Point(int.Parse(points[0]), int.Parse(points[1]));
            Point b = new Point(int.Parse(points[2]), int.Parse(points[3]));               

            allPoints.Add(a); allPoints.Add(b);
            g.DrawLine(blackPen, a, b);                
            counter++;
        }
        file.Close();
        g.Dispose();
        //-----------------------------------------------------------------------------------------------------------------------------------------------
        // Find the list's bounding box.
        IEnumerable<Point> po = allPoints;
        Rectangle r = BoundingBox(po);
        Console.WriteLine(String.Format("Bounding Box {0},{1},{2},{3}", r.X, r.Y, r.Width, r.Height));

        Bitmap nb = new Bitmap(r.Width, r.Height);
        Graphics gr = Graphics.FromImage(nb);
        gr.DrawImage(bmp, -r.X, -r.Y);

        //Save input file as an image (output)
        nb.Save("outputPicture.png");
        //-----------------------------------------------------------------------------------------------------------------------------------------------

    }


    public static Rectangle BoundingBox(IEnumerable<Point> points)
    {
        var x_query = from Point p in points select p.X;
        int xmin = x_query.Min();
        int xmax = x_query.Max();

        var y_query = from Point p in points select p.Y;
        int ymin = y_query.Min();
        int ymax = y_query.Max();

        return new Rectangle(xmin, ymin, (xmax - xmin), (ymax - ymin));        }

}//end Program
}//end Namespace

Solution

  • Some Background:

    In graphics you have to deal with several coordinate syetems:

    1. World coordinates, for example in meters. In your case these are the coordinates in the text file
    2. Canvas coordinates / Bitmap coordinates, usually in Pixels, these are the pixels in the generated image.

    Then you have some coordinate-transformation from world coordinates to canvas coordinates. You omitted this step, which generates your problems.

    If you create a coordinate conversion for example 1 unit in world -> 10 Pixels all your problems go away.

    EDIT

    In your case a multiplication by 10 will do:

            Point a = new Point(int.Parse(points[0]*10), int.Parse(points[1]*10));
            Point b = new Point(int.Parse(points[2]*10), int.Parse(points[3]*10));