This is actually a redo of last week’s post, just with a different title: while the approach shown worked well when creating external references to drawings using the same units, when bringing in (for instance) metric xrefs into an imperial master drawing the scale was all messed up. Thanks to Hans Lammerts for reporting the issue.
The scaling ended up being straightforward to implement: the hard work was done by UnitsConverter.GetConversionFactor(), which established the scale factor to use, converting between the Units property of the new block table record and the Insunits property of the target database. Then it was a simple matter of scaling the block reference by this amount.
So yes, last week’s simple solution proved to be overly so, in the end. Here’s a version of the code with a small amount of complexity added, but for a very good reason.
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using System;
using System.IO;
namespace XrefAttachAtZero
{
public static class Extensions
{
/// <summary>
/// Attaches the specified Xref to the current space in the current drawing.
/// </summary>
/// <param name="path">Path to the drawing file to attach as an Xref.</param>
/// <param name="pos">Position of Xref in WCS coordinates.</param>
/// <param name="name">Optional name for the Xref.</param>
/// <returns>Whether the attach operation succeeded.</returns>
public static bool XrefAttachAndInsert(
this Database db, string path, Point3d pos, string name = null
)
{
var ret = false;
if (!File.Exists(path))
return ret;
if (String.IsNullOrEmpty(name))
name = Path.GetFileNameWithoutExtension(path);
try
{
using (var tr = db.TransactionManager.StartOpenCloseTransaction())
{
// Attach the Xref - add it to the database's block table
var xId = db.AttachXref(path, name);
if (xId.IsValid)
{
// Open the newly created block, so we can get its units
var xbtr = (BlockTableRecord)tr.GetObject(xId, OpenMode.ForRead);
// Determine the unit conversion between the xref and the target
// database
var sf = UnitsConverter.GetConversionFactor(xbtr.Units, db.Insunits);
// Create the block reference and scale it accordingly
var br = new BlockReference(pos, xId);
br.ScaleFactors = new Scale3d(sf);
// Add the block reference to the current space and the transaction
var btr =
(BlockTableRecord)tr.GetObject(
db.CurrentSpaceId, OpenMode.ForWrite
);
btr.AppendEntity(br);
tr.AddNewlyCreatedDBObject(br, true);
ret = true;
}
tr.Commit();
}
}
catch (Autodesk.AutoCAD.Runtime.Exception)
{ }
return ret;
}
}
public class Commands
{
[CommandMethod("XAO")]
public void XrefAttachAtOrigin()
{
var doc = Application.DocumentManager.MdiActiveDocument;
if (doc == null)
return;
var db = doc.Database;
var ed = doc.Editor;
// Ask the user to specify a file to attach
var opts = new PromptOpenFileOptions("Select Reference File");
opts.Filter = "Drawing (*.dwg)|*.dwg";
var pr = ed.GetFileNameForOpen(opts);
if (pr.Status == PromptStatus.OK)
{
// Attach the specified file and insert it at the origin
var res = db.XrefAttachAndInsert(pr.StringResult, Point3d.Origin);
ed.WriteMessage(
"External reference {0}attached at the origin.",
res ? "" : "not "
);
}
}
}
}
Here’s the XAO command in action again.
This time I created two drawings: the one on the left uses the imperial acad.dwt template, the one on the right uses the metric acadiso.dwt. I created a CIRCLE with a radius of 5 at 10,10,0 in each drawing. I then saved the right-hand (metric) drawing to disk and the video shows using the XAO command to attach it into the left-hand drawing. You can see that the drawing is attached at the appropriate scale, making the content 25.4 times smaller.