Overview
- Obtain a session (rejoin, or onboard with the hub pairing code)
- Get-or-create a single app volume by its stable common name
- Enumerate and inspect every app volume handle
- Customise the volume's gesture mapping rules
- Set and clear a world anchor
- Map a room-space point into app content space and hit-test the cuboid
Prerequisites
- Complete the Onboarding and Rejoin tutorial
- A running QarOS hub (for the first run, read the pairing code off its onboarding screen)
Build and Run
cmake --build --preset x64-windows-debug --target app_volume_management
./build/x64-windows/Debug/app_volume_management.exe
<path-to-qar-streaming-c.dll> [runtime-dir] [pairing-code]
Parse Arguments
if(argc < 2)
{
return 1;
}
const char* library_path = argv[1];
const char* runtime_dir = NULL;
char runtime_dir_buffer[1024] = { 0 };
if(argc >= 3)
{
runtime_dir = argv[2];
}
else if(get_dir_from_path(library_path, runtime_dir_buffer, sizeof(runtime_dir_buffer)))
{
runtime_dir = runtime_dir_buffer;
}
const char* pairing_code = (argc >= 4) ? argv[3] : NULL;
Load, Init, and Obtain a Session
The session is obtained with the shared rejoin-or-onboard helper described in the Onboarding and Rejoin tutorial.
{
fprintf(stderr, "Failed to load '%s'.\n", library_path);
return 2;
}
{
return 3;
}
{
return 4;
}
runtime,
pairing_code,
"app_volume_management.onboarding-id.txt",
"App Volume Peer",
&onboarding_id,
&session
) != 0
|| session == NULL)
{
return 5;
}
Create and List
volume_init.common_name = "tutorial-volume.examples.qaros";
log_result("qar_app_volumes_get_or_create", create_result);
{
printf("Created app volume with id: ");
printf("\n");
}
size_t volume_count = 0;
log_result("qar_query_app_volumes_count", count_result);
{
if(handles)
{
size_t written = 0;
{
for(size_t i = 0; i < written; ++i)
{
if(!handle)
{
continue;
}
printf("- Volume id: ");
printf(
" name='%s' size(%.2f x %.2f x %.2f) position(%.2f, "
"%.2f, %.2f)\n",
name,
);
}
}
free(handles);
}
}
Customise the Gesture Configuration
Start from qar_app_volume_gesture_configuration_default(), which mirrors what a volume created without a configuration gets: two-hand distance -> app scale, one-hand 6DoF -> app pose (rotation off), hover, click. Rules are in descending priority. Change a rule in place, then replace the volume's default mode with qar_app_volumes_change_gesture_configuration(). The same struct can instead be passed in QarAppVolumeInit::gesture_configuration, but get-or-create ignores it when the volume already exists.
static void
{
{
{
}
{
}
}
"qar_app_volumes_change_gesture_configuration",
);
}
Pin to the Earth with a World Anchor
A world anchor states where app volume space sits on the Earth, as an ECEF WGS84 frame. Here the volume's +X points east, +Y up and +Z south of a latitude/longitude, which keeps the frame right-handed.
{
const double a = 6378137.0;
const double e2 = 6.69437999014e-3;
const double deg = 3.14159265358979323846 / 180.0;
const double sin_lat = sin(lat_deg * deg);
const double cos_lat = cos(lat_deg * deg);
const double sin_lon = sin(lon_deg * deg);
const double cos_lon = cos(lon_deg * deg);
const double n = a / sqrt(1.0 - e2 * sin_lat * sin_lat);
return frame;
}
static void
{
log_result("qar_app_volumes_change_app_world_anchor", set_result);
{
return;
}
"qar_app_volumes_clear_app_world_anchor",
);
}
Room-Space Point to App Content Space
Gesture points already arrive in app content space. A point the application has only in room space - a GUI panel's position, a device pose - is mapped in two steps: room -> app volume space through the volume pose, whose position is the cuboid centre, then app volume -> app content space through the app pose and app scale. The cuboid test happens in app volume space against the half extents.
{
const float ux = -q.x, uy = -q.y, uz = -q.z;
const float tx = 2.0f * (uy * v.z - uz * v.y);
const float ty = 2.0f * (uz * v.x - ux * v.z);
const float tz = 2.0f * (ux * v.y - uy * v.x);
r.x = v.x + q.w * tx + (uy * tz - uz * ty);
r.y = v.y + q.w * ty + (uz * tx - ux * tz);
r.z = v.z + q.w * tz + (ux * ty - uy * tx);
return r;
}
{
}
{
return app;
}
static bool
{
}
static void
{
float app_scale = 1.0f;
|| app_scale <= 0.0f)
{
printf("Volume state not available yet\n");
return;
}
printf(
"Room point (%.2f, %.2f, %.2f) -> app (%.2f, %.2f, %.2f), %s the "
"volume\n",
);
}
Generated via doxygen2docusaurus 2.2.1 by Doxygen 1.9.8.