Scanning blocks and counting attribute instances?

Discussion in 'AutoCAD' started by pkirill, Mar 31, 2005.

  1. pkirill

    pkirill Guest

    I know how to scan the block table and count the number of blocks with a certain attribute tag value. What I am having trouble with is scanning the blocks, and counting the number of *different* values when I actually have no idea what the values might be. For example I have a drawing with 80 instances of a block named P-FIXT-F that has an attribute tag of TYPE. Of the 80, there may be 15 with the TYPE value of "L1", 23 with "P1", 42 with "G2" and 20 with "H1".

    I'm trying to come up with a routine that will look at the TYPE value and create a separate count for each different value it comes across. But without knowing all the possible TYPEs to evaluate against and including them in the code, I can't seem to get it to work...

    Does this make any sense?

    Any help would be greatly appreciated!

    Thanks!
     
    pkirill, Mar 31, 2005
    #1
  2. pkirill

    Jeff Mishler Guest

    I think you want something like this which returns a list of dotted pairs:
    (("attvalue" . Total found)("attvalue" . Total found)("attvalue" . Total
    found))
    Here's a sample from running the code in my sample Topo drawing :

    Command: (count_atts "point" "desc")

    Select objects: Specify opposite corner: 15 found
    2 were filtered out.

    Select objects:
    (("TOE" . 1) ("NG" . 5) ("FL" . 4) ("START" . 1) ("CONT" . 1) ("DAYLIGHT" .
    1))

    You can then take the return value and do what you need with it.

    Code:
    (defun count_atts (bname att_tag / ss idx ent atts att val tally)
    (vl-load-com)
    (if (setq ss (ssget (list '(0 . "INSERT")(cons 2 bname)'(66 . 1))))
    (progn
    (setq idx -1)
    (while (< (setq idx (1+ idx))(sslength ss))
    (setq ent (vlax-ename->vla-object (ssname ss idx)))
    (setq atts (vlax-invoke ent 'getattributes))
    (foreach att atts
    (if (eq (vla-get-tagstring att) (strcase att_tag))
    (progn
    (setq val (vla-get-textstring att))
    (cond ((member (assoc val tally) tally)
    (setq tally (subst (cons val (1+ (cdr (assoc val
    tally)))) (assoc val tally) tally)))
    (tally (setq tally (append tally (list (cons val 1)))))
    (t (setq tally (list (cons val 1))))
    )
    );progn
    );if
    );foreach
    );while
    );progn
    );if
    tally ;return the values
    );defun
    
    --
    Jeff
    check out www.cadvault.com
    I know how to scan the block table and count the number of blocks with a
    certain attribute tag value. What I am having trouble with is scanning the
    blocks, and counting the number of *different* values when I actually have
    no idea what the values might be. For example I have a drawing with 80
    instances of a block named P-FIXT-F that has an attribute tag of TYPE. Of
    the 80, there may be 15 with the TYPE value of "L1", 23 with "P1", 42 with
    "G2" and 20 with "H1".

    I'm trying to come up with a routine that will look at the TYPE value and
    create a separate count for each different value it comes across. But
    without knowing all the possible TYPEs to evaluate against and including
    them in the code, I can't seem to get it to work...

    Does this make any sense?

    Any help would be greatly appreciated!

    Thanks!
     
    Jeff Mishler, Mar 31, 2005
    #2
  3. pkirill

    pkirill Guest

    Jeff - Thanks so much! That was exactly what I was hoping for!

    Here's what I wound up with in the end:


    (defun C:CBBA ()
    (if (or (= bname_show nil)
    (= bname_show ""))
    (setq bname_show ".")
    )
    (setq bname (getstring (strcat "\n\n\n\n\n\n\n\nEnter block name or
    Select block <" bname_show ">:")))
    (cond
    ((= (strcase bname) "S")(select_block))
    ((and (= bname "")(< (strlen bname_show)2))(vl-exit-with-value nil))
    ((and (> (strlen bname_show) 1)(= bname ""))(setq bname bname_show))
    )
    (setq bname_show bname)
    (select_tag)
    (count_atts bname att_tag)
    )
    (defun select_block ()
    (setq b-ename (car (entsel "Select block: ")))
    (while (not b-ename)
    (setq b-ename (car (entsel "Nothing selected. Try again.\nSelect block:
    "))))
    (setq blockent (entget b-ename))
    (if (/= (cdr (assoc 0 blockent)) "INSERT")
    (setq blockent (entget (setq b-ename (car (entsel "Entity is not a
    block. Try again.\nSelect block: ")))))
    (setq bname (cdr (assoc 2 blockent)))
    )
    )

    (defun select_tag ( / att_list)
    (if (or (= att_num_show nil)
    (= att_num_show ""))
    (setq att_num_show ".")
    )
    (vl-load-com)
    (setq ent (vlax-ename->vla-object b-ename))
    (setq atts (vlax-invoke ent 'getattributes))
    (setq att_cnt 0)
    (textscr)

    (princ (strcat "\n\nList of attributes in selected block:" (strcase bname)
    "\n"))
    (foreach att atts
    (princ (strcat "\n" (itoa (setq att_cnt (+ att_cnt 1))) ". " (setq att_tag
    (vla-get-tagstring att))))
    (setq att_list (cons att_tag att_list))
    )
    (setq att_list (reverse att_list))
    (setq att_num (getint (strcat "\n\nSelect tag by number (1-"(itoa
    att_cnt)")<" att_num_show ">: ")))
    (cond
    ((and (= att_num nil)(= att_num_show "."))(progn (princ "\nNo attribute
    selected! Exiting...")(vl-exit-with-value nil)))
    ((and (= att_num nil)(> (atoi att_num_show) 0))(setq att_num (atoi
    att_num_show)))
    )
    (while (or (< att_num 1)
    (> att_num att_cnt)
    )
    (setq att_num (getint (strcat "You must select a number between 1 and "
    (itoa att_cnt) "\nSelect tag by number (1-"(itoa att_cnt)")<" att_num_show
    ">: ")))
    )
    (setq att_num_show (itoa att_num))
    (setq att_tag (nth (- att_num 1) att_list))
    (princ (strcat "Sort by: " att_tag))
    )

    ;Special thanks to Jeff Mishler from the autodesk.autocad.customization
    newsgroup
    ;for kindly providing the count_atts subr!!
    (defun count_atts (bname att_tag / ss idx ent atts att val tally)
    (vl-load-com)
    (princ "\n\nSelecting blocks to evaluate... ")
    (if (setq ss (ssget (list '(0 . "INSERT")(cons 2 bname)'(66 . 1))))
    (progn
    (setq idx -1)
    (while (< (setq idx (1+ idx))(sslength ss))
    (setq ent (vlax-ename->vla-object (ssname ss idx)))
    (setq atts (vlax-invoke ent 'getattributes))
    (foreach att atts
    (if (eq (vla-get-tagstring att) (strcase att_tag))
    (progn
    (setq val (vla-get-textstring att))
    (cond ((member (assoc val tally) tally)
    (setq tally (subst (cons val (1+ (cdr (assoc val
    tally)))) (assoc val tally) tally)))
    (tally (setq tally (append tally (list (cons val 1)))))
    (t (setq tally (list (cons val 1))))
    )
    );progn
    );if
    );foreach
    );while
    );progn
    );if
    ;tally ;return the values
    (textscr)
    (princ (strcat "\n\n\nCount of " (strcase bname) " blocks by
    attribute:\n"))
    (foreach n tally
    (setq att_val (car n))
    (if (= (substr att_val 1 2) "%%")
    (setq att_val (substr att_val 4 (strlen att_val)))
    )
    (setq att_ttl (itoa (cdr n)))
    (princ (strcat att_val " = " att_ttl "\n"))
    )
    (setq print_to_file (getstring "Would you like to save these to a CSV or
    TXT file or Quit? [C/T/<Q>]: "))
    (cond
    ((or (= (strcase print_to_file) "Q")
    (= print_to_file "")
    )
    (vl-exit-with-value nil))
    ((= (strcase print_to_file) "C")(export_to_csv tally))
    ((= (strcase print_to_file) "T")(export_to_txt tally))
    )
    (princ)
    );defun

    (defun export_to_csv ( tally )
    (setq def_filename (strcat (vl-filename-base (getvar "dwgname"))
    "_att_count"))
    (setq path (getfiled "Save Block Count CSV" def_filename "csv" 1))
    (setq f (open path "w"))
    (foreach n tally
    (setq att_val (car n))
    (if (= (substr att_val 1 2) "%%")
    (setq att_val (substr att_val 4 (strlen att_val)))
    )
    (setq att_ttl (itoa (cdr n)))
    (write-line (strcat att_val "," att_ttl) f)
    )
    (close f)
    )

    (defun export_to_txt ( tally )
    (setq def_filename (strcat (vl-filename-base (getvar "dwgname"))
    "_att_count"))
    (setq path (getfiled "Save Block Count TXT" def_filename "txt" 1))
    (setq f (open path "w"))
    (foreach n tally
    (setq att_val (car n))
    (if (= (substr att_val 1 2) "%%")
    (setq att_val (substr att_val 4 (strlen att_val)))
    )
    (setq att_ttl (itoa (cdr n)))
    (write-line (strcat att_val "," att_ttl) f)
    )
    (close f)
    )
     
    pkirill, Apr 1, 2005
    #3
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.