namespace MagmaEngine.Math; public static class FixPointUtil { public static long DistancePointToSegmentSquared(FixPointVector2 point, FixPointVector2 segmentStart, FixPointVector2 segmentEnd) { var segment = segmentEnd - segmentStart; var toStart = point - segmentStart; var segmentLengthSquared = FixPointVector2.DotLong(segment, segment); if (segmentLengthSquared == 0L) return FixPointVector2.DotLong(toStart, toStart); var projection = FixPointVector2.DotLong(toStart, segment); if (projection <= 0) return FixPointVector2.DotLong(toStart, toStart); FixPointVector2 toPointOnSegment; if (projection >= segmentLengthSquared) toPointOnSegment = point - segmentEnd; else toPointOnSegment = toStart - segment * FixPoint16.FromRational(projection, segmentLengthSquared); return FixPointVector2.DotLong(toPointOnSegment, toPointOnSegment); } public static FixPoint16 DistancePointToSegment(FixPointVector2 point, FixPointVector2 segmentStart, FixPointVector2 segmentEnd) { return FixPoint16.SqrtLong(DistancePointToSegmentSquared(point, segmentStart, segmentEnd)); } public static bool LineLineIntersection(FixPointVector2 line1Start, FixPointVector2 line1End, FixPointVector2 line2Start, FixPointVector2 line2End, out FixPointVector2 intersectionPoint) { intersectionPoint = default; var s1 = line1End - line1Start; var s2 = line2End - line2Start; var det = (FixPoint16Long)(-s2.m_X) * s1.m_Y + (FixPoint16Long)(s1.m_X) * s2.m_Y; if (FixPoint16Long.Abs(det) < s_IntersectionEpsilon) return false; var t = ((FixPoint16Long)s2.m_X * (line1Start.m_Y - line2Start.m_Y) - (FixPoint16Long)s2.m_Y * (line1Start .m_X - line2Start.m_X)) / det; var px = line1Start.m_X + (t * s1.m_X); var py = line1Start.m_Y + (t * s1.m_Y); if (px.m_Value > s_LineIntersectionMax || px.m_Value < s_LineIntersectionMin || py.m_Value > s_LineIntersectionMax || py.m_Value < s_LineIntersectionMin) return false; intersectionPoint = new FixPointVector2(FixPoint16.FromValue(px.m_Value), FixPoint16.FromValue(py.m_Value)); return true; } public static FixPoint16 MultiplyClamped(FixPoint16 a, FixPoint16 b) { var iResult = (((long)a.m_Value * b.m_Value) + FixPoint16.c_Half) >> FixPoint16.c_Shift; if (iResult < FixPoint16.c_LongMin) iResult = FixPoint16.c_LongMin; else if (iResult > FixPoint16.c_LongMax) iResult = FixPoint16.c_LongMax; return new() { m_Value = (int)iResult }; } private static readonly FixPoint16 s_IntersectionEpsilon = FixPoint16.Epsilon * 30; private static readonly long s_LineIntersectionMax = FixPoint16.c_LongMax / 4; private static readonly long s_LineIntersectionMin = FixPoint16.c_LongMin / 4; }