Jump to content

Speed up LISP to select objects on selected layers


3dwannab

Recommended Posts

I have this LISP below to select objects based on a selection set. Only trouble is, is it's a bit slow when there's a lot of objects in the drawing.

 

I was wondering if there was a way to speed things up a bit.

 

Cheers in advance.

 

(defun c:QSLAYERS_SELECTED_QUICK (/ idx lay lst ss1)

  (princ "Filter select all on selected object/s Layer/s :\n")

  (if
    (setq ss1 (cond
                ((ssget "_I")) ; preselection, if any
                ((ssget)) ; User selection if no pre-selection
              )
    )
    (progn
      (repeat (setq idx (sslength ss1))
        (if (not (member (setq lay (cdr (assoc 8 (entget (ssname ss1 (setq idx (1- idx))))))) lst))
          (setq lst (vl-list* "," lay lst))
        )
      )

      (setq ss1 (ssget "_X" (list (cons 8 (apply 'strcat (cdr lst))))))

      (princ (strcat "\n: ------------------------------\n\t\t<<< " (itoa (sslength ss1)) (if (> (sslength ss1) 1) " <<< objects" " <<< object") " selected.\n: ------------------------------\n"))
      ;; (command "_.zoom" "_O" ss1 "")
      (sssetfirst nil ss1)
      (command "_.regen" "_.pselect" "_p" "")
    )
  )
)

 

Link to comment
Share on other sites

Do you know how to use QSELECT command...

Start it, set filter of desired Layer and click for BricsCAD yellow square, and for AutoCAD OK button from dialog box...

  • Like 1
Link to comment
Share on other sites

I could try write something using SELECTSIMILAR when I'm in work on Monday. Just set the option of SELECTSIMILAR to selects layers and no other properties. Will probably be much faster that way. 

Link to comment
Share on other sites

So to speed up what you have you want to make the repeat loop more efficient.

 

Just quick testing, it looks like you can just use:

 

(setq lst (vl-list* "," (cdr (assoc 8 (entget (ssname ss1 (setq idx (1- idx)))))) lst))

 

taking away the 'if' line, might make it a little quicker.

 

Also for me, I'd make the name something more snappy like QSQ - saves half a second of typing!

 

  • Like 1
Link to comment
Share on other sites

Thanks Steven. I'll give that a shot on Monday. I've this mapped to a keyboard shortcut with Ctrl+L (Bit handier ;).

 

I've all my Quick select lisps starting with QS then the auto fill kicks in to populate the command list. QSL.. Are all my layer functions, QSH... are hatches and so on. 

  • Like 1
Link to comment
Share on other sites

On 3/3/2023 at 7:31 PM, Steven P said:

So to speed up what you have you want to make the repeat loop more efficient.

 

Just quick testing, it looks like you can just use:

 

(setq lst (vl-list* "," (cdr (assoc 8 (entget (ssname ss1 (setq idx (1- idx)))))) lst))

 

taking away the 'if' line, might make it a little quicker.

 

Also for me, I'd make the name something more snappy like QSQ - saves half a second of typing!

 

I tried that but still slow. This is in a drawing that has 18k objects.

 

This seems to do the business, it's more or less instant.

 

Not sure why it says "*Invalid selection*" in the command line though....

 

(defun c:QSLAYERS_SELECTED_QUICK (/ *error* var_cmdecho var_osmode var_selectsimilarmode ss1)

  (defun *error* (errmsg)
    (and acDoc (vla-EndUndoMark acDoc))
    (and errmsg
         (not (wcmatch (strcase errmsg) "*CANCEL*,*EXIT*"))
         (princ (strcat "\n<< Error: " errmsg " >>\n"))
    )
    (setvar 'cmdecho var_cmdecho)
    (setvar 'osmode var_osmode)
    (setvar 'selectsimilarmode var_selectsimilarmode)
  )

  (setq acDoc (vla-get-ActiveDocument (vlax-get-acad-object)))
  (or (vla-EndUndoMark acDoc) (vla-StartUndoMark acDoc))

  (setq var_cmdecho (getvar 'cmdecho))
  (setq var_osmode (getvar 'osmode))
  (setq var_selectsimilarmode (getvar 'selectsimilarmode))
  (setvar 'cmdecho 0)
  (setvar 'osmode 0)
  (setvar 'selectsimilarmode 2) ; Select by layer

  (princ "Filter select all on selected object/s Layer/s :\n")

  (setq ss1 (cond
              ((ssget "_I")) ; preselection, if any
              ((vl-cmdf "_.selectsimilar" pause)) ; User selection if no pre-selection
            )
  )

  (if ss1 (vl-cmdf "_.selectsimilar" "")) ;; If the ss1 variable is a selection set

  (*error* nil)
  (princ)
)

  ; (c:QSLAYERS_SELECTED_QUICK)

 

Edited by 3dwannab
  • Like 1
Link to comment
Share on other sites

Not sure how to put this in here yet, just an idea, and no clue if it would work

 

Very quick testing and it didn't have Invalid Selection, was thinking try to do the selection with an ssget like you had above, and see what happens.. needs a loop in the selectsimilar line for a selection set to work here

 

(setq MyEnt1 (car (entsel)))
(setq MyEnt2 (car (entsel)))
(setq ss1 (vl-cmdf "_.selectsimilar" MyEnt1 MyEnt2 ""))

 

Link to comment
Share on other sites

This is working for me.

 

(defun c:QSLAYERS_SELECTED_QUICK (/ *error* var_cmdecho var_osmode var_selectsimilarmode ss1)

  (defun *error* (errmsg)
    (and acDoc (vla-EndUndoMark acDoc))
    (and errmsg
         (not (wcmatch (strcase errmsg) "*CANCEL*,*EXIT*"))
         (princ (strcat "\n<< Error: " errmsg " >>\n"))
    )
    (setvar 'cmdecho var_cmdecho)
    (setvar 'osmode var_osmode)
    (setvar 'selectsimilarmode var_selectsimilarmode)
  )

  (setq acDoc (vla-get-ActiveDocument (vlax-get-acad-object)))
  (or (vla-EndUndoMark acDoc) (vla-StartUndoMark acDoc))

  (setq var_cmdecho (getvar 'cmdecho))
  (setq var_osmode (getvar 'osmode))
  (setq var_selectsimilarmode (getvar 'selectsimilarmode))
  (setvar 'cmdecho 0)
  (setvar 'osmode 0)
  (setvar 'selectsimilarmode 2) ; Select by layer

  (princ "Filter select all on selected object/s Layer/s :\n")

  (setq ss1 (ssget "_I"))

  (if ss1
    (vl-cmdf "_.selectsimilar")
    (vl-cmdf "_.selectsimilar" pause)
  )

  (*error* nil)
  (princ)
)

 

  • Like 1
Link to comment
Share on other sites

Mmmh, I thought this was working but setting the selectsimilarmode variable to 2 isn't selecting layers. Even when issuing the command after changing the variable.

 

Attached is a sample drawing. Just select either of the dims which are both in the same layer and the selectsimilar command won't work.

 

 

Two Different Dim Types.dwg

Link to comment
Share on other sites

And in this form, would it suit you?

(defun c:dyn_filter ( / ss n lst_lay lst_typ dxf_ent lay typ m_filt)
  (cond
    ((setq ss
      (cond
        ((ssget "_I"))
        ((ssget))
      )
    )
      (setq lst_lay "" lst_typ "")
      (repeat (setq n (sslength ss))
        (setq dxf_ent (entget (ssname ss (setq n (1- n)))))
        (if (not (vl-string-search (setq lay (cdr (assoc 8 dxf_ent))) lst_lay))
          (setq lst_lay (strcat lay "," lst_lay))
        )
        (if (not (vl-string-search (setq typ (cdr (assoc 0 dxf_ent))) lst_typ))
          (setq lst_typ (strcat typ "," lst_typ))
        )
      )
      (setq m_filt
        (list
          (cons 0 lst_typ)
          (cons 8 lst_lay)
          (cons 67 (if (= 1 (getvar "CVPORT")) 1 0))
          (cons 410 (getvar "CTAB"))
        )
      )
      (if (zerop (getvar "PICKFIRST")) (setvar "PICKFIRST" 1))
      (sssetfirst nil nil)
      (setq ss (ssget "_X" m_filt))
      (princ (strcat "\n" (itoa (sslength ss)) " selected similar objects."))
      (sssetfirst nil ss)
    )
    (T (princ "\nNo selection"))
  )
  (prin1)
)

 

Link to comment
Share on other sites

Thanks @Tsuky, much faster. I've taken out type.

 

(defun c:dyn_filter (/ ss n lst_lay dxf_ent lay typ m_filt)
  (cond 
    ((setq ss (cond 
                ((ssget "_I"))
                ((ssget))
              )
     )
     (setq lst_lay "")
     (repeat (setq n (sslength ss)) 
       (setq dxf_ent (entget (ssname ss (setq n (1- n)))))
       (if (not (vl-string-search (setq lay (cdr (assoc 8 dxf_ent))) lst_lay)) 
         (setq lst_lay (strcat lay "," lst_lay))
       )
     )
     (setq m_filt (list 
                    (cons 8 lst_lay)
                    (cons 67 (if (= 1 (getvar "CVPORT")) 1 0))
                    (cons 410 (getvar "CTAB"))
                  )
     )
     (if (zerop (getvar "PICKFIRST")) (setvar "PICKFIRST" 1))
     (sssetfirst nil nil)
     (setq ss (ssget "_X" m_filt))
     (princ (strcat "\n" (itoa (sslength ss)) " selected similar objects."))
     (sssetfirst nil ss)
    )
    (T (princ "\nNo selection"))
  )
  (prin1)
)

 

Link to comment
Share on other sites

I've just found what was slowing it down from my original post. This line.

 

(command "_.regen" "_.pselect" "_p" "")

 

Taking this out is fast now. But I've had issues with the grips not showing which is why I've added this in the first place.

Link to comment
Share on other sites

Just look up help about ssget filters

 

examples (ssget '((0 . "INSERT"))) (ssget '((0 . "LWPOLYLINE")))  (ssget '((0 . "LWPOLYLINE")(8 . "Mylayer"))

 

  • Like 1
Link to comment
Share on other sites

On 3/11/2023 at 6:49 PM, barristann said:

Is it possible to modify this to select Blocks? Thank you.

Here's a mod of something LeeMac originally wrote.

 

(vl-load-com)

;;
;; Select Blocks by same name
;; Updated by 3dwannab on 2022.03.30.
;;
;; I updated this on the 2022.03.30 to use the SELECTSIMILAR command by setting
;; the SELECTSIMILARMODE to 128 which is to select similar by name.
;; Along with a filter for the selection of blocks, after this it's pretty simple.
;;
;; Initial code was here by Lee Mac: http://www.theswamp.org/index.php?topic=49667.msg548516#msg548516
;;

(defun c:QSBlocks_Same (/ *error* acDoc def lst ss1 ss2 var_cmdecho var_osmode var_selectsimilarmode)

  (princ "Filter select all similar Blocks by name :\n")

  (defun *error* (errmsg)
    (and acDoc (vla-EndUndoMark acDoc))
    (and errmsg
         (not (wcmatch (strcase errmsg) "*CANCEL*,*EXIT*"))
         (princ (strcat "\n<< Error: " errmsg " >>\n"))
    )
    (setvar 'cmdecho var_cmdecho)
    (setvar 'osmode var_osmode)
    (setvar 'selectsimilarmode var_selectsimilarmode)
  )

  (setq acDoc (vla-get-ActiveDocument (vlax-get-acad-object)))
  (or (vla-EndUndoMark acDoc) (vla-StartUndoMark acDoc))

  (setq var_cmdecho (getvar 'cmdecho))
  (setq var_osmode (getvar 'osmode))
  (setq var_selectsimilarmode (getvar 'selectsimilarmode))
  (setvar 'cmdecho 0)
  (setvar 'osmode 0)

  ; Code by Lee Mac http://www.cadtutor.net/forum/showthread.php?92638-Simple-fix-%28LISP-noob%29-Syntax-problem&p=633824&viewfull=1#post633824
  ;; Iterate over the block table and compile a list of xref blocks to exclude
  (while (setq def (tblnext "block" (not def)))
    (if (= 4 (logand 4 (cdr (assoc 70 def))))
      (setq lst (vl-list* "," (cdr (assoc 2 def)) lst))
    )
  )

  ;; Attempt to retrieve a selection of blocks (but not xrefs)
  (setq ss1 (ssget (cons '(0 . "INSERT") (if lst (vl-list* '(-4 . "<NOT") (cons 2 (apply 'strcat (cdr lst))) '((-4 . "NOT>")))))))

  ;; Set selectsimilarmode to use the name of an object.
  (setvar 'selectsimilarmode 128)

  ;; If ss1 one is valid then do this
  (if ss1
    (progn
      (vl-cmdf "_.selectsimilar" ss1 "")
      (setq ss2 (ssget)) ;; Create a new selection set for to zoom and reselect as the zoom objects will do this
      ;; (command "_.zoom" "_O" ss2 "")
      (sssetfirst nil ss2)
      (command "_.regen")
      (princ (strcat "\n: ------------------------------\n\t\t<<< " (itoa (sslength ss2)) (if (> (sslength ss2) 1) " <<< INSERTS objects" " <<< INSERT object") " selected\n: ------------------------------\n"))
    )
    (princ "\n: ------------------------------\n\t\t*** Nothing selected ***\n: ------------------------------\n")
  )

  (*error* nil)
  (princ)
)

 

Edited by 3dwannab
Added (vl-load-com)
  • Like 1
Link to comment
Share on other sites

3dwannab, I've tested this today several times and it works 100%. You have amazing skills sir! Thank you 3dwannab and Lee Mac for saving my job!

  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...