Skip to content

Commit

Permalink
Added TrigonometryBaker and Collider2dPointsGetter
Browse files Browse the repository at this point in the history
  • Loading branch information
arhcy committed Jul 3, 2018
1 parent 93c15ef commit f7ad6f2
Show file tree
Hide file tree
Showing 5 changed files with 331 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Assets/Math.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

68 changes: 68 additions & 0 deletions Assets/Math/TrigonometryBaker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) 2018 Archy Piragkov. All Rights Reserved. Licensed under the MIT license

using System;
using System.Collections.Generic;

namespace artics.Math
{
/// <summary>
/// Simple solution to cache Math.Sin and Math.Cos values with listed proximity. </br>
/// You cas use different sets of proximities.
/// </summary>
public class TrigonometryBaker
{
/// <summary>
/// stores sin and cos values grouped by proximity
/// </summary>
public Dictionary<uint, double[][]> BakingArray;

public TrigonometryBaker()
{
BakingArray = new Dictionary<uint, double[][]>();
}

/// <summary>
/// inits a set of sin and cos values with listed proximity and stores it in <see cref="BakingArray"/> dictionary.
/// </summary>
/// <param name="proximity">Proximity calculates by formula: (Math.PI * 2) / proximity</param>
/// <returns></returns>
public double[][] InitProximity(uint proximity)
{
double[][] values = new double[2][];
values[0] = new double[proximity];
values[1] = new double[proximity];

double angle = 0;
double angleStep = (System.Math.PI * 2) / proximity;

for (int i = 0; i < proximity; i++)
{
values[0][i] = System.Math.Sin(angle);
values[1][i] = System.Math.Cos(angle);

angle += angleStep;
}

BakingArray.Add(proximity, values);

return values;
}

/// <summary>
/// Gets calculated proximity or creates new set.
/// </summary>
/// <param name="proximity">Proximity calculates by formula: (Math.PI * 2) / proximity</param>
/// <returns></returns>
public double[][] GetProximityBake(uint proximity)
{
double[][] values = null;

BakingArray.TryGetValue(proximity, out values);

if (values == null)
values = InitProximity(proximity);

return values;
}
}
}
11 changes: 11 additions & 0 deletions Assets/Math/TrigonometryBaker.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

233 changes: 233 additions & 0 deletions Assets/UnityPhisicsVisualizers/Collider2dPointsGetter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
// Copyright (c) 2018 Archy Piragkov. All Rights Reserved. Licensed under the MIT license

using UnityEngine;
using artics.Math;

namespace artics.UnityPhisicsVisualizers
{
/// <summary>
/// set of static funtions solution to get raw poins of Unity physics 2d colliders.
/// </summary>
public class Collider2dPointsGetter
{
/// <summary>
/// number of iterations to get points of circle
/// </summary>
public static uint CircleProximity = 20;

/// <summary>
/// bakes sin and cos values for performance
/// </summary>
public static TrigonometryBaker TrigonometryManager = new TrigonometryBaker();


#region SimpleShapes
/// <summary>
/// Get coordinates of Box2DCollider
/// </summary>
/// <param name="collider"></param>
/// <param name="points"></param>
public static void GetBoxCoordinates(BoxCollider2D collider, ref Vector2[] points)
{
PointsArraySizevalidation(ref points, 4);

Vector2 offset = collider.offset;
Vector2 size = collider.size * 0.5f;

points[0].Set(offset.x - size.x, offset.y - size.y);
points[1].Set(offset.x - size.x, offset.y + size.y);
points[2].Set(offset.x + size.x, offset.y + size.y);
points[3].Set(offset.x + size.x, offset.y - size.y);
}

/// <summary>
/// get coordinates of <seealso cref="PolygonCollider2D"/>
/// </summary>
/// <param name="collider"></param>
/// <param name="points"></param>
public static void GetPolygonCoordinates(PolygonCollider2D collider, ref Vector2[] points)
{
CalculatePolygonCoodinates(collider.points, collider.offset, ref points);
}

/// <summary>
/// get coordinates of <seealso cref="EdgeCollider2D"/>
/// </summary>
/// <param name="collider">collider</param>
/// <param name="points">input points</param>
public static void GetEdgeCoordinates(EdgeCollider2D collider, ref Vector2[] points)
{
CalculatePolygonCoodinates(collider.points, collider.offset, ref points);
}

protected static void PointsArraySizevalidation(ref Vector2[] points, int size)
{
if (points == null || points.Length != size)
points = new Vector2[size];
}

protected static void CalculatePolygonCoodinates(Vector2[] colliderPoints, Vector2 offset, ref Vector2[] points)
{
PointsArraySizevalidation(ref points, colliderPoints.Length);

for (int i = 0; i < colliderPoints.Length; i++)
points[i].Set(colliderPoints[i].x + offset.x, colliderPoints[i].y + offset.y);
}

#endregion

#region Circle

protected static void ProximityCheck(ref uint proximity)
{
if (proximity == 0)
proximity = CircleProximity;
}


protected static void FillCirclePoint(Vector2[] points, Vector2 center, double radius, double[][] values, int IdOffset, int ValuesOffset, int times)
{
for (int i = 0; i < times; i++)
points[IdOffset + i].Set(center.x + (float)(radius * values[1][ValuesOffset + i]), center.y + (float)(radius * values[0][ValuesOffset + i]));
}

/// <summary>
/// get coordinates of <seealso cref="CircleCollider2D"/>. You can use
/// </summary>
/// <param name="collider">collider</param>
/// <param name="points">points array</param>
/// <param name="CustomProximity">if set to 0 it uses <see cref="CircleProximity"/>. Otherwise it uses listed value to calculate circular coordinates</param>
public static void GetCircleCoordinates(CircleCollider2D collider, ref Vector2[] points, uint CustomProximity = 0)
{
ProximityCheck(ref CustomProximity);
PointsArraySizevalidation(ref points, (int)CustomProximity);

double[][] values = TrigonometryManager.GetProximityBake(CustomProximity);

FillCirclePoint(points, collider.offset, collider.radius, values, 0, 0, (int)CustomProximity);
}

/// <summary>
/// get coordinates by listing center and radius
/// </summary>
/// <param name="center"></param>
/// <param name="radius"></param>
/// <param name="points"></param>
/// <param name="CustomProximity">if set to 0 it uses <see cref="CircleProximity"/>. Otherwise it uses listed value to calculate circular coordinates</param>
public static void GetCircleCoordinates(Vector2 center, float radius, ref Vector2[] points, uint CustomProximity = 0)
{
ProximityCheck(ref CustomProximity);
PointsArraySizevalidation(ref points, (int)CustomProximity);

double[][] values = TrigonometryManager.GetProximityBake(CustomProximity);

FillCirclePoint(points, center, radius, values, 0, 0, (int)CustomProximity);
}
#endregion

#region Capsule
/// <summary>
/// get coordinates of CapsuleCollider2D
/// </summary>
/// <param name="collider"></param>
/// <param name="points"></param>
/// <param name="CustomProximity">if set to 0 it uses <see cref="CircleProximity"/>. Otherwise it uses listed value to calculate circular coordinates</param>
public static void GetCapsuleCoordinates(CapsuleCollider2D collider, ref Vector2[] points, uint CustomProximity = 0)
{
ProximityCheck(ref CustomProximity);
PointsArraySizevalidation(ref points, (int)CustomProximity + 4);

uint rest = CustomProximity % 4;

if (rest > 0)
CustomProximity += rest;

Vector2 StartPosition = new Vector2();
Vector2 EndPosition = new Vector2();
float radius = 0;

if (collider.direction == CapsuleDirection2D.Vertical)
{
CalculateCapsuleBoundsVertical(collider, ref StartPosition, ref EndPosition, ref radius);
GetCapsulePointsVertical(StartPosition, EndPosition, radius, CustomProximity, points);
}
else
{
CalculateCapsuleBoundsHorizontal(collider, ref StartPosition, ref EndPosition, ref radius);
GetCapsulePointsHorizontal(StartPosition, EndPosition, radius, CustomProximity, points);
}
}

protected static void CalculateCapsuleBoundsVertical(CapsuleCollider2D collider, ref Vector2 StartPosition, ref Vector2 EndPosition, ref float Radius)
{
Vector2 size = collider.size;
Radius = Mathf.Abs(size.x * 0.5f * collider.transform.localScale.x);

StartPosition.x = 0;
EndPosition.x = 0;

StartPosition.y = Mathf.Max(0, size.y * 0.5f - Radius);
EndPosition.y = Mathf.Min(0, StartPosition.y * -1);

StartPosition += collider.offset;
EndPosition += collider.offset;
}

protected static void CalculateCapsuleBoundsHorizontal(CapsuleCollider2D collider, ref Vector2 StartPosition, ref Vector2 EndPosition, ref float Radius)
{
Vector2 size = collider.size;
Radius = Mathf.Abs(size.y * 0.5f * collider.transform.localScale.x);

StartPosition.y = 0;
EndPosition.y = 0;

StartPosition.x = Mathf.Max(0, size.x * 0.5f - Radius);
EndPosition.x = Mathf.Min(0, StartPosition.x * -1);

StartPosition += collider.offset;
EndPosition += collider.offset;
}

protected static void GetCapsulePointsVertical(Vector2 StartPosition, Vector2 EndPosition, float radius, uint CustomProximity, Vector2[] points)
{
double[][] values = TrigonometryManager.GetProximityBake(CustomProximity);
int half = Mathf.RoundToInt(CustomProximity / 2);

points[0].Set(StartPosition.x + radius, EndPosition.y);
points[1].Set(StartPosition.x + radius, StartPosition.y);

FillCirclePoint(points, StartPosition, radius, values, 2, 0, half);

points[half + 2].Set(StartPosition.x - radius, StartPosition.y);
points[half + 3].Set(StartPosition.x - radius, EndPosition.y);

FillCirclePoint(points, EndPosition, radius, values, half + 4, half, half);
}

protected static void GetCapsulePointsHorizontal(Vector2 StartPosition, Vector2 EndPosition, float radius, uint CustomProximity, Vector2[] points)
{
double[][] values = TrigonometryManager.GetProximityBake(CustomProximity);
int quart = Mathf.RoundToInt(CustomProximity / 4);

points[0].Set(EndPosition.x, EndPosition.y - radius);
points[1].Set(StartPosition.x, StartPosition.y - radius);

int idOffset = 2;

FillCirclePoint(points, StartPosition, radius, values, idOffset, quart * 3, quart);
idOffset += quart;
FillCirclePoint(points, StartPosition, radius, values, idOffset, 0, quart);
idOffset += quart;

points[idOffset].Set(StartPosition.x, StartPosition.y + radius);
points[idOffset + 1].Set(EndPosition.x, EndPosition.y + radius);

idOffset += 2;

FillCirclePoint(points, EndPosition, radius, values, idOffset, quart * 1, quart);
idOffset += quart;
FillCirclePoint(points, EndPosition, radius, values, idOffset, quart * 2, quart);
}
#endregion
}
}
11 changes: 11 additions & 0 deletions Assets/UnityPhisicsVisualizers/Collider2dPointsGetter.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit f7ad6f2

Please sign in to comment.