Find Block by Attribute Definition

Find Block by Attribute Definition

RocksterB
Advocate Advocate
5,544 Views
18 Replies
Message 1 of 19

Find Block by Attribute Definition

RocksterB
Advocate
Advocate

I need a lisp that will find blocks via the attribute definition instead of the attribute's value. Anyone have a routine that will do this?

0 Likes
Accepted solutions (1)
5,545 Views
18 Replies
Replies (18)
Message 2 of 19

Moshe-A
Mentor
Mentor

Rockster hi,

 

here is (isAttribTag) function, it will return T if the tag is found and nil if not

also it will return the tag value in a quoted argument

 

did not test it!

 

enjoy

Moshe

 

 

; Arguments:
; ent    - entity name of block reference
; tag    - requested tag
; Qvalue - Quoted argument, store attribute value

(defun isAttribTag (ent tag Qvalue / subent sube flag)
 (setq subent (entnext ent) sube (entget subent))
 (while (and
	  (not flag)
	  (/= (cdr (assoc '0 sube)) "SEQEND")
	)
  (if (eq (strcase (cdr (assoc '2 sube))) (strcase tag))
   (progn
    (set Qvalue (cdr (assoc '1 sube))) ; indirect set
    (setq flag t)
   )
   (setq subent (entnext subent) sube (entget subent))
  )
 ); while

 flag 
); isAttribTag


; sample usage:

(if (and
      (setq pick (entsel "\nSelect attribute block: "))
      (setq ename (car pick))
      (setq elist (entget ename))
      (eq (cdr (assoc  '0 elist)) "INSERT")
      (eq (cdr (assoc '66 elist)) 1)
    )
 (if (isAttribTag ename "TAGNAME" 'attValue)
  (princ attValue)
 )
)
Message 3 of 19

Satish_Rajdev
Advocate
Advocate

Do you mean you want to enter attribute tag name and then program will return block name having same attribute tag name?

 

 

Best Regards,
Satish Rajdev


REY Technologies | Linked IN | YouTube Channel


 

0 Likes
Message 4 of 19

RocksterB
Advocate
Advocate

Yes, I want to find all block containing a specific attribute tag name, ex "RMNO" or "ROOMNO".

 

Moshe, I tried your routine but I didnot get the results I was looking for. I need something that will find all of the blocks with an specific attribute tag. The gathered blocks will be examined.

0 Likes
Message 5 of 19

CodeDing
Advisor
Advisor

@RocksterB,

 

I edited @Moshe-A's code to what I believe you are looking for. I could not have completed it without their code. My code may not be ideal, so others may provide better solutions.

 

If this solves your issue, please give Moshe-A credit also.

 

Best,

~DD

 

; Arguments:
; ent    - entity name of block reference
; tag    - requested tag

(defun isAttribTag (ent tag / subent sube flag)
 (setq subent (entnext ent) sube (entget subent))
 (while (and
	  (not flag)
	  (/= (cdr (assoc '0 sube)) "SEQEND")
	);and
  (if (eq (strcase (cdr (assoc '2 sube))) (strcase tag))
  	(setq flag t)
  	(setq subent (entnext subent) sube (entget subent))
  );if
 ); while

 (princ flag)
); isAttribTag


; sample usage:
(defun c:TEST ( / ss tmp ename elist)
(if (setq ss (ssget "_X" '((0 . "INSERT"))))
  (progn
  (setq tmp 0)
	(repeat (sslength ss)
	(if (and
		(setq ename (ssname ss tmp))
		(setq elist (entget ename))
		(eq (cdr (assoc  '0 elist)) "INSERT")
		(eq (cdr (assoc '66 elist)) 1)
	    );and
	(progn
		(if (isAttribTag ename "LINE1")
			(setq tmp (1+ tmp))
			(ssdel ename ss)
		);if
	);progn
	;else
		(ssdel (ssname ss tmp) ss)
	);if
	);repeat
  );progn
);if
(cond
	((or (= 0 (sslength ss)) (not ss))
	(prompt "\nNo blocks with tag name found.")
	);end Cond 1
	((> (sslength ss) 0)
	(prompt "\nYes, blocks with tag name found.");<<<<<<<< Do stuff with ss
	);end Cond 2	
);cond
(princ)
);defun

 

0 Likes
Message 6 of 19

Moshe-A
Mentor
Mentor

Rockster,

 

What do you mean you did not get the result?

You would get the exact results out of my function if you write an AutoLISP command to iterate a collection of blocks

and call my function with the right arguments.

plus consider providing us with sample dwg with an explaintion what is your goal?

 

Moshe

 

 

0 Likes
Message 7 of 19

Kent1Cooper
Consultant
Consultant

@RocksterB wrote:

I need a lisp that will find blocks via the attribute definition instead of the attribute's value. Anyone have a routine that will do this?


It seems to me that since an Attribute with its Tag is a part of a Block's definition, such a routine should be looking at Block definitions  for such a Tag name, and then  finding all such Blocks, rather than looking at either a selected Block Insertion or at all the individual Insertions of all Blocks with Attributes.

 

A process that should work, if I understand the need correctly:

 

Step through the Block Table, and for each Block definition, step through its pieces looking for a Tag with the specified name [or names, if you put in e.g. "RMNO,ROOMNO" with comma separator].  If that [or any of them] is found, add a comma and that Block's name into an accumulating text string of qualifying Block names.

 

Have (ssget) find all Blocks of those names.  It could find them all at once, even if more than one Block name is involved, using that comma-delimited string of Block names, and it could select/grip/highlight all of them for you to look at, at least in the current workspace [it gets a little more complicated if they're in multiple Layouts, etc.].  It could save all their entity names in a selection-set variable, if that's a better way to do whatever you need with them.

 

[A possible complication -- it's not that simple if any are dynamic  Blocks, because (ssget) won't be able to find those by Block name, but that can be dealt with if necessary.]

 

Does that sound like it would get the result you want?

Kent Cooper, AIA
Message 8 of 19

RocksterB
Advocate
Advocate

Yes, that is a great overview of what I was requesting and trying to describe. I was keeping it simple, but your overview seems to hit the nail on the head. I hope I can get a routine based on your expanded evaluation of my issue. Hopefully, it will allow me to provide the block tag name, then seek & isolate them by highlight the block(s) so they can be altered. BTW, my blocks are dynamic blocks.

 

Moshe, it could be I didn't properly use your routine in the correct manner. I appreciated your input and assistance.

CodeDing, I gave the enhanced routine a try and it did acknowledge there are blocks containing the specified tag name, but didn't highlight where they were located. However, it could be simple because of how I using the routine correctly.

0 Likes
Message 9 of 19

patrick_35
Collaborator
Collaborator

Hi

 

A solution to find the block by attribute

(setq ent (vlax-ename->vla-object (car (nentsel))))
(vla-objectidtoobject (vla-get-database ent)(vla-get-ownerid ent)))

@+

0 Likes
Message 10 of 19

Kent1Cooper
Consultant
Consultant

@patrick_35 wrote:

.... A solution to find the block by attribute

(setq ent (vlax-ename->vla-object (car (nentsel))))
(vla-objectidtoobject (vla-get-database ent)(vla-get-ownerid ent)))

 

But doesn't that still require selecting  something?  As I understand it, they want to designate a Tag name [or names, which would mean typing them in, not selecting an example], and have the routine find all the Blocks of all definitions that have an Attribute with such Tag(s).

Kent Cooper, AIA
0 Likes
Message 11 of 19

Moshe-A
Mentor
Mentor

CodeDing,

 

explain the purpose of your last expressing in (isAttribTag)

(princ flag)

 

doing that will return flag value (T or nil) and that OK but also will princ T/nil on command line which totally redundant. imagine the function is called houndreds of times what will be showed in the command line?!

 

Moshe

 

 

 

 

; Arguments:
; ent    - entity name of block reference
; tag    - requested tag

(defun isAttribTag (ent tag / subent sube flag)
 (setq subent (entnext ent) sube (entget subent))
 (while (and
	  (not flag)
	  (/= (cdr (assoc '0 sube)) "SEQEND")
	);and
  (if (eq (strcase (cdr (assoc '2 sube))) (strcase tag))
  	(setq flag t)
  	(setq subent (entnext subent) sube (entget subent))
  );if
 ); while

 (princ flag)
); isAttribTag
0 Likes
Message 12 of 19

CodeDing
Advisor
Advisor

@Moshe-A,

 

You are right, thank you for the catch. Just bad habit I guess.

 

@RocksterB,

 

Something like this? It sounds like you strictly want these highlighted?

 

Also, if @Kent1Cooper is willing to critique my code here, I enjoy hearing his feedback lol.

 

Best,

~DD

 

; Arguments:
; ent    - entity name of block reference
; tag    - requested tag

(defun isAttribTag (ent tag / subent sube flag)
 (setq subent (entnext ent) sube (entget subent))
 (while (and
	  (not flag)
	  (/= (cdr (assoc '0 sube)) "SEQEND")
	);and
  (if (eq (strcase (cdr (assoc '2 sube))) (strcase tag))
  	(setq flag t)
  	(setq subent (entnext subent) sube (entget subent))
  );if
 ); while

 flag
); isAttribTag


; sample usage:
(defun c:TEST ( / ss tmp tmp2 ename elist tagtmp taglist g2g)

(setq taglist '())
(while (< 0 (strlen (setq tagtmp (getstring nil "\nEnter Tag String (Enter to continue): "))))
	(setq taglist (cons (strcase tagtmp) taglist))
);while

(if (and (setq ss (ssget "_X" '((0 . "INSERT")))) (> (length taglist) 0))
  (progn
  (setq tmp 0)
	(repeat (sslength ss)
	(if (and
		(setq ename (ssname ss tmp))
		(setq elist (entget ename))
		(eq (cdr (assoc  '0 elist)) "INSERT")
		(eq (cdr (assoc '66 elist)) 1)
	    );and
	(progn
	(setq tmp2 0 
	      g2g nil)
	(repeat (length taglist)
	  (setq tagtmp (nth tmp2 taglist))
		(if (isAttribTag ename tagtmp)
			(setq g2g t)
		);if
	  (setq tmp2 (1+ tmp2))
	);repeat
		(if g2g
			(setq tmp (1+ tmp))
			(ssdel ename ss)
		);if
	);progn
	;else
		(ssdel (ssname ss tmp) ss)
	);if
	);repeat
  );progn
);if
(cond
	((or (= 0 (sslength ss)) (not ss))
	(prompt "\nNo blocks with tag name found.")
	);end Cond 1
	((> (sslength ss) 0)
	(command "pselect" ss "")
	);end Cond 2	
);cond
(princ)
);defun

 

0 Likes
Message 13 of 19

Kent1Cooper
Consultant
Consultant
Accepted solution

@CodeDing wrote:

....@Moshe-A

Also, if @Kent1Cooper is willing to critique my code here, I enjoy hearing his feedback lol.

.... 


 

My one critique is a repeat, that it looks again like it finds every Block insertion, and then digs into each insertion individually, to find out first whether it's one with any Attributes at all, and then what their Tags are and whether any of them have (one of) the right Tag name(s).

 

The way I'd approach it is to look at Block definitions, [which typically would be far fewer  than insertions] for those that contain the right Tag(s), and once that has been determined, find not all  Block insertions, but first narrow that down in selection to only those that contain Attributes [typically far fewer  than all  Block insertions], and then check each of those, not digging inside for what Tags are in it, but simply looking at whether it is of one of the [Effective] Block names  that are already known  to contain the designated Tag(s).

 

If not for the fact that some could be Dynamic  Blocks, it could be simpler -- it wouldn't even need to find all Block insertions with Attributes, but could just directly find and highlight all Blocks of the determined names.  Because a Block's being Dynamic spoils the "name" on its insertions, (ssget) can't find them by Block name, but it's necessary to look at their Effective  name, which can't be filtered for in selection but needs to be checked individually.

 

The (wcmatch) function can look at multiple strings at once, so a single  string of Tag names and a single  string of Block names can be used, rather than a list of Tag names.

 

[And it's quite a bit shorter!]

 

Try this [minimally  tested]:

 

(defun C:BWST ; = Blocks With Specified Tag(s)
  (/ atts blknames blks blk blkname ent edata foundit n)
  (setq
    atts (strcase (getstring "\nTag name(s) {comma-separated if more than one}: "))
    blknames "" ; initially empty string
    blks (ssadd); initially empty selection set
  ); setq
  (while (setq blk (tblnext "block" (not blk))); step through Block table
    (setq
      ent (tblobjname "block" (setq blkname (cdr (assoc 2 blk))))
      foundit nil ; reset for each Block definition
    ); setq
    (while (and (not foundit) (setq ent (entnext ent)))
      ;; haven't found Tag(s) yet, still another object
      (setq edata (entget ent))
      (if (and (member '(0 . "ATTDEF") edata) (wcmatch (cdr (assoc 2 edata)) atts))
        (setq ; then -- this Block contains (one of the) specified Attribute Tag(s)
          blknames (strcat blknames blkname ",")
          foundit T
        ); setq
      ); if
    ); while - Block definition parts
  ); while - Block table entries
  (setq blkstemp (ssget "_X" '((0 . "INSERT") (66 . 1))))
    ;; find all Blocks with Attributes [only because of possibility of Dynamic Blocks]
  (repeat (setq n (sslength blkstemp)); look for those of correct name(s)
    (if
      (wcmatch ; of [one of the] correct name[s]?
        (strcase (vla-get-EffectiveName (vlax-ename->vla-object (setq blk (ssname blkstemp (setq n (1- n)))))))
        (strcase blknames)
      ); wcmatch
      (ssadd blk blks); then - put it in selection set
    ); if
  ); repeat
  (if (> (sslength blks) 0) (sssetfirst nil blks))
    ;; select/grip/highlight all Blocks of names with any specified Tag(s) [if any]
(princ) ); defun

EDIT:  [If you got this in the first ten minutes or so after posting, copy it again -- I noticed some things that needed fixing.]

Kent Cooper, AIA
Message 14 of 19

CodeDing
Advisor
Advisor

@Kent1Cooper,

 

Plenty of items in there that I don't use on a regular basis. Still expanding my knowledge. I appreciate the helpful breakdown. I have sat here and tried to dissect the whole thing. Got most of it, just some kinks on a few things. This was very informational for me, and hopefully OP also. Thank you.

 

Best,

~DD

0 Likes
Message 15 of 19

RocksterB
Advocate
Advocate
I can’t get to my computer until Monday, but appreciate all of you continuing to come up with a remedy to my problem. I will add that I have the situation where I have same named blocks with two close but differently named tags like ROOMNO and RMNO. At some point the blocks were not synchronized and doing so now makes various instances of the blocks lose their value. So I need to find the culprits.
0 Likes
Message 16 of 19

RocksterB
Advocate
Advocate

Success! The BWST routine worked and appears to have found blocks in both modelspace and paperspace. I used it on another tag name and it got me thinking, it would be even more helpful if the routine had the option to find all the blocks by tag name or by a specific named blocks . This could be done by the user clicking on a particular block. Can this be done without too much trouble? If it is, I'll use the routine as is.

 

Thanks for all the team work help guys!

0 Likes
Message 17 of 19

Kent1Cooper
Consultant
Consultant

@RocksterB wrote:

.... it would be even more helpful if the routine had the option to find all the blocks by tag name or by a specific named blocks . ....


QSELECT will find all Block of a specific name, without any code [only in the current space, but after all, while BWST can find others, it can't select/highlight/grip those not in the current space].  Do you mean to look for Blocks of more than one name, as BWST can do?

Kent Cooper, AIA
0 Likes
Message 18 of 19

RocksterB
Advocate
Advocate

True, QSELECT  can handle most other search criteria. I was thinking of situations where the same attribute tag name would exit in various blocks, say the tag name DWGNO, it could be convenient to have the routine chose separately the detail callouts from the building section or elevation call outs. Not to worry, I'm happy with what you guys cooked up for me. I'll wait a short while then send out the appropriate acknowledgements.

0 Likes
Message 19 of 19

Kent1Cooper
Consultant
Consultant

@RocksterB wrote:

.... to have the routine chose separately the detail callouts from the building section or elevation call outs. ....


SELECTSIMILAR will do that.  Call for the SEttings option, make sure "Name" is checked so it won't find all  Blocks, or all of them on the same Layer [or other criteria -- see the other choices in SEttings], and then just pick on a Block of the kind you want, hit Enter, and it will find and select/grip/highlight all of them.

Kent Cooper, AIA
0 Likes