【C#】计算多边形的面积

一、问题分析

在 C# 中计算多边形面积的一种常见方法是使用顶点坐标。

假设您有一个由一系列 (x, y) 顶点坐标定义的多边形,您可以使用"鞋带公式"(也称为高斯公式)来计算其面积。

如果是计算多边形的面积可以分为正常多边形、dicom图像中的多边形,这两种多边形可能考虑是否需要像素间距的转换问题。

二、考虑像素间距转换

在处理 DICOM 图像中的多边形面积计算时,如果需要更精确的结果,通常是需要考虑像素间距的。

像素间距在 DICOM 图像中用于描述每个像素在实际物理空间中的大小。如果不考虑像素间距,计算得到的面积只是基于像素坐标的数值,而不是真实的物理面积。

以下是一个示例,展示如何在计算多边形面积时考虑像素间距:

2.1 方法一

cs 复制代码
using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // 假设多边形的顶点坐标列表
        List<Point> points = new List<Point>
        {
            new Point(0, 0),
            new Point(1, 0),
            new Point(1, 1),
            new Point(0, 1)
        };

        // 假设像素间距
        double pixelSpacingX = 0.5; 
        double pixelSpacingY = 0.5;

        double area = CalculatePolygonAreaWithSpacing(points, pixelSpacingX, pixelSpacingY);
        Console.WriteLine($"考虑像素间距后的多边形面积为: {area}");
    }

    static double CalculatePolygonAreaWithSpacing(List<Point> points, double pixelSpacingX, double pixelSpacingY)
    {
        int count = points.Count;
        double area0 = 0;
        double area1 = 0;

        for (int i = 0; i < count; i++)
        {
            var x = points[i].X * pixelSpacingX;
            var y = (i + 1 < count? points[i + 1].Y : points[0].Y) * pixelSpacingY;
            area0 += x * y;

            var lat = points[i].Y * pixelSpacingY;
            var lon = (i + 1 < count? points[i + 1].X : points[0].X) * pixelSpacingX;
            area1 += x * y;
        }

        return Math.Round(Math.Abs(0.5 * (area0 - area1)), 2); 
    }

    class Point
    {
        public double X { get; set; }
        public double Y { get; set; }

        public Point(double x, double y)
        {
            X = x;
            Y = y;
        }
    }
}

2.2 方法二

cs 复制代码
public double CalculatePolygonArea()
{
    Tuple<double, double>[] tupleArray = new Tuple<double, double>[m_MaxPointNum];
    for (int i = 0; i < m_MaxPointNum; i++)
    {
        var point = m_Points[i];
        tupleArray[i] = Tuple.Create((double)point.X, (double)point.Y);
    }
    WhaleFC.Image.DicomImg dcm = (WhaleFC.Image.DicomImg)m_WndPara.GetDCM();
    double[] nArrPixelSpacing = dcm.GetPixelSpacing();
    double nPixelSpacingY = nArrPixelSpacing[0];
    double nPixelSpacingX = nArrPixelSpacing[1];
    double area = 0;
    for (int i = 0; i < m_MaxPointNum; i++)
    {
        double x1 = tupleArray[i].Item1 * nPixelSpacingX;
        double y1 = tupleArray[i].Item2 * nPixelSpacingY;
        double x2 = tupleArray[(i + 1) % m_MaxPointNum].Item1 * nPixelSpacingX;
        double y2 = tupleArray[(i + 1) % m_MaxPointNum].Item2 * nPixelSpacingY;
        area += (x1 * y2) - (x2 * y1);
    }
    return Math.Abs(area / 2.0);
}

三、不考虑像素间距转换

要计算 DICOM(Digital Imaging and Communications in Medicine,医学数字成像和通信)图像中多边形的面积,一种常见的方法是使用鞋带公式(Shoelace Formula)或称为高斯面积公式。以下是使用 C#实现计算多边形面积的示例代码:

3.1 方法一

cs 复制代码
using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // 假设多边形的顶点坐标列表
        List<Point> points = new List<Point>
        {
            new Point(0, 0),
            new Point(1, 0),
            new Point(1, 1),
            new Point(0, 1)
        };

        double area = CalculatePolygonArea(points);
        Console.WriteLine($"多边形面积为: {area}");
    }

    static double CalculatePolygonArea(List<Point> points)
    {
        int count = points.Count;
        double area0 = 0;
        double area1 = 0;

        for (int i = 0; i < count; i++)
        {
            var x = points[i].X;
            var y = i + 1 < count? points[i + 1].Y : points[0].Y;
            area0 += x * y;

            var lat = points[i].Y;
            var lon = i + 1 < count? points[i + 1].X : points[0].X;
            area1 += x * y;
        }

        return Math.Round(Math.Abs(0.5 * (area0 - area1)), 2); 
    }

    class Point
    {
        public double X { get; set; }
        public double Y { get; set; }

        public Point(double x, double y)
        {
            X = x;
            Y = y;
        }
    }
}

3.2 方法二

cs 复制代码
//计算多边形面积
public double CalculatePolygonArea(Point[] points)
{
    double area = 0;
    int j = points.Length - 1;
    for (int i = 0; i < points.Length; i++)
    {
        area += (points[j].X + points[i].X) * (points[j].Y - points[i].Y);
        j = i;
    }
    return Math.Abs(area / 2.0);
}

四、注意点

4.1 多边形是闭合的

请注意,为了确保多边形闭合,最后一个顶点和第一个顶点应该是相同的。如果提供的顶点不形成闭合多边形,则该函数会自动处理这种情况,因为它通过取模操作将最后一个顶点与第一个顶点关联起来。

