Tutorial 3: Coordinate Systems
In this tutorial you will learn to construct and manipulate coordinate systems in Ninbot:
how to create hierarchical coordinate systems using coordsys_child,
and understand the difference between independent and linked copies.
The Setup
Coordinate systems form a tree hierarchy with the World Coordinate System (WCS) at the root. You can attach child coordinate systems to parents and navigate the tree.
The Code
#include <print>
import ninbot;
int main()
{
using namespace nin;
using namespace nin::R3;
position_coordsys cs_wcs_default;
position_coordsys cs_wcs_explicit {WCS};
std::println("Default and WCS coordsys are equal: {}", cs_wcs_default == WCS);
position_coordsys_child original {WCS, { {1_m, 0_m, 0_m}, {} }};
position_coordsys copy1 = original;
position_coordsys copy2 = original;
position_coordsys linked = original.linked_copy();
std::println("\nTwo independent copies are equal: {}", copy1 == copy2);
std::println("Linked copy shares backend with original (call succeeds)");
position_coordsys_child CS_A {WCS, { {2_m, 0_m, 0_m}, {} }};
position_coordsys_child CS_B {CS_A, { {0_m, 1_m, 0_m}, {{0, 0, 1}, 90_deg} }};
position_coordsys_child CS_C {CS_A, { {-1_m, 0_m, 0_m}, {} }};
point origin_B_in_WCS = CS_B.origin();
std::println("Origin of CS_B in WCS: {}", origin_B_in_WCS.map_to(WCS));
return 0;
}
Building the code
Save the example as coordinate-systems.c++ alongside this CMakeLists.txt:
cmake_minimum_required(VERSION 4.0)
project(coordinate-systems LANGUAGES CXX)
find_package(Ninbot REQUIRED)
add_executable(coordinate-systems coordinate-systems.c++)
target_link_libraries(coordinate-systems PRIVATE ninbot::ninbot)
Then configure and build:
cmake -B build -G Ninja -DCMAKE_PREFIX_PATH=/path/to/ninbot/build
cmake --build build
./build/coordinate-systems
Walkthrough
The World Coordinate System
using namespace nin;
using namespace nin::R3;
The WCS is the global reference frame — all other coordinate systems are defined relative to it, either directly or through a chain of parent coordinate systems.
position_coordsys cs_wcs_default;
position_coordsys cs_wcs_explicit {WCS};
A default-constructed coordsys is equivalent to WCS. Both cs_wcs_default and cs_wcs_explicit refer to the same global reference frame.
Copying Coordinate Systems: Independent vs Linked
When you copy a coordinate system, Ninbot creates an independent backend copy by default. Each copy is a separate object with its own backend storage.
position_coordsys_child original {WCS, { {1_m, 0_m, 0_m}, {} }};
position_coordsys copy1 = original;
position_coordsys copy2 = original;
Here, copy1 and copy2 are independent copies of original.
Although they initially represent the same transformation, they are not equal to each other because they have different backends.
If you want multiple references to point to the same coordinate frame (sharing the backend),
use linked_copy():
position_coordsys linked = original.linked_copy();
This is important when passing coordinate system references around —
if you want different references to represent the same frame and reflect changes made through any reference,
you must use linked_copy().
Building a Coordinate System Hierarchy
Child coordinate systems are defined relative to a parent using coordsys_child.
Each child specifies a rigid transformation (translation + rotation) from its parent.
position_coordsys_child CS_A {WCS, { {2_m, 0_m, 0_m}, {} }};
CS_A is 2 metres along X from WCS with no rotation.
position_coordsys_child CS_B {CS_A, { {0_m, 1_m, 0_m}, {{0, 0, 1}, 90_deg} }};
CS_B is a child of CS_A, offset by 1 metre in Y and rotated 90° around the Z axis.
position_coordsys_child CS_C {CS_A, { {-1_m, 0_m, 0_m}, {} }};
CS_C is a sibling of CS_B — also a child of CS_A, but at -1 metre along X.
point origin_B_in_WCS = CS_B.origin();
std::println("Origin of CS_B in WCS: {}", origin_B_in_WCS.map_to(WCS));
You can query the position of a coordinate system’s origin in any other frame using .origin() and .map_to().