-1

Help me, because I'm rly tired of this...

I need to count angles between current point and the closest 3 points (look at an image below) - I need to sort the angles in descending order (to get the point with the largest angle - if it doesn't fit expectations, I have to get another one).

Angles

I tried to do something, but it doesn't work...

private static Vertex[] SortByAngle(IEnumerable<Vertex> vs, Vertex current, Vertex previous)
{
    if (current.CompareTo(previous) == 0)
    {
        previous.X = previous.X - 1.0; // this is a trick to handle the first point
    }

    var vertices = new Dictionary<Vertex, double>();
    foreach (var v in vs)
    {
        double priorAngle = Angle(previous, current);
        double nextAngle = Angle(current, v);
        double angleInBetween = 180.0 - (priorAngle + nextAngle);

        vertices.Add((Vertex) v.Clone(), angleInBetween);
    }

    // here the angles are incorrect, because I want to sort them in desc order, but it's a real mess when I do OrderByDescending - something is wrong with my code:S
    vertices = vertices.OrderBy(v => v.Value).ToDictionary(k => k.Key, v => v.Value);

    return vertices.Select(v => new Vertex(v.Key.X, v.Key.Y)).ToArray();
}

private static double Angle(Vertex v1, Vertex v2, double offsetInDegrees = 0.0)
{
    return (RadianToDegree(Math.Atan2(-v2.Y + v1.Y, -v2.X + v1.X)) + offsetInDegrees);
}

public static double RadianToDegree(double radian)
{
    var degree = radian * (180.0 / Math.PI);
    if (degree < 0)
        degree = 360 + degree;

    return degree;
}
  • vs is my set of 3 nearest points
  • current and previous are obvious:)
Nickon
  • 9,652
  • 12
  • 64
  • 119
  • So? whats exactly the problem? Are you unable to get the closes one or unable to calculate the angles. – Jeroen van Langen Aug 09 '13 at 14:12
  • When I get the points, they are in any order. Complete mess – Nickon Aug 09 '13 at 14:13
  • Something is a mistake made... But I can't find the source of the problem – Nickon Aug 09 '13 at 14:14
  • 1
    try: double angleInBetween = (180.0 - priorAngle) + nextAngle; And you should sort them first on distance between (using pythagoras) and select the top 3 – Jeroen van Langen Aug 09 '13 at 14:20
  • What is the Vertex class? You're sorting by Vertex.Value, but I don't know what that property/class is. This piece is really confusing `return vertices.Select(v => new Vertex(v.Key.X, v.Key.Y)).ToArray();` If that's where you're trying to sort... I don't understand why you're doing .ToDictionary() – Randy James Aug 09 '13 at 14:39
  • Be sure your angles are calculated not in absolute but in relative - meaning some of them could be negative) – Cyril Aug 09 '13 at 15:08
  • did you take the cross product to determine consistent rotation from one point to the next? i.e. looking for maximum angle in either clockwise or counter-clockwise direction each time. – haventchecked Aug 09 '13 at 15:16

1 Answers1

1

i didn't tested it, but i restyled a little, avoiding dictionaries. I think your mistake is in: double angleInBetween = 180.0 - (priorAngle + nextAngle); should be: double angleInBetween = (180.0 - priorAngle) + nextAngle;

    public struct Vertex
    {
        public double X { get; set; }
        public double Y { get; set; }
    }

    private static double CalcDistance(Vertex v1, Vertex v2)
    {
        double dX = (v2.X - v1.X);
        double dY = (v2.Y - v1.Y);

        return Math.Sqrt((dX * dX) + (dY * dY));
    }

    private static Vertex[] SortByAngle(IEnumerable<Vertex> vs, Vertex current, Vertex previous)
    {
        var verticesOnDistance = from vertex in vs
                                 where !vertex.Equals(current)
                                 let distance = CalcDistance(current, vertex)
                                 orderby distance
                                 select vertex;

        double priorAngle = Angle(previous, current);

        var verticeAngles = from vertex in verticesOnDistance.Take(3)
                            let nextAngle = Angle(current, vertex)
                            let angleInBetween = (180.0 - priorAngle) + nextAngle
                            orderby angleInBetween descending
                            select vertex;

        return verticeAngles.ToArray();
    }

    private static double Angle(Vertex v1, Vertex v2, double offsetInDegrees = 0.0)
    {
        return (RadianToDegree(Math.Atan2(-v2.Y + v1.Y, -v2.X + v1.X)) + offsetInDegrees);
    }

    public static double RadianToDegree(double radian)
    {
        var degree = radian * (180.0 / Math.PI);
        if (degree < 0)
            degree = 360 + degree;

        return degree;
    }

I'm running a little out of time here. I'll be on later... I'm not sure this is correct, but maybe shine another light on it...

Good luck

Jeroen van Langen
  • 21,446
  • 3
  • 42
  • 57