class BlkRef
{
public Point3d Insert { get; set; }
public Scale3d Scale { get; set; }
public ObjectId layerID { get; set; }
public Dictionary<string, string> Attributes { get; set; }
public BlockTableRecord Space { get; set; }
}
[CommandMethod("SWAPBLOCKS", CommandFlags.Session)]
public void SwapBlocks()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database db = doc.Database;
//get config data
OpenFileDialog ofd
= new OpenFileDialog
( "Select Config File",
Directory.GetParent(db.Filename).ToString(),
"xlsx;xls",
"ConfigFile",
OpenFileDialog.OpenFileDialogFlags.SearchPath
);
System.Windows.Forms.DialogResult dr = ofd.ShowDialog();
if (dr != System.Windows.Forms.DialogResult.OK)
return;
string[] configFile = ofd.GetFilenames();
object[,] configData = ExcelFunctions.ExtractSheetData(configFile[0], 1);
using (Database srcdb
= new Database
(false,
false)) {
BlockTable srcbt;
BlockTableRecord srcbtr;
try
{
List
<object> srcData
= new List
<object>(); string sourcePath = configData[1, 1].ToString();
//if original source block dwg doesnt exist, get a dwg which contains it
if (!File.Exists(sourcePath))
{
ed.WriteMessage("\n{0} does not exist!", configData[1, 1]);
srcData = GetBlockReference("Replacement");
sourcePath = srcData[0].ToString();
}
//get dwg with source block table record to clone into destination databases
while (true) //here we make sure we have the source block defined in the mapping file
{
//we skip this section if the config data pointed to an existing file
if (srcData.Count != 0)
{
sourcePath = srcData[0].ToString();
if (sourcePath == "fail") //if GetBlockReference failed operation failed
{
ed.WriteMessage("\nFailed to get a replacement block");
return;
}
if (srcData[1].ToString() != configData[2, 1].ToString()) //check we have the same block the mapping is set up for
{
ed.WriteMessage("\nBlock ({0}) does not match replacement from config file ({1})", srcData[1], configData[2, 1]);
srcData = GetBlockReference("Replacement");
continue;
}
}
using (DocumentLock locking = doc.LockDocument())
{
srcdb.ReadDwgFile(sourcePath, FileOpenMode.OpenForReadAndAllShare, true, "");
srcdb.CloseInput(true);
using (Transaction tr = srcdb.TransactionManager.StartTransaction())
{
srcbt = (BlockTable)tr.GetObject(srcdb.BlockTableId, OpenMode.ForRead);
if (srcbt.Has(configData[2, 1].ToString())) //check dwg has source block
{
srcbtr = (BlockTableRecord)tr.GetObject(srcbt[configData[2, 1].ToString()], OpenMode.ForRead);
break; //if so break from this while loop
}
tr.Commit();
}
if (!srcbt.Has(configData[2, 1].ToString()))
{
ed.WriteMessage("\n{0} does not have {1} block", sourcePath, configData[2, 1]);
srcData = GetBlockReference("Replacement");
}
}
}
}
catch (System.Exception)
{
throw;
}
// build dictionary to map attributes
Dictionary
<string,
string> AttMap
= new Dictionary
<string,
string>(); for (int i = 4; i <= configData.GetUpperBound(0); i++)
{
if ((configData[i, 1] != null) && (configData[i, 2] != null))
{
AttMap.Add((string)configData[i, 1], (string)configData[i, 2]);
ed.WriteMessage("\n{0},{1}", configData[i, 2], (string)configData[i, 1]);
}
}
//get drawings to process
ofd =
"Select DWGs to change block",
null,
"dwg",
"DWGsToChange",
OpenFileDialog.OpenFileDialogFlags.AllowMultiple
);
dr = ofd.ShowDialog();
if (dr != System.Windows.Forms.DialogResult.OK)
{
srcdb.Dispose();
return;
}
string[] names = ofd.GetFilenames();
//calculate scale difference from config data
Scale3d
[] scales
= new Scale3d
[2]; for (int i = 1; i <= 2; i++)
{
string curscale = (string)configData[3, i];
curscale = curscale.Replace("(", "").Replace(")", "");
string[] scalevals = curscale.Split(',');
ed.WriteMessage("\n{0},{1},{2}", scalevals[0], scalevals[1], scalevals[2]);
double scaX = Convert.ToDouble(scalevals[0]);
double scaY = Convert.ToDouble(scalevals[1]);
double scaZ = Convert.ToDouble(scalevals[2]);
scales
[i
- 1] = new Scale3d
(scaX, scaY, scaZ
); }
//replace block in each drawing
foreach (string name in names)
{
try
{
Database destdb
= new Database
(false,
true); destdb.ReadDwgFile(name, FileOpenMode.OpenForReadAndAllShare, false, "");
destdb.CloseInput(true);
HostApplicationServices.WorkingDatabase = destdb;
DocumentLock doclock = doc.LockDocument();
//get old blocks in this drawing
List
<BlkRef
> BlocksInDwg
= new List
<BlkRef
>(); using (Transaction tr = destdb.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)tr.GetObject(destdb.BlockTableId, OpenMode.ForWrite);
if (!bt.Has((string)configData[2, 2]))//dont waste time if dwg doesn't have the block
{
ed.WriteMessage("Block: {0} was not found processing {1}", (string)configData[2, 2], destdb.Filename);
continue;
}
//check each container in the database for old block
foreach (ObjectId id in bt)
{
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForWrite);
IEnumerable<BlockReference> blocks = AcDbExtensions.GetObjects<BlockReference>(btr, OpenMode.ForWrite, false, true).Where(BlockReference => BlockReference.Name == configData[2, 2].ToString());
foreach (BlockReference block in blocks)//extract block data to our list before erasing old blocks
{
BlkRef ThisBlock
= new BlkRef
(); ThisBlock.Insert = block.Position;
//calculate scale for new block
Scale3d scale
= new Scale3d
( block.ScaleFactors.X * scales[1].X / scales[0].X,
block.ScaleFactors.Y * scales[1].Y / scales[0].Y,
block.ScaleFactors.Z * scales[1].Z / scales[0].Z
);
ThisBlock.Scale = scale;
ThisBlock.layerID = block.LayerId;
Dictionary
<string,
string> Attributes
= new Dictionary
<string,
string>(); foreach (ObjectId arID in block.AttributeCollection)
{
AttributeReference ar = (AttributeReference)tr.GetObject(arID, OpenMode.ForWrite);
Attributes.Add(ar.Tag, ar.TextString);
ar.Erase();
}
ThisBlock.Attributes = Attributes;
ThisBlock.Space = btr;
block.Erase();
BlocksInDwg.Add(ThisBlock);
}
}
//erase old block def
BlockTableRecord destbtr = (BlockTableRecord)tr.GetObject(bt[(string)configData[2, 2]], OpenMode.ForWrite);
destbtr.Erase();
//clone new block def
ObjectIdCollection ids
= new ObjectIdCollection
(); ids.Add(srcbtr.ObjectId);
IdMapping mapping
= new IdMapping
(); srcdb.WblockCloneObjects(ids, destdb.BlockTableId, mapping, DuplicateRecordCloning.Replace, false);
BlockTableRecord newbtr = (BlockTableRecord)tr.GetObject(bt[(string)configData[2, 1]], OpenMode.ForRead);
ObjectId StartLayer = destdb.Clayer;
//insert new blocks from list
foreach (BlkRef blk in BlocksInDwg)
{
destdb.Clayer = blk.layerID;
BlockReference br
= new BlockReference
(blk
.Insert, newbtr
.ObjectId); BlockTableRecord btr = (BlockTableRecord)tr.GetObject(blk.Space.ObjectId, OpenMode.ForWrite);
btr.AppendEntity(br);
tr.AddNewlyCreatedDBObject(br, true);
br.ScaleFactors = blk.Scale;
IEnumerable<AttributeDefinition> attributes = AcDbExtensions.GetObjects<AttributeDefinition>(newbtr);
foreach (AttributeDefinition ad in attributes)
{
if (ad == null || ad.Constant) continue;
AttributeReference ar
= new AttributeReference
(); ar.SetDatabaseDefaults(destdb);
ar.SetAttributeFromBlock(ad, br.BlockTransform);
ar.Position = ad.Position.TransformBy(br.BlockTransform);
if (AttMap.ContainsKey(ad.Tag))
{
ar.TextString = blk.Attributes[AttMap[ad.Tag]];
ed.WriteMessage("{0},{1}", AttMap[ad.Tag], blk.Attributes[AttMap[ad.Tag]]);
}
else
ar.TextString = "";
br.AttributeCollection.AppendAttribute(ar);
tr.AddNewlyCreatedDBObject(ar, true);
try
{
ar.AlignmentPoint = ad.AlignmentPoint.TransformBy(br.BlockTransform);
}
catch
{
ed.WriteMessage("\n{0},{1},{2}", ar.Tag, ar.Justify, ar.TextString);
}
if (ar.IsMTextAttribute)
{
ar.UpdateMTextAttribute();
}
}
}
destdb.Clayer = StartLayer;
tr.Commit();
}
doclock.Dispose();
HostApplicationServices.WorkingDatabase = db;
destdb.SaveAs(name.Substring(0, name.Length - 4) + "_updated.dwg", DwgVersion.Current);
destdb.Dispose();
}
catch (System.Exception e)
{
System.Windows.MessageBox.Show(e.ToString(), "Error");
throw;
}
}
//HostApplicationServices.WorkingDatabase = db;
}
}
public List<object> GetBlockReference(string mode)
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
PromptEntityOptions peo
= new PromptEntityOptions
("\nSelect " + mode
+ " Block To Export or"); peo.AppendKeywordsToMessage = true;
peo.Keywords.Add("Open");
peo.Keywords.Add("Toggle");
peo.SetRejectMessage("\nNot a block reference!!!\n");
peo
.AddAllowedClass(typeof(BlockReference
),
false);
PromptEntityResult per = ed.GetEntity(peo);
if (per.StringResult == "Open")
{
OpenFileDialog ofd
= new OpenFileDialog
( "Select DWG",
Directory.GetParent(db.Filename).ToString(),
"dwg",
"DWG with block",
OpenFileDialog.OpenFileDialogFlags.SearchPath
);
System.Windows.Forms.DialogResult dr = ofd.ShowDialog();
if (dr == System.Windows.Forms.DialogResult.Cancel)
{
return GetBlockReference(mode);
}
else if (dr != System.Windows.Forms.DialogResult.OK)
{
List
<object> badresults
= new List
<object>(); badresults.Add("fail");
return badresults;
}
string[] names = ofd.GetFilenames();
Document newFile = Application.DocumentManager.Open(names[0], true, "");
List<object> results = GetBlockReference(mode);
newFile.CloseAndDiscard();
return results;
}
else if (per.StringResult == "Toggle")
{
ToggleSpace();
List<object> results = GetBlockReference(mode);
return results;
}
else
{
List
<object> results
=new List
<object>();
if (per.Status != PromptStatus.OK)
{
results.Add("fail");
return results;
}
using (Transaction tr = doc.TransactionManager.StartTransaction())
{
BlockReference br = (BlockReference)tr.GetObject(per.ObjectId, OpenMode.ForRead);
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(br.BlockTableRecord, OpenMode.ForRead);
results.Add(db.Filename);
results.Add(br.Name);
Scale3d scale
= new Scale3d
( (br.GeometricExtents.MaxPoint.X-br.GeometricExtents.MinPoint.X)/br.ScaleFactors.X,
(br.GeometricExtents.MaxPoint.Y-br.GeometricExtents.MinPoint.Y)/br.ScaleFactors.Y,
(br.GeometricExtents.MaxPoint.Z-br.GeometricExtents.MinPoint.Z)/br.ScaleFactors.Z
);
results.Add(scale);
foreach (ObjectId id in br.AttributeCollection)
{
AttributeReference ar = (AttributeReference)tr.GetObject(id, OpenMode.ForRead);
results.Add(ar.Tag);
}
}
return results;
}
}
public static void ToggleSpace()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
short tilemode = (short)Application.GetSystemVariable("TILEMODE");
using (DocumentLock docLock = doc.LockDocument())
{
if (tilemode == 1)
Application.SetSystemVariable("TILEMODE", 0);
else if ((short)Application.GetSystemVariable("CVPORT") != 1)
ed.SwitchToPaperSpace();
else
{
Application.SetSystemVariable("TILEMODE", 1);
}
}
}