-
Notifications
You must be signed in to change notification settings - Fork 67
Units
Units like meters, millimeters, and degrees give a meaning to numbers. The number 1.82 could mean 1.82m or 1.82mm. Without a unit it is the developers (or users) repsonsibility to guess the meaning. When the unit is obvious (I'm 1.82 tall), this may not be a problem. However, when users from different countries and automated algorithms work on a DXF drawing, units become important.
There are distance units (meters, millimeters, feet, inch, etc.), angular units (rad, degree, etc.), and many more unit types irrelevant for DXF (e.g. weight). The metric system is unique, while the imperial system is not. There are (too) many definitions of a feet and unfortunatley different versions are still in use. Additionally, applications may round numbers to improve readability (e.g. 3 decimal places), while internally the full precision is stored.
Early DXF versions were unitless and the user just knew the meaning - units were introduced around DXF version R12. It is important to understand that all values inside a DXF file represent a particular unit - there is no common internal unit which is converted for the UI.
The relevant properties related to units and number formatting can be found in the DxfHeader
class which can be accessed via the DxfFile.Header
property.
When reading values from a DXF file, you want to convert "their" units to your internal unit system, whatever that may be. Suppose you want all distance values in meters, then the following method would provide the appropriate conversion factor. Note that there are many more units possible, this is just a small example.
static double GetDistanceConversionFactor(DxfHeader dxfHeader)
{
switch (dxfHeader.DefaultDrawingUnits)
{
case DxfUnits.Unitless: // assume meters
case DxfUnits.Meters:
return 1.0;
case DxfUnits.Millimeters:
return 0.001;
case DxfUnits.Feet:
return 0.3048; // only valid for international feet
case DxfUnits.Inches:
return 0.3048 / 12; // only valid for international feet
default:
throw new NotSupportedException("DefaultDrawingUnits=" + dxfHeader.DefaultDrawingUnits);
}
}
When you want to distinguish metric and imperial system, the property DxfHeader.DrawingUnits
may give a hint, but there is nothing stopping the user from drawing in imperial millimeters.
You're not going to like what I have to say here, but it's the way it is:
as I interpreted the spec, the AngleUnitFormat
property is used by AutoCAD for how to display units to the user in DIMENSION
entities, but the internal representation is fixed and non-standard.
E.g., ARC
entities always specify their start and end angle values in degrees (page 76 of the latest specification doesn't list units, but I verified this by creating an arc in AutoCAD 2017 and saving as a DXF file and examining the output.)
ELLIPSE
entities, on the other hand, always specify their start and end angles in radians (page 97).
I've added doc comments where I could to help clarify this.
Essentially, this is the opposite direction - convert all values to the target unit before creating the entities. Additionally, set DxfHeader.DefaultDrawingUnits to that unit.
DxfFile dxf = new DxfFile();
dxf.Header.Version = DxfAcadVersion.R2013; // default version does not support units
dxf.Header.DrawingUnits = DxfDrawingUnits.Metric;
dxf.Header.DefaultDrawingUnits = DxfUnits.Centimeters;
dxf.Header.UnitFormat = DxfUnitFormat.Decimal;
dxf.Header.UnitPrecision = 3;
dxf.Header.DimensionUnitFormat = DxfUnitFormat.Decimal;
dxf.Header.DimensionUnitToleranceDecimalPlaces = 3;
dxf.Header.AlternateDimensioningScaleFactor = 0.0394;
// define a circle with 4 cm radius
dxf.Entities.Add(new DxfCircle(new DxfPoint(0,0,0), 4.0))
dxf.Save(...);