Attribute count with table

Attribute count with table

C.Utzinger
Collaborator Collaborator
6,210 Views
51 Replies
Message 1 of 52

Attribute count with table

C.Utzinger
Collaborator
Collaborator

Hello

 

I have found the following code.

 

(defun C:COUNTATT(/ acapp acol acsp adoc atable attdata attitem atts blkdata blkname blkobj col
        column colwidth  datalist en headers pt row sset swap  tabledata tags total txtheight widths x)
  
  ;private function
 
  (defun sum-and-groupby-three (lst / groups res sum tmp)
  (while lst
    (setq tmp        (car lst)
      sum
            (apply '+
               (mapcar 'atoi (mapcar 'cdadr 
                   (setq res (vl-remove-if-not

                           '(lambda (a) (and
                                  (eq (cdr (nth 0 a)) (cdr (nth 0 tmp)))
                                  (eq (cdr (nth 1 a)) (cdr (nth 1 tmp)))
                                  (eq (cdr (nth 2 a)) (cdr (nth 2 tmp)))))

                           lst

                         )
                   )
               ))
            )
      groups    (cons (subst (cons "QTY" (itoa sum))(cadr tmp) tmp) groups)
      lst
            (vl-remove-if
              '(lambda (a) (member a res))

              lst

            )
    )
  )
 
 (reverse groups)
)

