Ok, so took a while and got a working script on some occasions.
Functions
(yes I just edited @stravant’s Resize Allign plugin)
function GetGeometry(part, hit)
local cf = 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;
--
if part:IsA('Part') then
if part.Shape == Enum.PartType.Block or part.Shape == Enum.PartType.Cylinder 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 part.Shape == Enum.PartType.Ball 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, {}}
}
else
assert(false, "Bad Part Shape: `"..tostring(part.Shape).."`")
end
elseif part:IsA('CornerWedgePart') 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 part:IsA('WedgePart') 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 part:IsA('Terrain') then
local cellPos = game.Workspace.Terrain:WorldToCellPreferSolid(hit)
local mat, block, orient = game.Workspace.Terrain:GetCell(cellPos.x, cellPos.y, cellPos.z)
local pos = game.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
end
--
local geometry = {
part = part;
vertices = verts;
edges = edges;
faces = faces;
vertexMargin = vertexMargin or math.min(sx, sy, sz)*2;
}
--
local geomId = 0
--
for i, 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.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 i, 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.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 =false;
type = 'Vertex';
}
end
--
return geometry
end
local function rightVector(cf)
local _,_,_,r4,_,_,r7,_,_,r10,_,_ = cf:components()
return Vector3.new(r4,r7,r10)
end
local function leftVector(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 bottomVector(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 frontVector(cf)
local _,_,_,_,_,r6,_,_,r9,_,_,r12 = cf:components()
return Vector3.new(-r6,-r9,-r12)
end
local function otherNormals(dir)
if math.abs(dir.X) > 0 then
return Vector3.new(0, 1, 0), Vector3.new(0, 0, 1)
elseif math.abs(dir.Y) > 0 then
return Vector3.new(1, 0, 0), Vector3.new(0, 0, 1)
else
return Vector3.new(1, 0, 0), Vector3.new(0, 1, 0)
end
end
local function extend(v, amount)
return v.unit * (v.magnitude + amount)
end
local function drawFace(parent, part, normalId, color, trans)
local tb = {}
--
local hsize = part.Size / 2
local faceDir = Vector3.FromNormalId(normalId)
local faceA, faceB = otherNormals(faceDir)
faceDir, faceA, faceB = faceDir*hsize, faceA*hsize, faceB*hsize
--
local function seg(size, cf)
local segment = Instance.new('Part', parent)
segment.BrickColor = color
segment.Anchored = true
segment.Locked = true
segment.Archivable = false
segment.Transparency = trans
segment.TopSurface = 'Smooth'
segment.BottomSurface = 'Smooth'
segment.FormFactor = 'Custom'
segment.Size = size
segment.CFrame = part.CFrame * cf
table.insert(tb, segment)
end
--
seg(extend(faceA, 0.1)*2, CFrame.new(faceDir + faceB))
seg(extend(faceA, 0.1)*2, CFrame.new(faceDir - faceB))
seg(extend(faceB, 0.1)*2, CFrame.new(faceDir + faceA))
seg(extend(faceB, 0.1)*2, CFrame.new(faceDir - faceA))
--
return tb
end
local function getFacePoints(face)
local hsize = face.Object.Size / 2
local faceDir = Vector3.FromNormalId(face.Normal)
local faceA, faceB = otherNormals(faceDir)
faceDir, faceA, faceB = faceDir*hsize, faceA*hsize, faceB*hsize
--
local function sp(offset)
return (face.Object.CFrame * CFrame.new(offset)).p
end
--
return {
sp(faceDir + faceA + faceB);
sp(faceDir + faceA - faceB);
sp(faceDir - faceA - faceB);
sp(faceDir - faceA + faceB);
}
end
local function getPoints(part)
local hsize = part.Size / 2
local cf = part.CFrame
local points = {}
for i = -1, 1, 2 do
for j = -1, 1, 2 do
for k = -1, 1, 2 do
table.insert(points, cf:pointToWorldSpace(Vector3.new(i, j, k) * hsize))
end
end
end
return points
end
local function getNormal(face)
return face.Object.CFrame:vectorToWorldSpace(Vector3.FromNormalId(face.Normal))
end
local function getDimension(face)
local dir = Vector3.FromNormalId(face.Normal)
return Vector3.new(math.abs(dir.X), math.abs(dir.Y), math.abs(dir.Z))
end
function cl0(n)
return (n > 0) and n or 0
end
function RealDistanceFrom(point, part)
local p = part.CFrame:pointToObjectSpace(part.Position)
local hz = part.Size/2
local sep = Vector3.new(cl0(math.abs(p.x)-hz.x), cl0(math.abs(p.y)-hz.y), cl0(math.abs(p.z)-hz.z))
return sep.magnitude
end
function getClosestPointTo(part, points)
local closestDistance = math.huge
local closestPoint = nil
for _, point in pairs(points) do
local dist = RealDistanceFrom(point, part)
if dist < closestDistance then
closestDistance = dist
closestPoint = point
end
end
return closestPoint
end
function getFurthestPointTo(part, points)
local furthestDistance = -math.huge
local furthestPoint = nil
for _, point in pairs(points) do
local dist = RealDistanceFrom(point, part)
if dist > furthestDistance then
furthestDistance = dist
furthestPoint = point
end
end
return furthestPoint
end
-- Get the point in the list most "out" of the face
function getPositivePointToFace(face, points)
local hsize = face.Object.Size / 2
local faceDir = Vector3.FromNormalId(face.Normal)
local faceNormal = face.Object.CFrame:vectorToWorldSpace(faceDir)
local facePoint = face.Object.CFrame:pointToWorldSpace(faceDir * hsize)
--
local maxDist = -math.huge
local maxPoint = nil
for _, point in pairs(points) do
local dist = (point - facePoint):Dot(faceNormal)
if dist > maxDist then
maxDist = dist
maxPoint = point
end
end
return maxPoint
end
function getNegativePointToFace(face, points)
local hsize = face.Object.Size / 2
local faceDir = Vector3.FromNormalId(face.Normal)
local faceNormal = face.Object.CFrame:vectorToWorldSpace(faceDir)
local facePoint = face.Object.CFrame:pointToWorldSpace(faceDir * hsize)
--
local minDist = math.huge
local minPoint = nil
for _, point in pairs(points) do
local dist = (point - facePoint):Dot(faceNormal)
if dist < minDist then
minDist = dist
minPoint = point
end
end
return minPoint
end
function resizePart(part, normal, delta)
local axis = Vector3.FromNormalId(normal)
local cf = part.CFrame
local targetSize = part.Size + Vector3.new(math.abs(axis.X), math.abs(axis.Y), math.abs(axis.Z))*delta
if not part:IsA('FormFactorPart') then
-- Nothing to do, can't modify formfactor anyways
elseif part.FormFactor == Enum.FormFactor.Brick then
if targetSize.X % 1 ~= 0 or targetSize.Y % 1.2 ~= 0 or targetSize.Z % 1 ~= 0 then
part.FormFactor = 'Custom'
end
elseif part.FormFactor == Enum.FormFactor.Symmetric then
if targetSize.X % 1 ~= 0 or targetSize.Y % 1 ~= 0 or targetSize.Z % 1 ~= 0 then
part.FormFactor = 'Custom'
end
elseif part.FormFactor == Enum.FormFactor.Plate then
if targetSize.X % 1 ~= 0 or targetSize.Y % 0.4 ~= 0 or targetSize.Z % 1 ~= 0 then
part.FormFactor = 'Custom'
end
else
-- nothing to do, is custom
end
part:BreakJoints()
part.Size = targetSize
part:BreakJoints()
part.CFrame = cf * CFrame.new(axis * (delta/2))
end
------------------
--IMPLEMENTATION--
------------------
-- Target finding (Taking into account currently selected faces / target filter
-- Hover Face
-- Calculate the result
function DoExtend(faceA, faceB)
--
local pointsA = getFacePoints(faceA)
local pointsB = getFacePoints(faceB)
--
local extendPointA, extendPointB;
extendPointA = getPositivePointToFace(faceB, pointsA)
extendPointB = getPositivePointToFace(faceA, pointsB)
local startSep = extendPointB - extendPointA
--
local localDimensionA = getDimension(faceA)
local localDimensionB = getDimension(faceB)
local dirA = getNormal(faceA)
local dirB = getNormal(faceB)
--
-- Find the closest distance between the rays (extendPointA, dirA) and (extendPointB, dirB):
-- See: http://geomalgorithms.com/a07-_distance.html#dist3D_Segment_to_Segment
local a, b, c, d, e = dirA:Dot(dirA), dirA:Dot(dirB), dirB:Dot(dirB), dirA:Dot(startSep), dirB:Dot(startSep)
local denom = a*c - b*b
-- Is this a degenerate case?
if math.abs(denom) < 0.001 then
-- Parts are parallel, extend faceA to faceB
local lenA = (extendPointA - extendPointB):Dot(getNormal(faceB))
local extendableA = (localDimensionA * faceA.Object.Size).magnitude
if getNormal(faceA):Dot(getNormal(faceB)) > 0 then
lenA = -lenA
end
if lenA < -extendableA then
return
end
resizePart(faceA.Object, faceA.Normal, lenA)
return
end
-- Get the distances to extend by
local lenA = -(b*e - c*d) / denom
local lenB = -(a*e - b*d) / denom
-- Are both extents doable?
-- Note: Negative amounts to extend by *are* allowed, but only
-- up to the size of the part on the dimension being extended on.
local extendableA = (localDimensionA * faceA.Object.Size).magnitude
local extendableB = (localDimensionB * faceB.Object.Size).magnitude
if lenA < -extendableA then
return
end
if lenB < -extendableB then
return
end
-- Both are doable, execute:
resizePart(faceA.Object, faceA.Normal, lenA)
resizePart(faceB.Object, faceB.Normal, lenB)
end
local function getMag(p1,p2)
return (p1 - p2).magnitude
end
local function getPositionFromFace(face, part)
local c = part.CFrame
local rv = c.RightVector
local uv = c.UpVector
local lv = c.LookVector
local s = part.Size / 2
local rightFacePos = Vector3.new(0,rv * s.X,0)
local leftFacePos = Vector3.new(0, rv * -s.X)
local topFacePos = Vector3.new(0, uv * s.Y,0)
local bottomFacePos = Vector3.new(0, uv * -s.Y,0)
local frontFacePos = Vector3.new(0, uv * s.Z,0)
local backFacePos = Vector3.new(0, uv * -s.Z,0)
if face == "Front" then return frontFacePos end if face == "Back" then return backFacePos end if face == "Right" then return rightFacePos end if face == "Left" then return leftFacePos end if face == "Top" then return topFacePos end if face == "Bottom" then return bottomFacePos end
end
Implementation
local startPoint = cframe[1].p
local endpoint = cframe[2].p
local wall = Instance.new("Part")
wall.Size = Vector3.new(10, 0.5, (endPoint - startPoint).Magnitude)
wall.Anchored = true
wall.Name = "Base"
wall.Material = Enum.Material.SmoothPlastic
wall.CFrame = CFrame.new(startPoint, endPoint) * CFrame.Angles(0,0,math.rad(90))
wall.CFrame = wall.CFrame + wall.CFrame.LookVector * ((endPoint - startPoint).Magnitude/2)
local gridPoint = Instance.new("Part")
gridPoint.Size = Vector3.new(10, 0, (endPoint - startPoint).Magnitude)
gridPoint.Anchored = true
gridPoint.CanCollide = false
gridPoint.Name = "GridPoint"
gridPoint.Transparency = 1
gridPoint.Material = Enum.Material.SmoothPlastic
gridPoint.CFrame = wall.CFrame + wall.CFrame.UpVector * 0.55
local model = Instance.new("Model")
model.Parent = plane.ArchitectureHolder
model.Name = "Wall"
wall.Parent = model
gridPoint.Parent = model
model.PrimaryPart = wall
for _, v in pairs(wall:GetTouchingParts()) do
if v.Parent.Name == "Wall" then
local function gN(f)
return Enum.NormalId[f]
end
local f1Pos = getPositionFromFace("Front", wall)
local f2Pos = getPositionFromFace("Front", v)
local b1Pos = getPositionFromFace("Back", wall)
local b2Pos = getPositionFromFace("Back", v)
local closestFace = {"Front", "Front", getMag(f1Pos, f2Pos)}
if closestFace[3] > getMag(f1Pos, b2Pos) then closestFace = {"Front", "Back", getMag(f1Pos, b2Pos)} end
if closestFace[3] > getMag(b1Pos, f2Pos) then closestFace = {"Back", "Front", getMag(b1Pos, f2Pos)} end
if closestFace[3] > getMag(b1Pos, b2Pos)then closestFace = {"Back", "Back", getMag(b1Pos, b2Pos)} end
local face1 = {Object = wall; Normal = gN(closestFace[1])}
local face2 = {Object = v; Normal = gN(closestFace[2])}
print(wall, v, face1.Object, face2.Object)
DoExtend(face1, face2)
end
end
Im just gonna link the game cause its hard to describe. Sometimes when you place 3 touching walls, they all get resized down to like 0.3 studs. And some other times its perfect