Author Topic: SymbolTable.Has & erased objects  (Read 2745 times)

0 Members and 1 Guest are viewing this topic.

Andrey Bushman

  • Swamp Rat
  • Posts: 864
SymbolTable.Has & erased objects
« on: October 07, 2011, 04:08:56 AM »
Class SymbolTable has method "Has", which check to exists not erased records only. I want manage it: I write additional method. My code:
Code: [Select]
/// <include file='./SymbolTableExtensionMethods.xml' path='Documentation/Item[@Name="SymbolTableExtensionMethods"]/Methods/Method[@Name="Has_1"]/*'/>
public static bool Has(this SymbolTable table, string name, bool checkErased) {
    bool result = false;
    using (Transaction t = table.Database.TransactionManager.StartTransaction()) {
        foreach (ObjectId id in table) {
            if ((checkErased && id.IsErased) || !id.IsErased) {
                SymbolTableRecord tr = t.GetObject<SymbolTableRecord>(id, OpenMode.ForRead, true);
                result = tr.Name.Equals(name, StringComparison.CurrentCultureIgnoreCase);
            }
            if (result)
                break;
        }
    }
    return result;
}

My test code:

Code: [Select]
        [CommandMethod("hasTest", CommandFlags.Modal)]
        public void hasTest() {
            Document dwg = acad.DocumentManager.MdiActiveDocument;
            Editor ed = dwg.Editor;
            Database db = dwg.Database;

            //names of new layers
            string name1 = "Layer1";
            string name2 = "Layer2";

            //add new layers
            using (Transaction t = db.TransactionManager.StartTransaction()) {
                LayerTable lt = (LayerTable) t.GetObject(db.LayerTableId, OpenMode.ForWrite);
                LayerTableRecord ltr = new LayerTableRecord() { Name = name1 };
                lt.Add(ltr);
                LayerTableRecord ltr2 = new LayerTableRecord() { Name = name2 };
                lt.Add(ltr2);
                t.AddNewlyCreatedDBObject(ltr, true);
                t.AddNewlyCreatedDBObject(ltr2, true);
                t.Commit();
            }


            //delete one layer
            using (Transaction t = db.TransactionManager.StartTransaction()) {
                LayerTable lt = (LayerTable) t.GetObject(db.LayerTableId, OpenMode.ForWrite);
                LayerTableRecord ltr = (LayerTableRecord) t.GetObject(lt[name1], OpenMode.ForWrite);
                LayerTableRecord ltr2 = (LayerTableRecord) t.GetObject(lt[name2], OpenMode.ForWrite);
                ltr.Erase(true);
                t.Commit();
                bool param = false;
                //search Layer1 by name
                ed.WriteMessage("Search {0} by name, with parameter '{1}'. Result: {2}\n", name1, param, lt.Has(name1, param) ? "It is found" : "It is not found");
                param = !param;
                ed.WriteMessage("Search {0} by name, with parameter '{1}'. Result: {2}\n", name1, param, lt.Has(name1, param) ? "It is found" : "It is not found");
                param = false;
                //search Layer2 by name
                ed.WriteMessage("Search {0} by name, with parameter '{1}'. Result: {2}\n", name2, param, lt.Has(name2, param) ? "It is found" : "It is not found");
                param = !param;
                ed.WriteMessage("Search {0} by name, with parameter '{1}'. Result: {2}\n", name2, param, lt.Has(name2, param) ? "It is found" : "It is not found");
            }           
        }

but the erased objects don't get in "foreach" (not erased only). Test result:
Quote
Command: hasTest
Search Layer1 by name, with parameter 'False'. Result: It is not found
Search Layer1 by name, with parameter 'True'. Result: It is not found
Search Layer2 by name, with parameter 'False'. Result: It is found
Search Layer2 by name, with parameter 'True'. Result: It is found

How can I get erased records from SymbolTable?
« Last Edit: October 07, 2011, 04:44:22 AM by Andrey »

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: SymbolTable.Has & erased objects
« Reply #1 on: October 07, 2011, 04:49:56 AM »
I rewrite my method. It works:
Code: [Select]
        /// <include file='./SymbolTableExtensionMethods.xml' path='Documentation/Item[@Name="SymbolTableExtensionMethods"]/Methods/Method[@Name="Has_1"]/*'/>
        public static bool Has(this SymbolTable table, string name, bool checkErased) {
            bool result = false;
            Database db = table.Database;
            List<SymbolTableRecord> records = new List<SymbolTableRecord>();

            using (Transaction t = db.TransactionManager.StartTransaction()) {
                for (long i = db.BlockTableId.Handle.Value; i < db.Handseed.Value; i++) {
                    ObjectId id = ObjectId.Null;
                    Handle h = new Handle(i);
                    if (db.TryGetObjectId(h, out id) && id.IsValid && id.ObjectClass.Name.EndsWith("TableRecord")) {
                        SymbolTableRecord tr = (SymbolTableRecord) t.GetObject(id, OpenMode.ForRead, true);
                        if (tr.OwnerId == table.ObjectId)
                            records.Add(tr);
                    }
                }
                foreach (SymbolTableRecord tr in records) {
                    if ((checkErased && tr.IsErased) || !tr.IsErased) {
                        result = tr.Name.Equals(name, StringComparison.CurrentCultureIgnoreCase);
                    }
                    if (result)
                        break;
                }
            }
            return result;
        }

