LT-92: Adding checks for measurements length
This commit is contained in:
parent
a6cea542b7
commit
e3b8dd001a
@ -11,23 +11,16 @@ export class RecistChecker extends BaseChecker {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.criterias.push(new MaxTargetsCriteria(5));
|
||||
this.criterias.push(new MaxTargetPerOrganCriteria(2));
|
||||
this.criterias.push(new MeasurementsLengthCriteria({}));
|
||||
this.criterias.push(new ModalityCriteria(this.getModalityCriteriaOptions()));
|
||||
this.criterias.push(new NonTargetResponseCriteria());
|
||||
this.criterias.push(new TargetTypeCriteria());
|
||||
}
|
||||
const addCriteria = criteria => this.criterias.push(criteria);
|
||||
|
||||
check(data) {
|
||||
const nonconformity = [];
|
||||
this.criterias.forEach(criteria => {
|
||||
const criteriaResult = criteria.check(data);
|
||||
if (!criteriaResult.passed) {
|
||||
nonconformity.push(criteriaResult);
|
||||
}
|
||||
});
|
||||
return nonconformity;
|
||||
addCriteria(new MaxTargetsCriteria(5));
|
||||
addCriteria(new MaxTargetPerOrganCriteria(2));
|
||||
addCriteria(new ModalityCriteria(this.getModalityCriteriaOptions()));
|
||||
addCriteria(new NonTargetResponseCriteria());
|
||||
addCriteria(new TargetTypeCriteria());
|
||||
addCriteria(new MeasurementsLengthCriteria(this.getExtranodalLengthCriteriaOptions()));
|
||||
addCriteria(new MeasurementsLengthCriteria(this.getExtranodalXrayLengthCriteriaOptions()));
|
||||
addCriteria(new MeasurementsLengthCriteria(this.getNodalLengthCriteriaOptions()));
|
||||
}
|
||||
|
||||
getModalityCriteriaOptions() {
|
||||
@ -37,4 +30,37 @@ export class RecistChecker extends BaseChecker {
|
||||
};
|
||||
}
|
||||
|
||||
getExtranodalLengthCriteriaOptions() {
|
||||
return {
|
||||
longAxis: 10,
|
||||
longAxisSliceThicknessMultiplier: 2,
|
||||
modalityIn: ['CT', 'MR'],
|
||||
locationNotIn: ['Lymph Node'],
|
||||
message: 'Extranodal lesions must be >= 10mm long axis AND ' +
|
||||
'>= double the acquisition slice thickness by CT and MR'
|
||||
};
|
||||
}
|
||||
|
||||
getExtranodalXrayLengthCriteriaOptions() {
|
||||
return {
|
||||
shortAxis: 20,
|
||||
longAxis: 20,
|
||||
modalityIn: ['PX', 'XA'],
|
||||
locationNotIn: ['Lymph Node'],
|
||||
message: 'Extranodal lesions must be >= 20mm on chest x-ray ' +
|
||||
'(although x-rays rarely used for clinical trial assessment)'
|
||||
};
|
||||
}
|
||||
|
||||
getNodalLengthCriteriaOptions() {
|
||||
return {
|
||||
shortAxis: 15,
|
||||
shortAxisSliceThicknessMultiplier: 2,
|
||||
modalityIn: ['CT', 'MR'],
|
||||
locationIn: ['Lymph Node'],
|
||||
message: 'Nodal lesions must be >= 15mm short axis AND ' +
|
||||
'>= double the acquisition slice thickness by CT and MR'
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -4,20 +4,50 @@ export class MeasurementsLengthCriteria extends BaseCriteria {
|
||||
|
||||
constructor(options) {
|
||||
super();
|
||||
options = {
|
||||
shortAxis: 10,
|
||||
longAxis: 10,
|
||||
shortAxisSliceThicknessMultiplier: 2,
|
||||
longAxisSliceThicknessMultiplier: 2,
|
||||
modalitiesIn: ['CT', 'MR'],
|
||||
locationNotIn: ['Lymph Node']
|
||||
};
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
check(data) {
|
||||
let message;
|
||||
let measurements = [];
|
||||
const { options } = this;
|
||||
const longMultiplier = options.longAxisSliceThicknessMultiplier;
|
||||
const shortMultiplier = options.shortAxisSliceThicknessMultiplier;
|
||||
|
||||
data.targets.forEach(item => {
|
||||
const { measurement, metadata } = item;
|
||||
const { location, longestDiameter, shortestDiameter } = measurement;
|
||||
const { sliceThickness } = metadata;
|
||||
const modality = metadata.modality.toUpperCase();
|
||||
|
||||
// Stop here if the measurement does not match the modality and location filters
|
||||
if (options.locationIn && options.locationIn.indexOf(location) === -1) return;
|
||||
if (options.modalityIn && options.modalityIn.indexOf(modality) === -1) return;
|
||||
if (options.locationNotIn && options.locationNotIn.indexOf(location) > -1) return;
|
||||
if (options.modalityNotIn && options.modalityNotIn.indexOf(modality) > -1) return;
|
||||
|
||||
// Check the measurement length
|
||||
const failed = (
|
||||
(options.longAxis && longestDiameter < options.longAxis) ||
|
||||
(options.shortAxis && shortestDiameter < options.shortAxis) || (
|
||||
longMultiplier && !isNaN(sliceThickness) &&
|
||||
longestDiameter < (longMultiplier * sliceThickness)
|
||||
) || (
|
||||
shortMultiplier && !isNaN(sliceThickness) &&
|
||||
shortestDiameter < (shortMultiplier * sliceThickness)
|
||||
)
|
||||
);
|
||||
|
||||
// Mark this measurement as invalid if some of the checks have failed
|
||||
if (failed) {
|
||||
measurements.push(measurement);
|
||||
}
|
||||
});
|
||||
|
||||
// Use the options' message if some measurement is invalid
|
||||
if (measurements.length) {
|
||||
message = options.message;
|
||||
}
|
||||
|
||||
return this.respond(message, measurements);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user