Author Topic: Get BlockReferences by name  (Read 4816 times)

0 Members and 1 Guest are viewing this topic.

mcarson

  • Guest
Get BlockReferences by name
« 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?



Glenn R

  • Guest
Re: Get BlockReferences by name
« Reply #1 on: November 12, 2008, 05:25:41 AM »
Huh?

mcarson

  • Guest
Re: Get BlockReferences by name
« Reply #2 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...
« Last Edit: November 12, 2008, 05:55:49 AM by mcarson »

mcarson

  • Guest
Re: Get BlockReferences by name
« Reply #3 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;
   
}

Glenn R

  • Guest
Re: Get BlockReferences by name
« Reply #4 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?

sinc

  • Guest
Re: Get BlockReferences by name
« Reply #5 on: November 12, 2008, 08:15:34 AM »

mcarson

  • Guest
Re: Get BlockReferences by name
« Reply #6 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...

sinc

  • Guest
Re: Get BlockReferences by name
« Reply #7 on: November 29, 2008, 09:45:17 AM »
This is going to be more work than I thought.

Oops, mixed up my posts - nevermind.

TonyT

  • Guest
Re: Get BlockReferences by name
« Reply #8 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?




mcarson

  • Guest
Re: Get BlockReferences by name
« Reply #9 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...

TonyT

  • Guest
Re: Get BlockReferences by name
« Reply #10 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.