Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Twinki14 committed Jan 15, 2024
2 parents 0fcdffc + f9613a2 commit a3786b3
Show file tree
Hide file tree
Showing 12 changed files with 156 additions and 67 deletions.
2 changes: 1 addition & 1 deletion src/PolyZone.Tests/Shapes/CircleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class CircleTests
[Fact]
public void CircleA()
{
var circle = new Circle(-7.7f, -3.55f, 5f);
var circle = new Circle(new Vector2 { X = -7.7f, Y = -3.55f }, 5f);

var insidePoints = new[]
{
Expand Down
9 changes: 9 additions & 0 deletions src/PolyZone/Extensions/Vector3Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using CitizenFX.Core;
using PolyZone.Shapes.Interfaces;

namespace PolyZone.Extensions;

public static class Vector3Extensions
{
public static bool IsInside(this Vector3 vector2, in ISpatial3dShape shape) => shape.Contains(vector2);
}
42 changes: 0 additions & 42 deletions src/PolyZone/Shapes/Box.cs

This file was deleted.

27 changes: 18 additions & 9 deletions src/PolyZone/Shapes/Circle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,33 @@

namespace PolyZone.Shapes;

public class Circle(float x, float y, float radius) : ICircle
/// <summary>
/// A 2d circle, constructed from a center point and radius
/// </summary>
/// <param name="center">Center of the circle</param>
/// <param name="radius">Radius of the circle</param>
public class Circle(in Vector2 center, float radius) : ICircle
{
public Circle(in Vector2 center, float radius) : this(center.X, center.Y, radius)
{

}

public Vector2 Center { get; } = center;
public float Radius { get; } = radius;

/// <inheritdoc cref="ISpatial2dShape.Contains"/>
public bool Contains(in Vector2 point)
{
// Calculate the distance from the center of the circle to the given point
var distance = (float) Math.Sqrt(Math.Pow(point.X - x, 2) + Math.Pow(point.Y - y, 2));
var distance = (float) Math.Sqrt(Math.Pow(point.X - Center.X, 2) + Math.Pow(point.Y - Center.Y, 2));

// Check if the distance is less than or equal to the radius
return distance <= radius;
return distance <= Radius;
}

/// <inheritdoc cref="ISpatial2dShape.DistanceFrom"/>
public float DistanceFrom(in Vector2 point)
{
throw new NotImplementedException();
// Calculate the distance from the center of the circle to the given point
var distance = (float)Math.Sqrt(Math.Pow(point.X - Center.X, 2) + Math.Pow(point.Y - Center.Y, 2));

// Subtract the radius to get the distance from the circumference
return Math.Max(distance - Radius, 0);
}
}
46 changes: 46 additions & 0 deletions src/PolyZone/Shapes/Cuboid.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using CitizenFX.Core;
using PolyZone.Shapes.Interfaces;

namespace PolyZone.Shapes;

/// <summary>
/// A 3d cuboid shape, constructed from an upper left 3d point
/// </summary>
/// <param name="upperLeft">Upper left point</param>
/// <param name="length">Length of the cuboid</param>
/// <param name="width">Width of the cuboid</param>
/// <param name="height">Height of the cuboid</param>
public class Cuboid(in Vector3 upperLeft, float length, float width, float height) : ICuboid
{
public Vector3 UpperLeft { get; } = upperLeft;
public float Length { get; } = length;
public float Width { get; } = width;
public float Height { get; } = height;

/// <summary>
/// Calculated corners of the <see cref="Cuboid"/>, starts with the Upper Left
/// </summary>
public Vector3[] Corners { get; } =
[
// Upper face
new Vector3 { X = upperLeft.X, Y = upperLeft.Y, Z = upperLeft.Z }, // Upper Left (Front)
new Vector3 { X = upperLeft.X + length, Y = upperLeft.Y, Z = upperLeft.Z }, // Upper Right (Front)
new Vector3 { X = upperLeft.X + length, Y = upperLeft.Y + width, Z = upperLeft.Z }, // Lower Right (Front)
new Vector3 { X = upperLeft.X, Y = upperLeft.Y + width, Z = upperLeft.Z }, // Lower Left (Front)

// Lower face
new Vector3 { X = upperLeft.X, Y = upperLeft.Y, Z = upperLeft.Z + height }, // Upper Left (Back)
new Vector3 { X = upperLeft.X + length, Y = upperLeft.Y, Z = upperLeft.Z + height }, // Upper Right (Back)
new Vector3 { X = upperLeft.X + length, Y = upperLeft.Y + width, Z = upperLeft.Z + height }, // Lower Right (Back)
new Vector3 { X = upperLeft.X, Y = upperLeft.Y + width, Z = upperLeft.Z + height } // Lower Left (Back)
];

/// <inheritdoc cref="ISpatial3dShape.Contains"/>
public bool Contains(in Vector3 point)
{
// Check if the point is within the bounds defined by the corners of the cuboid
return point.X >= UpperLeft.X && point.X <= UpperLeft.X + Length &&
point.Y >= UpperLeft.Y && point.Y <= UpperLeft.Y + Width &&
point.Z >= UpperLeft.Z && point.Z <= UpperLeft.Z + Height;
}
}
6 changes: 0 additions & 6 deletions src/PolyZone/Shapes/Interfaces/IBox.cs

This file was deleted.

6 changes: 6 additions & 0 deletions src/PolyZone/Shapes/Interfaces/ICuboid.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace PolyZone.Shapes.Interfaces;

/// <summary>
/// A 3d cuboid shape
/// </summary>
public interface ICuboid : ISpatial3dShape;
6 changes: 6 additions & 0 deletions src/PolyZone/Shapes/Interfaces/IRectangle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace PolyZone.Shapes.Interfaces;

/// <summary>
/// A 2d rectangle / box
/// </summary>
public interface IRectangle : ISpatial2dShape;
6 changes: 6 additions & 0 deletions src/PolyZone/Shapes/Interfaces/ISphere.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace PolyZone.Shapes.Interfaces;

/// <summary>
/// A 3d spherical shape
/// </summary>
public interface ISphere : ISpatial3dShape;
15 changes: 6 additions & 9 deletions src/PolyZone/Shapes/Polygon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@ namespace PolyZone.Shapes;
/// <param name="points">A list of <see cref="Vector2"/> in sequential order, to make-up a polygonal shape</param>
public class Polygon(IReadOnlyList<Vector2> points) : IPolygon
{
private Vector2? _min;
private Vector2? _max;
private Rectangle? _boundingBox = null;

public IReadOnlyList<Vector2> Points { get; } = points;

/// <inheritdoc cref="ISpatial2dShape.Contains"/>
public bool Contains(in Vector2 point)
{
if (_min is null || _max is null)
if (_boundingBox is null)
{
float minX = float.MaxValue, minY = float.MaxValue;
float maxX = float.MinValue, maxY = float.MinValue;
Expand All @@ -30,22 +29,20 @@ public bool Contains(in Vector2 point)
maxY = Math.Max(maxY, vertex.Y);
}

_min = new Vector2 { X = minX, Y = minY };
_max = new Vector2 { X = maxX, Y = maxY };
_boundingBox = new Rectangle(new Vector2 { X = minX, Y = minY }, new Vector2 { X = maxX, Y = maxY });
}

return Contains(point, Points, _min.Value, _max.Value);
return Contains(point, Points, _boundingBox);
}

/// <inheritdoc cref="ISpatial2dShape.DistanceFrom"/>
public float DistanceFrom(in Vector2 point) => DistanceFrom(point, Points);

// https://web.archive.org/web/20210225074947/http://geomalgorithms.com/a03-_inclusion.html
private static bool Contains(in Vector2 point, IReadOnlyList<Vector2> polygon, in Vector2 boundingBoxMin, in Vector2 boundingBoxMax)
private static bool Contains(in Vector2 point, IReadOnlyList<Vector2> polygon, in Rectangle boundingBox)
{
if (point.X < boundingBoxMin.X || point.X > boundingBoxMax.X || point.Y < boundingBoxMin.Y || point.Y > boundingBoxMax.Y)
if (!boundingBox.Contains(point))
{
// Point is outside the bounding box, so it's definitely outside the polygon
return false;
}

Expand Down
32 changes: 32 additions & 0 deletions src/PolyZone/Shapes/Rectangle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using CitizenFX.Core;
using PolyZone.Shapes.Interfaces;

namespace PolyZone.Shapes;

/// <summary>
/// A 2d rectangular shape, constructed from an upperLeft and bottomRight point
/// </summary>
/// <param name="upperLeft">Upper left point of the rectangle</param>
/// <param name="bottomRight">Bottom right point of the rectangle</param>
public class Rectangle(in Vector2 upperLeft, in Vector2 bottomRight) : IRectangle
{
public Vector2 UpperLeft { get; } = upperLeft;
public Vector2 BottomRight { get; } = bottomRight;

/// <inheritdoc cref="ISpatial2dShape.Contains"/>
public bool Contains(in Vector2 point)
{
return point.X >= UpperLeft.X && point.X <= BottomRight.X &&
point.Y >= UpperLeft.Y && point.Y <= BottomRight.Y;
}

/// <inheritdoc cref="ISpatial2dShape.DistanceFrom"/>
public float DistanceFrom(in Vector2 point)
{
// Calculate the distance using Euclidean distance formula
var dx = Math.Max(Math.Max(UpperLeft.X - point.X, 0), point.X - BottomRight.X);
var dy = Math.Max(Math.Max(UpperLeft.Y - point.Y, 0), point.Y - BottomRight.Y);

return (float) Math.Sqrt(dx * dx + dy * dy);
}
}
26 changes: 26 additions & 0 deletions src/PolyZone/Shapes/Sphere.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using CitizenFX.Core;
using PolyZone.Shapes.Interfaces;

namespace PolyZone.Shapes;

/// <summary>
/// A 3d sphere constructed from a center 3d point and a radius
/// </summary>
/// <param name="center">Center of the sphere</param>
/// <param name="radius">Radius of the sphere</param>
public class Sphere(in Vector3 center, float radius) : ISphere
{
public Vector3 Center { get; } = center;
public float Radius { get; } = radius;

/// <inheritdoc cref="ISpatial3dShape.Contains"/>
public bool Contains(in Vector3 point)
{
// Calculate the distance from the center of the sphere to the given point
var distance = (float) Math.Sqrt(Math.Pow(point.X - Center.X, 2) + Math.Pow(point.Y - Center.Y, 2) + Math.Pow(point.Z - Center.Z, 2));

// Check if the distance is less than or equal to the radius
return distance <= Radius;

}
}

0 comments on commit a3786b3

Please sign in to comment.