local w=game:GetService("\087\111\114\107\115\112\097\099\101")local z={}local function g(w)local z,g,H,C,x,Q,h,V,q,N,f,S=w:components()return Vector3.new(C,h,N)end local function H(w)local z,g,H,C,x,Q,h,V,q,N,f,S=w:components()return Vector3.new(x,V,f)end local function C(w)local z,g,H,C,x,Q,h,V,q,N,f,S=w:components()return Vector3.new(Q,q,S)end local function x(w)return w:IsA("\080\097\114\116")and w.Shape==Enum.PartType.Ball end local Q=Vector3.new(1,1,1)local function h(w)for w,z in pairs(w:GetChildren())do if z:IsA("\083\112\101\099\105\097\108\077\101\115\104")then local w=z.Scale if z.MeshType==Enum.MeshType.Brick then return"\066\114\105\099\107",w elseif z.MeshType==Enum.MeshType.CornerWedge then return"\067\111\114\110\101\114\087\101\100\103\101",w elseif z.MeshType==Enum.MeshType.Cylinder then return"\082\111\117\110\100",w elseif z.MeshType==Enum.MeshType.Wedge then return"\087\101\100\103\101",w elseif z.MeshType==Enum.MeshType.Sphere then return"\082\111\117\110\100",w else warn("\080\097\114\116\071\101\111\109\101\116\114\121\058 \085\110\115\117\112\112\111\114\116\101\100 \077\101\115\104 \084\121\112\101 \096"..(z.MeshType.Name.."\096\044 \116\114\101\097\116\105\110\103 \097\115 \097 \110\111\114\109\097\108 \098\114\105\099\107\046"))end end end if w:IsA("\087\101\100\103\101\080\097\114\116")then return"\087\101\100\103\101",Q elseif w:IsA("\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",Q elseif w:IsA("\084\101\114\114\097\105\110")then return"\084\101\114\114\097\105\110",Q elseif w:IsA("\084\114\117\115\115\080\097\114\116")then return"\066\114\105\099\107",Q elseif w:IsA("\085\110\105\111\110\079\112\101\114\097\116\105\111\110")or w:IsA("\077\101\115\104\080\097\114\116")then return"\066\114\105\099\107",Q elseif w:IsA("\086\101\104\105\099\108\101\083\101\097\116")then return"\066\114\105\099\107",Q else if w.Shape==Enum.PartType.Ball then return"\082\111\117\110\100",Q elseif w.Shape==Enum.PartType.Cylinder then return"\082\111\117\110\100",Q elseif w.Shape==Enum.PartType.Block then return"\066\114\105\099\107",Q else assert(false,"\085\110\114\101\097\099\104\097\098\108\101")end end end local function V(z,Q,V)local q=V or z.CFrame local N=q.p local f=z.Size.x/2 local S=z.Size.y/2 local P=z.Size.z/2 local i=g(q)local Y=H(q)local t=C(q)local T,a,E local F local Z,X=h(z)f=f*X.X S=S*X.Y P=P*X.Z if Z=="\066\114\105\099\107"then T={((N+i*f)+Y*S)+t*P,((N+i*f)+Y*S)-t*P;((N-i*f)+Y*S)+t*P;((N-i*f)+Y*S)-t*P,((N+i*f)-Y*S)+t*P,((N+i*f)-Y*S)-t*P;((N-i*f)-Y*S)+t*P,((N-i*f)-Y*S)-t*P}a={{T[1];T[2];math.min(2*f,2*S)},{T[3];T[4];math.min(2*f,2*S)};{T[1];T[3];math.min(2*S,2*P)};{T[2];T[4],math.min(2*S,2*P)};{T[5],T[6];math.min(2*f,2*S)};{T[7],T[8];math.min(2*f,2*S)},{T[5];T[7];math.min(2*S,2*P)};{T[6];T[8];math.min(2*S,2*P)};{T[1],T[5],math.min(2*f,2*P)};{T[2];T[6],math.min(2*f,2*P)},{T[3];T[7];math.min(2*f,2*P)};{T[4],T[8];math.min(2*f,2*P)}}E={{T[1];i,t;{T[1],T[2];T[6],T[5]}},{T[3];-i;t,{T[3],T[4],T[8];T[7]}};{T[1];Y;i,{T[1],T[2],T[4],T[3]}};{T[5],-Y;i;{T[5],T[6],T[8],T[7]}};{T[1],t;i,{T[1];T[3],T[7],T[5]}};{T[2];-t;i,{T[2],T[4];T[8];T[6]}}}elseif Z=="\082\111\117\110\100"then T={Q}a={}local w=(Q-N).unit local z=(w:Cross(Vector3.new(0,1,0))).unit E={{Q;w,z;{}}}elseif Z=="\067\111\114\110\101\114\087\101\100\103\101"then local w=(t*S+Y*P).unit local z=(-i*S+Y*f).unit T={((N+i*f)+Y*S)-t*P;((N+i*f)-Y*S)+t*P;((N+i*f)-Y*S)-t*P;((N-i*f)-Y*S)+t*P;((N-i*f)-Y*S)-t*P}a={{T[2];T[3],0};{T[3],T[5],0},{T[5];T[4],0},{T[4];T[1],0},{T[1],T[3],0};{T[1],T[2];0},{T[1];T[5];0};{T[1];T[4];0}}E={{T[2];-Y,i;{T[2];T[3];T[5];T[4]}};{T[1],i;-Y;{T[1],T[3],T[2]}};{T[1];-t,-Y,{T[1],T[3];T[5]}},{T[1],w;i;{T[1];T[2];T[4]}};{T[1],z,t;{T[1],T[5],T[4]}}}elseif Z=="\087\101\100\103\101"then local w=(-t*S+Y*P).unit T={((N+i*f)+Y*S)+t*P,((N-i*f)+Y*S)+t*P,((N+i*f)-Y*S)+t*P;((N+i*f)-Y*S)-t*P;((N-i*f)-Y*S)+t*P;((N-i*f)-Y*S)-t*P}a={{T[1];T[2];math.min(2*S,2*P)};{T[1],T[4];math.min(2*S,2*P)};{T[2];T[6];math.min(2*S,2*P)};{T[3],T[4],math.min(2*f,2*S)},{T[5];T[6];math.min(2*f,2*S)};{T[3];T[5],math.min(2*S,2*P)};{T[4],T[6],math.min(2*S,2*P)};{T[1];T[3];math.min(2*f,2*P)};{T[2];T[5],math.min(2*f,2*P)}}E={{T[1],i,t;{T[1],T[4];T[3]}};{T[2],-i,t;{T[2];T[6];T[5]}};{T[3],-Y;i;{T[3];T[4],T[6],T[5]}};{T[1];t,i;{T[1];T[2];T[5],T[3]}};{T[2],w;w:Cross(i);{T[2];T[1];T[4],T[6]}}}elseif Z=="\084\101\114\114\097\105\110"then local z=w.Terrain:WorldToCellPreferSolid(Q)local g,H,C=w.Terrain:GetCell(z.x,z.y,z.z)local x=w.Terrain:CellCenterToWorld(z.x,z.y,z.z)F=4 local h={[Enum.CellOrientation.NegZ]=0,[Enum.CellOrientation.X]=1;[Enum.CellOrientation.Z]=2;[Enum.CellOrientation.NegX]=3}local V=(CFrame.Angles(0,(math.pi/2)*(h[C]-1),0)).lookVector local q=Vector3.new(0,1,0)local N=V:Cross(q)if H==Enum.CellBlock.Solid then T={((x+V*2)+q*2)+N*2,((x+V*2)+q*2)-N*2;((x-V*2)+q*2)+N*2,((x-V*2)+q*2)-N*2,((x+V*2)-q*2)+N*2;((x+V*2)-q*2)-N*2;((x-V*2)-q*2)+N*2,((x-V*2)-q*2)-N*2}a={{T[1],T[2],4};{T[3],T[4],4};{T[1];T[3];4};{T[2];T[4];4},{T[5];T[6];4},{T[7];T[8];4},{T[5];T[7],4},{T[6];T[8],4},{T[1],T[5],4},{T[2],T[6];4};{T[3];T[7];4};{T[4],T[8];4}}E={{x+V*2;V;N;{T[1],T[2],T[6],T[5]}};{x-V*2;-V;N;{T[3];T[4],T[8],T[7]}};{x+q*2;q,V;{T[1],T[2];T[4],T[3]}};{x-q*2;-q;V,{T[5],T[6],T[8];T[7]}},{x+N*2;N;V,{T[1],T[3];T[7],T[5]}},{x-N*2,-N,V;{T[2];T[4];T[8];T[6]}}}elseif H==Enum.CellBlock.VerticalWedge then N=-N V=-V local w=(-N*2+q*2).unit T={((x+V*2)+q*2)+N*2,((x-V*2)+q*2)+N*2,((x+V*2)-q*2)+N*2,((x+V*2)-q*2)-N*2;((x-V*2)-q*2)+N*2,((x-V*2)-q*2)-N*2}a={{T[1];T[2];4};{T[1],T[4];4},{T[2];T[6],4};{T[3],T[4];4};{T[5],T[6],4},{T[3],T[5];4},{T[4];T[6],4};{T[1];T[3];4},{T[2],T[5],4}}E={{x+V*2,V;N,{T[1];T[4];T[3]}},{x-V*2;-V,N;{T[2],T[6],T[5]}};{x-q*2;-q,V,{T[3];T[4];T[6];T[5]}},{x+N*2,N;V;{T[1],T[2],T[5],T[3]}};{x;w;w:Cross(V),{T[2];T[1];T[4];T[6]}}}elseif H==Enum.CellBlock.CornerWedge then T={((x+V*2)+q*2)-N*2;((x+V*2)-q*2)-N*2,((x+V*2)-q*2)+N*2;((x-V*2)-q*2)-N*2}a={{T[1];T[2],3};{T[1];T[3];3},{T[1],T[4];3},{T[2];T[3],3},{T[2],T[4];3},{T[3];T[4];3}}local w=((T[3]+T[4])/2+T[2])/2 local z=Vector3.new(w.x,x.y,w.z)local g=((N-V).unit*2+Vector3.new(0,math.sqrt(2),0)).unit E={{w,-q,V,{T[2];T[3],T[4]}},{x+V*2;V,q,{T[1];T[2];T[3]}};{x-N*2,-N,q,{T[1],T[2];T[4]}},{z;g;(V+N).unit,{T[1],T[3],T[4]}}}elseif H==Enum.CellBlock.InverseCornerWedge then T={((x+V*2)+q*2)+N*2;((x+V*2)+q*2)-N*2,((x-V*2)+q*2)-N*2,((x+V*2)-q*2)+N*2,((x+V*2)-q*2)-N*2,((x-V*2)-q*2)+N*2;((x-V*2)-q*2)-N*2}a={{T[1],T[2];4},{T[2];T[3];4},{T[4];T[5],4},{T[6];T[7],4},{T[4];T[6],4},{T[5],T[7],4},{T[1];T[4],4},{T[2],T[5];4},{T[3],T[7],4};{T[1];T[3];2.5};{T[1];T[6];2.5};{T[3],T[6],2.5}}local w=((T[4]+T[7])/2+T[6])/2 local z=Vector3.new(w.x,x.y,w.z)local g=((N-V).unit*2+Vector3.new(0,math.sqrt(2),0)).unit E={{x+V*2,V;N;{T[1],T[2],T[5];T[4]}};{x-V*2;-V,N;{T[3],T[7],T[6]}},{x+q*2;q;V,{T[1];T[2];T[3]}},{x-q*2;-q;V;{T[4],T[5],T[7];T[6]}},{x+N*2,N,V,{T[1],T[6];T[4]}},{x-N*2,-N;V,{T[2];T[3];T[7],T[5]}};{z;g,(V+N).unit,{T[1];T[3],T[6]}}}elseif H==Enum.CellBlock.HorizontalWedge then T={((x+V*2)+q*2)+N*2;((x+V*2)+q*2)-N*2,((x-V*2)+q*2)-N*2;((x+V*2)-q*2)+N*2;((x+V*2)-q*2)-N*2,((x-V*2)-q*2)-N*2}a={{T[1],T[2],4},{T[2];T[3];4};{T[4];T[5],4},{T[5],T[6];4},{T[1],T[4];4},{T[2];T[5],4},{T[3];T[6];4},{T[1];T[3],2.5},{T[4],T[6],2.5}}E={{x+V*2,V,N;{T[1];T[2],T[5],T[4]}};{x+q*2;q;V,{T[1],T[2],T[3]}},{x-q*2;-q;V,{T[4];T[5];T[6]}},{x-N*2,-N,V;{T[2];T[3];T[6];T[5]}},{x,(N-V).unit;q;{T[1];T[3];T[4],T[6]}}}else assert(false,"\117\110\114\101\097\099\104\097\098\108\101")end else assert(false,"\066\097\100 \115\104\097\112\101\058 "..Z)end local p={part=z,vertices=T;edges=a;faces=E,vertexMargin=F or math.min(f,S,P)*2,cframe=q}local u=0 for w,g in pairs(E)do u=u+1 g.id=u g.point=g[1]g.normal=g[2]g.direction=g[3]g.vertices=g[4]g.part=z g.type="\070\097\099\101"g[1],g[2],g[3],g[4]=nil,nil,nil,nil end for w,g in pairs(a)do u=u+1 g.id=u g.a,g.b=g[1],g[2]g.direction=(g.b-g.a).unit g.length=(g.b-g.a).Magnitude g.edgeMargin=g[3]g.part=z g.vertexMargin=p.vertexMargin g.type="\069\100\103\101"g[1],g[2],g[3]=nil,nil,nil end for w,g in pairs(T)do u=u+1 T[w]={position=g;id=u,ignoreUnlessNeeded=x(z),type="\086\101\114\116\101\120"}end return p end z.GetGeometry=V local function q(w)return w.normal end z.getNormal=q local function N(w,z)return(w-z).Magnitude<.001 end z.close=N return z
--- Gives out part geoemtry
-- @module PartGeometry
-- @author xLEGOx, modified by quenty
-- @see http://www.roblox.com/Stravant-MultiMove-item?id=166786055

local Workspace = game:GetService("Workspace")

local lib = {}

---- This one is from
--- http://www.roblox.com/Stravant-GapFill-item?id=165687726
local function rightVector(cf)
    local _,_,_,r4,_,_,r7,_,_,r10,_,_ = cf:components()
    return Vector3.new(r4,r7,r10)
end

local function topVector(cf)
    local _,_,_,_,r5,_,_,r8,_,_,r11,_ = cf:components()
    return Vector3.new(r5,r8,r11)
end
local function backVector(cf)
    local _,_,_,_,_,r6,_,_,r9,_,_,r12 = cf:components()
    return Vector3.new(r6,r9,r12)
end

local function IsSmoothPart(part)
    return part:IsA("Part") and (part.Shape == Enum.PartType.Ball)
end

local UNIFORM_SCALE = Vector3.new(1, 1, 1)
local function GetShape(part)
    for _, ch in pairs(part:GetChildren()) do
        if ch:IsA("SpecialMesh") then
            local scale = ch.Scale
            if ch.MeshType == Enum.MeshType.Brick then
                return "Brick", scale
            elseif ch.MeshType == Enum.MeshType.CornerWedge then
                return "CornerWedge", scale
            elseif ch.MeshType == Enum.MeshType.Cylinder then
                return "Round", scale
            elseif ch.MeshType == Enum.MeshType.Wedge then
                return "Wedge", scale
            elseif ch.MeshType == Enum.MeshType.Sphere then
                return "Round", scale
            else
                --spawn(function()
                warn("PartGeometry: Unsupported Mesh Type `" .. ch.MeshType.Name .. "`, treating as a normal brick.")
               -- end)
            end
        end
    end
    if part:IsA("WedgePart") then
        return "Wedge", UNIFORM_SCALE
    elseif part:IsA("CornerWedgePart") then
        return "CornerWedge", UNIFORM_SCALE
    elseif part:IsA("Terrain") then
        return "Terrain", UNIFORM_SCALE
    elseif part:IsA("TrussPart") then
        return "Brick", UNIFORM_SCALE
    elseif part:IsA("UnionOperation") or part:IsA("MeshPart") then
        -- Yeah, can"t do too much about this. :/
        return "Brick", UNIFORM_SCALE
    elseif part:IsA("VehicleSeat") then
        return "Brick", UNIFORM_SCALE
    else
        -- BasePart
        if part.Shape == Enum.PartType.Ball then
            return "Round", UNIFORM_SCALE
        elseif part.Shape == Enum.PartType.Cylinder then
            return "Round", UNIFORM_SCALE
        elseif part.Shape == Enum.PartType.Block then
            return "Brick", UNIFORM_SCALE
        else
            assert(false, "Unreachable")
        end
    end
end

--Abondon hope, all ye who enter:
local function GetGeometry(part, hit, cframeOverride)
    local cf = cframeOverride or part.CFrame
    local pos = cf.p
    --
    local sx = part.Size.x/2
    local sy = part.Size.y/2
    local sz = part.Size.z/2
    --
    local xvec = rightVector(cf)
    local yvec = topVector(cf)
    local zvec = backVector(cf)
    --
    local verts, edges, faces
    --
    local vertexMargin
    --
    local shape, scale = GetShape(part)
    --
    sx = sx * scale.X
    sy = sy * scale.Y
    sz = sz * scale.Z
    --
    if shape == "Brick" then
        --8 vertices
        verts = {
            pos +xvec*sx  +yvec*sy  +zvec*sz, --top 4
            pos +xvec*sx  +yvec*sy  -zvec*sz,
            pos -xvec*sx  +yvec*sy  +zvec*sz,
            pos -xvec*sx  +yvec*sy  -zvec*sz,
            --
            pos +xvec*sx  -yvec*sy  +zvec*sz, --bottom 4
            pos +xvec*sx  -yvec*sy  -zvec*sz,
            pos -xvec*sx  -yvec*sy  +zvec*sz,
            pos -xvec*sx  -yvec*sy  -zvec*sz,
        }
        --12 edges
        edges = {
            {verts[1], verts[2], math.min(2*sx, 2*sy)}, --top 4
            {verts[3], verts[4], math.min(2*sx, 2*sy)},
            {verts[1], verts[3], math.min(2*sy, 2*sz)},
            {verts[2], verts[4], math.min(2*sy, 2*sz)},
            --
            {verts[5], verts[6], math.min(2*sx, 2*sy)}, --bottom 4
            {verts[7], verts[8], math.min(2*sx, 2*sy)},
            {verts[5], verts[7], math.min(2*sy, 2*sz)},
            {verts[6], verts[8], math.min(2*sy, 2*sz)},
            --
            {verts[1], verts[5], math.min(2*sx, 2*sz)}, --verticals
            {verts[2], verts[6], math.min(2*sx, 2*sz)},
            {verts[3], verts[7], math.min(2*sx, 2*sz)},
            {verts[4], verts[8], math.min(2*sx, 2*sz)},
        }
        --6 faces
        faces = {
            {verts[1],  xvec, zvec, {verts[1], verts[2], verts[6], verts[5]}}, --right
            {verts[3], -xvec, zvec, {verts[3], verts[4], verts[8], verts[7]}}, --left
            {verts[1],  yvec, xvec, {verts[1], verts[2], verts[4], verts[3]}}, --top
            {verts[5], -yvec, xvec, {verts[5], verts[6], verts[8], verts[7]}}, --bottom
            {verts[1],  zvec, xvec, {verts[1], verts[3], verts[7], verts[5]}}, --back
            {verts[2], -zvec, xvec, {verts[2], verts[4], verts[8], verts[6]}}, --front
        }
    elseif shape == "Round" then
        -- just have one face and vertex, at the hit pos
        verts = { hit }
        edges = {} --edge can be selected as the normal of the face if the user needs it
        local norm = (hit-pos).unit
        local norm2 = norm:Cross(Vector3.new(0,1,0)).unit
        faces = {
            {hit, norm, norm2, {}}
        }
    elseif shape == "CornerWedge" then
        local slantVec1 = ( zvec*sy + yvec*sz).unit
        local slantVec2 = (-xvec*sy + yvec*sx).unit
        -- 5 verts
        verts = {
            pos +xvec*sx  +yvec*sy  -zvec*sz, --top 1
            --
            pos +xvec*sx  -yvec*sy  +zvec*sz, --bottom 4
            pos +xvec*sx  -yvec*sy  -zvec*sz,
            pos -xvec*sx  -yvec*sy  +zvec*sz,
            pos -xvec*sx  -yvec*sy  -zvec*sz,
        }
        -- 8 edges
        edges = {
            {verts[2], verts[3], 0}, -- bottom 4
            {verts[3], verts[5], 0},
            {verts[5], verts[4], 0},
            {verts[4], verts[1], 0},
            --
            {verts[1], verts[3], 0}, -- vertical
            --
            {verts[1], verts[2], 0}, -- side diagonals
            {verts[1], verts[5], 0},
            --
            {verts[1], verts[4], 0}, -- middle diagonal
        }
        -- 5 faces
        faces = {
            {verts[2], -yvec, xvec, {verts[2], verts[3], verts[5], verts[4]}}, -- bottom
            --
            {verts[1],  xvec, -yvec, {verts[1], verts[3], verts[2]}}, -- sides
            {verts[1], -zvec, -yvec, {verts[1], verts[3], verts[5]}},
            --
            {verts[1],  slantVec1, xvec, {verts[1], verts[2], verts[4]}}, -- tops
            {verts[1],  slantVec2, zvec, {verts[1], verts[5], verts[4]}},
        }

    elseif shape == "Wedge" then
        local slantVec = (-zvec*sy + yvec*sz).unit
        --6 vertices
        verts = {
            pos +xvec*sx  +yvec*sy  +zvec*sz, --top 2
            pos -xvec*sx  +yvec*sy  +zvec*sz,
            --
            pos +xvec*sx  -yvec*sy  +zvec*sz, --bottom 4
            pos +xvec*sx  -yvec*sy  -zvec*sz,
            pos -xvec*sx  -yvec*sy  +zvec*sz,
            pos -xvec*sx  -yvec*sy  -zvec*sz,
        }
        --9 edges
        edges = {
            {verts[1], verts[2], math.min(2*sy, 2*sz)}, --top 1
            --
            {verts[1], verts[4], math.min(2*sy, 2*sz)}, --slanted 2
            {verts[2], verts[6], math.min(2*sy, 2*sz)},
            --
            {verts[3], verts[4], math.min(2*sx, 2*sy)}, --bottom 4
            {verts[5], verts[6], math.min(2*sx, 2*sy)},
            {verts[3], verts[5], math.min(2*sy, 2*sz)},
            {verts[4], verts[6], math.min(2*sy, 2*sz)},
            --
            {verts[1], verts[3], math.min(2*sx, 2*sz)}, --vertical 2
            {verts[2], verts[5], math.min(2*sx, 2*sz)},
        }
        --5 faces
        faces = {
            {verts[1],  xvec, zvec, {verts[1], verts[4], verts[3]}}, --right
            {verts[2], -xvec, zvec, {verts[2], verts[6], verts[5]}}, --left
            {verts[3], -yvec, xvec, {verts[3], verts[4], verts[6], verts[5]}}, --bottom
            {verts[1],  zvec, xvec, {verts[1], verts[2], verts[5], verts[3]}}, --back
            {verts[2], slantVec, slantVec:Cross(xvec), {verts[2], verts[1], verts[4], verts[6]}}, --slanted
        }
    elseif shape == "Terrain" then
        local cellPos = Workspace.Terrain:WorldToCellPreferSolid(hit)
        local mat, block, orient = Workspace.Terrain:GetCell(cellPos.x, cellPos.y, cellPos.z)
        local pos = Workspace.Terrain:CellCenterToWorld(cellPos.x, cellPos.y, cellPos.z)
        --
        vertexMargin = 4
        --
        local orientToNumberMap = {
            [Enum.CellOrientation.NegZ] = 0;
            [Enum.CellOrientation.X]    = 1;
            [Enum.CellOrientation.Z]    = 2;
            [Enum.CellOrientation.NegX] = 3;
        }
        --
        local xvec = CFrame.Angles(0, math.pi/2*(orientToNumberMap[orient]-1), 0).lookVector
        local yvec = Vector3.new(0, 1, 0)
        local zvec = xvec:Cross(yvec)
        --
        if block == Enum.CellBlock.Solid then
            --8 vertices
            verts = {
                pos +xvec*2  +yvec*2  +zvec*2, --top 4
                pos +xvec*2  +yvec*2  -zvec*2,
                pos -xvec*2  +yvec*2  +zvec*2,
                pos -xvec*2  +yvec*2  -zvec*2,
                --
                pos +xvec*2  -yvec*2  +zvec*2, --bottom 4
                pos +xvec*2  -yvec*2  -zvec*2,
                pos -xvec*2  -yvec*2  +zvec*2,
                pos -xvec*2  -yvec*2  -zvec*2,
            }
            --12 edges
            edges = {
                {verts[1], verts[2], 4}, --top 4
                {verts[3], verts[4], 4},
                {verts[1], verts[3], 4},
                {verts[2], verts[4], 4},
                --
                {verts[5], verts[6], 4}, --bottom 4
                {verts[7], verts[8], 4},
                {verts[5], verts[7], 4},
                {verts[6], verts[8], 4},
                --
                {verts[1], verts[5], 4}, --verticals
                {verts[2], verts[6], 4},
                {verts[3], verts[7], 4},
                {verts[4], verts[8], 4},
            }
            --6 faces
            faces = {
                {pos+xvec*2,  xvec, zvec, {verts[1], verts[2], verts[6], verts[5]}}, --right
                {pos-xvec*2, -xvec, zvec, {verts[3], verts[4], verts[8], verts[7]}}, --left
                {pos+yvec*2,  yvec, xvec, {verts[1], verts[2], verts[4], verts[3]}}, --top
                {pos-yvec*2, -yvec, xvec, {verts[5], verts[6], verts[8], verts[7]}}, --bottom
                {pos+zvec*2,  zvec, xvec, {verts[1], verts[3], verts[7], verts[5]}}, --back
                {pos-zvec*2, -zvec, xvec, {verts[2], verts[4], verts[8], verts[6]}}, --front
            }

        elseif block == Enum.CellBlock.VerticalWedge then
            --top wedge. Similar to wedgepart, but we need to flip the Z axis
            zvec = -zvec
            xvec = -xvec
            --
            local slantVec = (-zvec*2 + yvec*2).unit
            --6 vertices
            verts = {
                pos +xvec*2  +yvec*2  +zvec*2, --top 2
                pos -xvec*2  +yvec*2  +zvec*2,
                --
                pos +xvec*2  -yvec*2  +zvec*2, --bottom 4
                pos +xvec*2  -yvec*2  -zvec*2,
                pos -xvec*2  -yvec*2  +zvec*2,
                pos -xvec*2  -yvec*2  -zvec*2,
            }
            --9 edges
            edges = {
                {verts[1], verts[2], 4}, --top 1
                --
                {verts[1], verts[4], 4}, --slanted 2
                {verts[2], verts[6], 4},
                --
                {verts[3], verts[4], 4}, --bottom 4
                {verts[5], verts[6], 4},
                {verts[3], verts[5], 4},
                {verts[4], verts[6], 4},
                --
                {verts[1], verts[3], 4}, --vertical 2
                {verts[2], verts[5], 4},
            }
            --5 faces
            faces = {
                {pos+xvec*2,  xvec, zvec, {verts[1], verts[4], verts[3]}}, --right
                {pos-xvec*2, -xvec, zvec, {verts[2], verts[6], verts[5]}}, --left
                {pos-yvec*2, -yvec, xvec, {verts[3], verts[4], verts[6], verts[5]}}, --bottom
                {pos+zvec*2,  zvec, xvec, {verts[1], verts[2], verts[5], verts[3]}}, --back
                {pos, slantVec, slantVec:Cross(xvec), {verts[2], verts[1], verts[4], verts[6]}}, --slanted
            }

        elseif block == Enum.CellBlock.CornerWedge then
            --top corner wedge
            --4 verts
            verts = {
                pos +xvec*2  +yvec*2  -zvec*2, --top 1
                --
                pos +xvec*2  -yvec*2  -zvec*2, --bottom 3
                pos +xvec*2  -yvec*2  +zvec*2,
                pos -xvec*2  -yvec*2  -zvec*2,
            }
            --6 edges
            edges = {
                {verts[1], verts[2], 3},
                {verts[1], verts[3], 3},
                {verts[1], verts[4], 3},
                {verts[2], verts[3], 3},
                {verts[2], verts[4], 3},
                {verts[3], verts[4], 3},
            }
            local centerXZ = ((verts[3]+verts[4])/2 + verts[2])/2
            local slantCenter = Vector3.new(centerXZ.x, pos.y, centerXZ.z)
            local slantFaceDir = ((zvec-xvec).unit*2 + Vector3.new(0, math.sqrt(2), 0)).unit
            --4 faces
            faces = {
                {centerXZ, -yvec, xvec, {verts[2], verts[3], verts[4]}},
                {pos + xvec*2,  xvec, yvec, {verts[1], verts[2], verts[3]}},
                {pos - zvec*2, -zvec, yvec, {verts[1], verts[2], verts[4]}},
                {slantCenter, slantFaceDir, (xvec+zvec).unit, {verts[1], verts[3], verts[4]}},
            }

        elseif block == Enum.CellBlock.InverseCornerWedge then
            --block corner cut
            --7 vertices
            verts = {
                pos +xvec*2  +yvec*2  +zvec*2, --top 3
                pos +xvec*2  +yvec*2  -zvec*2,
                pos -xvec*2  +yvec*2  -zvec*2,
                --
                pos +xvec*2  -yvec*2  +zvec*2, --bottom 4
                pos +xvec*2  -yvec*2  -zvec*2,
                pos -xvec*2  -yvec*2  +zvec*2,
                pos -xvec*2  -yvec*2  -zvec*2,
            }
            --12 edges
            edges = {
                {verts[1], verts[2], 4}, --top 4
                {verts[2], verts[3], 4},
                --
                {verts[4], verts[5], 4}, --bottom 4
                {verts[6], verts[7], 4},
                {verts[4], verts[6], 4},
                {verts[5], verts[7], 4},
                --
                {verts[1], verts[4], 4}, --verticals
                {verts[2], verts[5], 4},
                {verts[3], verts[7], 4},
                --
                {verts[1], verts[3], 2.5}, --slants
                {verts[1], verts[6], 2.5},
                {verts[3], verts[6], 2.5},
            }
            --7 faces
            local centerXZ = ((verts[4]+verts[7])/2 + verts[6])/2
            local slantCenter = Vector3.new(centerXZ.x, pos.y, centerXZ.z)
            local slantFaceDir = ((zvec-xvec).unit*2 + Vector3.new(0, math.sqrt(2), 0)).unit
            faces = {
                {pos+xvec*2,  xvec, zvec, {verts[1], verts[2], verts[5], verts[4]} }, --right
                {pos-xvec*2, -xvec, zvec, {verts[3], verts[7], verts[6]}           }, --left
                {pos+yvec*2,  yvec, xvec, {verts[1], verts[2], verts[3]}           }, --top
                {pos-yvec*2, -yvec, xvec, {verts[4], verts[5], verts[7], verts[6]} }, --bottom
                {pos+zvec*2,  zvec, xvec, {verts[1], verts[6], verts[4]}           }, --back
                {pos-zvec*2, -zvec, xvec, {verts[2], verts[3], verts[7], verts[5]} }, --front
                {slantCenter, slantFaceDir, (xvec+zvec).unit, {verts[1], verts[3], verts[6]}}, --slant
            }

        elseif block == Enum.CellBlock.HorizontalWedge then
            --block side wedge
            --6 vertices
            verts = {
                pos +xvec*2  +yvec*2  +zvec*2, --top 4
                pos +xvec*2  +yvec*2  -zvec*2,
                pos -xvec*2  +yvec*2  -zvec*2,
                --
                pos +xvec*2  -yvec*2  +zvec*2, --bottom 4
                pos +xvec*2  -yvec*2  -zvec*2,
                pos -xvec*2  -yvec*2  -zvec*2,
            }
            --9 edges
            edges = {
                {verts[1], verts[2], 4}, --top 4
                {verts[2], verts[3], 4},
                --
                {verts[4], verts[5], 4}, --bottom 4
                {verts[5], verts[6], 4},
                --
                {verts[1], verts[4], 4}, --verticals
                {verts[2], verts[5], 4},
                {verts[3], verts[6], 4},
                --
                {verts[1], verts[3], 2.5}, --slants
                {verts[4], verts[6], 2.5},
            }
            --5 faces
            faces = {
                {pos+xvec*2,  xvec, zvec, {verts[1], verts[2], verts[5], verts[4]} }, --right
                {pos+yvec*2,  yvec, xvec, {verts[1], verts[2], verts[3]}           }, --top
                {pos-yvec*2, -yvec, xvec, {verts[4], verts[5], verts[6]}           }, --bottom
                {pos-zvec*2, -zvec, xvec, {verts[2], verts[3], verts[6], verts[5]} }, --front
                {pos, (zvec-xvec).unit, yvec, {verts[1], verts[3], verts[4], verts[6]}}, --slant
            }

        else
            assert(false, "unreachable")
        end
    else
        assert(false, "Bad shape: "..shape)
    end
    --
    local geometry = {
        part = part;
        vertices = verts;
        edges = edges;
        faces = faces;
        vertexMargin = vertexMargin or math.min(sx, sy, sz)*2;
        cframe = cf;
    }
    --
    local geomId = 0
    --
    for _, dat in pairs(faces) do
        geomId = geomId + 1
        dat.id = geomId
        dat.point = dat[1]
        dat.normal = dat[2]
        dat.direction = dat[3]
        dat.vertices = dat[4]
        dat.part = part
        dat.type = "Face"
        --avoid Event bug (if both keys + indicies are present keys are discarded when passing tables)
        dat[1], dat[2], dat[3], dat[4] = nil, nil, nil, nil
    end
    for _, dat in pairs(edges) do
        geomId = geomId + 1
        dat.id = geomId
        dat.a, dat.b = dat[1], dat[2]
        dat.direction = (dat.b-dat.a).unit
        dat.length = (dat.b-dat.a).Magnitude
        dat.edgeMargin = dat[3]
        dat.part = part
        dat.vertexMargin = geometry.vertexMargin
        dat.type = "Edge"
        --avoid Event bug (if both keys + indicies are present keys are discarded when passing tables)
        dat[1], dat[2], dat[3] = nil, nil, nil
    end
    for i, dat in pairs(verts) do
        geomId = geomId + 1
        verts[i] = {
            position = dat;
            id = geomId;
            ignoreUnlessNeeded = IsSmoothPart(part);
            type = "Vertex";
        }
    end
    --
    return geometry
end

lib.GetGeometry = GetGeometry

local function getNormal(face)
    return face.normal
end
lib.getNormal = getNormal

local function close(a, b)
    return (a - b).Magnitude < 0.001
end
lib.close = close

return lib