Tutorial 1: Points and Translations

In this tutorial you will learn to work with point quantities in 3D space (a.k.a. position quantities), create translations — the simplest kind of transformation function — and apply translations to point quantities.

Quantities are raw data that have no relation to coordinate systems. They are plain measures of coordinates without a reference frame. In later tutorials you will learn how to associate these quantities to coordinate systems and to transform the quantities between those coordinate systems.

The Code

#include <print>
import ninbot;

int main()
{
   using namespace nin;

   R3::point_qty my_point_qty = {1_m, 2_m, 3_m};
   my_point_qty.z = 600_cm;
   for (length & coord : my_point_qty)
      coord += 1_m;

   std::println("The coordinates of my_point_qty are {}", my_point_qty);

   R3::translation tf1  = {10_cm, 0_m, 0_m};
   tf1.Δx += 1_cm + tf1.Δz;
   R3::translation tf2  = {0_m, 20_cm, 0_m};
   R3::translation tf21 = compose( tf2, tf1 );
   R3::translation tf12 = inv( tf21 );

   R3::point_qty transformed_qty = tf21( my_point_qty );

   std::println("Translated by {:_cm} results in {}", tf21, transformed_qty );
}

Output

The coordinates of my_point_qty are (2, 3, 7) (m)
Translated by (11, 20, 0) (cm) results in (2.11, 3.2, 7) (m)

Building the code

Save the example as points-translations.c++ alongside this CMakeLists.txt:

cmake_minimum_required(VERSION 4.0)
project(points-translations LANGUAGES CXX)

find_package(Ninbot REQUIRED)

add_executable(points-translations points-translations.c++)
target_link_libraries(points-translations PRIVATE ninbot::ninbot)

Then configure and build:

cmake -B build -G Ninja -DCMAKE_PREFIX_PATH=/path/to/ninbot/build
cmake --build build
./build/points-translations

Walkthrough

Imports and namespaces

#include <print>
import ninbot;
using namespace nin;

using namespace nin brings unit literals such as 1_m and the WCS tag into scope. This tutorial uses 3D types from nin::R3, referenced with the R3:: prefix.

Coordinate quantities

R3::point_qty my_point_qty = {1_m, 2_m, 3_m};

A point_qty holds the raw measures of a 3D position — three length values — without being tied to any coordinate system.

Accessing coordinates

my_point_qty.x += 1_m;

Individual components are accessible as named fields (x, y, z).

After modifying each field individually, my_point_qty becomes (3, 3, 4) (m).

Translations

R3::translation tf1 = {10_cm, 0_m, 0_m};

A translation is a transformation that shifts coordinates. Its components are named Δx, Δy, Δz to distinguish them from position coordinates.

tf1.Δx += 1_cm + tf1.Δz;

Translation components are mutable and support arithmetic with other length quantities.

Composing and inverting translations

R3::translation tf2 = {0_m, 20_cm, 0_m};
R3::translation tf12 = compose( tf1, tf2 );

compose combines two translations into one. The result of composing tf1 (0.11, 0, 0) (m) with tf2 (0, 0.2, 0) (m) is (0.11, 0.2, 0) (m).

R3::translation tf21 = inv( tf12 );

inv returns the inverse translation — applying it undoes the original.

Applying a translation

R3::point_qty transformed_qty = tf12( my_point_qty );

A translation is callable: tf12( my_point_qty ) applies the translation to a coordinate quantity, returning a new point_qty.

Printing

std::println("The coordinates of my_point_qty are {}", my_point_qty);

Both point_qty and translation support std::format / std::println. The default format wraps the numeric components in parentheses separated by ", ", followed by the unit in parentheses.

std::println( "If translated by {:_cm} results in {}", tf12, transformed_qty );

The format specifier {:_cm} converts all components to centimetres before printing. The unit specifier must match one of the Ninbot-defined literals and the dimensions must agree with the dimensions of the variable being formatted.