More Dictionary questions

More Dictionary questions

Anonymous
Not applicable
408 Views
5 Replies
Message 1 of 6

More Dictionary questions

Anonymous
Not applicable
Hi all you dictionary fans out there.
I'm think I want to use dictionaries for data storage for a routine I'm
working on and have been reading and re-reading every post in the archive
and every helpfile on dictionaries etc but i'm still fuzzy on all this.
are dictionaries and extension dictionaries the same thing or two different
things?
Is an extension dictionary attatched to an entity like xdata? is it the same
as xdata?
Does xdata only hold one key and one value?
If I make dictionaries under the Dictionaries collection and it has a 'name'
how do i get at that name? .objectName only returns AcDbDictionary or
something like that.

Sub readDicts()
Set colDicts = ThisDrawing.Dictionaries
Dim howMany As Integer, i As Integer
howMany = colDicts.count
Debug.Print "There are " & howMany & " dictionaries"
For i = 0 To colDicts.count - 1
MsgBox colDicts.Item(i).ObjectName
Next
End Sub

Coming from lisp I expect to have to check for the existence before adding
to it like
(if dictx
;exists
blah
; else
blah blah
);end if
but it seems like in vb what I'm seeing is
on error resume next or go to or?
try to do something with dictx
- then if dictx didn't exist the error handler takes care of it.
That just seems so wrong after having to prevent all errors with lisp
previously
but I guess i'll just have to get used to it.
So maybe I don't have to be able to get at my dictionary name to see if it's
there?

so what I'm trying is this:

Sub PutInDictionary(obj As AcadObject) As AcadDictionary

dictName = "whatever"
Set colDicts = ThisDrawing.Dictionaries
On Error Resume Next
Set newDict = ThisDrawing.Dictionaries(dictName)
If Err Then
err.clear???
'
'so create it
Set newDict = colDicts.Add(dictName)
'example of info I want to store
newDictEntry = newDict.AddXRecord("PtList", obj.Coordinates)
newDictEntry = newDict.AddXRecord("hndl", obj.Handle)
newDictEntry = newDict.AddXRecord("layr", obj.Layer)
Else
'
newDictEntry = newDict.AddXRecord("PtList", obj.Coordinates)
newDictEntry = newDict.AddXRecord("hndl", obj.Handle)
newDictEntry = newDict.AddXRecord("layr", obj.Layer)
End If

For i = 0 To newDict.count - 1
MsgBox newDict.Item(i).GetName
Debug.Print newDict.Item(i).GetName
Next i

End Sub

obviously I'm flailing about here, the example AddXrecord just adds one item
so I'm confused as to how to do the above.
Any guidance mucho appreciated.

What I want to end up with is a dictionary with a record for each of x
number of layers.
Each record will have a list of each item on that layer (polylines)
Each list will have various items of info like point list, size, etc.
I don't know if I need a different dictionary for each layer and then a
dictionary containing all those dictionaries?
And would the information lists for each pline be separate dictionaries or
separate xrecords within a dictionary?
Or can it all be one big dictionary with just xrecords to store the lists?
Is the xrecord itself an array of two arrays: a key array and a value array?
I am so confused! ?:<
Mark
0 Likes
409 Views
5 Replies
Replies (5)
Message 2 of 6

Anonymous
Not applicable


Mark

    I'm glad I'm not the only one who isn't 100% clear
on how this all works. But some things your unclear on I can help with.
Other things you mentioned articulated concepts I don't get either, and
raised more questions for me as well.

 

 

Mark Propst wrote:

Hi all you dictionary fans out there.

I'm think I want to use dictionaries for data storage for a routine
I'm

working on and have been reading and re-reading every post in the archive

and every helpfile on dictionaries etc but i'm still fuzzy on all this.

are dictionaries and extension dictionaries the same thing or two different

things?

The drawing contains a number of collections, the layer collection, the
block collection, and a collection called the dictionary collection. This
is a collection of dictionary objects. Each dictionary can itself contain
a collection of Xrecords. Autocad uses a dictionary in this collection
to hold layer state information. Extension dictionaries on the other hand
are like a dictionary that can be attached to any object, including all
drawing objects.
 

Is an extension dictionary attatched to an entity like xdata? is it
the same

as xdata?

No, Xdata is actually short for extended data. Being a lisp user, you hopefully
are familiar with DXF codes (the definition data autocad uses to create
objects). AutoCad has provided group codes following the normal definition
data which provide a repository for arbitrary data, and this is the 'extended
data '. In other words it can be used to store information generated by
a third party application. The group codes can be found in help, under
the visualLisp, Autolisp, and DXF book, in the DXF Reference, under
the heading advanced DXF issues. Size of the data contained and
the order it must be stored is important. Xrecords have no such restrictions
and can contain all the normal data types, arrays of variables, or other
objects, even other xrecords.
 

