Creating Multiple Blocks in selected rectangles

Creating Multiple Blocks in selected rectangles

ancrayzy
Advocate Advocate
504 Views
14 Replies
Message 1 of 15

Creating Multiple Blocks in selected rectangles

ancrayzy
Advocate
Advocate

Hi everyone,

I'm looking for lisp that have some step as below:

1. Command Input: The script should start by typing the command "Example".

2. Select Rectangles: The user selects multiple rectangles, each containing objects to be turned into blocks.

3. Enter Prefix: Prompt the user to input a prefix for naming the blocks.

4. Batch Create Blocks: Create blocks for the objects inside each rectangle, naming them sequentially from left to right and top to bottom (e.g., Prefix_1, Prefix_2, etc.).

Has anyone implemented something similar or can provide a sample AutoLISP code to achieve this? Any tips on handling the selection and sorting of rectangles for the naming order would be greatly appreciated.

Screenshot_2.png

0 Likes
Accepted solutions (1)
505 Views
14 Replies
Replies (14)
Message 2 of 15

Sea-Haven
Mentor
Mentor

Don't see to much of a problem if you select the rectangs by layer etc it will be in creation order. Else can sort on X&Y corner.

 

This is really an example as don't know what you want to name them and what sort of sequence number. 

 

; simple make blocks within rectangs
; By AlanH july 2025

(defun c:wow ( / bname co-ord lay lst num plent pts ss)

(setq bname (getstring "\nEnter block name prefic "))

(setq lay (cdr (assoc 8 (entget (car (entsel "\nPick a rectng for layer "))))))

(prompt "select rectangs ")
(setq ss (ssget (list (cons 0 "LWPOLYLINE")(cons 8 lay))))

(setq lst '())
(setq num 0)

(repeat (setq x (sslength ss))
  (setq plent (ssname ss (setq x (1- x))))
  (setq co-ord (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 10)) (entget plent))))
  (setq lst (cons (list (car co-ord)(caddr co-ord)) lst))
)

(command "-layer" "off" lay "")

(foreach pts lst
  (command "-block" (strcat bname "-" (rtos (setq num (1+ num)) 2 0)) (car pts) "CP" pts "" "")
  (command "insert" (strcat bname "-" (rtos num 2 0)) (car pts) 1 1 0)
)

(command "-layer" "on" lay "")

(princ)
)

 

 

Message 3 of 15

ancrayzy
Advocate
Advocate

Thank @Sea-Haven  for your support. I’ve tested the LISP you created, but unfortunately, it still doesn’t work for me. That said, it’s very helpful, and since I don’t have much knowledge of AutoLISP, I asked Grok to help improve it. Now, it works reasonably well for my current needs, though it’s still not exactly what I was hoping for.

 

I’d like to share it again in case you or someone else can help further improve it, so that others facing similar situations might benefit as well.

 

The main reason I’m not fully satisfied is that after selecting a rectangle to set the layer, the lisp automatically selects all rectangles in the drawing on that layer. It doesn’t allow the user to manually choose a specific area containing the rectangles to be processed. Additionally, the block creation direction seems random rather than following a consistent order along the X-axis and then the negative Y-axis.

 

; Create blocks from objects within rectangles
; Improved from AlanH's idea | July 2025

