Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Block Attribute Value formula IF function

21 REPLIES 21
SOLVED
Reply
Message 1 of 22
Anonymous
2975 Views, 21 Replies

Block Attribute Value formula IF function

I have a dynamic block containing an attribute, this attributes default value is a field, this field is as follows:

 

Field Names: Blockplaceholder,

Block Reference Property: Scale X,

Format: Decimal.

 

I'm utilising this attributes data to carefully track weather the block has been mirrored or not.

 

What I would like to acheive is the ability display just the (-) minus value from the field data return.

To clairy, i want the attribute to only display a value if it begins with a (-) minus and for the attribute value to remain clear if not.

 

I've been looking into IF functions for formulas or Deisel expression but I'm struggling to get somthing together.

 

any of you wizzards got an idea....?

21 REPLIES 21
Message 2 of 22
Satish_Rajdev
in reply to: Anonymous

If you want you can use this program for adding minus attribute if the X scale factor is negative.

 

 

(defun c:test (/ a b i)
  (if (setq a (ssget '((0 . "insert") (2 . "test block"))))
    (repeat (setq i (sslength a))
      (vl-some
	'(lambda (x)
	   (if (eq (vla-get-tagstring x) "MIRROR")
	     (vla-put-textstring
	       x
	       (if (minusp (vla-get-xscalefactor b))
		 "-"
		 ""
	       )
	     )
	   )
	 )
	(vlax-invoke
	  (setq b (vlax-ename->vla-object (ssname a (setq i (1- i)))))
	  'getattributes
	)
      )
    )
  )
  (princ)
)

 

Best Regards,
Satish Rajdev


REY Technologies | Linked IN | YouTube Channel


 

Message 3 of 22
DannyNL
in reply to: Anonymous

Dynamic Blocks with fields that reference the block instance are a bit tricky. They will only update if you invoke a dynamic action for the specific block.

So just inserting and mirroring will not trigger any field in the block that uses the block properties to update, but you first need to switch i.e. a visibility parameter to activate them, even if the dynamic action itself doesn't change or do any thing at all.

Formulas in blocks will be even more difficult and I do not have any experience with them myself.

 

But....you are referring to a dynamic block. So instead of mirroring, you can use a flip parameter. With the Extract Data tool you can create a table and/or Excel to extract all blocks and the current state of the parameter.

And if you want to have an attribute, that is also possible. By default an empty value, but If the block gets flipped give it a value of -1.

 

See example block, it contains a visibility, flip & block properties parameter. After insertion you can select the block and switch from normal to mirrored state and vice versa.

 

Flip_Block.gif

 

 

 

 

Message 4 of 22
Anonymous
in reply to: Satish_Rajdev

Satish,

Thank you so much for your response,

This may be able to help me achieve my goal with some minor tweaks.

 

Is it possible for the lisp routine to select all instances of multiple blocks containing the attribute “MIRROR” ….?

Also, would it be possible to add the “-“ or “ “ value as a suffix to the attribute value that may already exist within the “MIRRROR” attribute….?

 

I have attached an example dwg, containing two blocks called “test block” and “test block 2”, the “MIRROR” attribute already contain the value Test and it would be amazing if you routine could add a “-“ to the mirrored versions of the blocks, therefore attribute value would be Test-.

Any further help with this will be greatly appreciated.

 

Many thanks in advance.

Message 5 of 22
Anonymous
in reply to: DannyNL

Danny,

 

Thank you so much for your response, while your solution does solve my problem, unfortunately, due to the nature and amount of the blocks that are used, the use of a visibility parameter or flip parameter is actually more of a hindrance and less user friendly.

 

Thanks again for your input.

Message 6 of 22
Satish_Rajdev
in reply to: Anonymous

I've added both modifications, Please check :

(defun c:test (/ a b i)
  (if (setq a (ssget '((0 . "insert"))))
    (repeat (setq i (sslength a))
      (vl-some
	'(lambda (x)
	   (if (eq (strcase (vla-get-tagstring x)) "MIRROR")
	     (vla-put-textstring
	       x
	       (strcat (vla-get-textstring x)
		       (if (minusp (vla-get-xscalefactor b))
			 "-"
			 " "
		       )
	       )
	     )
	   )
	 )
	(vlax-invoke
	  (setq b (vlax-ename->vla-object (ssname a (setq i (1- i)))))
	  'getattributes
	)
      )
    )
  )
  (princ)
)

Best Regards,
Satish Rajdev


REY Technologies | Linked IN | YouTube Channel


 

Message 7 of 22
Anonymous
in reply to: Satish_Rajdev

Satish,

 

That's great, thank you so much for your speedy response.

 

However, when I call the lisp routine, it requests me to "select object".

Is it possible to have the routine recognise all instances of the blocks containing the attribute "MIRROR"...? Therefore removing the select objects process.

 

Additional modification that would be very helpful is the ability to run this routine over and over again without it adding an additional “-“ to an already populated attribute value.

 

Regards

Gary

Message 8 of 22
_gile
in reply to: Anonymous

Here's a way also working on AutoCAD MAC (requires AutoCAD 2012 or later).

 

EDIT: this one works whatever the block name

 

(defun c:test (/ ss i br)
  (if (setq ss (ssget "_X" '((0 . "insert") (66 . 1))))
    (repeat (setq i (sslength ss))
      (setq br (ssname ss (setq i (1- i))))
      (vl-catch-all-apply
        'setpropertyvalue
        (list br
              "MIRROR"
              (strcat
                (if (minusp (car (getpropertyvalue br "ScaleFactors")))
                  "-"
                  " "
                )
                (getpropertyvalue br "MIRROR")
              )
        )
      )
    )
  )
  (princ)
)


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 9 of 22
DannyNL
in reply to: Anonymous

This is my version with a kind of different approach.

 

Instead of scanning all blocks in your drawing, it will first scan all block definitions for the blocks with an attribute "MIRROR'. If one or more are found it will scan the drawing for all blocks with matching names and if found will change the value of the attribute to "-" if mirrored.

 

(defun c:Test (/ T_TagSearch T_TagValue T_ActiveDoc T_Blocks T_AttribFound T_BlockList )
   (setq T_TagSearch "MIRROR")
   (setq T_TagValue  "-")
   (setq T_Blocks (vla-get-Blocks (setq T_ActiveDoc (vla-get-ActiveDocument (vlax-get-acad-object)))))
   (vlax-for T_BlockDef T_Blocks
      (if
         (and
            (= (vla-get-IsLayout T_BlockDef) :vlax-false)
            (= (vla-get-IsXref   T_BlockDef) :vlax-false)
         )
         (progn
            (setq T_AttribFound nil)
            (vlax-for T_Object T_BlockDef
               (if
                  (and
                     (not T_AttribFound)
                     (= (vla-get-ObjectName T_Object) "AcDbAttributeDefinition")
                     (= (vla-get-TagString  T_Object) T_TagSearch)
                  )
                  (setq T_BlockList (cons (vla-get-Name T_BlockDef) T_BlockList))
               )
            )
         )
      )
   )
   (if
      T_BlockList
      (progn
         (vla-StartUndoMark T_ActiveDoc)
         (vlax-for T_Object (vla-get-ModelSpace T_ActiveDoc)
            (if
               (and
                  (= (vla-get-ObjectName    T_Object) "AcDbBlockReference")                        
                  (= (vla-get-HasAttributes T_Object) :vlax-true)
                  (member (vla-get-EffectiveName T_Object) T_BlockList)
                  (minusp (vla-get-XScaleFactor T_Object))
               )
               (foreach T_Attribute (vlax-safearray->list (vlax-variant-value (vla-GetAttributes T_Object)))
                  (if
                     (= (vla-get-TagString T_Attribute) T_TagSearch)
                     (vla-put-TextString T_Attribute T_TagValue)
                  )
               )
            )
         )
         (vla-EndUndoMark T_ActiveDoc)
      )
   )
   (mapcar 'vlax-release-object (list T_Blocks T_ActiveDoc))
   (princ)
)

 

 

 

 

Message 10 of 22
Anonymous
in reply to: _gile

_gile,

 

Thanks for you response!

 

Your latest code is great! Very fast and effective, I love both not having to select object and that it works with multiple block names.

However, its currently adding the “-“ or “ “ as a prefix to the attribute value as opposed to a suffix.

Additionally, do you think you could amend the code to be ran multiple times without it adding an additional “-“ or “ “….?

 

For example, if the dwg file is edited later down the line and blocks are added, deleted or mirrored, it would be great to run the lisp again and again.

 

Thanks for your input! Very much appreciated.

Message 11 of 22
DannyNL
in reply to: DannyNL

While waiting for @_gile, this is my modified code that enables to run it multiple times without adding the prefix multiple times.

Attribute tag and prefx to be used can be configured at the beginning of the code and prefix can be any string.

 

(defun c:Test (/ T_TagSearch T_TagValue T_ActiveDoc T_Blocks T_AttribFound T_BlockList )
   (setq T_TagSearch "MIRROR")
   (setq T_TagValue  "-")
   (setq T_Blocks (vla-get-Blocks (setq T_ActiveDoc (vla-get-ActiveDocument (vlax-get-acad-object)))))
   (vlax-for T_BlockDef T_Blocks
      (if
         (and
            (= (vla-get-IsLayout T_BlockDef) :vlax-false)
            (= (vla-get-IsXref   T_BlockDef) :vlax-false)
         )
         (progn
            (setq T_AttribFound nil)
            (vlax-for T_Object T_BlockDef
               (if
                  (and
                     (not T_AttribFound)
                     (= (vla-get-ObjectName T_Object) "AcDbAttributeDefinition")
                     (= (vla-get-TagString  T_Object) T_TagSearch)
                  )
                  (setq T_BlockList (cons (vla-get-Name T_BlockDef) T_BlockList))
               )
            )
         )
      )
   )
   (if
      T_BlockList
      (progn
         (vla-StartUndoMark T_ActiveDoc)
         (vlax-for T_Object (vla-get-ModelSpace T_ActiveDoc)
            (if
               (and
                  (= (vla-get-ObjectName    T_Object) "AcDbBlockReference")                        
                  (= (vla-get-HasAttributes T_Object) :vlax-true)
                  (member (vla-get-EffectiveName T_Object) T_BlockList)                  
               )
               (foreach T_Attribute (vlax-safearray->list (vlax-variant-value (vla-GetAttributes T_Object)))
                  (if                     
                     (= (vla-get-TagString T_Attribute) T_TagSearch)
                     (cond
                        (
                           (and
                              (minusp (vla-get-XScaleFactor T_Object))
                              (not (wcmatch (setq T_TagString (vla-get-TextString T_Attribute)) (strcat T_TagValue "*")))
                           )
                           (vla-put-TextString T_Attribute (strcat T_TagValue T_TagString))
                        )
                        (
                           (and
                              (not (minusp (vla-get-XScaleFactor T_Object)))
                              (wcmatch (setq T_TagString (vla-get-TextString T_Attribute)) (strcat T_TagValue "*"))
                           )
                           (vla-put-TextString T_Attribute (substr T_TagString (1+ (strlen T_TagValue))))
                        )
                     )
                  )
               )
            )
         )
         (vla-EndUndoMark T_ActiveDoc)
      )
   )
   (mapcar 'vlax-release-object (list T_Blocks T_ActiveDoc))
   (princ)
)
Message 12 of 22
_gile
in reply to: Anonymous

Sorry, my mistake.

 

Here's new version which only add a suffix ("-" or " ") if it does not already exists (it also removes wrong suffixes).

 

(defun c:test (/ ss i br)
  (if (setq ss (ssget "_X" '((0 . "insert") (66 . 1))))
    (repeat (setq i (sslength ss))
      (setq br (ssname ss (setq i (1- i))))
      (vl-catch-all-apply
        '(lambda (/ val)
           (setq val (getpropertyvalue br "MIRROR")
                 suf (substr val (strlen val))
           )
           (if (minusp (car (getpropertyvalue br "ScaleFactors")))
             (if (/= suf "-")
               (setpropertyvalue br "MIRROR" (strcat (vl-string-right-trim " " val) "-"))
             )
             (if (/= suf " ")
               (setpropertyvalue br "MIRROR" (strcat (vl-string-right-trim "-" val) " "))
             )
           )
         )
      )
    )
  )
  (princ)
)


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 13 of 22
Anonymous
in reply to: DannyNL

Danny,

 

Thanks, this is working great.

 

Is it possible for the "-" or " " to be added as a suffix as apposed to a prefix.

 

The fact thats i can run it over and over again is great!!

thanks again!.

 

 

Message 14 of 22
_gile
in reply to: _gile

Now talking about optimization, here's a version which neither select all attributed blocks references nor iterate through all entities in model spaces.

It first iterate through the block table looking for block definitions with a MIRROR attribute (as @DannyNL's last routine) and then, for each found block definition, directly get all inserted references.

 

(defun c:test (/ massoc getAllReferences addSuffix hasMirrorAtt block)

  (defun massoc (key alst)
    (if (setq alst (member (assoc key alst) alst))
      (cons (cdar alst) (massoc key (cdr alst)))
    )
  )

  (defun getAllReferences (bname / blk)
    (if (setq blk (tblobjname "BLOCK" bname))
      (vl-remove-if
        (function (lambda (x) (null (entget x))))
        (massoc 331 (entget (cdr (assoc 330 (entget blk)))))
      )
    )
  )

  (defun addSuffix (br / val suf)
    (setq val (getpropertyvalue br "MIRROR")
          suf (substr val (strlen val))
    )
    (if (minusp (car (getpropertyvalue br "ScaleFactors")))
      (if (/= suf "-")
        (setpropertyvalue br "MIRROR" (strcat (vl-string-right-trim " " val) "-"))
      )
      (if (/= suf " ")
        (setpropertyvalue br "MIRROR" (strcat (vl-string-right-trim "-" val) " "))
      )
    )
  )

  (defun hasMirrorAtt (blk / ent found elst)
    (setq ent (cdr (assoc -2 blk)))
    (while (and ent (not found))
      (if (and (= (cdr (assoc 0 (setq elst (entget ent)))) "ATTDEF")
               (= (cdr (assoc 2 elst)) "MIRROR")
          )
        (setq found T)
        (setq ent (entnext ent))
      )
    )
    found
  )

  (while (setq block (tblnext "BLOCK" (not block)))
    (if (hasMirrorAtt block)
      (foreach br (getAllReferences (cdr (assoc 2 block)))
        (addSuffix br)
      )
    )
  )
  (princ)
)


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 15 of 22
DannyNL
in reply to: Anonymous

Modified code for suffix and optimized code for selecting blocks in the drawing.

 

(defun c:Test (/ T_TagSearch T_TagValue T_ActiveDoc T_Blocks T_AttribFound T_BlockList T_Selection T_Object)
   (setq T_TagSearch "MIRROR")
   (setq T_TagValue  "-")
   (setq T_Blocks (vla-get-Blocks (setq T_ActiveDoc (vla-get-ActiveDocument (vlax-get-acad-object)))))
   (vlax-for T_BlockDef T_Blocks
      (if
         (and
            (= (vla-get-IsLayout T_BlockDef) :vlax-false)
            (= (vla-get-IsXref   T_BlockDef) :vlax-false)
         )
         (progn
            (setq T_AttribFound nil)
            (vlax-for T_Object T_BlockDef
               (if
                  (and
                     (not T_AttribFound)
                     (= (vla-get-ObjectName T_Object) "AcDbAttributeDefinition")
                     (= (vla-get-TagString  T_Object) T_TagSearch)
                  )
                  (setq T_BlockList (cons (vla-get-Name T_BlockDef) T_BlockList))
               )
            )
         )
      )
   )
   (if
      T_BlockList
      (progn
         (vla-StartUndoMark T_ActiveDoc)
         (foreach T_BlockName T_BlockList
            (if
               (setq T_Selection (ssget "_X" (list '(0 . "INSERT") (cons 2 T_BlockName) '(66 . 1))))
               (foreach T_Item (ssnamex T_Selection)
                  (setq T_Object (vlax-ename->vla-object (cadr T_Item)))
                  (foreach T_Attribute (vlax-safearray->list (vlax-variant-value (vla-GetAttributes T_Object)))
                     (if                     
                        (= (vla-get-TagString T_Attribute) T_TagSearch)
                        (cond
                           (
                              (and
                                 (minusp (vla-get-XScaleFactor T_Object))
                                 (not (wcmatch (setq T_TagString (vla-get-TextString T_Attribute)) (strcat "*" T_TagValue)))
                              )
                              (vla-put-TextString T_Attribute (strcat T_TagString T_TagValue))
                           )
                           (
                              (and
                                 (not (minusp (vla-get-XScaleFactor T_Object)))
                                 (wcmatch (setq T_TagString (vla-get-TextString T_Attribute)) (strcat "*" T_TagValue))
                              )
                              (vla-put-TextString T_Attribute (substr T_TagString 1 (- (strlen T_TagString) (strlen T_TagValue))))                          
                           )
                        )
                     )
                  )
               )
            )
         )
         (vla-EndUndoMark T_ActiveDoc)
      )
   )
   (mapcar 'vlax-release-object (list T_Blocks T_ActiveDoc))
   (princ)
)
Message 16 of 22
_gile
in reply to: DannyNL

@DannyNL, from the tests I did (mainly with .NET but it should be similar with LISP) a filtered select all (ssget "_X" ...) is not faster than iterating through all enities in the drawing and filter them. Internally a select all does through all enities in the drawing.

The getAllReferences function is faster because it directly access to the enames of the block references which are stored in the BLOCK_RECORD of the bloc definition.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 17 of 22
DannyNL
in reply to: _gile

@_gile Thanks for the info. Learned something new today Smiley Happy


In my mind it was assumed to be faster, also because it is space independent compared to iterating through modelspace. But I'm intrigued by your way of selecting and will dive into it in more detail and learn an alternative way of selecting the references myself as well.

Message 18 of 22
Anonymous
in reply to: DannyNL

@_gile & @DannyNL 

 

I cant thank you guys enough!

 

I think I've got what I need to achieve my goal.

 

I need to make some minor tweaks to my blocks and run some test but fingers crossed.

 

I've only written some LISP routines myself and just reading through yours is teaching me more and more.

 

THANKS!

Message 19 of 22
Anonymous
in reply to: Anonymous

OH NO!

@_gile@DannyNL

 

I'm so sorry gents!

 

I failed to mention all of my blocks are dynamic, abviously dynamic blocks end up with an anonymous *U* name.

 

I made the minor tweaks and your codes and they work an absolute treat, but only on the blocks that are not affected by their dynamic settings.

 

I tried to build a lisp that would collate all of my blocks by name and gave up because of these anonymous names.

 

Could your code be altered to suit dynamic blocks....?

 

 

Message 20 of 22
DannyNL
in reply to: Anonymous

You caught me just before heading home for dinner Smiley Happy

 

But in that case I'm going to revert back to my old code that iterates through all objects in modelspace with the modification of adding/removing a suffix.

If needed I can look into it more tomorrow and spend some more time on it.

 

For now this should work

 

(defun c:Test (/ T_TagSearch T_TagValue T_ActiveDoc T_Blocks T_AttribFound T_BlockList )
   (setq T_TagSearch "MIRROR")
   (setq T_TagValue  "-")
   (setq T_Blocks (vla-get-Blocks (setq T_ActiveDoc (vla-get-ActiveDocument (vlax-get-acad-object)))))
   (vlax-for T_BlockDef T_Blocks
      (if
         (and
            (= (vla-get-IsLayout T_BlockDef) :vlax-false)
            (= (vla-get-IsXref   T_BlockDef) :vlax-false)
         )
         (progn
            (setq T_AttribFound nil)
            (vlax-for T_Object T_BlockDef
               (if
                  (and
                     (not T_AttribFound)
                     (= (vla-get-ObjectName T_Object) "AcDbAttributeDefinition")
                     (= (vla-get-TagString  T_Object) T_TagSearch)
                  )
                  (setq T_BlockList (cons (vla-get-Name T_BlockDef) T_BlockList))
               )
            )
         )
      )
   )
   (if
      T_BlockList
      (progn
         (vla-StartUndoMark T_ActiveDoc)
         (vlax-for T_Object (vla-get-ModelSpace T_ActiveDoc)
            (if
               (and
                  (= (vla-get-ObjectName    T_Object) "AcDbBlockReference")                        
                  (= (vla-get-HasAttributes T_Object) :vlax-true)
                  (member (vla-get-EffectiveName T_Object) T_BlockList)                  
               )
               (foreach T_Attribute (vlax-safearray->list (vlax-variant-value (vla-GetAttributes T_Object)))
                  (if                     
                     (= (vla-get-TagString T_Attribute) T_TagSearch)
                     (cond
                        (
                           (and
                              (minusp (vla-get-XScaleFactor T_Object))
                              (not (wcmatch (setq T_TagString (vla-get-TextString T_Attribute)) (strcat "*" T_TagValue)))
                           )
                           (vla-put-TextString T_Attribute (strcat T_TagString T_TagValue))
                        )
                        (
                           (and
                              (not (minusp (vla-get-XScaleFactor T_Object)))
                              (wcmatch (setq T_TagString (vla-get-TextString T_Attribute)) (strcat "*" T_TagValue))
                           )
                           (vla-put-TextString T_Attribute (substr T_TagString 1 (- (strlen T_TagString) (strlen T_TagValue))))                          
                        )
                     )
                  )
               )
            )
         )
         (vla-EndUndoMark T_ActiveDoc)
      )
   )
   (mapcar 'vlax-release-object (list T_Blocks T_ActiveDoc))
   (princ)
)

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Forma Design Contest


Autodesk Design & Make Report