Skip to content

AdvancedMeshService ​

High-performance spatial mesh queries backed by a pluggable provider registry (BVH, Octree, SpatialHash). Sits on top of MeshService and adds contact/proximity neighbour queries, radius search, N-nearest search, raycasting, bounds/frustum intersection, clustering, per-mesh performance analysis, and advanced pipeline stages. The service warms up its broad-phase index lazily and keeps a per-query cache for contact-graph traversals.

Access ​

Registered under the name "advanced-mesh". Depends on mesh.

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

await viewer.ready();
const advancedMesh = viewer.getService<AdvancedMeshService>("advanced-mesh");
await advancedMesh?.warmupSpatialIndex();

Providers are auto-registered at init (spatial-hash, octree, bvh). Call enableProvider(name, config?) to activate one before running queries; the service also auto-enables a broad-phase provider (spatial-hash, falling back to octree) the first time a query needs one.

Public API ​

Lifecycle ​

  • init(context: ServiceContext): Promise<void>
  • destroy(): Promise<void>
  • getStatus(): ServiceStatus
  • configure(config: Partial<AdvancedMeshServiceConfig>): void

Provider management ​

  • registerProvider(factory: SpatialProviderFactory): void
  • enableProvider(name, config?: SpatialProviderConfig): Promise<void>
  • disableProvider(name: string): Promise<void>
  • getAvailableProviders(): string[]
  • getActiveProviders(): string[]
  • getProviderInfo(name: string): any
  • getProviderStats(name: string): any
  • warmupSpatialIndex(): Promise<void> — force-build the broad-phase index before the first interactive query.
  • beginProviderUpdateBatch(): void / endProviderUpdateBatch(options?: { timeBudgetMs?: number }): Promise<void> — batch mesh registration events so providers rebuild once. Contact cache is cleared on flush.

Neighbour queries ​

  • findContactNeighbours(sources: THREE.Object3D[], options?: ContactNeighbourQueryOptions): Promise<ContactNeighbourQueryResult> — BFS through contact graph. Broad-phase AABB filter, followed by sampled BVH proximity check, with optional exact BVH fallback. Results are cached per option-shape until any mesh event fires.
  • findProximityNeighbours(sources: THREE.Object3D[], options: ProximityNeighbourQueryOptions): Promise<SpatialQueryResult[]> — meshes whose bounds land inside a sphere around the source selection (or around each source individually).

Spatial queries ​

  • findMeshesInRadius(center, radius, options?: SpatialQueryOptions): Promise<SpatialQueryResult[]>
  • findNearestMeshes(point, count, options?): Promise<MeshDistanceResult[]>
  • raycast(ray, options?: RaycastOptions): Promise<RaycastResult[]>
  • raycastFirst(ray, options?: RaycastOptions): Promise<RaycastResult | null>
  • findIntersections(bounds: THREE.Box3, options?: SpatialQueryOptions): Promise<IntersectionResult[]>
  • findInFrustum(frustum, options?): Promise<SpatialQueryResult[]>
  • checkCollision(meshA, meshB): Promise<boolean>
  • findCollisions(mesh): Promise<CollisionResult[]>
  • performFrustumCulling(camera, includeOcclusion?): Promise<CullingResult>
  • executeAdvancedQuery(query: AdvancedMeshQuery): Promise<SpatialQueryResult[]>

Clustering and analysis ​

  • clusterMeshes(algorithm?: ClusteringAlgorithm, parameters?: any): Promise<MeshCluster[]> — built-in algorithms: SPATIAL_PROXIMITY, MATERIAL_BASED, SIZE_BASED.
  • analyzeMeshPerformance(meshes?): Promise<MeshPerformanceAnalysis[]>
  • getPerformanceStats(): { totalQueries; averageQueryTime; memoryUsage; activeSpatialStructures; contactGraphCacheEntries; activeProviders; providerStats }

Pipeline stages ​

AdvancedPipelineStage extends the mesh processing pipeline with:

