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

一、问题分析

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

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

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

 

二、考虑像素间距转换

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

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

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

2.1 方法一

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 方法二

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 方法一

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 方法二

//计算多边形面积
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 多边形的重叠部分需要注意 

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

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

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

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

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

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

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/396317.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java之贪婪爬取和非贪婪爬取

public class RegexDemo6 {public static void main(String[] args) {String str"java自从95年问世以来,abbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa" " 经历了很多版本,目前企业中用的最多是java8和java11,""因为这俩个是长期版本,下一个长期支持版本是java…

【平衡二叉树】数据结构—平衡二叉树

平衡二叉树&#xff08;Balanced Binary Tree&#xff09;是一种特殊的二叉树&#xff0c;它的左右子树的高度差不超过1&#xff0c;这样可以保证树的高度相对较低&#xff0c;从而使得查找、插入和删除操作的时间复杂度保持在 。 平衡二叉树的基本概念 1. 二叉树&#xff1a…

RTT-网络组件-AT命令-未完成

AT指令文档 调用树 at_client_init();at_client_para_init();client_parser();struct at_client {rt_device_t device;at_status_t status;char end_sign;char *send_buf;/* The maximum supported send cmd length */rt_size_t send_bufsz;/* The length of last cmd */rt_si…

【HBZ分享】Spring启动时核心refresh方法流程

refresh核心代码所在位置 在AbstractApplicationContext类中的refresh方法中 refresh的业务流程编排 调用obtainFreshBeanFactory()去创建一个全新的BeanFactory工厂&#xff0c;类型为DefaultListableBeanFctory&#xff0c;其功能为【解析xml】将里面bean标签内容解析成【…

尚硅谷谷粒商城项目笔记——十、调试前端项目renren-fast-vue【电脑CPU:AMD】

十、调试前端项目renren-fast-vue 如果遇到其他问题发在评论区&#xff0c;我看到后解决 1 先下载安装git git官网下载地址 2 登录gitee搜索人人开源找到renren-fast-vue复制下载链接。【网课视频中也有详细步骤】 3 下载完成后桌面会出现renren-fast-vue的文件夹 4 开始调…

对于springboot无法连接redis解决方案

对于springboot无法连接redis解决方案 一、测试是否能在本地应用上访问到你的redis&#xff08;如果是部署在linux上的话&#xff09;1. 开启telnet功能2. 开始测试端口是否能访问到&#xff08;适用于所有&#xff0c;包括MQ&#xff09;3. 开放6379端口4. 看spring的配置文件…

java springboot mqtt控制海康摄像头

GHHKControlService 接口 package org.gh.ghhk.service;public interface GHHKControlService {boolean monitorControl(String payload);}GHHKControlServiceImpl 实现类 ​ package org.gh.ghhk.service.impl;import com.alibaba.fastjson.JSONArray; import com.alibaba.…

MySQL —— CRUD

CRUD CRUD 即增加(Create)、查询(Retrieve)、更新(Update)、删除(Delete)四个单词的首字母缩写。 我们常说增删查改&#xff0c;增删改查… 这里我们的增删查改是对表格的数据行进行操作的~~ 新增 1.1.1 单行数据 全列插入 插入一行新数据行&#xff0c;使用 insert into t…

微信小程序项目-宠物商城项目uniapp源码和代码讲解

&#x1f939;‍♀️潜意识起点&#xff1a;个人主页 &#x1f399;座右铭&#xff1a;得之坦然&#xff0c;失之淡然。 &#x1f48e;擅长领域&#xff1a;大前端 是的&#xff0c;我需要您的&#xff1a; &#x1f9e1;点赞❤️关注&#x1f499;收藏&#x1f49b; 是我…

Django 自定义用户 VS 用户资料

Django是一个流行的Web框架&#xff0c;它提供了一套完整的用户认证系统&#xff0c;其中包括内置的User模型用于存储基本的用户信息&#xff0c;如用户名、密码等。然而&#xff0c;如果我们需要更详细的用户资料管理&#xff0c;比如添加更多的字段或者自定义验证规则&#x…

分布式主键 详解

文章目录 雪花算法结合分库分表的问题问题出现原因分析解决思路 分布式主键要考虑的问题主键生成策略雪花算法详解时间戳位问题工作进程位问题序列号位问题根据雪花算法扩展基因分片法 雪花算法结合分库分表的问题 问题出现 使用ShardingSphere框架自带的雪花算法生成分布式主…

LVS(Linux virual server)详解

目录 一、LVS&#xff08;Linux virual server&#xff09;是什么&#xff1f; 二、集群和分布式简介 2.1、集群Cluster 2.2、分布式 2.3、集群和分布式 三、LVS运行原理 3.1、LVS基本概念 3.2、LVS集群的类型 3.2.1 nat模式 3.2.2 DR模式 3.2.3、LVS工作模式总结 …

黑马Java零基础视频教程精华部分_18_Arrays各种方法

系列文章目录 文章目录 系列文章目录Arrays简介Arrays各种方法toString代码示例binarySearch代码示例copyOf代码示例copyOfRange和fill代码示例sort代码示例 Arrays简介 操作数组的工具类。 Arrays各种方法 toString代码示例 int[]arr{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; //to…

非线性链表之树结构和堆的代码实现

目录 一.树的结构 1.1树概念及结构 1.2 树的相关概念 1.3 树的表示 二. 二叉树概念及结构 2.1概念 2.2 特殊的二叉树&#xff1a; 2.3 二叉树的性质 2.4 二叉树的存储结构 2.4.1. 顺序存储 ​2.4.2. 链式存储 三. 堆的概念及结构 定义 性质 堆的实现 四.堆的代…

kafka零拷贝sendfile及mmap简述

概述 通常在选型比较消息中间件时&#xff0c;都会在备选栏有kafka&#xff1b; kafka突出的特点就是高吞吐&#xff0c;零拷贝&#xff1b; 这里的零拷贝其实就是内核和用户空间之间没有copy&#xff0c;并不是真的0拷贝&#xff1b; 毕竟数据在磁盘&#xff0c;要读到网卡发…

k8s集群管理 Pod管理命令

k8s集群管理命令 信息查询命令 子命令说明help用于查看命令及子命令的帮助信息cluster-info显示集群的相关配置信息api-resources查看当前服务器上所有的资源对象api-versions查看当前服务器上所有资源对象的版本config管理当前节点上的认证信息 资源对象概述 Pod概述 Pod 管…

# 利刃出鞘_Tomcat 核心原理解析(三)

利刃出鞘_Tomcat 核心原理解析&#xff08;三&#xff09; 一、 Tomcat专题 - Tomcat架构 - 启动流程 1、Tomcat 启动流程 2、Tomcat 启动 步骤 : 1&#xff09; 启动tomcat &#xff0c; 需要调用 bin/startup.bat (在linux 目录下 , 需要调用 bin/startup.sh) &#xff0c…

Dubbo框架实现RPC远程调用包括nacos的配置和初始化

项目背景介绍 这个技术我是直接在项目中运用并且学习的&#xff0c;所以我写笔记最优先的角度就是从项目背景出发 继上一次API网关完成了这个实现用户调用一次接口之后让接口次数增多的操作之后&#xff0c;又迎来了新的问题。 就是我们在调用接口的时候需要对用户进行校验&…

【Linux】详解IPC:共享内存

目录 IPC 共享内存 1.理解 2.运用 1. 创建 ipc - shmget 2. 创建 key - ftok ⭕shmid vs key 3. 连接 - shmat 4. 脱离 - shmdt 5. 控制/删除 - shmctl 总结 代码示例 3.实验 comm.hpp processa.cc processb.cc log.hpp makefile 测试 4.思考 IPC 进程间通…

vue3引入模块报错:无法找到模块“xxx”的声明文件

使用vue3ts导入vue文件的时候&#xff0c;报错&#xff1a;找不到模块“./XXX.vue”或其相应的类型声明 这是由于&#xff1a;Vue 文件并不是标准的 JavaScript 模块&#xff0c;因此 TypeScript 需要通过这种声明方式来理解和处理这些文件 我是使用vite创建的项目&#xff0…