Jump to content

Need help browsing (i think) dictionaries


Jef!

Recommended Posts

I made various lisps to help coworkers, going from dimstyles/text styles creation, layers creation, to lisps that crawl through them and change properties if they differ from our standard. Everything is working, but I have an issue with a part I would like to be more robust: We use Viewbases, which automatically create some layers. (MD_Visible, MD_Hidden, etc). In my lisps I seek and monitor these layers using their name. My 1st issue is that these layers can be renamed and remain associated with viewbase & viewbase creation. If someone rename them, I can't find them anymore. The 2nd issue I have is that some files get corrupted and CAD loses the association between viewbases and their original layers. When that happens, if you create a new vbase, CAD want to create the needed layers with their default names (ie MD_Visible), but since there are already layers with these names, it increments and create a MD_Visible_0 layer. I don't like to solely rely on finding these layers by name, even if it works 98% of the time.

 

Basically I would like to retrieve the enames of the layers associated to viewbases. My guess is that if it could be achieved it would be by going into the relevant dictionary. When it comes to browsing entities, tables or selections, vlide is awesome... but when it comes to browsing dictionaries, unless it is something documented, I just don't know how to and where to start. Any help would be appreciated.

Link to comment
Share on other sites

Hi, Jef!

 

If someone rename them, I can't find them anymore.

 

Use handles, If the layernames are changing:

