unity 用LineRender画四边形并测面积

作为一个菜鸡,这个高中数学题差不多废了我两个上午。。。好了,废话不多说,直接上代码。。。

using System.Collections.Generic;
using UnityEngine;


public class DrawAreaLine : MonoBehaviour
{
    public bool IsAreaLineOn = false;
    private LineRenderer AreaLine;
    private List<Vector3> PosList = new List<Vector3>();
    private RaycastHit hit;
    private Ray ray;
    private int num = 0;
    // Use this for initialization
    void Start()
    {
        AreaLine = transform.Find("Area").GetComponent<LineRenderer>();
        AreaLine.material = new Material(Shader.Find("Sprites/Default"));
        AreaLine.startColor = Color.blue;
        AreaLine.endColor = Color.blue;
        AreaLine.startWidth = 0.05f;
        AreaLine.endWidth = 0.05f;
        AreaLine.numCornerVertices = 5;
        AreaLine.numCapVertices = 5;

    }

    // Update is called once per frame
    void Update()
    {
        BeginAreaLine();
    }

    void BeginAreaLine()
    {
        if (IsAreaLineOn)
        {
            if (Input.GetMouseButtonDown(0))
            {
                if (AreaLine.enabled == false)
                {
                    AreaLine.enabled = true;
                }
                ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                if (Physics.Raycast(ray, out hit))
                {
                    Vector3 pos = new Vector3(hit.point.x, hit.point.y, hit.point.z) + new Vector3(0, 0.1f, 0);
                    //判断是否有相同位置的点
                    for (int i=0; i<PosList.Count;i++)
                    {
                        if (PosList[i]==pos)
                        {
                            return;
                        }
                    }
                    if (AreaLine.positionCount >= 4)
                    {
                        return;
                    }
                    if (AreaLine.positionCount == 3)
                    {
                        //判断第四个点位置,判断能否组成四边形
                        //判断顺时针还是逆时针
                        if (IsClockWise() == false)//ABC为逆时针方向
                        {
                            //逆时针判断能否画四边形
                            if (IfCanAntiClock(pos) == false)
                            {
                                return;
                            }
                        }
                        if (IsClockWise() == true) //ABC为顺时针方向
                        {
                            //顺时针能否画四边形
                            if(IfCanClick(pos)==false)
                            {
                                return;
                            }
                        }
                       
                    }
                    if (hit.collider.name == "PanelCube")
                    {
                        num++;
                        AreaLine.positionCount = num;
                        AreaLine.SetPosition(num - 1, pos);
                        PosList.Add(pos);
                        if (PosList.Count == 3)
                        {
                            //计算三角形面积
                            // AreaTriabgle();
                            print(AreaTriabgle());
                        }
                        if (PosList.Count == 4)
                        {
                            //计算四边形面积
                            //AreaQuadrangle();
                            print(AreaQuadrangle());
                        }
                    }
                    //print(AreaLine.positionCount);
                }
            }
            else if (Input.GetKeyDown(KeyCode.Delete))
            {
                DelectLine();
            }
            return;
        }
    }

    /// <summary>
    /// 判断逆时针能不能画成四边形
    /// </summary>
    /// <param name="PosD"></param>
    /// <returns>cyt</returns>
    bool IfCanAntiClock(Vector3 PosD)
    {
        //直线一般式表达:(y2-y1)x-(x2-x1)y-x1y2+x2y1=0
        bool can = false;
        Vector2 A = new Vector2(PosList[0].x, PosList[0].z);
        Vector2 B = new Vector2(PosList[1].x, PosList[1].z);
        Vector2 C = new Vector2(PosList[2].x, PosList[2].z);
        Vector2 D = new Vector2(PosD.x, PosD.z);
        //D在直线AB、AC下方且在BC上方
        if (((B.y - A.y) * D.x - (B.x - A.x) * D.y - A.x * B.y + B.x * A.y > 0)
            && (((C.y - A.y) * D.x - (C.x - A.x) * D.y - A.x * C.y + C.x * A.y > 0))
            && ((C.y - B.y) * D.x - (C.x - B.x) * D.y - B.x * C.y + C.x * B.y < 0))
        {
       
            can = false;
        }
        //D在AB上方且在BC、AC下方
        else if (((B.y - A.y) * D.x - (B.x - A.x) * D.y - A.x * B.y + B.x * A.y < 0)
            && ((C.y - B.y) * D.x - (C.x - B.x) * D.y - B.x * C.y + C.x * B.y > 0)
            && (C.y - A.y) * D.x - (C.x - A.x) * D.y - A.x * C.y + C.x * A.y > 0)
        {
            
            can = false;
        }
        else
        {
            print("keyi");
            can = true;
        }
        return can;
    }

