It's a shame that after so many years, AutoCAD still doesn't have the option to force a drawing's unit of length definition.
And also that the metric system is a stepchild.
My C# code to Get/Set DwgUnits:
using System;
using System.IO;
// ReSharper disable RedundantUsingDirective
#if BRX_APP
// base on https://www.bricsys.com/bricscad/help/en_US/V16/DevRef/
// see change: https://developer.bricsys.com/bricscad/help/en_US/V22/DevRef/
using _AcAp = Bricscad.ApplicationServices;
using _AcApCore = Bricscad.ApplicationServices;
using _AcBr = Teigha.BoundaryRepresentation;
using _AcCm = Teigha.Colors;
using _AcDb = Teigha.DatabaseServices;
using _AcEd = Bricscad.EditorInput;
using _AcGe = Teigha.Geometry;
using _AcGi = Teigha.GraphicsInterface;
using _AcGs = Teigha.GraphicsSystem;
using _AcPl = Bricscad.PlottingServices;
using _AcBrx = Bricscad.Runtime;
using _AcTrx = Teigha.Runtime;
using _AcWnd = Bricscad.Windows;
#elif ZRX_APP
// base on ZWCAD_2017_SP2_ZRXSDK:DOTNET_Migration_Manual.chm
using _AcAp = ZwSoft.ZwCAD.ApplicationServices;
using _AcApCore = ZwSoft.ZwCAD.ApplicationServices;
//using _AcBr = ZwSoft.ZwCAD.BoundaryRepresentation;
using _AcCm = ZwSoft.ZwCAD.Colors;
using _AcDb = ZwSoft.ZwCAD.DatabaseServices;
using _AcEd = ZwSoft.ZwCAD.EditorInput;
using _AcGe = ZwSoft.ZwCAD.Geometry;
using _AcGi = ZwSoft.ZwCAD.GraphicsInterface;
using _AcGs = ZwSoft.ZwCAD.GraphicsSystem;
using _AcPl = ZwSoft.ZwCAD.PlottingServices;
using _AcBrx = ZwSoft.ZwCAD.Runtime;
using _AcTrx = ZwSoft.ZwCAD.Runtime; // AcRx
using _AcWnd = ZwSoft.ZwCAD.Windows; // AcWd
#elif ARX_APP
using _AcAp = Autodesk.AutoCAD.ApplicationServices;
#if UpToAC1024
using _AcApCore = Autodesk.AutoCAD.ApplicationServices;
#else
using _AcApCore = Autodesk.AutoCAD.ApplicationServices.Core;
#endif
//using _AcBr = Autodesk.AutoCAD.BoundaryRepresentation;
using _AcCm = Autodesk.AutoCAD.Colors;
using _AcDb = Autodesk.AutoCAD.DatabaseServices;
using _AcEd = Autodesk.AutoCAD.EditorInput;
using _AcGe = Autodesk.AutoCAD.Geometry;
using _AcGi = Autodesk.AutoCAD.GraphicsInterface;
using _AcGs = Autodesk.AutoCAD.GraphicsSystem;
using _AcPl = Autodesk.AutoCAD.PlottingServices;
//using _AcBrx = Autodesk.AutoCAD.Runtime;
using _AcTrx = Autodesk.AutoCAD.Runtime; // AcRx
using _AcWnd = Autodesk.AutoCAD.Windows; // AcWd
using _AcLm = Autodesk.AutoCAD.LayerManager;
using _AcTp = Autodesk.AutoCAD.Windows.ToolPalette;
#endif
// ReSharper restore RedundantUsingDirective
namespace Datamap.Drawing {
public class DmUnits {
public static int DwgUnits { get; set; } = -1;
/*
* If INSUNITS is not correctly set in both source and target drawings, you should set the INSUNUTSDEFSOURCE and/or the INSUNITSDEFTARGET system variables.
INSUNITS
Specifies a drawing-units value for automatic scaling of blocks, images, or xrefs when inserted or attached to a drawing.
Type: Integer
Saved in: Drawing
Initial value: 1 (imperial) or 4 (metric)
Note: The INSUNITS setting is ignored when inserting annotative blocks into a drawing.
Value Description
0 Unspecified (No units)
1 Inches
2 Feet
3 Miles
4 Millimeters
5 Centimeters
6 Meters
7 Kilometers
8 Microinches
9 Mils
10 Yards
11 Angstroms
12 Nanometers
13 Microns
14 Decimeters
15 Dekameters
16 Hectometers
17 Gigameters
18 Astronomical Units
19 Light Years
20 Parsecs
21 US Survey Feet
Note: US Survey Feet is a historical survey unit that's about 2 parts per million larger than the International Feet unit. This difference is significant only at scales used for mapping in the U.S. The US Survey Feet setting is supported only for inserting or attaching drawings starting with AutoCAD 2017-based products. Drawings opened in prior versions will treat the US Survey Feet setting as Unitless.
INSUNITSDEFSOURCE (System Variable)
Sets source content units value when INSUNITS is set to 0.
Type: Integer
Saved in: Registry
Initial value: 1
Valid range is 0 to 20.
INSUNITSDEFTARGET (System Variable)
Sets target drawing units value when INSUNITS is set to 0.
Type: Integer
Saved in: Registry
Initial value: 1
Valid range is 0 to 20.
*/
public static int GetDwgUnits() {
var doc = _AcApCore.Application.DocumentManager.MdiActiveDocument;
var ed = doc.Editor;
var dwgUnits = -1;
/*
Base on : https://forums.autodesk.com/t5/net/programatically-setting-dwgunits/td-p/8652599
*/
var oldCmdEcho = (short)_AcApCore.Application.GetSystemVariable( "CMDECHO" );
var oldLogFileMode = (short)_AcApCore.Application.GetSystemVariable( "LOGFILEMODE" );
var logFileName = _AcApCore.Application.GetSystemVariable( "LOGFILENAME" ).ToString();
_AcApCore.Application.SetSystemVariable( "LOGFILEMODE", 0 );
if( File.Exists( logFileName ) ) {
File.Delete( logFileName );
}
_AcApCore.Application.SetSystemVariable( "LOGFILEMODE", 1 );
_AcApCore.Application.SetSystemVariable( "CMDECHO", 1 );
ed.Command( "_-DWGUNITS"
, "" // units for length
, "" // Linear display format
, "" // Linear display precision
, "" // Scale objects from other drawings upon insert? [Yes/No]
, "" // Match INSUNITS to drawing units? [Yes/No]
);
ed.Command( "GRAPHSCR" );
_AcApCore.Application.SetSystemVariable( "CMDECHO", 0 );
_AcApCore.Application.SetSystemVariable( "LOGFILEMODE", 0 );
// read current dwgunits "number" from a log file
try {
using( var sr = new StreamReader( logFileName ) ) {
/**********************************************************************
Command: -DWGUNITS
Loading AEC Base...
Loading AEC Base Extended...
Loading AEC Core...
Drawing units:
1. Inches
2. Feet
3. Millimeters
4. Centimeters
5. Decimeters
6. Meters
Unit for length <3>:
Drawing unit display formats:
1. Scientific
2. Decimal
Linear display format <2>:
Linear display precision <4>:
Scale objects from other drawings upon insert? [Yes/No] <Yes>:
Match INSUNITS to drawing units? [Yes/No] <Yes>:
*******************************************************************/
string line;
while( (line = sr.ReadLine()) != null ) {
if( line.Contains( "Unit for length" ) ) {
var start = line.IndexOf( "<", StringComparison.InvariantCultureIgnoreCase ) + 1;
var end = line.IndexOf( ">", StringComparison.InvariantCultureIgnoreCase );
if( start > 0 && end > start ) {
var dwgUnts = line.Substring( start, end - start );
if( int.TryParse( dwgUnts, out var units ) ) {
dwgUnits = units;
break;
}
ed.WriteMessage( "\nCould not parse drawing units." );
break;
}
ed.WriteMessage( "\nCould not find drawing units." );
break;
}
}
}
} catch( Exception e ) {
// Let the user know what went wrong.
ed.WriteMessage( $"\nThe file could not be read:\n{e.Message}" );
}
_AcApCore.Application.SetSystemVariable( "CMDECHO", oldCmdEcho );
_AcApCore.Application.SetSystemVariable( "LOGFILEMODE", oldLogFileMode );
//_AcApCore.Application.SetSystemVariable( "LOGFILEPATH", oldLogFilePath );
DwgUnits = dwgUnits;
return dwgUnits;
}
public static int SetDwgUnits( short dwgUnits = 6, short format = 2, short precision = 3, bool scaleInsert = false, bool match = false ) {
var doc = _AcApCore.Application.DocumentManager.MdiActiveDocument;
var ed = doc.Editor;
var oldDwgUnits = -1;
if( DwgUnits < 0 ) {
oldDwgUnits = GetDwgUnits();
}
if( dwgUnits == oldDwgUnits ) {
ed.Command( "_-DWGUNITS"
, dwgUnits // units for length
, format // Linear display format
, precision // Linear display precision
, scaleInsert ? "Yes" : "No" // Scale objects from other drawings upon insert? [Yes/No]
, match ? "Yes" : "No" // Match INSUNITS to drawing units? [Yes/No]
);
} else {
ed.Command( "_-DWGUNITS"
, dwgUnits // units for length
, format // Linear display format
, precision // Linear display precision
, scaleInsert ? "Yes" : "No" // Scale objects from other drawings upon insert? [Yes/No]
, match ? "Yes" : "No" // Match INSUNITS to drawing units? [Yes/No]
, "No"
);
}
ed.Command( "GRAPHSCR" );
DwgUnits = dwgUnits;
return dwgUnits;
}
public static void SetBlocksScale( short insUnits = 0, short insUnitsDefSource = 0, short insUnitsDefTarget = 6 ) {
var doc = _AcApCore.Application.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
var oldInsUnits = (short)_AcApCore.Application.GetSystemVariable( "INSUNITS" );
var oldSource = (short)_AcApCore.Application.GetSystemVariable( "INSUNITSDEFSOURCE" );
var oldTarget = (short)_AcApCore.Application.GetSystemVariable( "INSUNITSDEFTARGET" );
var oldMeasurement = db.Measurement;
db.Measurement = _AcDb.MeasurementValue.Metric;
_AcApCore.Application.SetSystemVariable( "INSUNITS", insUnits );
_AcApCore.Application.SetSystemVariable( "INSUNITSDEFSOURCE", insUnitsDefSource );
_AcApCore.Application.SetSystemVariable( "INSUNITSDEFTARGET", insUnitsDefTarget );
ed.WriteMessage( $"\nMeasurement\told={oldMeasurement}\tnew={_AcDb.MeasurementValue.Metric}" );
ed.WriteMessage( $"\nINSUNITS\t\told={oldInsUnits}\tnew={insUnits}" );
ed.WriteMessage( $"\nINSUNITSDEFSOURCE\told={oldSource}\tnew={insUnitsDefSource}" );
ed.WriteMessage( $"\nINSUNITSDEFTARGET\told={oldTarget}\tnew={insUnitsDefTarget}" );
ed.WriteMessage( $"\nEnd of {nameof( SetBlocksScale )}\n" );
}
}
}