/// <summary> /// Returns if a point lies inside a triangle. /// </summary> public static bool Intersect(Vector2 point, Triangle triangle) { // Adapted from C code by Eric Haines, from http://www.graphicsgems.org/. // Shoot a test ray along +X axis. The strategy is to compare vertex Y values // to the testing point's Y and quickly discard edges which are entirely to one // side of the test ray. Vector2 p1 = triangle.P1; Vector2 p2 = triangle.P2; Vector2 p3 = triangle.P3; bool yflag1 = p1.Y >= point.Y; bool yflag2 = p2.Y >= point.Y; bool yflag3 = p3.Y >= point.Y; bool inside_flag = false; if (yflag1 != yflag2 && yflag2 == ((p2.Y - point.Y) * (p1.X - p2.X) >= (p2.X - point.X) * (p1.Y - p2.Y))) inside_flag = !inside_flag; if (yflag2 != yflag3 && yflag3 == ((p3.Y - point.Y) * (p2.X - p3.X) >= (p3.X - point.X) * (p2.Y - p3.Y))) inside_flag = !inside_flag; if (yflag3 != yflag1 && yflag1 == ((p1.Y - point.Y) * (p3.X - p1.X) >= (p1.X - point.X) * (p3.Y - p1.Y))) inside_flag = !inside_flag; return inside_flag; }
/// <summary> /// Returns the squared distance from a point to a triangle. /// If the point is inside the triangle, the distance is zero. /// </summary> public static float DistanceSquared(Vector2 point, Triangle triangle) { // First, test corners for being the closest points on the triangle. // This should cover the most probable cases, assuming the triangle // is small relative to the distance 'p' is from 't' on average // over several calls to this method. // The second most probable case is that the closest point lies // on an edge of 't'. // The least probable case is that 'p' lies inside 't'. Vector2 p1 = triangle.P1; Vector2 p2 = triangle.P2; Vector2 p3 = triangle.P3; // Is 'p1' the closest point? Vector2 p1p = point - p1; Vector2 e12 = p2 - p1; Vector2 e13 = p3 - p1; float halfplane12 = Vector2.Dot(p1p, e12); float halfplane13 = Vector2.Dot(p1p, e13); if (halfplane12 <= 0 && halfplane13 <= 0) return Vector2.DistanceSquared(point, p1); // Is 'p2' the closest point? Vector2 p2p = point - p2; Vector2 e23 = p3 - p2; float halfplane21 = -Vector2.Dot(p2p, e12); float halfplane23 = Vector2.Dot(p2p, e23); if (halfplane21 <= 0 && halfplane23 <= 0) return Vector2.DistanceSquared(point, p2); // Is 'p3' the closest point? Vector2 p3p = point - p3; float halfplane31 = -Vector2.Dot(p3p, e13); float halfplane32 = -Vector2.Dot(p3p, e23); if (halfplane31 <= 0 && halfplane32 <= 0) return Vector2.DistanceSquared(point, p3); // Is the closest point on the edge between 'p2' and 'p3'? float distance23 = Vector2.Dot(triangle.Normal23, p2p); if (distance23 >= 0 && halfplane23 >= 0 && halfplane32 >= 0) return distance23 * distance23; // Is the closest point on the edge between 'p1' and 'p3'? float distance13 = Vector2.Dot(triangle.Normal13, p1p); if (distance13 >= 0 && halfplane13 >= 0 && halfplane31 >= 0) return distance13 * distance13; // Is the closest point on the edge between 'p1' and 'p2'? float distance12 = Vector2.Dot(triangle.Normal12, p1p); if (distance12 >= 0 && halfplane12 >= 0 && halfplane21 >= 0) return distance12 * distance12; // Otherwise 'p' lies inside 't'. return 0; }
public void TestDistancePointTriangle() { var q1 = new Vector2(30, 30); var q2 = new Vector2(-20, 20); var q3 = new Vector2(10, -30); var p1 = new Vector2(10, 10); var p2 = new Vector2(30, 30); var p3 = new Vector2(5, 25); var p4 = new Vector2(50, 50); var p5 = new Vector2(5 - 10, 25 + 50); var t1 = new Triangle(q1, q2, q3); var delta = 0.0001f; // amount of acceptable error // Point in triangle Assert.AreEqual(0, Geometry.Distance(p1, t1), delta); // interior Assert.AreEqual(0, Geometry.Distance(p2, t1), delta); // vertex Assert.AreEqual(0, Geometry.Distance(p3, t1), delta); // edge // Point outside triangle Assert.AreEqual(20 * Math.Sqrt(2), Geometry.Distance(p4, t1), delta); // closest to vertex Assert.AreEqual(Math.Sqrt(10 * 10 + 50 * 50), Geometry.Distance(p5, t1), delta); // closest to edge }
public void TestIntersectPointTriangle() { var p1 = new Vector2(0f, 0f); var p2 = new Vector2(19.9999f, 49.9999f); var p3 = new Vector2(10f, 0f); var p4 = new Vector2(0f, -20f); var v1 = new Vector2(0f, -10f); var v2 = new Vector2(20f, 50f); var v3 = new Vector2(-50f, 70f); var t1 = new Triangle(v1, v2, v3); Assert.IsTrue(Geometry.Intersect(p1, t1)); Assert.IsTrue(Geometry.Intersect(p2, t1)); Assert.IsFalse(Geometry.Intersect(p3, t1)); Assert.IsFalse(Geometry.Intersect(p4, t1)); }
private void CreateCollisionAreas() { #if !VERY_SMALL_TRIANGLES_ARE_COLLIDABLE var verySmallTriangles = _indexMap.GetVerySmallTriangles(); // sorted in increasing order #else var verySmallTriangles = new List<int>(); #endif TriangleCount = _indexData.Length / 3 - verySmallTriangles.Count(); _collisionAreas = new CollisionArea[_indexData.Length / 3]; var smallTriangleEnumerator = verySmallTriangles.GetEnumerator(); var smallTrianglesRemaining = smallTriangleEnumerator.MoveNext(); for (int i = 0; i + 2 < _indexData.Length; i += 3) { if (smallTrianglesRemaining && smallTriangleEnumerator.Current == i / 3) { smallTrianglesRemaining = smallTriangleEnumerator.MoveNext(); continue; } var v1 = _vertexData[_indexData[i + 0]]; var v2 = _vertexData[_indexData[i + 1]]; var v3 = _vertexData[_indexData[i + 2]]; var triangleArea = new Triangle(v1.ProjectXY(), v2.ProjectXY(), v3.ProjectXY()); _collisionAreas[i / 3] = new CollisionArea("General", triangleArea, this, CollisionAreaType.Static, CollisionMaterialType.Rough); } }