Jump to content

select duplicate attributes


Recommended Posts

Posted

Hello everyone,

 

I would like to select multiple attributes in one area (example: (ssget "_:L") and automatically select all duplicate tags based on the selected attributes.

can you give me some help?

 

Reference: https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/selecting-a-block-by-its-attribute-value/td-p/2195298

 

(defun c:ssatt (/ att elst tag val ss1 ss2 n ent)
(and
(setq att (car (nentsel "\nSelect source attribute: ")))
(setq elst (entget att))
(setq tag (cdr (assoc 2 elst))
val (cdr (assoc 1 elst))
ss2 (ssadd)
)
(setq ss1 (ssget "_X"
(list '(0 . "INSERT")
(assoc 2 (entget (cdr (assoc 330 elst))))
)
)
)
(repeat (setq n (sslength ss1))
(setq ent (ssname ss1 (setq n (1- n)))
att (entnext ent)
)
(while (= (cdr (assoc 0 (setq elst (entget att)))) "ATTRIB")
(if (and (= (cdr (assoc 2 elst)) tag)
(= (cdr (assoc 1 elst)) val)
)
(ssadd ent ss2)
)
(setq att (entnext att))
)
)
(sssetfirst nil ss2)
)
(princ)
)

 

 

 

;; Expected outcome. Select more than one attribute. (selection)

image.png.65b1cce3a02524d5acc871d307b44252.png

 

 

;;Compare selected and duplicate attributes.

image.png.e659d301758a1509204038b614280f40.png

Posted
(assoc 2 (entget (cdr (assoc 330 elst)))

is just the block name the nentsel is in. and would only select those blocks. it now searches all blocks for selected attribute of the same value. this might slow down the lisp depending on how many blocks you have. and if all your blocks only have unique attributes put it back in.

 

This still only allows you to select one attribute at a time but it repeats and will add to the selection set.

(defun c:ssatt (/ att elst tag val ss1 ss2 n ent)
  (setq ss2 (ssadd)) ;moved outside of while so it doesn't reset the selection set
  (while (setq att (car (nentsel "\nSelect source attribute: ")))
    (setq elst (entget att))
    (setq tag (cdr (assoc 2 elst))
          val (cdr (assoc 1 elst))
    )
    (if (setq ss1 (ssget "_X" '((0 . "INSERT"))))
      (progn
        (foreach ent (vl-remove-if 'listp (mapcar 'cadr (ssnamex ss1)))
          (setq att (entnext ent))
          (while (eq (cdr (assoc 0 (setq elst (entget att)))) "ATTRIB")
            (if (and (eq (cdr (assoc 2 elst)) tag)
                     (eq (cdr (assoc 1 elst)) val)
                )
              (ssadd ent ss2)
            )
            (setq att (entnext att))
          )
        )
      )
    )
    (if (setq ss1 (ssget "_X" '((0 . "ATTDEF"))))
      (foreach ent (vl-remove-if 'listp (mapcar 'cadr (ssnamex ss1)))
        (setq elst (entget ent))
        (if (and (eq (cdr (assoc 2 elst)) tag)
                 (eq (cdr (assoc 1 elst)) val)
            )
          (ssadd ent ss2)
        )
      )
    )
    (sssetfirst nil ss2)
  )
  (princ)
)

 

Posted (edited)

mhupp this may be useful, nentsel to get attribute tag name then use ssget pt where pt is the insertion pt of the tag, this second ssget will then get the block so you can get block name to use. (ssget (list (cons 0 "INSERT")(cons 2 bname)))

 

Edited by BIGAL
  • Like 2
Posted

@mhupp

 

Your idea is very interesting, I'm looking for a way to multiple selections. click and drag type.

 

image.thumb.png.33af681206e9b00a8ea7013a67818817.png

Posted

@BIGAL

 

1 hour ago, BIGAL said:

mhupp this may be useful, nentsel to get attribute tag name then use ssget pt where pt is the insertion pt of the tag, this second ssget will then get the block so you can get block name to use. (ssget (list (cons 0 "INSERT")(cons 2 bname)))

 

Could you exemplify this in the code?

 

Best regards

Posted (edited)

you cant use ssget to select sub entity's in a block. if what your trying to make a multiple selections is just an attdef in model space then you can use this.

 

(defun c:ssatt (/ att elst tag val ss ss1 ss2 n ent)
  (setq ss2 (ssadd))  ;moved outside of while so it doesn't reset the selection set
  (if (setq ss (ssget '((0 . "ATTDEF")))) 
    (foreach ent (vl-remove-if 'listp (mapcar 'cadr (ssnamex ss1)))
      (setq elst (entget att))
      (setq tag (cdr (assoc 2 elst))
            val (cdr (assoc 1 elst))
      )
      (if (setq ss1 (ssget "_X" '((0 . "INSERT"))))
        (progn
          (foreach ent (vl-remove-if 'listp (mapcar 'cadr (ssnamex ss1)))
            (setq att (entnext ent))
            (while (eq (cdr (assoc 0 (setq elst (entget att)))) "ATTRIB")
              (if (and (eq (cdr (assoc 2 elst)) tag)
                       (eq (cdr (assoc 1 elst)) val)
                  )
                (ssadd ent ss2)
              )
              (setq att (entnext att))
            )
          )
        )
      )
      (if (setq ss1 (ssget "_X" '((0 . "ATTDEF"))))
        (foreach ent (vl-remove-if 'listp (mapcar 'cadr (ssnamex ss1)))
          (setq elst (entget ent))
          (if (and (eq (cdr (assoc 2 elst)) tag)
                   (eq (cdr (assoc 1 elst)) val)
              )
            (ssadd ent ss2)
          )
        )
      )
    )
  )
  (sssetfirst nil ss2)
  (princ)
)
Edited by mhupp
updated code
Posted
1 hour ago, BIGAL said:

mhupp this may be useful, nentsel to get attribute tag name then use ssget pt where pt is the insertion pt of the tag, this second ssget will then get the block so you can get block name to use. (ssget (list (cons 0 "INSERT")(cons 2 bname)))

 

 

that is what

 

(setq ss1 (ssget "_X" (list '(0 . "INSERT") (assoc 2 (entget (cdr (assoc 330 elst)))))

 

is doing. its limiting the "search" for the attribute selected by nentsel to only that block name. I was saying you need to search all blocks to make sure the attribute isn't in another block by a different name. But if you know for sure that the attribute isn't shared between blocks. Then use above ssget.

Posted

@mhupp @BIGAL

 

Gentlemen, I appreciate your support. I'm sorry for the basic doubts I'm still a beginner.

 

The first script worked perfectly but with the single click at a time.


In the second script I can not select anything.

FInd attached the DWG file.

 

image.png.6799b6e37ce94aeecd073eb739eba691.png

 

 

If possible I would like to choose the attribute for the selection: example TAG1F, DESC2, DESC3 etc...

 

image.png.348dd338ef68313c3f408764f903e88a.png

 

Select_Duplicate_attr.dwg

Posted
3 hours ago, jr.roberto.santos said:

In the second script I can not select anything.

FInd attached the DWG file.

 

Like I said You cant use ssget to select sub entity's in a block.

The attributes are sub entity's of blocks. Working on something but wont get it posted tonight.

Posted

Here is my method for 1 tag as you have both tag name and block name.

 

(setq ent (entget (car (nentsel "\npick a attribute"))))
(setq ins (cdr (assoc 10 ent)))
(setq tag (cdr (assoc 2 ent)))
(setq txt (cdr (assoc 1 ent)))
(setq ent2 (entget (ssname (ssget ins) 0)))
(setq bname (cdr (assoc 2 ent2)))

 

Maybe use lee's list box, select block,  get all tags then select which ones to look for, or use my Multi toggles.lsp tick on ones required. Will do up to about 20 tags. There is a spacer can be removed to get more.Multi toggles.lsp

 

(setq obj (vlax-ename->vla-object (car  (entsel "Pick block"))))
(setq lst '())
(setq atts (vlax-invoke obj 'Getattributes))
(foreach att atts
(setq lst (cons (vla-get-tagstring att) lst))
)
(setq lst (reverse lst))
(setq lst (cons "please choose" lst))
(if (not AH:Toggs)(load "Multi toggles.lsp"))
(setq ans (reverse (ah:toggs lst)))

 

  • Agree 1
Posted

@BIGAL@mhupp

Thank you so much for your support.

 

In this example I include the match attribute manually.

This would be perfect if it were possible to take the list of previously selected attributes and include them a variable tag1.

 

 

;;;;;

(defun c:test_WILDCARD (/ ss2 ss tag val n na)

(setq tag1 "TAG1,TAG2,TAG3,TAG4") ;;<< trying to include the values of the selected attributes.
(setq ss2 (ssadd))
(sssetfirst nil nil)
(princ "\nSelect blocks containing attributes.")
(if (setq ss (ssget "_:L" '((0 . "INSERT") (66 . 1))))
(progn
(setq tag "TAG1F")
(setq val tag1)
(setq n 0)
(repeat (sslength ss)
(setq na (ssname ss n))
(if (func_att_match na tag val)
(setq ss2 (ssadd na ss2))
);if
(setq n (+ n 1));setq
);repeat
(if (equal (getvar "cmdnames") "")
(sssetfirst ss2 ss2)
(command ss2)
);if
);progn then
);if
(princ)

);defun c:test_WILDCARD
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun func_att_match ( na tag val / e1 a b flag)
(while (and (setq na (entnext na))
(setq e1 (entget na))
(not (equal (cdr (assoc 0 e1)) "SEQEND"))
(not flag)
);and
(if (equal (cdr (assoc 0 e1)) "ATTRIB")
(progn
(setq a (cdr (assoc 2 e1)) ;2 is tag
b (cdr (assoc 1 e1)) ;1 is value
);setq
(if (and a
(wcmatch a tag)
b
(wcmatch b val)
);and
(setq flag T);then jump out of the loop
);if
);progn then attrib
);if
);while
flag
);defun func_att_match

;;(princ "\nType ATTSELECT to run")
(princ)

 

;;;;;;

 

image.png.985bd7e525ebd814c139456cc78d546f.pngimage.png.675f50a64c35ae09de348216ec1067f2.png

Posted (edited)

Multi select kinda

Pick a block It will list all attribute tags in a dcl menu. Pick witch ones you want to search for from the dcl menu. it will then search all blocks that have attributes for same tag name and value. This will only select blocks that match all tag name + values of the first selectrd block.

 

;;----------------------------------------------------------------------------;;
;; SEARCH BLOCKS FOR MATCHING ATTRIBUTES
(defun C:foo (/ ss2 blk x blkname attlst attag att itm ss ent i)
  (setq ss2 (ssadd))
  (while (setq blk (car (entsel "\nSelect Block")))
    (if (and (= "INSERT" (cdr (assoc 0 (setq x (entget blk))))) (setq blkname (cdr (assoc 2 x))))
      (progn
        (setq attlst (mapcar '(lambda (at) (list (vla-get-tagstring at) (vla-get-textstring at)))
                             (vlax-invoke (vlax-ename->vla-object blk) 'getattributes)
                     )
        )
        (setq attag (mapcar '(lambda (at) (car at)) attlst))
        (setq att (AT:ListSelect (strcat "Attribues in " blkname) "Pick A Attribue to search for" 20 20 "true" attag))
        (foreach itm attlst  ;mapcar mabye?
          (if (member (car itm) att)
            (progn)
            (setq attlst (vl-remove itm attlst))
          )
        )
        (if (setq ss (ssget "X" (list '(0 . "INSERT") '(66 . 1) (cons 410 (getvar 'ctab)))))
          (foreach ent (vl-remove-if 'listp (mapcar 'cadr (ssnamex SS)))
            (setq att (entnext ent)
                  i 0
            )            
            (while (eq (cdr (assoc 0 (setq elst (entget att)))) "ATTRIB")
              (foreach itm attlst
                (if (and (eq (cdr (assoc 2 elst)) (car itm))
                         (eq (cdr (assoc 1 elst)) (cadr itm))
                    )
                  (setq i (1+ i))
                )
              )
              (if (eq i (length attlst)) (ssadd ent ss2))
              (setq att (entnext att))
            )
          )
        )
      )
      (prompt "\nNot a Block")
    )
  )
  (sssetfirst nil ss2)
  (princ)
)
;; List Select Dialog (Temp DCL list box selection, based on provided list)
;; title - list box title
;; label - label for list box
;; height - height of box
;; width - width of box
;; multi - selection method ["true": multiple, "false": single]
;; lst - list of strings to place in list box
;; Alan J. Thompson, 09.23.08 / 05.17.10 (rewrite)
(defun AT:ListSelect (title label height width multi lst / fn fo d f)
  (setq fo (open (setq fn (vl-filename-mktemp "" "" ".dcl")) "w"))
  (foreach x (list (strcat "list_select : dialog { label = \"" title "\"; spacer;")
                   (strcat ": list_box { label = \"" label "\";" "key = \"lst\";")
                   (strcat "allow_accept = true; height = " (vl-princ-to-string height) ";")
                   (strcat "width = " (vl-princ-to-string width) ";")
                   (strcat "multiple_select = " multi "; } spacer; ok_cancel; }")
             )
    (write-line x fo)
  )
  (close fo)
  (new_dialog "list_select" (setq d (load_dialog fn)))
  (start_list "lst")
  (mapcar (function add_list) lst)
  (end_list)
  (setq item (set_tile "lst" "0"))
  (action_tile "lst" "(setq item $value)")
  (setq f (start_dialog))
  (unload_dialog d)
  (vl-file-delete fn)
  (if (= f 1)
    ((lambda (s / i s l)
       (while (setq i (vl-string-search " " s))
         (setq l (cons (nth (atoi (substr s 1 i)) lst) l))
         (setq s (substr s (+ 2 i)))
       )
       (reverse (cons (nth (atoi s) lst) l))
     )
      item
    )
  )
)

 

Edited by mhupp

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...