A game framework written with osu! in mind.
at master 75 lines 2.7 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using osuTK; 5using System; 6using System.Runtime.CompilerServices; 7using System.Runtime.InteropServices; 8 9namespace osu.Framework.Graphics.Primitives 10{ 11 [StructLayout(LayoutKind.Sequential)] 12 public readonly struct Triangle : IConvexPolygon, IEquatable<Triangle> 13 { 14 // Note: Do not change the order of vertices. They are ordered in screen-space counter-clockwise fashion. 15 // See: IPolygon.GetVertices() 16 public readonly Vector2 P0; 17 public readonly Vector2 P1; 18 public readonly Vector2 P2; 19 20 public Triangle(Vector2 p0, Vector2 p1, Vector2 p2) 21 { 22 P0 = p0; 23 P1 = p1; 24 P2 = p2; 25 } 26 27 public ReadOnlySpan<Vector2> GetAxisVertices() => GetVertices(); 28 29 public ReadOnlySpan<Vector2> GetVertices() => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in P0), 3); 30 31 public bool Equals(Triangle other) => 32 P0 == other.P0 && 33 P1 == other.P1 && 34 P2 == other.P2; 35 36 /// <summary> 37 /// Checks whether a point lies within the triangle. 38 /// </summary> 39 /// <param name="pos">The point to check.</param> 40 /// <returns>Outcome of the check.</returns> 41 public bool Contains(Vector2 pos) 42 { 43 // This code parametrizes pos as a linear combination of 2 edges s*(p1-p0) + t*(p2->p0). 44 // pos is contained if s>0, t>0, s+t<1 45 float area2 = P0.Y * (P2.X - P1.X) + P0.X * (P1.Y - P2.Y) + P1.X * P2.Y - P1.Y * P2.X; 46 if (area2 == 0) 47 return false; 48 49 float s = (P0.Y * P2.X - P0.X * P2.Y + (P2.Y - P0.Y) * pos.X + (P0.X - P2.X) * pos.Y) / area2; 50 if (s < 0) 51 return false; 52 53 float t = (P0.X * P1.Y - P0.Y * P1.X + (P0.Y - P1.Y) * pos.X + (P1.X - P0.X) * pos.Y) / area2; 54 if (t < 0 || s + t > 1) 55 return false; 56 57 return true; 58 } 59 60 public RectangleF AABBFloat 61 { 62 get 63 { 64 float xMin = Math.Min(P0.X, Math.Min(P1.X, P2.X)); 65 float yMin = Math.Min(P0.Y, Math.Min(P1.Y, P2.Y)); 66 float xMax = Math.Max(P0.X, Math.Max(P1.X, P2.X)); 67 float yMax = Math.Max(P0.Y, Math.Max(P1.Y, P2.Y)); 68 69 return new RectangleF(xMin, yMin, xMax - xMin, yMax - yMin); 70 } 71 } 72 73 public float Area => 0.5f * Math.Abs(Vector2Extensions.GetOrientation(GetVertices())); 74 } 75}