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