4.2 多边形的重叠部分需要注意

多边形的重叠部分是否重复计算???

如果一个多边形的边相互交叉,那么按照鞋带公式计算得到的面积可能不会反映实际的几何形状,因为该公式假设多边形是简单且非自相交的。对于自相交多边形(即星形多边形),简单的鞋带公式可能无法正确计算面积,因为它可能会重复计算重叠区域。

为了正确处理自相交多边形的情况,一种方法是将其分解成多个不相交的简单多边形(通常是三角形),然后分别计算这些简单多边形的面积并进行求和。这通常涉及到更复杂的算法,例如三角剖分或者扫描线算法。

下面是一个简化的示例,使用一种方法来近似处理自相交多边形。这种方法基于对多边形边的处理,尝试确定每条边对面积的贡献。如果一条边跨越了另一条边,则需要调整计算逻辑以避免重叠区域被重复计算。但是请注意,这并不是一个完美的解决方案,对于复杂的自相交多边形,这种方法可能不会总是给出正确的结果。

以下是一个简化的处理自相交多边形的方法:

cs 复制代码
using System;
using System.Collections.Generic;

public class PolygonAreaCalculator
{
    public static double CalculatePolygonArea(List<Point> points)
    {
        if (points.Count < 3)
            throw new ArgumentException("There must be at least three points to define a polygon.");

        // Add the first point at the end to close the polygon.
        points.Add(points[0]);

        double area = 0.0;
        int n = points.Count;

        for (int i = 0; i < n - 1; i++)
        {
            Point p1 = points[i];
            Point p2 = points[i + 1];

            // Calculate the area contribution of each edge.
            area += (p1.X * p2.Y - p2.X * p1.Y);

            // Check if this edge crosses any other edges.
            for (int j = i + 2; j < n - 1; j++)
            {
                Point p3 = points[j];
                Point p4 = points[j + 1];

                // Check if the line segments (p1, p2) and (p3, p4) intersect.
                if (SegmentsIntersect(p1, p2, p3, p4))
                {
                    // Adjust the area calculation based on the intersection.
                    // This part is simplified and may not handle all cases correctly.
                    // A more sophisticated algorithm would be needed for complex cases.
                    area -= (p1.X * p2.Y - p2.X * p1.Y);
                }
            }
        }

        // Take the absolute value and divide by 2 to get the final area.
        return Math.Abs(area) / 2.0;
    }

    private static bool SegmentsIntersect(Point p1, Point p2, Point p3, Point p4)
    {
        // Implement a simple line segment intersection check.
        // This is a simplified version that does not handle all edge cases.
        double d1 = Direction(p3, p4, p1) * Direction(p3, p4, p2);
        double d2 = Direction(p1, p2, p3) * Direction(p1, p2, p4);

        return (d1 <= 0) && (d2 <= 0);
    }

    private static double Direction(Point p1, Point p2, Point p3)
    {
        return (p2.Y - p1.Y) * (p3.X - p2.X) - (p2.X - p1.X) * (p3.Y - p2.Y);
    }
}

public struct Point
{
    public double X;
    public double Y;

    public Point(double x, double y)
    {
        X = x;
        Y = y;
    }
}

这个方法尝试检查每条边是否与其他边相交,并根据交点调整面积计算。然而,这仍然是一种简化的处理方式,对于复杂的自相交多边形,需要更高级的算法来正确地计算面积。

如果您确实需要处理复杂的自相交多边形,并希望获得准确的结果,您可能需要考虑使用专门的几何处理库,如 CGAL (Computational Geometry Algorithms Library) 或者类似的库。

4.3 获取GDI+获取两个多边形区域相交、非相交区域

【C#】 使用GDI+获取两个多边形区域相交、非相交区域-CSDN博客文章浏览阅读227次。【C#】 使用GDI+获取两个多边形区域相交、非相交区域https://blog.csdn.net/wangnaisheng/article/details/140527315

4.4 在一个给定的宽、高范围内,获取到该多边形内部的所有坐标集合?

【C#】在一个给定的宽、高范围内,获取到该多边形内部的所有坐标集合?-CSDN博客文章浏览阅读594次,点赞9次,收藏7次。【C#】在一个给定的宽、高范围内,获取到该多边形内部的所有坐标集合?https://blog.csdn.net/wangnaisheng/article/details/140513467

相关推荐
码农君莫笑3 小时前
使用blazor开发信息管理系统的应用场景
数据库·信息可视化·c#·.net·visual studio
可喜~可乐5 小时前
C# WPF开发
microsoft·c#·wpf
666和7779 小时前
C#的单元测试
开发语言·单元测试·c#
小码编匠10 小时前
WPF 星空效果:创建逼真的宇宙背景
后端·c#·.net
Schwertlilien10 小时前
图像处理-Ch1-数字图像基础
图像处理·人工智能·算法
向宇it13 小时前
【从零开始入门unity游戏开发之——unity篇02】unity6基础入门——软件下载安装、Unity Hub配置、安装unity编辑器、许可证管理
开发语言·unity·c#·编辑器·游戏引擎
yngsqq13 小时前
一键打断线(根据相交点打断)——CAD c# 二次开发
windows·microsoft·c#
游客52014 小时前
opencv中的常用的100个API
图像处理·人工智能·python·opencv·计算机视觉
TENET信条14 小时前
day53 第十一章:图论part04
开发语言·c#·图论
anlog15 小时前
C#在自定义事件里传递数据
开发语言·c#·自定义事件