using System; using System.Collections.Generic; using UnityEngine; namespace ProceduralToolkit { /// /// Representation of a 3D line segment /// [Serializable] public struct Segment3 : IEquatable, IFormattable { public Vector3 a; public Vector3 b; /// /// Returns the normalized direction of the segment /// public Vector3 direction => (b - a).normalized; /// /// Returns the length of the segment /// public float length => (b - a).magnitude; /// /// Returns the center of the segment /// public Vector2 center => GetPoint(0.5f); /// /// Returns the axis-aligned bounding box of the segment /// public Bounds aabb { get { var bounds = new Bounds(); bounds.SetMinMax(Vector3.Min(a, b), Vector3.Max(a, b)); return bounds; } } public Segment3(Vector3 a, Vector3 b) { this.a = a; this.b = b; } /// /// Access the a or b component using [0] or [1] respectively /// public Vector3 this[int index] { get { switch (index) { case 0: return a; case 1: return b; default: throw new IndexOutOfRangeException("Invalid Segment3 index!"); } } set { switch (index) { case 0: a = value; break; case 1: b = value; break; default: throw new IndexOutOfRangeException("Invalid Segment3 index!"); } } } /// /// Returns a point on the segment at the given normalized position /// /// Normalized position public Vector3 GetPoint(float position) { return Geometry.PointOnSegment3(a, b, position); } /// /// Returns a list of evenly distributed points on the segment /// /// Number of points public List GetPoints(int count) { return Geometry.PointsOnSegment3(a, b, count); } /// /// Linearly interpolates between two segments /// public static Segment3 Lerp(Segment3 a, Segment3 b, float t) { t = Mathf.Clamp01(t); return new Segment3(a.a + (b.a - a.a)*t, a.b + (b.b - a.b)*t); } /// /// Linearly interpolates between two segments without clamping the interpolant /// public static Segment3 LerpUnclamped(Segment3 a, Segment3 b, float t) { return new Segment3(a.a + (b.a - a.a)*t, a.b + (b.b - a.b)*t); } #region Casting operators public static explicit operator Line3(Segment3 segment) { return new Line3(segment.a, (segment.b - segment.a).normalized); } public static explicit operator Ray(Segment3 segment) { return new Ray(segment.a, (segment.b - segment.a).normalized); } public static explicit operator Segment2(Segment3 segment) { return new Segment2((Vector2) segment.a, (Vector2) segment.b); } #endregion Casting operators public static Segment3 operator +(Segment3 segment, Vector3 vector) { return new Segment3(segment.a + vector, segment.b + vector); } public static Segment3 operator -(Segment3 segment, Vector3 vector) { return new Segment3(segment.a - vector, segment.b - vector); } public static bool operator ==(Segment3 a, Segment3 b) { return a.a == b.a && a.b == b.b; } public static bool operator !=(Segment3 a, Segment3 b) { return !(a == b); } public override int GetHashCode() { return a.GetHashCode() ^ (b.GetHashCode() << 2); } public override bool Equals(object other) { return other is Segment3 && Equals((Segment3) other); } public bool Equals(Segment3 other) { return a.Equals(other.a) && b.Equals(other.b); } public override string ToString() { return string.Format("Segment3(a: {0}, b: {1})", a, b); } public string ToString(string format) { return string.Format("Segment3(a: {0}, b: {1})", a.ToString(format), b.ToString(format)); } public string ToString(string format, IFormatProvider formatProvider) { return string.Format("Segment3(a: {0}, b: {1})", a.ToString(format, formatProvider), b.ToString(format, formatProvider)); } } }