Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

C/++/# Rounding error making my graphics barely off?

  1. Feb 23, 2017 #1
    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 (Text):

        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 (Text):

    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();
        }
    }
     
     
  2. jcsd
  3. Feb 23, 2017 #2

    mfb

    User Avatar
    2016 Award

    Staff: Mentor

    Did you check the intermediate results of your calculations? Is your angle right, are your calculated corners right, ...?
     
  4. Feb 23, 2017 #3
    I didn't read all of the code, but it looks like your square is off by a factor of 0.5 units.
     
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook

Have something to add?
Draft saved Draft deleted



Similar Discussions: Rounding error making my graphics barely off?
  1. Error in my code? (Replies: 5)

Loading...