[CAD LISP] Arrange Lighting Fixtures Perfectly with the Adaptive Grid Layout (FAR.lsp)
When drafting in AutoCAD, arranging lighting fixtures or sensors within a
designated ceiling boundary is one of those tasks that feels deceptively
simple but drains your time. Doing this manually—calculating the distances,
drawing temporary construction lines, offsetting offsets, and then using the
MOVE or ALIGN command for every single fixture—is an absolute chore.
If you have dozens of rooms to complete, this repetitive math and alignment
process slows down your workflow to a crawl. Even worse, human error often
creeps in, leaving fixtures slightly off-center or unevenly spaced. That is
why automating this process with a dedicated routine is essential for any
professional drafter looking to maintain speed, precision, and sanity.
Why You Should Use the 'FAR' LISP
- Perfect 1:2:1 Proportional Spacing: It automatically applies the golden layout rule for fixture placement (half-space from walls, full-space between fixtures), ensuring a visually balanced and compliant layout every time.
- Smart Boundary Adaptation: Whether your room is wide or long, the LISP automatically detects the dominant dimension (width vs. height) and groups/aligns your selected fixtures accordingly.
- Zero Manual Math: No more breaking out the calculator to divide room lengths by the number of fixtures. Just pick your boundary, and the LISP does the heavy lifting.
- Visual Verification: Once the arrangement is done, the tool draws a subtle guide line across the boundary corners, giving you an instant visual confirmation that the operation was executed perfectly.
How It Works (Step-by-Step Guide)
- Load the LISP File: Load the FAR.lsp file into AutoCAD using the APPLOAD command.
- Run the Command: Type FAR in the command line and press Enter.
- Select Fixtures: Select all the lighting fixtures or blocks you want to arrange, then press Enter.
- Specify the Boundary: * Click to specify the first corner of your layout boundary (e.g., the top-left corner of a room).
- Click to specify the opposite corner of the boundary (e.g., the bottom-right corner).
- Instant Execution: The LISP instantly calculates the bounding boxes of your objects, sorts them into rows or columns based on the room's aspect ratio, and snaps them into a clean, mathematically perfect grid.
Wrapping Up
The FAR LISP is a game-changer for electrical draftsmen and interior
lighting designers. By reducing a multi-step drafting and calculation
process into a simple select-and-click routine, you can keep your
momentum focused on actual design rather than fighting with the grid.
Here’s a LISP you can add to your startup suite. It’ll save you a ton of
alignment headaches today. Let me know if you run into any bugs.
The LISP Code
(defun c:FAR ( / acadObj doc space ss p1_ucs p2_ucs p1 p2 minX maxX minY maxY totalW totalH cX cY cnt i ent vla-obj minpt maxpt cenX cenY items tol rows current_row numR r unitY row numC unitX targetY c item targetX cols current_col startPt endPt lineObj )
(vl-load-com)
(setq acadObj (vlax-get-acad-object)
doc (vla-get-activedocument acadObj)
space (vla-get-modelspace doc))
(princ "\nSelect objects to arrange: ")
(if (and (setq ss (ssget))
(setq p1_ucs (getpoint "\nSpecify first corner of boundary: "))
(setq p2_ucs (getcorner p1_ucs "\nSpecify opposite corner of boundary: ")))
(progn
(vla-StartUndoMark doc)
(setq p1 (trans p1_ucs 1 0)
p2 (trans p2_ucs 1 0)
minX (min (car p1) (car p2))
maxX (max (car p1) (car p2))
minY (min (cadr p1) (cadr p2))
maxY (max (cadr p1) (cadr p2))
totalW (- maxX minX)
totalH (- maxY minY)
cX (/ (+ minX maxX) 2.0)
cY (/ (+ minY maxY) 2.0)
cnt (sslength ss)
i 0
items nil)
(repeat cnt
(setq ent (ssname ss i)
vla-obj (vlax-ename->vla-object ent))
(vla-getboundingbox vla-obj 'minpt 'maxpt)
(setq minpt (vlax-safearray->list minpt)
maxpt (vlax-safearray->list maxpt)
cenX (/ (+ (car minpt) (car maxpt)) 2.0)
cenY (/ (+ (cadr minpt) (cadr maxpt)) 2.0)
items (cons (list cenX cenY vla-obj) items)
i (1+ i))
)
(if (>= totalW totalH)
(progn
(setq tol (* totalH 0.1)
items (vl-sort items '(lambda (a b) (> (cadr a) (cadr b))))
rows nil
current_row nil)
(foreach item items
(if (null current_row)
(setq current_row (list item))
(if (< (abs (- (cadr item) (cadr (car current_row)))) tol)
(setq current_row (cons item current_row))
(progn
(setq rows (cons (vl-sort current_row '(lambda (a b) (< (car a) (car b)))) rows)
current_row (list item))
)
)
)
)
(if current_row
(setq rows (cons (vl-sort current_row '(lambda (a b) (< (car a) (car b)))) rows))
)
(setq rows (reverse rows)
numR (length rows)
r 1
unitY (/ totalH (* 2.0 numR)))
(foreach row rows
(setq numC (length row)
unitX (/ totalW (* 2.0 numC))
targetY (- maxY (* (- (* 2.0 r) 1.0) unitY))
c 1)
(foreach item row
(setq vla-obj (caddr item)
targetX (+ minX (* (- (* 2.0 c) 1.0) unitX)))
(vla-move vla-obj (vlax-3d-point (list (car item) (cadr item) 0.0)) (vlax-3d-point (list targetX targetY 0.0)))
(setq c (1+ c))
)
(setq r (1+ r))
)
)
(progn
(setq tol (* totalW 0.1)
items (vl-sort items '(lambda (a b) (< (car a) (car b))))
cols nil
current_col nil)
(foreach item items
(if (null current_col)
(setq current_col (list item))
(if (< (abs (- (car item) (car (car current_col)))) tol)
(setq current_col (cons item current_col))
(progn
(setq cols (cons (vl-sort current_col '(lambda (a b) (> (cadr a) (cadr b)))) cols)
current_col (list item))
)
)
)
)
(if current_col
(setq cols (cons (vl-sort current_col '(lambda (a b) (> (cadr a) (cadr b)))) cols))
)
(setq cols (reverse cols)
numC (length cols)
c 1
unitX (/ totalW (* 2.0 numC)))
(foreach col cols
(setq numR (length col)
unitY (/ totalH (* 2.0 numR))
targetX (+ minX (* (- (* 2.0 c) 1.0) unitX))
r 1)
(foreach item col
(setq vla-obj (caddr item)
targetY (- maxY (* (- (* 2.0 r) 1.0) unitY)))
(vla-move vla-obj (vlax-3d-point (list (car item) (cadr item) 0.0)) (vlax-3d-point (list targetX targetY 0.0)))
(setq r (1+ r))
)
(setq c (1+ c))
)
)
)
(setq startPt (vlax-3d-point p1)
endPt (vlax-3d-point p2)
lineObj (vla-addline space startPt endPt))
(vla-put-color lineObj 252)
(vla-EndUndoMark doc)
(princ "\nObjects arranged successfully in adaptive grid layout (1:2:1 ratio).")
)
)
(princ)
)

Post a Comment