Home > Software design >  How to get coordinate neighbors from a fixed point to a specific distance
How to get coordinate neighbors from a fixed point to a specific distance

Time:09-16

My task is to implement the GetNeighbors method, which returns from a set of points only points that are h-neighbors for a point with integer coordinates x and y. (read the summary in code for more understandment)

Actually, I have the same task as this guy Find k nearest neighbor in C#, but the answer there doesn't seem to work. And I think of doing it just with loops like it should be expected of me I guess :)>.

Now my code so far:

        /// <summary>
        /// Gets from a set of points only points that are h-neighbors for a point with integer coordinates x and y.
        /// </summary>
        /// <param name="point">Given point with integer coordinates x and y.</param>
        /// <param name="h">Distance around a given point.</param>
        /// <param name="points">A given set of points.</param>
        /// <returns>Only points that are h-neighbors for a point with integer coordinates x and y.</returns>
        /// <exception cref="ArgumentNullException">Throw when array points is null.</exception>
        /// <exception cref="ArgumentException">Throw when h-distance is less or equals zero.</exception>
        public static Point[] GetNeighbors(Point point, int h, params Point[] points)
        {
            if (points is null)
            {
                throw new ArgumentNullException(nameof(points));
            }

            if (h <= 0)
            {
                throw new ArgumentException(null);
            }

            List<Point> neighbors = new List<Point>();

            int left = point.X - h;
            int right = point.X   h;
            int bottom = point.Y - h;
            int top = point.Y   h;


            for (int y = top; y <= bottom; y  )
            {
                for (int x = left; x <= right; x  )
                {
                    // Yeah...
                }
            }

            return neighbors.ToArray();
        }

So what I have done so far is found the top, bottom, left and right borders in the neighborhood. What I think I only need to do is a if statement that could compare both the point I have and from the points array. Hm how to do that, I am not very familiar with using structs, everytime is a failure.

This is how struct Point was built:

/// <summary>
    /// Represents a point on the coordinate plane.
    /// </summary>
    public readonly struct Point : System.IEquatable<Point>
    {
        public Point(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }

        public int X { get; }

        public int Y { get; }
        
        public static bool operator ==(Point left, Point right)
        {
            return left.Equals(right);
        }
        
        public static bool operator !=(Point left, Point right)
        {
            return !(left == right);
        }
        
        public override int GetHashCode()
        {
            return this.X.GetHashCode() ^ this.Y.GetHashCode();
        }
        
        public override bool Equals(object obj)
        {
            if (obj is null)
            {
                return false;
            }

            if (!(obj is Point))
            {
                return false;
            }

            if (obj.GetType() != this.GetType())
            {
                return false;
            }

            Point point = (Point)obj;
            
            return this.Equals(point);
        }

        public bool Equals(Point other)
        {
            return this.X == other.X && this.Y == other.Y;
        }
    }

neighborhood

CodePudding user response:

You must not loop over the coordinates but over the points. Here is a solution using LINQ:

public static Point[] GetNeighbors(Point point, int h, params Point[] points)
{
    int minX = point.X - h;
    int maxX = point.X   h;
    int minY = point.Y - h;
    int maxY = point.Y   h;
    return points
        .Where(p => p.X >= minX && p.X <= maxX && p.Y >= minY && p.Y <= maxY)
        .ToArray();
}

With C# 9.0 you can simplify the comparison with pattern matching

        .Where(p => p.X is >=minX and <=maxX && p.Y is >=minY and <=maxY)

Here is a solution using an explicit loop. Since we don't know the size of the resulting array, I am storing the result in a list:

    ...
    var list = new List<Point>();
    foreach (Point p in points) {
        if (p.X is >=minX and <=maxX && p.Y is >=minY and <=maxY) {
            list.Add(p);
        }
    }
    return list.ToArray();

Or you could return a list instead.


Yet another solution is to use an iterator method:

public static IEnumerable<Point> GetNeighbors(Point point, int h, params Point[] points)
{
    int minX = point.X - h;
    int maxX = point.X   h;
    int minY = point.Y - h;
    int maxY = point.Y   h;
    foreach (Point p in points) {
        if (p.X is >=minX and <=maxX && p.Y is >=minY and <=maxY) {
            yield return p;
        }
    }
}

Note that this approach does not store the points in a collection, instead, the loop inside the method is executed as you loop over the result (explicitly in a foreach-loop or implicitly by applying .ToArray() or .Count() etc.).

Point[] result = GetNeighbors(center, 2, p1, p2, p3, p4).ToArray();
  • Related