Rounding error making my graphics barely off?

Click For Summary
The discussion revolves around the challenge of drawing a square on a grid using two given points that represent opposite corners. The user has successfully implemented the circle drawing but struggles with the square, which is yielding slightly inaccurate results. The provided code includes methods for calculating slopes and distances, as well as functions for drawing shapes on a raster grid. A key point raised is the potential issue of the square being off by a factor of 0.5 units, suggesting that the calculations for the square's corners or the angles may need to be re-evaluated. The importance of checking intermediate results and ensuring the accuracy of angles and coordinates is emphasized to troubleshoot the drawing discrepancies.
SlurrerOfSpeech
Messages
141
Reaction score
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
Did you check the intermediate results of your calculations? Is your angle right, are your calculated corners right, ...?
 
  • Like
Likes FactChecker
I didn't read all of the code, but it looks like your square is off by a factor of 0.5 units.
 
I tried a web search "the loss of programming ", and found an article saying that all aspects of writing, developing, and testing software programs will one day all be handled through artificial intelligence. One must wonder then, who is responsible. WHO is responsible for any problems, bugs, deficiencies, or whatever malfunctions which the programs make their users endure? Things may work wrong however the "wrong" happens. AI needs to fix the problems for the users. Any way to...

Similar threads

Replies
14
Views
5K
  • · Replies 4 ·
Replies
4
Views
6K
Replies
7
Views
2K
Replies
8
Views
5K
  • · Replies 1 ·
Replies
1
Views
2K