Skip to content

Orientation Gizmo

This example adds a small orientation widget to a 3D panel.

Preview

Run And Adapt

Commands below assume a Datoviz source checkout and start at the repository root. Use your configured build environment; Python routes additionally require local bindings.

Route Availability Command or action
C Canonical native source just example-c features/orientation_gizmo (build and run), or rerun ./build/examples/c/features/orientation_gizmo
Python Available; direct-engine adaptation python3 -m examples.python.gallery.features.orientation_gizmo
Browser Live WebGPU route Open live example

This example is approved as a starting point for user code and coding agents. Keep the object lifetimes and data shapes intact while adapting the data and styling.

What To Look For

The main scene is a lit cube controlled by an arcball, and the orientation gizmo is placed in the panel's bottom-right corner with a fixed screen size. Rotate the live cube and compare the cube faces with the gizmo axes; the widget helps users keep track of 3D orientation when inspecting volumes, meshes, or spatial point clouds.

Source

#!/usr/bin/env python3
"""3D cube with an arcball controller and a passive orientation gizmo."""

from __future__ import annotations

import ctypes

import datoviz as dvz

from examples.python.gallery import common as ex


def _add_reference_grid(panel) -> None:
    desc = dvz.dvz_reference_grid_desc()
    desc.plane = dvz.DVZ_REFERENCE_GRID_XZ
    desc.origin[1] = -0.59
    desc.size[:] = (7.0, 7.0)
    desc.spacing = 0.25
    desc.major_every = 4
    desc.minor_color = dvz.DvzColor(74, 86, 98, 95)
    desc.major_color = dvz.DvzColor(116, 132, 148, 145)
    desc.axis_color = dvz.DvzColor(176, 190, 204, 185)
    desc.depth_test = True
    grid = dvz.dvz_reference_grid(panel, ctypes.byref(desc))
    if not grid:
        raise RuntimeError("dvz_reference_grid() failed")


def _add_orientation_gizmo(panel) -> None:
    desc = dvz.dvz_orientation_gizmo_desc()
    desc.placement = dvz.dvz_placement_panel_corner(
        dvz.DVZ_HORIZONTAL_ANCHOR_RIGHT,
        dvz.DVZ_VERTICAL_ANCHOR_BOTTOM,
        150.0,
        150.0,
        -18.0,
        -18.0,
    )
    gizmo = dvz.dvz_orientation_gizmo(panel, ctypes.byref(desc))
    if not gizmo:
        raise RuntimeError("dvz_orientation_gizmo() failed")


def _add_scene(scene, panel) -> None:
    ex.manual_camera(panel)
    _add_reference_grid(panel)
    ex.add_cube_mesh(scene, panel, size=1.18)
    _add_orientation_gizmo(panel)


def main() -> None:
    scene, figure, panel = ex.scene_panel()
    _add_scene(scene, panel)

    def configure(view) -> None:
        arcball = dvz.dvz_view_arcball(view, panel, None)
        if not arcball:
            raise RuntimeError("dvz_view_arcball() failed")
        angles = (ctypes.c_float * 3)(0.0, 0.0, 0.0)
        if dvz.dvz_arcball_set(arcball, angles) != 0:
            raise RuntimeError("dvz_arcball_set() failed")

    ex.run_with_view(scene, figure, "Orientation Gizmo", configure)


if __name__ == "__main__":
    main()
/*
 * Copyright (c) 2021 Cyrille Rossant and contributors. All rights reserved.
 * Licensed under the MIT license. See LICENSE file in the project root for details.
 * SPDX-License-Identifier: MIT
 */

/* This example adds a small orientation widget to a 3D panel.
 *
 * What to look for: the main scene is a lit cube controlled by an arcball, and the orientation
 * gizmo is placed in the panel's bottom-right corner with a fixed screen size. Rotate the live
 * cube and compare the cube faces with the gizmo axes; the widget helps users keep track of 3D
 * orientation when inspecting volumes, meshes, or spatial point clouds.
 *
 * Scenario: features_orientation_gizmo
 * Style: features, graphite_cyan, 1280x720 window target
 *
 * Build:  just example-c features/orientation_gizmo
 * Run:    ./build/examples/c/features/orientation_gizmo --live
 * Smoke:  ./build/examples/c/features/orientation_gizmo --png
 */



/*************************************************************************************************/
/*  Includes                                                                                     */
/*************************************************************************************************/

#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

#include "_alloc.h"
#include "datoviz/geom.h"
#include "datoviz/scene.h"
#include "example_common.h"
#include "example_controller_preview.h"
#include "example_style.h"
#include "runner/scenario_runner.h"



/*************************************************************************************************/
/*  Constants                                                                                    */
/*************************************************************************************************/

#define WIDTH  EXAMPLE_WINDOW_WIDTH
#define HEIGHT EXAMPLE_WINDOW_HEIGHT

