Extract value of attribute inside block

Extract value of attribute inside block

andreas7ZYXQ
Advocate Advocate
1,024 Views
6 Replies
Message 1 of 7

Extract value of attribute inside block

andreas7ZYXQ
Advocate
Advocate

Im trying to extract the value of my attribute "adr" inside my selected block.
I got kind of lost here and wondering if someone could fill in the blanks of the code and might explain too (so i might figure it out next time 😃 )

Thanks!

 

(IF (setq blk1 (car (entsel "\nChoose block:")))
    (progn 
		(while (/= "SEQEND"(cdr (assoc 0(setq etdata(entget(setq blk1 (entnext blk1)))))))
			(and (= (cdr (assoc 0 etdata)) "ATTRIB")
			(equal (cdr (assoc 2 etdata)) "ADR")
			(setq avalue(cdr (assoc 2 (entget (car blk1)))))
			)
		)                 
    )
)
0 Likes
Accepted solutions (1)
1,025 Views
6 Replies
Replies (6)
Message 2 of 7

ВeekeeCZ
Consultant
Consultant

@andreas7ZYXQ wrote:

... (so i might figure it out next time 😃 )


I bet you do! Focus on the last line and rewrite it all. Fixed version you can get down below.

 

 

 

(defun c:Test ()
  (:GetBlockAttValue (car (entsel "\nChoose block:")) "ADR"))

(defun :GetBlockAttValue (blk att / etd val)
  (while (and (setq blk (entnext blk))
	      (/= "SEQEND" (cdr (assoc 0 (setq etd (entget blk))))))
    (and (= (cdr (assoc 0 etd)) "ATTRIB")
	 (= (strcase (cdr (assoc 2 etd))) (strcase att))
	 (setq val (cdr (assoc 1 etd)))))
  val)

 

0 Likes
Message 3 of 7

andreas7ZYXQ
Advocate
Advocate

Thanks @ВeekeeCZ

 

Iv´e continued and add the rest of my ideas.

I would like to pass val to my new WriteBlockAttValue. Since i never passed between subs i feel im kinda in deep water now.

my value looks like 01.001
and my target is to paste 01.101 in my other selected block that have the attribute name SADR.

And i also want to loop i all until i finish with all blocks.

 

(defun C:adress_plushundra  ()
	(:GetBlockAttValue (car (entsel "\nChoose block to copy:")) "ADR")
	(:WriteBlockAttValue (car (entsel "\nChoose block to paste new number:")) "SADR")
)

(defun :GetBlockAttValue (blk att / etd val)
	(while
		(and
			(setq blk (entnext blk))
			(/= "SEQEND" (cdr (assoc 0 (setq etd (entget blk)))))
		)
		(and
			(= (cdr (assoc 0 etd)) "ATTRIB")
			(= (strcase (cdr (assoc 2 etd))) (strcase att))
			(setq val (cdr (assoc 1 etd)))
		)
	)val
)


