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));
}
}
}