(defun c:wow (/ bname lay ss num x entname plobj co-ord minpt maxpt insertpt blkname innerSS)
  (vl-load-com) ; Load ActiveX automation
  (setvar "CMDECHO" 0) ; Turn off command echo

  ;; Prompt for block name prefix
  (while (not (setq bname (getstring t "\nEnter block name prefix: ")))
    (princ "\nBlock name cannot be empty."))
  (if (= bname "") (setq bname "BLOCK")) ; Set default name if empty

  ;; Select a sample rectangle to get layer
  (while (not (and (setq entname (entsel "\nPick a rectangle to get layer: "))
                   (setq entdata (entget (car entname)))
                   (= (cdr (assoc 0 entdata)) "LWPOLYLINE")))
    (princ "\nPlease select a valid LWPOLYLINE (rectangle)."))
  (setq lay (cdr (assoc 8 entdata)))

  ;; Select all LWPOLYLINEs on the specified layer
  (princ "\nSelecting rectangles...")
  (setq ss (ssget "_X" (list (cons 0 "LWPOLYLINE") (cons 8 lay))))
  (if (not ss)
    (progn
      (princ "\nNo rectangles found on layer.")
      (setvar "CMDECHO" 1)
      (princ)
      (exit)
    )
  )

  (setq num 0)
  (setq x 0)

  ;; Turn off the layer containing rectangles
  (vl-cmdf "-layer" "off" lay "")

  ;; Loop through each rectangle
  (while (< x (sslength ss))
    (setq plobj (ssname ss x))
    (setq co-ord (mapcar 'cdr (vl-remove-if-not
                                '(lambda (x) (= (car x) 10))
                                (entget plobj))))
    ;; Check if the polyline is a rectangle (4 vertices)
    (if (= (length co-ord) 4)
      (progn
        ;; Determine min and max points
        (setq minpt (list (apply 'min (mapcar 'car co-ord))
                          (apply 'min (mapcar 'cadr co-ord))))
        (setq maxpt (list (apply 'max (mapcar 'car co-ord))
                          (apply 'max (mapcar 'cadr co-ord))))
        ;; Calculate midpoint for block insertion
        (setq insertpt (mapcar '(lambda (a b) (/ (+ a b) 2.0)) minpt maxpt))

        ;; Find all objects inside the rectangle
        (setq innerSS (ssget "_CP" (list minpt
                                         (list (car maxpt) (cadr minpt))
                                         maxpt
                                         (list (car minpt) (cadr maxpt))
                                         minpt)))
        ;; Remove the rectangle polyline from the selection set
        (if innerSS
          (progn
            (ssdel plobj innerSS)
            (if (> (sslength innerSS) 0)
              (progn
                (setq num (1+ num))
                (setq blkname (strcat bname "-" (itoa num)))
                ;; Check if block already exists
                (if (tblobjname "BLOCK" blkname)
                  (princ (strcat "\nBlock " blkname " already exists. Skipping."))
                  (progn
                    ;; Create block
                    (vl-cmdf "-block" blkname insertpt innerSS "")
                    ;; Insert block
                    (vl-cmdf "insert" blkname insertpt 1 1 0)
                  )
                )
              )
            )
          )
        )
      )
      (princ "\nWarning: Polyline is not a rectangle (does not have 4 vertices).")
    )
    (setq x (1+ x))
  )

  ;; Turn on the layer containing rectangles
  (vl-cmdf "-layer" "on" lay "")
  (setvar "CMDECHO" 1)
  (princ)
)
0 Likes
Message 4 of 15

Sea-Haven
Mentor
Mentor

Have a look at Lee-mac Selection reference well worth while. https://www.lee-mac.com/ssget.html

 

Simple answer to your question.

 

