using System.Collections.Generic;
public static void Main()
Console.WriteLine("Hello World");
string input = "-7.550922_4.1042356_0.6384368_5.4494743;-1.7815869_3.484396_-7.300193_2.5778723;2.1230996_-3.5886428_-0.5217197_-4.023099;-7.300193_2.5778723_-7.5509224_4.1042356;-0.5217197_-4.0230985_-0.6676799_-3.1345446;-0.8337523_-2.285698_-1.7815874_3.4843962;0.6384367_5.449475_2.1230998_-3.588643;";
var aa = BTCMep.Helpers.AreaHelper.PolygonArea(input);
public static double PolygonArea(string input)
var originalLines = input.Split(';').Where(s => !string.IsNullOrEmpty(s)).Select(a => a.Split('_').Select(b => Convert.ToDouble(b)).ToArray()).ToList();
if (originalLines.Any(s => s.Length != 4))
var convertedLines = originalLines.Select(s => new Line(Math.Round(s.ElementAt(0), 2),
Math.Round(s.ElementAt(1), 2),
Math.Round(s.ElementAt(2), 2),
Math.Round(s.ElementAt(3), 2))).ToList();
var groups = DetectGroups(convertedLines);
groups = ConnectGroups(groups);
var groupedLines = groups.First().Select(s => new Line(s.ElementAt(0),
s.ElementAt(3))).ToList();
var distincedPoints = GetPoints(groupedLines);
var X = distincedPoints.Select(s => s.X).ToList();
var Y = distincedPoints.Select(s => s.Y).ToList();
for (int i = 0; i < n; i++)
area += (X[j] + X[i]) * (Y[j] - Y[i]);
return Math.Round(Math.Abs(area / 2.0), 2);
private static List<List<double[]>> ConnectGroups(List<List<double[]>> groups)
#region Process to find the connection and merge to group.
var mergedGroup = groups.SelectMany(s => s.Select(a => new Line(a.ElementAt(0),
a.ElementAt(3)))).ToList();
var processedGroups = new List<List<double[]>>();
for (int i = 0; i < groups.Count; i++)
processedGroups.Add(groups[i]);
var currentPoints = new List<double[]>();
foreach (var item in groups[i])
var point1 = new double[] { item.ElementAt(0), item.ElementAt(1) };
var point2 = new double[] { item.ElementAt(2), item.ElementAt(3) };
currentPoints.Add(point1);
currentPoints.Add(point2);
var alonePoint = new double[] { processedGroups[i].Last().ElementAt(2), processedGroups[i].Last().ElementAt(3) };
var listPointForComparation = new List<double[]>();
var remainingGroups = groups.Except(processedGroups).SelectMany(s => s).ToList();
foreach (var item in remainingGroups)
var point1 = new double[] { item.ElementAt(0), item.ElementAt(1) };
var point2 = new double[] { item.ElementAt(2), item.ElementAt(3) };
if (!listPointForComparation.Contains(point1))
listPointForComparation.Add(point1);
if (!listPointForComparation.Contains(point2))
listPointForComparation.Add(point2);
if (!listPointForComparation.Any())
var minDistance = double.PositiveInfinity;
var closestPoint = new double[0];
foreach (var p in listPointForComparation.Distinct())
var distance = Math.Sqrt(p.Zip(alonePoint, (a, b) => Math.Pow(a - b, 2)).Sum());
if (distance < minDistance)
if (closestPoint.Length == 0)
var newLine = new Line(alonePoint.ElementAt(0), alonePoint.ElementAt(1), closestPoint.ElementAt(0), closestPoint.ElementAt(1));
if (mergedGroup.All(s => (s.x1 == newLine.x1 && s.y1 == newLine.y1) || (s.x1 == newLine.x2 && s.y1 == newLine.y2)))
mergedGroup.Add(newLine);
groups = DetectGroups(mergedGroup);
#region Line Group Detector
private static List<List<double[]>> DetectGroups(List<Line> lines)
var groups = new List<List<double[]>>();
var graph = BuildGraph(lines);
var visited = new HashSet<Line>();
foreach (var line in lines)
if (visited.Contains(line))
var group = new List<Line>();
TraverseGroup(line, graph, visited, group);
groups.Add(group.Select(s => new double[] { s.x1, s.y1, s.x2, s.y2 }).ToList());
private static Dictionary<Line, List<Line>> BuildGraph(List<Line> lines)
var graph = new Dictionary<Line, List<Line>>();
foreach (var line1 in lines)
foreach (var line2 in lines)
if (line1 != line2 && line1.ConnectsTo(line2))
if (!graph.ContainsKey(line1))
graph[line1] = new List<Line>();
if (!graph.ContainsKey(line2))
graph[line2] = new List<Line>();
private static void TraverseGroup(Line line, Dictionary<Line, List<Line>> graph, HashSet<Line> visited, List<Line> group)
if (graph.ContainsKey(line))
foreach (var neighbor in graph[line])
if (!visited.Contains(neighbor))
TraverseGroup(neighbor, graph, visited, group);
private static List<List<PointF>> FindPolygons(List<PointF> points)
List<List<PointF>> polygons = new List<List<PointF>>();
List<PointF> polygon = new List<PointF>();
PointF lastPoint = polygon[0];
PointF nearestPoint = FindNearestPoint(lastPoint, points);
if (nearestPoint == PointF.Empty)
polygon.Add(nearestPoint);
points.Remove(nearestPoint);
lastPoint = nearestPoint;
private static PointF FindNearestPoint(PointF point, List<PointF> points)
PointF nearestPoint = PointF.Empty;
double minDistance = double.MaxValue;
foreach (PointF p in points)
double distance = Math.Sqrt(Math.Pow(point.X - p.X, 2) + Math.Pow(point.Y - p.Y, 2));
if (distance < minDistance)
private static List<PointF> GetPoints(List<Line> lines, PointF? findx = null)
List<PointF> points = new List<PointF>();
foreach (Line line in lines)
if (!findx.HasValue || findx.Value == PointF.Empty)
var remainingLines = lines.Where(s => s != line).ToList();
points.AddRange(GetPoints(remainingLines));
else if (findx == line.Point1)
var remainingLines = lines.Where(s => s != line).ToList();
points.AddRange(GetPoints(remainingLines));
else if (findx == line.Point2)
var remainingLines = lines.Where(s => s != line).ToList();
points.AddRange(GetPoints(remainingLines));
public double x1, y1, x2, y2;
public PointF Point1 { get { return new PointF { X = (float)x1, Y = (float)y1 }; } }
public PointF Point2 { get { return new PointF { X = (float)x2, Y = (float)y2 }; } }
public Line(double x1, double y1, double x2, double y2)
public bool ConnectsTo(Line other)
return x1 == other.x2 && y1 == other.y2 || x2 == other.x1 && y2 == other.y1;
class ArrayComparer : IEqualityComparer<double[]>
public bool Equals(double[] x, double[] y)
return x.SequenceEqual(y);
public int GetHashCode(double[] obj)
return string.Join(",", obj).GetHashCode();