local v=math.pi*2 local d=(1+math.sqrt(5))/2 local q=Vector3.new(1,0,0)local R=Vector3.new(0,1,0)local m=Vector3.new(0,0,1)local B=Vector3.new(-1,0,0)local s=Vector3.new(0,-1,0)local g=Vector3.new(0,0,-1)local i={Vector3.new(1,1,1),Vector3.new(-1,1,1),Vector3.new(-1,1,-1);Vector3.new(1,1,-1);Vector3.new(1,-1,1),Vector3.new(-1,-1,1);Vector3.new(-1,-1,-1);Vector3.new(1,-1,-1)}local W={1,2;3;4;5,6;7;8}local L={1;2;5,6,7,8}local w={4,5,6;7,8}local function k(v)local d={}for q=1,#v,1 do d[q]=i[v[q]]end return d end local function c(d)local m={}local s=v/d for v=1,d,1 do local g=CFrame.fromAxisAngle(q,v*s)*R m[v]=q+g m[d+v]=B+g end return m end local function r(v)local q={Vector3.new(-1,d,0),Vector3.new(1,d,0),Vector3.new(-1,-d,0),Vector3.new(1,-d,0),Vector3.new(0,-1,d);Vector3.new(0,1,d),Vector3.new(0,-1,-d),Vector3.new(0,1,-d);Vector3.new(d,0,-1);Vector3.new(d,0,1);Vector3.new(-d,0,-1),Vector3.new(-d,0,1)}local R={1,12,6,1;6;2;1,2,8,1,8;11;1;11,12,2;6;10,6;12,5;12;11,3;11,8,7,8;2,9;4,10,5;4,5,3;4;3;7;4,7;9,4;9,10;5,10,6,3;5;12;7,3,11,9;7;8;10,9;2}local m={}local function B(v,d)local R=v<d and v..("\044"..d)or d..("\044"..v)if not m[R]then q[#q+1]=(q[v]+q[d])/2 m[R]=#q end return m[R]end for v=1,v,1 do for v=#R,1,-3 do local d,q,m=R[v-2],R[v-1],R[v]local s=B(d,q)local g=B(q,m)local i=B(m,d)R[#R+1]=d R[#R+1]=s R[#R+1]=i R[#R+1]=q R[#R+1]=g R[#R+1]=s R[#R+1]=m R[#R+1]=i R[#R+1]=g R[#R+1]=s R[#R+1]=g R[#R+1]=i table.remove(R,v)table.remove(R,v-1)table.remove(R,v-2)end end for v=1,#q,1 do q[v]=q[v].Unit end return q end local function C(v,d,q)local R={}for m=1,#q,1 do R[m]=v:PointToWorldSpace(q[m]*d)end return R end local function X(v)local d=v[1]for q=2,#v,1 do d=d+v[2]end return d/#v end local function o(v)if v.ClassName=="\080\097\114\116"then if v.Shape==Enum.PartType.Block then return"\066\108\111\099\107"elseif v.Shape==Enum.PartType.Cylinder then return"\067\121\108\105\110\100\101\114"elseif v.Shape==Enum.PartType.Ball then return"\066\097\108\108"end elseif v.ClassName=="\087\101\100\103\101\080\097\114\116"then return"\087\101\100\103\101"elseif v.ClassName=="\067\111\114\110\101\114\087\101\100\103\101\080\097\114\116"then return"\067\111\114\110\101\114\087\101\100\103\101"elseif v:IsA("\066\097\115\101\080\097\114\116")then return"\066\108\111\099\107"end end local M=k(W)local F=k(L)local f=k(w)local t=c(20)local z=r(2)return{Block=function(v,d)return C(v,d,M)end;Wedge=function(v,d)return C(v,d,F)end;CornerWedge=function(v,d)return C(v,d,f)end,Cylinder=function(v,d)return C(v,d,t)end;Ball=function(v,d)return C(v,d,z)end;GetCentroid=X;Classify=o}
-- CONSTANTS

local PI2 = math.pi*2
local PHI = (1 + math.sqrt(5)) / 2

local RIGHT 	= Vector3.new(1, 0, 0)
local UP 		= Vector3.new(0, 1, 0)
local BACK 		= Vector3.new(0, 0, 1)
local LEFT 		= Vector3.new(-1, 0, 0)
local DOWN 		= Vector3.new(0, -1, 0)
local FORWARD 	= Vector3.new(0, 0, -1)

local CORNERS = {
	Vector3.new(1, 1, 1);
	Vector3.new(-1, 1, 1);
	Vector3.new(-1, 1, -1);
	Vector3.new(1, 1, -1);
	Vector3.new(1, -1, 1);
	Vector3.new(-1, -1, 1);
	Vector3.new(-1, -1, -1);
	Vector3.new(1, -1, -1);
}

-- VERTICE INDEX ARRAYS

