Attribute count with table

Attribute count with table

C.Utzinger
Collaborator Collaborator
6,215 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,216 Views
51 Replies
Replies (51)
Message 41 of 52

C.Utzinger
Collaborator
Collaborator

HI

 

I have spend many hours to get somewhere with the sortlist function, but i got nothing.

 

I want to do it on my own. If you just tell me how to start, it would be great.

 

I just have to count correctly this blocks and there will not be more.

 

In the dwg you can see the blocks, the mleaders and the (manually editet) table i schould get at the end.

 

I'm not asking for the solution (spoiler), just some help.

 

 

Kind regards

 

 

 

0 Likes
Message 42 of 52

ВeekeeCZ
Consultant
Consultant

Hi Christian, sorry that I've revealed the solution to you, but did not see other hints to give you.

 

Anyway - I would suggest to leave the :sortlst function as it is and don't make it more complicated.

 

Make a new function, a precedent function, which prepares a list tabledata the way which the :sortlst function can handle it.

 

Name:

:presortlst

 

Input:

'((("POS." . "12") ("83CM" . "5") ("TYP." . "Comax"))
(("POS." . "22") ("POS2." . "22a") ("80CM" . "4") ("125CM" . "4") ("TYP." . "Ferbox")))

 

Output:

'((("POS." . "12") ("83CM" . "5") ("TYP." . "Comax"))
(("POS." . "22") ("125CM" . "4") ("TYP." . "Ferbox"))
(("POS." . "22a") ("80CM" . "4") ("TYP." . "Ferbox")))

 

Good luck

Message 43 of 52

C.Utzinger
Collaborator
Collaborator

No problem...:)

 

Here is what i have...

 

I'm sure there is an easier way to do it...???

 

 

(defun c:<Test3 ( / asoc olst nlst)

	(setq olst '((("POS." . "12") ("83CM" . "5") ("TYP." . "Comax"))
       		    (("POS." . "22") ("POS2." . "22a") ("80CM" . "4") ("125CM" . "4") ("TYP." . "Ferbox"))))

	(foreach item olst
	  (if (setq asoc (assoc "POS2." item))
	   (progn	
	     (setq nlst (cons (list (assoc "POS." item)(assoc "125CM" item)(assoc "TYP." item)) nlst))
	     (setq nlst (cons (list (cons "POS." (cdr asoc))(assoc "80CM" item)(assoc "TYP." item)) nlst))
	   )
           (setq nlst (cons item nlst)))
        )
        (reverse nlst)
) ; end of defun

Kind regards

Message 44 of 52

C.Utzinger
Collaborator
Collaborator

I have put the function into the table code and it works!

 

But how can i make appear the TYP. also in the table.

I had it but in the table only appears 0 because of the sortlist function.

 

 

Kind regards

 

 

0 Likes
Message 45 of 52

C.Utzinger
Collaborator
Collaborator
I don't need the Typ. ;)...
0 Likes
Message 46 of 52

ВeekeeCZ
Consultant
Consultant
Accepted solution

Good! Of course it could be sorter, but not necessary is you find it more legible the you have it now. But you should also care about the format which also help better readability and understanding.

 

 

;If you have
(progn 
  (setq var1 ..)
  (setq var2 ..))
;you can use
(setq var1 ...
        var2 ...)

;if you have
(setq lst (cons list1 lst)
      lst (cons list2 lst))
;you can use 
(setq lst (cons lst2 (cons lst1 lst))))
;or better 
(setq lst (list lst2 lst1 lst))

;if you have
(if (test)
  (setq lst (expression1))
  (setq lst (expression 2)))
;you can use 
(setq lst (if (test)
                  (expression1)
                  (expression2))

You last (reverse lst)... in this case we don't care about the order... so only thing you need to look after is the last expression which became the value of the whole (:presortlst) function. If you not sure, the you can repeat the variable at the very end of the function (see the code). But I'm sure in this case.

 

(defun :presortlst (olst / asoc nlst)
  
  (foreach item olst
    (setq nlst (if (setq asoc (assoc "POS2." item))
                 (list (list (assoc "POS." item)
                             (assoc "125CM" item)
                             (assoc "TYP." item))
                       (list (cons "POS." (cdr asoc))
                             (assoc "80CM" item)
                             (assoc "TYP." item))
                       nlst)
                 (cons item nlst)))
    ;nlst   ; but this is not needed because I'm sure that the foreach always returns last nlst value. 
 )

 

Message 47 of 52

C.Utzinger
Collaborator
Collaborator

Thank you very much for your help and patience.

 

I learned a lot with this code.

 

And it seems to be finished now :)...

 

 

Kind regards

0 Likes
Message 48 of 52

ВeekeeCZ
Consultant
Consultant
Glad to help!
Enjoy the lisping!
0 Likes
Message 49 of 52

C.Utzinger
Collaborator
Collaborator

HI BeeKeeCZ

 

Do you remember this code:

 

  (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)
                                             (reverse (cons ee (reverse 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))

    )

I have a question to it...

 

 

I need to save also the Attribute TYP.  and don't lose it. So I will have:

 

((("POS." . "22") ("125CM" . "4") ("TYP." . "Ferbox")))

 

Can you help me? Better question... do you want to help me Smiley Frustrated!

 

 

Best regards

0 Likes
Message 50 of 52

C.Utzinger
Collaborator
Collaborator

 

HI

 

I have it now like this and it seems to work!

 

Is that ok, or something could go wrong...?

 

  (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
					     (assoc "TYP." e)
                                                    mlst)
                                             (reverse (cons ee (reverse mlst))))))

                              mlst)

                            a

                            nlst)
                     (cons e nlst)))))
            (reverse nlst)
    )

