UNPKG

@cornerstonejs/core

Version:
122 lines (121 loc) 4.57 kB
import { computeECGChannelLayouts, getVisibleECGChannels, } from '../../../utilities/ECGUtilities.js'; import ResolvedViewportView from '../ResolvedViewportView.js'; import { getAnchorWorldForCanvasPoint, getAnchorWorldForPan, resolveECGCanvasMapping, getPanForECGCanvasMapping, } from './ecgViewportCamera.js'; class ECGResolvedView extends ResolvedViewportView { get zoom() { return Math.max(this.state.viewState.scale ?? 1, 0.001); } get pan() { return getPanForECGCanvasMapping(this.getCanvasMapping()); } canvasToWorld(canvasPos) { const mapping = this.getCanvasMapping(); const channelLayouts = this.getChannelLayouts(); const subCanvasPos = [ (canvasPos[0] - mapping.xOffset) / mapping.effectiveRatio, (canvasPos[1] - mapping.yOffset) / mapping.effectiveRatio, ]; let z = 0; for (let index = 0; index < channelLayouts.length; index++) { const channelLayout = channelLayouts[index]; if (subCanvasPos[1] <= channelLayout.yOffset || index === channelLayouts.length - 1) { z = index; break; } } const channelLayout = channelLayouts[z]; return [ Math.max(0, Math.min(this.state.waveform.numberOfSamples - 1, (subCanvasPos[0] * this.state.waveform.numberOfSamples) / this.state.metrics.ecgWidth)), (channelLayout.baseline - subCanvasPos[1]) / this.state.metrics.channelScale, z, ]; } worldToCanvas(worldPos) { const mapping = this.getCanvasMapping(); const channelLayouts = this.getChannelLayouts(); const z = Math.round(worldPos[2]); if (z < 0 || z >= channelLayouts.length) { return [0, 0]; } return [ (worldPos[0] / this.state.waveform.numberOfSamples) * this.state.metrics.ecgWidth * mapping.effectiveRatio + mapping.xOffset, (channelLayouts[z].baseline - worldPos[1] * this.state.metrics.channelScale) * mapping.effectiveRatio + mapping.yOffset, ]; } getFrameOfReferenceUID() { return this.state.frameOfReferenceUID; } withZoom(zoom, canvasPoint) { const nextZoom = Math.max(zoom, 0.001); if (!canvasPoint) { return this.cloneWithViewState({ ...this.state.viewState, scale: nextZoom, scaleMode: 'fit', }); } return this.cloneWithViewState({ ...this.state.viewState, anchorWorld: getAnchorWorldForCanvasPoint(canvasPoint, this.getCanvasMapping()), anchorCanvas: [ canvasPoint[0] / Math.max(this.state.canvas.clientWidth, 1), canvasPoint[1] / Math.max(this.state.canvas.clientHeight, 1), ], scale: nextZoom, scaleMode: 'fit', }); } withPan(pan) { return this.cloneWithViewState({ ...this.state.viewState, anchorWorld: getAnchorWorldForPan([pan[0], pan[1]], this.getCanvasMapping()), }); } buildICamera() { const mapping = this.getCanvasMapping(); const canvasCenter = [ this.state.canvas.clientWidth / 2, this.state.canvas.clientHeight / 2, ]; return { parallelProjection: true, focalPoint: this.canvasToWorld(canvasCenter), position: [0, 0, 0], viewUp: [0, -1, 0], parallelScale: this.state.canvas.clientHeight / 2 / Math.max(mapping.effectiveRatio, 0.001), viewPlaneNormal: [0, 0, 1], }; } getCanvasMapping() { this.cachedCanvasMapping ||= resolveECGCanvasMapping({ canvas: this.state.canvas, camera: this.state.viewState, metrics: this.state.metrics, }); return this.cachedCanvasMapping; } getChannelLayouts() { return computeECGChannelLayouts({ visibleChannels: getVisibleECGChannels(this.state.waveform.channels, this.state.dataPresentation?.visibleChannels), channelScale: this.state.metrics.channelScale, }); } cloneWithViewState(viewState) { return new ECGResolvedView({ ...this.state, viewState, }); } } export default ECGResolvedView;