;            main part            ;
  (if (setq sset (ssget (list (cons 0 "INSERT") (cons 66 1))))
    (progn
      (setq tabledata nil
        attdata nil
        attitem nil
      )
      
      (while (setq en (ssname sset 0))
    (setq blkobj  (vlax-ename->vla-object en)
          blkname (vla-get-effectivename blkobj)
    )
    (setq atts (vlax-invoke blkobj 'getattributes))
    (foreach attobj    atts

          (setq attitem (cons (vla-get-tagstring attobj) (vla-get-textstring attobj)))
          (setq attdata (cons attitem attdata))

    )

    (setq tabledata (cons (reverse attdata) tabledata))
    (setq attdata nil
          attitem nil
    )
    (ssdel en sset)
      )
(setq headers (mapcar 'car (car tabledata))
        tags    headers 
      )
(setq tabledata (sum-and-groupby-three tabledata))

(setq tabledata (mapcar '(lambda (x)
                 (mapcar 'cdr x)
                   )
                  tabledata
              )
      )


      ;; sort by "A1" :
      
     (setq tabledata (vl-sort   tabledata '(lambda(a b)(< (car a)(car b)))))

 
      (setq total 0)
      (foreach i datalist (setq total (+ total (cdr i))))
    (initget 6)
  (setq txtheight (getreal "\nSpecify Text height for the table <50>:"))
  (cond ((not txtheight)(setq txtheight 50))) ;<-- text height as for as in your drawing

       (or adoc (setq adoc (vla-get-activedocument (setq acapp (vlax-get-acad-object)))))
      (or acsp (setq acsp (vla-get-block (vla-get-activelayout adoc))))
(setq acCol (vla-GetInterfaceObject acapp(strcat "AutoCAD.AcCmColor." (itoa(atoi(getvar "acadver"))))))
      (setq pt (getpoint "\nSpecify table location:"))
      (setq atable (vla-addtable
             acsp
             (vlax-3d-point pt)
             (+ 2 (length tabledata))
             (length headers)
             (* txtheight 1.2)
             (* txtheight 20)
           )
      )
      (vla-put-regeneratetablesuppressed atable :vlax-true)
       ;; calculate column widths : 
      (setq swap (append (list headers) tabledata)
        widths nil)
      (while (car swap)
    (setq column (mapcar 'car swap))
    (setq colwidth (* 1.2 (apply 'max (mapcar 'strlen column))txtheight))
    (setq widths (cons colwidth widths))
    (setq swap (mapcar 'cdr swap)))

      (setq widths (reverse widths))
       ;; set column widths
       (setq col 0)
       (foreach wid widths
         (vla-setcolumnwidth atable col wid)
         (setq col (1+ col))
         )
      (vla-put-horzcellmargin atable (* txtheight 0.5))
      (vla-put-vertcellmargin atable (* txtheight 0.3))
      (vla-setTextheight atable 1 txtheight)
      (vla-setTextheight atable 2 txtheight)
      (vla-setTextheight atable 4 txtheight)
      (vla-setText atable 0 0 "ATTRIBUTE SUMMARY")
      (vla-SetCellAlignment atable 0 0 acMiddleCenter)
            (vla-put-colorindex accol 2)
(vla-setcellcontentcolor atable 0 0 accol)
      (setq col -1)
      (foreach descr headers
    (vla-setText atable 1 (setq col (1+ col)) descr)
    (vla-SetCellAlignment atable 1 col acMiddleCenter)
    (vla-setcellcontentcolor atable 1 col accol)
      )
      
        (vla-put-colorindex accol 4)
      
       (setq row 2)
      
      (foreach record tabledata

    (setq col 0)
    (foreach item record
      (vla-setText atable row col item)
      (if (= 1 col)
      (vla-SetCellAlignment atable row col acMiddleCenter)
      (vla-SetCellAlignment atable row col acMiddleLeft)
           )
      (vla-setcellcontentcolor atable row col accol)
      (setq col (1+ col))
    )
    (setq row (1+ row))
      )
(vla-put-width atable (apply '+ widths))
      (vla-put-height atable (* 1.2 (vla-get-rows atable)txtheight))
      (vla-put-regeneratetablesuppressed atable :vlax-false)

    )
  )
 (if  accol (vlax-release-object accol))
 (if  acapp (vlax-release-object acapp))
(princ)
)
(prompt "\n\t---\tStart command with COUNTATT\t---\n")
(prin1)
 (or (vl-load-com))
(princ)

 

 

It works great, but i need it a Little different.

 

Is it possible to include Mleader with block and attributes?

 

And it would be great if it takes (from the atached blocks) the Attribute Position as type and Count the other two attributes. I mean like:

 

Pos.12 :   23x 83cm / 25x 125cm

 

Thank you in advance...

0 Likes
Accepted solutions (3)
6,211 Views
51 Replies
Replies (51)
Message 2 of 52

C.Utzinger
Collaborator
Collaborator

Here are more files i will use

0 Likes
Message 3 of 52

ВeekeeCZ
Consultant
Consultant

Following code works with MLEADERs and BLOCKs. Not with M/TEXTs.

 

Block always needs to include tag "POS."

 

(vl-load-com)

(defun c:COUNTATT (/ :sortlst acapp acol acsp adoc atable attdata attitem atts blkdata blkname blkobj col
                   column colwidth  datalist en headers pt row ss swap  tabledata tags total txtheight widths x)
  
  ;; Lee Mac
  ;; http://www.lee-mac.com/attributefunctions.html
  
  (defun LM:vl-getattributes ( blk )
    (mapcar '(lambda (att) (cons (vla-get-tagstring att) (vla-get-textstring att)))
            (vlax-invoke blk 'getattributes)))
  
  
  ;; Lee Mac
  ;; https://www.theswamp.org/index.php?topic=46547.0
  (defun LM:vl-getmleaderatts ( obj / rtn )
    (if (and (= "AcDbMLeader"  (vla-get-objectname  obj))
             (= acblockcontent (vla-get-contenttype obj)))
      (vlax-for sub (vla-item (vla-get-blocks (vla-get-document obj))
                              (vla-get-contentblockname obj))
        (if (= "AcDbAttributeDefinition" (vla-get-objectname sub))
          (setq rtn (cons (cons (vla-get-tagstring sub)
                                (vla-getblockattributevalue obj (LM:objectid sub)))
                          rtn)))))
    (reverse rtn))
  
  ;; ObjectID  -  Lee Mac
  ;; Returns a string containing the ObjectID of a supplied VLA-Object
  ;; Compatible with 32-bit & 64-bit systems
  
  (defun LM:objectid ( obj )
    (eval (list 'defun 'LM:objectid '(obj)
                (if (and (wcmatch (getenv "PROCESSOR_ARCHITECTURE") "*64*")
                         (vlax-method-applicable-p (vla-get-utility (LM:acdoc)) 'getobjectidstring))
                  (list 'vla-getobjectidstring (vla-get-utility (LM:acdoc)) 'obj ':vlax-false)
                  '(itoa (vla-get-objectid obj)))))
    (LM:objectid obj))
  
  ;; Active Document  -  Lee Mac
  ;; Returns the VLA Active Document Object
  
  (defun LM:acdoc nil
    (eval (list 'defun 'LM:acdoc 'nil (vla-get-activedocument (vlax-get-acad-object))))
    (LM:acdoc))
  ;|

  ; fixo
  (defun sum-and-groupby-three (lst / groups res sum tmp)
    (while lst
      (setq tmp (car lst)
	    sum (apply '+
		       (mapcar 'atoi (mapcar 'cdadr
					     (setq res (vl-remove-if-not
							 '(lambda (a) (and (eq (cdr (nth 0 a)) (cdr (nth 0 tmp)))
									   (eq (cdr (nth 1 a)) (cdr (nth 1 tmp)))
									   (eq (cdr (nth 2 a)) (cdr (nth 2 tmp)))))
							 lst)))))
	    groups (cons (subst (cons "QTY" (itoa sum))(cadr tmp) tmp) groups)
	    lst (vl-remove-if '(lambda (a) (member a res)) lst)))
    (reverse groups))
|;
  

;|

;sorts:

'(
(("POS." . "51") ("83CM" . "40") ("125CM" . "65"))
(("POS." . "51") ("83CM" . "45") ("125CM" . "65"))
(("POS." . "50") ("83CM" . "30") ("125CM" . "75"))
(("POS." . "50") ("83CM" . "45") ("125CM" . "75")))

;to

'(
(("POS." . "50") ("83CM" . "75") ("125CM" . "150"))
(("POS." . "51") ("83CM" . "85") ("125CM" . "130")))
|;
    
  (defun :sortlst (lst / nlst mlst)
    
    (setq lst (vl-remove nil (mapcar '(lambda (x) (if (setq a (assoc "POS." x))
                                                    (cons a (vl-sort (vl-remove-if '(lambda (y) (= "POS." (car y))) x)			; make '("POS." . x) the first member
                                                                     '(lambda (a1 a2) (< (atoi (car a1)) (atoi (car a2))))))))		; sort the rest by its value
                                     lst)))
    (foreach e lst
      (setq nlst (if (setq a (assoc (car e) nlst))
                   (subst (progn
                            (setq mlst a)
                            (foreach ee (vl-remove-if '(lambda (y) (= "POS." (car y))) e)
                              (setq mlst (if (setq aa (assoc (car ee) mlst))
                                           (subst (cons (car ee) (itoa (+ (atoi (cdr aa))
                                                                          (atoi (cdr ee)))))
                                                  aa
                                                  mlst)
                                           (reverse (cons ee (reverse a))))))
                            mlst)
                          a
                          nlst)
                   (cons e nlst))))
    (reverse nlst))
  
  
  ; ----------------------------------------------------------------------------------------------------------------------------
  ; ----------------------------------------------------------------------------------------------------------------------------
  
  
  
  (if (setq ss (ssget '((-4 . "<OR")
                        (-4 . "<AND") (0 . "INSERT") (66 . 1) (-4 . "AND>")
                        (0 . "MULTILEADER") (-4 . "OR>"))))
    (progn
      (repeat (setq i (sslength ss))
        (setq obj (vlax-ename->vla-object (ssname ss (setq i (1- i))))
              tabledata (cons (if (= "AcDbMLeader" (vla-get-objectname  obj))
                                (LM:vl-getmleaderatts obj)
                                (LM:vl-getattributes obj))
                              tabledata)))
      (print tabledata)
      
      (setq headers (mapcar 'car (car tabledata))
            tags    headers
            tabledata (:sortlst tabledata)
            tabledata (mapcar '(lambda (x) (mapcar 'cdr x))
                              tabledata))
      
      ;; sort by "A1" :
      
      (setq tabledata (vl-sort   tabledata '(lambda (a b)(< (car a)(car b)))))
      
      (setq total 0)
      (foreach i datalist (setq total (+ total (cdr i))))
      
      (initget 6)
      (setq txtheight (cond ((getreal "\nSpecify Text height for the table <50>: "))
                            (50))) ;<-- text height as for as in your drawing
      
      (or adoc (setq adoc (vla-get-activedocument (setq acapp (vlax-get-acad-object)))))
      (or acsp (setq acsp (vla-get-block (vla-get-activelayout adoc))))
      (setq acCol (vla-GetInterfaceObject acapp(strcat "AutoCAD.AcCmColor." (itoa (atoi (getvar "acadver"))))))
      
      (setq pt (getpoint "\nSpecify table location:")
            atable (vla-addtable
                     acsp
                     (vlax-3d-point pt)
                     (+ 2 (length tabledata))
                     (length headers)
                     (* txtheight 1.2)
                     (* txtheight 20)))
      
      (vla-put-regeneratetablesuppressed atable :vlax-true)
      
      ;; calculate column widths :
      (setq swap (append (list headers) tabledata)
            widths nil)
      (while (car swap)
        (setq column (mapcar 'car swap)
              colwidth (* 1.2 (apply 'max (mapcar 'strlen column)) txtheight)
              widths (cons colwidth widths)
              swap (mapcar 'cdr swap)))
      
      (setq widths (reverse widths))
      ;; set column widths
      (setq col 0)
      
      (foreach wid widths
        (vla-setcolumnwidth atable col wid)
        (setq col (1+ col)))
      
      (vla-put-horzcellmargin atable (* txtheight 0.5))
      (vla-put-vertcellmargin atable (* txtheight 0.3))
      (vla-setTextheight atable 1 txtheight)
      (vla-setTextheight atable 2 txtheight)
      (vla-setTextheight atable 4 txtheight)
      (vla-setText atable 0 0 "ATTRIBUTE SUMMARY")
      (vla-SetCellAlignment atable 0 0 acMiddleCenter)
      (vla-put-colorindex accol 2)
      (vla-setcellcontentcolor atable 0 0 accol)
      
      (setq col -1)
      (foreach descr headers
        (vla-setText atable 1 (setq col (1+ col)) descr)
        (vla-SetCellAlignment atable 1 col acMiddleCenter)
        (vla-setcellcontentcolor atable 1 col accol))
      
      (vla-put-colorindex accol 4)
      
      (setq row 2)
      
      (foreach record tabledata
        (setq col 0)
        (foreach item record
          (vla-setText atable row col item)
          (if (= 1 col)
            (vla-SetCellAlignment atable row col acMiddleCenter)
            (vla-SetCellAlignment atable row col acMiddleLeft))
          (vla-setcellcontentcolor atable row col accol)
          (setq col (1+ col)))
        (setq row (1+ row)))
      
      (vla-put-width atable (apply '+ widths))
      (vla-put-height atable (* 1.2 (vla-get-rows atable)txtheight))
      (vla-put-regeneratetablesuppressed atable :vlax-false)))
  
  (if  accol (vlax-release-object accol))
  (if  acapp (vlax-release-object acapp))
  (princ)
  )

(prompt "\n\t---\tStart command with COUNTATT\t---\n")
(princ)

 

 

0 Likes
Message 4 of 52

C.Utzinger
Collaborator
Collaborator

COOL!!!

 

Thats what i'm looking for...

 

Something is still wrong... when there are blocks with both attributes 125 and 83cm, then it works great. When there are two different blocks, one with only 83cm and one with both, then the table appears with no text.

 

Can you fix this?

0 Likes
Message 5 of 52

C.Utzinger
Collaborator
Collaborator

This Problem was also with the initial code...

0 Likes
Message 6 of 52

ВeekeeCZ
Consultant
Consultant

@c.utzinger wrote:

COOL!!!

 

Thats what i'm looking for...

 

Something is still wrong... when there are blocks with both attributes 125 and 83cm, then it works great. When there are two different blocks, one with only 83cm and one with both, then the table appears with no text.

 

Can you fix this?


Maybe later. But it should not be much difficult. Try yourself.

 

This is what you need to do - fill blanks.

 

; you have

'(
(("POS." . "25") ("200CM" . "10"))
(("POS." . "26") ("83CM" . "15") ("125CM" . "20"))
(("POS." . "27") ("125CM" . "10"))
)

; needs to be

'(
(("POS." . "25") ("83CM" . "") ("125CM" . "") ("200CM" . "10"))
(("POS." . "26") ("83CM" . "15") ("125CM" . "20") ("200CM" . ""))
(("POS." . "27") ("83CM" . "") ("125CM" . "10") ("200CM" . ""))
)

 

 

0 Likes
Message 7 of 52

ВeekeeCZ
Consultant
Consultant
Accepted solution

Not sure if you're going to try -- if so then consider this as the spoiler.

 

(vl-load-com)

(defun c:COUNTATT (/ :sortlst acapp acol acsp adoc atable attdata attitem atts blkdata blkname blkobj col
                   column colwidth  datalist en headers pt row ss swap  tabledata tags total txtheight widths x)
  
  ;; Lee Mac
  ;; http://www.lee-mac.com/attributefunctions.html
  
  (defun LM:vl-getattributes ( blk )
    (mapcar '(lambda (att) (cons (vla-get-tagstring att) (vla-get-textstring att)))
            (vlax-invoke blk 'getattributes)))
  
  
  ;; Lee Mac
  ;; https://www.theswamp.org/index.php?topic=46547.0
  (defun LM:vl-getmleaderatts ( obj / rtn )
    (if (and (= "AcDbMLeader"  (vla-get-objectname  obj))
             (= acblockcontent (vla-get-contenttype obj)))
      (vlax-for sub (vla-item (vla-get-blocks (vla-get-document obj))
                              (vla-get-contentblockname obj))
        (if (= "AcDbAttributeDefinition" (vla-get-objectname sub))
          (setq rtn (cons (cons (vla-get-tagstring sub)
                                (vla-getblockattributevalue obj (LM:objectid sub)))
                          rtn)))))
    (reverse rtn))
  
  ;; ObjectID  -  Lee Mac
  ;; Returns a string containing the ObjectID of a supplied VLA-Object
  ;; Compatible with 32-bit & 64-bit systems
  
  (defun LM:objectid ( obj )
    (eval (list 'defun 'LM:objectid '(obj)
                (if (and (wcmatch (getenv "PROCESSOR_ARCHITECTURE") "*64*")
                         (vlax-method-applicable-p (vla-get-utility (LM:acdoc)) 'getobjectidstring))
                  (list 'vla-getobjectidstring (vla-get-utility (LM:acdoc)) 'obj ':vlax-false)
                  '(itoa (vla-get-objectid obj)))))
    (LM:objectid obj))
  
  ;; Active Document  -  Lee Mac
  ;; Returns the VLA Active Document Object
  
  (defun LM:acdoc nil
    (eval (list 'defun 'LM:acdoc 'nil (vla-get-activedocument (vlax-get-acad-object))))
    (LM:acdoc))
  ;|

  ; fixo
  (defun sum-and-groupby-three (lst / groups res sum tmp)
    (while lst
      (setq tmp (car lst)
	    sum (apply '+
		       (mapcar 'atoi (mapcar 'cdadr
					     (setq res (vl-remove-if-not
							 '(lambda (a) (and (eq (cdr (nth 0 a)) (cdr (nth 0 tmp)))
									   (eq (cdr (nth 1 a)) (cdr (nth 1 tmp)))
									   (eq (cdr (nth 2 a)) (cdr (nth 2 tmp)))))
							 lst)))))
	    groups (cons (subst (cons "QTY" (itoa sum))(cadr tmp) tmp) groups)
	    lst (vl-remove-if '(lambda (a) (member a res)) lst)))
    (reverse groups))
|;
  
  
  ;|

;sortlst:

'(
(("POS." . "51") ("83CM" . "40") ("125CM" . "65"))
(("POS." . "51") ("83CM" . "45") ("125CM" . "65"))
(("POS." . "50") ("83CM" . "30") ("125CM" . "75"))
(("POS." . "50") ("83CM" . "45") ("125CM" . "75"))
(("POS." . "52") ("125CM" . "75")))

;to

'(
(("POS." . "50") ("83CM" . "75") ("125CM" . "150"))
(("POS." . "51") ("83CM" . "85") ("125CM" . "130"))
(("POS." . "51") ("83CM" . "")   ("125CM" . "75"))
)
|;
  
  (defun :sortlst (lst / nlst mlst)
    
    (foreach e lst
      (if (assoc "POS." e)
        (setq nlst (if (setq a (assoc (assoc "POS." e) nlst))
                     (subst (progn
                              (setq mlst a)
                              (foreach ee (vl-remove-if '(lambda (y) (= "POS." (car y))) e)
                                (setq mlst (if (setq aa (assoc (car ee) mlst))
                                             (subst (cons (car ee) (itoa (+ (atoi (cdr aa))
                                                                            (atoi (cdr ee)))))
                                                    aa
                                                    mlst)
                                             (reverse (cons ee (reverse a))))))
                              mlst)
                            a
                            nlst)
                     (cons e nlst)))))
    
    (setq hlst (cons "POS." (mapcar '(lambda (z) (strcat (itoa z) "CM"))		; headers
                                    (cdr (vl-sort (mapcar 'atoi
                                                          (mapcar 'car
                                                                  (apply 'append
                                                                         lst)))
                                                  '<)))))
    
    (mapcar '(lambda (x) (mapcar '(lambda (y) (cond ((assoc y x))
                                                    ((cons y ""))))
                                 hlst))
            (reverse nlst))
    )
  
  
  ; ----------------------------------------------------------------------------------------------------------------------------
  ; ----------------------------------------------------------------------------------------------------------------------------
  
  
  
  (if (setq ss (ssget '((-4 . "<OR")
                        (-4 . "<AND") (0 . "INSERT") (66 . 1) (-4 . "AND>")
                        (0 . "MULTILEADER") (-4 . "OR>"))))
    (progn
      (repeat (setq i (sslength ss))
        (setq obj (vlax-ename->vla-object (ssname ss (setq i (1- i))))
              tabledata (cons (if (= "AcDbMLeader" (vla-get-objectname  obj))
                                (LM:vl-getmleaderatts obj)
                                (LM:vl-getattributes obj))
                              tabledata)))
      
      (setq tabledata (:sortlst tabledata)
            headers (mapcar 'car (car tabledata))
            tags    headers
            tabledata (mapcar '(lambda (x) (mapcar 'cdr x))
                              tabledata))
      
      ;; sort by "A1" :
      
      (setq tabledata (vl-sort   tabledata '(lambda (a b)(< (car a)(car b)))))
      
      (setq total 0)
      (foreach i datalist (setq total (+ total (cdr i))))
      
      (initget 6)
      (setq txtheight (cond ((getreal "\nSpecify Text height for the table <50>: "))
                            (50))) ;<-- text height as for as in your drawing
      
      (or adoc (setq adoc (vla-get-activedocument (setq acapp (vlax-get-acad-object)))))
      (or acsp (setq acsp (vla-get-block (vla-get-activelayout adoc))))
      (setq acCol (vla-GetInterfaceObject acapp(strcat "AutoCAD.AcCmColor." (itoa (atoi (getvar "acadver"))))))
      
      (setq pt (getpoint "\nSpecify table location:")
            atable (vla-addtable
                     acsp
                     (vlax-3d-point pt)
                     (+ 2 (length tabledata))
                     (length headers)
                     (* txtheight 1.2)
                     (* txtheight 20)))
      
      (vla-put-regeneratetablesuppressed atable :vlax-true)
      
      ;; calculate column widths :
      (setq swap (append (list headers) tabledata)
            widths nil)
      (while (car swap)
        (setq column (mapcar 'car swap)
              colwidth (* 1.2 (apply 'max (mapcar 'strlen column)) txtheight)
              widths (cons colwidth widths)
              swap (mapcar 'cdr swap)))
      
      (setq widths (reverse widths))
      ;; set column widths
      (setq col 0)
      
      (foreach wid widths
        (vla-setcolumnwidth atable col wid)
        (setq col (1+ col)))
      
      (vla-put-horzcellmargin atable (* txtheight 0.5))
      (vla-put-vertcellmargin atable (* txtheight 0.3))
      (vla-setTextheight atable 1 txtheight)
      (vla-setTextheight atable 2 txtheight)
      (vla-setTextheight atable 4 txtheight)
      (vla-setText atable 0 0 "ATTRIBUTE SUMMARY")
      (vla-SetCellAlignment atable 0 0 acMiddleCenter)
      (vla-put-colorindex accol 2)
      (vla-setcellcontentcolor atable 0 0 accol)
      
      (setq col -1)
      (foreach descr headers
        (vla-setText atable 1 (setq col (1+ col)) descr)
        (vla-SetCellAlignment atable 1 col acMiddleCenter)
        (vla-setcellcontentcolor atable 1 col accol))
      
      (vla-put-colorindex accol 4)
      
      (setq row 2)
      
      (foreach record tabledata
        (setq col 0)
        (foreach item record
          (vla-setText atable row col item)
          (if (= 1 col)
            (vla-SetCellAlignment atable row col acMiddleCenter)
            (vla-SetCellAlignment atable row col acMiddleLeft))
          (vla-setcellcontentcolor atable row col accol)
          (setq col (1+ col)))
        (setq row (1+ row)))
      
      (vla-put-width atable (apply '+ widths))
      (vla-put-height atable (* 1.2 (vla-get-rows atable)txtheight))
      (vla-put-regeneratetablesuppressed atable :vlax-false)))
  
  (if  accol (vlax-release-object accol))
  (if  acapp (vlax-release-object acapp))
  (princ)
  )

(prompt "\n\t---\tStart command with COUNTATT\t---\n")
(princ)
Message 8 of 52

C.Utzinger
Collaborator
Collaborator
Sorry between a big mountain of work, I was trying first to understand the code, but i am really lost. I will try the spoiler code tomorrow.

Thank you really really much!

Give me some Post adress that i can send you some Swiss Chocolate!!!😁😁😁

Kind regards

0 Likes
Message 9 of 52

C.Utzinger
Collaborator
Collaborator

Good Morning

 

I will give it a hard testing, but it works!!!

 

Thank you very much... Postal address?

 

 

Kind regards

 

Christian

0 Likes
Message 10 of 52

ВeekeeCZ
Consultant
Consultant

@c.utzinger wrote:
... I was trying first to understand the code, but i am really lost. I will try the spoiler code tomorrow.
...


Glad to help.

 

If you want to learn some... well, it's better to start with simple ones... but there is one approach you should definitely learn from it.

 

List sorting.

Let's say you need to sort something (eg. lenght) by eg. layer. See the olst variable.

 

(defun c:test ( / asoc olst nlst)  ; nlst localized, necessary !!
  
  (setq olst '(("Layer1" . 10)
               ("Layer2" . 20)
               ("Layer1" . 30)))
  
  (foreach item olst
    (if (setq asoc (assoc (car item) nlst))
      (setq nlst (subst (cons (car item)
                              (+ (cdr asoc) (cdr item)))
                        asoc
                        nlst))
      (setq nlst (cons item nlst))))
  nlst
  )

If you look at my :sortlst function, there is this principle used twice (main list and nested lists).

 

PS. Your offer sounds tempting. Thanks

Message 11 of 52

C.Utzinger
Collaborator
Collaborator

Good morning

 

I had to make diferent Blocks with diferent types (Comax was only one type). I will have up to for or five types. For this i made a new Attribute (C-TYP., F-TYP., etc.).

 

I just changed this part, so it will count correctly.  

 

  (defun :sortlst (lst / nlst mlst)
   
    (foreach e lst
      (if (and (assoc "POS." e) (assoc "C-TYP."))

 

 

The Problem i have now is that it takes some Attributes from the ohter blocks (sometimes from absolutly different blocks XD), it don´t Count the values but the table Looks strange (see the jpeg). 

 

I was looking at the ssget part for selelcting the blocks by name, but i don´t know how to do this.

 

(if (setq ss (ssget '((-4 . "<OR")
                        (-4 . "<AND") (0 . "INSERT") (66 . 1) (-4 . "AND>")

                        (0 . "MULTILEADER") (-4 . "OR>"))))

 

 

Can you help me with this?

 

Kind regards

Message 12 of 52

ВeekeeCZ
Consultant
Consultant
Hi. Post the dwg where this is happening M
0 Likes
Message 13 of 52

C.Utzinger
Collaborator
Collaborator

Thank you

0 Likes
Message 14 of 52

C.Utzinger
Collaborator
Collaborator

Sorry here the DWG

0 Likes
Message 15 of 52

ВeekeeCZ
Consultant
Consultant

So try improved and fixed code.

 

- added positive filter for block names. You can use wild-cards. 

- the filter is applied for ssget, but visual feedback works for simple blocks only, not for blocks within a mleader. For a mleader is impossible to make it visual, but filter is applied later in the code just not visual.

 

- there is "a filter" for an attribute name. It takes all the attributes with names: #* (meaning: starts with any number after which could be anything. 

  accepted: 10cm; 10c; 001c; 01; 126.56;

  excluded: words; c10; x1

 

(vl-load-com)

(defun c:COUNTATT (/ :sortlst acapp acol acsp adoc atable attdata attitem atts blkdata blkname blkobj col
                   column colwidth  datalist en headers pt row ss swap  tabledata tags total txtheight widths x flt)
  
  ;; Lee Mac
  ;; http://www.lee-mac.com/attributefunctions.html
  
  (defun LM:vl-getattributes ( blk )
    (mapcar '(lambda (att) (cons (vla-get-tagstring att) (vla-get-textstring att)))
            (vlax-invoke blk 'getattributes)))
  
  
  ;; Lee Mac
  ;; https://www.theswamp.org/index.php?topic=46547.0
  (defun LM:vl-getmleaderatts ( obj flt / rtn)
    (if (and (= "AcDbMLeader"  (vla-get-objectname  obj))
             (= acblockcontent (vla-get-contenttype obj))
	     (wcmatch (strcase (vla-get-contentblockname obj)) (strcase flt))
	     )
      (vlax-for sub (vla-item (vla-get-blocks (vla-get-document obj))
                              (vla-get-contentblockname obj))
        (if (= "AcDbAttributeDefinition" (vla-get-objectname sub))
          (setq rtn (cons (cons (vla-get-tagstring sub)
                                (vla-getblockattributevalue obj (LM:objectid sub)))
                          rtn)))))
    (reverse rtn))
  
  ;; ObjectID  -  Lee Mac
  ;; Returns a string containing the ObjectID of a supplied VLA-Object
  ;; Compatible with 32-bit & 64-bit systems
  
  (defun LM:objectid ( obj )
    (eval (list 'defun 'LM:objectid '(obj)
                (if (and (wcmatch (getenv "PROCESSOR_ARCHITECTURE") "*64*")
                         (vlax-method-applicable-p (vla-get-utility (LM:acdoc)) 'getobjectidstring))
                  (list 'vla-getobjectidstring (vla-get-utility (LM:acdoc)) 'obj ':vlax-false)
                  '(itoa (vla-get-objectid obj)))))
    (LM:objectid obj))
  
  ;; Active Document  -  Lee Mac
  ;; Returns the VLA Active Document Object
  
  (defun LM:acdoc nil
    (eval (list 'defun 'LM:acdoc 'nil (vla-get-activedocument (vlax-get-acad-object))))
    (LM:acdoc))
  
;|

;sortlst:

'(
(("POS." . "51") ("83CM" . "40") ("125CM" . "65"))
(("POS." . "51") ("83CM" . "45") ("125CM" . "65"))
(("POS." . "50") ("83CM" . "30") ("125CM" . "75"))
(("POS." . "50") ("83CM" . "45") ("125CM" . "75"))
(("POS." . "52") ("125CM" . "75")))

;to

'(
(("POS." . "50") ("83CM" . "75") ("125CM" . "150"))
(("POS." . "51") ("83CM" . "85") ("125CM" . "130"))
(("POS." . "51") ("83CM" . "")   ("125CM" . "75"))
)
|;
  
  (defun :sortlst (lst / nlst mlst)
    
    (foreach e lst
      (if (assoc "POS." e)
        
        (setq nlst (if (setq a (assoc (assoc "POS." e) nlst))
                     (subst (progn
                              (setq mlst a)
                              (foreach ee (vl-remove-if (function (lambda (y) (wcmatch (car y) "POS."))) e)
                                (setq mlst (if (setq aa (assoc (car ee) mlst))
                                             (subst (cons (car ee) (itoa (+ (atoi (cdr aa))
                                                                            (atoi (cdr ee)))))
                                                    aa
                                                    mlst)
                                             (cons ee mlst))))
                              mlst)
                            a
                            nlst)
                     (cons e nlst)))))
    
    (setq hlst (cons "POS." (mapcar '(lambda (z) (strcat (itoa z) "CM"))		; headers
                                    (cdr (vl-sort (mapcar 'atoi				; headers filter out - accepts any #*
                                                          (mapcar 'car
                                                                  (apply 'append
                                                                         lst)))
                                                  '<)))))
    
    (mapcar '(lambda (x) (mapcar '(lambda (y) (cond ((assoc y x))
                                                    ((cons y ""))))
                                 hlst))
            (reverse nlst))
    )
  
  
  ; ----------------------------------------------------------------------------------------------------------------------------
  ; ----------------------------------------------------------------------------------------------------------------------------
  
  (setq flt "SPI-Ferbox*T80*,SPI-Comax_T83*")			; block filter
  
  (if (setq ss (ssget (list '(-4 . "<OR")
			    '(-4 . "<AND") '(0 . "INSERT") (cons 2 flt) '(66 . 1) '(-4 . "AND>")
			    '(0 . "MULTILEADER") '(-4 . "OR>"))))
    (progn
      (repeat (setq i (sslength ss))
        (setq obj (vlax-ename->vla-object (ssname ss (setq i (1- i))))
              tabledata (cons (if (= "AcDbMLeader" (vla-get-objectname  obj))
                                (LM:vl-getmleaderatts obj flt)
                                (LM:vl-getattributes obj))
                              tabledata)))
      
      (setq tabledata (vl-remove nil tabledata)
	    tabledata (:sortlst tabledata)
            headers (mapcar 'car (car tabledata))
            tags    headers
            tabledata (mapcar '(lambda (x) (mapcar 'cdr x))
                              tabledata))
      
      ;; sort by "A1" :
      
      (setq tabledata (vl-sort tabledata '(lambda (a b)(< (car a)(car b)))))
      
      (setq total 0)
      (foreach i datalist (setq total (+ total (cdr i))))
      
      (initget 6)
      (setq txtheight (cond ((getreal "\nSpecify Text height for the table <50>: "))
                            (50))) ;<-- text height as for as in your drawing
      
      (or adoc (setq adoc (vla-get-activedocument (setq acapp (vlax-get-acad-object)))))
      (or acsp (setq acsp (vla-get-block (vla-get-activelayout adoc))))
      (setq acCol (vla-GetInterfaceObject acapp(strcat "AutoCAD.AcCmColor." (itoa (atoi (getvar "acadver"))))))
      
      (setq pt (getpoint "\nSpecify table location:")
            atable (vla-addtable
                     acsp
                     (vlax-3d-point pt)
                     (+ 2 (length tabledata))
                     (length headers)
                     (* txtheight 1.2)
                     (* txtheight 20)))
      
      (vla-put-regeneratetablesuppressed atable :vlax-true)
      
      ;; calculate column widths :
      (setq swap (append (list headers) tabledata)
            widths nil)
      (while (car swap)
        (setq column (mapcar 'car swap)
              colwidth (* 1.2 (apply 'max (mapcar 'strlen column)) txtheight)
              widths (cons colwidth widths)
              swap (mapcar 'cdr swap)))
      
      (setq widths (reverse widths))
      ;; set column widths
      (setq col 0)
      
      (foreach wid widths
        (vla-setcolumnwidth atable col wid)
        (setq col (1+ col)))
      
      (vla-put-horzcellmargin atable (* txtheight 0.5))
      (vla-put-vertcellmargin atable (* txtheight 0.3))
      (vla-setTextheight atable 1 txtheight)
      (vla-setTextheight atable 2 txtheight)
      (vla-setTextheight atable 4 txtheight)
      (vla-setText atable 0 0 "ATTRIBUTE SUMMARY")
      (vla-SetCellAlignment atable 0 0 acMiddleCenter)
      (vla-put-colorindex accol 2)
      (vla-setcellcontentcolor atable 0 0 accol)
      
      (setq col -1)
      (foreach descr headers
        (vla-setText atable 1 (setq col (1+ col)) descr)
        (vla-SetCellAlignment atable 1 col acMiddleCenter)
        (vla-setcellcontentcolor atable 1 col accol))
      
      (vla-put-colorindex accol 4)
      
      (setq row 2)
      
      (foreach record tabledata
        (setq col 0)
        (foreach item record
          (vla-setText atable row col item)
          (if (= 1 col)
            (vla-SetCellAlignment atable row col acMiddleCenter)
            (vla-SetCellAlignment atable row col acMiddleLeft))
          (vla-setcellcontentcolor atable row col accol)
          (setq col (1+ col)))
        (setq row (1+ row)))
      
      (vla-put-width atable (apply '+ widths))
      (vla-put-height atable (* 1.2 (vla-get-rows atable)txtheight))
      (vla-put-regeneratetablesuppressed atable :vlax-false)))
  
  (if  accol (vlax-release-object accol))
  (if  acapp (vlax-release-object acapp))
  (princ)
  )

(prompt "\n\t---\tStart command with COUNTATT\t---\n")
(princ)

 

PS. Your guys are good this year, but still can't beat us in Paris! 

0 Likes
Message 16 of 52

C.Utzinger
Collaborator
Collaborator

Yes!

 

That I was looking for. I just use the filter for ssget. I made a mix from your first code and this one and now it works perfect.

 

I just have to integrate now an alert when there is no block (of the filter list) selected. I think i can do that :)...

 

 

Thank you very much.

 

Kind regards

 

 

 

PS: We will see tonight...

 

      I sent the chocolate on Saturday 🙂

0 Likes
Message 17 of 52

ВeekeeCZ
Consultant
Consultant

Ok, I hope it helps.

 

Congrats to the victory! We'll see today's quarter finals... but it would be miracle to beat the Russian beast. Good luck on the Tre Kronor!

And thanks... I got it. Right now we are finishing quite a big project, so I'll share this with me team right after we'll done! 😉 

Message 18 of 52

C.Utzinger
Collaborator
Collaborator

Cool!

 

Switzerland is out, lol!

 

 

Sorry I have to ask again! I need another help :(...

 

I found no other way... In the attached blocks you can see that i have now also a second Attribute "Pos2."

 

Pos. is for 125CM

Pos2. is for 80CM

 

For the the Comax pruduct it works perfect, but for Ferbox not :(:(:(...

 

Is there a possibility to make this count correctly?

 

Thanks in advance!

0 Likes
Message 19 of 52

C.Utzinger
Collaborator
Collaborator

Good morning

 

I had two times a failure in the counting, i don´t know why. I will look for it and when i have it then i will post it.

 

There seems to be no reason...

 

 

Kind regards

0 Likes
Message 20 of 52

C.Utzinger
Collaborator
Collaborator

HI

 

I have found when it happens, but i don´t now why.

 

See the attached dwg.

 

When i introduce first the Comax 125cm, then the Comax 83cm+125cm and at the end the Comax 83cm, then it seems to not count the comax 83cm (from the 83cm+125cm Block).

 

I inserted them with my Lisp routine, and also manually separate with insert, so it must be the table code.

 

I tried also the first table code you made for me (accepted solution), and it happens the same.

 

 

Have you an Idea why this happens?

 

 

Kind regards

0 Likes