I need help with a lisp routine to count the number of dynamic blocks of a specific name ("FD") by windowing an area of the drawing. I have a routine that I've been using to accomplish this, but i don't understand why it doesn't count dynamic blocks.
(DEFUN C:LOCATEFD(/ BLKNAME BLOCKSET TOTAL)
(SETQ BLKNAME "FD")
(PROGN(SETQ BLOCKSET(SSGET(LIST(CONS 2 BLKNAME))))
(IF(= BLOCKSET NIL)
(PROGN(SETQ TOTAL 0)
(ALERT(STRCAT "\nTHERE ARE NO FIRE DAMPERS IN THIS DRAWING"))
)))
(SETQ TOTAL(SSLENGTH BLOCKSET))
(SSSETFIRST NIL BLOCKSET)
(IF(= TOTAL 1)(ALERT(STRCAT "\nTHERE IS 1 FIRE DAMPER IN THIS DRAWING")))
(IF(> TOTAL 1)(ALERT(STRCAT "\nTHERE ARE "(ITOA TOTAL)" FIRE DAMPERS IN THIS DRAWING")))
(PRINC))
Thanks,
Larry
Good Morning,
This problem has happened many times, if you search for this you can find many solutions, the problem is that since dynamic blocks have been introduced the ssget function cannot access them by name, you will get a random name for this block, you must instead sort through them using vla function methods. and get the 'EffectiveName object property.
(vlax-get obj 'EffectiveName)
Hi,
Dynamic blocks are special ones, if they have some of its dynamic properties active, then ssget will not find it as usual, as the name of the block reference is changed to "*XX..." , but if the dynamic block is inserted with no active dynamic property then the original block name is preserved until you change some dynamic property on it.
Try this:
(defun countblk(blkName / ss s i n ent obj) (vl-load-com) (setq ss (ssget "X" '((0 . "INSERT")))) (setq s 0) (if ss (progn (setq i 0) (setq n (sslength ss)) (while (< i n) (setq ent (ssname ss i)) (setq obj (vlax-ename->vla-object ent)) (if (= blkName (vlax-get obj 'EffectiveName)) (setq s (+ s 1)) ) (setq i (+ i 1)) ) ) ) s ) (defun c:countblk() (setq blkName (getstring "\Block Name: ")) (alert (strcat "Block Count:=" (itoa (countblk blkName)))) (princ) )
Gaston Nunez
Thanks Gaston, that worked great.
Now for part two, am i also able to have the blocks selected after being counted as in my original routine (SSSETFIRST NIL BLOCKSET)? I wasn't able to figure out what the selection set is in your routine or if there is a selection set of the specified blocks.
What i was using my routine for was to 1) get a count of the specific blocks and 2) be able to globally change attribute values. Thus the reason for (SSSETFIRST NIL BLOCKSET)
Larry
Hi,
You can't select dynamic blocks using a name filter, so you have to select *all* the inserts in the dwg, and then get the effective name of the block references and compare it to the search name. If you need a selection set with the founded blocks, you have to add it "manually" as in:
(defun countblk(blkName / ss s i n ent obj) (vl-load-com) (setq ss (ssget "X" '((0 . "INSERT")))) (setq s 0) (if ss (progn (setq MyBlocksSS (ssadd)) ;The SS with the found blocks (setq i 0) (setq n (sslength ss)) (while (< i n) (setq ent (ssname ss i)) (setq obj (vlax-ename->vla-object ent)) (if (= blkName (vlax-get obj 'EffectiveName)) (progn (setq s (+ s 1)) (ssadd ent MyBlocksSS) ;; Add the found block to the SS ) ) (setq i (+ i 1)) ) ) ) s )
Now you have the blocks in the MyBlocksSS selection set
Gaston Nunez
Thank you very much Gaston. That worked perfectly.
Now I don't want to push my luck, but is there anyway to search for blocks by their name AND visibility state?
Hi,
You can get the dynamic properties from a block using this nice function from Lee Mac:
;;------------=={ Get Dynamic Property Value }==--------------;; ;; ;; ;; Returns the value of a Dynamic Block Property, if present ;; ;;------------------------------------------------------------;; ;; Author: Lee Mac, Copyright © 2010 - www.lee-mac.com ;; ;;------------------------------------------------------------;; ;; Arguments: ;; ;; block - VLA Dynamic Block Reference Object ;; ;; prop - Dynamic Block Property Name ;; ;;------------------------------------------------------------;; ;; Returns: Value of property, else nil ;; ;;------------------------------------------------------------;; (defun LM:GetDynamicPropValue ( block prop ) (setq prop (strcase prop)) (vl-some (function (lambda ( _prop ) (if (eq prop (strcase (vla-get-propertyname _prop))) (vlax-get _prop 'Value) ) ) ) (vlax-invoke block 'GetDynamicBlockProperties) ) )
Gaston Nunez
@bdsmls wrote:Thank you very much Gaston. That worked perfectly.
You can reduce the number of selected blocks by using a wildcard match
(setq ss (ssget "_X" (list '(0 . "INSERT") (cons 2 (strcat blkName ",`*U*")))))
@bdsmls wrote:
.....
Now I don't want to push my luck, but is there anyway to search for blocks by their name AND visibility state?
Unfortunately there is no easy way to "catch" those without knowing the specific visibility parameter name, not saying there is none. Parameter names may vary from one DB to another, the Visibiity parameter name may or may not be be "Visibility" , depending on the DB's author.
Anyhoo. to count DB and their respective visility state
(defun DbVisName (bname vis / ss data i e pname vis vname inc) (vl-load-com) (if (setq data nil ss (ssget "_X" (list (cons 0 "INSERT") (cons 2 (strcat bname ",`*U*"))))) (progn (repeat (setq i (sslength ss)) (cond ((and (eq (strcase (vla-get-EffectiveName (setq e (vlax-ename->vla-object (ssname ss (setq i (1- i))))))) (strcase bname)) (setq Pname (car (vl-remove-if-not '(lambda (j) (eq (strcase (vla-get-PropertyName j)) (strcase vis))) (vlax-invoke e 'GetDynamicBlockProperties)))) (setq vname (vlax-get Pname 'Value)) (if (setq inc (assoc vname data)) (setq data (subst (list vname (1+ (cadr inc))) inc data)) (setq data (cons (list vname 1) data))) ))) ) (princ (strcat "\nTotal \"" bname "\" Blocks Found: " (itoa (apply '+ (mapcar 'cadr data))))) (foreach itm data (print itm)) ) )(if (null data) (princ "\nBlock/Parameter Name not found")) (princ) )
command (dbvisname "FD" "visibility")
Total "FD" Blocks Found: 11
("VisState1" 3)
("VisState1" 1)
("VisState3" 😎
command (dbvisname "FDX" "visibility2")
Total "FDX" Blocks Found: 0
Block/Parameter Name not found
HTH
I'm getting a "Too Few Arguments" error when I try using the 'DbVisName' function. I added a c: to make it a command - am I doing something wrong? Apologies, I'm new to Lisp. Thanks!
Chris
Welcome to the Autodesk Discussion Groups, Chris!
Pebejse's function DbVisName, have two arguments,
bname -> the block name
vis -> the visibility parameter name
you'll kneed to load the code and run the code with something like this
(dbvisname "YourBlockName" "TheVisibilityParameterName")
or to use the function at the commandline as a command, without changing the original code, perhaps something like this
Not tested, I don't have AutoCAD in this pc...
(defun c:test ( / blkname parname) ;; by pbejse ;; http://forums.autodesk.com/t5/Visual-LISP-AutoLISP-and-General/Count-Dynamic-Blocks/m-p/3738778#M308... (defun DbVisName (bname vis / ss data i e pname vis vname inc) (vl-load-com) (if (setq data nil ss (ssget "_X" (list (cons 0 "INSERT") (cons 2 (strcat bname ",`*U*"))))) (progn (repeat (setq i (sslength ss)) (cond ((and (eq (strcase (vla-get-EffectiveName (setq e (vlax-ename->vla-object (ssname ss (setq i (1- i))))))) (strcase bname)) (setq Pname (car (vl-remove-if-not '(lambda (j) (eq (strcase (vla-get-PropertyName j)) (strcase vis))) (vlax-invoke e 'GetDynamicBlockProperties)))) (setq vname (vlax-get Pname 'Value)) (if (setq inc (assoc vname data)) (setq data (subst (list vname (1+ (cadr inc))) inc data)) (setq data (cons (list vname 1) data))) ))) ) (princ (strcat "\nTotal \"" bname "\" Blocks Found: " (itoa (apply '+ (mapcar 'cadr data))))) (foreach itm data (print itm)) ) )(if (null data) (princ "\nBlock/Parameter Name not found")) (princ) ) (if (and (setq blkname (getstring T "\nEnter the Block Name: ")) (setq parname (getstring "\nEnter the Visibility Parameter Name: ")) );; and (dbvisname blkname parname) );; if (princ) )
HTH
Henrique
Chris,
If the above solution is suitable to you, change
(setq parname (getstring "\nEnter the Visibility Parameter Name: "))
to
(setq parname (getstring T "\nEnter the Visibility Parameter Name: "))
to allow strings with empty spaces...
HTH
Henrique
Wow, thanks for the quick response!
The code you wrote worked for what it was supposed to do but what I'm trying to do is audit the drawing for dynamic blocks with a specific visability perameter name. Your code is great if you already know the exact block name, but I'm trying to find out the block names of the blocks with the visability perameter called "OBJECT". Basically I'm trying to run the routine with one arguement: visability name is "OBJECT".
I tried removing this bit of the code that prompted for the blockname but I get '; error: bad argument type: stringp nil:"
Thanks again for your help!
Chris
here is the line of code I tried removing to no success:
(and (setq blkname (getstring T "\nEnter the Block Name: "))
@ pbejse
Sorry, 'm murdering your code...
@Anonymous wrote:
Wow, thanks for the quick response!
The code you wrote worked for what it was supposed to do but what I'm trying to do is audit the drawing for dynamic blocks with a specific visability perameter name. Your code is great if you already know the exact block name, but I'm trying to find out the block names of the blocks with the visability perameter called "OBJECT". Basically I'm trying to run the routine with one arguement: visability name is "OBJECT".
I tried removing this bit of the code that prompted for the blockname but I get '; error: bad argument type: stringp nil:"
Thanks again for your help!
Chris
here is the line of code I tried removing to no success:
(and (setq blkname (getstring T "\nEnter the Block Name: "))
@ Chris
the code isn't mine, is from pebejse, I just add some code lines in order to use pebejse's function at the commandline as a command.
when our doubts/difficulties, are not the same as the original post, is always preferable to start a new thread with a new title because you'll get more help than in a old thread, and the help you receive will be directed to your doubt/difficulty...
I have a deadline to meet today and I don't have much free time, just a quick one, minimally tested and as a "demo" and "ruining pebejse's code"
(defun c:test (/ BNAME DATA E I PNAME SS VIS) (if (setq data nil vis (getstring T "\nEnter the Visibility Parameter Name: ") ss (ssget "_X" (list (cons 0 "INSERT") (cons 2 "`*U*") ) ) ) ;; setq (progn (repeat (setq i (sslength ss)) (cond ((and (setq bname (vla-get-EffectiveName (setq e (vlax-ename->vla-object (ssname ss (setq i (1- i)) ) ) ) ) ) (setq Pname (car (vl-remove-if-not '(lambda (j) (eq (strcase (vla-get-PropertyName j)) (strcase vis) ) ) (vlax-invoke e 'GetDynamicBlockProperties) ) ) ) (not (member bname data)) ) (setq data (cons bname data)) (foreach itm data (print itm)) ) );; cond );; repeat );; progn );; if (if (null data) (princ "\nBlock/Parameter Name not found")) (princ) )
HTH
Henrique
@Anonymous wrote:
... sorry if I'm out of line with the code...
...
What I tried to say, was that it should be easier to receive some help in a new thread...
@Anonymous wrote:
Thanks so much ...
...
You're welcome, Chris
Henrique