Does xdata only hold one key and one value?

No, with different techniques, xdata can hold many values of varying type.
 

If I make dictionaries under the Dictionaries collection and it has
a 'name'

how do i get at that name? .objectName only returns AcDbDictionary
or

something like that.

Sub readDicts()

Set colDicts = ThisDrawing.Dictionaries

Dim howMany As Integer, i As Integer

howMany = colDicts.count

Debug.Print "There are " & howMany & " dictionaries"

For i = 0 To colDicts.count - 1

MsgBox colDicts.Item(i).ObjectName

Next

End Sub


If a dictionary has a name it would be the name you gave it, when you made
it

examples:

Dim DicObj As AcadDictionary

''create a dictionary

DicObj = ThisDrawing.Dictionaries.Add("myDictionary")

'' access the dictionary with index, using either it's

'' name or index number

DicObj = ThisDrawing.Dictionaries.Item("myDictionary")

'' loop through the collection

'' using for..next, for..each, or do..loop

Dim cnt As Integer

Dim str As String

cnt = ThisDrawing.Dictionaries.Count - 1

Do While cnt >= 0

DicObj = ThisDrawing.Dictionaries.Item(cnt)

str = DicObj.Name

If str = "myDictionary" Then DoSomething

cnt = cnt - 1

Loop
 

Coming from lisp I expect to have to check for the existence before
adding

to it like

(if dictx

;exists

 blah

; else

 blah blah

);end if

but it seems like in vb what I'm seeing is

on error resume next or go to or?

try to do something with dictx

- then if dictx didn't exist the error handler takes care of it.

That just seems so wrong after having to prevent all errors with lisp

previously

but I guess i'll just have to get used to it.


OK, this is a major difference between lisp and VB. Lisp has minimal error
handling capabilities. (at least it did before VLAX) Visual Basic on the
other hand has been called 'programing by exception' and has robust error
handling. With lisp you learn to write bullet proof code and learn an extreme
advertion to errors. In VB, you can throw errors to test if an object is
valid

example:

On Error Resume Next

ThisDrawing.Dictionaries.Item ("MyDictionary")

If Err.Number <> 0 Then

DoSomething

'' if there was no error

''err.Number will = 0

Err.Clear

'' sets err.Number back to 0

End If

 

So maybe I don't have to be able to get at my dictionary name to see
if it's

there?

