ohif-viewer/extensions/dicom-microscopy/src/utils/RoiAnnotation.js

197 lines
4.7 KiB
JavaScript
Raw Normal View History

feat(microscopy): add dicom microscopy extension and mode (#3247) * skeleton for dicom-microscopy extension * skeleton for microscopy mode * [feat] ported @radicalimaging/microscopy-dicom to OHIF's default extension * [feat] ported microscopy mode from private repo * added new definitions to the package.json * webpack configuration update for microscopy extension * register new icons for microscopy tools * fixes to the microscopy extension and mode * trivial error fix - typescript type import error * link microscopy extension with default OHIF app plugin config * demo config fix * fix logs * remove unsed imports * [fix] loading of microscopy * [fix] webworker script loading, normalizing denaturalized dataset * found the latest version of dicom-microscopy-viewer that works with current OHIF extension : 0.35.2 * hide thumbnail pane by default, as we have issues with * comments * remove unused code * [feat] microscopy - annotation selection * [feat] microscopy - edit annotation label * wip * [bugfix] dicom-microscopy tool * [bugfix] dicom microscopy annotations * [fix] mixed-content blocking caused by BulkDataURI * [fix] microscopy measurements panel - center button * [fix] microscopy measurements panel - styling * [fix] microscopy - controls * fix local loading of microscopy * fix local loading of dicom microscopy * fix typo - indexof to indexOf * [fix] remove unused icons * remove commented out lines from webpack configuration * platform/viewer/public/config/default.js - revert accidental changes * [refactor] redirecting to microscopy mode on Local mode * attribution to DMV and SLIM viewer * [fix] code review feedbacks * fix thumbnails * [fix] microscopy - fix old publisher.publish() to PubSubService._broadcastEvent() * [fix] interactions, webpack config, roi selection * [feat] microscopy - remove select tool from UI * microscopy author * [fix] saving and loading SR * [bugfix] - missing publish() function in MicroscopyService, replace with _broadcastEvent * remove author section from readme * refactor SR saving feature * fix webpack config after merge * [bugfix] repeated import * fix e2e * webpack configuration * hide "Create report" button for microscopy
2023-04-28 02:53:52 +02:00
import areaOfPolygon from './areaOfPolygon';
import { PubSubService } from '@ohif/core';
const EVENTS = {
LABEL_UPDATED: 'labelUpdated',
GRAPHIC_UPDATED: 'graphicUpdated',
VIEW_UPDATED: 'viewUpdated',
REMOVED: 'removed',
};
/**
* Represents a single annotation for the Microscopy Viewer
*/
class RoiAnnotation extends PubSubService {
constructor(
roiGraphic,
studyInstanceUID,
seriesInstanceUID,
label = '',
viewState = null
) {
super(EVENTS);
this.uid = roiGraphic.uid;
this.roiGraphic = roiGraphic;
this.studyInstanceUID = studyInstanceUID;
this.seriesInstanceUID = seriesInstanceUID;
this.label = label;
this.viewState = viewState;
this.setMeasurements(roiGraphic);
}
getScoord3d() {
const roiGraphic = this.roiGraphic;
const roiGraphicSymbols = Object.getOwnPropertySymbols(roiGraphic);
const _scoord3d = roiGraphicSymbols.find(
s => String(s) === 'Symbol(scoord3d)'
);
return roiGraphic[_scoord3d];
}
getCoordinates() {
const scoord3d = this.getScoord3d();
const scoord3dSymbols = Object.getOwnPropertySymbols(scoord3d);
const _coordinates = scoord3dSymbols.find(
s => String(s) === 'Symbol(coordinates)'
);
const coordinates = scoord3d[_coordinates];
return coordinates;
}
/**
* When called will trigger the REMOVED event
*/
destroy() {
this._broadcastEvent(EVENTS.REMOVED, this);
}
/**
* Updates the ROI graphic for the annotation and triggers the GRAPHIC_UPDATED
* event
*
* @param {Object} roiGraphic
*/
setRoiGraphic(roiGraphic) {
this.roiGraphic = roiGraphic;
this.setMeasurements();
this._broadcastEvent(EVENTS.GRAPHIC_UPDATED, this);
}
/**
* Update ROI measurement values based on its scoord3d coordinates.
*
* @returns {void}
*/
setMeasurements() {
const type = this.roiGraphic.scoord3d.graphicType;
const coordinates = this.roiGraphic.scoord3d.graphicData;
switch (type) {
case 'ELLIPSE':
// This is a circle so only need one side
const point1 = coordinates[0];
const point2 = coordinates[1];
let xLength2 = point2[0] - point1[0];
let yLength2 = point2[1] - point1[1];
xLength2 *= xLength2;
yLength2 *= yLength2;
const length = Math.sqrt(xLength2 + yLength2);
const radius = length / 2;
const areaEllipse = Math.PI * radius * radius;
this._area = areaEllipse;
this._length = undefined;
break;
case 'POLYGON':
const areaPolygon = areaOfPolygon(coordinates);
this._area = areaPolygon;
this._length = undefined;
break;
case 'POINT':
this._area = undefined;
this._length = undefined;
break;
case 'POLYLINE':
let len = 0;
for (let i = 1; i < coordinates.length; i++) {
const p1 = coordinates[i - 1];
const p2 = coordinates[i];
let xLen = p2[0] - p1[0];
let yLen = p2[1] - p1[1];
xLen *= xLen;
yLen *= yLen;
len += Math.sqrt(xLen + yLen);
}
this._area = undefined;
this._length = len;
break;
}
}
/**
* Update the OpenLayer Map's view state for the annotation and triggers the
* VIEW_UPDATED event
*
* @param {Object} viewState The new view state for the annotation
*/
setViewState(viewState) {
this.viewState = viewState;
this._broadcastEvent(EVENTS.VIEW_UPDATED, this);
}
/**
* Update the label for the annotation and triggers the LABEL_UPDATED event
*
* @param {String} label New label for the annotation
*/
setLabel(label, finding) {
this.label = label || (finding && finding.CodeMeaning);
this.finding = finding || {
CodingSchemeDesignator: '@ohif/extension-dicom-microscopy',
CodeValue: label,
CodeMeaning: label,
};
this._broadcastEvent(EVENTS.LABEL_UPDATED, this);
}
/**
* Returns the geometry type of the annotation concatenated with the label
* defined for the annotation.
* Difference with getDetailedLabel() is that this will return empty string for empy
* label.
*
* @returns {String} Text with geometry type and label
*/
getLabel() {
const label = this.label ? `${this.label}` : '';
return label;
}
/**
* Returns the geometry type of the annotation concatenated with the label
* defined for the annotation
*
* @returns {String} Text with geometry type and label
*/
getDetailedLabel() {
const label = this.label ? `${this.label}` : '(empty)';
return label;
}
getLength() {
return this._length;
}
getArea() {
return this._area;
}
}
export { EVENTS };
export default RoiAnnotation;