broncos15 Posted September 15, 2016 Posted September 15, 2016 I had a quick question on the most efficient way to code a layer freeze program I am working on. The point of the routine is to freeze all utility layers that aren't structures. I am going about this by doing (command "._layer" "_F" "*|C-CATV*" "" for example, and then thawing anything with a -STRC or something similar. I am going about this in this way because the wildcard method always seems so much faster than iterating over all the layers. My only issue is that I don't want to thaw a layer that is already frozen, like if C-STRM-STRC was frozen for example. What would be the fastest way to code this part? I don't want to have to do an individual check because there are thousands of layers in our template file. Would I need to do something in the beginning with wcmatch and storing all the frozen layers that match a certain criteria? Quote
rlx Posted September 16, 2016 Posted September 16, 2016 I found this : http://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/trying-to-freeze-layers-by-using-wildcard-layer-name/td-p/4941568 (defun c:fREV ();; to freeze (vl-load-com) (vlax-for layer(vla-get-layers (vla-get-activedocument (vlax-get-acad-object))) (if (and (wcmatch (strcase (vla-get-name layer)) "*REV*") (not (wcmatch (vla-get-name layer) "*|*")) (not (wcmatch (strcase (vla-get-name layer)) (strcase (getvar 'CLAYER)))) ) (vla-put-freeze layer :vlax-true) ) ) (princ) ) (defun c:tREV ();; to thaw (vl-load-com) (vlax-for layer(vla-get-layers (vla-get-activedocument (vlax-get-acad-object))) (if (and (wcmatch (strcase (vla-get-name layer)) "*REV*") (not (wcmatch (vla-get-name layer) "*|*")) ) (vla-put-freeze layer :vlax-false) ) ) (princ) ) gr. Rlx Quote
Grrr Posted September 16, 2016 Posted September 16, 2016 (edited) Hi, Thats an interesting task... so here goes my attempt: (while (setq LayEnx (tblnext "LAYER" (null LayEnx))) (if (= 1 (logand 1 (cdr (assoc 70 LayEnx)))) ; layer is frozen (setq LstFrozenLayers (cons LayEnx LstFrozenLayers)) (setq LstThawedLayers (cons LayEnx LstThawedLayers)) ) ) (setq match "*|C-CATV*") (mapcar 'entupd (mapcar (function (lambda (x) (if (wcmatch (cdr (assoc 2 x)) match) (cond ; I don't know how to subst the layer's elist with (logand) ((member x LstFrozenLayers) (subst (assoc 70 x) (cons 70 0) x) ) ((member x LstThawedLayers) (subst (assoc 70 x) (cons 70 1) x) ) ) ) ) ) (list LstFrozenLayers LstThawedLayers) ) ) The above fragment would be the ideal situation for the task (using only Vanilla LISP).. though theres only 1 problem: I don't know how to subst layer's elist with combination of (logand) function. In case you don't understand whats happening in the code, let me explain: 1. It iterates trough the LAYERS table, and separates the layers into 2 groups(lists): Frozen and Thawed 2. Then using the lambda, for each layer we check for the matching name, and in which group/list (Frozen or Thawed) it belongs to.. and by substituting x's layer's elist we switch its frozen/thawed status. Here goes my alternative suggestion (using VLAX): (while (setq ld (tblnext "LAYER" (null ld))) (setq LayersEnxs (cons ld LayersEnxs)) ) (setq match "*|C-CATV*") (mapcar (function (lambda (x / o ) (if (wcmatch (cdr (assoc 2 x)) match) (progn ; I use VLA, because I don't know how to subst a layer's elist with (logand) (vlax-put (setq o (vlax-ename->vla-object (tblobjname "LAYER" (cdr (assoc 2 x))))) 'Freeze :vlax-false) (vla-update o) ) ) ) ) (vl-remove-if-not (function (lambda (x) (= 1 (logand 1 (cdr (assoc 70 x)))))) LayersEnxs); frozen layers's elists ) (vla-Regen (vla-get-ActiveDocument (vlax-get-acad-object)) acActiveViewport) It thaws the frozen layers with that wcmatching name (but this VLA method should be slower than the Vanilla icecream one). HTH By the way I love answering, and asking questions at the same time EDIT: Heres another... (setq match "*|C-CATV*") (vlax-map-collection (vla-get-Layers (vla-get-ActiveDocument (vlax-get-acad-object))) (function (lambda (x) (if (and (wcmatch (vla-get-name x) match) (eq (vla-get-Freeze x) :vlax-true) ) (vla-update (vlax-put x 'Freeze :vlax-false)) ) ) ) ) I think you get the idea... but I don't really think you can accomplish it without iterating all of the layers. Edited September 16, 2016 by Grrr Quote
rlx Posted September 16, 2016 Posted September 16, 2016 I don't know how much time it takes to iterate all of the layers when you talk about thousands but so what if you're talking in seconds... Think the c:tRev just needs one extra check for layer status (defun c:tREV ();; to thaw (vl-load-com) (vlax-for layer(vla-get-layers (vla-get-activedocument (vlax-get-acad-object))) (if (and (wcmatch (strcase (vla-get-name layer)) "*|C-CATV*") (= (vla-get-Freeze layer) :vlax-false) ;if layer is not frozen ) ) (vla-put-freeze layer :vlax-false) ) ) (princ) ) But you really did your homework Grrr :-) gr. Rlx Quote
Grrr Posted September 16, 2016 Posted September 16, 2016 (edited) But you really did your homework Grrr :-) gr. Rlx Thanks, but like broncos15 I'm also curious... if someone can come up with benchmarking what iteration method would be the fastest, since there are many ways via using (mapcar + lambda)/(foreach)/(vlax-map-collection)/(vlax-for). Would it be faster accessing directly the LAYERS table/collection and perform the changes there, or instead firstly create a list containing the layers, and iterate the list to perform these changes. Edited September 16, 2016 by Grrr Quote
rlx Posted September 16, 2016 Posted September 16, 2016 This might help you on your way : http://www.cadtutor.net/forum/showthread.php?59993-Help-How-to-test-speed-of-a-function Even my patience has limits but if it works it works , besides ... next time your boss thinks you can do everything superfast , so speed is not always a good thing ;-) gr. Rlx here's another discussion : https://www.theswamp.org/index.php?topic=45954.0 Quote
rlx Posted September 16, 2016 Posted September 16, 2016 A simple way to check your speed can be done with _vl-times see this example http://www.cadtutor.net/forum/showthread.php?95337-Batch-rename-with-info-from-block-attributte&highlight=RlxReadTitleBlock at beginning of your function put something like : (defun bladiebla () (setq start (car(_vl-times))) ;do your stuff ;;;for testing (princ (strcat "\n\nProcessed " (itoa (length filelist)) " drawings in " (rtos (/ (- (car (_VL-TIMES)) start) 1000.) 2 4) " secs.")) Gr. Rlx Quote
BIGAL Posted September 16, 2016 Posted September 16, 2016 If your looking at seconds then your looking at the wrong task to improve, something I did, took others around 10 mins to draw, the lisp replacement 2 seconds, pity I never got paid for it. Rlx I agree "if it works it works". Quote
Roy_043 Posted September 16, 2016 Posted September 16, 2016 @ broncos15: In some case a clever wcmatch string can do the trick. (command "_.-layer" "_thaw" "NewLayer[~2]*" "") This will thaw all layers with names starting with "NewLayer" except those starting with "NewLayer2" (matching is case insensitive). Quote
Lee Mac Posted September 18, 2016 Posted September 18, 2016 FWIW, here's another way using Vanilla: (defun c:myfreeze ( / cla dxf enx lay ) (setq cla (getvar 'clayer)) (while (setq lay (tblnext "layer" (not lay))) (setq lay (cdr (assoc 2 lay))) (and (wcmatch lay "*|C-CATV*") (wcmatch lay "~*-STRC") (/= cla lay) (setq enx (entget (tblobjname "layer" lay)) dxf (assoc 70 enx) ) (entmod (subst (cons 70 (boole 7 1 (cdr dxf))) dxf enx)) ) ) (princ) ) Quote
Grrr Posted September 18, 2016 Posted September 18, 2016 Sorry for picking up your code Lee, but I think you could skip the (setq enx (entget (tblobjname "layer" lay)) by modifying this part: (while (setq lay (tblnext "layer" (not lay))) (setq lay (cdr (assoc 2 lay))) to: (while (setq enx (tblnext "layer" (not enx))) (setq lay (cdr (assoc 2 enx))) I also think that this should be the fastest approach - by directly iterating over the layers table. I think I understand what you did with this (boole) function for this particular request.. but since I suck at working with bit/bitcodes overall, can you recommend where to start for learning how to deal with them? Quote
Lee Mac Posted September 18, 2016 Posted September 18, 2016 Sorry for picking up your code Lee, but I think you could skip the (setq enx (entget (tblobjname "layer" lay)) by modifying this part: (while (setq lay (tblnext "layer" (not lay))) (setq lay (cdr (assoc 2 lay))) to: (while (setq enx (tblnext "layer" (not enx))) (setq lay (cdr (assoc 2 enx))) I also think that this should be the fastest approach - by directly iterating over the layers table. Did you try it? The list returned by tblnext is not the full DXF data for the AcDbLayerTableRecord as returned by tblobjname and hence cannot be used to modify the layer properties. Quote
Grrr Posted September 19, 2016 Posted September 19, 2016 Did you try it? The list returned by tblnext is not the full DXF data for the AcDbLayerTableRecord as returned by tblobjname and hence cannot be used to modify the layer properties. Just tried, it: ............... LOG Watch ............... DXF = (70 . 0) ENX = ((-1 . <Entity name: 7ff6b3003900>) (0 . "LAYER") (5 . "10") (102 . "{ACAD_XDICTIONARY") (360 . <Entity name: 7ff6b30041e0>) (102 . "}") (330 . <Entity name: 7ff6b3003820>) (100 . "AcDbSymbolTableRecord") (100 . "AcDbLayerTableRecord") (2 . "0") (70 . ... LAY = ((0 . "LAYER") (2 . "0") (70 . 0) (62 . 7) (6 . "Continuous")) ............... But would there be a difference if you substituted (using boole) the LAY instead of ENX, since GC 70 occurs in both, and use (entupd) on the "LAY" symbol (because it refers to the layer definition)? Sorry I'm questioning you, but I can't seem to understand the difference between. Quote
Roy_043 Posted September 19, 2016 Posted September 19, 2016 In some cases you can use a partial entity list as the argument for (entmod). But the entity list should at least also contain the -1 group code reference to the entity name. Since the list from (entnext) lacks this it cannot be used with (entmod). Note that (entupdt) and (entmod) are very different functions. Quote
Grrr Posted September 19, 2016 Posted September 19, 2016 In some cases you can use a partial entity list as the argument for (entmod). But the entity list should at least also contain the -1 group code reference to the entity name. Since the list from (entnext) lacks this it cannot be used with (entmod). Note that (entupdt) and (entmod) are very different functions. Thanks Roy, I understand now.. still seems weird why (tblnext) won't return the Full DXF data from the AcDbLayerTableRecord. This DXF/Elist manipulation seems toughter, than dealing with custom-made lists. Quote
a_67vdub Posted September 19, 2016 Posted September 19, 2016 I think I understand what you did with this (boole) function for this particular request.. but since I suck at working with bit/bitcodes overall, can you recommend where to start for learning how to deal with them? Here's a great article by Stig Madsen regarding bitcodes: http://www.afralisp.net/archive/lisp/binary_I.htm Steve Quote
Grrr Posted September 19, 2016 Posted September 19, 2016 Here's a great article by Stig Madsen regarding bitcodes: http://www.afralisp.net/archive/lisp/binary_I.htm Steve THANK YOU ! I didn't knew that AfraLisp had an archive... very cool stuff! Tomorrow I'll start geeking. Quote
broncos15 Posted September 19, 2016 Author Posted September 19, 2016 Thank you everyone for the responses! Sorry I was out on vacation, so I hadn't had a chance to review these. I'll start testing these and seeing differences in speed. I need to study the lambda function more because I keep messing it up unfortunately. Quote
tombu Posted September 20, 2016 Posted September 20, 2016 I have a group of Layer States in my templates. I use the drop-down in the Ribbon to control how layers are displayed. I added this to my acaddoc.lsp: (vl-registry-write (strcat "HKEY_CURRENT_USER\\" (vlax-product-key) "\\Profiles\\" (getvar "cprofile") "\\Dialogs\\AcLayerApps:LayerStatesManager") "LayerNotFound" "0") ; Layer States Manager - Do not turn off layers not found in layer state to make sure it does not turn off layers not found in layer state. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.