as stated previously, you access a dictionary object using .Dictionaries.Item(index)
using the index number (0) or name (MyDictionary") as the index reference
 

so what I'm trying is this:

Sub PutInDictionary(obj As AcadObject) As AcadDictionary

<assume all necessary declarations here>

dictName = "whatever"

Set colDicts = ThisDrawing.Dictionaries

On Error Resume Next

Set newDict = ThisDrawing.Dictionaries(dictName)

If Err Then

err.clear???

'    <it isn't there>

'so create it

Set newDict = colDicts.Add(dictName)

'example of info I want to store

newDictEntry = newDict.AddXRecord("PtList", obj.Coordinates)

newDictEntry = newDict.AddXRecord("hndl", obj.Handle)

newDictEntry = newDict.AddXRecord("layr", obj.Layer)

Else

'    <it is there>

newDictEntry = newDict.AddXRecord("PtList", obj.Coordinates)

newDictEntry = newDict.AddXRecord("hndl", obj.Handle)

newDictEntry = newDict.AddXRecord("layr", obj.Layer)

End If

For i = 0 To newDict.count - 1

MsgBox newDict.Item(i).GetName

Debug.Print newDict.Item(i).GetName

Next i

End Sub

obviously I'm flailing about here, the example AddXrecord just adds
one item


some of the documentation is a little ... ah ..sparse
 

so I'm confused as to how to do the above.

Any guidance mucho appreciated.

What I want to end up with is a dictionary with a record for each of
x

number of layers.

Each record will have a list of each item on that layer (polylines)

Each list will have various items of info like point list, size, etc.

I don't know if I need a different dictionary for each layer and then
a

dictionary containing all those dictionaries?

And would the information lists for each pline be separate dictionaries
or

separate xrecords within a dictionary?

Or can it all be one big dictionary with just xrecords to store the
lists?

Is the xrecord itself an array of two arrays: a key array and a value
array?


It can be, an array that is. Sounds like an interesting project, and obviously
there are many ways to skin a cat. hope this helped. I'm not clear on some
aspects of all this and I could be wrong about about some of it. Maybe
someone who i more familiar with it can help us both. The example code
was not tested and may not run as posted, and was provided for example
only.
0 Likes
Message 3 of 6

Anonymous
Not applicable
Hi Andy,
Thanks for the clarifications
I had tried more or less what you have below but must have done something
wrong because I couldn't get a .name property out of the object, only an
.ObjectName property
But with the following mods to your code I got this to partially run

"Andy & Starr" wrote in message

If a dictionary has a name it would be the name you gave it, when you made
it
'---I added
Sub ()
Dim DicObj As AcadDictionary
'--- I had to change this
'DicObj = ThisDrawing.Dictionaries.Add("myDictionary")
'---to:
Set DicObj = ThisDrawing.Dictionaries.Add("myDictionary")

'' loop through the collection
Dim cnt As Integer
Dim str As String
cnt = ThisDrawing.Dictionaries.Count - 1
Do While cnt >= 0
'---I changed this
'DicObj = ThisDrawing.Dictionaries.Item(cnt)
'---to this
Set DicObj = ThisDrawing.Dictionaries.Item(cnt)
str = DicObj.Name
'--- then added this
Debug.Print str
cnt = cnt - 1
Loop
'--- and this
End Sub
'that worked til cnt = 3 then bombed with "Type Mismatch"
'the result (in immediate window) was
myDictionary
AcDbVariableDictionary
ACAD_PLOTSTYLENAME

so I don't know why the next dictionary is different in type from the first
3.
and I'm still trying to figure out how to populate the dictionary once I
create it.
(with more than one record)
I have run the example AddXrecord and I see that the xrecorddatatype and
xrecorddata are arrays which apparently need redimmed each time you add an
xrecord.
siince i've read that redim array slows things down maybe I don't want to be
using dictionaries at all if I have many items to store.
I've used collections and maybe that's the route to take but I haven't
figured out yet what object to change my list into to store it in the
collection if not an array?
Right now I have a list of lists of lists of data similar to an entity list.

What I want to end up with is a dictionary - or collection? - with a
record for each of x number of layers.
Each record will have a list of each item on that layer (polylines)
Each list will have various items of info like point list, size, etc.
I don't know if I need a different dictionary for each layer and then a
dictionary containing all those dictionaries?
And would the information lists for each pline be separate dictionaries or
separate xrecords within a dictionary?
Or can it all be one big dictionary with just xrecords to store the lists?
Is the xrecord itself an array of two arrays: a key array and a value array

Thanks again for the response and I'll keep trying to figure this out an
hope someone may be able to shed some more light on this topic.


Thanks again,
Mark
0 Likes
Message 4 of 6

Anonymous
Not applicable
Mark:
When you asked about getting the name property out of a dictionary, I
thought that odd, because I knew they had one. So figuring you were working in
VBA in AutoCad I fired Cad up, launched the IDE and tried er out just to make
sure. Well... I made a dictionary object, and couldn't get it to come up in the
list. I was sure it had one, so I fired up my VB editor, made a dictionary
object, and sure enough, it has a name (not objectname) property. Now, I'm
freaking out, I check the references to make sure the same object model is
loaded. Then I open the Acad IDE again, and lo and behold, my dictionary object
in the same file now has a name property. ! I thought about mentioning that
little glitch to you, but I figured if you didn't have stand alone VB it
wouldn't help ya anyhow.
The code I sent you was more of an syntax example for the individual
methods. But I think what you are ultimately trying to do is basically a
quantity take off routine. It's a common programing task for cad. I'm working on
a similar project, only I'm counting block references. The task, as I see it, is
this... we go into the drawing and, by whatever means, select or acquire a
group of drawing objects, from which we wish to extract some data, be it the
area of a polyline, or an attribute from a block or whatever. After we have
processed the data, we need a way to store it. We need a collection of
collections, a container to hold some objects, which is itself a member of a
collection of like containers. And the containers must be sized dynamically,
because there may be any number of objects in each container, and any number of
containers in the collection. We must be able to give the containers a label or
hold some data, so we can distinguish which container we have and we must be
able to loop though the containers and objects to access the data.
How to do so, I guess, depends on what we need to store. Do we need to
store the object itself, or just the handle. You can access any property
relatively easily if you have it's handle. (for that matter, use HandleToObject
method and you have the object from a string, although it might not be real
fast) Do we need to loop through the objects only once to gather the data, or
will we have to loop through many times, say as the user picks between
categories. Do we need to modify the objects, maybe only ones in this group not
in that one. How do you need to output the data? Can you just post it in a form,
or placed it in the drawing, or maybe plug it into a spreadsheet. Do you need to
save it to a file?
Arrays are the natural first choice. But dynamically sizing a two dimension
array is a pain. And you have to use redim preserve, then you can only redim the
second dimension of the array. So that won't work. I see Acad providing the
dictionaries for situations exactly like this. We could do it in a couple of
different ways. 1. We could create a dictionary for each layer, then store the
polys in Xrecords. 2. We could create a dictionary, and create Xrecords for each
layer, then give each Xrecord an extension dictionary to store the polys in. 3.
we could use number 2 but store the objects in an array in the Xrecord instead
of creating an extension dictionary. 4. We could create a dictionary, create
Xrecords for each layer, and store Xrecords in the Xrecords 5. or we could use
number 2 but store the data in the extended data (Xdata) in each Xrecord. Or
here's a novel approach, we could name a selection set after each layer (group)
and store the objects in the selection sets. If we only need to hang on to them
for a brief time and there aren't to many, this might could work. So there are
obviously a few ways to trap this mouse, how you do so depends on your needs.
I think using an array in the example code for SetXRecordData was a poor
choice. You can use any variable type in the method. It's just an example and it
runs. But it's a little cryptic, and they needlessly use constants (always a
good idea, but not necessary in the example) which makes it harder to follow.
I have little experience with dictionaries, but that may change in the next
day or two. For me, they are one of a few possible solutions. And I could use
different combinations to make different features work Which will be best will
probably require writing a little piece of each and testing. If I come up with
something you could use I'll let ya know.
0 Likes
Message 5 of 6

