Files
StructureHelper/StructureHelperCommon/Models/Shapes/Logics/PolygonCalculator.cs
Evgeny Redikultsev c31e56869c Add polygon shape
2025-09-07 08:12:07 +05:00

78 lines
2.2 KiB
C#

using System;
namespace StructureHelperCommon.Models.Shapes
{
public class PolygonCalculator : IPolygonCalculator
{
public double GetPerimeter(IPolygonShape 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(IPolygonShape 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(IPolygonShape 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);
}
}
}