ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

unity C# 计算3D空间任意多边形面积,距离,角度测量工具

2022-06-22 17:00:18  阅读:209  来源: 互联网

标签:Count hit point C# lv unity points var 3D


效果图

代码:

using UnityEngine;
using System.Collections.Generic;
using System;
/// <summary>
/// 划线面积,距离,角度
/// </summary>
public class UnderlinedMeasureTool : MonoBehaviour
{
    /// <summary>
    /// 相机
    /// </summary>
    public Camera _camera;
    public int size = 30;//文字大小
    //圆点的预制体
    public GameObject aim;
    public LineRenderer lineRender;
    bool sb = false;

    //GL 绘制的顶点数组  顺序是  0->1  2->3 4->5    取法 0 1 3 5 7 9
    //参考UI界面
    private List<Vector3> lv;//划线的点
    private List<Vector3> lv1;//存坐标的点
    public List<GameObject> aims;
    public int type = 3;
    void Start()
    {
        lv = new List<Vector3>();
        lv1 = new List<Vector3>();
        aims = new List<GameObject>();
    }
    void Update()
    {
        if (Input.GetMouseButtonDown(0))//绘制多边形
        {
            Ray ray = _camera.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, Mathf.Infinity))
            {
                //创建圆点
                GameObject go = Instantiate(aim, new Vector3(hit.point.x, hit.point.y, hit.point.z), Quaternion.Euler(90, 0, 0)) as GameObject;
                aims.Add(go);
                lv1.Add(hit.point);
                if (type == 1)
                {
                    if (lv.Count >= 2)
                    {
                        ClearLines();
                        GameObject go1 = Instantiate(aim, new Vector3(hit.point.x, hit.point.y, hit.point.z), Quaternion.Euler(90, 0, 0)) as GameObject;
                        aims.Add(go1);
                        lv1.Add(hit.point);

                        lv.Add(hit.point);
                    }
                    else
                    {
                        lv.Add(hit.point);
                    }
                }
                else if (type == 2)
                {
                    if (lv.Count >= 3)
                    {
                        ClearLines();
                        GameObject go1 = Instantiate(aim, new Vector3(hit.point.x, hit.point.y, hit.point.z), Quaternion.Euler(90, 0, 0)) as GameObject;
                        aims.Add(go1);
                        lv1.Add(hit.point);

                        lv.Add(hit.point);
                    }
                    else if (lv.Count >= 2)
                    {
                        if (sb)
                        {
                            lv.RemoveAt(lv.Count - 1);
                            lv.RemoveAt(lv.Count - 1);
                        }
                        lv.Add(hit.point);

                        sb = true;
                    }
                    else
                    {
                        lv.Add(hit.point);
                    }
                }
                else if (type == 3)
                {
                    if (lv.Count >= 2)
                    {
                        //存入点就是反复存入来自动连线,0--1 1--2 2--3.。。。。类似这格式存储点
                        if (sb)
                        {
                            lv.RemoveAt(lv.Count - 1);
                            lv.RemoveAt(lv.Count - 1);
                        }
                        lv.Add(lv[lv.Count - 1]);
                        lv.Add(hit.point);
                        lv.Add(lv[0]);
                        lv.Add(hit.point);

                        sb = true;
                    }
                    else
                    {
                        lv.Add(hit.point);
                    }
                }
               
            }
            //print(lv.Count);

