mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
* Physics worlds * Paul's a good boy * Build working * Ingame and not lagging to hell * Why didn't you commit ahhhhh * Hard collisions working * Solver parity * Decent broadphase work done * BroadPhase outline done * BroadPhase working * waiting for pvs * Fix static PVS AABB * Stop static bodies from awakening * Optimise a bunch of stuff * Even more broadphase stuff * I'm fucking stupid * Optimise fixture updates * Collision solver start * Building * A is for Argumentative * Fix contact caching island flags * Circle shapes actually workeded * Damping * DS2 consumables only * Slightly more stable * Even slightlier more stablier * VV your heart out * Initial joint support * 90% of joints I just wanted to push as I'd scream if I lost progress * JOINT PURGATORY * Joints barely functional lmao * Okay these joints slightly more functional * Remove station FrictionJoint * Also that * Some Box2D ports * Cleanup mass * Edge shape * Active contacts * Fix active contacts * Optimise active contacts even more * Boxes be stacking * I would die for smug oh my fucking god * In which everything is fixed * Distance joints working LETS GO * Remove frequency on distancejoint * Fix some stuff and break joints * Crashing fixed mehbeh * ICollideSpecial and more resilience * auto-clear * showbb vera * Slap that TODO in there * Fix restartround crash * Random fixes * Fix fixture networking * Add intersection method for broadphase * Fix contacts * Licenses done * Optimisations * Fix wall clips * Config caching for island * allocations optimisations * Optimise casts * Optimise events queue for physics * Contact manager optimisations * Optimise controllers * Sloth joint or something idk * Controller graph * Remove content cvar * Random cleanup * Finally remove VirtualController * Manifold structs again * Optimise this absolute retardation * Optimise * fix license * Cleanup physics interface * AHHHHHHHHHHHHH * Fix collisions again * snivybus * Fix potential nasty manifold bug * Tests go snivy Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
214 lines
7.0 KiB
C#
214 lines
7.0 KiB
C#
using System;
|
|
using Robust.Shared.Maths;
|
|
|
|
namespace Robust.Shared.Physics.Collision
|
|
{
|
|
/// <summary>
|
|
/// A rectangle that can be rotated.
|
|
/// </summary>
|
|
[Serializable]
|
|
internal readonly struct OrientedRectangle : IEquatable<OrientedRectangle>
|
|
{
|
|
/// <summary>
|
|
/// Center point of the rectangle in world space.
|
|
/// </summary>
|
|
public readonly Vector2 Center;
|
|
|
|
/// <summary>
|
|
/// Half of the total width and height of the rectangle.
|
|
/// </summary>
|
|
public readonly Vector2 HalfExtents;
|
|
|
|
/// <summary>
|
|
/// World rotation of the rectangle in radians.
|
|
/// </summary>
|
|
public readonly float Rotation;
|
|
|
|
/// <summary>
|
|
/// A 1x1 unit box with the origin centered and identity rotation.
|
|
/// </summary>
|
|
public static readonly OrientedRectangle UnitCentered = new(Vector2.Zero, Vector2.One, 0);
|
|
|
|
public OrientedRectangle(Box2 worldBox)
|
|
{
|
|
Center = worldBox.Center;
|
|
|
|
var hWidth = MathF.Abs(worldBox.Right - worldBox.Left) * 0.5f;
|
|
var hHeight = MathF.Abs(worldBox.Bottom - worldBox.Top) * 0.5f;
|
|
|
|
HalfExtents = new Vector2(hWidth, hHeight);
|
|
Rotation = 0;
|
|
}
|
|
|
|
public OrientedRectangle(Vector2 halfExtents)
|
|
{
|
|
Center = default;
|
|
HalfExtents = halfExtents;
|
|
Rotation = default;
|
|
}
|
|
|
|
public OrientedRectangle(Vector2 center, Vector2 halfExtents)
|
|
{
|
|
Center = center;
|
|
HalfExtents = halfExtents;
|
|
Rotation = default;
|
|
}
|
|
|
|
public OrientedRectangle(Vector2 center, Vector2 halfExtents, float rotation)
|
|
{
|
|
Center = center;
|
|
HalfExtents = halfExtents;
|
|
Rotation = rotation;
|
|
}
|
|
|
|
public OrientedRectangle(in Vector2 center, in Box2 localBox, float rotation)
|
|
{
|
|
Center = center;
|
|
HalfExtents = new Vector2(localBox.Width / 2, localBox.Height / 2);
|
|
Rotation = rotation;
|
|
}
|
|
|
|
/// <summary>
|
|
/// calculates the smallest AABB that will encompass this rectangle. The AABB is in local space.
|
|
/// </summary>
|
|
public Box2 CalcBoundingBox()
|
|
{
|
|
var Fi = Rotation;
|
|
|
|
var CX = Center.X;
|
|
var CY = Center.Y;
|
|
|
|
var WX = HalfExtents.X;
|
|
var WY = HalfExtents.Y;
|
|
|
|
var SF = MathF.Sin(Fi);
|
|
var CF = MathF.Cos(Fi);
|
|
|
|
var NH = MathF.Abs(WX * SF) + MathF.Abs(WY * CF); //boundrect half-height
|
|
var NW = MathF.Abs(WX * CF) + MathF.Abs(WY * SF); //boundrect half-width
|
|
|
|
return new Box2((float)(CX - NW), (float)(CY - NH), (float)(CX + NW), (float)(CY + NH)); //draw bound rectangle
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests if a point is contained inside this rectangle.
|
|
/// </summary>
|
|
/// <param name="point">Point to test.</param>
|
|
/// <returns>True if the point is contained inside this rectangle.</returns>
|
|
public bool Contains(Vector2 point)
|
|
{
|
|
// rotate around rectangle center by -rectAngle
|
|
var s = MathF.Sin(-Rotation);
|
|
var c = MathF.Cos(-Rotation);
|
|
|
|
// set origin to rect center
|
|
var newPoint = point - Center;
|
|
|
|
// rotate
|
|
newPoint = new Vector2(newPoint.X * c - newPoint.Y * s, newPoint.X * s + newPoint.Y * c);
|
|
|
|
// put origin back
|
|
newPoint += Center;
|
|
|
|
// check if our transformed point is in the rectangle, which is no longer
|
|
// rotated relative to the point
|
|
|
|
var xMin = -HalfExtents.X;
|
|
var xMax = HalfExtents.X;
|
|
var yMin = -HalfExtents.Y;
|
|
var yMax = HalfExtents.Y;
|
|
|
|
return newPoint.X >= xMin && newPoint.X <= xMax && newPoint.Y >= yMin && newPoint.Y <= yMax;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the closest point inside the rectangle to the given point in world space.
|
|
/// </summary>
|
|
public Vector2 ClosestPointWorld(Vector2 worldPoint)
|
|
{
|
|
// inverse-transform the sphere's center into the box's local space.
|
|
var localPoint = InverseTransformPoint(worldPoint);
|
|
|
|
var xMin = -HalfExtents.X;
|
|
var xMax = HalfExtents.X;
|
|
var yMin = -HalfExtents.Y;
|
|
var yMax = HalfExtents.Y;
|
|
|
|
// clamp the point to the border of the box
|
|
var cx = MathHelper.Clamp(localPoint.X, xMin, xMax);
|
|
var cy = MathHelper.Clamp(localPoint.Y, yMin, yMax);
|
|
|
|
return TransformPoint(new Vector2(cx, cy));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Transforms a point from the rectangle's local space to world space.
|
|
/// </summary>
|
|
public Vector2 TransformPoint(Vector2 localPoint)
|
|
{
|
|
var theta = Rotation;
|
|
var (x, y) = localPoint;
|
|
var dx = MathF.Cos(theta) * x - MathF.Sin(theta) * y;
|
|
var dy = MathF.Sin(theta) * x + MathF.Cos(theta) * y;
|
|
return new Vector2(dx, dy) + Center;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Transforms a point from world space to the rectangle's local space.
|
|
/// </summary>
|
|
public Vector2 InverseTransformPoint(Vector2 worldPoint)
|
|
{
|
|
var theta = -Rotation;
|
|
var (x, y) = worldPoint + -Center;
|
|
var dx = MathF.Cos(theta) * x - MathF.Sin(theta) * y;
|
|
var dy = MathF.Sin(theta) * x + MathF.Cos(theta) * y;
|
|
return new Vector2(dx, dy);
|
|
}
|
|
|
|
#region Equality Members
|
|
|
|
/// <inheritdoc />
|
|
public bool Equals(OrientedRectangle other)
|
|
{
|
|
return Center.Equals(other.Center) && HalfExtents.Equals(other.HalfExtents) && Rotation.Equals(other.Rotation);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override bool Equals(object? obj)
|
|
{
|
|
return obj is OrientedRectangle other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override int GetHashCode()
|
|
{
|
|
return HashCode.Combine(Center, HalfExtents, Rotation);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check for equality by value between two <see cref="OrientedRectangle"/>.
|
|
/// </summary>
|
|
public static bool operator ==(OrientedRectangle left, OrientedRectangle right) {
|
|
return left.Equals(right);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check for inequality by value between two <see cref="OrientedRectangle"/>.
|
|
/// </summary>
|
|
public static bool operator !=(OrientedRectangle left, OrientedRectangle right) {
|
|
return !left.Equals(right);
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Returns the string representation of this object.
|
|
/// </summary>
|
|
public override string ToString()
|
|
{
|
|
var box = new Box2(-HalfExtents.X, -HalfExtents.Y, HalfExtents.X, HalfExtents.Y).Translated(Center);
|
|
return $"{box}, {Rotation}";
|
|
}
|
|
}
|
|
}
|