Rounding error making my graphics barely off?

In summary, the conversation is about trying to draw a circle and a possibly rotated square on a grid. The person is having trouble with the square and is given two points that represent the coordinates for the opposite ends of the square. They share their method for drawing the square and mention some code for reference. They also ask for help with an issue they are having with the output being slightly off.
  • #1
SlurrerOfSpeech
141
11
I'm trying to draw a circle and a (possibly rotated) square on a grid. I have the circle part down and it's the square that is giving me trouble. I am originally given 2 points which represent the coordinates containing opposite ends of the square. For example, those 2 points would be (8,14) and (16,14) in the following image.

1487108939-1509098632-image.png
and the output would look like

LyzcoA2.png


I had to rehash my memory of matrices, lines on graphs, etc., but eventually (after almost 10 hours) I came up with

Code:
    public void DrawSquare(double x1, double y1, double x3, double y3)
    {
        // Increment input coordinates so that they now are
        // at the center of the squares
        x1 += 0.5;
        y1 += 0.5;
        x3 += 0.5;
        y3 += 0.5;        // Ensure x1 <= x3
        if(x1 > x3)
        {
            SwapDoubles(ref x1, ref x3);
            SwapDoubles(ref y1, ref y3);
        }

        // Get midpoints of x-y pairs
        double midx = (x1 + x3) / 2;
        double midy = (y1 + y3) / 2;
      
        // Get the slope of the line y = mx + b that goes through the two points
        double ydiff = y3 - y1;
        double xdiff = x3 - x1;
        double m = (xdiff == 0 || ydiff == 0) ? 0 : ydiff / xdiff;

        // Get the slopes of the above line rotated -45 deg and 45 deg
        double m1 = RotateSlope(m, Math.PI / 4);
        double m2 = RotateSlope(m, -1 * Math.PI / 4);
        // Get the intercepts for the lines with the above slopes passing through the midpoint
        double b1 = midy - m1 * midx;
        double b2 = midy - m2 * midx;

        // now we have two lines y = m1 * x + b1 and y = m2 * x + b2 which are at 45 degree
        // angles from the line y = mx + b passing through the two original points, and
        // which pass through the midpoint of the original two points

        // Get distance from center to lines that run across the sides of the square
        double dist = Math.Sqrt(Math.Pow((double)x1 - midx, 2) + Math.Pow((double)y1 - midy, 2)) / Math.Sqrt(2);

        DrawInRange((Coordinate<int> coord) =>
        {
            // distance from middle of coordinate to line 1
            double d1 = ClosestDistanceToLine(m1, -1, b1, coord.X + 0.5, coord.Y + 0.5);
            // distance from middle coordinate to line 2
            double d2 = ClosestDistanceToLine(m2, -1, b2, coord.X + 0.5, coord.Y + 0.5);
            return  d1 <= dist && d2 <= dist;
        });
    }

    // https://en.wikipedia.org/wiki/Rotation_matrix
    static double RotateSlope(double m, double angle)
    {
        double y = m;
        double x = 1;
        double _x = Math.Cos(angle) * x + Math.Sin(angle) * y;
        double _y = -1 * Math.Sin(angle) * x + Math.Cos(angle) * y;
        return _y / _x;
    }

    // finds the closest distance beteen the line y = mx + b and the point (x0, y0)
    // http://www.intmath.com/plane-analytic-geometry/perpendicular-distance-point-line.php
    static double ClosestDistanceToLine(double A, double B, double C, double x0, double y0)
    {
        double numerator = Math.Abs(A * x0 + B * y0 + C);
        double denominator = Math.Sqrt(Math.Pow(A, 2.0) + Math.Pow(B, 2.0));
        return  numerator / denominator;
    }

which is giving me output slightly off

LZ3f7TR.png
Any idea why?

Full code dump if you want:

Code:
using System;
using System.Collections.Generic;
using System.Linq;

class Coordinate<T>
{
    public T X { get; private set; }
    public T Y { get; private set; }

    public Coordinate(T x, T y)
    {
        X = x;
        Y = y;
    }
}

class RasterGraphics
{
    public int Width { get; private set; }
    public int Height { get; private set; }
    public char[,] Graph { get; private set; }

    public RasterGraphics(int width, int height)
    {
        Width = width;
        Height = height;
        Graph = new char[height, width];
        for(int i = 0; i < height; ++i)
            for(int j = 0; j < width; ++j)
                Graph[i, j] = '.';
    }

    public void DrawCircle(int x, int y, int radius)
    {
        double dx = (double)x + 0.5, dy = (double)y + 0.5;
        DrawInRange((Coordinate<int> coord) =>
        {
            Coordinate<double> center = new Coordinate<double>((double)coord.X + 0.5, (double)coord.Y + 0.5);
            double dist = Math.Sqrt(Math.Pow(dx - center.X, 2.0) + Math.Pow(dy - center.Y, 2.0));
            return dist <= radius;
        });
    }

    public void DrawInRange(Func<Coordinate<int>,bool> condition)
    {
        IEnumerable<Coordinate<int>> coordsInRange = GetCoords().Where(condition);
        foreach(Coordinate<int> coord in coordsInRange)
            Graph[coord.Y, coord.X] = '#';
    }

    private IEnumerable<Coordinate<int>> GetCoords()
    {
        for(int i = 0, m = Graph.GetLength(0); i < m; ++i)
            for(int j = 0, n = Graph.GetLength(1); j < n; ++j)
                yield return new Coordinate<int>(j, i);
    }

    private static void SwapDoubles(ref double i, ref double j)
    {
        double temp = i;
        i = j;
        j = temp;
    }

