Skip to content
João Santos edited this page May 4, 2021 · 4 revisions

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.

Reading Distance Units from a DXF File

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.

Reading Angular Units from DXF

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.

Writing Values+Unit to DXF

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(...);