lispautocadautolisp

AutocadLisp - let variable argument definition mistaken as e function


I've never used LISP before and I'm using AI to try to create simple automations for autocad so I can speedup the proccess. Everything works fine to the point where I have a let expression which takes as an argument list of variables for initialization but the second variable is mistaken for a function and thus when I try to run the script in AutoCad I get the following error:

Command: CASING
Enter offset value: 18
Do you want the offset vertical lines to span from the bottom line to the top line of the rectangle? (Y/N): y
Do you want the offset horizontal lines to span from the left line to the right line of the rectangle? (Y/N): y
Getting selection set
Filtering rectangles
Adding entity: <Entity name: 2889a984ea0>
Vertices: ((39.7611 42.9035) (174.28 42.9035) (174.28 220.962) (39.7611 220.962))
In the if ; error: no function definition: BOTTOM-RIGHT

Here is my lisp script:

(defun c:casing (/ ss rectangles i ent entData coords all-vertices offset vertical-span horizontal-span)
  ;; Load Visual LISP extension functions
  (vl-load-com)

  ;; Function to count vertices of a polyline
  (defun get-vertex-count (ent)
    (cond
      ((= (cdr (assoc 0 ent)) "LWPOLYLINE")
       (length (vl-remove-if-not '(lambda (x) (= (car x) 10)) ent)))
      ((= (cdr (assoc 0 ent)) "POLYLINE")
       (let ((count 0) (vertex (entnext ent)))
         (while (and vertex (= (cdr (assoc 0 (entget vertex))) "VERTEX"))
           (setq count (1+ count))
           (setq vertex (entnext vertex)))
         count))
      (t 0)))

  ;; Function to sort vertices in a consistent order
  (defun sort-vertices (vertices)
    ;; Sort vertices by y-coordinate, then by x-coordinate
    (setq vertices (vl-sort vertices (function (lambda (a b)
                                                 (if (/= (cadr a) (cadr b))
                                                     (< (cadr a) (cadr b))
                                                   (< (car a) (car b)))))))
    ;; Ensure the order is bottom-left, bottom-right, top-right, top-left
    (if (> (car (nth 1 vertices)) (car (nth 0 vertices)))
        (setq vertices (list (nth 0 vertices) (nth 1 vertices) (nth 3 vertices) (nth 2 vertices)))
      (setq vertices (list (nth 1 vertices) (nth 0 vertices) (nth 2 vertices) (nth 3 vertices))))
    vertices)

  ;; Prompt for offset value
  (setq offset (getreal "\nEnter offset value: "))

  ;; Prompt for vertical span
  (setq vertical-span (getstring "\nDo you want the offset vertical lines to span from the bottom line to the top line of the rectangle? (Y/N): "))

  ;; Prompt for horizontal span
  (setq horizontal-span (getstring "\nDo you want the offset horizontal lines to span from the left line to the right line of the rectangle? (Y/N): "))

  ;; Get pre-selected objects or prompt for selection
  (princ "\nGetting selection set")
  (setq ss (ssget "_I"))
  (if (null ss)
    (setq ss (ssget)))
  (if (null ss)
    (progn
      (alert "No objects selected! Select rectangles before running the command.")
      (exit)))

  ;; Filter rectangles
  (princ "\nFiltering rectangles")
  (setq rectangles '())
  (setq all-vertices '())
  (setq i 0)
  (while (< i (sslength ss))
    (setq ent (ssname ss i))
    (setq entData (entget ent))
    (if (and (= (cdr (assoc 0 entData)) "LWPOLYLINE")
             (= (cdr (assoc 70 entData)) 1)
             (= (get-vertex-count entData) 4))
      (progn
        (princ "\nAdding entity: ") (princ ent)
        (setq rectangles (cons ent rectangles))
        (setq coords (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 10)) entData)))
        (setq coords (sort-vertices coords))
        (setq all-vertices (cons coords all-vertices))))
    (setq i (1+ i)))

  (if (null rectangles)
    (progn
      (alert "No rectangles selected!")
      (exit)))

  ;; Create offset lines
  (foreach vertices all-vertices
    (princ "\nVertices: ") (princ vertices)
    (if (= (length vertices) 4)
      (progn
        (princ "\nIn the if ")
        (let ((bottom-left (nth 0 vertices))
              (bottom-right (nth 1 vertices))
              (top-right (nth 2 vertices))
              (top-left (nth 3 vertices)))
          (princ "\nAfter foreach")
          (princ "\nBottom-left: ") (princ bottom-left)
          (princ "\nBottom-right: ") (princ bottom-right)
          (princ "\nTop-right: ") (princ top-right)
          (princ "\nTop-left: ") (princ top-left)
          ;; Create offset vertical lines
          (if (equal vertical-span "Y" t)
            (progn
              (princ "\nBefore first line")
              (command "LINE" (list (+ (car bottom-left) offset) (cadr bottom-left)) (list (+ (car top-left) offset) (cadr top-left)) "")
              (princ "\nBefore second line")
              (command "LINE" (list (- (car bottom-right) offset) (cadr bottom-right)) (list (- (car top-right) offset) (cadr top-right)) ""))
            (progn
              (command "LINE" (list (+ (car bottom-left) offset) (cadr bottom-left)) (list (+ (car bottom-left) offset) (cadr top-left)) "")
              (command "LINE" (list (- (car bottom-right) offset) (cadr bottom-right)) (list (- (car bottom-right) offset) (cadr top-right)) "")))
          ;; Create offset horizontal lines
          (if (equal horizontal-span "Y" t)
            (progn
              (command "LINE" (list (car bottom-left) (+ (cadr bottom-left) offset)) (list (car bottom-right) (+ (cadr bottom-right) offset)) "")
              (command "LINE" (list (car top-left) (- (cadr top-left) offset)) (list (car top-right) (- (cadr top-right) offset)) ""))
            (progn
              (command "LINE" (list (car bottom-left) (+ (cadr bottom-left) offset)) (list (car bottom-right) (+ (cadr bottom-left) offset)) "")
              (command "LINE" (list (car top-left) (- (cadr top-left) offset)) (list (car top-right) (- (cadr top-left) offset)) "")))))
      (princ "\nError: Vertices list does not contain exactly 4 elements.")))

  ;; Output the vertices coordinates
  (princ "\nVertices coordinates of selected rectangles: ")
  (foreach vertices all-vertices
    (princ "\nRectangle vertices: ") (princ vertices))

  (princ "\nDone processing")
  (princ))

The issue appears to be at line 81: (bottom-right (nth 1 vertices))

I checked the syntax multiple times. I checkt parentheses but everything seems fine for me. Used 3 different AI's to find the issue with no luck. Everything else except this part works as expected and I can't seem to figure out why. I checked the flow algorithm flow and syntax. Even got acquainted with the syntax and learned a little bit about lisp and how it works.


Solution

  • AutoLISP doesn't use let to bind local variables. Instead, you declare them after / in the parameter list, and then assign them. So add those four variables to the parameter list of c:casing, and then use

    (setq bottom-left (nth 0 vertices)
          bottom-right (nth 1 vertices)
          top-right (nth 2 vertices)
          top-left (nth 3 vertices))