140 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C#
		
	
			
		
		
	
	
			140 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C#
		
	
using System;
 | 
						|
using System.Collections.Generic;
 | 
						|
using UnityEngine;
 | 
						|
using UnityEngine.UI;
 | 
						|
 | 
						|
[RequireComponent(typeof(CanvasRenderer))]
 | 
						|
public class RadarChart : MaskableGraphic
 | 
						|
{
 | 
						|
    public int EdgeCount
 | 
						|
    {
 | 
						|
        get
 | 
						|
        {
 | 
						|
            if (m_Weights == null)
 | 
						|
                return 0;
 | 
						|
            return m_Weights.Count;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public List<float> Weights
 | 
						|
    {
 | 
						|
        get { return m_Weights; }
 | 
						|
    }
 | 
						|
 | 
						|
    [SerializeField] private List<float> m_Weights;
 | 
						|
 | 
						|
    //重绘UI的Mesh
 | 
						|
    protected override void OnPopulateMesh(VertexHelper vh)
 | 
						|
    {
 | 
						|
        if (m_Weights == null || m_Weights.Count <= 2)
 | 
						|
        {
 | 
						|
            base.OnPopulateMesh(vh);
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        int edgeCount = m_Weights.Count;
 | 
						|
 | 
						|
        float deltaAngle = 360f / edgeCount;
 | 
						|
 | 
						|
        vh.Clear();
 | 
						|
 | 
						|
        for (int i = 0; i < edgeCount; i++)
 | 
						|
        {
 | 
						|
            GetTriangle(vh, i, deltaAngle);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    private void GetTriangle(VertexHelper vh, int index, float deltaAngle)
 | 
						|
    {
 | 
						|
        float edgeLength = Mathf.Min(rectTransform.rect.width, rectTransform.rect.height) * 0.5f;
 | 
						|
        var color32 = color;
 | 
						|
        Vector3 cent = new Vector3(0, 0);
 | 
						|
        float angle1 = 90 + (index + 1) * deltaAngle;
 | 
						|
        float angle2 = 90 + (index) * deltaAngle;
 | 
						|
        float radius1 = (index == m_Weights.Count - 1 ? m_Weights[0] : m_Weights[index + 1]) * edgeLength;
 | 
						|
        float radius2 = m_Weights[index] * edgeLength;
 | 
						|
 | 
						|
        Vector3 p1 = new Vector3(radius1 * Mathf.Cos(angle1 * Mathf.Deg2Rad), radius1 * Mathf.Sin(angle1 * Mathf.Deg2Rad));
 | 
						|
        Vector3 p2 = new Vector3(radius2 * Mathf.Cos(angle2 * Mathf.Deg2Rad), radius2 * Mathf.Sin(angle2 * Mathf.Deg2Rad));
 | 
						|
 | 
						|
        vh.AddVert(cent, color32, Vector2.zero);
 | 
						|
        vh.AddVert(p1, color32, new Vector2(0, 1));
 | 
						|
        vh.AddVert(p2, color32, new Vector2(1, 0));
 | 
						|
 | 
						|
        vh.AddTriangle(index * 3, index * 3 + 1, index * 3 + 2);
 | 
						|
    }
 | 
						|
 | 
						|
    public void SetEdges(float[] edges)
 | 
						|
    {
 | 
						|
        m_Weights.Clear();
 | 
						|
        for(int i = 0; i < edges.Length; i++)
 | 
						|
        {
 | 
						|
            m_Weights.Add(edges[i]);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
 | 
						|
    {
 | 
						|
        if (raycastTarget)
 | 
						|
        {
 | 
						|
            Vector2 local;
 | 
						|
            RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, sp, eventCamera, out local);
 | 
						|
 | 
						|
            int edgeCount = m_Weights.Count;
 | 
						|
 | 
						|
            float deltaAngle = 360f / edgeCount;
 | 
						|
 | 
						|
            for (int i = 0; i < edgeCount; i++)
 | 
						|
            {
 | 
						|
                bool result = IsInPolygon(i, deltaAngle, local);
 | 
						|
                if (result)
 | 
						|
                    return true;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    private bool IsInPolygon(int index, float deltaAngle, Vector2 point)
 | 
						|
    {
 | 
						|
        float edgeLength = Mathf.Min(rectTransform.rect.width, rectTransform.rect.height) * 0.5f;
 | 
						|
        Vector2 cent = new Vector2(0, 0);
 | 
						|
        float angle1 = 90 + (index + 1) * deltaAngle;
 | 
						|
        float angle2 = 90 + (index) * deltaAngle;
 | 
						|
        float radius1 = (index == m_Weights.Count - 1 ? m_Weights[0] : m_Weights[index + 1]) * edgeLength;
 | 
						|
        float radius2 = m_Weights[index] * edgeLength;
 | 
						|
 | 
						|
        Vector2 p1 = new Vector2(radius1 * Mathf.Cos(angle1 * Mathf.Deg2Rad), radius1 * Mathf.Sin(angle1 * Mathf.Deg2Rad));
 | 
						|
        Vector2 p2 = new Vector2(radius2 * Mathf.Cos(angle2 * Mathf.Deg2Rad), radius2 * Mathf.Sin(angle2 * Mathf.Deg2Rad));
 | 
						|
 | 
						|
        return IsInTriangle(cent, p1, p2, point);
 | 
						|
    }
 | 
						|
 | 
						|
    private bool IsInTriangle(Vector2 vertex1, Vector2 vertex2, Vector2 vertex3, Vector2 point)
 | 
						|
    {
 | 
						|
        Vector2 v0 = vertex3 - vertex1;
 | 
						|
        Vector2 v1 = vertex2 - vertex1;
 | 
						|
        Vector2 v2 = point - vertex1;
 | 
						|
 | 
						|
        float dot00 = Vector2.Dot(v0, v0);
 | 
						|
        float dot01 = Vector2.Dot(v0, v1);
 | 
						|
        float dot02 = Vector2.Dot(v0, v2);
 | 
						|
        float dot11 = Vector2.Dot(v1, v1);
 | 
						|
        float dot12 = Vector2.Dot(v1, v2);
 | 
						|
 | 
						|
        float inverDeno = 1 / (dot00 * dot11 - dot01 * dot01);
 | 
						|
 | 
						|
        float u = (dot11 * dot02 - dot01 * dot12) * inverDeno;
 | 
						|
        if (u < 0 || u > 1)
 | 
						|
        {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        float v = (dot00 * dot12 - dot01 * dot02) * inverDeno;
 | 
						|
        if (v < 0 || v > 1)
 | 
						|
        {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        return u + v <= 1;
 | 
						|
    }
 | 
						|
} |