Still a lot left to do, but this should be better. It now just grabs all parts on the file, nukes the entire file and places them back in order. So all submodels and steps etc. will be removed.
Still need to fix the packing and overlap but no need to do anything to the model anymore. Just hit the button. Also no need to select anything. Will also prompt for target size and direction
Still need to fix the packing and overlap but no need to do anything to the model anymore. Just hit the button. Also no need to select anything. Will also prompt for target size and direction
Code:
function getSubfileDimensions(subfile)
local minVec = subfile:getBoundingBoxMin()
local maxVec = subfile:getBoundingBoxMax()
return maxVec:getX() - minVec:getX(), minVec:getY(), maxVec:getZ() - minVec:getZ() -- Return width, minY, and depth
end
function sortSubfiles(a, b)
local widthA, _, depthA = getSubfileDimensions(a.sf)
local widthB, _, depthB = getSubfileDimensions(b.sf)
local sizeA = widthA * depthA
local sizeB = widthB * depthB
if sizeA ~= sizeB then
return sizeA < sizeB
end
local nameA = a.sf:getFileName()
local nameB = b.sf:getFileName()
if nameA ~= nameB then
return nameA < nameB
end
return a.color < b.color
end
function buildFlatList(parentSf, parentPosOri, list)
local cnt = parentSf:getRefCount()
for i = 1, cnt do
local ref = parentSf:getRef(i)
local sf = ref:getSubfile()
local absPosOri = ref:getPosOri() * parentPosOri
if sf:isPart() then
table.insert(list, {
ref = ref,
pos = absPosOri:getPos(),
color = ref:getColor(),
sf = sf
})
elseif not sf:isGenerated() then
buildFlatList(sf, absPosOri, list)
end
end
end
function deleteAllLines(mainSf)
for i = mainSf:getLineCount(), 1, -1 do
local line = mainSf:getLine(i)
line:delete()
end
end
function knollingLayout()
local ses = ldc.session()
if not ses:isLinked() then
ldc.dialog.runMessage('No active model.')
return
end
-- Ask for the target width in LDU
local maxRowSize = tonumber(ldc.dialog.runInput('Target width in LDU (minimum 40)?', '2000'))
if maxRowSize == nil or maxRowSize < 40 then
return
end
local layoutDirection = ldc.dialog.runInput('Layout direction (width or depth)', 'depth')
if layoutDirection == nil or (layoutDirection ~= 'depth' and layoutDirection ~= 'width') then
return
end
local list = {}
local mainSf = ldc.subfile()
buildFlatList(mainSf, ldc.matrix(), list)
deleteAllLines(mainSf)
table.sort(list, sortSubfiles)
local spacing = 20
local currentRowSize = 0
local currentRowMaxDim = 0
local mainOffset = 0
local secondaryOffset = 0
local newRefs = {}
for _, item in ipairs(list) do
local newRef = mainSf:addNewRef(item.sf:getFileName())
newRef:setColor(item.color)
local width, minY, depth = getSubfileDimensions(item.sf)
local primarySize, secondarySize
if layoutDirection == 'width' then
primarySize = width
secondarySize = depth
else
primarySize = depth
secondarySize = width
end
if currentRowSize + primarySize + spacing > maxRowSize then
mainOffset = 0
secondaryOffset = secondaryOffset + currentRowMaxDim + spacing
currentRowSize = 0
currentRowMaxDim = 0
end
local pos
if layoutDirection == 'width' then
pos = ldc.vector(mainOffset, 0, secondaryOffset)
else
pos = ldc.vector(secondaryOffset, 0, mainOffset)
end
newRef:setPos(pos)
mainOffset = mainOffset + primarySize + spacing
currentRowSize = currentRowSize + primarySize + spacing
currentRowMaxDim = math.max(currentRowMaxDim, secondarySize + spacing)
table.insert(newRefs, newRef)
end
end
-- Register the macro for the knolling layout
function register()
local macro_lo = ldc.macro('Perform knolling layout')
macro_lo:setHint('Arrange elements densely with even spacing in the XY plane with Z = 0.')
macro_lo:setEvent('run', 'knollingLayout')
end
register()