Use this module, please search on the devforums before posting.
function CalcCanvas(CanvasPart)
local canvasSize = CanvasPart.Size
-- want to create CFrame such that cf.lookVector == self.CanvasPart.CFrame.upVector
-- do this by using object space and build the CFrame
local back = Vector3.new(0, -1, 0)
local top = Vector3.new(0, 0, -1)
local right = Vector3.new(-1, 0, 0)
-- convert to world space
local cf = CanvasPart.CFrame * CFrame.fromMatrix(-back*canvasSize/2, right, top, back)
-- use object space vectors to find the width and height
local size = Vector2.new((canvasSize * right).magnitude, (canvasSize * top).magnitude)
return cf, size
end
function CalcPlacementCFrame(model, position, rotation, CanvasPart)
-- use other method to get info about the surface
local cf, size = CalcCanvas(CanvasPart)
-- rotate the size so that we can properly constrain to the surface
local modelSize
if model:IsA("Model") then
modelSize = CFrame.fromEulerAnglesYXZ(0, rotation, 0) * model:GetExtentsSize() --model.PrimaryPart.Size
else
modelSize = model.Size
end
modelSize = Vector3.new(math.abs(modelSize.x), math.abs(modelSize.y), math.abs(modelSize.z))
-- get the position relative to the surface's CFrame
local lpos = cf:pointToObjectSpace(position);
-- the max bounds the model can be from the surface's center
local size2 = (size - Vector2.new(modelSize.x, modelSize.z))/2
-- constrain the position using size2
local x = math.clamp(lpos.x, -size2.x, size2.x);
local y = math.clamp(lpos.y, -size2.y, size2.y);
local g = 1
if (g > 0) then
x = math.sign(x)*((math.abs(x) - math.abs(x) % g) + (size2.x % g))
y = math.sign(y)*((math.abs(y) - math.abs(y) % g) + (size2.y % g))
end
-- create and return the CFrame
return cf * CFrame.new(x, y, -modelSize.y/2) * CFrame.Angles(-math.pi/2 + tilt, -math.pi/2+rotation, 0)
end