TheSwamp

Code Red => .NET => Topic started by: mcarson on November 12, 2008, 05:21:47 AM

Title: Get BlockReferences by name
Post by: mcarson on November 12, 2008, 05:21:47 AM
Working on a coordinate export program to export the xyz coordinates of all block references with attributes to a csv file.
I thought everything was cool until I encountered a 'strange' occurance.

db = Acdb.HostApplicationServices.WorkingDatabase
tr = (db.TransactionManager.StartTransaction())
openMode = AcDb.OpenMode.ForRead

Code: [Select]
public static IEnumerable<AcDb.BlockReference> GetBlockReferencesByName(AcDb.Database db, AcDb.Transaction tr, AcDb.OpenMode openMode, string blockName)
{
    List<AcDb.BlockReference> brlist = new List<AcDb.BlockReference>();
    AcDb.BlockTable bt = (AcDb.BlockTable)tr.GetObject(db.BlockTableId, AcDb.OpenMode.ForRead);
    try {
        if (!bt.Has(blockName)) {
            throw new AcRx.Exception(AcRx.ErrorStatus.InvalidBlockName);
        }
        AcDb.BlockTableRecord btr = (AcDb.BlockTableRecord)tr.GetObject(bt.Item(blockName), AcDb.OpenMode.ForRead);
        foreach (AcDb.ObjectId oid in btr.GetBlockReferenceIds(true, false)) {
            AcDb.BlockReference br = (AcDb.BlockReference)tr.GetObject(oid, openMode);
            brlist.Add(br);
        }
        return brlist;
    }
    catch (AcRx.Exception ex) {
        AcAp.Application.ShowAlertDialog(ex.Message);
    }
    return brlist;
}

This code is supposed to return all blockreferences of a given name contained in the working database. Which it does!

For a test, copy a number of blocks from a drawing using copybase
Start a new drawing and pasteorig or something

The program, when executed on this new drawing picks up two blocktables, i think - the one in memory and the newly created objects. Odd.

I know I am missing some part of this? Any ideas?


Title: Re: Get BlockReferences by name
Post by: Glenn R on November 12, 2008, 05:25:41 AM
Huh?
Title: Re: Get BlockReferences by name
Post by: mcarson on November 12, 2008, 05:50:37 AM
Huh?

Sorry. Do you understand what I am talking about?

Upon further investigation, the block reference list returned contains block references where the BlockName is {"eWasErased"}. It is these I do not want.
I cannot look at the block name when it is erased...
Title: Re: Get BlockReferences by name
Post by: mcarson on November 12, 2008, 05:59:33 AM
Modified the code slightly...

Included a Try, Catch to attempt to get the blockname - horrible fix but seems to work

Is there a better way?

Code: [Select]
public static IEnumerable<AcDb.BlockReference> GetBlockReferencesByName(string blockName)
{
    List<AcDb.BlockReference> brlist = new List<AcDb.BlockReference>();
   
    AcDb.Database db = AcDb.HostApplicationServices.WorkingDatabase;
    AcDb.TransactionManager tm = db.TransactionManager;
    using (AcDb.Transaction tr = tm.StartTransaction) {
        AcDb.BlockTable bt = (AcDb.BlockTable)tr.GetObject(db.BlockTableId, AcDb.OpenMode.ForRead);
       
        try {
            if (!bt.Has(blockName)) {
                throw new AcRx.Exception(AcRx.ErrorStatus.InvalidBlockName);
            }
            AcDb.BlockTableRecord btr = (AcDb.BlockTableRecord)tr.GetObject(bt.Item(blockName), AcDb.OpenMode.ForRead);
            foreach (AcDb.ObjectId oid in btr.GetBlockReferenceIds(true, false)) {
                AcDb.BlockReference br = (AcDb.BlockReference)tr.GetObject(oid, AcDb.OpenMode.ForRead);
                try {
                    if (!br.BlockName.Contains("eWasErased")) {
                        brlist.Add(br);
                    }
                }
                catch (Exception ex) {
                    continue;
                }
            }
           
            return brlist;
        }
        catch (AcRx.Exception ex) {
            AcAp.Application.ShowAlertDialog(ex.Message);
        }
    }
    return brlist;
   
}
Title: Re: Get BlockReferences by name
Post by: Glenn R on November 12, 2008, 06:40:14 AM
I think you're getting confused because it looks like you've struck the 'default indexer' bug.