DvzScenarioSpec dvz_example_orientation_gizmo_scenario(void);



/*************************************************************************************************/
/*  Structs                                                                                      */
/*************************************************************************************************/

typedef struct OrientationGizmoState
{
    DvzGeometry* geometry;
    DvzArcball* arcball;
} OrientationGizmoState;



/*************************************************************************************************/
/*  Scenario callbacks                                                                           */
/*************************************************************************************************/

/**
 * Initialize the orientation-gizmo feature scenario.
 *
 * @param ctx scenario context
 * @param out_user scenario state output
 * @return true on success
 */
static bool _scenario_init(DvzScenarioContext* ctx, void** out_user)
{
    if (ctx == NULL)
        return false;
    if (out_user != NULL)
        *out_user = NULL;

    OrientationGizmoState* state = (OrientationGizmoState*)dvz_calloc(1, sizeof(*state));
    if (state == NULL)
        return false;
    if (out_user != NULL)
        *out_user = state;

    ctx->figure = dvz_figure(ctx->scene, ctx->width, ctx->height, 0);
    if (ctx->figure == NULL)
        return false;

    DvzPanel* panel = dvz_panel_full(ctx->figure);
    if (panel == NULL)
        return false;
    example_graphite_cyan_set_panel_background(panel);

    if (example_set_default_3d_camera(panel, 1.0f) == NULL)
        return false;
    if (!example_add_graphite_cyan_xz_reference_grid(panel, -0.59f, true))
        return false;
    if (!example_add_graphite_cyan_cube_mesh(ctx->scene, panel, 1.18, NULL, &state->geometry))
        return false;

    DvzController* controller = dvz_arcball(ctx->scene, NULL);
    if (controller == NULL)
        return false;
    DvzArcball* arcball = dvz_controller_arcball(controller);
    if (arcball == NULL)
        return false;
    state->arcball = arcball;
    if (dvz_scenario_bind_controller(ctx, panel, controller, DVZ_DIM_MASK_XYZ) != 0)
        return false;

    DvzOrientationGizmoDesc gizmo = dvz_orientation_gizmo_desc();
    gizmo.placement = dvz_placement_panel_corner(
        DVZ_HORIZONTAL_ANCHOR_RIGHT, DVZ_VERTICAL_ANCHOR_BOTTOM, 150, 150, -18, -18);
    return dvz_orientation_gizmo(panel, &gizmo) != NULL;
}


/**
 * Apply deterministic preview motion for generated gallery media.
 *
 * @param ctx scenario context
 * @param user scenario state
 */
static void _scenario_frame(DvzScenarioContext* ctx, void* user)
{
    if (ctx == NULL || !ctx->preview_mode || user == NULL)
        return;

    OrientationGizmoState* state = (OrientationGizmoState*)user;
    ExamplePreviewArcballDesc desc = example_preview_arcball_cube_desc();
    example_preview_arcball(
        state->arcball, ctx->preview_frame_index, ctx->preview_frame_count, &desc);
}



/**
 * Destroy the orientation-gizmo feature scenario state.
 *
 * @param ctx scenario context
 * @param user scenario state
 */
static void _scenario_destroy(DvzScenarioContext* ctx, void* user)
{
    (void)ctx;
    OrientationGizmoState* state = (OrientationGizmoState*)user;
    if (state == NULL)
        return;
    if (state->geometry != NULL)
        dvz_geometry_destroy(state->geometry);
    dvz_free(state);
}



/**
 * Return the orientation-gizmo scenario specification.
 *
 * @return scenario specification
 */
DvzScenarioSpec dvz_example_orientation_gizmo_scenario(void)
{
    return (DvzScenarioSpec){
        .id = "features_orientation_gizmo",
        .title = "Orientation Gizmo",
        .width = WIDTH,
        .height = HEIGHT,
        .fps = 60.0,
        .requirements = DVZ_SCENARIO_REQ_MESH_VISUAL | DVZ_SCENARIO_REQ_CONTROLLER |
                        DVZ_SCENARIO_REQ_ARCBALL,
        .init = _scenario_init,
        .frame = _scenario_frame,
        .destroy = _scenario_destroy,
    };
}



/*************************************************************************************************/
/*  Functions                                                                                    */
/*************************************************************************************************/

/**
 * Run the orientation-gizmo feature example through the native scenario runner.
 *
 * @param argc command-line argument count
 * @param argv command-line argument vector
 * @return process exit code
 */
#ifndef DVZ_EXAMPLE_NO_MAIN
int main(int argc, char** argv)
{
    DvzScenarioSpec spec = dvz_example_orientation_gizmo_scenario();
    return dvz_scenario_run_native_cli(&spec, argc, argv) == 0 ? 0 : 1;
}
#endif
Example details

Data

Field Value
kind synthetic