Author Topic: Get and set layer and entity transparency using LISP  (Read 12779 times)

0 Members and 1 Guest are viewing this topic.

BlackBox

  • King Gator
  • Posts: 3770
Get and set layer and entity transparency using LISP
« on: May 02, 2013, 09:04:01 PM »
The following was inspired by Adam's code in this ADNDevBlog article: Get and set layer and entity transparency using LISP

While certainly not as inspiring as the offering that Tony provided in the comments of that ADNDevBlog article, I thought to post these for Adam's consideration since the code he did post in his article only answered half of the original request, and given the article's title including both Layer and Entity transparency.



In any event, here are my meager offerings for others' consideration, in the context of Adam's original ADNDevBlog article:

Code - Auto/Visual Lisp: [Select]
  1.  
  2. (defun GetLayerTransparency (layerName / layer transparency)
  3.   (if (setq layer (tblobjname "layer" layerName))
  4.     (if (setq transparency
  5.                (cdr
  6.                  (assoc
  7.                    1071
  8.                    (cdar
  9.                      (cdr
  10.                        (assoc -3
  11.                               (entget layer '("AcCmTransparency"))
  12.                        )
  13.                      )
  14.                    )
  15.                  )
  16.                )
  17.         )
  18.       (fix (- 100 (/ (lsh (lsh transparency 24) -24) 2.55)))
  19.       0
  20.     )
  21.   )
  22. )
  23. (defun SetLayerTransparency (layerName transparency / *error* oldCmdecho oldNomutt ok)
  24.  
  25.   (defun *error* (msg)
  26.     (and oldCmdecho (setvar 'cmdecho oldCmdecho))
  27.     (and oldNomutt (setvar 'nomutt oldNomutt))
  28.     (cond ((not msg))                                                   ; Normal exit
  29.           ((member msg '("Function cancelled" "quit / exit abort")))    ; <esc> or (quit)
  30.           ((princ (strcat "\n** Error: " msg " ** ")))                  ; Fatal error, display it
  31.     )
  32.     ok
  33.   )
  34.  
  35.   (if (and (tblsearch "layer" layerName)
  36.            (<= 0 transparency 90)
  37.            (setq oldCmdecho (getvar 'cmdecho))
  38.            (setvar 'cmdecho 0)
  39.            (setq oldNomutt (getvar 'nomutt))
  40.            (setvar 'nomutt 1)
  41.       )
  42.     (setq ok
  43.            (vl-cmdf "._-layer" "transparency" transparency layerName ""
  44.                    )
  45.     )
  46.   )
  47.   (*error* nil)
  48. )
  49.  
  50.  
  51.  
  52. (defun GetEntityTransparency (entity / typ transparency)
  53.   (cond ((= 'VLA-OBJ (setq typ (type entity)))
  54.          (vla-get-entitytransparency entity)
  55.         )
  56.         ((= 'ENAME typ)
  57.          (if (setq transparency (cdr (assoc 440 (entget entity))))
  58.            (fix (- 100 (/ (lsh (lsh transparency 24) -24) 2.55)))
  59.            0
  60.          )
  61.         )
  62.   )
  63. )
  64. (defun SetEntityTransparency (entity transparency / typ)
  65.   (if (or (and (= 'STR (setq typ (type transparency)))
  66.                (= "BYLAYER" (strcase transparency))
  67.           )
  68.           (and (= 'INT typ) (<= 0 transparency 90))
  69.       )
  70.      (cond ((= 'VLA-OBJECT (setq typ (type entity)))
  71.             (not (vla-put-entitytransparency entity transparency))
  72.            )
  73.            ((= 'ENAME typ)
  74.             (SetEntityTransparency
  75.               (vlax-ename->vla-object entity)
  76.               transparency
  77.             )
  78.            )
  79.      )
  80.   )
  81. )
  82.  

Cheers
« Last Edit: May 03, 2013, 12:22:38 AM by BlackBox »
"How we think determines what we do, and what we do determines what we get."

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Re: Get and set layer and entity transparency using LISP
« Reply #1 on: May 03, 2013, 08:28:53 AM »
Code - Auto/Visual Lisp: [Select]
  1. (lsh (lsh transparency 24) -24)

Why the shift of 24 bits?

The bit to be removed is the 25th bit (33554432), hence for 32-bit integers, only a 7-bit shift is required to remove all bits above and including the 25th, and one could not argue that the code is accounting for 64-bit integers, since this would require a shift of 39 bits.

However, to remove the single 25th bit, rather than shifting bits back & forth, an alternative solution is to simply mask the unrequired bit, e.g.:
Code - Auto/Visual Lisp: [Select]
  1. (logand <DXF-440> -33554433)

BlackBox

  • King Gator
  • Posts: 3770
Re: Get and set layer and entity transparency using LISP
« Reply #2 on: May 03, 2013, 09:19:38 AM »
Code - Auto/Visual Lisp: [Select]
  1. (lsh (lsh transparency 24) -24)

Why the shift of 24 bits?

The bit to be removed is the 25th bit (33554432), hence for 32-bit integers, only a 7-bit shift is required to remove all bits above and including the 25th, and one could not argue that the code is accounting for 64-bit integers, since this would require a shift of 39 bits.

However, to remove the single 25th bit, rather than shifting bits back & forth, an alternative solution is to simply mask the unrequired bit, e.g.:
Code - Auto/Visual Lisp: [Select]
  1. (logand <DXF-440> -33554433)

Thanks for pointing that out, Lee.

I'm sure that makes perfect sense to some, I don't really understand that part well myself, as I only streamlined the steps I could from Adam's original code as stated above.

Please feel free to further critique, offer a simpler adaptation, etc. as it only reinforces the point I originally made (in my ADNDevBlog article comment), that the code was more complicated than it needed to be.

Cheers
"How we think determines what we do, and what we do determines what we get."

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Re: Get and set layer and entity transparency using LISP
« Reply #3 on: May 03, 2013, 10:15:23 AM »
Please feel free to further critique, offer a simpler adaptation, etc. as it only reinforces the point I originally made (in my ADNDevBlog article comment), that the code was more complicated than it needed to be.

I would personally make the following changes:

Code - Auto/Visual Lisp: [Select]
  1. (defun getlayertransparency ( lay / trn )
  2.     (if (setq lay (tblobjname "LAYER" lay))
  3.         (if (setq trn (cdr (assoc 1071 (cdadr (assoc -3 (entget lay '("AcCmTransparency")))))))
  4.             (fix (- 100 (/ (logand trn -33554433) 2.55)))
  5.             0
  6.         )
  7.     )
  8. )

Note (cdar (cdr ... )) = (cdadr ... ).

Code - Auto/Visual Lisp: [Select]
  1. (defun setlayertransparency ( lay trn / cmd rtn )
  2.     (if (and (tblsearch "LAYER" lay) (<= 0 trn 90))
  3.         (progn
  4.             (setq cmd (getvar 'cmdecho))
  5.             (setvar 'cmdecho 0)
  6.             (setq rtn (vl-cmdf "_.-layer" "_TR" trn lay ""))
  7.             (setvar 'cmdecho cmd)
  8.             rtn
  9.         )
  10.     )
  11. )

I saw no reason for the error handler and no reason to change NOMUTT

Code - Auto/Visual Lisp: [Select]
  1. (defun getentitytransparency ( ent )
  2.     (cond
  3.         (   (= 'vla-object (type ent))
  4.             (vla-get-entitytransparency ent)
  5.         )
  6.         (   (= 'ename (type ent))
  7.             (getentitytransparency (vlax-ename->vla-object ent))
  8.         )
  9.     )
  10. )

Seems more consistent with your setentitytransparency function.

BlackBox

  • King Gator
  • Posts: 3770
Re: Get and set layer and entity transparency using LISP
« Reply #4 on: May 03, 2013, 12:03:19 PM »
Well done, Lee... As always.  :-)
"How we think determines what we do, and what we do determines what we get."

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Re: Get and set layer and entity transparency using LISP
« Reply #5 on: May 03, 2013, 03:48:11 PM »
Cheers dude, I haven't ventured into entity transparency before, so this was refreshing  8-)

BlackBox

  • King Gator
  • Posts: 3770
Re: Get and set layer and entity transparency using LISP
« Reply #6 on: May 03, 2013, 03:52:04 PM »
Cheers dude, I haven't ventured into entity transparency before, so this was refreshing  8-)

Nor had I, until reading that article, and it got me thinking where I could put it to use... When I saw the original code, and all of the unnecessary conversion to/from Vla-Object & Ename, I thought I'd take a go at it.

The only real issue I've encountered was in processing large drawings of entities (not using the code posted here)... LISP is terribly slow in this process as compared to .NET, which is a shame... Otherwise, I might find ways to use this (conceptually) more for my work.

In any event, I always appreciate your feedback, Lee.

Cheers
"How we think determines what we do, and what we do determines what we get."

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Get and set layer and entity transparency using LISP
« Reply #7 on: May 04, 2013, 02:39:07 AM »
Why use recursion?
Code - Auto/Visual Lisp: [Select]
  1. (defun getentitytransparency (ent)
  2.   (vla-get-entitytransparency (if (= (type ent) 'ename) (vlax-ename->vla-object ent) ent))
  3. )

BlackBox

  • King Gator
  • Posts: 3770
Re: Get and set layer and entity transparency using LISP
« Reply #8 on: May 04, 2013, 03:45:25 AM »
Well done. :thumbsup:
"How we think determines what we do, and what we do determines what we get."

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Re: Get and set layer and entity transparency using LISP
« Reply #9 on: May 04, 2013, 07:51:03 AM »
Why use recursion?
Code - Auto/Visual Lisp: [Select]
  1. (defun getentitytransparency (ent)
  2.   (vla-get-entitytransparency (if (= (type ent) 'ename) (vlax-ename->vla-object ent) ent))
  3. )

I guess you have extra argument checking without too much extra code, e.g.:

Passing argument not of entity/vla-object data type:
Lee Mac - nil
Roy - error


vlax-ename->vla-object returns nil (i.e. entity is erased):
Lee Mac - nil
Roy - error


The alternative to account for the above without using recursion could be:
Code - Auto/Visual Lisp: [Select]
  1. (defun getentitytransparency ( ent )
  2.     (if (or (= 'vla-object (type ent))
  3.             (and (= 'ename (type ent))
  4.                  (setq ent (vlax-ename->vla-object ent))
  5.             )
  6.         )
  7.         (vla-get-entitytransparency ent)
  8.     )
  9. )

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Get and set layer and entity transparency using LISP
« Reply #10 on: May 06, 2013, 06:20:33 AM »
@Lee Mac:
If you want this argument checking you should be consistent and also check for a deleted object.

alanjt

  • Needs a day job
  • Posts: 5352
  • Standby for witty remark...
Re: Get and set layer and entity transparency using LISP
« Reply #11 on: May 06, 2013, 09:44:22 AM »
Wouldn't this be the easier solution (slight mod of your original)?

Code: [Select]
(defun getentitytransparency (ent)
  (cond
    ((= 'vla-object (type ent))
     (vla-get-entitytransparency ent)
    )
    ((= 'ename (type ent))
     (vla-get-entitytransparency (vlax-ename->vla-object ent))
    )
  )
)

With your recursion method, you are checking the entity type 3 times, if it's an ename.
Civil 3D 2019 ~ Windohz 7 64bit
Dropbox

PrinceLISPalot

  • Newt
  • Posts: 35
  • perfectionist trapped inside the mind of an idiot.
Re: Get and set layer and entity transparency using LISP
« Reply #12 on: August 24, 2023, 05:58:59 PM »

I would personally make the following changes:
Code - Auto/Visual Lisp: [Select]
  1. (defun getlayertransparency ( lay / trn )
  2.     (if (setq lay (tblobjname "LAYER" lay))
  3.         (if (setq trn (cdr (assoc 1071 (cdadr (assoc -3 (entget lay '("AcCmTransparency")))))))
  4.             (fix (- 100 (/ (logand trn -33554433) 2.55)))
  5.             0
  6.         )
  7.     )
  8. )


Playing with this function I noticed that some layers would return a transparency setting of 100 instead of 0. It seems that in some cases AcCmTransparency is available but is set = 0. I adjusted the code to add a check that trn was also greater than 0.

Code - Auto/Visual Lisp: [Select]
  1. (defun getlayertransparency ( lay / trn )
  2.     (if (setq lay (tblobjname "LAYER" lay))
  3.         (if (and (setq trn (cdr (assoc 1071 (cdadr (assoc -3 (entget lay '("AcCmTransparency"))))))) (> trn 0))
  4.             (fix (- 100 (/ (logand trn -33554433) 2.55)))
  5.             0
  6.         )
  7.     )
  8. )

Also find that if the Layer Transparency is set = 40 the function returns 39.

For reference attach a drawing created in AutoCAD 2018 used to test with.

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Re: Get and set layer and entity transparency using LISP
« Reply #13 on: August 25, 2023, 06:03:59 AM »
Many thanks for your testing, feedback, and additions  :-)

This should correct the 39/40 issue (which arises from the inaccuracy of doubles at the limit of precision):

Code - Auto/Visual Lisp: [Select]
  1. (defun getlayertransparency ( lay / trn )
  2.     (if (setq lay (tblobjname "LAYER" lay))
  3.         (if (and (setq trn (cdr (assoc 1071 (cdadr (assoc -3 (entget lay '("AcCmTransparency"))))))) (< 0 trn))
  4.             (fix (- 100 (/ (logand trn (~ 33554432)) 2.55) -1e-8))
  5.             0
  6.         )
  7.     )
  8. )

PrinceLISPalot

  • Newt
  • Posts: 35
  • perfectionist trapped inside the mind of an idiot.
Re: Get and set layer and entity transparency using LISP
« Reply #14 on: August 28, 2023, 02:24:54 AM »
I realised that you could use getpropertyvalue and setpropertyvalue functions to get and set transparency


Code - Auto/Visual Lisp: [Select]
  1. ; GetEntityTransparency
  2. ; Gets the Transparency for an entity
  3. ; returns
  4. ; -1 = ByLayer
  5. ; -2 = ByBlock
  6. ; 0 - 90 where Transparency has been explicitly set
  7. (defun GetEntityTransparency (entity)
  8.   (getpropertyvalue entity "Transparency")
  9. )
  10.  
  11. ; SetEntityTransparency
  12. ; sets the Transparency for an entity
  13. ; -1 = ByLayer
  14. ; -2 = ByBlock
  15. ; 0 - 90 for explicitly set transparency
  16. ; returns the value set if successful, nil otherwise
  17. ; Note. This function doesn't work as expected in BricsCAD V23.
  18.  
  19. (defun SetEntityTransparency (entity trn)
  20.         (cond ((<= -2 trn 90)
  21.                         (setpropertyvalue entity "Transparency" trn)
  22.                         (getpropertyvalue entity "Transparency")
  23.                         )
  24.         )
  25. )

These functions will also work with layers and explains why sometimes a layer with 0 transparency returns a value when querying "AcCmTransparency". It would seem a new layer in AutoCAD has transparency set to -1 by default, which is ByLayer. If you subsequently change the transparency for the layer, then set back to 0 then that is what it is set to i.e. it doesn't get set back to -1. In BricsCAD the transparency looks to be 0 by default.


It's a bit redundant but functions to get an set layer transparency using this approach would be

Code - Auto/Visual Lisp: [Select]
  1. ; GetLayerTransparency
  2. ; Returns the given layers transparency value
  3. ; will return a value between
  4. ; 0 - 90
  5.  
  6. (defun getlayertransparency (lay / trn )
  7.     (if (setq lay (tblobjname "LAYER" lay))
  8.        (if (< (setq trn (getpropertyvalue lay "Transparency")) 0)
  9.                 0
  10.                 trn
  11.            )
  12.     )
  13. )
  14.  
  15. ; SetLayerTransparency
  16. ; Sets the given layers transparency
  17. ; valid value
  18. ; 0 - 90
  19. ; Note. This function doesn't work as expected in BricsCAD V23.
  20.  
  21. (defun SetLayerTransparency (lay trn)
  22.     (cond ((and (tblsearch "LAYER" lay) (<= 0 trn 90))
  23.                         (setq lay (tblobjname "LAYER" lay))
  24.                         (setpropertyvalue lay "Transparency" trn)
  25.                         (getpropertyvalue lay "Transparency")
  26.                  )
  27.         )
  28. )

Setting transparency this way doesn't work as expected in BricsCAD. It looks like it may be expecting the value in the form of "AcCmTransparency", which would require conversion of the % based figure.

I guess this proves things are easier if you use a MAC  :-D