Найти выпуклый многоугольник охватывающий N точек на плоскости - C#
Формулировка задачи:
N точек на плоскости заданы своими координатами. Найти такой минимальный по площади выпуклый многоугольник, что все N точек лежат либо внутри этого многоугольника, либо на его границе (такой выпуклый многоугольник называется выпуклой оболочкой).
Решение задачи: «Найти выпуклый многоугольник охватывающий N точек на плоскости»
textual
Листинг программы
using System;
using System.Linq;
using System.Collections.Generic;
class Point : IComparable<Point>
{
private double[] coordinates = new double[2];
public Point(double x, double y)
{
coordinates[0] = x;
coordinates[1] = y;
}
public double this[int index]
{
get { return coordinates[index]; }
}
public double Distance(Point other)
{
double dx = this[0] - other[0];
double dy = this[1] - other[1];
return Math.Sqrt(dx * dx + dy * dy);
}
public override string ToString()
{
return String.Format("({0}; {1})", this[0], this[1]);
}
public int CompareTo(Point other)
{
int compare = Math.Sign(other[1] - this[1]);
if (compare == 0) compare = Math.Sign(this[0] - other[0]);
return compare;
}
}
class Line : IComparable<Line>
{
private Point[] points = new Point[2];
private double? alpha = null;
private double? length = null;
public Line(Point a, Point b)
{
points[0] = a;
points[1] = b;
}
public Point this[int index]
{
get { return points[index]; }
}
public double Alpha
{
get
{
if (alpha == null)
{
alpha = Math.Atan2(this[1][1] - this[0][1], this[1][0] - this[0][0]);
if (alpha < 0.0) alpha += Math.PI + Math.PI;
}
return (double)alpha;
}
}
public double Length
{
get
{
if (length == null)
{
length = this[0].Distance(this[1]);
}
return (double)length;
}
}
public int CompareTo(Line other)
{
int compare = Math.Sign(this.Alpha - other.Alpha);
if (compare == 0) compare = Math.Sign(other.Length - this.Length);
return compare;
}
}
class Corner : IComparable<Corner>
{
private Line[] lines = new Line[2];
private double? phi = null;
public Corner(Line ab, Point c)
{
lines[0] = ab;
lines[1] = new Line(ab[1], c);
}
public Line this[int index]
{
get { return lines[index]; }
}
public double Phi
{
get
{
if (phi == null)
{
phi = this[1].Alpha - this[0].Alpha;
if (phi < 0.0) phi += Math.PI + Math.PI;
}
return (double)phi;
}
}
public int CompareTo(Corner other)
{
int compare = Math.Sign(this.Phi - other.Phi);
if (compare == 0) compare = Math.Sign(other[1].Length - this[1].Length);
return compare;
}
}
class Program
{
public static void Main()
{
List<Point> points = new List<Point>();
for (int i = -2; i <= 2; i++)
{
for (int j = -2; j <= 2; j++)
{
points.Add(new Point((double)i, (double)j));
}
}
Point first = points.Max();
Line last = points
.Where(p => p.CompareTo(first) != 0)
.Select(p => new Line(first, p))
.Min();
List<Line> lines = new List<Line>();
lines.Add(last);
while ((last = lines[lines.Count - 1])[1].CompareTo(first) != 0)
{
Corner corner = points
.Where(p => p.CompareTo(last[0]) != 0 && p.CompareTo(last[1]) != 0)
.Select(p => new Corner(last, p))
.Min();
lines.Add(corner[1]);
}
foreach (Line line in lines)
{
Console.WriteLine(line[0]);
}
}
}