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