From d2ab30e7a69bfe7efda63ae75812207377917bd3 Mon Sep 17 00:00:00 2001 From: miepzerino <o.skotnik@gmail.com> Date: Sun, 30 Mar 2025 18:50:27 +0000 Subject: [PATCH] Merge branch 'Flexalon-UI-Layouts' into develop --- Assets/Flexalon/Runtime/Core/FlexalonMath.cs | 540 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 540 insertions(+), 0 deletions(-) diff --git a/Assets/Flexalon/Runtime/Core/FlexalonMath.cs b/Assets/Flexalon/Runtime/Core/FlexalonMath.cs new file mode 100644 index 0000000..bf03681 --- /dev/null +++ b/Assets/Flexalon/Runtime/Core/FlexalonMath.cs @@ -0,0 +1,540 @@ +using UnityEngine; + +namespace Flexalon +{ + /// <summary> Common math help functions. </summary> + public static class Math + { + public static readonly float MaxValue = 999999f; + public static readonly Vector3 MaxVector = new Vector3(MaxValue, MaxValue, MaxValue); + + /// <summary> Returns the opposite direction. </summary> + /// <param name="direction"> The direction to get the opposite of. </param> + /// <returns> The opposite direction. </returns> + 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; + } + } + + /// <summary> Returns the opposite direction. </summary> + /// <param name="direction"> The direction to get the opposite of. </param> + /// <returns> The opposite direction. </returns> + public static Direction GetOppositeDirection(int direction) + { + return GetOppositeDirection((Direction)direction); + } + + /// <summary> Returns the axis of a direction. </summary> + /// <param name="direction"> The direction to get the axis of. </param> + /// <returns> The axis of the direction. </returns> + 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; + } + } + + /// <summary> Returns the axis of a direction. </summary> + /// <param name="direction"> The direction to get the axis of. </param> + /// <returns> The axis of the direction. </returns> + public static Axis GetAxisFromDirection(int direction) + { + return GetAxisFromDirection((Direction)direction); + } + + /// <summary> Returns the positive and negative directions of an axis. </summary> + /// <param name="axis"> The axis to get the directions of. </param> + /// <returns> The positive and negative directions of the axis. </returns> + 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); + } + } + + /// <summary> Returns the positive and negative directions of an axis. </summary> + /// <param name="axis"> The axis to get the directions of. </param> + /// <returns> The positive and negative directions of the axis. </returns> + public static (Direction, Direction) GetDirectionsFromAxis(int axis) + { + return GetDirectionsFromAxis((Axis)axis); + } + + /// <summary> Returns the positive direction of an axis. </summary> + /// <param name="axis"> The axis to get the direction of. </param> + /// <returns> The positive direction of the axis. </returns> + public static float GetPositiveFromDirection(Direction direction) + { + switch (direction) + { + case Direction.PositiveX: + case Direction.PositiveY: + case Direction.PositiveZ: + return 1; + default: + return -1; + } + } + + /// <summary> Returns the positive direction of an axis. </summary> + /// <param name="axis"> The axis to get the direction of. </param> + /// <returns> The positive direction of the axis. </returns> + public static float GetPositiveFromDirection(int direction) + { + return GetPositiveFromDirection((Direction)direction); + } + + /// <summary> Returns a unit vector in the direction. </summary> + /// <param name="direction"> The direction to get the vector of. </param> + /// <returns> A unit vector in the direction. </returns> + 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; + } + + /// <summary> Returns a unit vector in the direction. </summary> + /// <param name="direction"> The direction to get the vector of. </param> + /// <returns> A unit vector in the direction. </returns> + public static Vector3 GetVectorFromDirection(int direction) + { + return GetVectorFromDirection((Direction)direction); + } + + /// <summary> Returns a unit vector in the positive direction of axis. </summary> + /// <param name="axis"> The axis to get the vector of. </param> + /// <returns> A unit vector in the axis. </returns> + 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; + } + + /// <summary> Returns a unit vector in the positive direction of axis. </summary> + /// <param name="axis"> The axis to get the vector of. </param> + /// <returns> A unit vector in the axis. </returns> + public static Vector3 GetVectorFromAxis(int axis) + { + return GetVectorFromAxis((Axis)axis); + } + + /// <summary> Returns the other two axes. </summary> + /// <param name="axis"> The axis to get the other two axes of. </param> + /// <returns> The other two axes. </returns> + 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); + } + } + + /// <summary> Returns the other two axes. </summary> + /// <param name="axis"> The axis to get the other two axes of. </param> + /// <returns> The other two axes. </returns> + public static (int, int) GetOtherAxes(int axis) + { + var other = GetOtherAxes((Axis)axis); + return ((int)other.Item1, (int)other.Item2); + } + + /// <summary> Given two axes, returns the third axis. </summary> + /// <param name="axis1"> The first axis. </param> + /// <param name="axis2"> The second axis. </param> + /// <returns> The third axis. </returns> + public static Axis GetThirdAxis(Axis axis1, Axis axis2) + { + var otherAxes = GetOtherAxes(axis1); + return (otherAxes.Item1 == axis2) ? otherAxes.Item2 : otherAxes.Item1; + } + + /// <summary> Given two axes, returns the third axis. </summary> + /// <param name="axis1"> The first axis. </param> + /// <param name="axis2"> The second axis. </param> + /// <returns> The third axis. </returns> + public static int GetThirdAxis(int axis1, int axis2) + { + return (int) GetThirdAxis((Axis)axis1, (Axis)axis2); + } + + /// <summary> Returns the axes of a plane. </summary> + /// <param name="plane"> The plane to get the axes of. </param> + /// <returns> The axes of the plane. </returns> + 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); + } + } + + /// <summary> Returns the axes of a plane. </summary> + /// <param name="plane"> The plane to get the axes of. </param> + /// <returns> The axes of the plane. </returns> + public static (int, int) GetPlaneAxesInt(Plane plane) + { + var axes = GetPlaneAxes(plane); + return ((int)axes.Item1, (int)axes.Item2); + } + + /// <summary> Multiplies each component of two vectors. </summary> + /// <param name="a"> The first vector. </param> + /// <param name="b"> The second vector. </param> + /// <returns> The multiplied vector. </returns> + public static Vector3 Mul(Vector3 a, Vector3 b) + { + a.x *= b.x; + a.y *= b.y; + a.z *= b.z; + return a; + } + + /// <summary> Divides each component of two vectors. </summary> + /// <param name="a"> The divided vector. </param> + /// <param name="b"> The divisor vector. </param> + /// <returns> The divided vector. </returns> + public static Vector3 Div(Vector3 a, Vector3 b) + { + a.x /= b.x; + a.y /= b.y; + a.z /= b.z; + return a; + } + + /// <summary> Rotates a bounds around the origin and returns a new bounds + /// that encapsulates all of the rotated corners. </summary> + /// <param name="bounds"> The bounds to rotate. </param> + /// <param name="rotation"> The rotation to rotate the bounds by. </param> + /// <returns> The new bounds. </returns> + 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; + } + + /// <summary> Creates rotated and scaled bounds at center. </summary> + /// <param name="center"> The center of the bounds. </param> + /// <param name="size"> The size of the bound before rotation. </param> + /// <param name="rotation"> The rotation to apply to the size. </param> + 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; + } + + /// <summary> Scales a bounds by multiplying the center and size by 'scale'. </summary> + /// <param name="bounds"> The bounds to scale. </param> + /// <param name="scale"> The scale to scale the bounds by. </param> + /// <returns> The scaled bounds. </returns> + public static Bounds ScaleBounds(Bounds bounds, Vector3 scale) + { + bounds.center = Math.Mul(bounds.center, scale); + bounds.size = Math.Mul(bounds.size, scale); + return bounds; + } + + /// <summary> Determines the aligned position in a size. </summary> + /// <param name="size"> The size to align to. </param> + /// <param name="align"> The alignment. </param> + /// <returns> The aligned position. </returns> + 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; + } + + /// <summary> Determines the aligned position in a size for an axis. </summary> + /// <param name="size"> The size to align to. </param> + /// <param name="axis"> The axis to align to. </param> + /// <param name="align"> The alignment. </param> + /// <returns> The aligned position. </returns> + public static float Align(Vector3 size, int axis, Align align) + { + return Align(size[axis], align); + } + + /// <summary> Determines the aligned position in a size. </summary> + /// <param name="size"> The size to align to. </param> + /// <param name="horizontal"> The horizontal alignment. </param> + /// <param name="vertical"> The vertical alignment. </param> + /// <param name="depth"> The depth alignment. </param> + /// <returns> The aligned position. </returns> + 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)); + } + + /// <summary> Aligns a child size to a parent size. </summary> + /// <param name="childSize"> The size of the child. </param> + /// <param name="parentSize"> The size of the parent. </param> + /// <param name="parentAlign"> The alignment of the parent. </param> + /// <param name="childAlign"> The pivot of the child. </param> + /// <returns> The aligned position of the child. </returns> + public static float Align(float childSize, float parentSize, Align parentAlign, Align childAlign) + { + return Align(parentSize, parentAlign) - Align(childSize, childAlign); + } + + /// <summary> Aligns a child size to a parent size. </summary> + /// <param name="childSize"> The size of the child. </param> + /// <param name="parentSize"> The size of the parent. </param> + /// <param name="align"> The alignment of the parent and child. </param> + /// <returns> The aligned position of the child. </returns> + public static float Align(float childSize, float parentSize, Align align) + { + return Align(childSize, parentSize, align, align); + } + + /// <summary> Aligns a child size to a parent size on an axis. </summary> + /// <param name="childSize"> The size of the child. </param> + /// <param name="parentSize"> The size of the parent. </param> + /// <param name="axis"> The axis to align on. </param> + /// <param name="align"> The alignment of the parent and child. </param> + /// <returns> The aligned position of the child. </returns> + public static float Align(Vector3 childSize, Vector3 parentSize, int axis, Align align) + { + return Align(childSize[axis], parentSize[axis], align); + } + + /// <summary> Aligns a child size to a parent size on an axis. </summary> + /// <param name="childSize"> The size of the child. </param> + /// <param name="parentSize"> The size of the parent. </param> + /// <param name="axis"> The axis to align on. </param> + /// <param name="align"> The alignment of the parent and child. </param> + /// <returns> The aligned position of the child. </returns> + public static float Align(Vector3 childSize, Vector3 parentSize, Axis axis, Align align) + { + return Align(childSize, parentSize, (int)axis, align); + } + + /// <summary> Aligns a child size to a parent size on an axis. </summary> + /// <param name="childSize"> The size of the child. </param> + /// <param name="parentSize"> The size of the parent. </param> + /// <param name="axis"> The axis to align on. </param> + /// <param name="parentAlign"> The alignment of the parent. </param> + /// <param name="childAlign"> The pivot of the child. </param> + /// <returns> The aligned position of the child. </returns> + public static float Align(Vector3 childSize, Vector3 parentSize, int axis, Align parentAlign, Align childAlign) + { + return Align(childSize[axis], parentSize[axis], parentAlign, childAlign); + } + + /// <summary> Aligns a child size to a parent size on an axis. </summary> + /// <param name="childSize"> The size of the child. </param> + /// <param name="parentSize"> The size of the parent. </param> + /// <param name="axis"> The axis to align on. </param> + /// <param name="parentAlign"> The alignment of the parent. </param> + /// <param name="childAlign"> The pivot of the child. </param> + /// <returns> The aligned position of the child. </returns> + public static float Align(Vector3 childSize, Vector3 parentSize, Axis axis, Align parentAlign, Align childAlign) + { + return Align(childSize, parentSize, (int)axis, parentAlign, childAlign); + } + + /// <summary> Aligns a child size to a parent size on all axes. </summary> + /// <param name="childSize"> The size of the child. </param> + /// <param name="parentSize"> The size of the parent. </param> + /// <param name="parentHorizontal"> The horizontal alignment of the parent. </param> + /// <param name="parentVertical"> The vertical alignment of the parent. </param> + /// <param name="parentDepth"> The depth alignment of the parent. </param> + /// <param name="childHorizontal"> The horizontal pivot of the child. </param> + /// <param name="childVertical"> The vertical pivot of the child. </param> + /// <param name="childDepth"> The depth pivot of the child. </param> + /// <returns> The aligned position of the child. </returns> + 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); + } + + /// <summary> Aligns a child size to a parent size on all axes. </summary> + /// <param name="childSize"> The size of the child. </param> + /// <param name="parentSize"> The size of the parent. </param> + /// <param name="horizontal"> The horizontal alignment of the parent and child. </param> + /// <param name="vertical"> The vertical alignment of the parent and child. </param> + /// <param name="depth"> The depth alignment of the parent and child. </param> + /// <returns> The aligned position of the child. </returns> + 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); + } + + /// <summary> Given the bounds of a component, creates a bounds for the node respecting the + /// size types. Aspect ratio is preserved when possible. </summary> + /// <param name="componentBounds"> The bounds of the component. </param> + /// <param name="node"> The node to measure the bounds for. </param> + /// <param name="size"> The size of the node. </param> + /// <param name="min"> The minimum size of the node. </param> + /// <param name="max"> The maximum size of the node. </param> + /// <returns> The bounds of the node. </returns> + 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; + } + + /// <summary> 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. </summary> + /// <param name="componentBounds"> The bounds of the component. </param> + /// <param name="node"> The node to measure the bounds for. </param> + /// <param name="size"> The size of the node. </param> + /// <param name="min"> The minimum size of the node. </param> + /// <param name="max"> The maximum size of the node. </param> + /// <returns> The bounds of the node. </returns> + 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; + } + + /// <summary> Applies absolute value of to each vector component. </summary> + /// <param name="v"> The vector to apply absolute value to. </param> + /// <returns> The vector with absolute value applied. </returns> + 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; + } + + /// <summary> Clamps value of to each vector component between min and max. </summary> + /// <param name="v"> The vector to clamp. </param> + /// <param name="min"> The minimum value. </param> + /// <param name="max"> The maximum value. </param> + /// <returns> The clamped vector. </returns> + 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; + } + } +} \ No newline at end of file -- Gitblit v1.9.3