using UnityEngine;
namespace FairyGUI
{
///
///
///
public class EllipseMesh : IMeshFactory, IHitTest
{
///
///
///
public Rect? drawRect;
///
///
///
public float lineWidth;
///
///
///
public Color32 lineColor;
///
///
///
public Color32? centerColor;
///
///
///
public Color32? fillColor;
///
///
///
public float startDegree;
///
///
///
public float endDegreee;
static int[] SECTOR_CENTER_TRIANGLES = new int[] {
0, 4, 1,
0, 3, 4,
0, 2, 3,
0, 8, 5,
0, 7, 8,
0, 6, 7,
6, 5, 2,
2, 1, 6
};
public EllipseMesh()
{
lineColor = Color.black;
startDegree = 0;
endDegreee = 360;
}
public void OnPopulateMesh(VertexBuffer vb)
{
Rect rect = drawRect != null ? (Rect)drawRect : vb.contentRect;
Color32 color = fillColor != null ? (Color32)fillColor : vb.vertexColor;
float sectionStart = Mathf.Clamp(startDegree, 0, 360);
float sectionEnd = Mathf.Clamp(endDegreee, 0, 360);
bool clipped = sectionStart > 0 || sectionEnd < 360;
sectionStart = sectionStart * Mathf.Deg2Rad;
sectionEnd = sectionEnd * Mathf.Deg2Rad;
Color32 centerColor2 = centerColor == null ? color : (Color32)centerColor;
float radiusX = rect.width / 2;
float radiusY = rect.height / 2;
int sides = Mathf.CeilToInt(Mathf.PI * (radiusX + radiusY) / 4);
sides = Mathf.Clamp(sides, 40, 800);
float angleDelta = 2 * Mathf.PI / sides;
float angle = 0;
float lineAngle = 0;
if (lineWidth > 0 && clipped)
{
lineAngle = lineWidth / Mathf.Max(radiusX, radiusY);
sectionStart += lineAngle;
sectionEnd -= lineAngle;
}
int vpos = vb.currentVertCount;
float centerX = rect.x + radiusX;
float centerY = rect.y + radiusY;
vb.AddVert(new Vector3(centerX, centerY, 0), centerColor2);
for (int i = 0; i < sides; i++)
{
if (angle < sectionStart)
angle = sectionStart;
else if (angle > sectionEnd)
angle = sectionEnd;
Vector3 vec = new Vector3(Mathf.Cos(angle) * (radiusX - lineWidth) + centerX, Mathf.Sin(angle) * (radiusY - lineWidth) + centerY, 0);
vb.AddVert(vec, color);
if (lineWidth > 0)
{
vb.AddVert(vec, lineColor);
vb.AddVert(new Vector3(Mathf.Cos(angle) * radiusX + centerX, Mathf.Sin(angle) * radiusY + centerY, 0), lineColor);
}
angle += angleDelta;
}
if (lineWidth > 0)
{
int cnt = sides * 3;
for (int i = 0; i < cnt; i += 3)
{
if (i != cnt - 3)
{
vb.AddTriangle(0, i + 1, i + 4);
vb.AddTriangle(i + 5, i + 2, i + 3);
vb.AddTriangle(i + 3, i + 6, i + 5);
}
else if (!clipped)
{
vb.AddTriangle(0, i + 1, 1);
vb.AddTriangle(2, i + 2, i + 3);
vb.AddTriangle(i + 3, 3, 2);
}
else
{
vb.AddTriangle(0, i + 1, i + 1);
vb.AddTriangle(i + 2, i + 2, i + 3);
vb.AddTriangle(i + 3, i + 3, i + 2);
}
}
}
else
{
for (int i = 0; i < sides; i++)
{
if (i != sides - 1)
vb.AddTriangle(0, i + 1, i + 2);
else if (!clipped)
vb.AddTriangle(0, i + 1, 1);
else
vb.AddTriangle(0, i + 1, i + 1);
}
}
if (lineWidth > 0 && clipped)
{
//扇形内边缘的线条
vb.AddVert(new Vector3(radiusX, radiusY, 0), lineColor);
float centerRadius = lineWidth * 0.5f;
sectionStart -= lineAngle;
angle = sectionStart + lineAngle * 0.5f + Mathf.PI * 0.5f;
vb.AddVert(new Vector3(Mathf.Cos(angle) * centerRadius + radiusX, Mathf.Sin(angle) * centerRadius + radiusY, 0), lineColor);
angle -= Mathf.PI;
vb.AddVert(new Vector3(Mathf.Cos(angle) * centerRadius + radiusX, Mathf.Sin(angle) * centerRadius + radiusY, 0), lineColor);
vb.AddVert(new Vector3(Mathf.Cos(sectionStart) * radiusX + radiusX, Mathf.Sin(sectionStart) * radiusY + radiusY, 0), lineColor);
vb.AddVert(vb.GetPosition(vpos + 3), lineColor);
sectionEnd += lineAngle;
angle = sectionEnd - lineAngle * 0.5f + Mathf.PI * 0.5f;
vb.AddVert(new Vector3(Mathf.Cos(angle) * centerRadius + radiusX, Mathf.Sin(angle) * centerRadius + radiusY, 0), lineColor);
angle -= Mathf.PI;
vb.AddVert(new Vector3(Mathf.Cos(angle) * centerRadius + radiusX, Mathf.Sin(angle) * centerRadius + radiusY, 0), lineColor);
vb.AddVert(vb.GetPosition(vpos + sides * 3), lineColor);
vb.AddVert(new Vector3(Mathf.Cos(sectionEnd) * radiusX + radiusX, Mathf.Sin(sectionEnd) * radiusY + radiusY, 0), lineColor);
vb.AddTriangles(SECTOR_CENTER_TRIANGLES, sides * 3 + 1);
}
}
public bool HitTest(Rect contentRect, Vector2 point)
{
if (!contentRect.Contains(point))
return false;
float radiusX = contentRect.width * 0.5f;
float raduisY = contentRect.height * 0.5f;
float xx = point.x - radiusX - contentRect.x;
float yy = point.y - raduisY - contentRect.y;
if (Mathf.Pow(xx / radiusX, 2) + Mathf.Pow(yy / raduisY, 2) < 1)
{
if (startDegree != 0 || endDegreee != 360)
{
float deg = Mathf.Atan2(yy, xx) * Mathf.Rad2Deg;
if (deg < 0)
deg += 360;
return deg >= startDegree && deg <= endDegreee;
}
else
return true;
}
return false;
}
}
}