Skip to content

Instantly share code, notes, and snippets.

@Robadob
Last active May 11, 2023 06:43
Show Gist options
  • Save Robadob/d6d479f39bf7a1944e87c6b1780a813d to your computer and use it in GitHub Desktop.
Save Robadob/d6d479f39bf7a1944e87c6b1780a813d to your computer and use it in GitHub Desktop.
3D Geometry Functions
#ifndef __3DGeometry_h__
#define __3DGeometry_h__
#include <glm/glm.hpp>
/**
* Returns the closest point on a given infinite line to a given point
**/
glm:vec3 closestPointOnLine(const glm::vec3 &line1, const glm::vec3 &line2, const glm::vec3 &point)
{//https://forum.unity3d.com/threads/how-do-i-find-the-closest-point-on-a-line.340058/#post-2198950
glm::vec3 dir = normalize(line2-line1);
glm::vec3 v = point-line1;
float d = dot(v, dir);
return line1 + dir*d;
}
/**
* Returns the closest point on a given line segment to a given point
**/
glm::vec3 closestPointOnLineSegment(const glm::vec3 &line1, const glm::vec3 &line2, const glm::vec3 &point)
{//https://forum.unity3d.com/threads/how-do-i-find-the-closest-point-on-a-line.340058/#post-2199249
glm::vec3 line = line2 - line1;
float len = length(line);
line = normalize(line);
glm::vec3 v = point - line1;
float d = dot(v, line);
d = glm::clamp<float>(d, 0, len);
return line1 + line*d;
}
/**
* Returns the distance to the closest point on a given line segment to a given point
**/
float distPointLine(const glm::vec3 &line1, const glm::vec3 &line2, const glm::vec3 &point)
{//http://www.randygaul.net/2014/07/23/distance-point-to-line-segment/
glm::vec3 n = line2 - line1;
glm::vec3 pa = line1 - point;
float c = dot(n, pa);
if (c > 0.0f)//Nearest point goes past A
return dot(pa,pa);
glm::vec3 bp = point - line2;
if (dot(n, bp) > 0.0f)//Nearest point goes past B
return dot(bp,bp);
glm::vec3 e = pa - n * (c / dot(n, n));
return dot(e, e);
}
//I think this is known as determinant, confirms whether 3 point are wound in a clockwise order
bool isCW(const glm::vec2 &p0, const glm::vec2 &p1, const glm::vec2 &p2)
{//Taken from SO
return (p1.x*p2.y - p1.y*p2.x - p0.x*p2.y + p0.y*p2.x + p0.x*p1.y - p0.y*p1.x)< 0;
}
//Projects the 3d poly into the 2d plane of Normal(0,1,0) and ensures point is in bounds
bool insideConvexPoly3D2D(const glm::vec3 *beforeFirstPoint, const glm::vec3 *afterLastPoint, const glm::vec3 &testPoint)
{//Based on http://erich.realtimerendering.com/ptinpoly/
glm::vec2 testPoint2D = glm::vec2(testPoint.x, testPoint.z);
glm::vec2 pt1;
glm::vec2 pt2 = glm::vec2((*(afterLastPoint - 1)).x, (*(afterLastPoint - 1)).z);
float yMin = FLT_MAX;
float yMax = -FLT_MAX;
for (const glm::vec3 *i = beforeFirstPoint; i < afterLastPoint; ++i)
{
pt1 = pt2;
pt2 = glm::vec2((*i).x, (*i).z);
if (!isCW(pt1, pt2, testPoint2D))
{
return false;
}
yMin = glm::min(yMin, (*i).y);
yMax = glm::max(yMax, (*i).y);
}
if (testPoint.y >= yMin&&testPoint.y <= yMax)
return true;
return false;
}
/**
* Intersects an infinite ray with an infinite plane
* Returns false where the infinite ray is parallel to the plane
**/
bool linePlaneIntersection(const glm::vec3 &rayStart, const glm::vec3 &rayEnd,
const glm::vec3 &planeNormal, const glm::vec3 &pointOnPlane, glm::vec3& contact)
{//https://stackoverflow.com/a/35396994/1646387
// get d value
float d = dot(planeNormal, pointOnPlane);
glm::vec3 rayNormal = normalize(rayEnd - rayStart);
if (dot(planeNormal, rayNormal) == 0) {
return false; // No intersection, the line is parallel to the plane
}
// Compute the X value for the directed line ray intersecting the plane
float x = (d - dot(planeNormal, rayStart)) / dot(planeNormal, rayNormal);
// output contact point
contact = rayStart + rayNormal*x; //Make sure your ray vector is normalized
return true;
}
#endif //__3DGeometry_h__
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment