Author Topic: insert value into attribute  (Read 8162 times)

0 Members and 1 Guest are viewing this topic.

Pad

  • Bull Frog
  • Posts: 342
insert value into attribute
« on: October 25, 2010, 10:32:53 AM »
Hello

I wish to insert a stored variable (which happens to be text) into an attributed block, the attribute tag is 'height'.
I also wish to add a prefix of 'H: ' to the stored variable.

I can do the second bit by:
(SETQ HT1 (STRCAT "H: " HT))

this is the lisp I have at the moment.

The block has 7 attributes and the height attribute is the 6th.

A quick hand with this would be appreciated.

I need to change this part:
(COMMAND "text" PTXT THGT "<<0" HT2)
(command "move" "last" "" PTXT pause)

so that 'HT2' is inserted into the attributed block

Code: [Select]
;;
;;
(defun C:TH()
;;


(setq ent1 (car (entsel "\nPick the Tree Level:"))); single pick
(setq ent4 (car (entsel "\nPick the Height Level:"))); single pick

(if ent1
(progn
(setq elist1 (entget ent1)); get a List of that entity
(setq atr1 (entnext ent1)); get 1st attribute entity
(setq en1 (entget atr1)); get a List of attribute entity
(setq val1 (cdr (assoc 1 en1))); get the attrib's value
(setq num1 (atof val1)); make a number of val

(if ent4
(progn
(setq elist4 (entget ent4)); get a List of that entity
(setq atr4 (entnext ent4)); get 1st attribute entity
(setq en4 (entget atr4)); get a List of attribute entity
(setq val4 (cdr (assoc 1 en4))); get the attrib's value
(setq num4 (atof val4)); make a number of val



   (prompt (strcat "\nTREE LEVEL=" val1)); display on Command Line
   (prompt (strcat "\nHEIGHT LEVEL=" val4)); display on Command Line


(SETVAR "cmdecho" 0)

(COMMAND "units" "" 2 "" "" "" "")

  (setq HT (rtos (- num4 num1)))

(COMMAND "units" "" 3 "" "" "" "")

(SETVAR "cmdecho" 1)

   (prompt (strcat "\nTREE HEIGHT=" HT)); display on Command Line


 ); progn
 ); if


(SETQ DFLT 0)
(SETQ TXTHG (GETVAR "textsize"))
(PRINC "\nText Height: <")
(PRIN1 TXTHG)
(PRINC ">: ")
(SETQ THGT (GETDIST))
(IF (= THGT nil)
(SETQ THGT TXTHG)
)


;(SETQ ANNOT (GETSTRING "\nAnnotation: "))

(SETQ HT1 (STRCAT "H: " HT))
(SETQ HT2 (STRCASE HT1))


;;(SETQ PTXT (GETPOINT "\nLocate Text: "))

(setq old_layer (getvar "clayer")); Get current Layer

(SETVAR "cmdecho" 0)

(setq PTXT (getvar "viewctr"))

(COMMAND "layer" "se" "tree text" "")

;(COMMAND "text" PTXT THGT "<<0" HT2)
;(command "move" "last" "" PTXT pause)


(setq CLASHING "CLASHING_LEVELS")


(if (not (tblsearch "layer" CLASHING))
(command "_layer" "M" CLASHING ""); Make the Layer, and set it current
); if

(command "_change" ent4 "" "_P" "_LA" CLASHING "")

(command "_layer" "S" old_layer ""); reset Layer

(SETVAR "cmdecho" 1)

 (princ)
))); function LEV2HT

cheers
P
« Last Edit: October 25, 2010, 10:42:31 AM by Pad »

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: insert value into attribute
« Reply #1 on: October 25, 2010, 11:03:09 AM »
Are the Tag names for the attributes not constant? 
Do you know them in advance?

Can you post a sample DWG with the two blocks in it?

I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: insert value into attribute
« Reply #2 on: October 25, 2010, 11:05:49 AM »
Here is a OLD example using visual lisp.
Code: [Select]
;;  Room Number Update by CAB 03/21/2005
;;  Update selected blocks with attribute "ROOM#"
;;  with user entered room number
;;  NOTE: Very little error checking
;;
;;   Modified a subroutine by Jeff Mishler 1/11/05
;;
(defun c:rm#update (/ rm# attname ss count blk atts2 att2 att1 bc)
  (vl-load-com)

  (setq rm# (getstring t "\nEnter new room number: ")
        attname "RM#"  ; uppercase only
        bc 0) ; block counter

  (prompt "\n***  Select blocks to change room number.  ***")
  ;;  get only blocks with attributes
  (if (and rm#
           (not (eq rm# ""))
           (setq ss (ssget (list '(0 . "INSERT") '(66 . 1))))
      )
    (progn
      (setq count -1)
      (while (< (setq count (1+ count)) (sslength ss))
        (setq blk   (vlax-ename->vla-object (ssname ss count))
              atts2 (vlax-invoke blk "getattributes")
        )
        (foreach att2 atts2
          (if (= attname (vla-get-tagstring att2))
            (progn
              (vla-put-textstring att2 rm#)
              (vla-update att2)
              (vla-update blk)
              (setq bc (1+ bc))
            )
          )
        )
      )
      (prompt (strcat "\n-=< " (itoa bc) " blocked updated  >=-"))
    ) ; progn
    (prompt "\n---  No blocks Updated  ---")
  ) ; endif
  (princ)
) ; defun
(prompt "\nRoom Number Update Loaded, Enter Rm#Update to run.")
(princ)
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

Pad

  • Bull Frog
  • Posts: 342
Re: insert value into attribute
« Reply #3 on: October 25, 2010, 11:27:48 AM »
hi cab

thanks for your reply.

the tag is constant 'height'

attached is an example.
the tree canopies should look familiar to you  :-)

thanks for the example, but i do struggle to understand visual lisp.  But I will give it a study.

P

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Re: insert value into attribute
« Reply #4 on: October 25, 2010, 11:37:08 AM »
Perhaps this subfunction will help you along the way - using Vanilla:

Code: [Select]
;; block = Attributed Block Entity Name       [ENAME]
;; tag   = Tag of Attribute to set to value   [STR]
;; value = Value to which tag is set          [STR]

(defun SetAttribValue ( block tag value / el )
  (if (= 1 (cdr (assoc 66 (entget block))))
    (while
      (not
        (eq "SEQEND"
          (cdr
            (assoc 0
              (setq el
                (entget
                  (setq block (entnext block))
                )
              )
            )
          )
        )
      )
      (if (eq tag (cdr (assoc 2 el)))
        (entupd
          (cdr
            (assoc -1
              (entmod
                (subst
                  (cons 1 value) (assoc 1 el) el
                )
              )
            )
          )
        )
      )
    )
  )
)


;; Example

(defun c:test ( / en tg vl )
 
  (if (and (setq en (car (entsel "\nSelect Block: ")))
           (eq "INSERT" (cdr (assoc 0 (entget en))))
           (setq tg (getstring "\nSpecify Tag to Update: "))
           (setq vl (getstring t "\nSpecify New Value: "))
      )
    (SetAttribValue en (strcase tg) vl)
  )

  (princ)
)

I have also included an example of how to call the subfunction.

Pad

  • Bull Frog
  • Posts: 342
Re: insert value into attribute
« Reply #5 on: October 25, 2010, 11:44:04 AM »
oh yeah, I reckon I can do something with that.
Cheers CAB!
P

Pad

  • Bull Frog
  • Posts: 342
Re: insert value into attribute
« Reply #6 on: October 25, 2010, 12:00:08 PM »
yep got it working! brilliant stuff.

Pad

  • Bull Frog
  • Posts: 342
Re: insert value into attribute
« Reply #7 on: October 25, 2010, 12:06:25 PM »
one other thing

at the top of the lisp i now have this:

(setq en (car (entsel "\nPick the Tree Level:"))); single pick

and I changed this bit to:
  (if (and ;(setq en (car (entsel "\nSelect Block: ")))

I would like to have the option to select the block again. ie:   (if (and (setq en (car (entsel "\nSelect Block: ")))
but only if the block originally picked is not a 'PT2' block.

Is that possible?

Ta


Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Re: insert value into attribute
« Reply #8 on: October 25, 2010, 12:08:45 PM »
oh yeah, I reckon I can do something with that.
Cheers CAB!
P

yep got it working! brilliant stuff.

I would like to have the option to select the block again. ie:   (if (and (setq en (car (entsel "\nSelect Block: ")))
but only if the block originally picked is not a 'PT2' block.

Sorry Pad, are you referring to my code or CAB's?

Pad

  • Bull Frog
  • Posts: 342
Re: insert value into attribute
« Reply #9 on: October 25, 2010, 12:10:50 PM »
Sorry Lee.

I had a silly monent and thought your code was posted by CAB.
Your code has done the trick!
Cheers Lee  :-)

David Bethel

  • Swamp Rat
  • Posts: 656
Re: insert value into attribute
« Reply #10 on: October 25, 2010, 12:15:34 PM »
Or maybe something I little older style wise:

Code: [Select]
  (princ "\nSelect INSERTs To Update....")
  (and (setq i -1 ss (ssget '((0 . "INSERT")(66 . 1))))
       (while (setq en (ssname ss (setq i (1+ i))))
              (setq an (entnext en)
                    ad (entget an)
                    ch nil)
              (while (= "ATTRIB" (cdr (assoc 0 ad)))
                     (and (= (strcase (cdr (assoc 2 ad))) "HEIGHT")
                          (setq ch T)
                          (entmod (subst (cons 1 ht1) (assoc 1 ad) ad)))
                     (setq an (entnext an)
                           ad (entget an)))
              (if ch (entupd en))))
R12 Dos - A2K

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Re: insert value into attribute
« Reply #11 on: October 25, 2010, 12:16:49 PM »
Sorry Lee.

I had a silly monent and thought your code was posted by CAB.
Your code has done the trick!

Not a problem :-)

To answer your question, perhaps you could use a construct similar to this:

Code: [Select]
(defun c:test ( / en )
  (while
    (progn
      (if (setq en (car (entsel "\nSelect Block: ")))
       
        (if (and (eq "INSERT" (cdr (assoc 0 (entget en))))
                 (= 1 (cdr (assoc 66 (entget en))))
                 (eq "PT2" (strcase (cdr (assoc 2 (entget en)))))
            )

          (SetAttribValue en
            (strcase (getstring "\nSpecify Tag: "))
            (getstring t "\nSpecify New Value: ")
          )

          (princ "\n** Please Select a PT2 Block! **")
        )
      )
    )
  )

  (princ)
)

I'm sure it could be coded in a number of ways  :-)

Pad

  • Bull Frog
  • Posts: 342
Re: insert value into attribute
« Reply #12 on: October 25, 2010, 12:27:49 PM »
thanks.
I'll give that a go.

snownut2

  • Swamp Rat
  • Posts: 971
  • Bricscad 22 Ultimate
Re: insert value into attribute
« Reply #13 on: November 12, 2012, 07:29:39 PM »
Perhaps this subfunction will help you along the way - using Vanilla:

Code: [Select]
;; block = Attributed Block Entity Name       [ENAME]
;; tag   = Tag of Attribute to set to value   [STR]
;; value = Value to which tag is set          [STR]

(defun SetAttribValue ( block tag value / el )
  (if (= 1 (cdr (assoc 66 (entget block))))
    (while
      (not
        (eq "SEQEND"
          (cdr
            (assoc 0
              (setq el
                (entget
                  (setq block (entnext block))
                )
              )
            )
          )
        )
      )
      (if (eq tag (cdr (assoc 2 el)))
        (entupd
          (cdr
            (assoc -1
              (entmod
                (subst
                  (cons 1 value) (assoc 1 el) el
                )
              )
            )
          )
        )
      )
    )
  )
)


;; Example

(defun c:test ( / en tg vl )
 
  (if (and (setq en (car (entsel "\nSelect Block: ")))
           (eq "INSERT" (cdr (assoc 0 (entget en))))
           (setq tg (getstring "\nSpecify Tag to Update: "))
           (setq vl (getstring t "\nSpecify New Value: "))
      )
    (SetAttribValue en (strcase tg) vl)
  )

  (princ)
)

I have also included an example of how to call the subfunction.

Lee,

I would like to not have to select the block, but to indicate it programmatically.  Have not had much success in that regard.

Bruce

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Re: insert value into attribute
« Reply #14 on: November 13, 2012, 08:31:44 AM »
I would like to not have to select the block, but to indicate it programmatically.  Have not had much success in that regard.

Without knowing the entity handle of the block reference (for use with handent / vla-handletoobject), you would need to use an automated selection method such as using the ssget function with either the _W / _C / _WP / _CP / _X etc. mode strings, or the nentselp function with a given point argument.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: insert value into attribute
« Reply #15 on: November 13, 2012, 12:09:52 PM »
I would like to not have to select the block, but to indicate it programmatically.  Have not had much success in that regard.

Bruce

When you say "it" do you mean that there is only one INSERT in the drawing of that block?
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

snownut2

  • Swamp Rat
  • Posts: 971
  • Bricscad 22 Ultimate
Re: insert value into attribute
« Reply #16 on: November 17, 2012, 01:39:18 PM »
CAB,

That is correct, there will only be one instance of the block in the drawing.  All attributes in the block is set to invisible, and the block consist of nothing but attributes, so the user will not know the block exist.  I am experimenting with using blocks in this way to store information, I need to be able to retrieve this information (not an issue) and update the information.  I was using the attedit command, however there seems to be issues when using symbols (the "@" symbol for example) and the attedit command.  So I am looking for a way to update attributes in the block in other ways.  There are approximately 70 bits of information I would like to save in each drawing (design criteria for running automated functions).

I have been storing the information in external data files, very cumbersome and prone to synchronization issues, as undo commands do not reflect in the external files.  Also leads to issues when the user tries to perform a "Save As" command. 

Thanks,

Bruce


CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: insert value into attribute
« Reply #17 on: November 17, 2012, 07:04:08 PM »
Maybe this will help.
Code - Auto/Visual Lisp: [Select]
  1. ;;=======================[ AttUpdate.lsp ]=======================
  2. ;;; Author: Charles Alan Butler
  3. ;;; Version:  1.1 May 20, 2006
  4. ;;; Purpose: To update attributes in a drawing, nested blocks & xref
  5. ;;;          Ignores locked or Frozen layers
  6. ;;; Sub_Routines: -None
  7. ;;; Requirements: -set var to your block name & tag list to update
  8. ;;; Returns: -None
  9. ;;;==============================================================
  10. ;;
  11. (defun c:attupdate ()
  12.   ;;  preset variables for automatic mode
  13.   (or blkname (setq blkname "MyBlockName"))
  14.   (or taglist (setq taglist '(("TagName" "New text")("TagName" "New text"))))
  15.   (global_atts blkname taglist)
  16.   (princ)
  17. )
  18. (prompt "\nAttUpdate Loaded, Enter AttUpdate to run.")
  19.  
  20.  
  21. ;; CAB 01/20/2006
  22. ;; Function to update selected attributes of a given block
  23. ;; only those included in the list will be updated **
  24. ;; usage- (global_atts "BlockName" ((tag_name new_value)...))
  25. ;;
  26. ;; Arguments
  27. ;;  bname    block text label
  28. ;;  attlist list as described above
  29. ;; Returns the block count if successful or nil
  30. (defun global_atts (bname attlist / blk ename hit idx ss)
  31.   (if (setq ss (ssget "_X" (list '(0 . "INSERT") (cons 2 bname) '(66 . 1))))
  32.     (progn
  33.       (prompt "\n***  Updating Blocks, Please wait. ***\n")
  34.       ;;  force tag name to upper case
  35.       (setq attlist (mapcar '(lambda(x) (list (strcase (car x)) (cadr x))) attlist))
  36.       (setq idx -1)
  37.       (while (setq ename (ssname ss (setq idx (1+ idx))))
  38.         (setq blk (vlax-ename->vla-object ename))
  39.         (foreach att (vlax-invoke blk 'getattributes)
  40.           (if (setq hit (assoc (strcase (vla-get-tagstring att)) attlist))
  41.             (vla-put-textstring att (cadr hit))
  42.           )
  43.         )
  44.         (vla-update blk)
  45.       )
  46.       (if (not (minusp idx)) (1- idx))
  47.     )
  48.   )
  49. )
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

snownut2

  • Swamp Rat
  • Posts: 971
  • Bricscad 22 Ultimate
Re: insert value into attribute
« Reply #18 on: November 18, 2012, 12:16:39 PM »
CAB,

Thanks for the reply, both sets of code supplied work great.   8-)

Bruce

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

dgorsman

  • Water Moccasin
  • Posts: 2437
Re: insert value into attribute
« Reply #20 on: November 19, 2012, 03:20:16 PM »
Danger Will Robinson, Danger!

Invisible blocks like these can turn into a royal PITA follwing the "out of sight, out of mind" principle.  I've seen these types of blocks get nested several deep into symbol blocks, such as doing touch-ups on symbol block DWGs where the invisible data block is automatically added.  Those blocks get copied, exploded, re-blocked, selectively WBLOCK'd elsewhere.  Those drawings get inserted wholesale into others.  Within a very short period of time you can get thousands of instances of these in your drawings; some are resident in the drawing, others are nested into various other blocks.

So seconded on the recommendation for XDATA or XRECORDs.
If you are going to fly by the seat of your pants, expect friction burns.

try {GreatPower;}
   catch (notResponsible)
      {NextTime(PlanAhead);}
   finally
      {MasterBasics;}

snownut2

  • Swamp Rat
  • Posts: 971
  • Bricscad 22 Ultimate
Re: insert value into attribute
« Reply #21 on: November 19, 2012, 07:22:15 PM »
Dgorsman & CAB,

Thanks for the xdata advice, I have never tried working with xdata or dictionaries in the past.  Any idea on limitations i.e.; string lengths, real or integers ?  I have the need to store all types of information strings, reals & integers.  I will look into this since I really only want to fix this issue once (dispose of the external files). 

Thanks,

Bruce


irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: insert value into attribute
« Reply #22 on: November 20, 2012, 05:51:21 AM »
XData has a size limit per entity. Dictionaries have no limit at all. XData only accepts certain data types in certain code groups, dictionaries can accept nearly any data type anywhere.
Personally I think dictionaries is the way to go in your case - since you can "attach" a dictionary to the DWG and need not attach it to something "inside" the DWG. Actually the simplest built-in method of using dictionaries is through the vlax-ldata-* functions.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

snownut2

  • Swamp Rat
  • Posts: 971
  • Bricscad 22 Ultimate
Re: insert value into attribute
« Reply #23 on: November 22, 2012, 05:23:56 PM »
CAB,
I have taken your advise and decided to use "XRECORDS",  I have been successful in creating a sub-dictionary within the main dictionary and an XRECORD within my sub-dictionary.  I have successfully placed data into this dictionary and can read the data.  My issue is with modifying the data, see structure below and function I am working on to modify the data.

>Main Dictionary
    >Sub-Dictionary (SADATA_DICT)
        >XRECORD (LDATA_VARS)

I am currently using the 410-419 DXF Group codes for testing.

Code: [Select]
(defun update_Xrecord ( DATA_VARS DXF_VAL MOD_VAL / xRecVar)
  (setq xRecVar (get-or-make-Xrecord DATA_VARS))
  (entmod (subst (cons DXF_VAL MOD_VAL)(assoc DXF_VAL xRecVar) xRecVar))
  )

(update_Xrecord "LDATA_VARS" 410 "Update test successful !")
 
(setq DATA_VARS "LDATA_VARS")

I am getting the following error "; error: bad argument type: listp <Entity name: 7eb4aa60>"

Any help or advise would be appreciated.

Thanks,

Bruce

Happy Thanksgiving to all......
 

snownut2

  • Swamp Rat
  • Posts: 971
  • Bricscad 22 Ultimate
Re: insert value into attribute
« Reply #24 on: November 23, 2012, 06:48:12 AM »
Well the entmod function was working erratically, seemed to be appending to the end of the xrecord instead of modifying it.  So I ended up doing the following;
    1.- Create list of the existing xrecord, in a Sub-Dictionary within the NOD.
    2.- Substitute values in the list for new values based on their DXF Group Codes.
    3.- Delete the original Xrecord.
    4.- Create a New Xrecord based on the Substituted List.

Thanks CAB for the advice to go this route, it will definitely make it difficult for the Users to mess up the data saved withing the Drawing..   8-)



irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: insert value into attribute
« Reply #25 on: November 23, 2012, 07:08:09 AM »
Have you seen the help on XRecords: http://docs.autodesk.com/ACD/2011/ENU/filesDXF/WS1a9193826455f5ff18cb41610ec0a2e719-7970.htm
You can only use codes from 1 through 369 (excluding 5 and 105).
And to see which code takes what type of data: http://docs.autodesk.com/ACD/2011/ENU/filesDXF/WS1a9193826455f5ff18cb41610ec0a2e719-7a64.htm
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: insert value into attribute
« Reply #26 on: November 23, 2012, 08:31:13 AM »
Well the entmod function was working erratically, seemed to be appending to the end of the xrecord instead of modifying it.  So I ended up doing the following;
    1.- Create list of the existing xrecord, in a Sub-Dictionary within the NOD.
    2.- Substitute values in the list for new values based on their DXF Group Codes.
    3.- Delete the original Xrecord.
    4.- Create a New Xrecord based on the Substituted List.

Thanks CAB for the advice to go this route, it will definitely make it difficult for the Users to mess up the data saved withing the Drawing..   8-)

That's the ticket. Replace and not update.
http://www.theswamp.org/index.php?topic=5003.0
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

snownut2

  • Swamp Rat
  • Posts: 971
  • Bricscad 22 Ultimate
Re: insert value into attribute
« Reply #27 on: November 23, 2012, 05:03:09 PM »
irned,

I was hoping to use a different DXF Group Code for each of my string variables, however due to the limit of 10 (300-309) DXF Group Codes for strings that line of thought will not work.  In my experimenting to date I have used 410-412 group codes in the XRECORD entity without issue.  Even after shutting the machine down and restarting the values are still intact. 

It appears I will need to use a single group code for 20 different strings.  I have been experimenting and researching how to call say the 3rd instance of group code 300.  I have not had much luck in accomplishing this task.  Since I may not have any idea on the contents of the string, I would really like to use say the 3rd instance of Group Code 300.

Here is my line of code to substitute the new text string (MOD_VAL)  in the (xRecFile) XRECORD entity.  This line will modify the 1st instance of the Group Code (DXF_VAL) found.

Code: [Select]
  (setq Values (subst (cons DXF_VAL MOD_VAL)(assoc  DXF_VAL xRecFile)xRecFile))

Any thoughts on how to perform the "subst" function on the 3rd instance of the group code.

Please correct me if I am wrong, if the drawings containing the xrecords with group codes over the 369 limit are not exported to dxf format and subsequently imported from dxf format then the 410-409  & 470-479 string type series of group codes will work fine.

Thanks,

Bruce

« Last Edit: November 24, 2012, 02:12:11 AM by snownut2 »

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Re: insert value into attribute
« Reply #28 on: November 24, 2012, 08:09:47 AM »
I have been experimenting and researching how to call say the 3rd instance of group code 300.

Consider the use of a 'mAssoc' function, (there are many variations* of this function):

Code - Auto/Visual Lisp: [Select]
  1. ;; mAssoc  -  Lee Mac
  2. ;; Returns all associations of a key in an association list
  3.  
  4. (defun LM:mAssoc ( key lst / item )
  5.     (if (setq item (assoc key lst))
  6.         (cons (cdr item) (LM:mAssoc key (cdr (member item lst))))
  7.     )
  8. )

Code - Auto/Visual Lisp: [Select]
  1. _$ (setq l '((300 . "A") (123 . "B") (300 . "C") (123 . "D") (300 . "E")))
  2. ((300 . "A") (123 . "B") (300 . "C") (123 . "D") (300 . "E"))
  3. _$ (LM:mAssoc 300 l)
  4. ("A" "C" "E")


Any thoughts on how to perform the "subst" function on the 3rd instance of the group code.

Substituting one value for another:
Code - Auto/Visual Lisp: [Select]
  1. _$ (setq l (subst '(300 . "F") (cons 300 (nth 1 (LM:mAssoc 300 l))) l))
  2. ((300 . "A") (123 . "B") (300 . "F") (123 . "D") (300 . "E"))


*variations:

Code - Auto/Visual Lisp: [Select]
  1. (defun mAssoc1 ( key lst / rtn )
  2.     (foreach x lst
  3.         (if (= key (car x))
  4.             (setq rtn (cons (cdr x) rtn))
  5.         )
  6.     )
  7.     (reverse rtn)
  8. )
Code - Auto/Visual Lisp: [Select]
  1. (defun mAssoc2 ( key lst )
  2.     (apply 'append
  3.         (mapcar
  4.             (function
  5.                 (lambda ( x ) (if (= key (car x)) (list (cdr x))))
  6.             )
  7.             lst
  8.         )
  9.     )
  10. )
Code - Auto/Visual Lisp: [Select]
  1. (defun mAssoc3 ( key lst )
  2.     (mapcar 'cdr
  3.         (vl-remove-if-not
  4.             (function (lambda ( x ) (= key (car x))))
  5.             lst
  6.         )
  7.     )
  8. )
Code - Auto/Visual Lisp: [Select]
  1. (defun mAssoc4 ( key lst / item rtn )
  2.     (while (setq item (assoc key lst))
  3.         (setq rtn (cons (cdr item) rtn) lst (cdr (member item lst)))
  4.     )
  5.     (reverse rtn)
  6. )
Code - Auto/Visual Lisp: [Select]
  1. (defun mAssoc5 ( key lst )
  2.     (mapcar 'cdr (acet-list-m-assoc key lst))
  3. )
Code - Auto/Visual Lisp: [Select]
  1. (defun mAssoc6 ( key lst )
  2.     (if lst
  3.         (if (= key (caar lst))
  4.             (cons (cdar lst) (mAssoc6 key (cdr lst)))
  5.             (mAssoc6 key (cdr lst))
  6.         )
  7.     )
  8. )
« Last Edit: November 24, 2012, 08:15:34 AM by Lee Mac »

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: insert value into attribute
« Reply #29 on: November 24, 2012, 08:35:08 AM »
And for subst'ing the 3rd 300 code (even if some of them might be exactly the same), try some of these: http://www.theswamp.org/index.php?topic=41680.0
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

snownut2

  • Swamp Rat
  • Posts: 971
  • Bricscad 22 Ultimate
Re: insert value into attribute
« Reply #30 on: November 24, 2012, 03:42:10 PM »
Thank you to all who helped on this project, CAB, Lee Mac & irned.

Below are the completed Functions, I am sure they are not as concise as Lee Mac's work (probably take 3-lines of code in total).

The below functions will perform the following;
       1.- Create a Sub-Dictionary within the NOD.
            2.- Create an Xrecord within the Sub-Dictionary.
                 3.- Retrieve Values within the Xrecord, based in the nth occurrence of the associated DXF Group Code.
                      4.- Update Values within the Xrecord, based in the nth occurrence of the associated DXF Group Code.
                            5.- Read the entire contents of the Xrecord.

This should give you enough Xrecord tools to be able to incorporate their use quite easily.

Function to Create the "SADATA_DICT" within the NOD
        Syntax for function call;               
               (GC_Dict  < dictname >)

Code: [Select]

(defun GC_Dict ( dictname / adict) 
  (if (not (setq adict (dictsearch (namedobjdict) dictname)))
    (progn
      (setq adict (entmakex '((0 . "DICTIONARY")(100 . "AcDbDictionary"))))
      (if adict (setq adict (dictadd (namedobjdict) dictname adict)))
    )
    (setq adict (cdr (assoc -1 adict)))
  )
);defun

(GC_Dict "SADATA_DICT") Example Calling Line



Function to Create an XRECORD in the "SADATA_DICT" within the NOD
        Syntax for function call;
         (GM_Xrecord < XRECORD NAME >)

Code: [Select]

(defun GM_Xrecord ( DATA_VARS / adict anXrec)
  (cond
    ((setq adict (GC_Dict "SADATA_DICT"))
     (cond     
       ((not (setq anXrec (dictsearch adict DATA_VARS)))
(setq anXrec (entmakex values))
        (if anXrec (setq anXrec (dictadd adict DATA_VARS anXrec)))
)
       (setq anXrec
(cdr (assoc -1 (dictsearch adict DATA_VARS)))
);setq
       );cond
     );setq
    );cond
  );defun


(GM_Xrecord "LDATA_VARS") Example Calling Line ;


Following are some examples for the <Values> variable that needs to be created prior to Calling the (GM_Xrecord) Function.

Code: [Select]

(setq x 11.23
      y 23.43
      z 43.23
      test 34.54
      test2 "This is line 5")

(setq Values  (list(cons 0 "XRECORD") ; used for storing integers in "XRECORDS" can also use 270-289
   (cons 100  "AcDbXrecord")
   (cons 70 2 )
   (cons 71 3 )
   (cons 72 4 )
   (cons 73 5 )
   (cons 74 6 )
   (cons 75 7 )
   (cons 76 8 )
   (cons 12 (list x y))
   (cons 11 (list x y z))
   )
      );setq

(setq Values  (list(cons 0 "XRECORD") ; used for storing reals in "XRECORDS" can also use 140-149
   (cons 100  "AcDbXrecord")
   (cons 40 2.1234 )
   (cons 41 3.4568 )
   (cons 42 4.3254 )
   (cons 43 5.3214 )
   (cons 44 6.3256 )
   (cons 45 test )
   (cons 46 8.6384 )
   (cons 47 9.2458 )
   (cons 48 10.7854 )
   )
      );setq

(setq Values  (list(cons 0 "XRECORD") ; used for storing strings in "XRECORDS" can also use 301-309
   (cons 100  "AcDbXrecord")
   (cons 300 "This is line 1" )
   (cons 300 "This is line 2" )
   (cons 300 "This is line 10" )
   (cons 300 "This is line 3" )
   (cons 300 "This is line 4" )
   (cons 300 test2 )
   (cons 300 "This is line 6" )
   (cons 300 "This is line 7" )
   (cons 300 "This is line 8" )
   (cons 300 "This is line 9" )
   )
      );setq


Function to retrieve values from an XRECORD using the DXF Group Code      
      Syntax for function call;                        
                (GetVar_Xrecord <XRECORD NAME> <DXF Group Code to Update> <Nth Group Code>)   

Many Thanks to Lee Mac for his LM:mAssoc Function.

Code: [Select]

(defun GetVar_Xrecord ( DATA_VARS DXF_VAL LnmBr / xRecFile vars )
  (defun LM:mAssoc ( DXF_VAL xRecFile / item )
    (if (setq item (assoc DXF_VAL xRecFile))
      (cons (cdr item) (LM:mAssoc DXF_VAL (cdr (member item xRecFile))))
      )
    );defun

  (setq vars (GM_Xrecord DATA_VARS))
  (cond (vars
         (setq xRecFile  (entget vars))
(cdr (cons DXF_VAL(nth LnmBr (LM:mAssoc DXF_VAL xRecFile))))
        )
        (T nil)
  )
);defun

(setq VARNAME (GetVar_Xrecord "LDATA_VARS" 300 2 )) Calling Line


Function to Update the values in an XRECORD using the nth DXF Group Code   
        Syntax for function call;                        
              (Update_Xrecord <XRECORD NAME> <DXF Group Code to Update> <New Value> <Nth Group Code>)

Code: [Select]

(defun Update_Xrecord (DATA_VARS DXF_VAL MOD_VAL LnmBr / xRecFile Values SAdict)
  (defun LM:mAssoc ( DXF_VAL xRecFile / item )
    (if (setq item (assoc DXF_VAL xRecFile))
      (cons (cdr item) (LM:mAssoc DXF_VAL (cdr (member item xRecFile))))
      )
    );defun

  (setq SAdict (dictsearch (namedobjdict) "SADATA_DICT")
xRecFile (dictsearch (cdr (assoc -1 SAdict)) DATA_VARS)

  (setq values (subst (cons DXF_VAL MOD_VAL) (cons DXF_VAL(nth LnmBr (LM:mAssoc DXF_VAL xRecFile))) xRecFile))
  (entdel (cdr (assoc -1 xRecFile)))
  (GM_Xrecord DATA_VARS)
  );defun

(Update_Xrecord "LDATA_VARS" 300 "Update test successful again 3 !" 4) Example Calling line


Function to See the Values in the specified XRECORD
       Syntax for function call;   
       (xRecord_Exist < Xrecord Name >)   

Code: [Select]

(defun xRecord_Exist ( DATA_VARS / SAdict xRecFile )
  (setq SAdict (dictsearch (namedobjdict) "SADATA_DICT")
xRecFile (dictsearch (cdr (assoc -1 SAdict)) DATA_VARS)
)
  (princ xRecFile)
  )

(xRecord_Exist "LDATA_VARS")  ExampleCalling line


Any comments or feedback is always welcome.

Enjoy,

Bruce