All files / extensions/cornerstone/src/services/ViewportService/backends IViewportBackend.ts

0% Statements 0/0
0% Branches 0/0
0% Functions 0/0
0% Lines 0/0

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196                                                                                                                                                                                                                                                                                                                                                                                                       
import type { Types } from '@cornerstonejs/core';
import type ViewportInfo from '../Viewport';
import type {
  Presentations,
  PositionPresentation,
  LutPresentation,
} from '../../../types/Presentation';
import type { StackViewportData, VolumeViewportData } from '../../../types/CornerstoneCacheService';
import type { DataIdPayload } from './dataIdRegistry';
 
/** A pending overlay (SEG/RTSTRUCT) add produced by the service's prelude. */
export type OverlayMountTask = {
  imageIds?: string[];
  addOverlayFn?: () => Promise<void>;
};
 
/**
 * Everything the service's lane-agnostic stack-mount prelude computes: the
 * backend receives it ready-made and performs only the lane-specific mount.
 */
export interface StackMountContext {
  /** All display set UIDs bound to the viewport (first = the stack source). */
  displaySetInstanceUIDs: string[];
  imageIds: string[];
  /** Resolved initial slice (position presentation / view reference / HP options). */
  initialImageIndex: number;
  /** VOI/invert/colormap seeded from the LUT presentation or display set options. */
  properties: Record<string, unknown>;
  displayArea?: unknown;
  rotation?: number;
  flipHorizontal?: boolean;
  presentations: Presentations;
  viewportInfo: ViewportInfo;
  overlayProcessingResults?: OverlayMountTask[];
}
 
/**
 * Everything the service's lane-agnostic volume-mount prelude computes before
 * the lane fork in setVolumesForViewport.
 */
export interface VolumeMountContext {
  /** Volume inputs with their display set options, overlays already filtered out. */
  filteredVolumeInputArray: Array<{
    volumeInput: {
      imageIds?: string[];
      volumeId: string;
      displaySetInstanceUID: string;
      blendMode?: unknown;
      slabThickness?: number;
      [key: string]: unknown;
    };
    displaySetOptions: unknown;
  }>;
  /** Per-volume VOI/invert/colormap/preset derived from the display set options. */
  volumesProperties: Array<{ properties: Record<string, unknown>; volumeId: string }>;
  viewportInfo: ViewportInfo;
  overlayProcessingResults?: OverlayMountTask[];
  presentations: Presentations;
}
 
/**
 * Selects how OHIF drives cornerstone viewports (migration plan §4.3). One
 * implementation is chosen ONCE, lazily on first use (a `get backend()` getter on
 * CornerstoneViewportService — NOT the constructor, because the service singleton is
 * built during extension registration before init.tsx sets the flag), from
 * `appConfig.useNextViewports`:
 *   - LegacyViewportBackend: today's behavior, selected when the flag is off (default).
 *   - NextViewportBackend: the native GenericViewport ("next") path.
 *
 * The service holds exactly one backend for its lifetime and routes the forked
 * concerns through it: mount dispatch, the per-family MOUNT BODIES
 * (mountStack/mountVolumes/mountEcg/mountOther/remount), presentation
 * capture/restore, and the native dataId lifecycle. The service keeps only the
 * lane-agnostic preludes (option/property derivation, bookkeeping, events) and
 * the genuinely shared volume tail; it contains no per-lane branches itself.
 */
export interface IViewportBackend {
  /**
   * Routes a viewport's data to the correct per-family mount. Legacy routes by the
   * runtime cornerstone viewport type; next routes by the bound data shape, because
   * native stack and volume content both report a single PLANAR_NEXT type (§4.4).
   */
  dispatchMount(
    viewport: Types.IViewport,
    viewportData: StackViewportData | VolumeViewportData,
    viewportInfo: ViewportInfo,
    presentations?: Presentations
  ): Promise<void>;
 
  /**
   * Mounts an image stack. Legacy: setStack/setProperties/setPresentations +
   * displayArea/rotation/flip via the camera surface. Next: register the dataId,
   * setDisplaySets, seed VOI from metadata, apply presentation + view state.
   */
  mountStack(viewport: Types.IStackViewport, context: StackMountContext): Promise<void>;
 