local BLOCK = {1, 2, 3, 4, 5, 6, 7, 8}
local WEDGE = {1, 2, 5, 6, 7, 8}
local CORNERWEDGE = {4, 5, 6, 7, 8}

-- VERTICE FUNCTIONS

local function fromIndexArray(array)
	local output = {}
	for i = 1, #array do
		output[i] = CORNERS[array[i]]
	end
	return output
end

local function cylinder(n)
	local output = {}
	local arc = PI2 / n
	for i = 1, n do
		local vi = CFrame.fromAxisAngle(RIGHT, i*arc) * UP
		output[i] = RIGHT + vi
		output[n + i] = LEFT + vi
	end
	return output
end

local function icoSphere(n)
	local verts = {
		Vector3.new(-1,  PHI, 0),
		Vector3.new(1,  PHI, 0),
		Vector3.new(-1, -PHI, 0),
		Vector3.new(1, -PHI, 0),
		
		Vector3.new(0, -1,  PHI),
		Vector3.new(0,  1,  PHI),
		Vector3.new(0, -1, -PHI),
		Vector3.new(0,  1, -PHI),
		
		Vector3.new(PHI, 0, -1),
		Vector3.new(PHI, 0,  1),
		Vector3.new(-PHI, 0, -1),
		Vector3.new(-PHI, 0,  1)
	}
	
	local indices = {
		1, 12, 6,
		1, 6, 2,
		1, 2, 8,
		1, 8, 11,
		1, 11, 12,
		
		2, 6, 10,
		6, 12, 5,
		12, 11, 3,
		11, 8, 7,
		8, 2, 9,
		
		4, 10, 5,
		4, 5, 3,
		4, 3, 7,
		4, 7, 9,
		4, 9, 10,
		
		5, 10, 6,
		3, 5, 12,
		7, 3, 11,
		9, 7, 8,
		10, 9, 2
	}
	
	local splits = {}
	
	local function split(i, j)
		local key = i < j and (i .. "," .. j) or (j .. "," .. i)
		
		if (not splits[key]) then
			verts[#verts+1] = (verts[i] + verts[j]) / 2
			splits[key] = #verts
		end
		
		return splits[key]
	end
	
	for _ = 1, n do
		for  i = #indices, 1, -3 do
			local v1, v2, v3 = indices[i - 2], indices[i - 1], indices[i]
			local a = split(v1, v2)
			local b = split(v2, v3)
			local c = split(v3, v1)
			
			indices[#indices+1] = v1
			indices[#indices+1] = a
			indices[#indices+1] = c
			
			indices[#indices+1] = v2
			indices[#indices+1] = b
			indices[#indices+1] = a
			
			indices[#indices+1] = v3
			indices[#indices+1] = c
			indices[#indices+1] = b
			
			indices[#indices+1] = a
			indices[#indices+1] = b
			indices[#indices+1] = c
			
			table.remove(indices, i)
			table.remove(indices, i - 1)
			table.remove(indices, i - 2)
		end
	end
	
	-- normalize
	for i = 1, #verts do
		verts[i] = verts[i].Unit
	end
	
	return verts
end

-- Useful functions

local function vertShape(cf, size2, array)
	local output = {}
	for i = 1, #array do
		output[i] = cf:PointToWorldSpace(array[i] * size2)
	end
	return output
end

local function getCentroidFromSet(set)
	local sum = set[1]
	for i = 2, #set do
		sum = sum + set[2]
	end
	return sum / #set
end

local function classify(part)
	if (part.ClassName == "Part") then
		if (part.Shape == Enum.PartType.Block) then
			return "Block"
		elseif (part.Shape == Enum.PartType.Cylinder) then
			return "Cylinder"
		elseif (part.Shape == Enum.PartType.Ball) then
			return "Ball"
		end;
	elseif (part.ClassName == "WedgePart") then
		return "Wedge"
	elseif (part.ClassName == "CornerWedgePart") then
		return "CornerWedge"
	elseif (part:IsA("BasePart")) then -- mesh, CSG, truss, etc... just use block
		return "Block"
	end
end

-- 

local BLOCK_ARRAY = fromIndexArray(BLOCK)
local WEDGE_ARRAY = fromIndexArray(WEDGE)
local CORNERWEDGE_ARRAY = fromIndexArray(CORNERWEDGE)
local CYLINDER_ARRAY = cylinder(20)
local SPHERE_ARRAY = icoSphere(2)

return {
	Block = function(cf, size2) return vertShape(cf, size2, BLOCK_ARRAY) end;
	Wedge = function(cf, size2) return vertShape(cf, size2, WEDGE_ARRAY) end;
	CornerWedge = function(cf, size2) return vertShape(cf, size2, CORNERWEDGE_ARRAY) end;
	Cylinder = function(cf, size2) return vertShape(cf, size2, CYLINDER_ARRAY) end;
	Ball = function(cf, size2) return vertShape(cf, size2, SPHERE_ARRAY) end;
	
	GetCentroid = getCentroidFromSet;
	Classify = classify;
}