Hello everyone.
I want to constrain a circle I created in my project using a rectangle. I watched a few videos and they generally use the same method, but this method does not give the result I want.
I have prepared a visual demo for you below.
I want to constrain the angle I give using the blue circle with the red rectangle. You can see the angle as the green line. The little white circle is the value I got.
This method works correctly when the angle is 0,90,180,270 etc. However, as you can see below, it does not give the desired result for other values.
The value I want should be exactly on the green line.
Here’s my code for this demo:
using UnityEngine;
public class CircleLimiter : MonoBehaviour
{
public Vector2 rectangleSize;
public float circleRadius;
public float angle;
void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawWireCube(Vector3.zero, rectangleSize);
Gizmos.color = Color.blue;
Gizmos.DrawWireSphere(Vector3.zero, circleRadius);
Gizmos.color = Color.green;
Vector3 positionByAngle = new Vector3(Mathf.Cos(angle * Mathf.Deg2Rad) * circleRadius, Mathf.Sin(angle * Mathf.Deg2Rad) * circleRadius);
Gizmos.DrawLine(Vector3.zero, positionByAngle);
Gizmos.color = Color.white;
Gizmos.DrawWireSphere(Limit(positionByAngle, rectangleSize), 0.2f);
}
Vector2 Limit(Vector2 position, Vector2 limit)
{
limit /= limit;
return new Vector2(
Mathf.Clamp(position.x, -limit.x, limit.x),
Mathf.Clamp(position.y, -limit.y, limit.y)
);
}
}
I would be very grateful if you could answer my question or direct me to related topics.
Thanks in advance.
I managed to solve it somehow but I would like to know if there is a better way. After dividing the area into triangles, I got the result I wanted using the right triangle formulas.
Vector3 Limiter(float ang, Vector2 limit)
{
Vector3 result = Vector3.zero;
float x = 0;
float y = 0;
float _ang = ang % 360;
ang = _ang;
if (_ang < 0)
ang = 360 + _ang;
float a = limit.x;
float b = limit.y;
float c = Mathf.Sqrt(Mathf.Pow(limit.x, 2) + Mathf.Pow(limit.y, 2));
float aAngle = Mathf.Acos(a / c) * Mathf.Rad2Deg;
float bAngle = 90 - aAngle;
float zoneAngle = 0;
if (ang >= 0 && ang < aAngle)
{
zoneAngle = ang;
x = a;
y = a * Mathf.Tan(zoneAngle * Mathf.Deg2Rad);
}
else if (ang >= aAngle && ang < aAngle + bAngle * 2)
{
zoneAngle = zoneAngleOverride ? zoneAngleOverrideValue : bAngle - (ang - aAngle);
x = b * Mathf.Tan(zoneAngle * Mathf.Deg2Rad);
y = b;
}
else if (ang >= aAngle + bAngle * 2 && ang < aAngle * 3 + bAngle * 2)
{
zoneAngle = zoneAngleOverride ? zoneAngleOverrideValue : aAngle - (ang - bAngle * 2 - aAngle);
x = -a;
y = a * Mathf.Tan(zoneAngle * Mathf.Deg2Rad);
}
else if (ang >= aAngle * 3 + bAngle * 2 && ang < aAngle * 3 + bAngle * 4)
{
zoneAngle = zoneAngleOverride ? zoneAngleOverrideValue : -bAngle + (ang - bAngle * 2 - aAngle * 3);
x = b * Mathf.Tan(zoneAngle * Mathf.Deg2Rad);
y = -b;
}
else
{
zoneAngle = ang;
x = a;
y = a * Mathf.Tan(zoneAngle * Mathf.Deg2Rad);
}
result = new Vector3(x, y, 0);
return result;
}
Cool solution! What are you using this for ?
Here is another solution
public static Vector2 ClampPointInRect(float width, float height, Vector2 point)
{
Vector2 vec = point;
float pi = Mathf.PI;
float angle = Mathf.Atan2(point.y, point.x);
if (angle < 0)
angle = pi * 2 + angle;
float tan = Mathf.Tan(angle);
float cot = 1 / Mathf.Tan(angle);
if (angle < pi * .25f)
vec = new(width, tan * height);
else if (angle < pi * .5f)
vec = new(cot * width, height);
else if (angle < pi * .75f)
vec = new(cot * width, height);
else if (angle < pi)
vec = new(-width, -tan * height);
else if (angle < pi * 1.25f)
vec = new(-width, -tan * height);
else if (angle < pi * 1.5f)
vec = new(-cot * width, -height);
else if (angle < pi * 1.75f)
vec = new(-cot * width, -height);
else if (angle < pi * 2.0f)
vec = new(width, tan * height);
return vec;
}