Skip to content

Instantly share code, notes, and snippets.

@unitycoder
Last active February 22, 2024 12:03
Show Gist options
  • Save unitycoder/10241239e080720376830f84511ccd3c to your computer and use it in GitHub Desktop.
Save unitycoder/10241239e080720376830f84511ccd3c to your computer and use it in GitHub Desktop.
Math Algorithms c# Calculate - 2D Line Intersection
// https://forum.unity.com/threads/line-intersection.17384/#post-4442284
bool FasterLineSegmentIntersection (Vector2 line1point1, Vector2 line1point2, Vector2 line2point1, Vector2 line2point2) {
Vector2 a = line1point2 - line1point1;
Vector2 b = line2point1 - line2point2;
Vector2 c = line1point1 - line2point1;
float alphaNumerator = b.y * c.x - b.x * c.y;
float betaNumerator = a.x * c.y - a.y * c.x;
float denominator = a.y * b.x - a.x * b.y;
if (denominator == 0) {
return false;
} else if (denominator > 0) {
if (alphaNumerator < 0 || alphaNumerator > denominator || betaNumerator < 0 || betaNumerator > denominator) {
return false;
}
} else if (alphaNumerator > 0 || alphaNumerator < denominator || betaNumerator > 0 || betaNumerator < denominator) {
return false;
}
return true;
}
// https://stackoverflow.com/questions/481144/equation-for-testing-if-a-point-is-inside-a-circle
//test if coordinate (x, y) is within a radius from coordinate (center_x, center_y)
public bool IsPointInCircle(float centerX, float centerY, float radius, float x, float y)
{
if (IsInRectangle(centerX, centerY, radius, x, y))
{
float dx = centerX - x;
float dy = centerY - y;
dx *= dx;
dy *= dy;
float distanceSquared = dx + dy;
float radiusSquared = radius * radius;
return distanceSquared <= radiusSquared;
}
return false;
}
bool IsInRectangle(float centerX, float centerY, float radius, float x, float y)
{
return x >= centerX - radius && x <= centerX + radius && y >= centerY - radius && y <= centerY + radius;
}
// https://github.com/chengkehan/Line-Triangle-Intersection/blob/master/Assets/LineTriangleIntersection.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LineTriangleIntersection : MonoBehaviour
{
public Transform tri0 = null;
public Transform tri1 = null;
public Transform tri2 = null;
public Transform line0 = null;
public Transform line1 = null;
// UE4:kDOP.h appLineCheckTriangleSOA
private void OnDrawGizmos()
{
Vector3 trip0 = tri0.position;
Vector3 trip1 = tri1.position;
Vector3 trip2 = tri2.position;
Vector3 linep0 = line0.position;
Vector3 linep1 = line1.position;
Gizmos.matrix = Matrix4x4.identity;
// Draw triangle
Gizmos.color = Color.yellow;
Gizmos.DrawLine(trip0, trip1);
Gizmos.DrawLine(trip1, trip2);
Gizmos.DrawLine(trip2, trip0);
// Draw line
Gizmos.color = Color.red;
Gizmos.DrawLine(linep0, linep1);
// Line is on the same side of triangle-plane
Vector3 triNormal = Vector3.Cross(trip1 - trip0, trip2 - trip0);
triNormal.Normalize();
float triPlaneD = Vector3.Dot(trip0, triNormal);
Vector4 triPlane = new Vector4(triNormal.x, triNormal.y, triNormal.z, triPlaneD);
float line0D = Vector3.Dot(linep0, triNormal) - triPlaneD;
float line1D = Vector3.Dot(linep1, triNormal) - triPlaneD;
if (line0D * line1D > 0)
{
return;
}
// Figure out the hit point(intersection)
float hitTime = line0D / (line0D - line1D);
Vector3 lineDir = linep1 - linep0;
Vector3 hitP = linep0 + lineDir * hitTime;
// Check if the point point is inside the triangle
Vector3[] trips = new Vector3[] { trip0, trip1, trip2 };
for(int sideIndex = 0; sideIndex < 3; ++sideIndex)
{
Vector3 edge = trips[(sideIndex + 1) % 3] - trips[sideIndex];
Vector3 sideDir = Vector3.Cross(triNormal, edge);
Vector3 hitDir = hitP - trips[sideIndex];
float side = Vector3.Dot(hitDir, sideDir);
if(side < 0)
{
// Hit point is outside the triangle.
return;
}
}
// Draw intersection
Gizmos.color = Color.green;
Gizmos.DrawCube(hitP, Vector3.one * 0.5f);
}
}
// get fraction part
float frac = 123.1234f % 1;
// average of two ints in a single instruction
(a>>1)+(b>>1)+(a&b&1)
(a&b) + ((a^b) >> 1)
// convert small integer to float https://youtu.be/BpwvXkoFcp8?t=1379
ushort x = ...;
uint y = x | 0x4b000000;
float f = as_float(y)-8388608.0f;
// generate mask from sign of float data
float x = ...;
uint mask = as_int(x) >> 31;
// compare if two lines are identical
https://twitter.com/schneckerstein/status/1191813789408256002
// SLAB : Intersection of Line Segment and Cube
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SlabTest : MonoBehaviour
{
public Transform startT = null;
public Transform endT = null;
public Vector3 boundsSize = Vector3.one * 3;
private Bounds bounds = new Bounds(Vector3.zero, Vector3.one * 3);
private void OnDrawGizmos()
{
// Resize bounds
bounds.size = boundsSize;
// Transform line segment from world space to local space
Matrix4x4 w2l = transform.worldToLocalMatrix;
Vector3 startP = w2l.MultiplyPoint(startT.position);
Vector3 endP = w2l.MultiplyPoint(endT.position);
// Draw bounds
Gizmos.color = Color.yellow;
Gizmos.matrix = transform.localToWorldMatrix;
Gizmos.DrawWireCube(bounds.center, bounds.size);
// Draw line segment
Gizmos.color = Color.cyan;
Gizmos.DrawCube(startP, Vector3.one * 0.3f);
Gizmos.DrawCube(endP, Vector3.one * 0.3f);
Gizmos.DrawLine(startP, endP);
Vector3 min = bounds.min;
Vector3 max = bounds.max;
Vector3 dir = endP - startP;
Vector3 oneOverDir = new Vector3(1.0f / dir.x, 1.0f / dir.y, 1.0f / dir.z);
// Slabs
float _minSlabX = (min.x - startP.x) * oneOverDir.x;
float _minSlabY = (min.y - startP.y) * oneOverDir.y;
float _minSlabZ = (min.z - startP.z) * oneOverDir.z;
float _maxSlabX = (max.x - startP.x) * oneOverDir.x;
float _maxSlabY = (max.y - startP.y) * oneOverDir.y;
float _maxSlabZ = (max.z - startP.z) * oneOverDir.z;
// Min/Max Slabs
float minSlabX = Mathf.Min(_minSlabX, _maxSlabX);
float minSlabY = Mathf.Min(_minSlabY, _maxSlabY);
float minSlabZ = Mathf.Min(_minSlabZ, _maxSlabZ);
float maxSlabX = Mathf.Max(_minSlabX, _maxSlabX);
float maxSlabY = Mathf.Max(_minSlabY, _maxSlabY);
float maxSlabZ = Mathf.Max(_minSlabZ, _maxSlabZ);
float minSlab = Mathf.Max(minSlabX, minSlabY, minSlabZ);
float maxSlab = Mathf.Min(maxSlabX, maxSlabY, maxSlabZ);
// Check hit
bool bHit = maxSlab >= 0.0f && maxSlab >= minSlab && minSlab <= 1.0f;
if(bHit)
{
Gizmos.color = Color.red;
int hitSurface = 0;
if (minSlab >= 0 && minSlab <= 1)
{
// Draw first hit point
++hitSurface;
Gizmos.DrawSphere(startP + new Vector3(minSlab * dir.x, minSlab * dir.y, minSlab * dir.z), 0.4f);
}
if (maxSlab >= 0 && maxSlab <= 1)
{
// Draw second hit point
++hitSurface;
Gizmos.DrawSphere(startP + new Vector3(maxSlab * dir.x, maxSlab * dir.y, maxSlab * dir.z), 0.4f);
}
if (hitSurface == 0)
{
// line segment inside bounds
Debug.LogError("inside");
}
else
{
// line segment hit surface
Debug.LogError("hit");
}
}
else
{
// line segment hit nothing
Debug.LogError("nohit");
}
}
private float CompareGE(float a, float b)
{
return a >= b ? 0xFFFFFFFF : 0;
}
private float CompareGT(float a, float b)
{
return a > b ? 0xFFFFFFFF : 0;
}
private float BitwiseAnd(float a, float b)
{
int ia = System.BitConverter.ToInt32(System.BitConverter.GetBytes(a), 0);
int ib = System.BitConverter.ToInt32(System.BitConverter.GetBytes(b), 0);
int r = ia & ib;
return System.BitConverter.ToSingle(System.BitConverter.GetBytes(r), 0);
}
}
// https://forum.unity.com/threads/all-intersection-point-in-single-collider.453956/#post-2942175
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
[ExecuteInEditMode]
public class ClippingScript : MonoBehaviour
{
    public Vector2 LineStart;
    public Vector2 LineEnd;
    public float crossScale = 0.05f;
 
