## Overview

Here is code that you can reuse for common operations with the direction vectors, points in space, and transformation matrices.

## Transform a Point

Use rose_xform_apply() to tranform a point.

```RoseXform my_transform;

// Transform the following point.
RosePoint pt1(1, 2, 3);
RosePoint result_point;

rose_xform_apply(result_point, my_transform, pt1);
```

## Transform a Direction

Use rose_xform_apply_dir() to tranform a direction, which ignores any translation part of the transform.

```RoseXform my_transform;

// Transform the following point.
RoseDirection dir1(0, -1, 0);
RoseDirection result_dir;

rose_xform_apply_dir(result_dir, my_transform, dir1);
```

## Transform an Axis Placement

Use rose_xform_compose() to tranform a transform. It multiplies the matrices so you get the combination of both.

```RoseXform assembly_xf;
RoseXform part_xf;
RoseXform combined_xf;

rose_xform_compose(combined_xf, assembly_xf, part_xf);

// then apply the combined transform as usual
rose_xform_apply(result_pt, combined_xf, some_point);
```

## Make a Transform from a STEP or IFC Axis Placement

A STEP axis placement has a Z-axis direction called axis, an X-axis direction called ref_direction, and an origin called location. The stix_xform_put() function assigns and normalizes everything, or you can set the parts individually with the origin() and put_dirs() functions. The put_dirs() function has logic to handle defaults, compute the Y-axis direction, and normalize everything.

```RoseXform xf;
stp_axis2_placement_3d * ap;

// Set the xform in one call --
stix_xform_put(xf, ap);

// OR set the components individually with the lower level functions
if (!ap) return;

// populate with the direction vectors
xf.zdir(ap->axis()? ap->axis()->direction_ratios(): 0);
xf.xdir(ap->ref_direction()? ap->ref_direction()->direction_ratios(): 0);
xf.origin(ap->location()? ap->location()->coordinates(): 0);
xf.put_dirs(xf.zdir(), xf.xdir());
```

An IFC axis placement uses the same structure as STEP, but with a CamelCase naming convention. The ifcx_xform_put() function assigns and normalizes everything, or you can set the parts individually.

```RoseXform xf;
IfcAxis2Placement3D * ap;

// Set the xform in one call --
ifcx_xform_put(xf, ap);

// OR set the components individually with the lower level functions
if (!ap) return;

// populate with the direction vectors
xf.zdir(ap->Axis()? ap->Axis()->DirectionRatios(): 0);
xf.xdir(ap->RefDirection()? ap->RefDirection()->DirectionRatios(): 0);
xf.origin(ap->Location()? ap->Location()->Coordinates(): 0);
xf.put_dirs(xf.zdir(), xf.xdir());
```

## Make a Point from a STEP or IFC Point

A STEP Cartesian point has a coordinates list, typically three numbers, but in a 2D context there may only be two. You can assign the list of numbers directly to a RosePoint object, or you call stix_vec_put() with the STEP point. It will assign zeros if the list is not present or does not have enough coordinates.

```RosePoint point;
stp_cartesian_point * stp_pt;

// Set with one call
stix_vec_put(point, stp_pt);

// OR set by assigning the list of coordinates
if (stp_pt)
point = stp_pt-> coordinates();
```

An IFC Cartesian point uses the same structure, but with a CamelCase naming convention. You can assign numbers directly to a RosePoint object, or call ifcx_vec_put() with the point.

```RosePoint point;
IfcCartesianPoint * ifc_pt;

// Set with one call
ifcx_vec_put(point, ifc_pt);

// OR set by assigning the list of coordinates
if (ifc_pt)
point = ifc_pt-> Coordinates();
```

## Make a Direction from a STEP or IFC Direction

A STEP Direction has a direction_ratios list, typically i, j, k, but in a 2D context there may only be two values. Assign the list of numbers directly to a RoseDirection object, or you call stix_vec_put() with the STEP direction. It will assign zeros if the list is not present or does not have enough coordinates.

The STEP and IFC direction components are not required to be normalized, so call rose_vec_normalize() afterwards if you must have a unit vector.

```RoseDirection dir;
stp_direction * stp_dir;

// Set with one call, then normalize
stix_vec_put(point, stp_dir);
rose_vec_normalize(dir);

// OR set by assigning the list of coordinates
if (stp_dir) {
dir = stp_dir-> direction_ratios();
rose_vec_normalize(dir);
}
```

An IFC Direction uses the same structure, but with a CamelCase naming convention. Call ifcx_vec_put() with the direction and normalize if desired.

```RoseDirection dir;
ifc_direction * ifc_dir;

// Set with one call, then normalize
ifcx_vec_put(point, ifc_dir);
rose_vec_normalize(dir);

// OR set by assigning the list of coordinates
if (ifc_dir) {
dir = ifc_dir-> DirectionRatios();
rose_vec_normalize(dir);
}
```