78 lines
2.2 KiB
C#
78 lines
2.2 KiB
C#
using System;
|
|
|
|
namespace StructureHelperCommon.Models.Shapes
|
|
{
|
|
public class PolygonCalculator : IPolygonCalculator
|
|
{
|
|
public double GetPerimeter(ILinePolygonShape polygon)
|
|
{
|
|
if (polygon.Vertices.Count < 2)
|
|
return 0;
|
|
|
|
double perimeter = 0;
|
|
|
|
for (int i = 0; i < polygon.Vertices.Count - 1; i++)
|
|
{
|
|
perimeter += Distance(polygon.Vertices[i].Point, polygon.Vertices[i + 1].Point);
|
|
}
|
|
|
|
if (polygon.IsClosed && polygon.Vertices.Count > 2)
|
|
{
|
|
perimeter += Distance(polygon.Vertices[^1].Point, polygon.Vertices[0].Point);
|
|
}
|
|
|
|
return perimeter;
|
|
}
|
|
|
|
public double GetArea(ILinePolygonShape polygon)
|
|
{
|
|
if (!polygon.IsClosed || polygon.Vertices.Count < 3)
|
|
return 0;
|
|
|
|
// Shoelace formula
|
|
double sum = 0;
|
|
for (int i = 0; i < polygon.Vertices.Count; i++)
|
|
{
|
|
var p1 = polygon.Vertices[i].Point;
|
|
var p2 = polygon.Vertices[(i + 1) % polygon.Vertices.Count].Point;
|
|
sum += (p1.X * p2.Y - p2.X * p1.Y);
|
|
}
|
|
|
|
return Math.Abs(sum) / 2.0;
|
|
}
|
|
|
|
public bool ContainsPoint(ILinePolygonShape polygon, IPoint2D point)
|
|
{
|
|
if (!polygon.IsClosed || polygon.Vertices.Count < 3)
|
|
return false;
|
|
|
|
// Ray casting algorithm
|
|
bool inside = false;
|
|
int j = polygon.Vertices.Count - 1;
|
|
|
|
for (int i = 0; i < polygon.Vertices.Count; i++)
|
|
{
|
|
var pi = polygon.Vertices[i].Point;
|
|
var pj = polygon.Vertices[j].Point;
|
|
|
|
if (((pi.Y > point.Y) != (pj.Y > point.Y)) &&
|
|
(point.X < (pj.X - pi.X) * (point.Y - pi.Y) / (pj.Y - pi.Y) + pi.X))
|
|
{
|
|
inside = !inside;
|
|
}
|
|
j = i;
|
|
}
|
|
|
|
return inside;
|
|
}
|
|
|
|
private double Distance(IPoint2D p1, IPoint2D p2)
|
|
{
|
|
double dx = p2.X - p1.X;
|
|
double dy = p2.Y - p1.Y;
|
|
return Math.Sqrt(dx * dx + dy * dy);
|
|
}
|
|
}
|
|
|
|
}
|