ts
enum AdvancedPipelineStage {
  BVH_BUILD = "bvh-build",
  CLUSTERING = "clustering",
  LOD_GENERATE = "lod-generate",
  PERFORMANCE_ANALYSIS = "performance-analysis",
  QUALITY_ANALYSIS = "quality-analysis",
}

The service registers a default PERFORMANCE_ANALYSIS handler that attaches per-mesh analysis onto XViewerMeshMetadata.performanceAnalysis when performanceMonitoring is enabled.

Types ​

ts
interface ContactNeighbourQueryOptions extends SpatialQueryOptions {
  depth?: number;                  // BFS depth (default 1)
  thresholdMm?: number;            // contact gap tolerance in mm (default 0)
  worldUnitsPerMillimeter?: number; // scale from mm to world units (default 1)
  precise?: boolean;               // run BVH sampled check (default true)
  exactFallback?: boolean;         // exact BVH-vs-BVH check on miss (default false)
  maxSampledVertices?: number;     // per-mesh sampling cap (default 96)
  includeHidden?: boolean;
  maxCandidatesPerSource?: number;
  maxPreciseChecks?: number;
  useCache?: boolean;              // default true
  debug?: boolean;                 // log per-query stats
}

interface ContactNeighbourQueryResult {
  neighbours: THREE.Object3D[];
  stats: ContactNeighbourQueryStats;
}

interface ContactNeighbourQueryStats {
  depth: number;
  thresholdWorld: number;
  sources: number;
  broadPhaseProvider: string | null;
  broadPhaseCandidates: number;
  preciseChecks: number;
  sampledChecks: number;
  exactChecks: number;
  cacheHits: number;
  cacheMisses: number;
  bvhBuilds: number;
  queryTimeMs: number;
  sourceBreakdown: ContactNeighbourSourceStats[];
}

interface ProximityNeighbourQueryOptions extends SpatialQueryOptions {
  radius: number;
  centerMode?: "selection" | "individual"; // union vs. per-source spheres
  includeHidden?: boolean;
}

interface SpatialQueryOptions {
  includeMetadata?: boolean;
  sortBy?: "distance" | "size" | "name" | "layer";
  sortOrder?: "asc" | "desc";
  maxResults?: number;
  filterPredicate?: (
    mesh: THREE.Object3D,
    metadata?: XViewerMeshMetadata,
  ) => boolean;
}

Cache invalidation ​

The contact-neighbour cache is cleared automatically when:

  • mesh:registered, mesh:unregistered, or mesh:updated fires on the event bus.
  • mesh:display-updated fires (visibility or material change).
  • endProviderUpdateBatch() flushes queued provider updates.

Events ​

EventPayload
advanced-mesh:provider-registered{ provider, capabilities }
advanced-mesh:provider-initialized{ provider, meshCount, initTime }
advanced-mesh:contact-neighbours-queried{ sources, neighbours, stats }
advanced-mesh:clustering-completed{ algorithm, clusterCount, processingTime }
advanced-mesh:performance-analysis-complete{ totalMeshes, analysisTime, recommendations }

Example ​

ts
const advancedMesh = viewer.getService<AdvancedMeshService>("advanced-mesh");
if (!advancedMesh) return;

// Ensure the broad-phase index is ready before running interactive queries.
await advancedMesh.warmupSpatialIndex();

// Batch mesh registrations so providers rebuild once.
advancedMesh.beginProviderUpdateBatch();
await loader.loadGlbDetachedBatch(urls);
await advancedMesh.endProviderUpdateBatch({ timeBudgetMs: 20 });

// Contact-graph BFS with a 0.5 mm gap tolerance.
const { neighbours, stats } = await advancedMesh.findContactNeighbours(
  selection,
  { depth: 2, thresholdMm: 0.5, precise: true, exactFallback: false },
);
console.log(neighbours.length, "contact neighbours in", stats.queryTimeMs, "ms");

// Anything within 25 mm of the selection centroid.
const nearby = await advancedMesh.findProximityNeighbours(selection, {
  radius: 25,
  centerMode: "selection",
});

XViewr SDK and xConvert CLI documentation.