Author Topic: What's the most efficent way to get layout names  (Read 5164 times)

0 Members and 1 Guest are viewing this topic.

Viktor

  • Guest
What's the most efficent way to get layout names
« on: October 21, 2009, 01:56:00 PM »
I have a need in one of my apps to let the user pick layouts out of a drawing. Normally, I have a listbox with a list of files in a selected directory, and if a user checks a mutli-tab checkbox, then I want to update the list with all the filesnames and layouts.

Anyway, I've written a simple GetLayouts function to go through the btrs and check if its a layout then retrieve the name and return an array of names. This works great if there's 5 files, but if I have 50 this may take upto 20 seconds... The most consuming part of the code of course is this:
database.ReadDwgFile(filepath, FileOpenMode.OpenForReadAndAllShare, False, "")

So is there any other quicker way to get layouts?

Thanks,
Viktor.

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: What's the most efficent way to get layout names
« Reply #1 on: October 21, 2009, 02:07:07 PM »
Hi,

You can iterate the "ACAD_LAYOUT" dictionary.

Code: [Select]
using (Transaction tr = db.TransactionManager.StartTransaction())
{
    DBDictionary NOD = (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead);
    DBDictionary layouts = (DBDictionary)tr.GetObject(NOD.GetAt("ACAD_LAYOUT"), OpenMode.ForRead);
    foreach (DBDictionaryEntry entry in layouts)
    {
        string name = entry.Key;
        ...
    }
}
« Last Edit: October 21, 2009, 02:17:28 PM by gile »
Speaking English as a French Frog

Glenn R

  • Guest
Re: What's the most efficent way to get layout names
« Reply #2 on: October 21, 2009, 04:22:57 PM »
Viktor,

You need to specify at the least, the following information for more targeted help from members:

1. AutoCAD version
2. .NET framework version
3. Operating system and service packs
4. Visual Studio version
5. 32 or 64 bit for all the above for good measure

Also, a small example project that members can test with would be very beneficial as well.

Viktor

  • Guest
Re: What's the most efficent way to get layout names
« Reply #3 on: October 21, 2009, 05:05:39 PM »
Viktor,

You need to specify at the least, the following information for more targeted help from members:

1. AutoCAD version
2. .NET framework version
3. Operating system and service packs
4. Visual Studio version
5. 32 or 64 bit for all the above for good measure

Also, a small example project that members can test with would be very beneficial as well.


My apology Glenn, it was more of a general question, here's more info:

1. AutoCad 2010
2. .net 3.5
4. XP
4. VS2008 express
5. 32bit
6. VB.net

Here's the function I use to get the layouts:
Code: [Select]
    Public Function GetLayouts(ByVal filepath As String) As ArrayList
        Dim database As New Database(False, True)
        Dim list As New ArrayList
        Dim transaction As Transaction = database.TransactionManager.StartTransaction
        Using database
            Try
                database.ReadDwgFile(filepath, FileOpenMode.OpenForReadAndAllShare, True, Nothing)
                Dim enumerator As SymbolTableEnumerator = DirectCast(database.BlockTableId.GetObject(OpenMode.ForRead), BlockTable).GetEnumerator
                Do While enumerator.MoveNext
                    Dim record As BlockTableRecord = DirectCast(enumerator.Current.GetObject(OpenMode.ForRead), BlockTableRecord)
                    If record.IsLayout Then
                        Dim layout As Layout = DirectCast(record.LayoutId.GetObject(OpenMode.ForRead), Layout)
                        If (layout.LayoutName <> "Model") Then
                            list.Add((layout.LayoutName))
                        End If
                    End If
                Loop
            Catch exception1 As Exception
                transaction.Abort()
                Return Nothing
            Finally
                transaction.Dispose()
            End Try
        End Using
        Return list
    End Function

This works, but the fact that I have to read the database of each drawing in my list takes quiet a bit of time. For example, if i have 30 drawings that are 2-5mb each with 3-5 layouts in each, this can take upto 30 seconds to scan for layouts. Like I said, the most consuming part of this code is opening the database.

I'd guess there's no other way without using objectarx, but thought i'd ask either way.

Glenn R

  • Guest
Re: What's the most efficent way to get layout names
« Reply #4 on: October 21, 2009, 05:48:06 PM »
heh...forgot to add 6. Language - thanks.

In ObjectARX, you would still have to 'read' the dwg dbase as well, so that point is moot.

You could also do this:

Code: [Select]
[CommandMethod("MyCommandLocal", CommandFlags.Modal)]
public void MyCommand() // This method can have any name
{
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;

using (Transaction tr = db.TransactionManager.StartTransaction())
{
DBDictionary layoutDict = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead, false) as DBDictionary;
foreach (DBDictionaryEntry dictEnt in layoutDict)
{
//Layout layout = tr.GetObject(dictEnt.Value, OpenMode.ForRead, false) as Layout;
//ed.WriteMessage("{0}Layout name: {1}", Environment.NewLine, layout.LayoutName);
ed.WriteMessage("{0}Layout name: {1}", Environment.NewLine, dictEnt.Key);
}
}
}

Also, why are you using GetEnumerator?

Viktor

  • Guest
Re: What's the most efficent way to get layout names
« Reply #5 on: October 21, 2009, 06:02:06 PM »
heh...forgot to add 6. Language - thanks.

In ObjectARX, you would still have to 'read' the dwg dbase as well, so that point is moot.

You could also do this:

