using UnityEngine; using System.Collections.Generic; using System.Linq; namespace UnityEngine.ProBuilder { /// /// Internal bounds class. /// sealed class Bounds2D { public Vector2 center = Vector2.zero; [SerializeField] Vector2 m_Size = Vector2.zero; [SerializeField] Vector2 m_Extents = Vector2.zero; public Vector2 size { get { return m_Size; } set { m_Size = value; m_Extents.x = m_Size.x * .5f; m_Extents.y = m_Size.y * .5f; } } public Vector2 extents { get { return m_Extents; } } /// /// Returns an array of Vector2[] points for each corner, in the order right to left, top to bottom. /// public Vector2[] corners { get { return new Vector2[] { new Vector2(center.x - extents.x, center.y + extents.y), new Vector2(center.x + extents.x, center.y + extents.y), new Vector2(center.x - extents.x, center.y - extents.y), new Vector2(center.x + extents.x, center.y - extents.y) }; } } public Bounds2D() {} public Bounds2D(Vector2 center, Vector2 size) { this.center = center; this.size = size; } /// /// Create bounds from a set of 2d points. /// /// public Bounds2D(IList points) { SetWithPoints(points); } /// /// Create bounds from a set of 2d points. /// /// /// public Bounds2D(IList points, IList indexes) { SetWithPoints(points, indexes); } /// /// Create bounds from a set of 3d points cast to 2d. /// /// /// internal Bounds2D(Vector3[] points, Edge[] edges) { float xMin = 0f, xMax = 0f, yMin = 0f, yMax = 0f; if (points.Length > 0 && edges.Length > 0) { xMin = points[edges[0].a].x; yMin = points[edges[0].a].y; xMax = xMin; yMax = yMin; for (int i = 0; i < edges.Length; i++) { xMin = Mathf.Min(xMin, points[edges[i].a].x); xMin = Mathf.Min(xMin, points[edges[i].b].x); yMin = Mathf.Min(yMin, points[edges[i].a].y); yMin = Mathf.Min(yMin, points[edges[i].b].y); xMax = Mathf.Max(xMax, points[edges[i].a].x); xMax = Mathf.Max(xMax, points[edges[i].b].x); yMax = Mathf.Max(yMax, points[edges[i].a].y); yMax = Mathf.Max(yMax, points[edges[i].b].y); } } this.center = new Vector2((xMin + xMax) / 2f, (yMin + yMax) / 2f); this.size = new Vector3(xMax - xMin, yMax - yMin); } public Bounds2D(Vector2[] points, int length) { float xMin = 0f, xMax = 0f, yMin = 0f, yMax = 0f; if (points.Length > 0) { xMin = points[0].x; yMin = points[0].y; xMax = xMin; yMax = yMin; for (int i = 1; i < length; i++) { xMin = Mathf.Min(xMin, points[i].x); yMin = Mathf.Min(yMin, points[i].y); xMax = Mathf.Max(xMax, points[i].x); yMax = Mathf.Max(yMax, points[i].y); } } this.center = new Vector2((xMin + xMax) / 2f, (yMin + yMax) / 2f); this.size = new Vector3(xMax - xMin, yMax - yMin); } /// /// Returns true if the point is contained within the bounds. False otherwise. /// /// /// public bool ContainsPoint(Vector2 point) { return !(point.x > center.x + extents.x || point.x < center.x - extents.x || point.y > center.y + extents.y || point.y < center.y - extents.y); } /// /// Returns true if any part of the line segment is contained within this bounding box. /// /// /// /// public bool IntersectsLineSegment(Vector2 lineStart, Vector2 lineEnd) { if (ContainsPoint(lineStart) || ContainsPoint(lineEnd)) { return true; } else { Vector2[] aabb = corners; return (Math.GetLineSegmentIntersect(aabb[0], aabb[1], lineStart, lineEnd) || Math.GetLineSegmentIntersect(aabb[1], aabb[3], lineStart, lineEnd) || Math.GetLineSegmentIntersect(aabb[3], aabb[2], lineStart, lineEnd) || Math.GetLineSegmentIntersect(aabb[2], aabb[0], lineStart, lineEnd)); } } /// /// Returns true if bounds overlap. /// /// /// public bool Intersects(Bounds2D bounds) { Vector2 dist = this.center - bounds.center; Vector2 size = this.size + bounds.size; return Mathf.Abs(dist.x) * 2f < size.x && Mathf.Abs(dist.y) * 2f < size.y; } /// /// Check if this rect is intersected by another. /// /// /// True if bounds overlaps rect. public bool Intersects(Rect rect) { Vector2 dist = this.center - rect.center; Vector2 size = this.size + rect.size; return Mathf.Abs(dist.x) * 2f < size.x && Mathf.Abs(dist.y) * 2f < size.y; } /// /// Set this bounds center and size to encapsulate points. /// /// public void SetWithPoints(IList points) { float xMin = 0f, xMax = 0f, yMin = 0f, yMax = 0f; int len = points.Count; if (len > 0) { xMin = points[0].x; yMin = points[0].y; xMax = xMin; yMax = yMin; for (int i = 1; i < len; i++) { float x = points[i].x; float y = points[i].y; if (x < xMin) xMin = x; if (x > xMax) xMax = x; if (y < yMin) yMin = y; if (y > yMax) yMax = y; } } center.x = (xMin + xMax) / 2f; center.y = (yMin + yMax) / 2f; m_Size.x = xMax - xMin; m_Size.y = yMax - yMin; m_Extents.x = m_Size.x * .5f; m_Extents.y = m_Size.y * .5f; } /// /// Set this bounds center and size to encapsulate points. /// /// /// public void SetWithPoints(IList points, IList indexes) { float xMin = 0f, xMax = 0f, yMin = 0f, yMax = 0f; if (points.Count > 0 && indexes.Count > 0) { xMin = points[indexes[0]].x; yMin = points[indexes[0]].y; xMax = xMin; yMax = yMin; for (int i = 1; i < indexes.Count; i++) { float x = points[indexes[i]].x; float y = points[indexes[i]].y; if (x < xMin) xMin = x; if (x > xMax) xMax = x; if (y < yMin) yMin = y; if (y > yMax) yMax = y; } } center.x = (xMin + xMax) / 2f; center.y = (yMin + yMax) / 2f; m_Size.x = xMax - xMin; m_Size.y = yMax - yMin; m_Extents.x = m_Size.x * .5f; m_Extents.y = m_Size.y * .5f; } /// /// Returns the center of the bounding box of points. Optional parameter @length limits the bounds calculations /// to only the points up to length in array. /// /// /// /// public static Vector2 Center(IList points) { float xMin = 0f, xMax = 0f, yMin = 0f, yMax = 0f; int size = points.Count; xMin = points[0].x; yMin = points[0].y; xMax = xMin; yMax = yMin; for (int i = 1; i < size; i++) { float x = points[i].x; float y = points[i].y; if (x < xMin) xMin = x; if (x > xMax) xMax = x; if (y < yMin) yMin = y; if (y > yMax) yMax = y; } return new Vector2((xMin + xMax) / 2f, (yMin + yMax) / 2f); } public static Vector2 Center(IList points, IList indexes) { float xMin = 0f, xMax = 0f, yMin = 0f, yMax = 0f; int size = indexes.Count; xMin = points[indexes[0]].x; yMin = points[indexes[0]].y; xMax = xMin; yMax = yMin; for (int i = 1; i < size; i++) { float x = points[indexes[i]].x; float y = points[indexes[i]].y; if (x < xMin) xMin = x; if (x > xMax) xMax = x; if (y < yMin) yMin = y; if (y > yMax) yMax = y; } return new Vector2((xMin + xMax) / 2f, (yMin + yMax) / 2f); } public static Vector2 Size(IList points, IList indexes) { float xMin = 0f, xMax = 0f, yMin = 0f, yMax = 0f; int size = indexes.Count; xMin = points[indexes[0]].x; yMin = points[indexes[0]].y; xMax = xMin; yMax = yMin; for (int i = 1; i < size; i++) { float x = points[indexes[i]].x; float y = points[indexes[i]].y; if (x < xMin) xMin = x; if (x > xMax) xMax = x; if (y < yMin) yMin = y; if (y > yMax) yMax = y; } return new Vector2(xMax - xMin, yMax - yMin); } internal static Vector2 Center(IList points, IEnumerable indexes) { float xMin = 0f, xMax = 0f, yMin = 0f, yMax = 0f; var first = indexes.First(); xMin = points[first].x; yMin = points[first].y; xMax = xMin; yMax = yMin; foreach(var index in indexes) { float x = points[index].x; float y = points[index].y; if (x < xMin) xMin = x; if (x > xMax) xMax = x; if (y < yMin) yMin = y; if (y > yMax) yMax = y; } return new Vector2((xMin + xMax) / 2f, (yMin + yMax) / 2f); } public override string ToString() { return "[cen: " + center + " size: " + size + "]"; } } }