Skip to content

MeasurementService ​

Manages 3D measurements (distance, angle, area, multi-point, bounding box, volume, circle, arc) using a descriptor-based type system. Owns measurement state, raycasting, and point interaction; rendering and label layout are owned by the per-type descriptors.

Access ​

Registered under the name "measurement" on ViewerCore.

ts
import { MeasurementService } from "@optellix/xviewr-sdk";

await viewer.ready();
const measurement = viewer.getService<MeasurementService>("measurement");

Since 4.0 ​

  • Spline measurement mode (splineDescriptor, SplineResult) — variable-point Catmull-Rom sampling with computed arc length.
  • STEP-edge measurement modes (stepEdgeLengthDescriptor, StepEdgeLengthResult, StepMeasurementCandidate) with StepMeasurementSubMode sub-modes: coordinate, single-edge-length, multi-edge-length, linear-point-to-point, linear-point-to-edge, linear-point-to-circle. StepMeasurementPointKind is "edge-start" | "edge-end".
  • Async volume measurement: computeVolumeMeasurementAsync(objects, options) plus AsyncVolumeMeasurementOptions (signal: AbortSignal, onProgress, yieldEvery, useWorker) and VolumeMeasurementProgress (phase: "collect" | "analyze" | "integrate" | "complete", ratio).
  • Edge snapping: MeasurementConfig.edgeSnap and edgeSnapPixelThreshold snap points to loaded STEP edge overlays when the pointer is within N screen pixels of an edge. A parallel contourSnapPixelThreshold snaps to the active section contour.
  • Display-unit formatting: MeasurementConfig.displayUnit and setDisplayUnit(unit: Partial<MeasurementDisplayUnit>) control label scale, length suffix, area/volume suffixes, and precision.
  • setStepMeasurementMode(mode) / getStepMeasurementMode() — toggle STEP sub-mode independently of the main measurement mode.

Public API ​

Lifecycle ​

  • activate(): void — turn on pointer-driven measurement placement.
  • deactivate(): void — turn off placement and detach listeners.
  • reset(): void — clear all measurements and pending points.

Configuration ​

  • getConfig(): MeasurementConfig
  • updateConfig(config: Partial<MeasurementConfig>): void
  • setMeasurementMode(mode: string): void — "distance", "angle", "area", "multipoint", "aabb", "obb", "volume", "circle", "arc", or any registered descriptor name.
  • getMeasurementMode(): string

Points ​

  • addPoint(point: THREE.Vector3, hitMesh?: THREE.Mesh | null, hitFace?: number | null): void
  • setTemporaryPoint(point: THREE.Vector3 | null): void
  • getAllPoints(): THREE.Vector3[]
  • getCurrentPoints(): THREE.Vector3[]
  • getTemporaryPoint(): THREE.Vector3 | null
  • updatePointer(x: number, y: number): void — canvas-relative coords.
  • raycast(): THREE.Intersection | null

Measurements ​

  • createMeasurement(points: THREE.Vector3[], type?: string): Measurement — type defaults to "distance".
  • createMeasurementWithResult(points: THREE.Vector3[], type: string, result: MeasurementResultValue): Measurement
  • measureVolume(objects: THREE.Object3D[], options?: VolumeMeasurementOptions): Measurement | null
  • completeMeasurement(): Promise<void> — manual finalize for variable-point modes (area, multipoint).
  • getMeasurements(): Measurement[]
  • removeMeasurement(id: string): boolean
  • setMeasurementVisibility(id: string, visible: boolean): boolean
  • updateMeasurementPoint(measurementId: string, pointIndex: number, point: THREE.Vector3): boolean

Descriptors ​

  • registerDescriptor(descriptor: MeasurementTypeDescriptor): void
  • getDescriptor(name: string): MeasurementTypeDescriptor | undefined

Built-in descriptors exported from the SDK: distanceDescriptor, angleDescriptor, areaDescriptor, multiPointDescriptor, splineDescriptor, aabbDescriptor, obbDescriptor, volumeDescriptor, circleDescriptor, arcDescriptor, stepEdgeLengthDescriptor. Bounding-box computers: AABBComputer, OBBComputer. Volume helpers: computeVolumeMeasurement(objects, options), computeVolumeMeasurementAsync(objects, options), normalizeVolumeOptions(options).

Events ​

EventPayload
measurement:activatednull
measurement:deactivatednull
measurement:config-updated{ config: MeasurementConfig }
measurement:point-added{ point, totalPoints }
measurement:temporary-point-changed{ point }
measurement:created{ measurement }
measurement:volume-created{ measurement, options }
measurement:removed{ measurement }
measurement:visibility-changed{ id, visible }
measurement:reset{ clearedMeasurements }
measurement:in-progress{ mode, pointCount, canComplete }
measurement:mode-changed{ mode, requiredPoints }
measurement:point-updated{ measurement }
measurement:hover-point{ measurementId, pointIndex } | null

Example ​

ts
const measurement = viewer.getService<MeasurementService>("measurement");

measurement.setMeasurementMode("distance");
measurement.activate();

viewer.eventBus.on("measurement:created", ({ measurement: m }) => {
  if (m.result.type === "distance") {
    console.log(`distance: ${m.result.distance.toFixed(2)}`);
  }
});

// Programmatic volume measurement on a selection.
const volume = measurement.measureVolume(selectedObjects, {
  method: "auto",
  voxelResolution: 64,
});

Configuration ​

ts
interface MeasurementConfig {
  textScalingFactor: number;       // label scale base
  raycastThreshold: number;
  sectionEnabled: boolean;         // limit raycast to contour objects
  contourObjects: THREE.Object3D | THREE.Object3D[] | null;
  selectableOnly: boolean;         // only raycast userData.isSelectable
  measurementMode: string;
  autoCreateMeasurements: boolean; // finalize when requiredPoints reached
  showComponents: boolean;         // render dx/dy/dz legs on 2-point distance
  surfaceSnap: boolean;            // drape distance/multipoint along mesh
  volumeMeasurement: VolumeMeasurementOptions;
}

interface VolumeMeasurementOptions {
  method?: "auto" | "tetrahedron" | "voxel";
  voxelResolution?: number;        // default 48
  voxelMaxCells?: number;          // default 250000
  voxelSampleMode?: "center" | "corners";
  voxelAxisVotes?: boolean;        // 3-axis parity voting
  watertightTolerance?: number;    // default 1e-5
}

Result types ​

MeasurementResultValue is the union of DistanceResult, AngleResult, AreaResult, MultiPointResult, BoundingBoxResult, VolumeResult, CircleResult, ArcResult. Each carries a type discriminator matching the descriptor name.

XViewr SDK and xConvert CLI documentation.