// MIT License - Copyright (c) 2023 wallstop
// Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE
namespace WallstopStudios.UnityHelpers.Core.Helper
{
using System;
using System.Collections.Generic;
using UnityEngine;
///
/// Lightweight geometric helpers for Rect accumulation and sidedness tests.
///
public static class Geometry
{
///
/// Computes the axis-aligned bounding that contains all input rects.
///
/// A non-empty sequence of rectangles to accumulate.
/// The minimal axis-aligned that contains all input rectangles.
///
/// Expects a non-empty sequence. Passing an empty sequence throws .
///
public static Rect Accumulate(this IEnumerable rects)
{
using IEnumerator enumerator = rects.GetEnumerator();
if (!enumerator.MoveNext())
{
throw new InvalidOperationException("Sequence contains no elements");
}
Rect accumulated = enumerator.Current;
while (enumerator.MoveNext())
{
Rect next = enumerator.Current;
accumulated = new Rect(
Mathf.Min(accumulated.xMin, next.xMin),
Mathf.Min(accumulated.yMin, next.yMin),
Mathf.Max(accumulated.xMax, next.xMax) - Mathf.Min(accumulated.xMin, next.xMin),
Mathf.Max(accumulated.yMax, next.yMax) - Mathf.Min(accumulated.yMin, next.yMin)
);
}
return accumulated;
}
//Where is p in relation to a-b
// < 0 -> to the right
// = 0 -> on the line
// > 0 -> to the left
///
/// Returns signed area indicating where point p lies relative to vector a→b in 2D.
/// < 0 → right, 0 → on line, > 0 → left.
///
public static double IsAPointLeftOfVectorOrOnTheLineDouble(Vector2 a, Vector2 b, Vector2 p)
{
double abx = b.x - a.x;
double aby = b.y - a.y;
double apx = p.x - a.x;
double apy = p.y - a.y;
return abx * apy - aby * apx;
}
public static float IsAPointLeftOfVectorOrOnTheLine(Vector2 a, Vector2 b, Vector2 p)
{
return (float)IsAPointLeftOfVectorOrOnTheLineDouble(a, b, p);
}
///
/// Returns signed area indicating where point p lies relative to vector a→b in 2D (using Vector3 x/y).
///
public static double IsAPointLeftOfVectorOrOnTheLineDouble(Vector3 a, Vector3 b, Vector3 p)
{
double abx = b.x - a.x;
double aby = b.y - a.y;
double apx = p.x - a.x;
double apy = p.y - a.y;
return abx * apy - aby * apx;
}
public static float IsAPointLeftOfVectorOrOnTheLine(Vector3 a, Vector3 b, Vector3 p)
{
return (float)IsAPointLeftOfVectorOrOnTheLineDouble(a, b, p);
}
///
/// Returns signed area indicating where point p lies relative to vector a→b in 2D (int version).
///
public static int IsAPointLeftOfVectorOrOnTheLine(Vector2Int a, Vector2Int b, Vector2Int p)
{
return (b.x - a.x) * (p.y - a.y) - (b.y - a.y) * (p.x - a.x);
}
}
}