local B=(Vector3.new()).Dot local G=(Vector3.new()).Cross local R=math.clamp local function p(B)if B.Magnitude==0 then return Vector3.zero end return B.Unit end local function r(G,p,r)local c=p-G local j=B(r-G,c)/B(c,c)return G+R(j,0,1)*c end local function c(B,G,R)local p=R-B local r=p:Dot(G)local c=R-r*G return c end local function j(R,p,r,c)local j=G(c-r,R-r)local y=G(c-r,p-r)if B(j,y)>=0 then return true else return false end end local function y(B,G,R,p)if j(B,G,R,p)and(j(B,R,G,p)and j(B,p,G,R))then return true end return false end local function W(B,R,j,W)debug.profilebegin("\084\114\105\097\110\103\108\101")local l=r(B,R,W)local a=r(R,j,W)local Y=r(j,B,W)local f=p(G(R-B,j-B))local H=((B+R)+j)*.3333 local q=c(H,f,W)if y(W,B,R,j)then debug.profileend()return q,f end local N=(l-W).Magnitude local Z=(a-W).Magnitude local J=(Y-W).Magnitude local S=math.min(N,Z,J)if S==N then debug.profileend()return l,f elseif S==Z then debug.profileend()return a,f elseif S==J then debug.profileend()return Y,f end debug.profileend()return W,f end return W
--[[

    !! THIS IS NOT MEANT TO BE USED AS A COLLIDER SOLVER, ITS MEANT TO BE USED IN OTHER COLLIDER SOLVERS !!

]]

--!native
local dot = Vector3.new().Dot
local cross = Vector3.new().Cross
local clamp = math.clamp

local function SafeUnit(v3)
	if v3.Magnitude == 0 then
		return Vector3.zero
	end

	return v3.Unit
end

local function ClosestPointOnLineSegment(A, B, P)
	local AB = B - A
	local t = dot(P - A, AB) / dot(AB, AB)
	return A + clamp(t, 0, 1) * AB
end

local function ProjectOnPlane(pos, normal, point)
	local d = point - pos
	local v_dot = d:Dot(normal)
	local v = point - v_dot * normal

	return v
end

local function SameSide(p1, p2, a, b)
	local cp1 = cross(b - a, p1 - a)
	local cp2 = cross(b - a, p2 - a)
	if dot(cp1, cp2) >= 0 then
		return true
	else
		return false
	end
end

local function PointInTriangle(p, a, b, c)
	if SameSide(p, a, b, c) and SameSide(p, b, a, c) and SameSide(p, c, a, b) then
		return true
	end

	return false
end

local function ClosestPointOnTri(v0, v1, v2, point) -- ClosestPoint, Normal
	debug.profilebegin("Triangle")
	local Edge0 = ClosestPointOnLineSegment(v0, v1, point)
	local Edge1 = ClosestPointOnLineSegment(v1, v2, point)
	local Edge2 = ClosestPointOnLineSegment(v2, v0, point)

	local Normal = SafeUnit(cross(v1 - v0, v2 - v0))
	local Center = (v0 + v1 + v2) * 0.3333
	local Projected = ProjectOnPlane(Center, Normal, point)

	if PointInTriangle(point, v0, v1, v2) then
		debug.profileend()
		return Projected, Normal
	end

	local d0 = (Edge0 - point).Magnitude
	local d1 = (Edge1 - point).Magnitude
	local d2 = (Edge2 - point).Magnitude

	local d = math.min(d0, d1, d2)

	if d == d0 then
		debug.profileend()
		return Edge0, Normal
	elseif d == d1 then
		debug.profileend()
		return Edge1, Normal
	elseif d == d2 then
		debug.profileend()
		return Edge2, Normal
	end

	debug.profileend()
	return point, Normal
end

return ClosestPointOnTri
