
namespace XELF.Framework {

	/// <summary>
	/// プリュカー座標
	/// </summary>
	public struct Plucker { // (V : W)
		/// <summary>
		/// N
		/// </summary>
		public Vector3 N;
		/// <summary>
		/// W
		/// </summary>
		public float W;

		// 
		/// <summary>
		/// 平面と線の交点。(U x N - d U : V . N)
		/// </summary>
		/// <param name="plane"></param>
		/// <param name="line"></param>
		/// <param name="result"></param>
		public static void Intersects(ref Plucker plane, ref PluckerLine line, out Plucker result) {
			result = new Plucker();
			Vector3.Cross(ref line.U, ref plane.N, out result.N);
			Vector3 a;
			Vector3.Multiply(ref line.U, plane.W, out a);
			Vector3.Subtract(ref result.N, ref a, out result.N);
			Vector3.Dot(ref line.V, ref plane.N, out result.W);
		}
		/// <summary>
		/// 平面と平面の交差する線。{N1 x N2 : d2 N1 - d1 N2}
		/// </summary>
		/// <param name="planeA"></param>
		/// <param name="planeB"></param>
		/// <param name="result"></param>
		public static void Intersects(ref Plucker planeA, ref Plucker planeB, out PluckerLine result) {
			result = new PluckerLine();
			Vector3.Cross(ref planeA.N, ref planeB.N, out result.U);
			Vector3.Multiply(ref planeA.N, planeB.W, out result.V);
			Vector3 a;
			Vector3.Multiply(ref planeB.N, planeA.W, out a);
			Vector3.Subtract(ref result.V, ref a, out result.V);
		}
	}

	/// <summary>
	/// プリュッカー線座標
	/// </summary>
	public struct PluckerLine { // {U : V}
		/// <summary>
		/// U
		/// </summary>
		public Vector3 U;
		/// <summary>
		/// V
		/// </summary>
		public Vector3 V;

		/// <summary>
		/// コンストラクタ
		/// </summary>
		/// <param name="u"></param>
		/// <param name="v"></param>
		public PluckerLine(Vector3 u, Vector3 v) {
			U = u; V = v;
		}

		/// <summary>
		/// 2点を通る有向直線
		/// </summary>
		/// <param name="from"></param>
		/// <param name="to"></param>
		public static PluckerLine CreateFromPointToPoint(Vector3 from, Vector3 to) {
			var result = new PluckerLine();
			Vector3.Subtract(ref to, ref from, out result.U);
			Vector3.Cross(ref to, ref from, out result.V);
			return result;
		}

		/// <summary>
		/// 直線上の点。(V x U - t U : U . U)
		/// </summary>
		/// <param name="t"></param>
		/// <param name="point"></param>
		public void GetPoint(float t, out Vector4 point) {
			Vector3 a, b;
			Vector3.Cross(ref V, ref U, out a);
			Vector3.Multiply(ref U, t, out b);
			Vector3.Subtract(ref a, ref b, out a);
			point = new Vector4(a, U.LengthSquared());
		}

		/// <summary>
		/// 有向直線の位置関係を調べる。aU . bV + aV . bU
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="result">0のとき交差か平行。0より大きいとき反時計回り。0未満のとき時計回り。</param>
		public static void Side(ref PluckerLine a, ref PluckerLine b, out float result) {
			result =
				a.U.X * b.V.X +
				a.U.Y * b.V.Y +
				a.U.Z * b.V.Z +
				a.V.X * b.U.X +
				a.V.Y * b.U.Y +
				a.V.Z * b.U.X;
		}
		/// <summary>
		/// 有向直線の位置関係を調べる。aU . bV + aV . bU
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns>0のとき交差か平行。0より大きいとき反時計回り。0未満のとき時計回り。</returns>
		public static float Side(PluckerLine a, PluckerLine b) {
			return
				a.U.X * b.V.X +
				a.U.Y * b.V.Y +
				a.U.Z * b.V.Z +
				a.V.X * b.U.X +
				a.V.Y * b.U.Y +
				a.V.Z * b.U.X;
		}
	}

}
