Builtin Shapes 2D¶
This example shows built-in 2D geometry rendered as meshes.
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/builtin_shapes_2d (build and run), or rerun ./build/examples/c/features/builtin_shapes_2d |
| Python | Available; direct-engine adaptation | python3 -m examples.python.gallery.features.builtin_shapes_2d |
| 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 panel uses equal-aspect data coordinates, then uploads generated geometry for a plane, disc, sector, regular polygon, star, and a triangulated polygon with a hole. Each shape becomes a mesh visual attached in data space. In the live preview, pan and zoom while checking that circles stay round and the polygon hole remains open. These builders are useful for annotations, regions of interest, and custom 2D glyphs without hand-writing triangles.
Source¶
#!/usr/bin/env python3
"""Built-in 2D geometry builders rendered as retained meshes."""
from __future__ import annotations
import ctypes
import numpy as np
import datoviz as dvz
from examples.python.gallery import common as ex
def _set_equal_view2d(panel) -> None:
desc = dvz.dvz_panel_view2d_desc()
desc.mode = dvz.DVZ_PANEL_VIEW2D_CONTAIN
desc.aspect = dvz.DVZ_PANEL_VIEW2D_ASPECT_EQUAL
desc.padding = 0.04
desc.domain_x[:] = (-1.05, +1.05)
desc.domain_y[:] = (-0.72, +0.72)
desc.has_domain_x = True
desc.has_domain_y = True
if dvz.dvz_panel_set_view2d(panel, ctypes.byref(desc)) != 0:
raise RuntimeError("dvz_panel_set_view2d() failed")
def _add_geometry(scene, panel, geometry) -> None:
if not geometry:
raise RuntimeError("geometry creation failed")
mesh = dvz.dvz_mesh(scene, 0)
if not mesh:
dvz.dvz_geometry_destroy(geometry)
raise RuntimeError("dvz_mesh() failed")
try:
if dvz.dvz_mesh_set_geometry(mesh, geometry) != 0:
raise RuntimeError("dvz_mesh_set_geometry() failed")
ex.add_visual(panel, mesh)
finally:
dvz.dvz_geometry_destroy(geometry)
def _plane(scene, panel) -> None:
desc = dvz.dvz_geometry_plane_desc()
desc.center[:] = (-0.66, +0.40, 0.0)
desc.width = 0.46
desc.height = 0.30
desc.color = ex.CYAN
_add_geometry(scene, panel, dvz.dvz_geometry_plane(ctypes.byref(desc)))
def _disc(scene, panel) -> None:
desc = dvz.dvz_geometry_disc_desc()
desc.center[:] = (0.0, +0.40, 0.01)
desc.radius = 0.21
desc.segments = 48
desc.color = ex.GREEN
_add_geometry(scene, panel, dvz.dvz_geometry_disc(ctypes.byref(desc)))
def _sector(scene, panel) -> None:
desc = dvz.dvz_geometry_sector_desc()
desc.center[:] = (+0.66, +0.40, 0.02)
desc.radius = 0.27
desc.start_angle = -0.35
desc.sweep_angle = 4.4
desc.segments = 36
desc.color = ex.YELLOW
_add_geometry(scene, panel, dvz.dvz_geometry_sector(ctypes.byref(desc)))
def _regular_polygon(scene, panel) -> None:
desc = dvz.dvz_geometry_regular_polygon_desc()
desc.center[:] = (-0.66, -0.30, 0.03)
desc.radius = 0.25
desc.sides = 7
desc.color = ex.TEXT
_add_geometry(scene, panel, dvz.dvz_geometry_regular_polygon(ctypes.byref(desc)))
def _star(scene, panel) -> None:
desc = dvz.dvz_geometry_star_desc()
desc.center[:] = (0.0, -0.30, 0.04)
desc.outer_radius = 0.28
desc.inner_radius = 0.12
desc.points = 5
desc.color = ex.RED
_add_geometry(scene, panel, dvz.dvz_geometry_star(ctypes.byref(desc)))
def _hole_polygon(scene, panel) -> None:
outer = np.array(
[
[+0.46, -0.56, 0.05],
[+0.88, -0.50, 0.05],
[+0.84, -0.12, 0.05],
[+0.54, -0.02, 0.05],
[+0.36, -0.28, 0.05],
],
dtype=np.float32,
)
hole = np.array(
[
[+0.58, -0.38, 0.05],
[+0.72, -0.36, 0.05],
[+0.70, -0.22, 0.05],
[+0.56, -0.22, 0.05],
],
dtype=np.float32,
)
positions = np.vstack((outer, hole)).astype(np.float32)
colors = ex.color_array(*(ex.BLUE for _ in range(len(positions))))
indices = np.array(
[
0, 1, 6,
0, 6, 5,
1, 2, 7,
1, 7, 6,
2, 3, 8,
2, 8, 7,
3, 4, 8,
4, 5, 8,
4, 0, 5,
],
dtype=np.uint32,
)
mesh = dvz.dvz_mesh(scene, 0)
if not mesh:
raise RuntimeError("dvz_mesh() failed")
if dvz.dvz_visual_set_data_many(mesh, {"position": positions, "color": colors}) != 0:
raise RuntimeError("dvz_visual_set_data_many(holed polygon) failed")
if dvz.dvz_visual_set_index_data(mesh, indices) != 0:
raise RuntimeError("dvz_visual_set_index_data(holed polygon) failed")
ex.add_visual(panel, mesh)
def main() -> None:
scene, figure, panel = ex.scene_panel()
_set_equal_view2d(panel)
_plane(scene, panel)
_disc(scene, panel)
_sector(scene, panel)
_regular_polygon(scene, panel)
_star(scene, panel)
_hole_polygon(scene, panel)
def configure_view(view) -> None:
desc = dvz.dvz_panzoom_desc()
desc.controller_flags = dvz.DVZ_PANZOOM_FLAGS_KEEP_ASPECT
controller = dvz.dvz_panzoom(scene, ctypes.byref(desc))
if not controller:
raise RuntimeError("dvz_panzoom() failed")
if dvz.dvz_view_bind_controller(view, panel, controller, dvz.DVZ_DIM_MASK_XY) != 0:
raise RuntimeError("dvz_view_bind_controller() failed")
ex.run_with_view(scene, figure, "Builtin Shapes 2D", configure_view)
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
*/
/* builtin_shapes_2d - This example shows built-in 2D geometry rendered as retained meshes.
*
* Scenario: features_builtin_shapes_2d
* Style: features, graphite_cyan, 1280x720 window target
*
* Build: just example-c features/builtin_shapes_2d
* Run: ./build/examples/c/features/builtin_shapes_2d --live
* Smoke: ./build/examples/c/features/builtin_shapes_2d --png
*
* What to look for: the panel uses equal-aspect data coordinates, then uploads generated geometry
* for a plane, disc, sector, regular polygon, star, and a triangulated polygon with a hole. Each
* shape becomes a mesh visual attached in data space. In the live preview, pan and zoom while
* checking that circles stay round and the polygon hole remains open. These builders are useful
* for annotations, regions of interest, and custom 2D glyphs without hand-writing triangles.
*/
/*************************************************************************************************/
/* Includes */
/*************************************************************************************************/
#include <stdbool.h>
#include <stdint.h>
#include "_assertions.h"
#include "datoviz/controller/panzoom.h"
#include "datoviz/geom.h"
#include "datoviz/scene.h"
#include "example_common.h"
#include "example_style.h"
#include "runner/scenario_runner.h"
DvzScenarioSpec dvz_example_builtin_shapes_2d_scenario(void);
/*************************************************************************************************/
/* Constants */
/*************************************************************************************************/
#define WIDTH EXAMPLE_WINDOW_WIDTH
#define HEIGHT EXAMPLE_WINDOW_HEIGHT
/*************************************************************************************************/
/* Helpers */
/*************************************************************************************************/
/**
* Upload one geometry as a retained mesh and immediately release the CPU copy.
*
* @param scene scene owning the visual
* @param panel target panel
* @param geometry geometry to upload
* @return true when the mesh was added
*/
static bool _add_geometry(DvzScene* scene, DvzPanel* panel, DvzGeometry* geometry)
{
ANN(scene);
ANN(panel);
if (geometry == NULL)
return false;
DvzVisual* mesh = dvz_mesh(scene, 0);
if (mesh == NULL)
{
dvz_geometry_destroy(geometry);
return false;
}
DvzVisualAttachDesc attach = dvz_visual_attach_desc();
attach.coord_space = DVZ_VISUAL_COORD_DATA;
const bool ok = dvz_mesh_set_geometry(mesh, geometry) == 0 &&
dvz_panel_add_visual(panel, mesh, &attach) == 0;
dvz_geometry_destroy(geometry);
return ok;
}
/**
* Create a triangulated polygon with a hole.
*
* @return geometry, or NULL on failure
*/
static DvzGeometry* _hole_polygon(void)
{
const dvec2 outer[] = {
{+0.46, -0.56},
{+0.88, -0.50},
{+0.84, -0.12},
{+0.54, -0.02},
{+0.36, -0.28},
};
const dvec2 hole[] = {
{+0.58, -0.38},
{+0.72, -0.36},
{+0.70, -0.22},
{+0.56, -0.22},
};
const DvzPolygonRing holes[] = {{.xy = hole, .count = DVZ_ARRAY_COUNT(hole)}};
return dvz_triangulate_polygon(
&(DvzPolygonDesc){
DVZ_STRUCT_INIT_FIELDS(DvzPolygonDesc),
.outer = {.xy = outer, .count = DVZ_ARRAY_COUNT(outer)},
.holes = holes,
.hole_count = DVZ_ARRAY_COUNT(holes),
},
NULL);
}
/*************************************************************************************************/
/* Scenario callbacks */
/*************************************************************************************************/
/**
* Initialize the builtin 2D shapes feature scenario.
*
* @param ctx scenario context
* @param out_user unused 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;
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;
if (!example_configure_equal_aspect_panel(
panel, (DvzDataDomain){.min = -1.05, .max = +1.05},
(DvzDataDomain){.min = -0.72, .max = +0.72}, 0.04))
return false;
const bool ok =
_add_geometry(
ctx->scene, panel,
dvz_geometry_plane(&(DvzGeometryPlaneDesc){
DVZ_STRUCT_INIT_FIELDS(DvzGeometryPlaneDesc),
.center = {-0.66, +0.40, 0.0},
.width = 0.46,
.height = 0.30,
.color = example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_ACCENT_PRIMARY),
})) &&
_add_geometry(
ctx->scene, panel,
dvz_geometry_disc(&(DvzGeometryDiscDesc){
DVZ_STRUCT_INIT_FIELDS(DvzGeometryDiscDesc),
.center = {0.0, +0.40, 0.01},
.radius = 0.21,
.segments = 48,
.color = example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_ACCENT_SECONDARY),
})) &&
_add_geometry(
ctx->scene, panel,
dvz_geometry_sector(&(DvzGeometrySectorDesc){
DVZ_STRUCT_INIT_FIELDS(DvzGeometrySectorDesc),
.center = {+0.66, +0.40, 0.02},
.radius = 0.27,
.start_angle = -0.35,
.sweep_angle = 4.4,
.segments = 36,
.color = example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_WARNING),
})) &&
_add_geometry(
ctx->scene, panel,
dvz_geometry_regular_polygon(&(DvzGeometryRegularPolygonDesc){
DVZ_STRUCT_INIT_FIELDS(DvzGeometryRegularPolygonDesc),
.center = {-0.66, -0.30, 0.03},
.radius = 0.25,
.sides = 7,
.color = example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_TEXT),
})) &&
_add_geometry(
ctx->scene, panel,
dvz_geometry_star(&(DvzGeometryStarDesc){
DVZ_STRUCT_INIT_FIELDS(DvzGeometryStarDesc),
.center = {0.0, -0.30, 0.04},
.outer_radius = 0.28,
.inner_radius = 0.12,
.points = 5,
.color = example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_ERROR),
})) &&
_add_geometry(ctx->scene, panel, _hole_polygon());
DvzPanzoomDesc panzoom_desc = dvz_panzoom_desc();
panzoom_desc.controller_flags = DVZ_PANZOOM_FLAGS_KEEP_ASPECT;
DvzController* controller = dvz_panzoom(ctx->scene, &panzoom_desc);
if (controller == NULL)
return false;
return ok && dvz_scenario_bind_controller(ctx, panel, controller, DVZ_DIM_MASK_XY) == 0;
}
/**
* Return the builtin 2D shapes scenario specification.
*
* @return scenario specification
*/
DvzScenarioSpec dvz_example_builtin_shapes_2d_scenario(void)
{
return (DvzScenarioSpec){
.id = "features_builtin_shapes_2d",
.title = "Builtin Shapes 2D",
.width = WIDTH,
.height = HEIGHT,
.fps = 60.0,
.requirements = DVZ_SCENARIO_REQ_MESH_VISUAL | DVZ_SCENARIO_REQ_CONTROLLER |
DVZ_SCENARIO_REQ_PANZOOM,
.init = _scenario_init,
};
}
/*************************************************************************************************/
/* Functions */
/*************************************************************************************************/
/**
* Run the builtin 2D shapes 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_builtin_shapes_2d_scenario();
return dvz_scenario_run_native_cli(&spec, argc, argv) == 0 ? 0 : 1;
}
#endif
Example details
- ID:
features_builtin_shapes_2d - Category:
feature - Lane:
features - Status:
supported - Source:
examples/c/features/builtin_shapes_2d.c - Approved adaptation starter:
yes - Python source:
examples/python/gallery/features/builtin_shapes_2d.py - Python adaptation: Available; direct-engine adaptation
- Browser support: Live in browser
- WebGPU live route:
examples/webgpu/live.html?id=features_builtin_shapes_2d - Browser capability tags:
mesh,controller - Validation:
smoke+screenshot
Data
| Field | Value |
|---|---|
kind |
synthetic |