Best regards

0 Likes
Message 51 of 52

C.Utzinger
Collaborator
Collaborator

I'm stupid!

 

Nothing works... I have tried 100 possibilities and nothing works.

 

  (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)
                                             (reverse (cons ee (reverse mlst))))))
                              mlst)
                            a
                            nlst)
                     (cons e nlst)))))
     (reverse nlst)
    )

I took away the hlst part. I think i don´t Need it.

 

Please help... It's driving me crazy...

 

Smiley EmbarassedSmiley Frustrated

 

0 Likes
Message 52 of 52

C.Utzinger
Collaborator
Collaborator

OK!

 

I have found a solution, but it is really really ugly ugly ugly.

 

  (defun :presortlst (lst / nlst)
	(foreach e lst
	  (cond ((and (assoc "83CM" e)(assoc "FAKT1" e)(assoc "125CM" e)(assoc "FAKT2" e))
		 (setq nlst (cons (list (assoc "POS." e)(cons "83CM" (itoa (* (atoi(cdr(assoc "83CM" e)))(atoi(cdr(assoc "FAKT1" e))))))(cons "125CM" (itoa (* (atoi(cdr(assoc "125CM" e)))(atoi(cdr(assoc "FAKT2" e))))))) nlst)))
		((and (assoc "83CM" e)(assoc "FAKT1" e))
		 (setq nlst (cons (list (assoc "POS." e)(cons "83CM" (itoa (* (atoi(cdr(assoc "83CM" e)))(atoi(cdr(assoc "FAKT1" e))))))) nlst)))

((and (assoc "TYP2." e)(assoc "FAKT2" e)) (setq nlst (cons (list (cons "POS." (cons (cdr (assoc "POS." e))(cdr (assoc "TYP2." e))))(cons "125CM" (itoa (* (atoi(cdr(assoc "125CM" e)))(atoi(cdr(assoc "FAKT2" e))))))) nlst))) ((assoc "TYP2." e) (setq nlst (cons (list (cons "POS." (cons (cdr (assoc "POS." e))(cdr (assoc "TYP2." e))))(assoc "125CM" e)) nlst)))
((and (assoc "125CM" e)(assoc "FAKT2" e)) (setq nlst (cons (list (assoc "POS." e)(cons "125CM" (itoa (* (atoi(cdr(assoc "125CM" e)))(atoi(cdr(assoc "FAKT2" e))))))) nlst))) ((and (assoc "ANZ." e)(assoc "FAKT1" e)(assoc "ANZ2." e)(assoc "FAKT2" e)) (setq nlst (cons (list (assoc "POS." e)(cons "ANZ." (itoa (* (atoi(cdr(assoc "ANZ." e)))(atoi(cdr(assoc "FAKT1" e))))))) nlst)) (setq nlst (cons (list (cons "POS." (cdr (assoc "POS2." e)))(cons "ANZ." (itoa (* (atoi(cdr(assoc "ANZ2." e)))(atoi(cdr(assoc "FAKT2" e))))))) nlst))) ((and (assoc "ANZ." e)(assoc "ANZ2." e)) (setq nlst (cons (list (assoc "POS." e)(assoc "ANZ." e)) nlst)) (setq nlst (cons (list (cons "POS." (cdr (assoc "POS2." e)))(cons "ANZ." (cdr(assoc "ANZ2." e)))) nlst))) ((and (assoc "ANZ." e)(assoc "FAKT1" e)) (setq nlst (cons (list (assoc "POS." e)(cons "ANZ." (itoa (* (atoi(cdr(assoc "ANZ." e)))(atoi(cdr(assoc "FAKT1" e))))))) nlst))) (T (setq nlst (cons e nlst)))) ) (reverse nlst) ) (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) (reverse (cons ee (reverse mlst)))))) mlst) a nlst) (cons e nlst))))) (reverse nlst)) ) (defun :finalsortlst (lst / nlst mlst) (load "SPI-Datenbank.lsp") (cond ((= Typ. "COMAX")(foreach e lst (ut:comaxdaten))(reverse nlst)) ((= Typ. "FERBOX")(foreach e lst (ut:ferboxdaten))(reverse nlst)) ((= Typ. "EBEA")(foreach e lst (ut:ebeadaten))(reverse nlst))
((= Typ. "ACINOXplus")(foreach e lst (setq nlst (cons (list (cons "POS." (cadr (assoc "POS." e)))(cons "TYP." (cdr (cdr (assoc "POS." e))))(cons "Länge" "")(cons "XPS" "")(assoc "125CM" e)) nlst))))
(T tabledata)) ); end of defun

I know it's a mess!

 

Best regards

 

 

0 Likes