Jump to content

Relation between GroupLayerFilters and Layers


Grrr

Recommended Posts

Hi, guys

My question may be fairly complex, so I hope someone could answer:

Does anyone know what is the programmatical relation between the Group Layer Filters and Layers? - or where I can find it?

 

I've found where are the Group Layer Filters located (using VLAX),

but I think the only useful information about them I have at this point are their names.

Shouldn't each one of them have a "count" property of the number of layers inside them?

Or atleast every layer object to have some connection-info(method or property) with the Group Layer Filter where its located within.

 

ScreenShot-LayGroups.jpg

 

In order to find any relation I have dumped:

- Layers collection,

- Layers collection Extended Dict,

- Every item inside of Layers collection Extended Dict,

- "ACAD_LAYERFILTERS" collection (located inside Layers Coll Extended Dict),

- Every item inside of "ACAD_LAYERFILTERS" collection,

- Active Layer,

- Active Layer's Extended Dict

 

Heres a sample drawing using (C:ForTest) :

Group Layer Filters Test.dwg

 

Here is the (shortened) info I got, using VLIDE's console:

; Helper functions:
(defun DT ( o / ) (if (= (type o) 'VLA-OBJECT) (vlax-dump-object o T))) ; Dump True (I'm using it as a shortcut)
(defun GetExtDict ( o / ) (if (and (= (type o) 'VLA-OBJECT) (vlax-method-applicable-p o 'GetExtensionDictionary)) (vlax-invoke o 'GetExtensionDictionary)))
(defun DTColl ( coll / ) (if (= (type coll) 'VLA-OBJECT) (vlax-for o coll (vlax-dump-object o T)))) ; Dump True (everything inside of a collection)
(defun Coll->Lst ( #Collection / Lst ) (vlax-for o #Collection (setq Lst (cons o Lst))) (reverse Lst)); convert Collection into List

; Start digging:
(setq AcLay (vla-get-ActiveLayer (vla-get-ActiveDocument (vlax-get-acad-object))))
(setq ExtDictAcLay (GetExtDict AcLay))
(setq LayColl (vla-get-Layers (vla-get-ActiveDocument (vlax-get-acad-object))))
(setq ExtDictCollOfLayersColl (GetExtDict LayColl))
; (DTColl ExtDictCollOfLayersColl) ; inside of it there are: ACAD_LAYERFILTERS ACAD_LAYERSTATES ACLYDICTIONARY
(setq LAYERFILTERS (vla-item ExtDictCollOfLayersColl "ACAD_LAYERFILTERS"))
(setq LAYERSTATES (vla-item ExtDictCollOfLayersColl "ACAD_LAYERSTATES"))
(setq ACLYDICTIONARY (vla-item ExtDictCollOfLayersColl "ACLYDICTIONARY"))

_$ (DTcoll LAYERFILTERS)
; IAcadXRecord: XRecord objects are used to store and manage arbitrary data
; Property values:
;   Application (RO) = #<VLA-OBJECT IAcadApplication 00007ff78a999110>
;   Document (RO) = #<VLA-OBJECT IAcadDocument 0000002a7ec52b78>
;   Handle (RO) = "20C"
;   HasExtensionDictionary (RO) = 0
;   Name = "Group1"
;   ObjectID (RO) = 42
;   ObjectName (RO) = "AcDbXrecord"
;   OwnerID (RO) = 43
;   TranslateIDs = -1
; Methods supported:
;   Delete ()
;   GetExtensionDictionary ()
;   GetXData (3)
;   GetXRecordData (2)
;   SetXData (2)
;   SetXRecordData (2)

; IAcadXRecord: XRecord objects are used to store and manage arbitrary data
; Property values:
;   Application (RO) = #<VLA-OBJECT IAcadApplication 00007ff78a999110>
;   Document (RO) = #<VLA-OBJECT IAcadDocument 0000002a7ec52b78>
;   Handle (RO) = "20E"
;   HasExtensionDictionary (RO) = 0
;   Name = "Group2"
;   ObjectID (RO) = 44
;   ObjectName (RO) = "AcDbXrecord"
;   OwnerID (RO) = 43
;   TranslateIDs = -1
; Methods supported:
;   Delete ()
;   GetExtensionDictionary ()
;   GetXData (3)
;   GetXRecordData (2)
;   SetXData (2)
;   SetXRecordData (2)

; IAcadXRecord: XRecord objects are used to store and manage arbitrary data
; Property values:
;   Application (RO) = #<VLA-OBJECT IAcadApplication 00007ff78a999110>
;   Document (RO) = #<VLA-OBJECT IAcadDocument 0000002a7ec52b78>
;   Handle (RO) = "210"
;   HasExtensionDictionary (RO) = 0
;   Name = "Group3"
;   ObjectID (RO) = 45
;   ObjectName (RO) = "AcDbXrecord"
;   OwnerID (RO) = 43
;   TranslateIDs = -1
; Methods supported:
;   Delete ()
;   GetExtensionDictionary ()
;   GetXData (3)
;   GetXRecordData (2)
;   SetXData (2)
;   SetXRecordData (2)

; IAcadXRecord: XRecord objects are used to store and manage arbitrary data
; Property values:
;   Application (RO) = #<VLA-OBJECT IAcadApplication 00007ff78a999110>
;   Document (RO) = #<VLA-OBJECT IAcadDocument 0000002a7ec52b78>
;   Handle (RO) = "212"
;   HasExtensionDictionary (RO) = 0
;   Name = "Group4"
;   ObjectID (RO) = 46
;   ObjectName (RO) = "AcDbXrecord"
;   OwnerID (RO) = 43
;   TranslateIDs = -1
; Methods supported:
;   Delete ()
;   GetExtensionDictionary ()
;   GetXData (3)
;   GetXRecordData (2)
;   SetXData (2)
;   SetXRecordData (2)
T
_$ 

You may try yourself the above lines, to "dig" / inspect.

 

If you can't open the dwg, use the following test code to re-create the Group Layer Filters and Layers test dwg:

; To create the test Layers with their LayerGroupFilters:
(defun C:ForTest ( / LayGroupNames LayLstGroup1 LayLstGroup2 LayLstGroup3 LayLstGroup4 n)

(defun CreateLayer ( #Name / )
	(entmake 
		(list
			(cons 0 "LAYER")
			(cons 100 "AcDbSymbolTableRecord")
			(cons 100 "AcDbLayerTableRecord")
			(cons 2 #Name)
			(cons 70 0)
		)
	)
)

(setq LayGroupNames '("Group1" "Group2" "Group3" "Group4"))
(setq 
	LayLstGroup1 '("Group1-Lay1" "Group1-Lay2" "Group1-Lay3" "Group1-Lay4" "Group1-Lay5" "Group1-Lay6" "Group1-Lay7")
	LayLstGroup2 '("Group2-Lay1" "Group2-Lay2" "Group2-Lay3" "Group2-Lay4" "Group2-Lay5" "Group2-Lay6" "Group2-Lay7")
	LayLstGroup3 '("Group3-Lay1" "Group3-Lay2" "Group3-Lay3" "Group3-Lay4" "Group3-Lay5" "Group3-Lay6" "Group3-Lay7")
	LayLstGroup4 '("Group4-Lay1" "Group4-Lay2" "Group4-Lay3" "Group4-Lay4" "Group4-Lay5" "Group4-Lay6" "Group4-Lay7")
)

(setq n 0)
(foreach x (list LayLstGroup1 LayLstGroup2 LayLstGroup3 LayLstGroup4)
	(mapcar 'CreateLayer x)
	(command "._-layer" "filter" "new" "property" "All" (strcat "NAME==\"" (nth n LayGroupNames) "*\"") (nth n LayGroupNames) "X" nil)
	(setq n (1+ n))
)

(princ)
); defun C:ForTest

 

The reason is that I was curious about a thread with "a simple request" from AUGI's forum.

Where the user asked if its possible to rename a group of particular layers, by adding prefix of the name of the Layer Group Filter they're located in.

However thats not my goal.

Link to comment
Share on other sites

  • 1 month later...

Okay... I did a a small progress today:

(defun C:test ( / ld AllLyrNames LayersColl LFtContainer MyLayerFilterNames Lst FtsLst)

(while (setq ld (tblnext "LAYER" (not ld)))
	(setq AllLyrNames (cons (cdr (assoc 2 ld)) AllLyrNames))
)

(setq LayersColl (vla-get-Layers (vla-get-ActiveDocument (vlax-get-acad-object))))
(setq LFtContainer (vla-item (vla-GetExtensionDictionary LayersColl) "ACAD_LAYERFILTERS"))
(vlax-map-collection LFtContainer '(lambda (x) (setq MyLayerFilterNames (cons (vla-get-Name x) MyLayerFilterNames))))

; (if MyLayerFilterNames
; (foreach x (reverse MyLayerFilterNames)
; (print (HowMyLayerFilterIsCreated x))
; )
; )

(if MyLayerFilterNames
	(progn
		(if (not Lst) (setq Lst (list)))
		(setq FtsLst (mapcar 'HowMyLayerFilterIsCreated MyLayerFilterNames))
		(foreach Ft FtsLst
			(setq Lst (append Lst (mapcar '(lambda (x) (if (wcmatch x (cadr Ft)) (cons (car Ft) x))) AllLyrNames)))
		)
		(setq Lst (reverse (vl-remove nil Lst)))
		(foreach x Lst (print x))
	)
); if MyLayerFilterNames

(princ)
); defun C:test

(defun HowMyLayerFilterIsCreated ( LyrFilterName / LayersColl LFtContainer MyLayerFilter XRecordDataLst MyLayerFilterXRecordDataType MyLayerFilterXRecordData )
(if 
	(and
		(setq LayersColl (vla-get-Layers (vla-get-ActiveDocument (vlax-get-acad-object))))
		(setq LFtContainer (vla-item (vla-GetExtensionDictionary LayersColl) "ACAD_LAYERFILTERS"))
		(setq MyLayerFilter (vla-item LFtContainer LyrFilterName))
	)
	(progn
		(vla-GetXRecordData MyLayerFilter 'MyLayerFilterXRecordDataType 'MyLayerFilterXRecordData)
		(setq XRecordDataLst (mapcar 'vlax-variant-value (vlax-safearray->list MyLayerFilterXRecordData)))
	)
)
XRecordDataLst
);| defun HowMyLayerFilterIsCreated |; (or (vlax-get-acad-object) (vl-load-com))

The printed result from the above attached .dwg looks like this:

Command: TEST
("Group1" . "Group1-Lay1")
("Group1" . "Group1-Lay2")
("Group1" . "Group1-Lay3")
("Group1" . "Group1-Lay4")
("Group1" . "Group1-Lay5")
("Group1" . "Group1-Lay6")
("Group1" . "Group1-Lay7")
("Group2" . "Group2-Lay1")
("Group2" . "Group2-Lay2")
("Group2" . "Group2-Lay3")
("Group2" . "Group2-Lay4")
("Group2" . "Group2-Lay5")
("Group2" . "Group2-Lay6")
("Group2" . "Group2-Lay7")
("Group3" . "Group3-Lay1")
("Group3" . "Group3-Lay2")
("Group3" . "Group3-Lay3")
("Group3" . "Group3-Lay4")
("Group3" . "Group3-Lay5")
("Group3" . "Group3-Lay6")
("Group3" . "Group3-Lay7")
("Group4" . "Group4-Lay1")
("Group4" . "Group4-Lay2")
("Group4" . "Group4-Lay3")
("Group4" . "Group4-Lay4")
("Group4" . "Group4-Lay5")
("Group4" . "Group4-Lay6")
("Group4" . "Group4-Lay7")

I only need to figure out how to structure this Lst quote like this:

'("Group1" . '("Group1-Lay1" "Group1-Lay2" "Group1-Lay3" "Group1-Lay5" "Group1-Lay6" "Group1-Lay7"))
'("Group2" . '("Group2-Lay1" "Group2-Lay2" "Group2-Lay3" "Group2-Lay5" "Group2-Lay6" "Group2-Lay7"))
'("Group3" . '("Group3-Lay1" "Group3-Lay2" "Group3-Lay3" "Group3-Lay5" "Group3-Lay6" "Group3-Lay7"))
'("Group4" . '("Group4-Lay1" "Group4-Lay2" "Group4-Lay3" "Group4-Lay5" "Group4-Lay6" "Group4-Lay7"))

So it would be more readable (atleast for me).

Link to comment
Share on other sites

Maybe do it backwards look at the car = group1 add "Group1-layername" to a temporary "lsttemp" get next if = group1 add "Group1-layername" to "lsttemp" keep going. Once group1 /= group2 make your new layer group1 list ("group1" . '(lsttemp)) replace lsttemp as nil and do agian for group2. hope it makes sense.

 

groupname = "Group1"
lsttemp = ("Group1-Lay1" "Group1-Lay2" "Group1-Lay3" "Group1-Lay5" "Group1-Lay6" "Group1-Lay7"))

Link to comment
Share on other sites

Are the layer filters in the drawing really 'group filters'? I can't be sure since BricsCAD only supports layer property filters, but the filters in the drawing seem to be of that type.

Link to comment
Share on other sites

Maybe do it backwards look at the car = group1 add "Group1-layername" to a temporary "lsttemp" get next if = group1 add "Group1-layername" to "lsttemp" keep going. Once group1 /= group2 make your new layer group1 list ("group1" . '(lsttemp)) replace lsttemp as nil and do agian for group2. hope it makes sense.

 

groupname = "Group1"
lsttemp = ("Group1-Lay1" "Group1-Lay2" "Group1-Lay3" "Group1-Lay5" "Group1-Lay6" "Group1-Lay7"))

Yes BIGAL, I was thinking about something similar, but perhaps I could go back even more, and modify the "Lst" creation to suit my previous discovery (from the commented part of the code above):

(defun C:test ( / LayersColl LFtContainer MyLayerFilterNames )

(setq LayersColl (vla-get-Layers (vla-get-ActiveDocument (vlax-get-acad-object))))
(setq LFtContainer (vla-item (vla-GetExtensionDictionary LayersColl) "ACAD_LAYERFILTERS"))
(vlax-map-collection LFtContainer '(lambda (x) (setq MyLayerFilterNames (cons (vla-get-Name x) MyLayerFilterNames))))

(if MyLayerFilterNames
	(foreach x (reverse MyLayerFilterNames)
		(print (HowMyLayerFilterIsCreated x))
	)
)

(princ)
); defun C:test

(defun HowMyLayerFilterIsCreated ( LyrFilterName / LayersColl LFtContainer MyLayerFilter XRecordDataLst MyLayerFilterXRecordDataType MyLayerFilterXRecordData )
(if 
	(and
		(setq LayersColl (vla-get-Layers (vla-get-ActiveDocument (vlax-get-acad-object))))
		(setq LFtContainer (vla-item (vla-GetExtensionDictionary LayersColl) "ACAD_LAYERFILTERS"))
		(setq MyLayerFilter (vla-item LFtContainer LyrFilterName))
	)
	(progn
		(vla-GetXRecordData MyLayerFilter 'MyLayerFilterXRecordDataType 'MyLayerFilterXRecordData)
		(setq XRecordDataLst (mapcar 'vlax-variant-value (vlax-safearray->list MyLayerFilterXRecordData)))
	)
)
XRecordDataLst
);| defun HowMyLayerFilterIsCreated |; (or (vlax-get-acad-object) (vl-load-com))

I had this result:

Command: TEST
("Group1" "Group1*" "*" "*" 0 "*" "*")
("Group2" "Group2*" "*" "*" 0 "*" "*")
("Group3" "Group3*" "*" "*" 0 "*" "*")
("Group4" "Group4*" "*" "*" 0 "*" "*")

Maybe doing some wcmatch for the cadr's with each layer name, and somehow cons with the car's (representing the group names).

I think that these lists I have, are related to this line:

LayerFilterProperties.jpg

 

Are the layer filters in the drawing really 'group filters'? I can't be sure since BricsCAD only supports layer property filters, but the filters in the drawing seem to be of that type.

I'm afraid you are correct Roy, as I'm using this line to create these sample property filters:

(command "._-layer" "filter" "new" "property" "All" (strcat "NAME==\"" (nth n LayGroupNames) "*\"") (nth n LayGroupNames) "X" nil)

I really didn't knew the difference between the two:

LayerFilter.jpg

But now I see that upon double-clicking on the folder with the groupfilter name, the above dialog "Layer Filter Properties" appears only on the created "Property" filters, and not the "Group" ones. :oops:

Although I'm not sure what infomation I will find for the "GROUP" ones with (HowMyLayerFilterIsCreated).

I will experiment further, atleast I now got the "info" I needed... so it became a question of list construction/manipulation.

Link to comment
Share on other sites

@Grrr:

The item method will error out if the item is not in the collection:

(vla-item (vla-get-layers (vla-get-activedocument (vlax-get-acad-object))) "DoesNotExist") => Error

You can use a "vl-catch-all construction" to solve this:

(KGA_Sys_Apply 'vla-item (list (vla-get-layers (vla-get-activedocument (vlax-get-acad-object))) "DoesNotExist"))

;;; ======================================================================
;;; Lib function: KGA_Sys_Apply
;;; Purpose:      Shortcut for standard "vl-catch-all construction".
;;; Arguments:    expr   - Expression to evaluate.
;;;               varLst - List of variables.
;;; Return value: Varies. Note: A nil value can mean two things: there was
;;;               an error or the expression returned nil.
;;;               Use (KGA_Sys_ApplyAlt) if this is a problem.
;;; Remarks:      None.
;;; Examples:
;;; (KGA_Sys_Apply 'strcat '("a" "bb" "ccc" 1))      => nil
;;; (KGA_Sys_Apply 'strcat '("a" "bb" "ccc" "dddd")) => "abbcccdddd"
;;; ======================================================================
(defun KGA_Sys_Apply (expr varLst / ret)
 (if (not (vl-catch-all-error-p (setq ret (vl-catch-all-apply expr varLst))))
   ret
 )
)

;;; Similar to (KGA_Sys_Apply) but the return value is T or nil (there was an error).
(defun KGA_Sys_ApplyAlt (expr varLst)
 (not (vl-catch-all-error-p (vl-catch-all-apply expr varLst)))
)

Link to comment
Share on other sites

Yeah Roy, I forgot to "error-trap" these. I prefer to use this:

; modeT - if is set to true: then the return would be 'T or nil, otherwise the returned value or nil
; Examples: ;;; (ErrCatch nil '/ '(4 2)) -> 2 ;;; (ErrCatch T '/ '(4 2)) -> T ;;; (ErrCatch nil '/ '(4 0)) -> nil ;;; (ErrCatch T '/ '(4 0)) -> nil ;;;
(defun ErrCatch ( modeT func varLst / rtn ) (if (not (vl-catch-all-error-p (setq rtn (vl-catch-all-apply func varLst)))) (if modeT 'T rtn)) )

Example:

; No layer filters in this drawing yet:
_$ (setq LFtContainer (ErrCatch nil 'vla-item (list (vla-GetExtensionDictionary LayersColl) "ACAD_LAYERFILTERS")))
nil
; After creating the layer filters:
_$ (setq LFtContainer (ErrCatch nil 'vla-item (list (vla-GetExtensionDictionary LayersColl) "ACAD_LAYERFILTERS")))
#<VLA-OBJECT IAcadDictionary 0000000abe59ea88>
_$ (setq LFtContainer (ErrCatch T 'vla-item (list (vla-GetExtensionDictionary LayersColl) "ACAD_LAYERFILTERS")))
T

Thanks! :)

Link to comment
Share on other sites

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...