In a nutshell, if you do this on any SymbolTable, looking for a hit:

Code: [Select]
SymBolTable["SomeSymbolName"]

This can return an erased entry. If, for example, you return an 'erased' BlockTableRecord, any references that GetBlockReferenceIds returns, must also be erased as you can't delete a symboltable entry if there is anything referencing it...make sense?
Title: Re: Get BlockReferences by name
Post by: sinc on November 12, 2008, 08:15:34 AM
Look at:

http://www.caddzone.com/DBUtils.cs
Title: Re: Get BlockReferences by name
Post by: mcarson on November 29, 2008, 06:37:18 AM
Yeah, understand

This is going to be more work than I thought. Will post the solution after the weekend...
Title: Re: Get BlockReferences by name
Post by: sinc on November 29, 2008, 09:45:17 AM
This is going to be more work than I thought.

Oops, mixed up my posts - nevermind.
Title: Re: Get BlockReferences by name
Post by: TonyT on November 29, 2008, 04:44:17 PM
Unless I'm missing something, what your tool does can be
done by AutoCAD's Data Extraction.

Is there something about it that the latter can't handle?

Working on a coordinate export program to export the xyz coordinates of all block references with attributes to a csv file.
I thought everything was cool until I encountered a 'strange' occurance.

db = Acdb.HostApplicationServices.WorkingDatabase
tr = (db.TransactionManager.StartTransaction())
openMode = AcDb.OpenMode.ForRead

Code: [Select]
public static IEnumerable<AcDb.BlockReference> GetBlockReferencesByName(AcDb.Database db, AcDb.Transaction tr, AcDb.OpenMode openMode, string blockName)
{
    List<AcDb.BlockReference> brlist = new List<AcDb.BlockReference>();
    AcDb.BlockTable bt = (AcDb.BlockTable)tr.GetObject(db.BlockTableId, AcDb.OpenMode.ForRead);
    try {
        if (!bt.Has(blockName)) {
            throw new AcRx.Exception(AcRx.ErrorStatus.InvalidBlockName);
        }
        AcDb.BlockTableRecord btr = (AcDb.BlockTableRecord)tr.GetObject(bt.Item(blockName), AcDb.OpenMode.ForRead);
        foreach (AcDb.ObjectId oid in btr.GetBlockReferenceIds(true, false)) {
            AcDb.BlockReference br = (AcDb.BlockReference)tr.GetObject(oid, openMode);
            brlist.Add(br);
        }
        return brlist;
    }
    catch (AcRx.Exception ex) {
        AcAp.Application.ShowAlertDialog(ex.Message);
    }
    return brlist;
}

This code is supposed to return all blockreferences of a given name contained in the working database. Which it does!

For a test, copy a number of blocks from a drawing using copybase
Start a new drawing and pasteorig or something

The program, when executed on this new drawing picks up two blocktables, i think - the one in memory and the newly created objects. Odd.

I know I am missing some part of this? Any ideas?



Title: Re: Get BlockReferences by name
Post by: mcarson on December 03, 2008, 02:52:00 PM
A note on one of the other threads pointed out that the data extraction tool was more powerful now - which it is - and great!
I just have to figure out how to access this through the API to find out if all my work is in vain...
Title: Re: Get BlockReferences by name
Post by: TonyT on December 05, 2008, 05:47:26 AM
A note on one of the other threads pointed out that the data extraction tool was more powerful now - which it is - and great!
I just have to figure out how to access this through the API to find out if all my work is in vain...

There's a post on Through The Interface that shows how to
control Data Extraction from a .NET application.