            lineRender.positionCount = lv.Count;
            lineRender.SetPositions(lv.ToArray());
        }
    }

    void OnGUI()
    {
        GUIStyle text = new GUIStyle();
        text.fontSize = size;
        // 利用gui 为了实时动态更新画线数据
        if (lv.Count >= 2)
        {
            //除了第一个点和最后个点,其它点都是存了两遍
            for (int i = 0; i < lv.Count - 1; i = i + 2)
            {
                Vector3 s = new Vector3((lv[i].x + lv[i + 1].x) / 2, (lv[i].y + lv[i + 1].y) / 2, (lv[i].z + lv[i + 1].z) / 2);
                Vector3 a = _camera.WorldToScreenPoint(s);
                //注意屏幕坐标系与GUI的ui坐标系y轴相反,ToString(".000")保留小数点后3位数,几个零几位数
                //显示线段的长度
                GUI.Label(new Rect(a.x- size, Screen.height - a.y, 50, 20), "<color=red>" + Vector3.Distance(lv[i], lv[i + 1]).ToString(".000") + "</color>" + "<color=blue>" + "m" + "</color>",text);

            }
        }
        //显示面积
        if (lv1.Count > 2 && type == 3)
        {
            Vector3 a = _camera.WorldToScreenPoint(lv1[0]);
            GUI.Label(new Rect(a.x - 0, Screen.height - a.y, 50, 20), "<color=yellow>" + Compute_3D_polygon_area(lv1).ToString(".00") + "</color>" + "<color=blue>" + "㎡" + "</color>", text);
        }
        //显示角度
        if (lv1.Count == 3 && type == 2)
        {
            Vector3 a = _camera.WorldToScreenPoint(lv1[1]);
            GUI.Label(new Rect(a.x, Screen.height - a.y, 50, 20), "<color=yellow>" + Angle(lv1[1], lv1[0], lv1[lv1.Count - 1]).ToString(".000") + "</color>" + "<color=blue>" + "℃" + "</color>", text);
        }
    }
    // 清除重新测量
    public void ClearLines()
    {
        if (lv == null) return;
        sb = false;
        for (int i = 0; i < aims.Count; i++)
        {
            Destroy(aims[i]);
        }
        lv.Clear();
        lv1.Clear();
        aims.Clear();
        lineRender.positionCount = 0;
    }
    //计算任意多边形的面积,顶点按照顺时针或者逆时针方向排列,不需要考虑y轴的坐标. 2D
    public double ComputePolygonArea(List<Vector3> points)
    {
        int point_num = points.Count;
        if (point_num < 3) return 0.0;
        float s = points[0].y * (points[point_num - 1].x - points[1].x);
        for (int i = 1; i < point_num; ++i)
            s += points[i].y * (points[i - 1].x - points[(i + 1) % point_num].x);
        return Mathf.Abs(s / 2.0f);
    }
    public double Compute_3D_polygon_area(List<Vector3> points)
    {
        //points为任意多边形的点集合 注意输入时要按环的流动输入,不能乱序输入
        //此方法是3D空间的,相较于2D更具有普适性
        if (points.Count < 3) return 0.0;

        var P1X = points[0][0];
        var P1Y = points[0][1];
        var P1Z = points[0][2];
        var P2X = points[1][0];
        var P2Y = points[1][1];
        var P2Z = points[1][2];
        var P3X = points[2][0];
        var P3Y = points[2][1];
        var P3Z = points[2][2];

        var a = Mathf.Pow(((P2Y - P1Y) * (P3Z - P1Z) - (P3Y - P1Y) * (P2Z - P1Z)), 2) + Mathf.Pow(((P3X - P1X) * (P2Z - P1Z) - (P2X - P1X) * (P3Z - P1Z)), 2) + Mathf.Pow(((P2X - P1X) * (P3Y - P1Y) - (P3X - P1X) * (P2Y - P1Y)), 2);
        var cosnx = ((P2Y - P1Y) * (P3Z - P1Z) - (P3Y - P1Y) * (P2Z - P1Z)) / (Mathf.Pow(a, 0.5f));
        var cosny = ((P3X - P1X) * (P2Z - P1Z) - (P2X - P1X) * (P3Z - P1Z)) / (Mathf.Pow(a, 0.5f));
        var cosnz = ((P2X - P1X) * (P3Y - P1Y) - (P3X - P1X) * (P2Y - P1Y)) / (Mathf.Pow(a, 0.5f));

        var s = cosnz * ((points[points.Count - 1][0]) * (P1Y) - (P1X) * (points[points.Count - 1][1])) + cosnx * ((points[points.Count - 1][1]) * (P1Z) - (P1Y) * (points[points.Count - 1][2])) + cosny * ((points[points.Count - 1][2]) * (P1X) - (P1Z) * (points[points.Count - 1][0]));

        for (int i = 0; i < points.Count-1; i++)
        {
            var p1 = points[i];
            var p2 = points[i + 1];
            var ss = cosnz * ((p1[0]) * (p2[1]) - (p2[0]) * (p1[1])) + cosnx * ((p1[1]) * (p2[2]) - (p2[1]) * (p1[2])) + cosny * ((p1[2]) * (p2[0]) - (p2[2]) * (p1[0]));
            s += ss;
        }

        return Mathf.Abs(s / 2.0f);
    }
    //计算夹角
    public double Angle(Vector3 cen, Vector3 first, Vector3 second)
    {
        double M_PI = 3.1415926535897931;

        double ma_x = first.x - cen.x;
        double ma_y = first.y - cen.y;
        double ma_z = first.z - cen.z;
        double mb_x = second.x - cen.x;
        double mb_y = second.y - cen.y;
        double mb_z = second.z - cen.z;
        double v1 = (ma_x * mb_x) + (ma_y * mb_y) + (ma_z * mb_z);
        double ma_val = Math.Sqrt(ma_x * ma_x + ma_y * ma_y + ma_z * ma_z);
        double mb_val = Math.Sqrt(mb_x * mb_x + mb_y * mb_y + mb_z * mb_z);
        double cosM = v1 / (ma_val * mb_val);
        double angleAMB = Math.Acos(cosM) * 180 / M_PI;
        return angleAMB;
    }
}

原文链接:https://blog.csdn.net/qq_22972867/article/details/120452678

标签:Count,hit,point,C#,lv,unity,points,var,3D
来源: https://www.cnblogs.com/AranNice/p/16401264.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有