  /**
   * Lane-specific volume mount. Next mounts the volumes natively (registered
   * dataIds + one setDisplaySets call + per-binding presentations) and returns
   * true — the service then only broadcasts. Legacy returns false, and the
   * service runs the shared volume tail (setVolumes/addVolumes optimization,
   * property application, presentations, jumpToSlice), which a native
   * overlay-only mount also traverses safely.
   */
  mountVolumes(viewport: Types.IViewport, context: VolumeMountContext): Promise<boolean>;
 
  /**
   * The shared volume tail's overlay-only fallback: when every volume input is
   * an overlay display set, legacy still mounts them via setVolumes; next
   * no-ops (its overlays are added via the segmentation representations).
   */
  mountOverlayOnlyVolumes(viewport: Types.IViewport, volumeInputArray: unknown[]): Promise<void>;
 
  /**
   * Mounts an ECG waveform. Legacy: viewport.setEcg(imageId). Next: register
   * the display set's dataId and mount through the generic setDisplaySets API.
   */
  mountEcg(
    viewport: Types.IECGViewport,
    displaySet: { displaySetInstanceUID: string; imageIds?: string[] },
    imageId: string
  ): Promise<void>;
 
  /**
   * Mounts video / whole-slide content (the caller applies the view reference
   * afterwards). Legacy keys the displaySetId off imageIds[0]; next registers
   * the family-specific dataId first.
   */
  mountOther(
    viewport: Types.IViewport,
    displaySet: { displaySetInstanceUID: string; imageIds: string[] }
  ): Promise<void>;
 
  /**
   * Re-mounts changed viewport data onto an existing viewport (updateViewport),
   * optionally restoring the camera afterwards. Legacy snapshots getCamera and
   * dispatches by runtime type; next snapshots the semantic view state and
   * routes through dispatchMount. May return undefined when the viewport family
   * has no re-mount path (matching the historical legacy behavior).
   */
  remount(
    viewport: Types.IViewport,
    viewportData: StackViewportData | VolumeViewportData,
    viewportInfo: ViewportInfo,
    keepCamera: boolean
  ): Promise<void> | undefined;
 
  /**
   * Reads the position presentation (camera/zoom/pan + view reference) to persist
   * for restore. Legacy uses getViewPresentation (pan/zoom); native stores the
   * semantic view-state displayArea (pan/zoom) since it has no getViewPresentation.
   */
  getPositionPresentation(
    csViewport: Types.IViewport,
    viewportInfo: ViewportInfo,
    viewportId: string
  ): PositionPresentation;
 
  /**
   * Restores a position presentation. Both apply the view reference (slice/
   * orientation); legacy then applies getViewPresentation via setViewPresentation,
   * native applies the stored displayArea via setViewState.
   */
  setPositionPresentation(
    viewport: Types.IViewport,
    positionPresentation: PositionPresentation
  ): void;
 
  /**
   * Restores a LUT presentation (VOI/colormap/invert). Legacy uses setProperties;
   * native uses setDisplaySetPresentation (a PLANAR_NEXT viewport has no
   * setProperties), so calling setPresentations on native no longer throws.
   */
  setLutPresentation(viewport: Types.IViewport, lutPresentation: LutPresentation): void;
 
  /**
   * Registers a native dataset id for a viewport against cornerstone's global
   * GenericViewport metadata provider (§4.7). Next ref-counts and tracks per
   * viewport so it can be released on unmount; legacy is a no-op (never registers).
   */
  registerDataId(viewportId: string, dataId: string, payload: DataIdPayload): void;
 
  /**
   * Releases the dataset registrations a viewport owns. Called from the service's
   * disableElement BEFORE the viewport bookkeeping is deleted. Next releases (and
   * removes from the provider when the last reference is gone); legacy is a no-op.
   */
  onViewportDisabled(viewportId: string): void;
 
  /**
   * Flushes all remaining registrations. Called from the service's destroy().
   * Next clears its registry; legacy is a no-op.
   */
  destroy(): void;
}