Camera Tour Planner

Builds camera waypoint sequences for building walkthroughs. The planner extracts spaces and portals, samples viewpoints, orders them, then smooths the result into a CameraTour. Inspired by Liu, Xu & Sun (2012), "Automatic camera path planning for IFC building models" (Automation in Construction).

Pipeline:

  1. Extract spaces + door portals from the source (default: IFC semantic walk over a paired DataModel).
  2. Sample candidate viewpoints inside each space, scored by visibility coverage.
  3. Plan the tour order. The default starts with a greedy nearest-neighbour pass and refines with 2-opt. Pass planTourGreedy to skip refinement.
  4. Smooth the stops into a waypoint list ready for CameraPath + CameraPathAnimation playback.

The planner returns data only. playCameraTour applies a tour to a View's Camera, so tours can be planned server-side and loaded with a model.

Source files are bucketed into graph/ (the space + viewpoint graph types), plan/ (planning entry point + result/options types), build/ (the smoothing leg), and play/ (playback runtime). The strategy subdirs (extractors/, samplers/, planners/) and internal/ are part of the same module. The public symbols are re-exported from this barrel.

Three steps: plan, play, then drive the playback handle from UI.

import {
planCameraTour,
playCameraTour,
extractSpacesFromGeometry,
} from "@xeokit/sdk/presentations/cameraTour";

Planning is data-only. The IFC space extractor is the default; pass extractor: extractSpacesFromGeometry for non-IFC sources.

const planResult = await planCameraTour({
sceneModel: scene.models["building"],
dataModel: data.models["building"],
options: {
samplesPerSpace: 8,
dwellSeconds: 2.5,
transitionSeconds: 1.5,
},
});

if (!planResult.ok) throw new Error(planResult.error);
const tour = planResult.value;

Drives the View's Camera through the planned waypoints and returns a CameraTourPlayback handle for pause, seek, and disposal.

const playResult = playCameraTour(view, tour, {
rate: 1.0,
loop: false,
onWaypoint: (i, w) => console.log(`Now in ${w.spaceLabel}`),
});

if (!playResult.ok) throw new Error(playResult.error);
const playback = playResult.value;

Wire the playback handle to the host UI.

pauseBtn.onclick   = () => playback.pause();
playBtn.onclick = () => playback.play();
seekSlider.oninput = () => {
playback.progress = +seekSlider.value / 100;
};

For glTF, OBJ, dotbim, or other sources without IfcSpace metadata, use the geometry-only extractor.

const planResult = await planCameraTour({
sceneModel: scene.models["mesh-only"],
extractor: extractSpacesFromGeometry,
});

Interfaces

BuildTourWaypointsInput
BuildTourWaypointsResult
CameraTour
CameraTourPlanOptions
CameraTourPlanParams
CameraTourPlayback
CameraTourWaypoint
PlayCameraTourOptions
SpaceExtractor
SpaceExtractorInput
SpaceGraph
SpaceGraphEdge
SpaceGraphNode
TourPlanner
TourPlannerInput
TourPlanResult
TourStop
ViewpointGraph
ViewpointGraphNode
ViewpointSampler
ViewpointSamplerInput

Variables

extractSpacesFromGeometry
extractSpacesFromIfc
planTourGreedy
planTourTwoOpt
sampleVisibilityGrid

Functions

buildTourWaypoints
planCameraTour
playCameraTour