    /// <summary>
    /// 顺时针能否画成四边形
    /// </summary>
    /// <param name="posD"></param>
    /// <returns>cyt</returns>
    bool IfCanClick(Vector3 PosD)
    {
        //直线一般式表达:(y2-y1)x-(x2-x1)y-x1y2+x2y1=0
        bool CanClick = false;
        Vector2 A = new Vector2(PosList[0].x, PosList[0].z);
        Vector2 B = new Vector2(PosList[1].x, PosList[1].z);
        Vector2 C = new Vector2(PosList[2].x, PosList[2].z);
        Vector2 D = new Vector2(PosD.x, PosD.z);
        //在AB、AC上方、BC下方,以ac为底边观察的
        if (((B.y - A.y) * D.x - (B.x - A.x) * D.y - A.x * B.y + B.x * A.y < 0)
            && (((C.y - A.y) * D.x - (C.x - A.x) * D.y - A.x * C.y + C.x * A.y <0))
            && ((C.y - B.y) * D.x - (C.x - B.x) * D.y - B.x * C.y + C.x * B.y >0)
            )
        {
            CanClick = false;
        }
        //在AC、BC上方,在AB下方
        else if (((B.y - A.y) * D.x - (B.x - A.x) * D.y - A.x * B.y + B.x * A.y > 0)
            && (((C.y - A.y) * D.x - (C.x - A.x) * D.y - A.x * C.y + C.x * A.y < 0))
            && ((C.y - B.y) * D.x - (C.x - B.x) * D.y - B.x * C.y + C.x * B.y < 0)
            )
        {
            CanClick = false;
        }
        else
        {
            CanClick = true;
        }
        return CanClick;
    }
    /// <summary>
    /// 计算三角形面积
    /// </summary>
    float AreaTriabgle()
    {
        //点到直线距离d=Mathf.Abs( (A*x0+B*y0+C)/Mathf.Sqrt(A*A+B*B) );
        float area;
        Vector2 A = new Vector2(PosList[0].x, PosList[0].z);
        Vector2 B = new Vector2(PosList[1].x, PosList[1].z);
        Vector2 C = new Vector2(PosList[2].x, PosList[2].z);
        //AC长度(底边长)
        float AC = Vector2.Distance(A, C);
        //B到AC的距离(AC边的高)
        float h = Mathf.Abs(((C.y - A.y) * B.x - (C.x - A.x) * B.y - A.x * C.y + C.x * A.y) / Mathf.Sqrt((C.y - A.y) * (C.y - A.y) + (C.x - A.x) * (C.x - A.x)));
        area = AC * h / 2;
        return area;
    }
    /// <summary>
    /// 计算四边形面积
    /// </summary>
    float AreaQuadrangle()
    {
        float area;
        Vector2 A = new Vector2(PosList[0].x, PosList[0].z);
        Vector2 B = new Vector2(PosList[1].x, PosList[1].z);
        Vector2 C = new Vector2(PosList[2].x, PosList[2].z);
        Vector2 D = new Vector2(PosList[3].x, PosList[3].z);
        //AC长度(底边长)
        float AC = Vector2.Distance(A, C);
        //B到AC的距离(AC边的高)
        float hB = Mathf.Abs(((C.y - A.y) * B.x - (C.x - A.x) * B.y - A.x * C.y + C.x * A.y) / Mathf.Sqrt((C.y - A.y) * (C.y - A.y) + (C.x - A.x) * (C.x - A.x)));
        float hD = Mathf.Abs(((C.y - A.y) * D.x - (C.x - A.x) * D.y - A.x * C.y + C.x * A.y) / Mathf.Sqrt((C.y - A.y) * (C.y - A.y) + (C.x - A.x) * (C.x - A.x)));
        //判断是否是凹四边形
        if (IsConcaveQuadrilateral() == true)
        {
            area = AC * Mathf.Abs((hB - hD)) / 2;
        }
        else
            area = AC * (hB + hD) / 2;
        return area;
    }
    /// <summary>
    /// 删除线
    /// </summary>
    void DelectLine()
    {
        num = 0;
        //lineRenderer.SetVertexCount(LengthOfLineRenderer);
        AreaLine.positionCount = num;
        PosList.Clear();
        AreaLine.enabled = false;
    }

