1. I want to populate drawings with user-specified block(s) using a text file that contains 'to-be' coordinates and attributes on a per-line basis
**I have achieved this task - tested and working - thanks for all the help**
However, to be able to insert in the AutoCAD drafting "Wblock" fashion is proving a little tricky. But I'll only want help when I accept defeat.... if I've not expended my quota already.
2. Attached is a text file and, because I'm nice, a block as well.
3. I'm targeting AutoCAD 2008.
4 & 5 visual Studio C# Express 08 with 3.5 framework.
public class Commands
{
[CommandMethod("MultiBlocks")]
public void MultiBlocks()
{
OpenFileDialog coordsSelectDialog = new OpenFileDialog("Coodinate Selection", "", "txt",
"Select a Coordinate File", OpenFileDialog.OpenFileDialogFlags.NoUrls);
bool coordsSelected = false;//So we can loop until valid file selected or user cancels
while (!coordsSelected)
{
System.Windows.Forms.DialogResult coordsResult = coordsSelectDialog.ShowDialog();
if (coordsResult == System.Windows.Forms.DialogResult.Cancel)
return;
if (coordsResult != System.Windows.Forms.DialogResult.OK)
{
System.Windows.Forms.MessageBox.Show("Select Another File");
}
else
{
coordsSelected = true; //Loop will no longer execute & we have a valid file
}
}
using (TextReader coordsFile = new StreamReader(coordsSelectDialog.Filename))
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
string blockName = "";
bool isStringValid = false;//Enabling us to loop until string is valid or user cancels
while (!isStringValid)
{
PromptStringOptions psoBlockSelect = new PromptStringOptions("Enter The Name of The Block to 'Multi-Insert'");
PromptResult prBlockSelected = ed.GetString(psoBlockSelect);
if (prBlockSelected.Status == PromptStatus.Cancel)
return;
if (prBlockSelected.Status != PromptStatus.OK)
System.Windows.Forms.MessageBox.Show("Error With User Input - Try Again or Cancel");
else
{
isStringValid = true;
blockName = prBlockSelected.StringResult;
}
}
while (true)
try
{
string lineRead = coordsFile.ReadLine();
if (String.IsNullOrEmpty(lineRead))
break;
string[] lineSeparated = lineRead.Trim().Split(' ');
//Convert first two elements to double for our insertion point
Point3d insPoint = new Point3d(Double.Parse(lineSeparated[0]), Double.Parse(lineSeparated[1]), 0);
Database db = HostApplicationServices.WorkingDatabase;
using (Transaction trans = db.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead);
ObjectId blockId;
//Iterate the Block Table, searching for our Block
if (!bt.Has(blockName.ToString()))
{
System.Windows.Forms.MessageBox.Show("Specified Block Name Not Valid in This Document"
, "Input Error");
return;
}
blockId = bt[blockName.ToString()];//Essentially our "Block Definition"
BlockReference blockRef = new BlockReference(insPoint, blockId);
//Add to ModelSpace immediately to ensure successful attribute population
BlockTableRecord mSpace = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
mSpace.AppendEntity(blockRef);
trans.AddNewlyCreatedDBObject(blockRef, true);
if (lineSeparated.Count() > 2)//If true, we have attribute data
{
BlockTableRecord thisBlock = (BlockTableRecord)trans.GetObject(blockId, OpenMode.ForRead);
int counter = 2; //Element in "lineSeparated" where attribute information will begin - after coordinates
foreach (ObjectId obj in thisBlock)
{
Entity ent = (Entity)trans.GetObject(obj, OpenMode.ForRead);
if (ent is AttributeDefinition)
{
AttributeDefinition attDef = (AttributeDefinition)(ent);
AttributeReference attRef = new AttributeReference();
attRef.SetPropertiesFrom(ent);
attRef.TextString = lineSeparated[counter];
attRef.Position = new Point3d(blockRef.Position.X + attDef.Position.X,
blockRef.Position.Y + attDef.Position.Y,
0);
attRef.Tag = attDef.Tag;
attRef.Height = attDef.Height;
attRef.Rotation = attDef.Rotation;
//Add this attribute to the "Block Reference" & the transaction
blockRef.AttributeCollection.AppendAttribute(attRef);
trans.AddNewlyCreatedDBObject(attRef, true);
//Increment the counter so the next attribute will utilise the next array element
counter++;
}
}
}
//Complete by adding Block Referenc to transaction
trans.Commit();
}
}
catch
{
System.Windows.Forms.MessageBox.Show("Error - Application Terminated", "Error");
return;
}
}
}
There is the code.
I've got plans to make it more robust and to be able to use a "Wblock". But I need to get my head around "Database.Insert(), DeepClone(), Wblock()" etc.
Also I need to add some user information that specifies that attributes will be populated sequentially corresponding to their order in the AutoCAD "Block Attribute Manager".
Fun, fun...