The public interface (headers under include/dgd/) is documented and contains the full API details. This brief guide outlines common workflows and highlights the headers to include for each task.
Headers to include:
- Minimal:
#include "dgd/geometry/convex_set.h" - Concrete types (pick as needed):
- 2D:
#include "dgd/geometry/2d/ellipse.h",.../polygon.h,.../rectangle.h, etc. - 3D:
#include "dgd/geometry/3d/cone.h",.../mesh.h,.../ellipsoid.h, etc. - 2D/3D (for capsules and spheres):
#include "dgd/geometry/xd/capsule.h",.../sphere.h.
- 2D:
- Halfspace:
#include "dgd/geometry/halfspace.h"
Example (2D ellipse and polygon):
#include "dgd/geometry/2d/ellipse.h"
#include "dgd/geometry/2d/polygon.h"
using namespace dgd;
auto a = std::make_unique<Ellipse>(/*hlx=*/1.0, /*hly=*/0.5, /*margin=*/0.05);
std::vector<Vec2r> verts = /* build or load vertices */;
auto b = std::make_unique<Polygon>(verts, /*inradius=*/0.1, /*margin=*/0.0);-
Base transforms: Concrete types store their geometry in their own local frame. Check the documentation for each concrete type to determine its base frame and center point.
-
User-defined convex sets: To add a custom set, derive from
ConvexSet<dim>and implement the required virtual function:Real SupportFunction(const Vecr<dim>&, Vecr<dim>&, SupportFunctionHint<dim>*);
and, optionally, other virtual functions. See the existing implementations (e.g.,
Ellipse,Polygon,Cone,Mesh) for examples.
Types of user-defined convex sets that can be defined include:- 2D: semi-circle.
- 3D: hemi-sphere, ellipsoidal plate.
Convex hull of 2D/3D points can be computed as follows:
-
Graham scan (convex hull in 2D):
- Header:
#include "dgd/graham_scan.h" - Use
GrahamScan(input_points, output_hull)to compute a 2D convex hull (in CCW orientation) from a point cloud.
- Header:
-
Mesh import (from .obj files), convex hull in 3D, and adjacency graph computation:
- Header:
#include "dgd/mesh_loader.h" - Use
MeshLoaderto import points (or to process an in-memory vertex list). - Example workflow:
- Fill
std::vector<Vec3r> pts(or callMeshLoader::LoadObjif .obj file is available, and skip step 2). - Call
ml.ProcessPoints(pts)(removes duplicates). - Build convex hull and vertex adjacency graph:
ml.MakeVertexGraph(vert, graph)→ returns the vertex list and adjacency graph.
Build convex hull and facet adjacency graph:
ml.MakeFacetGraph(normal, offset, graph, interior-point)→ returns the facet list (normals and offsets), adjacency graph, and an interior point. - Compute inradius at the center point:
ml.ComputeInradius(center), etc.
- Fill
- Header:
Important: The center point returned by MeshLoader (or used internally) is not guaranteed to be the world origin — check the loader's returned center point and adjust accordingly.
Public runtime-dispatch API (cheap to include):
- Header:
#include "dgd/dgd.h" - Runtime (virtual-dispatch) functions:
dgd::GrowthDistance<dim>(const ConvexSet<dim>*, const Transformr<dim>&, const ConvexSet<dim>*, const Transformr<dim>&, const Settings&, Output<dim>&, bool warm_start)dgd::DetectCollision<dim>(...)
Header-only, zero-virtual-cost templates (opt-in):
- Header:
#include "dgd/solvers/bundle_scheme_impl.h" - Call:
dgd::GrowthDistanceCpTpl<dim, Concrete1, Concrete2>(...)dgd::DetectCollisionTpl<dim, Concrete1, Concrete2>(...)
- Note: These templates are heavy; include
bundle_scheme_impl.honly in translation units where you need peak performance. The library does not provide pre-instantiatedTplfunctions — including the header is required.
Simple example (runtime API):
#include "dgd/dgd.h"
#include "dgd/geometry/2d/ellipse.h"
#include "dgd/geometry/2d/polygon.h"
using namespace dgd;
Ellipse a(...);
Polygon b(...);
Transform2r ta = Transform2r::Identity();
Transform2r tb = Transform2r::Identity();
Linear(tb) = /* set rotation matrix */;
Affine(tb) = /* set translation vector */;
Settings settings;
Output<2> out;
Real gd = GrowthDistance(&a, ta, &b, tb, settings, out, /*warm_start=*/false);
bool collision = DetectCollision(&a, ta, &b, tb, settings, out, false);Example (header-only templated API):
#include "dgd/solvers/bundle_scheme_impl.h" // heavy; opt-in
#include "dgd/geometry/2d/ellipse.h"
#include "dgd/geometry/2d/polygon.h"
using namespace dgd;
Ellipse a(...);
Polygon b(...);
Transform2r ta = Transform2r::Identity();
Transform2r tb = Transform2r::Identity();
Linear(tb) = /* set rotation matrix */;
Affine(tb) = /* set translation vector */;
Settings settings;
Output<2> out;
Real gd = GrowthDistanceCpTpl(&a, ta, &b, tb, settings, out, /*warm_start=*/false);
bool collision = DetectCollisionTpl(&a, ta, &b, tb, settings, out, false);Two available solver algorithms (currently):
- Cutting plane (
GrowthDistanceCp):- Best for polytopic sets (with zero margin), and robust.
- Trust region Newton (
GrowthDistanceTrn):- Second-order solver best for sets with curved surfaces.
Solver / warm-start guidance (broad categories):
| Set pair category | Preferred solver | Warm-start type |
|---|---|---|
| Polytope + Polytope | Cutting plane | Warm start: Primal |
| Curved set + Any set | Trust region Newton | Warm start: Dual or problem-dependent |
- The code exposes both solver entry points (see the
dgd/dgd.handdgd/solvers/bundle_scheme_impl.hheaders). - Warm-start effectiveness depends on the solver, warm start type, and problem instance.
For the runtime API:
- Warm start is turned off for the trust region Newton solver, as it can be slower than cold start.
- The function
GrowthDistanceautomatically selects a solver based on the problem instance. For more granular control, use the runtime solver entry points or the header-only, templated API.
For the header-only templated API:
- Warm start is not disabled for the trust region Newton solver, but note that it can result in a significant primal infeasibility error (~10e-7).
Header: #include "dgd/error_metrics.h"
Use the provided helpers to validate solver outputs (primal/dual infeasibility and primal-dual gap). Example:
#include "dgd/error_metrics.h"
SolutionError err = ComputeSolutionError(&a, ta, &b, tb, out);
std::cout << "primal infeas: " << err.prim_infeas_err
<< " dual gap: " << err.prim_dual_gap << "\n";Note that, due to the nature of the algorithms, the dual infeasibility error is always zero.
- See
tests/andbenchmarks/for example usages (both runtime and header-only usages are present).
Full example:
// main.cc
#include <iostream>
#include <memory>
#include "dgd/dgd.h" // runtime API (small header)
#include "dgd/error_metrics.h"
#include "dgd/utils/transformations.h"
#include "dgd/geometry/2d/ellipse.h"
#include "dgd/geometry/2d/polygon.h"
#include "dgd/geometry/3d/cone.h"
#include "dgd/geometry/3d/ellipsoid.h"
// OPTIONAL: include this only if you want the header-only, non-virtual API.
// It is heavy; include in translation units where you need max performance and the concrete types are known.
// #include "dgd/solvers/bundle_scheme_impl.h"
using namespace dgd;
int main() {
try {
// 2D example (runtime API)
{
Ellipse a(3.0, 1.5, /*margin=*/0.05);
std::vector<Vec2r> verts = {Vec2r(1.0, 0.0), Vec2r(0.0, 1.0),
Vec2r(-1.0, 0.0), Vec2r(0.0, -1.0)};
Polygon b(verts, /*inradius=*/0.8, /*margin=*/0.0);
Transform2r ta = Transform2r::Identity();
Transform2r tb = Transform2r::Identity();
Affine(tb) += Vec2r::Constant(4.0);
Settings settings;
Output<2> out;
// runtime-dispatch call (small header, virtual dispatch)
Real gd = GrowthDistance(&a, ta, &b, tb, settings, out, false);
std::cout << "[2D] growth distance = " << gd << '\n';
// solution error metrics
SolutionError err = ComputeSolutionError(&a, ta, &b, tb, out);
std::cout << "[2D] primal infeas = " << err.prim_infeas_err
<< " prim-dual gap = " << err.prim_dual_gap << '\n';
// collision detection example
bool coll = DetectCollision(&a, ta, &b, tb, settings, out, false);
std::cout << "[2D] collision? " << (coll ? "yes" : "no") << '\n';
}
// 3D example (runtime API)
{
Cone a(/*radius=*/1.0, /*height=*/2.0, /*margin=*/0.05);
Ellipsoid b(/*rx=*/0.8, /*ry=*/0.6, /*rz=*/1.2, /*margin=*/0.05);
Transform3r ta = Transform3r::Identity();
Transform3r tb = Transform3r::Identity();
Affine(tb) += Vec3r::Constant(0.1);
Settings settings;
Output<3> out;
// runtime-dispatch
Real gd = GrowthDistance(&a, ta, &b, tb, settings, out, false);
std::cout << "[3D] growth distance = " << gd << '\n';
// solution error metrics
SolutionError err = ComputeSolutionError(&a, ta, &b, tb, out);
std::cout << "[3D] primal infeas = " << err.prim_infeas_err
<< " prim dual gap = " << err.prim_dual_gap << '\n';
// collision detection example
bool coll = DetectCollision(&a, ta, &b, tb, settings, out, false);
std::cout << "[3D] collision? " << (coll ? "yes" : "no") << '\n';
}
} catch (const std::exception& e) {
std::cerr << "example failed: " << e.what() << '\n';
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}CMake file:
cmake_minimum_required(VERSION 3.15)
project(DgdExample)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
find_package(Eigen3 5.0 QUIET)
if(NOT Eigen3_FOUND)
find_package(Eigen3 3.4 REQUIRED)
endif()
find_package(dgd REQUIRED)
# Main executable
add_executable(dgd_example "main.cc")
target_link_libraries(dgd_example PRIVATE dgd::dgd)