Programatically setting DWGUNITS

Programatically setting DWGUNITS

Anonymous
Not applicable
3,978 Views
22 Replies
Message 1 of 23

Programatically setting DWGUNITS

Anonymous
Not applicable

Hi Folks, does anyone know how to programatically read and set DWGUNITS for the current drawing?

 

Environment:  Objectarx, C#, Map3D 2018

 

// Get the Database Object
doc.Database.DwgUnits =  // DOES NOT EXIST

Thank you

 

0 Likes
3,979 Views
22 Replies
Replies (22)
Message 21 of 23

_gile
Consultant
Consultant

Hi,

 

You can simply use Application.SetSystemVariable.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 22 of 23

drodmanWYZ8J
Participant
Participant

AutoLISP novice here. A simple -DWGUNITS workaround is to copy a list of commands directly into the command line. This avoids the script stopping if there's no prompt for the 6th parameter.

 

(command "qsave") (command "fileopen" "C:\\Temp\\1.dwg") (command "-DWGUNITS" "2" "2" "4" "N" "N" "N")
(command "qsave") (command "fileopen" "C:\\Temp\\2.dwg") (command "-DWGUNITS" "2" "2" "4" "N" "N" "N")

etc.

 

ON the same line, I set INSUNITS to zero and -UNITS command too

 

(command "qsave") (command "fileopen" "C:\\Temp\\1.dwg") (command "-DWGUNITS" "2" "2" "4" "N" "N" "N") (command "INSUNITS" "0") (command "-UNITS" "2" "4" "5" "5" "E" "N")

 

My issue is the U. S. Survey foot. A common problem is DWGs with large (~1,000,000) coordinates that are actually U. S. Survey foot but unit settings are incorrectly International foot. I don't want the software automatically scaling between International & U. S. Survey foot, so I set INSUNITS to unitless, and other settings so AutoCAD doesn't second-guess my INSUNITS (-DWGUNITS as above, also INSUNITSDEFSOURCE & INSUNITSDEFTARGET to 0). Unfortunately these aren't all the settings I have to worry about. Civil 3D has more, including Units & Zone, Survey Database, LandXML import/export.  There's even a separate linear unit setting for Geographic Location, if you ever use that...

 

At least the feds are outlawing the U. S. Survey foot after 2022. It will still be a problem (already is), but less so in 50 years.

https://www.ngs.noaa.gov/web/news/us-survey-foot.shtml

 

0 Likes
Message 23 of 23

Izhar_Azati
Advocate
Advocate

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" );
		}


	}
}

 

 

0 Likes