Code: [Select]
[CommandMethod("MyCommandLocal", CommandFlags.Modal)]
public void MyCommand() // This method can have any name
{
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;

using (Transaction tr = db.TransactionManager.StartTransaction())
{
DBDictionary layoutDict = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead, false) as DBDictionary;
foreach (DBDictionaryEntry dictEnt in layoutDict)
{
//Layout layout = tr.GetObject(dictEnt.Value, OpenMode.ForRead, false) as Layout;
//ed.WriteMessage("{0}Layout name: {1}", Environment.NewLine, layout.LayoutName);
ed.WriteMessage("{0}Layout name: {1}", Environment.NewLine, dictEnt.Key);
}
}
}

Also, why are you using GetEnumerator?

Thankgs Glenn, yea i was feeling hopeless either way but thought of asking. In the sample you provided you're getting the layouts of the current drawing if i'm not mistaken, I don't want to open drawings cause that would take another 20 minutes.

As far as enumerator goes, i actually copied this from a vb.net book i use, but to be honest with you i rarely use the enumerator other than where I copied it. I may not be doing it any better way though, i just loop through the id's in a for each loop once i find what i need i exit for.

What's the best way?

I also signed up for the linq class at AU this year, i love linq for everything outside of autocad db, so it'd be interesting to see how i can use it in autocad db. Do you linq?

Glenn R

  • Guest
Re: What's the most efficent way to get layout names
« Reply #6 on: October 21, 2009, 06:09:25 PM »
In the sample you provided you're getting the layouts of the current drawing if i'm not mistaken, I don't want to open drawings cause that would take another 20 minutes.

Yes I am, but it's a quick example. You will see that I'm getting the layouts from the DATABASE of the current document...it's still a databse, the same as you're constructing and using in ReadDwgFile.

Also, you're iterating the whole block table to find the layouts, which in dwgs of 2-5mb could be large, whereas I'm going straight to the layouts dictionary, similar to what gile posted above, which, all things being equal, should be faster.

Try it.

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: What's the most efficent way to get layout names
« Reply #7 on: October 21, 2009, 06:18:58 PM »
Something like this ?

Code: [Select]
public ArrayList GetLayouts(string filename)
{
    ArrayList lst = new ArrayList();
    using (Database db = new Database(false, true))
    {
        try
        {
            db.ReadDwgFile(filename, System.IO.FileShare.None, false, string.Empty);
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                DBDictionary NOD = (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead);
                DBDictionary layouts = (DBDictionary)tr.GetObject(NOD.GetAt("ACAD_LAYOUT"), OpenMode.ForRead);
                foreach (DBDictionaryEntry entry in layouts)
                {
                    string name = entry.Key;
                    if (name == "Model") continue;
                        lst.Add(name);
                }
                tr.Commit();
            }
            return lst;
        }
        catch
        {
            return null;
        }
    }
}
Speaking English as a French Frog

Glenn R

  • Guest
Re: What's the most efficent way to get layout names
« Reply #8 on: October 21, 2009, 06:23:49 PM »
I don't think FileShare.None is correct; from memory this will block anybody from using the file...it's the opposite to what I always think it is ;)

Also gile, you're going for the NOD, whereas what I posted, bypasses that, but other than that, yes.

Viktor

  • Guest
Re: What's the most efficent way to get layout names
« Reply #9 on: October 21, 2009, 06:40:00 PM »
In the sample you provided you're getting the layouts of the current drawing if i'm not mistaken, I don't want to open drawings cause that would take another 20 minutes.

Yes I am, but it's a quick example. You will see that I'm getting the layouts from the DATABASE of the current document...it's still a databse, the same as you're constructing and using in ReadDwgFile.

Also, you're iterating the whole block table to find the layouts, which in dwgs of 2-5mb could be large, whereas I'm going straight to the layouts dictionary, similar to what gile posted above, which, all things being equal, should be faster.

Try it.

No doubt its faster the way you have it, will be using your approach there. But to eliminate the reading of the database I am changing the architecture of the app. Instead of reloading the list with filenames/layouts I instead load on demand when the user actually clicks on the file, then I get all the data from all the layouts and allow the user to shuffle between sheets at that point. So i'm moving the delay to a place where its less noticable.

Anyway, thanks everyone for their input.

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: What's the most efficent way to get layout names
« Reply #10 on: October 21, 2009, 06:44:14 PM »
Thanks for the corrections.

I didn't saw "db.LayoutDictionaryId" before (so many things to learn...)
Speaking English as a French Frog

Glenn R

  • Guest
Re: What's the most efficent way to get layout names
« Reply #11 on: October 21, 2009, 06:46:57 PM »
Viktor,

I was going to suggest a lazy loading approach, but try what I suggested first and then make the decision.

Gile,

You're wlecome.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: What's the most efficent way to get layout names
« Reply #12 on: October 21, 2009, 07:39:01 PM »
[.........?

I also signed up for the linq class at AU this year, i love linq for everything outside of autocad db, so it'd be interesting to see how i can use it in autocad db. Do you linq?

Who's teaching the class Viktor ??
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

csharpbird

  • Newt
  • Posts: 64
Re: What's the most efficent way to get layout names
« Reply #13 on: October 22, 2009, 09:03:39 AM »
[.........?

I also signed up for the linq class at AU this year, i love linq for everything outside of autocad db, so it'd be interesting to see how i can use it in autocad db. Do you linq?

Who's teaching the class Viktor ??
Albert Szilvasy
Using .NET 4.0 with AutoCADŽ
 
http://au.autodesk.com/?nd=e_class&session_id=5164


Viktor

  • Guest
Re: What's the most efficent way to get layout names
« Reply #14 on: October 22, 2009, 12:25:58 PM »
How many of you guys going to AU .net classes?

btw, who's using linq in autocad db so far?