(defun :WriteBlockAttValue (blk att / etd val)
	(while
		(and
			(setq blk (entnext blk))
			(/= "SEQEND" (cdr (assoc 0 (setq etd (entget blk)))))
		)
		(and
			(= (cdr (assoc 0 etd)) "ATTRIB")
			(= (strcase (cdr (assoc 2 etd))) (strcase att))
			(setq val2(atoi(substr val(+ 2(vl-string-search "." val)))))
			(setq val1(substr val 1 (vl-string-search "." val)))
			(setq txt (strcat val1 "." (nth (strlen (setq sn (itoa val2)))'(nil "10" "1" "")) sn))
			(entmod (subst (cons 1 txt)(assoc 1 etd)etd))
		)
	)val
)
0 Likes
Message 4 of 7

ВeekeeCZ
Consultant
Consultant

In general, sub-routines look like this:

 

(defun :subroutine1 (argument1 argument2 / var-localized1 var-localized2)
  ...
  (setq var-localized somefunctions...)
  ...
  var-localized   ;; - very last statement became a value of the whole :subroutine1
)

- you should always pass values thru arguments and the value of the subfunction only (last statement), do not use any global variables.

 

My example:

 

(defun :GetBlockAttValue (blk att / etd val)
  (while (and (setq blk (entnext blk))
	      (/= "SEQEND" (cdr (assoc 0 (setq etd (entget blk))))))
    (and (= (cdr (assoc 0 etd)) "ATTRIB")
	 (= (strcase (cdr (assoc 2 etd))) (strcase att))
	 (setq val (cdr (assoc 1 etd)))))
  val)

blk and att are arguments (values - in), no need to localize them.

val became the value of the whole function, in main program you should use this:

 

(setq ValueOfAtt (:GetBlockAttValue (car (entsel) "ADR"))

 

If you need to get out of you sub more values then on, use list! Then last statement would be (list val1 val2).

 

 

So your routine:

 

(defun C:adress_plushundra  ( / :GetBlockAttValue :WriteBlockAttValue blk-in att-adr-val blk-out) ; subroutines may be localized as well

  (while (and (setq blk-in (car (entsel "\nChoose block to copy:")))
	      (princ (strcat "\nADR value: " (setq att-adr-val (:GetBlockAttValue blk-in "ADR"))))
	      (setq blk-out (car (entsel "\nChoose block to paste new number:")))
	      )
    (:WriteBlockAttValue blk-out "SADR" att-adr-val))
  (princ)
)

(defun :GetBlockAttValue (blk att / etd val)
...
  val
  )


(defun :WriteBlockAttValue (blk att val / etd)
...
  ;val - no need for this
  )

 

0 Likes
Message 5 of 7

andreas7ZYXQ
Advocate
Advocate

I see, have to try and figure out the whole picture.

I edited my code like below but it wont work. (No function definition :GETBLOCKATTVALUE)


(defun C:adress_plushundra  ( / :GetBlockAttValue :WriteBlockAttValue blk-in att-adr-val blk-out) ; subroutines may be localized as well
	(while
		(and (setq blk-in (car (entsel "\nChoose block to copy:")))
	      (princ (strcat "\nADR value: " (setq att-adr-val (:GetBlockAttValue blk-in "ADR"))))
	      (setq blk-out (car (entsel "\nChoose block to paste new number:")))
	    )
    (:WriteBlockAttValue blk-out "SADR" att-adr-val)
	)
  (princ)
)

(defun :GetBlockAttValue (blk att / etd val)
	(while
		(and
			(setq blk (entnext blk))
			(/= "SEQEND" (cdr (assoc 0 (setq etd (entget blk)))))
		)
		(and
			(= (cdr (assoc 0 etd)) "ATTRIB")
			(= (strcase (cdr (assoc 2 etd))) (strcase att))
			(setq val (cdr (assoc 1 etd)))
		)
	)val
)

(defun :WriteBlockAttValue (blk att val / etd)
	(while
		(and
			(setq blk (entnext blk))
			(/= "SEQEND" (cdr (assoc 0 (setq etd (entget blk)))))
		)
		(and
			(= (cdr (assoc 0 etd)) "ATTRIB")
			(= (strcase (cdr (assoc 2 etd))) (strcase att))
			(setq val2(atoi(substr val(+ 2(vl-string-search "." val)))))
			(setq val1(substr val 1 (vl-string-search "." val)))
			(setq txt (strcat val1 "." (nth (strlen (setq sn (itoa val2)))'(nil "10" "1" "")) sn))
			(entmod (subst (cons 1 txt)(assoc 1 etd)etd))
		)
	)
)
0 Likes
Message 6 of 7

ВeekeeCZ
Consultant
Consultant
Accepted solution

Ohh, sorry. Sure, subs have to be inside of the main function -- because I've localized them. If I would not, they could be anywhere.

 

(defun c:Main ( / :sub1 :sub2)

  (defun :sub1 ()
    ;; code sub1
    )

  (defun :sub2 ( / var1 var2)
    ;; code sub2
    )

  ;; code main function

  ) ;end of c:Main defu 

 

BTW you should take a habbit of localizing all the variables you've used. If you used them inside of a sub, then localize them in that sub.

 

PS. Next time you may consider posting some sample block then I could the code easily test (without spending the time of creating them!?!)

0 Likes
Message 7 of 7

andreas7ZYXQ
Advocate
Advocate

Thanks @ВeekeeCZ

It works like a charm!.
And thank you so much for teaching me some new things!

0 Likes