using System.Collections.Generic;
public static void Main()
var x = new double[]{-137.422, -62.9051, 6.80396, 127.393, 128.194, 69.3018, -0.807953, -50.0851, -58.0976, -6.0161, 65.2955, 123.787, 178.673, 170.66, 134.203, 28.4378, -68.1133, -133.415};
var y = new double[]{22.4472, 93.3582, 112.188, 106.98, 67.3175, 70.5225, 65.7149, 41.6773, -10.0036, -40.0506, -2.39166, -10.8048, -88.5265, -143.412, -170.254, -162.642, -129.791, -41.2525};
var pt = PolyLabel.GetPoleOfInaccessibility( x, y, 0.1f );
Console.WriteLine( "[{0},{1}]", pt[0], pt[1] );
public MapPoint( double x, double y )
public double X { get; set; }
public double Y { get; set; }
public double Half { get; set; }
public double Distance { get; set; }
public double Max { get; set; }
public Cell(double x, double y, double half, List<List<MapPoint>> polygon)
Distance = Adjunct.PointToPolygonDistance(x, y, polygon);
Max = Distance + Half * Math.Sqrt(2);
public class CellMaxComparer : IComparer<Cell>
public int Compare(Cell x, Cell y)
return x.Max.CompareTo(y.Max);
public static class Adjunct
public static double PointToPolygonDistance(double x, double y, List<List<MapPoint>> polygon)
double minDistSq = double.MaxValue;
for (int k = 0; k < polygon.Count; k++)
List<MapPoint> ring = polygon[k];
for (int i = 0; i < count; j = i++)
if (((a.Y > y) != (b.Y > y)) && (x < ((b.X - a.X) * (y - a.Y) / (b.Y - a.Y + a.X))))
minDistSq = Math.Min(minDistSq, GetSegDistSq(x, y, a, b));
return (inside ? 1 : -1) * Math.Sqrt(minDistSq);
public static double GetSegDistSq(double px, double py, MapPoint a, MapPoint b)
var t = ((px - x) * dx + (py - y) * dy) / (dx * dx + dy * dy);
return dx * dx + dy * dy;
public static double[] GetPoleOfInaccessibility( double[] x, double[] y, float precision )
var lst = new List<List<MapPoint>>{ new List<MapPoint>() };
for ( int i = 0; i < x.Length; i++ )
lst[0].Add( new MapPoint( x[i], y[i] ) );
var result = PoleOfInaccessibility( lst, precision );
return new double[]{ result.Item1, result.Item2 };
public static Tuple<double, double> PoleOfInaccessibility(List<List<MapPoint>> polygon, double precision = 1.0, bool debug = false)
double minY = double.MaxValue;
double maxY = double.MinValue;
double minX = double.MaxValue;
double maxX = double.MinValue;
for (int i = 0; i < polygon[0].Count; i++)
MapPoint p = polygon[0][i];
if (p.X < minX) minX = p.X;
if (p.Y < minY) minY = p.Y;
if (p.X > maxX) maxX = p.X;
if (p.Y > maxY) maxY = p.Y;
double width = maxX - minX;
double height = maxY - minY;
double cellSize = Math.Min(width, height);
double half = cellSize / 2;
List<Cell> cellList = new List<Cell>();
CellMaxComparer comp = new CellMaxComparer();
return Tuple.Create<double, double>(minX, minY);
for (double x = minX; x < maxX; x += cellSize)
for (double y = minY; y < maxY; y += cellSize)
cellList.Add(new Cell(x + half, y + half, half, polygon));
Cell bestCell = GetCentroidCell(polygon);
Cell bboxCell = new Cell(minX + width / 2, minY + height / 2, 0, polygon);
if (bboxCell.Distance > bestCell.Distance)
int numProbes = cellList.Count;
while (cellList.Count != 0)
int i = cellList.Count - 1;
if (cell.Distance > bestCell.Distance)
if (cell.Max - bestCell.Distance <= precision) continue;
cellList.Add(new Cell(cell.X - half, cell.Y - half, half, polygon));
cellList.Add(new Cell(cell.X + half, cell.Y - half, half, polygon));
cellList.Add(new Cell(cell.X - half, cell.Y + half, half, polygon));
cellList.Add(new Cell(cell.X + half, cell.Y + half, half, polygon));
return Tuple.Create<double, double>(bestCell.X, bestCell.Y);
public static Cell GetCentroidCell(List<List<MapPoint>> polygon)
List<MapPoint> points = polygon[0];
int count = points.Count;
for (int i = 0; i < count; j = i++)
double f = a.X * b.Y - b.X * a.Y;
return new Cell(points[0].X, points[0].Y, 0, polygon);
return new Cell(x / area, y / area, 0, polygon);