using UnityEngine;
namespace Flexalon
{
/// Common math help functions.
public static class Math
{
public static readonly float MaxValue = 999999f;
public static readonly Vector3 MaxVector = new Vector3(MaxValue, MaxValue, MaxValue);
/// Returns the opposite direction.
/// The direction to get the opposite of.
/// The opposite direction.
public static Direction GetOppositeDirection(Direction direction)
{
switch (direction)
{
case Direction.PositiveX: return Direction.NegativeX;
case Direction.NegativeX: return Direction.PositiveX;
case Direction.PositiveY: return Direction.NegativeY;
case Direction.NegativeY: return Direction.PositiveY;
case Direction.PositiveZ: return Direction.NegativeZ;
case Direction.NegativeZ: return Direction.PositiveZ;
default: return Direction.PositiveX;
}
}
/// Returns the opposite direction.
/// The direction to get the opposite of.
/// The opposite direction.
public static Direction GetOppositeDirection(int direction)
{
return GetOppositeDirection((Direction)direction);
}
/// Returns the axis of a direction.
/// The direction to get the axis of.
/// The axis of the direction.
public static Axis GetAxisFromDirection(Direction direction)
{
switch (direction)
{
case Direction.PositiveX: return Axis.X;
case Direction.NegativeX: return Axis.X;
case Direction.PositiveY: return Axis.Y;
case Direction.NegativeY: return Axis.Y;
case Direction.PositiveZ: return Axis.Z;
case Direction.NegativeZ: return Axis.Z;
default: return Axis.X;
}
}
/// Returns the axis of a direction.
/// The direction to get the axis of.
/// The axis of the direction.
public static Axis GetAxisFromDirection(int direction)
{
return GetAxisFromDirection((Direction)direction);
}
/// Returns the positive and negative directions of an axis.
/// The axis to get the directions of.
/// The positive and negative directions of the axis.
public static (Direction, Direction) GetDirectionsFromAxis(Axis axis)
{
switch (axis)
{
case Axis.X: return (Direction.PositiveX, Direction.NegativeX);
case Axis.Y: return (Direction.PositiveY, Direction.NegativeY);
case Axis.Z: return (Direction.PositiveZ, Direction.NegativeZ);
default: return (Direction.PositiveX, Direction.NegativeX);
}
}
/// Returns the positive and negative directions of an axis.
/// The axis to get the directions of.
/// The positive and negative directions of the axis.
public static (Direction, Direction) GetDirectionsFromAxis(int axis)
{
return GetDirectionsFromAxis((Axis)axis);
}
/// Returns the positive direction of an axis.
/// The axis to get the direction of.
/// The positive direction of the axis.
public static float GetPositiveFromDirection(Direction direction)
{
switch (direction)
{
case Direction.PositiveX:
case Direction.PositiveY:
case Direction.PositiveZ:
return 1;
default:
return -1;
}
}
/// Returns the positive direction of an axis.
/// The axis to get the direction of.
/// The positive direction of the axis.
public static float GetPositiveFromDirection(int direction)
{
return GetPositiveFromDirection((Direction)direction);
}
/// Returns a unit vector in the direction.
/// The direction to get the vector of.
/// A unit vector in the direction.
public static Vector3 GetVectorFromDirection(Direction direction)
{
switch (direction)
{
case Direction.PositiveX:
return Vector3.right;
case Direction.PositiveY:
return Vector3.up;
case Direction.PositiveZ:
return Vector3.forward;
case Direction.NegativeX:
return Vector3.left;
case Direction.NegativeY:
return Vector3.down;
case Direction.NegativeZ:
return Vector3.back;
}
return Vector3.zero;
}
/// Returns a unit vector in the direction.
/// The direction to get the vector of.
/// A unit vector in the direction.
public static Vector3 GetVectorFromDirection(int direction)
{
return GetVectorFromDirection((Direction)direction);
}
/// Returns a unit vector in the positive direction of axis.
/// The axis to get the vector of.
/// A unit vector in the axis.
public static Vector3 GetVectorFromAxis(Axis axis)
{
switch (axis)
{
case Axis.X:
return Vector3.right;
case Axis.Y:
return Vector3.up;
case Axis.Z:
return Vector3.forward;
}
return Vector3.zero;
}
/// Returns a unit vector in the positive direction of axis.
/// The axis to get the vector of.
/// A unit vector in the axis.
public static Vector3 GetVectorFromAxis(int axis)
{
return GetVectorFromAxis((Axis)axis);
}
/// Returns the other two axes.
/// The axis to get the other two axes of.
/// The other two axes.
public static (Axis, Axis) GetOtherAxes(Axis axis)
{
switch (axis)
{
case Axis.X: return (Axis.Y, Axis.Z);
case Axis.Y: return (Axis.X, Axis.Z);
default: return (Axis.X, Axis.Y);
}
}
/// Returns the other two axes.
/// The axis to get the other two axes of.
/// The other two axes.
public static (int, int) GetOtherAxes(int axis)
{
var other = GetOtherAxes((Axis)axis);
return ((int)other.Item1, (int)other.Item2);
}
/// Given two axes, returns the third axis.
/// The first axis.
/// The second axis.
/// The third axis.
public static Axis GetThirdAxis(Axis axis1, Axis axis2)
{
var otherAxes = GetOtherAxes(axis1);
return (otherAxes.Item1 == axis2) ? otherAxes.Item2 : otherAxes.Item1;
}
/// Given two axes, returns the third axis.
/// The first axis.
/// The second axis.
/// The third axis.
public static int GetThirdAxis(int axis1, int axis2)
{
return (int) GetThirdAxis((Axis)axis1, (Axis)axis2);
}
/// Returns the axes of a plane.
/// The plane to get the axes of.
/// The axes of the plane.
public static (Axis, Axis) GetPlaneAxes(Plane plane)
{
switch (plane)
{
case Plane.XY: return (Axis.X, Axis.Y);
case Plane.XZ: return (Axis.X, Axis.Z);
default: return (Axis.Z, Axis.Y);
}
}
/// Returns the axes of a plane.
/// The plane to get the axes of.
/// The axes of the plane.
public static (int, int) GetPlaneAxesInt(Plane plane)
{
var axes = GetPlaneAxes(plane);
return ((int)axes.Item1, (int)axes.Item2);
}
/// Multiplies each component of two vectors.
/// The first vector.
/// The second vector.
/// The multiplied vector.
public static Vector3 Mul(Vector3 a, Vector3 b)
{
a.x *= b.x;
a.y *= b.y;
a.z *= b.z;
return a;
}
/// Divides each component of two vectors.
/// The divided vector.
/// The divisor vector.
/// The divided vector.
public static Vector3 Div(Vector3 a, Vector3 b)
{
a.x /= b.x;
a.y /= b.y;
a.z /= b.z;
return a;
}
/// Rotates a bounds around the origin and returns a new bounds
/// that encapsulates all of the rotated corners.
/// The bounds to rotate.
/// The rotation to rotate the bounds by.
/// The new bounds.
public static Bounds RotateBounds(Bounds bounds, Quaternion rotation)
{
if (rotation == Quaternion.identity) return bounds;
var rotatedCenter = rotation * bounds.center;
var p1 = rotation * bounds.max;
var p2 = rotation * new Vector3(bounds.max.x, bounds.max.y, bounds.min.z);
var p3 = rotation * new Vector3(bounds.max.x, bounds.min.y, bounds.max.z);
var p4 = rotation * new Vector3(bounds.max.x, bounds.min.y, bounds.min.z);
var p5 = rotation * new Vector3(bounds.min.x, bounds.max.y, bounds.max.z);
var p6 = rotation * new Vector3(bounds.min.x, bounds.max.y, bounds.min.z);
var p7 = rotation * new Vector3(bounds.min.x, bounds.min.y, bounds.max.z);
var p8 = rotation * bounds.min;
var rotatedBounds = new Bounds(rotatedCenter, Vector3.zero);
rotatedBounds.Encapsulate(p1);
rotatedBounds.Encapsulate(p2);
rotatedBounds.Encapsulate(p3);
rotatedBounds.Encapsulate(p4);
rotatedBounds.Encapsulate(p5);
rotatedBounds.Encapsulate(p6);
rotatedBounds.Encapsulate(p7);
rotatedBounds.Encapsulate(p8);
return rotatedBounds;
}
/// Creates rotated and scaled bounds at center.
/// The center of the bounds.
/// The size of the bound before rotation.
/// The rotation to apply to the size.
public static Bounds CreateRotatedBounds(Vector3 center, Vector3 size, Quaternion rotation)
{
if (rotation == Quaternion.identity) return new Bounds(center, size);
var bounds = RotateBounds(new Bounds(Vector3.zero, size), rotation);
bounds.center = center;
return bounds;
}
/// Scales a bounds by multiplying the center and size by 'scale'.
/// The bounds to scale.
/// The scale to scale the bounds by.
/// The scaled bounds.
public static Bounds ScaleBounds(Bounds bounds, Vector3 scale)
{
bounds.center = Math.Mul(bounds.center, scale);
bounds.size = Math.Mul(bounds.size, scale);
return bounds;
}
/// Determines the aligned position in a size.
/// The size to align to.
/// The alignment.
/// The aligned position.
public static float Align(float size, Align align)
{
if (align == global::Flexalon.Align.Start)
{
return -size * 0.5f;
}
else if (align == global::Flexalon.Align.End)
{
return size * 0.5f;
}
return 0;
}
/// Determines the aligned position in a size for an axis.
/// The size to align to.
/// The axis to align to.
/// The alignment.
/// The aligned position.
public static float Align(Vector3 size, int axis, Align align)
{
return Align(size[axis], align);
}
/// Determines the aligned position in a size.
/// The size to align to.
/// The horizontal alignment.
/// The vertical alignment.
/// The depth alignment.
/// The aligned position.
public static Vector3 Align(Vector3 size, Align horizontal, Align vertical, Align depth)
{
return new Vector3(
Align(size, 0, horizontal),
Align(size, 1, vertical),
Align(size, 2, depth));
}
/// Aligns a child size to a parent size.
/// The size of the child.
/// The size of the parent.
/// The alignment of the parent.
/// The pivot of the child.
/// The aligned position of the child.
public static float Align(float childSize, float parentSize, Align parentAlign, Align childAlign)
{
return Align(parentSize, parentAlign) - Align(childSize, childAlign);
}
/// Aligns a child size to a parent size.
/// The size of the child.
/// The size of the parent.
/// The alignment of the parent and child.
/// The aligned position of the child.
public static float Align(float childSize, float parentSize, Align align)
{
return Align(childSize, parentSize, align, align);
}
/// Aligns a child size to a parent size on an axis.
/// The size of the child.
/// The size of the parent.
/// The axis to align on.
/// The alignment of the parent and child.
/// The aligned position of the child.
public static float Align(Vector3 childSize, Vector3 parentSize, int axis, Align align)
{
return Align(childSize[axis], parentSize[axis], align);
}
/// Aligns a child size to a parent size on an axis.
/// The size of the child.
/// The size of the parent.
/// The axis to align on.
/// The alignment of the parent and child.
/// The aligned position of the child.
public static float Align(Vector3 childSize, Vector3 parentSize, Axis axis, Align align)
{
return Align(childSize, parentSize, (int)axis, align);
}
/// Aligns a child size to a parent size on an axis.
/// The size of the child.
/// The size of the parent.
/// The axis to align on.
/// The alignment of the parent.
/// The pivot of the child.
/// The aligned position of the child.
public static float Align(Vector3 childSize, Vector3 parentSize, int axis, Align parentAlign, Align childAlign)
{
return Align(childSize[axis], parentSize[axis], parentAlign, childAlign);
}
/// Aligns a child size to a parent size on an axis.
/// The size of the child.
/// The size of the parent.
/// The axis to align on.
/// The alignment of the parent.
/// The pivot of the child.
/// The aligned position of the child.
public static float Align(Vector3 childSize, Vector3 parentSize, Axis axis, Align parentAlign, Align childAlign)
{
return Align(childSize, parentSize, (int)axis, parentAlign, childAlign);
}
/// Aligns a child size to a parent size on all axes.
/// The size of the child.
/// The size of the parent.
/// The horizontal alignment of the parent.
/// The vertical alignment of the parent.
/// The depth alignment of the parent.
/// The horizontal pivot of the child.
/// The vertical pivot of the child.
/// The depth pivot of the child.
/// The aligned position of the child.
public static Vector3 Align(Vector3 childSize, Vector3 parentSize, Align parentHorizontal, Align parentVertical, Align parentDepth, Align childHorizontal, Align childVertical, Align childDepth)
{
return Align(parentSize, parentHorizontal, parentVertical, parentDepth) -
Align(childSize, childHorizontal, childVertical, childDepth);
}
/// Aligns a child size to a parent size on all axes.
/// The size of the child.
/// The size of the parent.
/// The horizontal alignment of the parent and child.
/// The vertical alignment of the parent and child.
/// The depth alignment of the parent and child.
/// The aligned position of the child.
public static Vector3 Align(Vector3 childSize, Vector3 parentSize, Align horizontal, Align vertical, Align depth)
{
return Align(parentSize, horizontal, vertical, depth) -
Align(childSize, horizontal, vertical, depth);
}
/// Given the bounds of a component, creates a bounds for the node respecting the
/// size types. Aspect ratio is preserved when possible.
/// The bounds of the component.
/// The node to measure the bounds for.
/// The size of the node.
/// The minimum size of the node.
/// The maximum size of the node.
/// The bounds of the node.
public static Bounds MeasureComponentBounds(Bounds componentBounds, FlexalonNode node, Vector3 size, Vector3 min, Vector3 max)
{
componentBounds.size = Vector3.Max(componentBounds.size, Vector3.one * 0.0001f);
var bounds = componentBounds;
bool componentX = node.GetSizeType(Axis.X) == SizeType.Component;
bool componentY = node.GetSizeType(Axis.Y) == SizeType.Component;
bool componentZ = node.GetSizeType(Axis.Z) == SizeType.Component;
var scale = (componentX && componentY && componentZ) ? 1 :
Mathf.Min(
componentX ? float.MaxValue : size.x / bounds.size.x,
componentY ? float.MaxValue : size.y / bounds.size.y,
componentZ ? float.MaxValue : size.z / bounds.size.z);
var maxScale = Mathf.Min(max.x / bounds.size.x, max.y / bounds.size.y, max.z / bounds.size.z);
var minScale = Mathf.Max(min.x / bounds.size.x, min.y / bounds.size.y, min.z / bounds.size.z);
var clampedScale = Mathf.Clamp(scale, minScale, maxScale);
var clampedSize = Math.Clamp(size, min, max);
bounds.size = new Vector3(
componentX ? bounds.size.x * clampedScale : clampedSize.x,
componentY ? bounds.size.y * clampedScale : clampedSize.y,
componentZ ? bounds.size.z * clampedScale : clampedSize.z);
bounds.center = Math.Mul(bounds.center, Math.Div(bounds.size, componentBounds.size));
return bounds;
}
/// Given the bounds of a component, creates a bounds for the node respecting the
/// size types. Aspect ratio is preserved for X and Y when possible.
/// The bounds of the component.
/// The node to measure the bounds for.
/// The size of the node.
/// The minimum size of the node.
/// The maximum size of the node.
/// The bounds of the node.
public static Bounds MeasureComponentBounds2D(Bounds componentBounds, FlexalonNode node, Vector3 size, Vector3 min, Vector3 max)
{
componentBounds.size = Vector3.Max(componentBounds.size, Vector3.one * 0.0001f);
var bounds = componentBounds;
bool componentX = node.GetSizeType(Axis.X) == SizeType.Component;
bool componentY = node.GetSizeType(Axis.Y) == SizeType.Component;
var scale = (componentX && componentY) ? 1 :
Mathf.Min(
componentX ? float.MaxValue : size.x / bounds.size.x,
componentY ? float.MaxValue : size.y / bounds.size.y);
var maxScale = Mathf.Min(max.x / bounds.size.x, max.y / bounds.size.y);
var minScale = Mathf.Max(min.x / bounds.size.x, min.y / bounds.size.y);
var clampedScale = Mathf.Clamp(scale, minScale, maxScale);
var clampedSize = Math.Clamp(size, min, max);
bounds.size = new Vector3(
componentX ? bounds.size.x * clampedScale : clampedSize.x,
componentY ? bounds.size.y * clampedScale : clampedSize.y,
clampedSize.z);
bounds.center = Math.Mul(bounds.center, Math.Div(bounds.size, componentBounds.size));
return bounds;
}
/// Applies absolute value of to each vector component.
/// The vector to apply absolute value to.
/// The vector with absolute value applied.
public static Vector3 Abs(Vector3 v)
{
v.x = Mathf.Abs(v.x);
v.y = Mathf.Abs(v.y);
v.z = Mathf.Abs(v.z);
return v;
}
/// Clamps value of to each vector component between min and max.
/// The vector to clamp.
/// The minimum value.
/// The maximum value.
/// The clamped vector.
public static Vector3 Clamp(Vector3 v, Vector3 min, Vector3 max)
{
v.x = Mathf.Clamp(v.x, min.x, max.x);
v.y = Mathf.Clamp(v.y, min.y, max.y);
v.z = Mathf.Clamp(v.z, min.z, max.z);
return v;
}
}
}