# Tutorial for OCS/UCS Usage¶

First you need an understanding of vectors, if you don’t have it, watch the YouTube tutorials of 3Blue1Brown about Linear Algebra.

Second read the Coordinate Systems introduction please.

For WCS there is not much to say as, it is what it is: the main world coordinate system, and a drawing unit can have any real world unit you want. Autodesk added some mechanism to define a scale for dimension and text entities, but because I am not an AutoCAD user, I am not familiar with it, and further more I think this is more an AutoCAD topic than a DXF topic.

## Object Coordinate System (OCS)¶

The OCS is used to place planar 2D entities in 3D space. **ALL** points of a planar entity lay in the same plane,
this is also true if the plane is located in 3D space by an OCS. There are three basic DXF attributes that gives a 2D
entity its spatial form.

### Extrusion¶

The extrusion vector defines the OCS, it is a normal vector to the base plane of a planar entity. This base plane is
always located in the origin of the WCS. But there are some entities like `Ellipse`

, which have an
extrusion vector, but do not establish an OCS. For this entities the extrusion vector defines only the extrusion
direction and thickness defines the extrusion distance, but all other points in WCS.

### Elevation¶

The elevation value defines the z-axis value for all points of a planar entity, this is an OCS value, and defines the distance of the entity plane from the base plane.

This value exists only in output from DXF versions prior to R11 as separated DXF attribute (group code 38).
In DXF version R12 and later, the elevation value is supplied as z-axis value of each point. But as always in DXF, this
simple rule does not apply to all entities: `LWPolyline`

has an elevation attribute, `Hatch`

has an
elevation point (z=elevation , x=y=0), and so on.

### Thickness¶

Defines the extrusion distance for an entity.

## Placing 2D Circle in 3D Space¶

The colors for axis follow the AutoCAD standard:

- red is x-axis
- green is y-axis
- blue is z-axis

```
import ezdxf
from ezdxf.algebra import OCS
dwg = ezdxf.new('R2010')
msp = dwg.modelspace()
# For this example the OCS is rotated around x-axis about 45 degree
# OCS z-axis: x=0, y=1, z=1
# extrusion vector must not normalized here
ocs = OCS((0, 1, 1))
msp.add_circle(
# You can place the 2D circle in 3D space
# but you have to convert WCS into OCS
center=ocs.from_wcs((0, 2, 2)),
# center in OCS: (0.0, 0.0, 2.82842712474619)
radius=1,
dxfattribs={
# here the extrusion vector should be normalized,
# which is granted by using the ocs.uz
'extrusion': ocs.uz,
'color': 2,
})
# mark center point of circle in WCS
msp.add_point((0, 2, 2), dxfattribs={'color': 2})
```

The following image shows the 2D circle in 3D space in AutoCAD Left and Front view. The blue line shows the OCS z-axis (extrusion direction), elevation is the distance from the origin to the center of the circle in this case 2.828, and you see that the x- and y- axis of OCS and WCS are not aligned.

## Placing LWPolyline in 3D Space¶

For simplicity of calculation I use the `UCS`

class in this example to place a 2D pentagon in 3D space.

```
import ezdxf
from ezdxf.algebra import Vector, UCS
dwg = ezdxf.new('R2010')
msp = dwg.modelspace()
# center point of the pentagon should be (0, 2, 2), and the shape is
# rotated around x-axis about 45 degree, to accomplish this I use an
# UCS with z-axis (0, 1, 1) and an x-axis parallel to WCS x-axis.
ucs = UCS(
origin=(0, 2, 2), # center of pentagon
ux=(1, 0, 0), # x-axis parallel to WCS x-axis
uz=(0, 1, 1), # z-axis
)
# calculating corner points in local (UCS) coordinates
points = [Vector.from_deg_angle((360/5)*n) for n in range(5)]
# converting UCS into OCS coordinates
ocs_points = list(ucs.points_to_ocs(points))
# LWPOLYLINE accepts only 2D points and has an separated DXF attribute elevation.
# All points have the same z-axis (elevation) in OCS!
elevation = ocs_points[0].z
msp.add_lwpolyline(
# LWPOLYLINE point format: (x, y, [start_width, [end_width, [bulge]]])
# the z-axis would be start_width, so remove it
points=[p[:2] for p in ocs_points],
dxfattribs={
'elevation': elevation,
'extrusion': ucs.uz,
'closed': True,
'color': 2,
})
```

The following image shows the 2D pentagon in 3D space in AutoCAD Left, Front and Top view. The three lines from the center of the pentagon show the UCS, the three colored lines in the origin show the OCS the white lines in the origin show the WCS.

The z-axis of the UCS and the OCS show the same direction (extrusion direction), and the x-axis of the UCS and the WCS show the same direction. The elevation is the distance from the origin to the center of the pentagon and all points of the pentagon have the same elevation, and you see that the y- axis of UCS, OCS and WCS are not aligned.

## Using UCS to Place 3D Polyline¶

It is much simpler to use a 3D `Polyline`

to create the 3D pentagon. The `UCS`

class is handy for
this example and all kind of 3D operations.

```
import math
import ezdxf
from ezdxf.algebra import UCS, Matrix44
dwg = ezdxf.new('R2010')
msp = dwg.modelspace()
# using an UCS simplifies 3D operations, but UCS definition can happen later
# calculating corner points in local (UCS) coordinates without Vector class
angle = math.radians(360/5)
corners_ucs = [(math.cos(angle*n), math.sin(angle*n), 0) for n in range(5)]
# let's do some transformations
tmatrix = Matrix44.chain( # creating a transformation matrix
Matrix44.z_rotate(math.radians(15)), # 1. rotation around z-axis
Matrix44.translate(0, .333, .333), # 2. translation
)
transformed_corners_ucs = tmatrix.transform_vectors(corners_ucs)
# transform UCS into WCS
ucs = UCS(
origin=(0, 2, 2), # center of pentagon
ux=(1, 0, 0), # x-axis parallel to WCS x-axis
uz=(0, 1, 1), # z-axis
)
corners_wcs = list(ucs.points_to_wcs(transformed_corners_ucs))
msp.add_polyline3d(
points=corners_wcs,
dxfattribs={
'closed': True,
'color': 2,
})
# add lines from center to corners
center_wcs = ucs.to_wcs((0, .333, .333))
for corner in corners_wcs:
msp.add_line(center_wcs, corner, dxfattribs={'color': 2})
```

## Placing 2D Text in 3D space¶

The problem by placing text in 3D space is the text rotation, which is always counter clockwise around the OCS z-axis, and 0 degree is in the positive OCS x-axis, and the x-axis is calculated by the Arbitrary Axis Algorithm.

Calculate the OCS rotation angle by converting the rotation angle in UCS or WCS into a vector or start with text direction as vector, transform this direction vector into OCS and convert the OCS vector back into an angle in the OCS xy-plane (see example).

AutoCAD supports thickness for the TEXT entity only for shx fonts and not for true type fonts.

```
import ezdxf
from ezdxf.algebra import UCS, Vector
dwg = ezdxf.new('R2010')
msp = dwg.modelspace()
# thickness for text works only with shx fonts not with true type fonts
dwg.styles.new('TXT', dxfattribs={'font': 'romans.shx'})
ucs = UCS(origin=(0, 2, 2), ux=(1, 0, 0), uz=(0, 1, 1))
# calculation of text direction as angle in OCS:
# convert text rotation in degree into a vector in UCS
text_direction = Vector.from_deg_angle(-45)
# transform vector into OCS and get angle of vector in xy-plane
rotation = ucs.to_ocs(text_direction).angle_deg
text = msp.add_text(
text="TEXT",
dxfattribs={
# text rotation angle in degrees in OCS
'rotation': rotation,
'extrusion': ucs.uz,
'thickness': .333,
'color': 2,
'style': 'TXT',
})
# set text position in OCS
text.set_pos(ucs.to_ocs((0, 0, 0)), align='MIDDLE_CENTER')
```

Hint

For calculating OCS angles from an UCS, be aware that 2D entities, like TEXT or ARC, are placed parallel to the xy-plane of the UCS.

## Placing 2D Arc in 3D space¶

Here we have the same problem as for placing text, you need the start and end angle of the arc in degrees in OCS, and this example also shows a shortcut for calculating the OCS angles.

```
ucs = UCS(origin=(0, 2, 2), ux=(1, 0, 0), uz=(0, 1, 1))
msp.add_arc(
center=ucs.to_ocs((0, 0)),
radius=1,
start_angle=ucs.to_ocs_angle_deg(45), # shortcut
end_angle=ucs.to_ocs_angle_deg(270), # shortcut
dxfattribs={
'extrusion': ucs.uz,
'color': 2,
})
center = ucs.to_wcs((0, 0))
msp.add_line(
start=center,
end=ucs.to_wcs(Vector.from_deg_angle(45)),
dxfattribs={'color': 2},
)
msp.add_line(
start=center,
end=ucs.to_wcs(Vector.from_deg_angle(270)),
dxfattribs={'color': 2},
)
```