(defun GetLyrsAndHandles ( / d enx L )
 (while (setq d (tblnext "LAYER" (not d)))
   (setq enx (entget (tblobjname "LAYER" (cdr (assoc 2 d)))))
   (setq L (cons (mapcar 'cdr (list (assoc 2 enx) (assoc 5 enx))) L))
 )
)

 

The 2nd issue I have is that some files get corrupted and CAD loses the association between viewbases and their original layers. When that happens,

if you create a new vbase, CAD want to create the needed layers with their default names (ie MD_Visible), but since there are already layers with these names,

it increments and create a MD_Visible_0 layer. I don't like to solely rely on finding these layers by name, even if it works 98% of the time.

 

You could merge those layers, like:

(vlax-map-collection (setq LyrColl (vla-get-Layers (vla-get-ActiveDocument (vlax-get-acad-object)))) ; Unlock and Thaw all layers
 '(lambda (x) (vla-put-Lock x :vlax-false) (vl-catch-all-apply 'vla-put-Freeze (list x :vlax-false)))
)
(if (setq SS (ssget "_X" '((8 . "MD_Visible*")))) ; Merge Layer of the entities
 (repeat (setq i (sslength SS))
   (entmod (append (entget (ssname SS (setq i (1- i)))) '((8 . "MD_Visible"))))
 )
)
(vlax-for x LyrColl (vl-catch-all-apply 'vla-Delete (list x))) ; attempt to delete unused layers

 

EDIT: To elaborate the solution about the first problem,

 

And to demonstrate an example, by storing the layer names with their handles into a dictionary (drawing dependent) :

 

(StoreLayerInfo)               ; To store the layers
(PutSomeLayerNames)            ; To put some random layer names
(RestoreTheOriginalLayerNames) ; To put the original layer names

 

; Use this to store the layer names and their handles into a "LayerInfoDict" dictionary, inside of (namedobjdict) :
; (StoreLayerInfo)
(defun StoreLayerInfo ( / d )
 
 (defun GetOrAddDict ( parentDict dictName ) ; Michael Puckett
   (cond ;;  no error checking in the interests of speed, ;;  caller responsible for ensuring appropriate  ;;  data is passed
     ( (cdr (assoc -1 (dictsearch parentDict dictName))) )
     ( (dictadd parentDict dictName (entmakex '((0 . "DICTIONARY") (100 . "AcDbDictionary")))) )    
   )
 ); defun GetOrAddDict
 
 (defun AddOrReplaceXrec ( parentDict xrecName xrecData / xrec ) ; Michael Puckett
   ;;  no error checking in the interests of speed, ;;  caller responsible for ensuring appropriate ;;  data is passed
   (if (setq xrec (dictsearch parentDict xrecName)) (entdel (cdr (assoc -1 xrec))) )
   (dictadd parentDict xrecName (entmakex (append '((0 . "XRECORD") (100 . "AcDbXrecord")) xrecData)))
 ); defun AddOrReplaceXrec
 
 (defun GetLyrsAndHandles ( / d enx L )
   (while (setq d (tblnext "LAYER" (not d)))
     (setq enx (entget (tblobjname "LAYER" (cdr (assoc 2 d)))))
     (setq L (cons (mapcar 'cdr (list (assoc 2 enx) (assoc 5 enx))) L))
   )
 ); defun GetLyrsAndHandles
 
 (setq d (GetOrAddDict (namedobjdict) "LayerInfoDict"))
 (mapcar 
   '(lambda (x) (AddOrReplaceXrec d (car x) (list (cons 1 (cadr x)))))
   (GetLyrsAndHandles)
 )
); defun StoreLayerInfo

; Use this to restore the layer names and their current names from the "LayerInfoDict" dictionary:
;(alert 
;  (apply 'strcat 
;    (mapcar '(lambda (x) (strcat "\nOriginal Name: " (car x) "\tCurrent name: " (cdr x)))
;      (RetrieveLayerInfo)
;    )
;  )

(defun RetrieveLayerInfo ( / L names handles newnames )
 (setq L (mapcar 'cdr (vl-member-if '(lambda (x) (= 3 (car x))) (dictsearch (namedobjdict) "LayerInfoDict"))))
 (setq names (vl-remove-if-not '(lambda (x) (eq 'STR (type x))) L))
 (setq handles (apply 'append (mapcar '(lambda (x) (if (eq 'ENAME (type x)) (list (cdr (assoc 1 (entget x)))))) L)))
 (setq newnames (mapcar '(lambda (x) (cdr (assoc 2 x))) (mapcar 'entget (mapcar 'handent handles))))
 (mapcar 'cons names newnames)
); defun RetrieveLayerInfo

; (PutSomeLayerNames)
(defun PutSomeLayerNames ( / i )
 (setq i 0)
 (vlax-for Lyr (vla-get-Layers (vla-get-ActiveDocument (vlax-get-acad-object)))
   (vl-catch-all-apply 'vla-put-name (list lyr (itoa (setq i (1+ i)))))
 )
); defun PutSomeLayerNames

; (RestoreTheOriginalLayerNames)
(defun RestoreTheOriginalLayerNames ( / LyrColl )
 (setq LyrColl (vla-get-Layers (vla-get-ActiveDocument (vlax-get-acad-object))))
 (mapcar '(lambda (x) (vl-catch-all-apply 'vla-put-name (list (vla-item LyrColl (cdr x)) (car x))))
   (RetrieveLayerInfo)
 )
); defun RestoreTheOriginalLayerNames

Edited by Grrr
Link to comment
Share on other sites

Hi Grrr

 

BTW congrats on your lisp skill progress over the last months. :)

 

Ok, very clever coding, but you are missing few points here. (all of them actually) :D

Getting handles won't help here. What would the advantage be to retrieve layers handles instead or their Enames?

 

Also Viewbases are very... special. you cannot grab em with ssget. Neither could you for instance (ssget "_X" '((8 . "MD_Visible*"))) or entmod it if it is the layer associated with viewbases. It just wont work. Even if it did, somewhere in a dictionary (sy_* I think) there is something telling CAD which layer is associated with Viewbases' visible lines for instance. Even if you merge MD_Visible_0 on MD_Visible, and delete MD_Visible_0, next time you create a viewbase, since the layer associated is not found, CAD create a new one. Since the name MD_Visible already exists, it created MD_Visible_0. Back to square 1.

 

In that example shown, "MD_Visible" would actually need to be merged on "MD_Visible_0"(which was obviously created last, hence the _0), (than MD_Visible could be purged, and MD_Visible_0 renamed to MD_Visible, retaining its associativity). BUT that is where I am, (at 98%), because ATM I assume that the layer with the highest digit after the _ was created last and is the associated Viewbase layer. The 2% would be: if someone renames "MD_Visible" to "BOB", from that point the "BOB" layer controls the display of viewbases visible lines. CAD knows which layer display ViewBases visible/hidden/etc lines. That is why I need to get CAD to tell me, and since it wont then I need to retrieve the info, that probably lies within a dictionnary. If I don't my code won't know which layers to monitor.

Link to comment
Share on other sites

Just saw your edit. I could make my own dict, but there is a bug (2015, sp2) that makes cad (don't know how or why) lose the association of the layers used for the viewbase. When it happens CAD creates all the MD layers with _0 at the end. By creating another dict, I would probably be in the same boat as ACad when that bug occurs. Maybe not if we use handles. Still I'm not that confortable with creating, handling and maintaining dicts in all dwgs if the sole purpose is to retrieve an information that might be already is in another dict. (IF it is).

 

The only way I see: retrieving ename/handle of one of these (MD) layers, and try to find it in dicts, starting by SY_IDW_DICT_ROOT, SY_IDW_VERSION, and SY_ROOT_DICTIONARY. Digging in anonymous undocumented dictionnaries full of Nested massocs. Hmmmmm. Hours of fun.

Link to comment
Share on other sites

Hi Grrr

BTW congrats on your lisp skill progress over the last months. :)

 

Thanks! :)

 

Getting handles won't help here. What would the advantage be to retrieve layers handles instead or their Enames?

 

Handles won't change, they live with the drawing (and define the same object - no matter what of its property is changed).

Enames change every time you re-open the drawing.

One of the advantages are that you can export for example some txt file with the layer names and handles content (or save them into some dictionary like the example I showed).

And you can easily retrieve back your enames, using handent or vla-HandleToObject method.

 

Also Viewbases are very... special. you cannot grab em with ssget. Neither could you for instance (ssget "_X" '((8 . "MD_Visible*"))) or entmod it if it is the layer associated with viewbases. It just wont work. Even if it did, somewhere in a dictionary (sy_* I think) there is something telling CAD which layer is associated with Viewbases' visible lines for instance.

 

Unfortunatelly, I have no clue what Viewbases are... (and I'm not sure If can anyone /lisper/ else on this forum tell)

So one way to start is to reveal some information about them, using entget / vlax-dump-object (obviously).

 

When it comes to browsing entities, tables or selections, vlide is awesome... but when it comes to browsing dictionaries, unless it is something documented, I just don't know how to and where to start. Any help would be appreciated.

 

Forgot to answer this - From my short experience :

Start from (namedobjdict) and use inspect tool to dig into.

Obviously it requires some list manipulations and accessors when dealing with dictionaries (for the vanilla way).

Or with activex, probably:

(vlax-for o (vla-get-Dictionaries (vla-get-ActiveDocument (vlax-get-acad-object)))
 (vlax-dump-object o)
)

 

 

BTW Alternative way would be to use reactor, but I don't know how this will work for you:

 

; Run this on Startup, every time you use Ctrl+S, the layers are unlocked and thawed, and their names are restored
(and 
 (defun GetLyrs ( / L  )
   (vlax-for o (vla-get-Layers (vla-get-ActiveDocument (vlax-get-acad-object)))
     (setq L (cons (list o (vla-get-Name o)) L))
   )
   L
 )
 (setq *LockedLyrs* (GetLyrs))
 (defun LockLayerNames:callback ( rtr arg / e enx Lyr )
   (vlax-map-collection (setq LyrColl (vla-get-Layers (vla-get-ActiveDocument (vlax-get-acad-object)))) ; Unlock and Thaw all layers
     '(lambda (x) (vla-put-Lock x :vlax-false) (vl-catch-all-apply 'vla-put-Freeze (list x :vlax-false)))
   )
   (foreach x *LockedLyrs* (vl-catch-all-apply 'vla-put-Name x))
   (princ)
 ); defun LockLayerNames:callback
 (progn
   (foreach r (cdar (vlr-reactors :vlr-DWG-reactor)) (and (= (vlr-data r) "LockLayerNames") (vlr-remove r)) )
   (vlr-DWG-reactor "LockLayerNames" '((:vlr-beginSave . LockLayerNames:callback)))
 )
); and 

[color="seagreen"]; 1. Run The Above (in vlide's console for example)
; 2. (PutSomeLayerNames) - in vlide's console
; 3. Ctrl+S to save the drawing - the layers should restore[/color]

(defun PutSomeLayerNames ( / i )
 (setq i 0)
 (vlax-for Lyr (vla-get-Layers (vla-get-ActiveDocument (vlax-get-acad-object)))
   (vl-catch-all-apply 'vla-put-name (list lyr (itoa (setq i (1+ i)))))
 )
); defun PutSomeLayerNames

 

EDIT: I think that the end-problem are the viewbases you mentioned, and not the Layers themselves (afterall we're just trying to rename them).

So perhaps they are connected with xdata - which means that you should try using also:

(entget e '("*"))

To retrieve the full dxf data.

 

Thats all from me - I'm not sure can I help you further. :)

Link to comment
Share on other sites

Basically I would like to retrieve the enames of the layers associated to viewbases.

 

Ok Jef! , trying to help you with the above issue:

 

Now I did some test - used VIEWBASE for the first time (Luckily I have Inventor installed).

The objects created, cannot be accessed through (entsel), however they occur under the "ACDBVIEWREPBLOCKREFERENCE" type:

; (GetViewBaseReferenceNames)
(defun GetViewBaseReferenceNames ( / e enx L )
 (setq e (entnext))
 (while (setq e (entnext e))
   (and
     (setq enx (entget e))
     (= "ACDBVIEWREPBLOCKREFERENCE" (cdr (assoc 0 enx)))
     (setq L (cons (cdr (assoc 2 enx)) L))
   )
 )
 L
); defun GetViewBaseReferenceNames

 

As you can see, their block definitions have names like:

_$ (GetViewBaseReferenceNames)
("*S12" "*S10" "*S8" "*S6" "*S4" "*S2")

 

This means that you can dig into such definitions, and extract their subentities's layers like:

; _$ (GetLyrsVLA) -> ("0" "MD_Visible" "MD_Visible Narrow" "MD_Hidden")
(defun GetLyrsVLA ( / L )
 (vlax-for o (vla-get-Blocks (vla-get-ActiveDocument (vlax-get-acad-object)))
   (if (wcmatch (vla-get-Name o) "`*S*")
     (vlax-for x o (setq L (cons (vla-get-Layer x) L)) )
   )
 )
 (LM:Unique L)
); defun GetLyrsVLA

; _$ (GetLyrs) -> ("0" "MD_Visible" "MD_Visible Narrow" "MD_Hidden")
(defun GetLyrs ( / d e L )
 (while (setq d (tblnext "BLOCK" (not d)))
   (wcmatch (cdr (assoc 2 d)) "`*S*")
   (setq e (tblobjname "BLOCK" (cdr (assoc 2 d))))
   (while (setq e (entnext e))
     (setq L (cons (cdr (assoc 8 (entget e))) L))
   )
 )
 (LM:Unique L)
); defun GetLyrs

;; Unique  -  Lee Mac
;; Returns a list with duplicate elements removed.
(defun LM:Unique ( l )
 (if l (cons (car l) (LM:Unique (vl-remove (car l) (cdr l)))))
)

 

Accessing each block definition from the block reference won't work, since it appears that there are created more definitions than references:

; _$ (BlkDefNames)
; ("*S1" "*S2" "*S3" "*S4" "*S5" "*S6" "*S7" "*S8" "*S9" "*S10" "*S11" "*S12")
(defun BlkDefNames ( / L )
 (vlax-for o (vla-get-Blocks (vla-get-ActiveDocument (vlax-get-acad-object)))
   (if (wcmatch (vla-get-Name o) "`*S*")
     (setq L (cons (vla-get-Name o) L))
   )
 )
 (reverse L)
); defun BlkDefNames

 

Basically I mean, something like this won't work:

(foreach x (GetViewBaseReferenceNames) 
 (setq e (tblobjname "BLOCK" x))
 (while (setq e (entnext e))
   (setq L (cons (cdr (assoc 8 (entget e))) L))
 )
)

 

 

But if you still consider to dig into the dictionaries, this could be a good start:

(setq 
 SY_ROOT (dictsearch (namedobjdict) "SY_ROOT_DICTIONARY")
 SY_MAPPINGS (dictsearch (cdr (assoc -1 SY_ROOT)) "SY_MAPPINGS")
 SY_VIEWSOURCEMGR (dictsearch (cdr (assoc -1 SY_ROOT)) "SY_VIEWSOURCEMGR")
)
(setq UsedPaths
 (apply 'append
   (mapcar '(lambda (x) (if (and (= 1 (car x)) (/= "" (cdr x))) (list (cdr x)))) 
     (entget (cdr (assoc 350 SY_VIEWSOURCEMGR)))
   )
 )
)

 

 

 

BTW Heres a sample data from such viewbase "block" reference:

((-1 . <Entity name: 7ff7be707860>)
 (0 . "ACDBVIEWREPBLOCKREFERENCE")
 (5 . "2F6")
 (102 . "{ACAD_REACTORS")
 (330 . <Entity name: 7ff7be707950>)
 (102 . "}")
 (330 . <Entity name: 7ff7be7039f0>)
 (100 . "AcDbEntity")
 (67 . 0)
 (410 . "Model")
 (8 . "VLD_AnnotateLINES")
 (100 . "AcDbBlockReference")
 (2 . "*S2")
 (10 0.0 0.0 0.0)
 (41 . 1.0)
 (42 . 1.0)
 (43 . 1.0)
 (50 . 0.0)
 (70 . 0)
 (71 . 0)
 (44 . 0.0)
 (45 . 0.0)
 (210 0.0 0.0 1.0)
 (100 . "AcDbViewRepBlockReference")
 (330 . <Entity name: 7ff7be707770>)
)

; IAcadBlockReference: AutoCAD Block Reference Interface
; Property values:
;   Application (RO) = #<VLA-OBJECT IAcadApplication 00007ff7bff49110>
;   Document (RO) = #<VLA-OBJECT IAcadDocument 00000050f24ea108>
;   EffectiveName (RO) = "*S2"
;   EntityTransparency = "ByLayer"
;   Handle (RO) = "2F6"
;   HasAttributes (RO) = 0
;   HasExtensionDictionary (RO) = 0
;   Hyperlinks (RO) = #<VLA-OBJECT IAcadHyperlinks 00000050f285a9d8>
;   InsertionPoint = (-9805.13 -9967.06 0.0)
;   InsUnits (RO) = "Unitless"
;   InsUnitsFactor (RO) = 1.0
;   IsDynamicBlock (RO) = 0
;   Layer = "VLD_AnnotateLINES"
;   Linetype = "ByLayer"
;   LinetypeScale = 1.0
;   Lineweight = -1
;   Material = "ByLayer"
;   Name = "*S2"
;   Normal = (0.0 0.0 1.0)
;   ObjectID (RO) = 65
;   ObjectName (RO) = "AcDbViewRepBlockReference"
;   OwnerID (RO) = 66
;   PlotStyleName = "ByLayer"
;   Rotation = 0.0
;   TrueColor = #<VLA-OBJECT IAcadAcCmColor 00000050f285ab80>
;   Visible = -1
;   XEffectiveScaleFactor = 1.0
;   XScaleFactor = 1.0
;   YEffectiveScaleFactor = 1.0
;   YScaleFactor = 1.0
;   ZEffectiveScaleFactor = 1.0
;   ZScaleFactor = 1.0

 

HTH

Double-posting so you can see this.

Link to comment
Share on other sites

Lots of interesting things here.

Now I did some test - used VIEWBASE for the first time (Luckily I have Inventor installed).

The objects created, cannot be accessed through (entsel), however they occur under the "ACDBVIEWREPBLOCKREFERENCE" type:

M'well, if your profile info is correct (about using Acad 2015) you do not need inventor to can create viewbases. The source can be "model space" (as long as you have 3d solids) or "file" which only accepts inventor models (iam/ipt/ipn). VBases mechanic comes from inventor, I'm pretty sure that is why they have a very unique behavior (no way to copy one, for instance, as they get filtered out).

What i'm curious to know is how on earth did you find that *they occur under the "ACDBVIEWREPBLOCKREFERENCE" type*?

 

Accessing each block definition from the block reference won't work, since it appears that there are created more definitions than references:

Ok, after some time experimenting, (created 1 parent view, 2 projected, 1 section and 2 detail) heres what I found out:

-(speculation)*S blocks = 2 x VB + 1 per parent view (?).

-First contained 3d solids. A lot dispite the fact that I only have 1 in modelspace. I think block is the one that is the root the ghost bug, where duplicates of old objects and detached xref reside and keep appearing. These 3d solids (that might or might not be visible in vbases) will prevent the purge of the layers on which they are (were).

-(GetViewBaseReferenceNames) returns *S blocs, the actual VB (or object you can select in paperspace if you prefer), which contains few layer infos. These are the active layer at the time VB was created (so layer appearing in the property palette when you select a viewbase, and MD_Annotation if there is a section line or detail boundary made from that specific viewbase.

-The other *S blocs seem to be the graphical representation of the viewbases. They contain a bunch of lines, arcs and ellipses, all on layers MD (vis/vis narrow/hidden/hidden narrow)

 

So 5 out of 6 layers can be found that way, the 6th (MdHatch) can be grabbed by ssget. So far I havn't found a way to be sure that the hatch belongs to a view base, so I arbitrary grab'em for the moment.

 

But if you still consider to dig into the dictionaries, this could be a good start:
(setq 
 SY_ROOT (dictsearch (namedobjdict) "SY_ROOT_DICTIONARY")
 SY_MAPPINGS (dictsearch (cdr (assoc -1 SY_ROOT)) "SY_MAPPINGS")
 SY_VIEWSOURCEMGR (dictsearch (cdr (assoc -1 SY_ROOT)) "SY_VIEWSOURCEMGR")
)
(setq UsedPaths
 (apply 'append
   (mapcar '(lambda (x) (if (and (= 1 (car x)) (/= "" (cdr x))) (list (cdr x)))) 
     (entget (cdr (assoc 350 SY_VIEWSOURCEMGR)))
   )
 )
)

That was the part I was most looking forward to play with. I don't know if maybe there is some differences in the dxf code between VBases coming from CAD and the one made using Inventor, but that (usepaths) returns nil. I havn't figured out yet what it is supposed to do, up to usedpaths it works

Command: !sy_viewsourcemgr

((-1 . ) (0 . "ACDBVIEWREPSOURCEMGR") (5 . "15154") (102 . "{ACAD_REACTORS") (330 . ) (102 . "}") (330 . ) (100 . "AcDbViewRepSourceMgr") (290 . 1) (350 . ) (90 . 0))

 

What I cannot figure is how do people surf dicts and find what they are looking for without waisting hours/days? For instance SY_mapping is made of dozens of enames and 64 bits integer values (160).

(160 . 5368709448) (330 . ) (330 . ) (160 . 5368709629) (330 . ) (330 . ) (160 . 5368709656) (330 . ) (330 . ) (160 . 5368709683) (330 . ) (330 . ) (160 . 5368709796) (330 . ) (330 .

You retrieve enames and check them out 1 by 1 until you find what you are looking for? It baffles me. If I look at the dxf reference, i.e. Layer's dxf, 02 group code is the name, 62 is the color. Pretty straight forward and "static". When I search for "160" there is only 1 result in the whole 286 pages: in the "group code value type reference" table. What is that? In the same table i see that 90-99 is a 32bit integer value but so is 420-429, 440-449 and 1071. Why is that? And dicts? Like the one I just shown a part of, ename ename value, ename ename value. How do you make sens out of that?

 

Ok, I'll be back later or tomorrow. My left eye is starting to bleed while smoke is coming out of my right ear. Looking forward to read some input on that, that is if you don't die of old age while reading this reply. Sorry for the length and thanks for your insight so far.

 

Cheers!

Link to comment
Share on other sites

Lots of interesting things here.

M'well, if your profile info is correct (about using Acad 2015) you do not need inventor to can create viewbases. The source can be "model space" (as long as you have 3d solids) or "file" which only accepts inventor models (iam/ipt/ipn). VBases mechanic comes from inventor, I'm pretty sure that is why they have a very unique behavior (no way to copy one, for instance, as they get filtered out).

Yes, it is correct - Its just that the VIEWBASE file dialog prompted me for an iam/ipt/ipn files (since I used inventor in the past I had a few).

So thats how I reproduced these objects you were talking about. (I didn't knew that 3d solids can be used)

 

What i'm curious to know is how on earth did you find that *they occur under the "ACDBVIEWREPBLOCKREFERENCE" type*?

 

Like you mentioned, those objects cannot be grabbed by ssget, so I wrote some quick subfunction to iterate over all graphical enames, and get their types:

(defun GetTypes ( / e L )
 (setq e (entnext))
 (while (setq e (entnext e))
   (setq L (cons (cdr (assoc 0 (entget e))) L))
 )
 (LM:Unique L)
); defun GetTypes

;; Unique  -  Lee Mac
;; Returns a list with duplicate elements removed.
(defun LM:Unique ( l )
 (if l (cons (car l) (LM:Unique (vl-remove (car l) (cdr l)))))
)

 

Below you can see that some of these types doesn't appear standard to AutoCAD:

_$ (GetTypes) 
("MTEXT" "LWPOLYLINE" [color=red]"DRAWINGVIEW"[/color] [color=red]"ACDBVIEWREPBLOCKREFERENCE"[/color] "VIEWPORT")
_$ 

This means that we have to access their dxf data, similairly to the above technique (GetTypes) hence I wrote this (GetViewBaseReferenceNames) subfun.

 

Ok, after some time experimenting, (created 1 parent view, 2 projected, 1 section and 2 detail) heres what I found out:

-(speculation)*S blocks = 2 x VB + 1 per parent view (?).

-First contained 3d solids. A lot dispite the fact that I only have 1 in modelspace. I think block is the one that is the root the ghost bug, where duplicates of old objects and detached xref reside and keep appearing. These 3d solids (that might or might not be visible in vbases) will prevent the purge of the layers on which they are (were).

-(GetViewBaseReferenceNames) returns *S blocs, the actual VB (or object you can select in paperspace if you prefer), which contains few layer infos. These are the active layer at the time VB was created (so layer appearing in the property palette when you select a viewbase, and MD_Annotation if there is a section line or detail boundary made from that specific viewbase.

-The other *S blocs seem to be the graphical representation of the viewbases. They contain a bunch of lines, arcs and ellipses, all on layers MD (vis/vis narrow/hidden/hidden narrow)

 

So 5 out of 6 layers can be found that way, the 6th (MdHatch) can be grabbed by ssget. So far I havn't found a way to be sure that the hatch belongs to a view base, so I arbitrary grab'em for the moment.

 

Note that my test was done upon 1 base view and two projected views (which means that my observation may not be full).

Those viewbases may generate more objects (blocks with different pattern name / layers).

 

That was the part I was most looking forward to play with. I don't know if maybe there is some differences in the dxf code between VBases coming from CAD and the one made using Inventor, but that (usepaths) returns nil. I havn't figured out yet what it is supposed to do, up to usedpaths it works

 

What I cannot figure is how do people surf dicts and find what they are looking for without waisting hours/days? For instance SY_mapping is made of dozens of enames and 64 bits integer values (160).

 

You retrieve enames and check them out 1 by 1 until you find what you are looking for? It baffles me. If I look at the dxf reference, i.e. Layer's dxf, 02 group code is the name, 62 is the color. Pretty straight forward and "static". When I search for "160" there is only 1 result in the whole 286 pages: in the "group code value type reference" table. What is that? In the same table i see that 90-99 is a 32bit integer value but so is 420-429, 440-449 and 1071. Why is that? And dicts? Like the one I just shown a part of, ename ename value, ename ename value. How do you make sens out of that?

 

I'm definitely not a dictionary guru. So I'll just describe my approach:

Personally I start to dig into them from the (namedobjdict) with the VLIDE's inspect tool, and make use of the "Pretty Print" function to display the dxf list in a readable way.

Sample format would be:

((-1 . <Entity name: 7ff7bf2038c0>)
 (0 . "DICTIONARY")
 (330 . <Entity name: 0>)
 (5 . "C")
 (100 . "AcDbDictionary")
 (280 . 0)
 (281 . 1)
 (3 . "ACAD_ASSOCNETWORK")
 (350 . <Entity name: 7ff7bf204eb0>)
 (3 . "ACAD_CIP_PREVIOUS_PRODUCT_INFO")
 (350 . <Entity name: 7ff7bf2049e0>)
 (3 . "ACAD_COLOR")
 (350 . <Entity name: 7ff7bf203bb0>)
 (3 . "ACAD_DETAILVIEWSTYLE")
 (350 . <Entity name: 7ff7bf204a30>)
 (3 . "ACAD_GROUP")
 (350 . <Entity name: 7ff7bf2038d0>)
 (3 . "ACAD_LAYOUT")
 (350 . <Entity name: 7ff7bf2039a0>)
 (3 . "ACAD_MATERIAL")
 (350 . <Entity name: 7ff7bf203ba0>)
 (3 . "ACAD_MLEADERSTYLE")
 (350 . <Entity name: 7ff7bf204150>)
 (3 . "ACAD_MLINESTYLE")
 (350 . <Entity name: 7ff7bf203970>)
 (3 . "ACAD_PLOTSETTINGS")
 (350 . <Entity name: 7ff7bf203990>)
 (3 . "ACAD_PLOTSTYLENAME")
 (350 . <Entity name: 7ff7bf2038e0>)
 (3 . "ACAD_SCALELIST")
 (350 . <Entity name: 7ff7bf2040c0>)
 (3 . "ACAD_SECTIONVIEWSTYLE")
 (350 . <Entity name: 7ff7bf204a10>)
 (3 . "ACAD_TABLESTYLE")
 (350 . <Entity name: 7ff7bf203c60>)
 (3 . "ACAD_VISUALSTYLE")
 (350 . <Entity name: 7ff7bf203ef0>)
 (3 . "AcDbVariableDictionary")
 (350 . <Entity name: 7ff7bf203ae0>)
 (3 . "SY_IDW_DICT_ROOT")
 (350 . <Entity name: 7ff7bf208620>)
 (3 . "SY_IDW_VERSION")
 (350 . <Entity name: 7ff7bf208630>)
 (3 . "SY_ROOT_DICTIONARY")
 (350 . <Entity name: 7ff7bf204d00>)
)

 

Obviously when you have to deal with such list, you must make use of the list manipulation and dictionary handling functions.

 

That said, you can see how easier it is to access for example the "ACAD_MLEADERSTYLE" dictionary:

$ (dictsearch (namedobjdict) "ACAD_MLEADERSTYLE") ; using dictsearch
((-1 . <Entity name: 7ff7bf204150>) (0 . "DICTIONARY") (5 . "12D") (102 . "{ACAD_REACTORS") (330 . <Entity name: 7ff7bf2038c0>) (102 . "}") (330 . <Entity name: 7ff7bf2038c0>) (100 . "AcDbDictionary") (280 . 0) (281 . 1) (3 . "Annotative") (350 . <Entity name: 7ff7bf204230>) (3 . "Standard") (350 . <Entity name: 7ff7bf204160>))
_$ 

_$ (entget (cdar (cdr (vl-member-if '(lambda (x) (equal x '(3 . "ACAD_MLEADERSTYLE"))) (entget (namedobjdict)))))) ; using list manipulation
((-1 . <Entity name: 7ff7bf204150>) (0 . "DICTIONARY") (5 . "12D") (102 . "{ACAD_REACTORS") (330 . <Entity name: 7ff7bf2038c0>) (102 . "}") (330 . <Entity name: 7ff7bf2038c0>) (100 . "AcDbDictionary") (280 . 0) (281 . 1) (3 . "Annotative") (350 . <Entity name: 7ff7bf204230>) (3 . "Standard") (350 . <Entity name: 7ff7bf204160>))
_$ 

 

The dxf reference gives some idea about what group code represents what type of data. But its not fully documented (or its documented only for the standard AutoCAD objects).

Sometimes I find it much easier to use ActiveX when it comes to accessing deeply stored data.

 

I find interesting the dictionary questions you posted - hopefully someone more expirienced will answer.

 

Overall you can see that the whole process is to look for some information - graphical / non-graphical enames/objects,

So atleast you could get an idea where and how to look - in order to solve your problem (thats the only way I could help).

 

Usually when it comes to such "non-standard" objects, you might get few or no replies from other people.

Thats my impression about such threads (people are not interested or not familiar enough, to help solving such unpopular problem).

Link to comment
Share on other sites

  • 2 years later...

Guys,

 

From the layout which contains the drawingview entities, you need to build a list of those items via a scan of the entire drawing database...the object type you mentioned (ACDBVIEWREPBLOCKREFERENCE) is what you get when you select an item within the drawing view object (like when using a field->select object) and not the view border.  Also, the type changes based upon the representation of the drawingview object (forex, shaded vs. linework).  Note that the drawingview object may contain the summary information you are seeking regarding view layer/scale/location/extents etc., then from there your lisp can "drill down" the associated entities to discover what "MD_*" layers it exists on (handles the renaming problem).  I use this technique not for standards enforcement, but for assembly and parts breakouts of my model into automatically dimensioned views/details (kind of like a simpler version of Advance Steel only with native Autocad objects). Also, any manipulation of an entity that is essentially blocked by AutoDesk is at risk for obsolescence by use - hence the disconnect that you mentioned.  Handles don't work because when the model is manipulated using commands that destroy the original entity and it's associated handle - it get's lost!  This is tough, but doable.

I would suggest generating a clone of the drawingview with a new anonymous block of you own design which contains XData with the links back to the original objects in Model space, to avoid this potential corruption of the file.  Your reactor idea would be a good fit here.  The reason I implemented this design in my library was started for I could copy a drawing view object from one layout to another without data loss/disconnects.

In closing...IMO-you guys are amazing->keep up the good fight.  I am semi-retired Software Engineer who worked in the industry over 30 yrs. and invents new things on the daily...Keep working on it and you will get there!  My advice, "When you develop a little to close to the Sun (i.e. the application core), you may get burned." Hence the cloning (Clone it to Own It!).

 

TANX.Rob

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...