Is there a faster way to insert many blocks instead of using the insert command?

Is there a faster way to insert many blocks instead of using the insert command?

jamieq
Collaborator Collaborator
1,291 Views
5 Replies
Message 1 of 6

Is there a faster way to insert many blocks instead of using the insert command?

jamieq
Collaborator
Collaborator

I have a lisp program I built that inserts a pipe size block on all lines of a certain layer, at the midpoint of each line and matching the angle (corrected to prevent upside down sizes). The code, while fairly messy, works just perfectly. The only problem is, when I select large amounts of lines, it takes a long time to insert every block. The situation that prompted me to ask is that I have 1654 lines, and it takes nearly 40 seconds to insert them all. Granted, that's not all that long. But I built this program because I use SprinkCAD (a fire sprinkler design extension for AutoCAD), and their built in function to insert sizes will insert on all 1654 lines in under 1 second. Before anyone asks, the reason I don't user their function and I built my own is because theirs inserts one size on both of the two types of pipe, while mine will insert one size on one type and another size on the other type. I would just like to make mine quicker if I can. My code is below. 

 

 

(defun c:insmanysz (/ ss i sn e p1 p2 ang)
(defun RtD (r) (* 180.0 (/ r pi)))
(defun GetStr (/ rtn)
	(while
		(not
			(and
			(setq rtn (strcase (getstring) T))
			(< (strlen rtn) 3)
			); and
		); not
		(alert "\n2 characters maximum.")
	); while
	rtn
)

(command "undo" "begin")
(setq oReq (getvar "ATTREQ") oDia (getvar "ATTDIA") oLay (getvar "CLAYER") oOsmode (getvar "OSMODE"))
(setvar "ATTREQ" 1)(setvar "ATTDIA" 0)(setvar "CLAYER" "PIPESPC")(setvar "OSMODE" 0)
(if (= sz1 nil)(setq sz1 "4"))
(if (= ty1 nil)(setq ty1 "10"))
(if (= sz2 nil)(setq sz2 "1"))
(if (= ty2 nil)(setq ty2 "40"))
(write-line (strcat "\nMain size: " sz1 ", type: " ty1 ". Branch line size: " sz2 ", and type: " ty2 "."))
(if (and 
	(setq getSet (strcase (getstring "\nType S to change, or enter to start picking.")))
	(= getSet "S"))
(progn	
  (princ (strcat "\nMain pipe size <" sz1 "> : "))
  (setq sz1a (GetStr))
  (if (= sz1a "")(setq sz1a sz1))
  (setq sz1 sz1a)

  (princ (strcat "\nMain pipe type <" ty1 "> : "))
  (setq ty1a (GetStr))
  (if (= ty1a "")(setq ty1a ty1))   
  (setq ty1 ty1a)

  (princ (strcat "\nBranch line pipe size <" sz2 "> : "))
  (setq sz2a (GetStr))
  (if (= sz2a "")(setq sz2a sz2))
  (setq sz2 sz2a)

  (princ (strcat "\nBranch line pipe type <" ty2 "> : "))
  (setq ty2a (GetStr))
  (if (= ty2a "")(setq ty2a ty2))
  (setq ty2 ty2a)
 )
)
  (if (setq ss (ssget '((0 . "LINE")(8 . "PIPEBL,PIPEMN,PIPEBLEX,PIPEMNEX"))))
    (repeat (setq i (sslength ss))
      (setq sn (ssname ss (setq i (1- i))))
      (setq p1 (cdr (assoc 10 (setq e (entget sn)))))
      (setq p2 (cdr (assoc 11 e)))
		(if (or (= (cdr (assoc 8 e)) "PIPEMN")(= (cdr (assoc 8 e)) "PIPEMNEX"))
			(setq sz sz1 ty ty1)
			(setq sz sz2 ty ty2)
		)
       (progn
          (setq ang (RtD (angle p1 p2)))		  
			(cond   ((and (<= ang 90.1)(>= ang 0))(setq ang ang))
					((and (> ang 90.1)(< ang 180))(setq ang (+ ang 180)))
					((and (>= ang 180)(<= ang 270.1))(setq ang (- ang 180)))
					((and (> ang 270.1)(< ang 360))(setq ang ang))
					((= ang 360)(setq ang 0))
					(t)
			)
		  (setq mid (list
			(/ (+ (car p1) (car p2)) 2.0)
			(/ (+ (cadr p1) (cadr p2)) 2.0)
		  ))
        )
		(setq ang (rtos ang 2 1))
			(if (= (substr ang (- (strlen ang) 1) 2) ".0")
				(setq ang (substr ang 1 (- (strlen ang) 2)))
				(setq ang ang)
			)
		(command "-insert" "PIPESPC" mid "1" ang sz ty)
	  
    )
   (princ)
  )
(setvar "ATTREQ" oReq)(setvar "ATTDIA" oDia)(setvar "CLAYER" oLay)(setvar "OSMODE" oOsmode)
(command "undo" "end")
(princ)
)
0 Likes
Accepted solutions (1)
1,292 Views
5 Replies
Replies (5)
Message 2 of 6

Kent1Cooper
Consultant
Consultant
Accepted solution

Using (entmake) instead of (command "_.insert" ...) will be much faster.  You can find example of its use with a Search for  (entmake  and  (0 . "INSERT").

Kent Cooper, AIA
Message 3 of 6

SeeMSixty7
Advisor
Advisor

I really don't understand why your system takes so long to do the insert, but I tried to give you some extra time saving below.

 

You really don't need the RtD function. The below code does not use it.

 

Hopefully this helps some. Good luck,

 

(defun c:insmanysz (/ ss i sn e p1 p2 ang)
(defun RtD (r) (* 180.0 (/ r pi)))
(defun GetStr (/ rtn)
	(while
		(not
			(and
			(setq rtn (strcase (getstring) T))
			(< (strlen rtn) 3)
			); and
		); not
		(alert "\n2 characters maximum.")
	); while
	rtn
)

(command "undo" "begin")
(setq oReq (getvar "ATTREQ") oDia (getvar "ATTDIA") oLay (getvar "CLAYER") oOsmode (getvar "OSMODE"))
(setvar "ATTREQ" 1)(setvar "ATTDIA" 0)(setvar "CLAYER" "PIPESPC")(setvar "OSMODE" 0)
(if (= sz1 nil)(setq sz1 "4"))
(if (= ty1 nil)(setq ty1 "10"))
(if (= sz2 nil)(setq sz2 "1"))
(if (= ty2 nil)(setq ty2 "40"))
(write-line (strcat "\nMain size: " sz1 ", type: " ty1 ". Branch line size: " sz2 ", and type: " ty2 "."))
(if (and 
	(setq getSet (strcase (getstring "\nType S to change, or enter to start picking.")))
	(= getSet "S"))
(progn	
  (princ (strcat "\nMain pipe size <" sz1 "> : "))
  (setq sz1a (GetStr))
  (if (= sz1a "")(setq sz1a sz1))
  (setq sz1 sz1a)

  (princ (strcat "\nMain pipe type <" ty1 "> : "))
  (setq ty1a (GetStr))
  (if (= ty1a "")(setq ty1a ty1))   
  (setq ty1 ty1a)

  (princ (strcat "\nBranch line pipe size <" sz2 "> : "))
  (setq sz2a (GetStr))
  (if (= sz2a "")(setq sz2a sz2))
  (setq sz2 sz2a)

  (princ (strcat "\nBranch line pipe type <" ty2 "> : "))
  (setq ty2a (GetStr))
  (if (= ty2a "")(setq ty2a ty2))
  (setq ty2 ty2a)
 )
)
  (if (setq ss (ssget '((0 . "LINE")(8 . "PIPEBL,PIPEMN,PIPEBLEX,PIPEMNEX"))))
    (repeat (setq i (sslength ss))
      (setq sn (ssname ss (setq i (1- i))))
      (setq p1 (cdr (assoc 10 (setq e (entget sn)))))
      (setq p2 (cdr (assoc 11 e)))
		(if (or (= (cdr (assoc 8 e)) "PIPEMN")(= (cdr (assoc 8 e)) "PIPEMNEX"))
			(setq sz sz1 ty ty1)
			(setq sz sz2 ty ty2)
		)
;;;;;;;;;;;;;;;Start of Revised code		
		(setq ang (angle p1 p2)
			  mid (polar p1 ang (* (distance p1 p2) 0.5))
		)
		(setq ang 
			(cond
			  ((or (= ang 0) (= ang (* 2.0 PI)))
				0.0
			  )
			  ((and (> (cos ang) 0) (> (sin ang) 0)) ;Quandrant 1
				ang
			  )
			  ((and (< (cos ang) 0) (> (sin ang) 0)) ;Quandrant 2 
				(+ ang PI)
			  )
			  ((and (< (cos ang) 0) (< (sin ang) 0)) ;Quandrant 3
				  (- ang PI)
			  )
			  ((and (> (cos ang) 0) (< (sin ang) 0)) ;Quandrant 4
				  ang
			  )
			)
		)
		(command "-insert" "PIPESPC" mid "1" (angtos ang 0 0) sz ty)		
;;;;;;;;;;;;;;;;End Revised Code
    )
   (princ)
  )
(setvar "ATTREQ" oReq)(setvar "ATTDIA" oDia)(setvar "CLAYER" oLay)(setvar "OSMODE" oOsmode)
(command "undo" "end")
(princ)
)
0 Likes
Message 4 of 6

Kent1Cooper
Consultant
Consultant

@SeeMSixty7 wrote:

I really don't understand why your system takes so long to do the insert, but I tried to give you some extra time saving below.

....

 

....
;;;;;;;;;;;;;;;Start of Revised code		
		(setq ang (angle p1 p2)
			  mid (polar p1 ang (* (distance p1 p2) 0.5))
		)
		(setq ang 
			(cond
			  ((or (= ang 0) (= ang (* 2.0 PI)))
				0.0
			  )
			  ((and (> (cos ang) 0) (> (sin ang) 0)) ;Quandrant 1
				ang
			  )
			  ((and (< (cos ang) 0) (> (sin ang) 0)) ;Quandrant 2 
				(+ ang PI)
			  )
			  ((and (< (cos ang) 0) (< (sin ang) 0)) ;Quandrant 3
				  (- ang PI)
			  )
			  ((and (> (cos ang) 0) (< (sin ang) 0)) ;Quandrant 4
				  ang
			  )
			)
		)
		(command "-insert" "PIPESPC" mid "1" (angtos ang 0 0) sz ty)		
;;;;;;;;;;;;;;;;End Revised Code
....

I don't think that will save much time -- I'm pretty sure it's the (command) function approach that eats up the time, and using (entmake) instead will be the key to speeding it up [if the Attributes can be included -- I virtually never use them, so I'm not sure about (entmake)ing them, but if they can be done that way, even (entmake)ing the Blocks and their Attributes in separate functions will probably be faster than (command)-function operations].

 

But in any case, even this proposed adjustment to find the more text-upright direction for the Block rotation angle can be considerably simplified.  For one thing, if the 'ang' variable is coming from an (angle) function between two points, and not the result of some calculation from other numbers, it will never be as large as 2 pi [360 degrees], so you don't have to check for that value.  But you can supply an angle greater than 2 pi, and it will happily use it as if subtracting 2 pi from it -- you don't have to subtract instead of add within a certain range.  So the possibilities can be reduced to simply the choice between using it as is and adding pi to it to turn it around [even if the result will send it past 2 pi]:

 

  (if (and (< (/ pi 2) ang) (<= ang (* pi 1.5))) (setq ang (+ ang pi)))

Kent Cooper, AIA
Message 5 of 6

SeeMSixty7
Advisor
Advisor

Kent,

I agree it is not going to speed up the process a lot, but it is something that is repeated 1500+ times, so it will save some. I can run a command insert 1500 times and it takes a second or less to install a block that many times on my machine. I prefer entmake as well, and I find it useful if not cleaner than using command, but I did not see it providing that much improvement either. I agree it would provide some improvement. I offered what I did with the intention he would review your method as well.

 

On the angle, I agree, I left the 360 or (* 2.0 PI) in there just to avoid explaining it.

 

I also agree on using the if statement as you proposed. I did not look closely enough at the ang formula he was using. I saw that he was identifying quadrants and just moved on that logic. Kudos to you on optimizing even more.

 

 

0 Likes
Message 6 of 6

jamieq
Collaborator
Collaborator

This worked. It took some figuring out, but I was able to write the proper entmake lists, and now it inserts all 1654 blocks in less than a second. Thanks!