Upright

The functions in this module can help to convert an inverted OCS defined by an extrusion vector (0, 0, -1) into a WCS aligned OCS defined by an extrusion vector (0, 0, 1).

This simplifies 2D entity processing for ezdxf users and creates DXF output for 3rd party DXF libraries which ignore the existence of the OCS.

Supported DXF entities:

  • CIRCLE

  • ARC

  • ELLIPSE (WCS entity, flips only the extrusion vector)

  • SOLID

  • TRACE

  • LWPOLYLINE

  • POLYLINE (only 2D entities)

  • HATCH

  • MPOLYGON

  • INSERT (block references)

Warning

The WCS representation of OCS entities with flipped extrusion vector is not 100% identical to the source entity, curve orientation and vertex order may change, see additional explanation below. A mirrored text represented by an extrusion vector (0, 0, -1) cannot represented by an extrusion vector (0, 0, 1), therefore this CANNOT work for text entities or entities including text: TEXT, ATTRIB, ATTDEF, MTEXT, DIMENSION, LEADER, MLEADER

Usage

The functions can be applied to any DXF entity without expecting errors or exceptions if the DXF entity is not supported or the extrusion vector differs from (0, 0, -1). This also means you can apply the functions multiple times to the same entities without any problems. A common case would be to upright all entities of the model space:

import ezdxf
from ezdxf.upright import upright_all

doc = ezdxf.readfile("your.dxf")
msp = doc.modelspace()
upright_all(msp)
# doing it again is no problem but also has no further effects
upright_all(msp)

Another use case is exploding block references (INSERT) which may include reflections (= scaling by negative factors) that can lead to inverted extrusion vectors.

for block_ref in msp.query("INSERT"):
    entities = block_ref.explode()  # -> EntityQuery object
    upright_all(entities)

Functions

ezdxf.upright.upright(entity: DXFGraphic) None

Flips an inverted OCS defined by extrusion vector (0, 0, -1) into a WCS aligned OCS defined by extrusion vector (0, 0, 1). DXF entities with other extrusion vectors and unsupported DXF entities will be silently ignored. For more information about the limitations read the documentation of the ezdxf.upright module.

ezdxf.upright.upright_all(entities: Iterable[DXFGraphic]) None

Call function upright() for all DXF entities in iterable entities:

upright_all(doc.modelspace())

Additional Explanation

This example shows why the entities with an inverted OCS, extrusion vector is (0, 0, -1), are not exact the same as with an WCS aligned OCS, extrusion vector is (0, 0, 1).

Note

The ARC entity represents the curve always in counter-clockwise orientation around the extrusion vector.

import ezdxf
from ezdxf.upright import upright
from ezdxf.math import Matrix44

doc = ezdxf.new()
msp = doc.modelspace()

arc = msp.add_arc(
    (5, 0),
    radius=5,
    start_angle=-90,
    end_angle=90,
    dxfattribs={"color": ezdxf.const.RED},
)
# draw lines to the start- and end point of the ARC
msp.add_line((0, 0), arc.start_point, dxfattribs={"color": ezdxf.const.GREEN})
msp.add_line((0, 0), arc.end_point, dxfattribs={"color": ezdxf.const.BLUE})

# copy arc
mirrored_arc = arc.copy()
msp.add_entity(mirrored_arc)

# mirror copy
mirrored_arc.transform(Matrix44.scale(-1, 1, 1))

# This creates an inverted extrusion vector:
assert mirrored_arc.dxf.extrusion.isclose((0, 0, -1))

# draw lines to the start- and end point of the mirrored ARC
msp.add_line((0, 0), mirrored_arc.start_point, dxfattribs={"color": ezdxf.const.GREEN})
msp.add_line((0, 0), mirrored_arc.end_point, dxfattribs={"color": ezdxf.const.BLUE})

Result without applying the upright() function - true mirroring:

_images/upright_arc_0.png
...

# This creates an inverted extrusion vector:
assert mirrored_arc.dxf.extrusion.isclose((0, 0, -1))

start_point_inv = mirrored_arc.start_point
end_point_inv = mirrored_arc.end_point

upright(mirrored_arc)
# OCS is aligned with WCS:
assert mirrored_arc.dxf.extrusion.isclose((0, 0, 1))

# start- and end points are swapped after applying upright()
assert mirrored_arc.start_point.isclose(end_point_inv)
assert mirrored_arc.end_point.isclose(start_point_inv)

# draw lines to the start- and end point of the mirrored ARC
msp.add_line((0, 0), mirrored_arc.start_point, dxfattribs={"color": ezdxf.const.GREEN})
msp.add_line((0, 0), mirrored_arc.end_point, dxfattribs={"color": ezdxf.const.BLUE})

Result after applying the upright() function - false mirroring:

_images/upright_arc_1.png

To avoid this issue the ARC entity would have to represent the curve in clockwise orientation around the extrusion vector (0, 0, 1), which is not possible!

Note

The shape of the mirrored arcs is the same for both extrusion vectors, but the start- and the end points are swapped (reversed vertex order)!