Struggling to convert a Vector3 position into a valid Vector2 for my EditableImage

I have this script to draw circles on a SurfaceGui using a tool. Self explanatory:

local Tool = script.Parent
local Handle = Tool.Handle

local Player = game.Players.LocalPlayer
local Character = Player.Character

local function GetFace(Part: BasePart, Direction: Vector3)
	local MaxFace = {Face = nil, Vector = nil}
	local MaxDot = 0

	local MinFace = {Face = nil, Vector = nil}
	local MinDot = 0

	for i, Face in Enum.NormalId:GetEnumItems() do
		local FaceVector = Part.CFrame:VectorToWorldSpace(Vector3.FromNormalId(Face))
		local Dot = FaceVector:Dot(Direction)

		if Dot > 0 and Dot > MaxDot then
			MaxDot = Dot
			MaxFace.Vector = FaceVector
			MaxFace.Face = Face
		elseif Dot < 0 and Dot < MinDot then
			MinDot = Dot
			MinFace.Vector = FaceVector
			MinFace.Face = Face
		end
	end

	return MinFace, MaxFace
end

Tool.Activated:Connect(function()
	
	local Params = RaycastParams.new()
	Params.FilterDescendantsInstances = Character:GetDescendants()
	Params.FilterType = Enum.RaycastFilterType.Exclude

	local ForwardVector = Handle.CFrame.LookVector.Unit

	print("Raycast call")

	local RaycastResult = workspace:Raycast(Handle.Position, ForwardVector*50, Params)

	if not RaycastResult then return end
	if not RaycastResult.Instance then return end

	print("Raycast success!")

	local HitPart: BasePart? = RaycastResult.Instance
	local HitPos = RaycastResult.Position
	local Normal = RaycastResult.Normal

	local MinFace, MaxFace = GetFace(HitPart, Normal)

	print(MaxFace.Face.Name)

	for i, Constituent in Player.PlayerGui:GetChildren() do
		if not Constituent:IsA("SurfaceGui") then continue end
		if Constituent.Adornee ~= HitPart then continue end
		if Constituent.Face ~= MaxFace.Face then continue end
		
		print("EditableImage found!")
		
		local ImageLabel = Constituent:FindFirstChildOfClass("ImageLabel")
		local EditableImage = ImageLabel:FindFirstChildOfClass("EditableImage")
		
		--// Everything works up until this part where even though it doesnt error a circle is never drawn
		local RaycastPosVector2 = Vector2.new(HitPos.X, HitPos.Y)
		
		print(RaycastPosVector2)

		EditableImage:DrawCircle(RaycastPosVector2, 200, Color3.fromRGB(0, 0, 0), 0, Enum.ImageCombineType.Add)
	end
end)

Everything works up until the last part where I have a comment… I don’t really know how to convert the HitPos into a valid Vector2 in a way that the circle shows up. (EditableImage size is (1, 1))

RaycastPosVector2 is world space coordinate point. EditableImage:DrawCircle asks for a position relative from it’s top left corner. You’re gonna need to get the top left corner in world space coordinates and subtract the HitPos from it to get the relative coordinate points. Use the normal of hit face to help you.

local helperPart = Instance.new("Part")

helperPart.CFrame =  CFrame.new(FaceVector, Normal)
local hpcfr = helperPart.CFrame

local topleft = CFrame.fromMatrix(hpcfr.Position, hpcfr.XVector, hpcfr.YVector, Normal)
-- this should convert the world coordinates of the center of the face to object space

local offsetX = hpcfr.RightVector * 0.5 
local offsetY = hpcfr.UpVector * 0.5 

-- this should add 0.5 unit in the X and Y direction of object space,
-- should be the top left corner of a square with 1x1 dimensions
-- I am assuming FaceVector = the center of the face in world space

 topleft = topleft + offsetX + offsetY

HitPos = CFrame.fromMatrix(HitPos, hpcfr.XVector, hpcfr.YVector, Normal)
local offset3d = - (topleft.Position - HitPos.Position)
-- if I'm doing things correctly here worldoffset3d.Z should be 0 now

local relativecoord = Vector2.new(offset3d.X, offset3d.Y) 
-- relativecoord should be the coordinates from the topleft to HitPos
-- should work with DrawCircle

I updated my reply because I realize I made some mistakes. Let me know if it helps… or doesn’t

It works, all I did was just get the relative coords by doing Vector2.new(0, SurfaceGui.AbsoluteSize.Y) and scaling the HitPos accordingly. Thank you!