Test Result:
Quote
Command: hasTest
Search Layer1 by name, with parameter 'False'. Result: It is not found
Search Layer1 by name, with parameter 'True'. Result: It is found
Search Layer2 by name, with parameter 'False'. Result: It is found
Search Layer2 by name, with parameter 'True'. Result: It is found

kaefer

  • Guest
Re: SymbolTable.Has & erased objects
« Reply #2 on: October 07, 2011, 05:01:58 AM »
I rewrite my method. It works:

Ouch. Do you remember Tony T's DBUtils.cs*?

Wouldn't this be a tad more elegant...
Code: [Select]
    static class Extensions
    {
        [System.Security.SuppressUnmanagedCodeSecurity]
        [DllImport( "acdb18.dll", CallingConvention = CallingConvention.ThisCall, CharSet = CharSet.Unicode,
            EntryPoint = "?getAt@AcDbSymbolTable@@QEBA?AW4ErrorStatus@Acad@@PEB_WAEAVAcDbObjectId@@_N@Z")]
        public static extern ErrorStatus getAt( IntPtr symbolTable, string name, out ObjectId id, bool getErased );
       
        public static ObjectId GetSymbolTableRecordId( SymbolTable table, string name, bool getErased )
        {
            ObjectId id = ObjectId.Null;
            ErrorStatus es = getAt(table.UnmanagedObject, name, out id, getErased);
            return id;
        }
        public static bool Has(this SymbolTable table, string name, bool checkErased)
        {
            ObjectId oid = GetSymbolTableRecordId(table, name, checkErased);
            return !oid.IsNull;
        }
    }

* Many thanks to Алексей Кулик for Tony's code and to le for the link.

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: SymbolTable.Has & erased objects
« Reply #3 on: October 07, 2011, 05:18:00 AM »
2 kaefer

Your code is anchored to the AutoCAD version. My full solution:

Code: [Select]
    /// <include file='./SymbolTableExtensionMethods.xml' path='Documentation/Item[@Name="SymbolTableExtensionMethods"]/Common/*'/>
    public static class SymbolTableExtensionMethods {

        /// <include file='./SymbolTableExtensionMethods.xml' path='Documentation/Item[@Name="SymbolTableExtensionMethods"]/Methods/Method[@Name="Has_1"]/*'/>
        public static bool Has(this SymbolTable table, string name, out ObjectId objId, bool checkErased) {
            return Has(table, out objId, checkErased, tr => tr.Name.Equals(name, StringComparison.CurrentCultureIgnoreCase));
        }

        /// <include file='./SymbolTableExtensionMethods.xml' path='Documentation/Item[@Name="SymbolTableExtensionMethods"]/Methods/Method[@Name="Has_2"]/*'/>
        public static bool Has(this SymbolTable table, ObjectId objId, bool checkErased) {
            ObjectId id = ObjectId.Null;
            return Has(table, out id, checkErased, tr => tr.ObjectId == objId);
        }

        /// <include file='./SymbolTableExtensionMethods.xml' path='Documentation/Item[@Name="SymbolTableExtensionMethods"]/Methods/Method[@Name="Has_3"]/*'/>
        public static bool Has(this SymbolTable table, out ObjectId objId, bool checkErased, Func<SymbolTableRecord, bool> func) {
            bool result = false;
            ObjectId _id = ObjectId.Null;
            using (Transaction t = table.Database.TransactionManager.StartTransaction()) {               
                SymbolTableRecord tr = null;
                SymbolTable st = (SymbolTable) t.GetObject(table.ObjectId, OpenMode.ForRead);
                st = st.IncludingErased;
                foreach (ObjectId id in st) {
                    if ((checkErased && id.IsErased) || !id.IsErased) {
                        tr = (SymbolTableRecord) t.GetObject(id, OpenMode.ForRead, true);
                        result = func(tr);
                    }
                    if (result) {
                        _id = tr.ObjectId;
                        break;
                    }
                }
            }           
            objId = _id;
            return result;
        }
    }

There is no necessity to cause the unmanaged code. My code doesn't depend on version AutoCAD. I have allocated fuller example here.
« Last Edit: October 07, 2011, 10:22:20 AM by Andrey »

Chumplybum

  • Newt
  • Posts: 97
Re: SymbolTable.Has & erased objects
« Reply #4 on: October 09, 2011, 08:41:47 PM »
i think from version A2010 and onwards, theres an 'IncludingErased' property under the symboltable class... this may help out?


cheers, Mark

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: SymbolTable.Has & erased objects
« Reply #5 on: October 10, 2011, 12:29:00 AM »
i think from version A2010 and onwards, theres an 'IncludingErased' property under the symboltable class... this may help out?


cheers, Mark

Look more attentively - I use it in the code. :)