import {DicomParser} from '../../src/dicom/dicomParser.js';
import {b64urlToArrayBuffer} from '../dicom/utils.js';
import {
AnnotationGroupFactory
} from '../../src/image/annotationGroupFactory.js';
import {Circle} from '../../src/math/circle.js';
import {Ellipse} from '../../src/math/ellipse.js';
import {Line} from '../../src/math/line.js';
import {Point2D} from '../../src/math/point.js';
import {Protractor} from '../../src/math/protractor.js';
import {Rectangle} from '../../src/math/rectangle.js';
import {ROI} from '../../src/math/roi.js';
// doc imports
/* eslint-disable no-unused-vars */
import {AnnotationGroup} from '../../src/image/annotationGroup.js';
/* eslint-enable no-unused-vars */
import dwv034Arrow from './dwv034/sr-arrow.dcm';
import dwv034Circle from './dwv034/sr-circle.dcm';
import dwv034Ellipse from './dwv034/sr-ellipse.dcm';
import dwv034Protractor from './dwv034/sr-protractor.dcm';
import dwv034Rectangle from './dwv034/sr-rectangle.dcm';
import dwv034Roi from './dwv034/sr-roi.dcm';
import dwv034Ruler from './dwv034/sr-ruler.dcm';
import tid1500v0Arrow from './tid1500-0/sr-arrow.dcm';
import tid1500v0Circle from './tid1500-0/sr-circle.dcm';
import tid1500v0Ellipse from './tid1500-0/sr-ellipse.dcm';
import tid1500v0Protractor from './tid1500-0/sr-protractor.dcm';
import tid1500v0Rectangle from './tid1500-0/sr-rectangle.dcm';
import tid1500v0Roi from './tid1500-0/sr-roi.dcm';
import tid1500v0Ruler from './tid1500-0/sr-ruler.dcm';
/**
* Tests for the annotation I/O.
*/
/** @module tests/annotation */
/* global QUnit */
QUnit.module('annotation');
/**
* Get an annotation group from a buffer string.
*
* @param {string} bufferStr The buffer string.
* @returns {AnnotationGroup} The annotation group.
*/
function getAnnotationGroup(bufferStr) {
const dicomParser = new DicomParser();
dicomParser.parse(b64urlToArrayBuffer(bufferStr));
const tags = dicomParser.getDicomElements();
const fac = new AnnotationGroupFactory();
let group;
if (typeof fac.checkElements(tags) === 'undefined') {
group = fac.create(tags);
}
return group;
}
/**
* Check common properties of an annotation group.
*
* @param {AnnotationGroup} annotationGroup The group to check.
* @param {Function} assert The qunit assert.
* @param {string} prefix A message prefix.
*/
function checkGroupCommonProperties(annotationGroup, assert, prefix) {
const annotations = annotationGroup.getList();
const colours = ['#ffff80', '#ffa348', '#ed333b'];
assert.ok(annotationGroup.getLength() === 3,
prefix + ' annotationGroup length');
assert.ok(annotations.length === 3,
prefix + ' annotations length');
for (let i = 0; i < annotations.length; ++i) {
const annotation = annotations[i];
assert.ok(typeof annotation.trackingId !== 'undefined',
prefix + ' annotation ' + i + ' trackingId');
assert.ok(typeof annotation.trackingUid !== 'undefined',
prefix + ' annotation ' + i + ' trackingUid');
assert.ok(typeof annotation.referencedSopClassUID !== 'undefined',
prefix + ' annotation ' + i + ' referencedSopClassUID');
assert.ok(typeof annotation.referencedSopInstanceUID !== 'undefined',
prefix + ' annotation ' + i + ' referencedSopInstanceUID');
assert.ok(typeof annotation.colour !== 'undefined',
prefix + ' annotation ' + i + ' colour');
assert.equal(annotation.colour, colours[i],
prefix + ' annotation ' + i + ' good colour');
assert.ok(typeof annotation.textExpr !== 'undefined',
prefix + ' annotation ' + i + ' textExpr');
if (i === 2) {
assert.ok(typeof annotation.labelPosition !== 'undefined',
prefix + ' annotation ' + i + ' labelPosition');
}
}
}
/**
* Check a quantification.
*
* @param {object} quantification The quantification to check.
* @param {Function} assert The qunit assert.
* @param {string} prefix A message prefix.
*/
function checkQuantification(quantification, assert, prefix) {
assert.ok(typeof quantification.min !== 'undefined',
prefix + ' quantification.min');
assert.ok(typeof quantification.max !== 'undefined',
prefix + ' quantification.max');
assert.ok(typeof quantification.mean !== 'undefined',
prefix + ' quantification.mean');
assert.ok(typeof quantification.surface !== 'undefined',
prefix + ' quantification.surface');
}
/**
* Check an arrow annotation group.
*
* @param {AnnotationGroup} annotationGroup The group to check.
* @param {Function} assert The qunit assert.
*/
function checkArrowGroup(annotationGroup, assert) {
const annotations = annotationGroup.getList();
for (let i = 0; i < annotations.length; ++i) {
const annotation = annotations[i];
const prefix = 'arrow annotation ' + i;
assert.ok(annotation.mathShape instanceof Point2D,
prefix + ' mathShape');
assert.ok(typeof annotation.quantification === 'undefined',
prefix + ' quantification');
if (i !== 0) {
assert.equal(annotation.textExpr, 'label',
prefix + ' annotation ' + i + ' good textExpr');
}
}
}
/**
* Check a circle annotation group.
*
* @param {AnnotationGroup} annotationGroup The group to check.
* @param {Function} assert The qunit assert.
*/
function checkCircleGroup(annotationGroup, assert) {
const annotations = annotationGroup.getList();
for (let i = 0; i < annotations.length; ++i) {
const annotation = annotations[i];
const prefix = 'circle annotation ' + i;
assert.ok(annotation.mathShape instanceof Circle,
prefix + ' mathShape');
assert.equal(annotation.textExpr, '{surface}',
prefix + ' annotation ' + i + ' good textExpr');
assert.ok(typeof annotation.quantification.radius !== 'undefined',
prefix + ' quantification.radius');
const radius = Math.round(
parseFloat(annotation.quantification.radius.value));
assert.equal(radius, 2, prefix + ' radius is ~2');
assert.equal(annotation.quantification.radius.unit, 'unit.mm',
prefix + ' radius unit');
checkQuantification(annotation.quantification, assert, prefix);
}
}
/**
* Check an ellipse annotation group.
*
* @param {AnnotationGroup} annotationGroup The group to check.
* @param {Function} assert The qunit assert.
*/
function checkEllipseGroup(annotationGroup, assert) {
const annotations = annotationGroup.getList();
for (let i = 0; i < annotations.length; ++i) {
const annotation = annotations[i];
const prefix = 'ellipse annotation ' + i;
assert.ok(annotation.mathShape instanceof Ellipse,
prefix + ' mathShape');
assert.equal(annotation.textExpr, '{surface}',
prefix + ' annotation ' + i + ' good textExpr');
assert.ok(typeof annotation.quantification.a !== 'undefined',
prefix + ' quantification.a');
assert.ok(typeof annotation.quantification.b !== 'undefined',
prefix + ' quantification.b');
const radiusA = Math.round(parseFloat(annotation.quantification.a.value));
assert.equal(radiusA, 3, prefix + ' radiusA is ~3');
assert.equal(annotation.quantification.a.unit, 'unit.mm',
prefix + ' radiusA unit');
const radiusB = Math.round(parseFloat(annotation.quantification.b.value));
assert.equal(radiusB, 2, prefix + ' radiusB is ~2');
assert.equal(annotation.quantification.b.unit, 'unit.mm',
prefix + ' radiusB unit');
checkQuantification(annotation.quantification, assert, prefix);
}
}
/**
* Check a protractor annotation group.
*
* @param {AnnotationGroup} annotationGroup The group to check.
* @param {Function} assert The qunit assert.
*/
function checkProtractorGroup(annotationGroup, assert) {
const annotations = annotationGroup.getList();
for (let i = 0; i < annotations.length; ++i) {
const annotation = annotations[i];
const prefix = 'protractor annotation ' + i;
assert.ok(annotation.mathShape instanceof Protractor,
prefix + ' mathShape');
assert.equal(annotation.textExpr, '{angle}',
prefix + ' annotation ' + i + ' good textExpr');
assert.ok(typeof annotation.quantification.angle !== 'undefined',
prefix + ' quantification.angle');
const angle = Math.round(parseFloat(annotation.quantification.angle.value));
assert.equal(angle, 90, prefix + ' angle is ~90');
assert.equal(annotation.quantification.angle.unit, 'unit.degree',
prefix + ' angle unit');
}
}
/**
* Check a rectangle annotation group.
*
* @param {AnnotationGroup} annotationGroup The group to check.
* @param {Function} assert The qunit assert.
*/
function checkRectangleGroup(annotationGroup, assert) {
const annotations = annotationGroup.getList();
for (let i = 0; i < annotations.length; ++i) {
const annotation = annotations[i];
const prefix = 'rectangle annotation ' + i;
assert.ok(annotation.mathShape instanceof Rectangle,
prefix + ' mathShape');
assert.equal(annotation.textExpr, '{surface}',
prefix + ' annotation ' + i + ' good textExpr');
assert.ok(typeof annotation.quantification.width !== 'undefined',
prefix + ' quantification.width');
assert.ok(typeof annotation.quantification.height !== 'undefined',
prefix + ' quantification.height');
const width = Math.round(parseFloat(
annotation.quantification.width.value));
assert.equal(width, 6, prefix + ' width is ~6');
assert.equal(annotation.quantification.width.unit, 'unit.mm',
prefix + ' width unit');
const height = Math.round(parseFloat(
annotation.quantification.height.value));
assert.equal(height, 4, prefix + ' height is ~4');
assert.equal(annotation.quantification.height.unit, 'unit.mm',
prefix + ' height unit');
checkQuantification(annotation.quantification, assert, prefix);
}
}
/**
* Check a roi annotation group.
*
* @param {AnnotationGroup} annotationGroup The group to check.
* @param {Function} assert The qunit assert.
*/
function checkRoiGroup(annotationGroup, assert) {
const annotations = annotationGroup.getList();
for (let i = 0; i < annotations.length; ++i) {
const annotation = annotations[i];
const prefix = 'roi annotation ' + i;
assert.ok(annotation.mathShape instanceof ROI,
prefix + ' mathShape');
if (i !== 0) {
assert.equal(annotation.textExpr, 'label',
prefix + ' annotation ' + i + ' good textExpr');
}
assert.ok(typeof annotation.quantification === 'undefined',
prefix + ' quantification');
}
}
/**
* Check a ruler annotation group.
*
* @param {AnnotationGroup} annotationGroup The group to check.
* @param {Function} assert The qunit assert.
*/
function checkRulerGroup(annotationGroup, assert) {
const annotations = annotationGroup.getList();
for (let i = 0; i < annotations.length; ++i) {
const annotation = annotations[i];
const prefix = 'ruler annotation ' + i;
assert.ok(annotation.mathShape instanceof Line,
prefix + ' mathShape');
assert.equal(annotation.textExpr, '{length}',
prefix + ' annotation ' + i + ' good textExpr');
assert.ok(typeof annotation.quantification.length !== 'undefined',
prefix + ' quantification.length');
const length = Math.round(
parseInt(annotation.quantification.length.value, 10));
assert.equal(length, 4, prefix + ' length is ~4');
assert.equal(annotation.quantification.length.unit, 'unit.mm',
prefix + ' length unit');
}
}
//----------------------------------------------------
// dwv 0.34
//----------------------------------------------------
/**
* Tests for {@link Annotation} from dwv034 containing an arrow.
*
* @function module:tests/annotation~read-dwv034-arrow
*/
QUnit.test('Read dwv034 annotation arrow', function (assert) {
const annotationGroup = getAnnotationGroup(dwv034Arrow);
checkGroupCommonProperties(annotationGroup, assert, 'arrow');
checkArrowGroup(annotationGroup, assert);
});
/**
* Tests for {@link Annotation} from dwv034 containing a circle.
*
* @function module:tests/annotation~read-dwv034-circle
*/
QUnit.test('Read dwv034 annotation circle', function (assert) {
const annotationGroup = getAnnotationGroup(dwv034Circle);
checkGroupCommonProperties(annotationGroup, assert, 'circle');
checkCircleGroup(annotationGroup, assert);
});
/**
* Tests for {@link Annotation} from dwv034 containing a ellipse.
*
* @function module:tests/annotation~read-dwv034-ellipse
*/
QUnit.test('Read dwv034 annotation ellipse', function (assert) {
const annotationGroup = getAnnotationGroup(dwv034Ellipse);
checkGroupCommonProperties(annotationGroup, assert, 'ellipse');
checkEllipseGroup(annotationGroup, assert);
});
/**
* Tests for {@link Annotation} from dwv034 containing a protractor.
*
* @function module:tests/annotation~read-dwv034-protractor
*/
QUnit.test('Read dwv034 annotation protractor', function (assert) {
const annotationGroup = getAnnotationGroup(dwv034Protractor);
checkGroupCommonProperties(annotationGroup, assert, 'protractor');
checkProtractorGroup(annotationGroup, assert);
});
/**
* Tests for {@link Annotation} from dwv034 containing a rectangle.
*
* @function module:tests/annotation~read-dwv034-rectangle
*/
QUnit.test('Read dwv034 annotation rectangle', function (assert) {
const annotationGroup = getAnnotationGroup(dwv034Rectangle);
checkGroupCommonProperties(annotationGroup, assert, 'rectangle');
checkRectangleGroup(annotationGroup, assert);
});
/**
* Tests for {@link Annotation} from dwv034 containing a ROI.
*
* @function module:tests/annotation~read-dwv034-roi
*/
QUnit.test('Read dwv034 annotation roi', function (assert) {
const annotationGroup = getAnnotationGroup(dwv034Roi);
checkGroupCommonProperties(annotationGroup, assert, 'roi');
checkRoiGroup(annotationGroup, assert);
});
/**
* Tests for {@link Annotation} from dwv034 containing a ruler.
*
* @function module:tests/annotation~read-dwv034-ruler
*/
QUnit.test('Read dwv034 annotation ruler', function (assert) {
const annotationGroup = getAnnotationGroup(dwv034Ruler);
checkGroupCommonProperties(annotationGroup, assert, 'ruler');
checkRulerGroup(annotationGroup, assert);
});
//----------------------------------------------------
// TID 1500 v0
//----------------------------------------------------
/**
* Tests for {@link Annotation} from tid1500 v0 containing an arrow.
*
* @function module:tests/annotation~read-tid1500v0-arrow
*/
QUnit.test('Read tid1500 v0 annotation arrow', function (assert) {
const annotationGroup = getAnnotationGroup(tid1500v0Arrow);
checkGroupCommonProperties(annotationGroup, assert, 'arrow');
checkArrowGroup(annotationGroup, assert);
});
/**
* Tests for {@link Annotation} from tid1500 v0 containing a circle.
*
* @function module:tests/annotation~read-tid1500v0-circle
*/
QUnit.test('Read tid1500 v0 annotation circle', function (assert) {
const annotationGroup = getAnnotationGroup(tid1500v0Circle);
checkGroupCommonProperties(annotationGroup, assert, 'circle');
checkCircleGroup(annotationGroup, assert);
});
/**
* Tests for {@link Annotation} from tid1500 v0 containing an ellipse.
*
* @function module:tests/annotation~read-tid1500v0-ellipse
*/
QUnit.test('Read tid1500 v0 annotation ellipse', function (assert) {
const annotationGroup = getAnnotationGroup(tid1500v0Ellipse);
checkGroupCommonProperties(annotationGroup, assert, 'ellipse');
checkEllipseGroup(annotationGroup, assert);
});
/**
* Tests for {@link Annotation} from tid1500 v0 containing a protractor.
*
* @function module:tests/annotation~read-tid1500v0-protractor
*/
QUnit.test('Read tid1500 v0 annotation protractor', function (assert) {
const annotationGroup = getAnnotationGroup(tid1500v0Protractor);
checkGroupCommonProperties(annotationGroup, assert, 'protractor');
checkProtractorGroup(annotationGroup, assert);
});
/**
* Tests for {@link Annotation} from tid1500 v0 containing a rectangle.
*
* @function module:tests/annotation~read-tid1500v0-rectangle
*/
QUnit.test('Read tid1500 v0 annotation rectangle', function (assert) {
const annotationGroup = getAnnotationGroup(tid1500v0Rectangle);
checkGroupCommonProperties(annotationGroup, assert, 'rectangle');
checkRectangleGroup(annotationGroup, assert);
});
/**
* Tests for {@link Annotation} from tid1500 v0 containing a roi.
*
* @function module:tests/annotation~read-tid1500v0-roi
*/
QUnit.test('Read tid1500 v0 annotation roi', function (assert) {
const annotationGroup = getAnnotationGroup(tid1500v0Roi);
checkGroupCommonProperties(annotationGroup, assert, 'roi');
checkRoiGroup(annotationGroup, assert);
});
/**
* Tests for {@link Annotation} from tid1500 v0 containing a ruler.
*
* @function module:tests/annotation~read-tid1500v0-ruler
*/
QUnit.test('Read tid1500 v0 annotation ruler', function (assert) {
const annotationGroup = getAnnotationGroup(tid1500v0Ruler);
checkGroupCommonProperties(annotationGroup, assert, 'ruler');
checkRulerGroup(annotationGroup, assert);
});