Anonymous
Not applicable
"Andy & Starr" wrote in message
> Then I open the Acad IDE again, and lo and behold, my dictionary object
> in the same file now has a name property. !

that's trippy! It didn't work for me at home when I first tried it, (yes, I
have vb but wasn't using it) then after modifying your example it ran here
at work (also without running vb)
so who knows?

>But I think what you are ultimately trying to do is basically a
> quantity take off routine.

correctamundo

> We could do it in a couple of
> different ways. 1. We could create a dictionary for each layer, then store
the
> polys in Xrecords.

I'm thinking a dictionary can hold other dictionaries? so then each layer
dict can live in the all-layers dict? is that true?...no probably not, a
dictionary has xrecords - they can have xrecords in them....yeah, number 4
below...

>2. We could create a dictionary, and create Xrecords for each
> layer, then give each Xrecord an extension dictionary to store the polys
in.

hmm...got to learn about those extension dicts too. do they use xrecords
also for the data? back to the un-help files...
...later, back at the ng... from the un-help-full files:
"The extension dictionary is an optional sequence that stores the handle of
a dictionary object that belongs to the current object, which in turn may
contain entries. This facility allows attachment of arbitrary database
objects to any database object. Any object or entity may have this section.
"
(not a word about how to create an extension dictionary, how to populate it
nor how to stick it into an xrecord...oh well...)

my reaction: "huh?"
so I create a dictionary, load it with xrecords, get it's handle, and then
put that handle into an extension dictionary and attatch that to an xrecord
in another dictionary????
I don't see why this should be the least confusing!

>3. we could use number 2 but store the objects in an array in the Xrecord
instead
> of creating an extension dictionary.
>4. We could create a dictionary, create
> Xrecords for each layer, and store Xrecords in the Xrecords

that sounds like what I'm thinking of if I can figure out how to do it...

>5. or we could use
> number 2 but store the data in the extended data (Xdata) in each Xrecord.

hmm... xdata, so with xdata I can group my lists with (1002 . "{") and
thereby have nested lists, and as I read the help, I can have multiple same
group codes - eg 1010,1020,1030 for pt1, then 101,1020,1030 for pt2, etc
etc. is that right?
Then getXData returns the lists into two variant variables which are each
loaded with an array.
the first one an array of the group code, and the second one an array of the
values.
so i step through the arrays and figure out which element I have and then
deal with it accordingly....maybe we're on to something here.

> Or
> here's a novel approach, we could name a selection set after each layer
(group)
> and store the objects in the selection sets. If we only need to hang on to
them
> for a brief time and there aren't to many, this might could work.

In my case, I had the stuff in a sel set, got some data out of the entities,
manipulated the data, stored it in multiple lists in an assoc code sort of
way, and now am looking to store it for unpredictable time frame. Maybe I'll
use it then or maybe I'll need to come back to it later(another session).
therefore the need to store with persistence. I got the first part done with
lisp first cause i've been at that longer.
Now I have to port to vb so i can open other dwgs and do stuff with the info
in my lists, which lisp cant do - (going from one dwg to another.)


>So there are
> obviously a few ways to trap this mouse, how you do so depends on your
needs.
> If I come up with
> something you could use I'll let ya know.
>
I think my mouse is laughing at me...feeling no fear!

Thanks again for your help. It always helps to hear the same thing repeated
different ways and gradually it seeps in....I don't know how many times I've
re-read those help files...egads!!!
if only I could get back some of those brain cells from the seventies and
eighties...oh yeah and the nineties...
Have a good one, and good luck with your project too.
Mark
0 Likes
Message 6 of 6

Anonymous
Not applicable
Mark:


> I'm thinking a dictionary can hold other dictionaries? so then each layer
> dict can live in the all-layers dict? is that true?...no probably not, a
> dictionary has xrecords - they can have xrecords in them....yeah, number 4
> below...

I think you answered you own question. My understanding is that a dictionary can
contain an Xrecord, that Xrecord in turn could contain another dictionary. So
you could have a dictionary (all Layers) which has Xrecords (this Layer) and
(That Layer) which contain a dictionary each (this Layer Dictionary), which have
Xrecords for each object


> hmm...got to learn about those extension dicts too. do they use xrecords
> also for the data? back to the un-help files...
> ...later, back at the ng... from the un-help-full files:
> "The extension dictionary is an optional sequence

you would probably call it a dotted pair, in other words an additional tagged
data element in the list for that object.

> that stores the handle

Ah yes the handle, a unique string referencing the object that is persistant for
the life of the object

> of a dictionary object that belongs to the current object,

in other words the object has its own dictionary object attached to it

> which in turn may contain entries.

haHA... we have an object, an Xrecord which is a member of a dictionary, we give
this Xrecord it's own extension dictionary, then we add Xrecords to the Xrecords
dictionary.

> This facility allows attachment of arbitrary database
> objects to any database object.

That's us dude

> Any object or entity may have this section.

Yeah I read that like twenty eight time.

> "
> (not a word about how to create an extension dictionary, how to populate it
> nor how to stick it into an xrecord...oh well...)

GetExtensionDictionary
If an object does not have an extension dictionary, this method will create a
new extension dictionary for that object and return it in the return value.
You can query an object to see if it has an extension dictionary by using the
HasExtensionDictionary property.
This is a method of the XRecord object. Create a Dictionary, add an Xrecord and
call the method

>
>
> my reaction: "huh?"

my reaction: ...........ah........was that english?

>
> so I create a dictionary, load it with xrecords, get it's handle, and then
> put that handle into an extension dictionary and attatch that to an xrecord
> in another dictionary????

see above

> >4. We could create a dictionary, create
> > Xrecords for each layer, and store Xrecords in the Xrecords
> that sounds like what I'm thinking of if I can figure out how to do it...

that or putting a dictionary in each Xrecord sounds like a good bet to me to

> >5. or we could use
> > number 2 but store the data in the extended data (Xdata) in each Xrecord.
>
> hmm... xdata, so with xdata I can group my lists with (1002 . "{") and
> thereby have nested lists, and as I read the help, I can have multiple same
> group codes - eg 1010,1020,1030 for pt1, then 101,1020,1030 for pt2, etc
> etc. is that right?
> Then getXData returns the lists into two variant variables which are each
> loaded with an array.
> the first one an array of the group code, and the second one an array of the
> values.
> so i step through the arrays and figure out which element I have and then
> deal with it accordingly....maybe we're on to something here.
>

This appeals to you cause your a lisp guy, you're used to deciphering those
lists

>
> > Or
> > here's a novel approach, we could name a selection set after each layer
> (group)
> > and store the objects in the selection sets. If we only need to hang on to
> them
> > for a brief time and there aren't to many, this might could work.
>
> In my case, I had the stuff in a sel set, got some data out of the entities,
> manipulated the data, stored it in multiple lists in an assoc code sort of
> way, and now am looking to store it for unpredictable time frame. Maybe I'll
> use it then or maybe I'll need to come back to it later(another session).

> therefore the need to store with persistence. I got the first part done with

> lisp first cause i've been at that longer.
> Now I have to port to vb so i can open other dwgs and do stuff with the info
> in my lists, which lisp cant do - (going from one dwg to another.)
>
> >So there are
> > obviously a few ways to trap this mouse, how you do so depends on your
> needs.
> > If I come up with
> > something you could use I'll let ya know.
> >
> I think my mouse is laughing at me...feeling no fear!
>
> Thanks again for your help. It always helps to hear the same thing repeated
> different ways and gradually it seeps in....I don't know how many times I've
> re-read those help files...egads!!!

I'm going to go play with these Xrecord thingies. Let ya know
0 Likes