    public void DrawSquare(double x1, double y1, double x3, double y3)
    {
        // Increment input coordinates so that they now are
        // at the center of the squares
        x1 += 0.5;
        y1 += 0.5;
        x3 += 0.5;
        y3 += 0.5;        // Ensure x1 <= x3
        if(x1 > x3)
        {
            SwapDoubles(ref x1, ref x3);
            SwapDoubles(ref y1, ref y3);
        }

        // Get midpoints of x-y pairs
        double midx = (x1 + x3) / 2;
        double midy = (y1 + y3) / 2;
      
        // Get the slope of the line y = mx + b that goes through the two points
        double ydiff = y3 - y1;
        double xdiff = x3 - x1;
        double m = (xdiff == 0 || ydiff == 0) ? 0 : ydiff / xdiff;

        // Get the slopes of the above line rotated -45 deg and 45 deg
        double m1 = RotateSlope(m, Math.PI / 4);
        double m2 = RotateSlope(m, -1 * Math.PI / 4);
        // Get the intercepts for the lines with the above slopes passing through the midpoint
        double b1 = midy - m1 * midx;
        double b2 = midy - m2 * midx;

        // now we have two lines y = m1 * x + b1 and y = m2 * x + b2 which are at 45 degree
        // angles from the line y = mx + b passing through the two original points, and
        // which pass through the midpoint of the original two points

        // Get distance from center to lines that run across the sides of the square
        double dist = Math.Sqrt(Math.Pow((double)x1 - midx, 2) + Math.Pow((double)y1 - midy, 2)) / Math.Sqrt(2);

        DrawInRange((Coordinate<int> coord) =>
        {
            // distance from middle of coordinate to line 1
            double d1 = ClosestDistanceToLine(m1, -1, b1, coord.X + 0.5, coord.Y + 0.5);
            // distance from middle coordinate to line 2
            double d2 = ClosestDistanceToLine(m2, -1, b2, coord.X + 0.5, coord.Y + 0.5);
            return  d1 <= dist && d2 <= dist;
        });
    }

    // https://en.wikipedia.org/wiki/Rotation_matrix
    static double RotateSlope(double m, double angle)
    {
        double y = m;
        double x = 1;
        double _x = Math.Cos(angle) * x + Math.Sin(angle) * y;
        double _y = -1 * Math.Sin(angle) * x + Math.Cos(angle) * y;
        return _y / _x;
    }

    // finds the closest distance beteen the line y = mx + b and the point (x0, y0)
    // http://www.intmath.com/plane-analytic-geometry/perpendicular-distance-point-line.php
    static double ClosestDistanceToLine(double A, double B, double C, double x0, double y0)
    {
        double numerator = Math.Abs(A * x0 + B * y0 + C);
        double denominator = Math.Sqrt(Math.Pow(A, 2.0) + Math.Pow(B, 2.0));
        return  numerator / denominator;
    }

    public void Print()
    {
        for(int i = 0, m = Graph.GetLength(0); i < m; ++i)
            Console.WriteLine(GetRow(i));
    }

    private string GetRow(int row)
    {
        int n = Graph.GetLength(1);
        char[] letters = new char[n];
        for(int j = 0; j < n; ++j)
            letters[j] = Graph[row, j];
        return new string(letters);
    }
}

class Solution
{
    static void Main(String[] args)
    {
        int w = 20;
        int h = 16;
        int circleX = 9;
        int circleY = 6;
        int r = 5;
        int x1 = 16;
        int y1 = 14;
        int x3 = 8;
        int y3 = 16;
        var raster = new RasterGraphics(w, h);
        raster.DrawCircle(circleX, circleY, r);
        raster.DrawSquare(x1, y1, x3, y3);
        raster.Print();
    }
}
 
Technology news on Phys.org
  • #2
Did you check the intermediate results of your calculations? Is your angle right, are your calculated corners right, ...?
 
  • Like
Likes FactChecker
  • #3
I didn't read all of the code, but it looks like your square is off by a factor of 0.5 units.
 

1. Why do rounding errors occur in graphics?

Roundoff error occurs in graphics due to the limitations of binary floating-point arithmetic used to represent decimal numbers on a computer. This means that not all numbers can be accurately represented, resulting in small discrepancies when performing calculations.

2. How do rounding errors affect the accuracy of my graphics?

Rounding errors can cause small visual discrepancies in graphics, such as slightly shifted pixels or lines that are not perfectly straight. These errors can accumulate and become more noticeable over time, especially in complex graphics.

3. Can rounding errors be avoided?

While rounding errors cannot be completely avoided, they can be minimized by using higher precision floating-point formats or alternative methods of representation, such as fixed-point arithmetic. It is also important to carefully consider the level of precision needed for the specific graphic being created.

4. How can I fix rounding errors in my graphics?

Rounding errors can be reduced by using more precise calculations, rounding to the nearest integer, or implementing error-correcting algorithms. It is also important to regularly check and adjust for rounding errors during the development process.

5. Are rounding errors a common issue in graphics?

Yes, rounding errors are a common issue in graphics, especially in computer graphics where complex calculations are involved. However, with proper understanding and implementation, these errors can be managed and minimized to ensure high accuracy and visual quality in graphics.

Similar threads

  • Programming and Computer Science
Replies
14
Views
4K
  • Precalculus Mathematics Homework Help
Replies
7
Views
883
  • Programming and Computer Science
Replies
4
Views
5K
  • Engineering and Comp Sci Homework Help
Replies
1
Views
2K
Replies
8
Views
4K
Back
Top