    Vector2[] polygonPoints;
    PolygonCollider2D polygon;
    List<Vector2> clipPoints = new List<Vector2> ();
 
 
    // Use this for initialization
    void Start ()
    {
        // Start the body rotating.
        GetComponent<Rigidbody2D> ().angularVelocity = 45.0f;
 
        polygon = GetComponent<PolygonCollider2D> ();
    }
 
    // Update is called once per frame
    void Update ()
    {
        // Fetch the polygon points in world-space (not the most efficient way of doing things)!
        polygonPoints = polygon.points;
        for (var i = 0; i < polygonPoints.Length; ++i)
            polygonPoints[i] = transform.TransformPoint (polygonPoints[i]);
 
        // Perform clipping against the polygon.
        clipPoints.Clear ();
        var pointCount = polygonPoints.Length;
        for (int i = 0, j = pointCount - 1; i < pointCount; j = i++)
        {
            var edgeStart = polygonPoints[i];
            var edgeEnd = polygonPoints[j];
 
            Vector2 clipPoint;
            if (LineSegmentIntersection (LineStart, LineEnd, edgeStart, edgeEnd, out clipPoint))
                clipPoints.Add (clipPoint);
        }
 
        // Draw the clipping line.
        Debug.DrawLine (LineStart, LineEnd, Color.red);
 
        // Draw the clip points.
        foreach (var v in clipPoints)
        {
            var clipPoint = (Vector3)v;
            Debug.DrawLine (clipPoint + (Vector3.left * crossScale), clipPoint + (Vector3.right * crossScale), Color.white);
            Debug.DrawLine (clipPoint + (Vector3.up * crossScale), clipPoint + (Vector3.down * crossScale), Color.white);
        }
    }
 