    /// <summary>
    /// 判断是否是凹四边形
    /// </summary>
    /// <returns>cyt</returns>
    bool IsConcaveQuadrilateral()
    {
        bool Concave = false;
        Vector2 A = new Vector2(PosList[0].x, PosList[0].z);
        Vector2 B = new Vector2(PosList[1].x, PosList[1].z);
        Vector2 C = new Vector2(PosList[2].x, PosList[2].z);
        Vector2 D = new Vector2(PosList[3].x, PosList[3].z);
        //逆时针状况
        //两种情况,一种是D在三角形ABC内部,另一种是D在直线AB跟BC下方(以ab为底边观察)
        if (IsClockWise()==false)
        {
            if (((B.y - A.y) * D.x - (B.x - A.x) * D.y - A.x * B.y + B.x * A.y < 0)
            && ((C.y - B.y) * D.x - (C.x - B.x) * D.y - B.x * C.y + C.x * B.y < 0)
            && ((C.y - A.y) * D.x - (C.x - A.x) * D.y - A.x * C.y + C.x * A.y > 0))
            {
                Concave = true;
            }
            else if (((B.y - A.y) * D.x - (B.x - A.x) * D.y - A.x * B.y + B.x * A.y > 0)
                && ((C.y - B.y) * D.x - (C.x - B.x) * D.y - B.x * C.y + C.x * B.y > 0))
            {
                Concave = true;
            }
            else
            {
                Concave = false;
            }
        }
        //顺时针
        //两种情况,在三角形abc内部和在AB上、AC下
        if (IsClockWise()==true)
        {
            if (((B.y - A.y) * D.x - (B.x - A.x) * D.y - A.x * B.y + B.x * A.y > 0)
            && ((C.y - B.y) * D.x - (C.x - B.x) * D.y - B.x * C.y + C.x * B.y > 0)
            && ((C.y - A.y) * D.x - (C.x - A.x) * D.y - A.x * C.y + C.x * A.y < 0)
                )
            {
                Concave = true;
            }
            else if (((B.y - A.y) * D.x - (B.x - A.x) * D.y - A.x * B.y + B.x * A.y < 0)
            && ((C.y - B.y) * D.x - (C.x - B.x) * D.y - B.x * C.y + C.x * B.y < 0
                ))
            {
                Concave = true;
            }
            else
            {
                Concave = false;
            }
        }
        return Concave;
    }
    /// <summary>
    /// 判断是否为顺时针,以ac为底边观察
    /// </summary>
    /// <param>cyt</param>
    /// <returns></returns>
    bool IsClockWise()
    {
        bool IsClock = false;
        Vector2 A = new Vector2(PosList[0].x, PosList[0].z);
        Vector2 B = new Vector2(PosList[1].x, PosList[1].z);
        Vector2 C = new Vector2(PosList[2].x, PosList[2].z);
        //如果B在A的右边,C在AB上方为逆时针
        if (B.x>=A.x)
        {
            if ((B.y - A.y) * C.x - (B.x - A.x) * C.y - A.x * B.y + B.x * A.y < 0)
            {
                IsClock = false;
            }
            else
            {
                IsClock = true;
            }
        }
        //如果B在A的左边,C在AB下方为逆时针
        if (B.x<A.x)
        {
            if ((B.y - A.y) * C.x - (B.x - A.x) * C.y - A.x * B.y + B.x * A.y < 0)
            {
                IsClock = false;
            }
            else
            {
                IsClock = true;
            }
        }
        return IsClock;
    }
}

注释还算比较清楚,各种情况都判断了,也是想过用向量来判断能否实现,发现不好使....

  AreaLine = transform.Find("Area").GetComponent<LineRenderer>();这个跟
     if (hit.collider.name == "PanelCube")这两句需要自己在场景中设置一下,然后运行的时候把脚本的
IsAreaLineOn变量设为true就能画了...按下delect可以删除画的四边形,然后在点击就可以继续画了。
实现思路的话首先将所有的点加入一个集合中(每次输入都排除了重复的点),然后根据集合里的的前三个点判断画的三角形是顺时针画的三角形还是逆时针画的三角形,
然后在根据是顺时针和逆时针分别判断第四个点的位置,判断第四个点在三角形三条边所在直线的位置判断能否画成四边形。
计算面积的话是先判断了顺时针话还是逆时针画,然后分别判断画的是凸四边形还是凹四边形,然后在计算面积。
哎。。。生无可恋。。。。
希望能帮到人,若需转载请标明出处,谢谢....
原文地址:https://www.cnblogs.com/lanrenqilanming/p/8051585.html