(setq ss (ssget "_X" selects every instance within ALL of the dwg including layouts

(setq ss (ssget needs you to select when "X" removed

 

As you implied always rectangs no need to check is 4 points, yes use midpoint.

 

 

Message 5 of 15

pbejse
Mentor
Mentor

@ancrayzy wrote:

2. Select Rectangles: The user selects multiple rectangles, each containing objects to be turned into blocks.

3. Enter Prefix: Prompt the user to input a prefix for naming the blocks.

4. Batch Create Blocks: Create blocks for the objects inside each rectangle, naming them sequentially from left to right and top to bottom (e.g., Prefix_1, Prefix_2, etc.).


And what of the Insertion point? Lower left? Center of the rectangle as shown on your diagram?

Message 6 of 15

ancrayzy
Advocate
Advocate

Hi @Sea-Haven 

With limited knowledge of lisp, I cannot apply your answer to fix lisp. I use Grok but the generated lisps are still unusable so I do not use them.

 

Hi @pbejse 

The insertion point can be the center of the rectangle if possible. Or the center or the left or bottom of the block is the best option (because in my case this doesn't matter).

 

0 Likes
Message 7 of 15

pbejse
Mentor
Mentor

@ancrayzy wrote:

Hi @pbejse 

The insertion point can be the center of the rectangle if possible. Or the center or the left or bottom of the block is the best option (because in my case this doesn't matter).

 


We will try Center insertion point for now

(defun c:TurnMeToABlock ( / ThePointsOfRectangle objectSelection BlockNamePrefix dataFromPolyline blockNameIncrement increment
			 boxedSelection boxCollection newName selectionFromBox)
(defun ThePointsOfRectangle (e / coordinates)
  (foreach itm (entget e)
    (if (= (car itm) 10)
      	(setq coordinates (cons (Cdr itm) coordinates))))
  (list  coordinates (mapcar '(lambda (a b) (* (+ a b) 0.5)) (car coordinates)(caddr coordinates))))
  
  
  
  (if (and
	(setq objectSelection (ssget '((0 . "LWPOLYLINE")(8 . "Rectagle")(90 . 4)))) ;<-- Rectagle was taken from your example drawing
	(setq BlockNamePrefix (getstring "\nEnter Block name prefix: "))
	(/= BlockNamePrefix "")
	)
     (progn
       (setq blockNameIncrement 0)
    	(repeat (Setq increment (sslength objectSelection))
	  
	      	(setq dataFromPolyline  (ThePointsOfRectangle (ssname objectSelection (Setq increment (1- increment)))))
		(Setq boxedSelection (ssget "CP" (car dataFromPolyline)'((8 . "~Rectagle"))))
	      	(setq boxCollection (cons (list (cadr dataFromPolyline) boxedSelection) boxCollection)))

    (foreach box (vl-sort boxCollection '(lambda (a b)
				         (if (equal (caar a) (caar b) 1e-6)
				           (> (cadar a) (cadar b))(> (cadar a) (cadar b))
				         )))
      (while (tblsearch "BLOCK"
		      (setq newName (strcat BlockNamePrefix "_"
					    (itoa (setq	blockNameIncrement
							 (1+ blockNameIncrement
							 )
						  )
					    )
				    )
		      )
	     )
	(princ (strcat "\nBlock name " newName " already exists."))
	)
      	(Setq selectionFromBox (cadr box))
	      (entmake
	                (list
	                   '(0 . "BLOCK") (cons 10 (trans (car box)  1 0))
	                    (cons 02 newName) (cons 70 0))
	                )
      	      
	      (repeat (setq i (sslength selectionFromBox))
	                (entmake (entget (setq e (ssname selectionFromBox (setq i (1- i))))))
	                (entdel e)
	            )
      (if (setq newName (entmake '((0 . "ENDBLK"))))
                (entmake
                    (list '(0 . "INSERT")
                        (cons 02 newName)
                        (cons 10 (trans (car box) 1 0))
                    )
                )
            )
      )
       )
    )
  (princ)
  )

 

Message 8 of 15

Sea-Haven
Mentor
Mentor

@ancrayzy you can see in Pbejse code there is no "_X" in the ssget which is what I said to do. I added the pick a rectangle as the layer name is odd, possibly spelt wrong,  "RECTANGLE" and you may use different layer names. 

Message 9 of 15

ancrayzy
Advocate
Advocate

hi @pbejse ,

I tried your lisp and it work good but in some cases some objects in some rectangles are deleted and do not make a block (all rectangles are the same).

I have attached file autocad example for the above error (as picture below).

 

Screenshot_7.png

0 Likes
Message 10 of 15

pbejse
Mentor
Mentor
Accepted solution

@ancrayzy wrote:

hi @pbejse ,

I tried your lisp and it work good but in some cases some objects in some rectangles are deleted and do not make a block (all rectangles are the same).


There seems to be issues with entmake function on some type of entities like a SPLINE, here's a quick mod using Vlisp

(defun c:TurnMeToABlock ( / ThePointsOfRectangle objectSelection BlockNamePrefix dataFromPolyline blockNameIncrement increment
			 boxedSelection boxCollection newName aDoc selectionFromBox space vlObject vlObjects newBlock)
(defun ThePointsOfRectangle (e / coordinates)
  (foreach itm (entget e)
    (if (= (car itm) 10)
      	(setq coordinates (cons (Cdr itm) coordinates))))
  (list  coordinates (mapcar '(lambda (a b) (* (+ a b) 0.5)) (car coordinates)(caddr coordinates))))
  
  (setq aDoc (vla-get-activedocument (vlax-get-acad-object))
	space (vlax-get (vla-get-ActiveLayout aDoc) 'Block))
  
  (if (and
	(setq objectSelection (ssget '((0 . "LWPOLYLINE")(8 . "Rectagle")(90 . 4)))) ;<-- Rectagle was taken from your example drawing
	(setq BlockNamePrefix (getstring "\nEnter Block name prefix: "))
	(/= BlockNamePrefix "")
	)
     (progn
       (setq blockNameIncrement 0)
    	(repeat (Setq increment (sslength objectSelection))
	  
	      	(setq vlObjects nil dataFromPolyline  (ThePointsOfRectangle (ssname objectSelection (Setq increment (1- increment)))))
		(Setq boxedSelection (ssget "CP" (car dataFromPolyline)'((8 . "~Rectagle"))))
		(repeat (setq i (sslength boxedSelection))
				(setq vlObjects (cons (vlax-ename->vla-object (ssname boxedSelection (setq i (1- i))))
									vlObjects))		
			)
	      	(setq boxCollection (cons (list (cadr dataFromPolyline) vlObjects ) boxCollection)))

    (foreach box (vl-sort boxCollection '(lambda (a b)
					   (Cond
					     ((< (caar a)(caar b)) T)
					     ((equal (caar a) (caar b) 1e-6)(> (cadar a) (cadar b))
					     ))))
					     
				
      (while (tblsearch "BLOCK"
		      (setq newName (strcat BlockNamePrefix "_"
					    (itoa (setq	blockNameIncrement
							 (1+ blockNameIncrement
							 )
						  )
					    )
				    )
		      )
	     )
	(princ (strcat "\nBlock name " newName " already exists."))
	)
      
      (and
	(progn
		(vlax-invoke aDoc 'copyobjects (cadr box)
		  (setq newBlock (vlax-invoke (vla-get-blocks aDoc) 'add (trans (car box)  1 0) newName)))
	        (vlax-invoke space 'insertblock (trans (car box)  1 0) (vla-get-name newBlock) 1.0 1.0 1.0 0.0
	            )      
         (foreach itm (cadr box) (vla-delete itm))	  
	  )
      )
       )
    )
    )
  (princ)
  )

HTH

0 Likes
Message 11 of 15

Sea-Haven
Mentor
Mentor

Because I used a different method than @pbejse I make 18 blocks in one go, it is using command but it made the 18 blocks almost instantly, yes the @pbejse is better when dealing with lots of objects.. You just need to work out the correct insertion point wanted as suggested the centre point.

Message 12 of 15

ancrayzy
Advocate
Advocate

Is there a limit to the number of rectangles this LISP can handle?
It worked with the Trees.dwg file I uploaded, but failed when I tried it with a larger number of rectangles (for examle 225 rectangles as attached file).

0 Likes
Message 13 of 15

pbejse
Mentor
Mentor

Good catch @ancrayzy 

I was today years old when i learned that there's such a thing as "exceeded maximum number of selection sets"

 

Code at post #10 updated [ edited to account for the selection sets issue ]

Message 14 of 15

ancrayzy
Advocate
Advocate

Many thanks to @pbejse , the lisp at post #10 working perfectly.

Message 15 of 15

pbejse
Mentor
Mentor

@ancrayzy wrote:

Many thanks to @pbejse , the lisp at post #10 working perfectly.


 

You are welcome, glad it helps.