    bool LineSegmentIntersection (Vector2 a, Vector2 b, Vector2 c, Vector2 d, out Vector2 point)
    {
        // Sign of areas correspond to which side of ab points c and d are.
        float area1 = SignedTriangleArea (a, b, d);
        float area2 = SignedTriangleArea (a, b, c);
 
        // If c and d are on different sides of ab, areas have different signs.
        if (area1 * area2 < 0.0f)
        {
            // Compute signs for a and b with respect to segment cd.
            float area3 = SignedTriangleArea (c, d, a);
            float area4 = area3 + area2 - area1;
 
            // Points a and b on different sides of cd if areas have different signs.
            if (area3 * area4 < 0.0f)
            {
                float time = area3 / (area3 - area4);
                point = a + time * (b - a);
                return true;
            }
        }
 
        // Segments are not intersecting or collinear.
        point = Vector2.zero;
        return false;
    }
 
    float SignedTriangleArea (Vector2 a, Vector2 b, Vector2 c)
    {
        return (a.x - c.x) * (b.y - c.y) - (a.y - c.y) * (b.x - c.x);
    }
 
}
@unitycoder
Copy link
Author

Approximate and vectorized versions of common mathematical functions
https://github.com/romeric/fastapprox

@unitycoder
Copy link
Author

@unitycoder
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment