TIN体积

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.IO;
using System.Drawing;

namespace TIN_321
{
    public partial class Form1 : Form
    {
        string[] all_lines;
        List<Mypoints> allPoints = new List<Mypoints>(); 
        string jzH;

        // 初始三角网构建
        List<Triangle> T1 = new List<Triangle>(); 
        List<Triangle> T2 = new List<Triangle>(); 
        List<Edge> S = new List<Edge>(); 

        public Form1()
        {
            InitializeComponent();
        }
        private bool isDragging = false;
        private Point mouseDownLocation; 

        private void 打开文件ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog op = new OpenFileDialog();
            if (op.ShowDialog() == DialogResult.OK)
            {
                all_lines = File.ReadAllLines(op.FileName);
            }
            else
            {
                return;
            }

            try
            {
                jzH = all_lines[0].Split(',')[1];
                for (int i = 2; i < all_lines.Length; i++)
                {
                    string[] part = all_lines[i].Split(',');
                    Mypoints p = new Mypoints
                    {
                        name = part[0],
                        x = double.Parse(part[1]),
                        y = double.Parse(part[2]),
                        h = double.Parse(part[3])
                    };
                    allPoints.Add(p);
                    dataGridView1.Rows.Add(part[0], part[1], part[2], part[3]);
                }
                toolStripStatusLabel1.Text = "导入成功!";
                toolStripStatusLabel2.Text = "基准高程:" + jzH;
            }
            catch
            {
                MessageBox.Show("导入失败");
                return;
            }
        }

        private void 计算三角网及体积ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("正在计算,请稍后");
            if (allPoints.Count < 3)
            {
                MessageBox.Show("至少需要三个点才能计算凸包!");
                return;
            }

            // 找到最下方的点,作为基点
            Mypoints P0 = allPoints.OrderBy(p => p.y).ThenBy(p => p.x).First();

            // 排序其他点
            List<Mypoints> sortedPoints = allPoints.Where(p => p != P0).ToList();
            sortedPoints.Sort((p1, p2) =>
            {
                double angle1 = Math.Atan2(p1.y - P0.y, p1.x - P0.x);
                double angle2 = Math.Atan2(p2.y - P0.y, p2.x - P0.x);

                if (angle1 == angle2)
                {
                    double distance1 = Distance(P0, p1);
                    double distance2 = Distance(P0, p2);
                    return distance2.CompareTo(distance1); // 保证按距离从远到近排列
                }
                return angle1.CompareTo(angle2); // 按角度排序
            });

            List<Mypoints> convexHull = new List<Mypoints> { P0, sortedPoints[0], sortedPoints[1] };

            foreach (var p in sortedPoints.Skip(2))
            {
                while (convexHull.Count >= 2 && CrossProduct(convexHull[convexHull.Count - 2], convexHull[convexHull.Count - 1], p) <= 0)
                {
                    convexHull.RemoveAt(convexHull.Count - 1);
                }
                convexHull.Add(p);
            }

            // 构建初始三角形
            List<Mypoints> innerPoints = allPoints.Where(p => !convexHull.Contains(p)).ToList();
            foreach (var p in innerPoints)
            {
                foreach (var edge in convexHull.Select((point, index) => new { point, index }))
                {
                    var triangle = new Triangle(p, edge.point, convexHull[(edge.index + 1) % convexHull.Count]);
                    T1.Add(triangle);
                }
            }

            // 生成三角网并移除无效三角形
            foreach (var p in innerPoints)
            {
                List<Triangle> tempT1 = new List<Triangle>(T1);
                foreach (var triangle in tempT1)
                {
                    double[] circumcenter = CalculateCircumcenter(triangle);
                    double x0 = circumcenter[0];
                    double y0 = circumcenter[1];
                    double r = circumcenter[2];
                    if (IsInsideCircumcircle(p, x0, y0, r))
                    {
                        T1.Remove(triangle);
                        T2.Add(triangle);
                    }
                }
                UpdateEdgesAndTriangles(T2, S, p);
            }

            RemoveSmallOrLargeTriangles(T1); 
            toolStripStatusLabel1.Text = "不规则三角网生成完成!";
            OutputFirstTwentyTriangles();
            richTextBox1.Clear();

            double balanceElevation = CalculateBalanceElevation(T1);
            richTextBox1.AppendText($"平衡高程: {balanceElevation}\n");

            double referenceHeight = double.Parse(jzH);
            CalculateCutFillVolume(T1, referenceHeight);
            DrawConvexHullPoints(convexHull);

            DrawTrianglesOnChart(T1);
            MessageBox.Show("完成!");
        }
        private void DrawConvexHullPoints(List<Mypoints> convexHull)
        {
            chart2.Series.Clear(); 

            var convexHullSeries = new System.Windows.Forms.DataVisualization.Charting.Series
            {
                Name = "ConvexHullPoints",
                ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Point,
                MarkerStyle = System.Windows.Forms.DataVisualization.Charting.MarkerStyle.Circle,
                MarkerSize = 10, 
                BorderWidth = 3, 
                Color = System.Drawing.Color.Red 
            };

            foreach (var point in convexHull)
            {
                convexHullSeries.Points.AddXY(point.x, point.y);
            }

            chart2.Series.Add(convexHullSeries);
            chart2.ChartAreas[0].AxisY.Minimum = 2800;
            chart2.ChartAreas[0].AxisY.Maximum = 3000;
        }

        private void DrawTrianglesOnChart(List<Triangle> triangles)
        {
            chart1.Series.Clear(); 

            var series = new System.Windows.Forms.DataVisualization.Charting.Series
            {
                Name = "Triangles",
                ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line,
                BorderWidth = 2
            };

            foreach (var triangle in triangles)
            {
                AddTriangleEdgesToChart(triangle, series);
            }

            chart1.Series.Add(series);
        }

        private void AddTriangleEdgesToChart(Triangle triangle, System.Windows.Forms.DataVisualization.Charting.Series series)
        {
            AddEdgeToChart(triangle.A, triangle.B, series);
            AddEdgeToChart(triangle.B, triangle.C, series);
            AddEdgeToChart(triangle.C, triangle.A, series);
        }

        private void AddEdgeToChart(Mypoints p1, Mypoints p2, System.Windows.Forms.DataVisualization.Charting.Series series)
        {
            series.Points.AddXY(p1.x, p1.y);  // 起点
            series.Points.AddXY(p2.x, p2.y);  // 终点
        }

        private double CalculateBalanceElevation(List<Triangle> triangles)
        {
            double numerator = 0;
            double denominator = 0;

            foreach (var triangle in triangles)
            {
                double avgHeight = (triangle.A.h + triangle.B.h + triangle.C.h) / 3;
                double area = CalculateTriangleArea(triangle);
                numerator += avgHeight * area;
                denominator += area;
            }

            return numerator / denominator;
        }

        private double CalculateTriangleArea(Triangle triangle)
        {
            double x1 = triangle.A.x, y1 = triangle.A.y;
            double x2 = triangle.B.x, y2 = triangle.B.y;
            double x3 = triangle.C.x, y3 = triangle.C.y;

            return Math.Abs((x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1)) / 2.0;
        }
        private void CalculateCutFillVolume(List<Triangle> triangles, double referenceHeight)
        {
            foreach (var triangle in triangles)
            {
                double avgHeight = (triangle.A.h + triangle.B.h + triangle.C.h) / 3;
                double area = CalculateTriangleArea(triangle);

                double deltaHeight = avgHeight - referenceHeight;
                if (deltaHeight > 0)
                {
                    // 填方
                    double fillVolume = area * deltaHeight;
                    richTextBox1.Text+=($"三角形: {triangle.A.name}, {triangle.B.name}, {triangle.C.name} 填方体积: {fillVolume}\n");
                }
                else
                {
                    // 挖方
                    double cutVolume = area * (-deltaHeight);
                    richTextBox1.Text += ($"三角形: {triangle.A.name}, {triangle.B.name}, {triangle.C.name} 挖方体积: {cutVolume}\n");
                }
            }
        }

       
        private void OutputFirstTwentyTriangles()
        {
            var trianglesToDisplay = T1.Take(20).ToList(); // 获取前20个三角形
            foreach (var triangle in trianglesToDisplay)
            {
                string triangleText = $"三角形: {triangle.A.name}, {triangle.B.name}, {triangle.C.name}\n";
                richTextBox1.Text+=triangleText;
            }

            richTextBox1.Text += "前20个三角形已显示";
        }

        private double[] CalculateCircumcenter(Triangle triangle)
        {
            double x1 = triangle.A.x, y1 = triangle.A.y;
            double x2 = triangle.B.x, y2 = triangle.B.y;
            double x3 = triangle.C.x, y3 = triangle.C.y;

            double d = 2 * (x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2));
            double x0 = ((Math.Pow(x1, 2) + Math.Pow(y1, 2)) * (y2 - y3) + (Math.Pow(x2, 2) + Math.Pow(y2, 2)) * (y3 - y1) + (Math.Pow(x3, 2) + Math.Pow(y3, 2)) * (y1 - y2)) / d;
            double y0 = ((Math.Pow(x1, 2) + Math.Pow(y1, 2)) * (x3 - x2) + (Math.Pow(x2, 2) + Math.Pow(y2, 2)) * (x1 - x3) + (Math.Pow(x3, 2) + Math.Pow(y3, 2)) * (x2 - x1)) / d;
            double r = Math.Sqrt(Math.Pow(x0 - x1, 2) + Math.Pow(y0 - y1, 2));

            return new double[] { x0, y0, r };
        }

        private double Distance(Mypoints p1, Mypoints p2)
        {
            return Math.Sqrt(Math.Pow(p2.x - p1.x, 2) + Math.Pow(p2.y - p1.y, 2));
        }

        private double CrossProduct(Mypoints p1, Mypoints p2, Mypoints p3)
        {
            return (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x);
        }

        private bool IsInsideCircumcircle(Mypoints p, double x0, double y0, double r)
        {
            return Math.Pow(p.x - x0, 2) + Math.Pow(p.y - y0, 2) < Math.Pow(r, 2);
        }

        private void UpdateEdgesAndTriangles(List<Triangle> T2, List<Edge> S, Mypoints p)
        {
            foreach (var triangle in T2)
            {
                AddEdge(triangle, S);
            }

            T2.Clear();
            foreach (var edge in S)
            {
                var newTriangle = new Triangle(edge.P1, edge.P2, p);
                T1.Add(newTriangle);
            }
            S.Clear();
        }

        private void AddEdge(Triangle triangle, List<Edge> edgeList)
        {
            AddEdgeToList(triangle.A, triangle.B, edgeList);
            AddEdgeToList(triangle.B, triangle.C, edgeList);
            AddEdgeToList(triangle.C, triangle.A, edgeList);
        }

        private void AddEdgeToList(Mypoints p1, Mypoints p2, List<Edge> edgeList)
        {
            if (!edgeList.Any(e => (e.P1 == p1 && e.P2 == p2) || (e.P1 == p2 && e.P2 == p1)))
            {
                edgeList.Add(new Edge(p1, p2));
            }
        }

        private void RemoveSmallOrLargeTriangles(List<Triangle> triangles)
        {
            triangles.RemoveAll(t =>
            {
                double angleA = CalculateAngle(t.A, t.B, t.C);
                double angleB = CalculateAngle(t.B, t.A, t.C);
                double angleC = CalculateAngle(t.C, t.A, t.B);
                return angleA < 5 || angleB < 5 || angleC < 5 || angleA > 160 || angleB > 160 || angleC > 160;
            });
        }

        private double CalculateAngle(Mypoints A, Mypoints B, Mypoints C)
        {
            double ab = Math.Sqrt(Math.Pow(A.x - B.x, 2) + Math.Pow(A.y - B.y, 2));
            double bc = Math.Sqrt(Math.Pow(B.x - C.x, 2) + Math.Pow(B.y - C.y, 2));
            double ac = Math.Sqrt(Math.Pow(A.x - C.x, 2) + Math.Pow(A.y - C.y, 2));
            return Math.Acos((ab * ab + bc * bc - ac * ac) / (2 * ab * bc)) * (180 / Math.PI);
        }

        private void toolStripButton4_Click(object sender, EventArgs e)
        {
            double xMin = chart1.ChartAreas[0].AxisX.Minimum;
            double xMax = chart1.ChartAreas[0].AxisX.Maximum;
            double yMin = chart1.ChartAreas[0].AxisY.Minimum;
            double yMax = chart1.ChartAreas[0].AxisY.Maximum;

            chart1.ChartAreas[0].AxisX.Minimum = xMin + (xMax - xMin) * 0.1;
            chart1.ChartAreas[0].AxisX.Maximum = xMax - (xMax - xMin) * 0.1;
            chart1.ChartAreas[0].AxisY.Minimum = yMin + (yMax - yMin) * 0.1;
            chart1.ChartAreas[0].AxisY.Maximum = yMax - (yMax - yMin) * 0.1;
        }

        private void toolStripButton5_Click(object sender, EventArgs e)
        {
            double xMin = chart1.ChartAreas[0].AxisX.Minimum;
            double xMax = chart1.ChartAreas[0].AxisX.Maximum;
            double yMin = chart1.ChartAreas[0].AxisY.Minimum;
            double yMax = chart1.ChartAreas[0].AxisY.Maximum;

            chart1.ChartAreas[0].AxisX.Minimum = xMin - (xMax - xMin) * 0.1;
            chart1.ChartAreas[0].AxisX.Maximum = xMax + (xMax - xMin) * 0.1;
            chart1.ChartAreas[0].AxisY.Minimum = yMin - (yMax - yMin) * 0.1;
            chart1.ChartAreas[0].AxisY.Maximum = yMax + (yMax - yMin) * 0.1;
        }

        private void chart1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                isDragging = true;
                mouseDownLocation = e.Location;
            }
        }

        private void chart1_MouseMove(object sender, MouseEventArgs e)
        {
            if (isDragging)
            {
                // 计算鼠标移动的偏移量
                int deltaX = e.X - mouseDownLocation.X;
                int deltaY = e.Y - mouseDownLocation.Y;

                // 获取当前X轴和Y轴的最小最大值
                double xMin = chart1.ChartAreas[0].AxisX.Minimum;
                double xMax = chart1.ChartAreas[0].AxisX.Maximum;
                double yMin = chart1.ChartAreas[0].AxisY.Minimum;
                double yMax = chart1.ChartAreas[0].AxisY.Maximum;

                // 更新坐标轴的最小最大值来实现平移
                chart1.ChartAreas[0].AxisX.Minimum = xMin - deltaX * (xMax - xMin) / chart1.Width;
                chart1.ChartAreas[0].AxisX.Maximum = xMax - deltaX * (xMax - xMin) / chart1.Width;
                chart1.ChartAreas[0].AxisY.Minimum = yMin + deltaY * (yMax - yMin) / chart1.Height;
                chart1.ChartAreas[0].AxisY.Maximum = yMax + deltaY * (yMax - yMin) / chart1.Height;

                // 更新鼠标按下的位置
                mouseDownLocation = e.Location;
            }
        }

        private void chart1_MouseUp(object sender, MouseEventArgs e)
        {
            isDragging = false; // 结束拖动
        }

    }
}

namespace TIN_321
{
    public class Triangle
    {
        public Mypoints A { get; set; }
        public Mypoints B { get; set; }
        public Mypoints C { get; set; }

        public Triangle(Mypoints a, Mypoints b, Mypoints c)
        {
            A = a;
            B = b;
            C = c;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TIN_321
{
    public class Edge
    {
        public Mypoints P1 { get; set; }
        public Mypoints P2 { get; set; }

        public Edge(Mypoints p1, Mypoints p2)
        {
            P1 = p1;
            P2 = p2;
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xin2cd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值