Idea for LUA script to create a knolling layout


RE: Idea for LUA script to create a knolling layout
#20
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

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()
Reply
« Next Oldest | Next Newest »



Messages In This Thread
RE: Idea for LUA script to create a knolling layout - by Fredrik Hareide - 2024-10-19, 15:22

Forum Jump:


Users browsing this thread: 1 Guest(s)