TheSwamp
Code Red => .NET => Topic started 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
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?
-
Huh?
-
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...
-
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?
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;
}
-
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:
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?
-
Look at:
http://www.caddzone.com/DBUtils.cs
-
Yeah, understand
This is going to be more work than I thought. Will post the solution after the weekend...
-
This is going to be more work than I thought.
Oops, mixed up my posts - nevermind.
-
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
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?
-
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...
-
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.