189 lines
7.0 KiB
JavaScript
189 lines
7.0 KiB
JavaScript
import { ReactiveVar } from 'meteor/reactive-var';
|
|
import { Tracker } from 'meteor/tracker';
|
|
import { _ } from 'meteor/underscore';
|
|
import { OHIF } from 'meteor/ohif:core';
|
|
import 'meteor/ohif:viewerbase';
|
|
import { CriteriaEvaluator } from './CriteriaEvaluator';
|
|
import * as evaluations from './evaluations';
|
|
|
|
class ConformanceCriteria {
|
|
|
|
constructor(measurementApi, timepointApi) {
|
|
this.measurementApi = measurementApi;
|
|
this.timepointApi = timepointApi;
|
|
this.nonconformities = new ReactiveVar();
|
|
this.groupedNonConformities = new ReactiveVar();
|
|
this.maxTargets = new ReactiveVar(null);
|
|
this.maxNewTargets = new ReactiveVar(null);
|
|
|
|
const validate = _.debounce(trialCriteriaType => this.validate(trialCriteriaType), 300);
|
|
Tracker.autorun(() => {
|
|
const selectedType = OHIF.lesiontracker.TrialCriteriaTypes.findOne({ selected: true });
|
|
this.measurementApi.changeObserver.depend();
|
|
validate(selectedType);
|
|
});
|
|
}
|
|
|
|
validate(trialCriteriaType) {
|
|
return new Promise((resolve, reject) => {
|
|
const baselinePromise = this.getData('baseline');
|
|
const followupPromise = this.getData('followup');
|
|
Promise.all([baselinePromise, followupPromise]).then(values => {
|
|
const [baselineData, followupData] = values;
|
|
const mergedData = {
|
|
targets: [],
|
|
nonTargets: []
|
|
};
|
|
|
|
mergedData.targets = mergedData.targets.concat(baselineData.targets);
|
|
mergedData.targets = mergedData.targets.concat(followupData.targets);
|
|
mergedData.nonTargets = mergedData.nonTargets.concat(baselineData.nonTargets);
|
|
mergedData.nonTargets = mergedData.nonTargets.concat(followupData.nonTargets);
|
|
|
|
this.maxTargets.set(null);
|
|
this.maxNewTargets.set(null);
|
|
const resultBoth = this.validateTimepoint('both', trialCriteriaType, mergedData);
|
|
const resultBaseline = this.validateTimepoint('baseline', trialCriteriaType, baselineData);
|
|
const resultFollowup = this.validateTimepoint('followup', trialCriteriaType, followupData);
|
|
const nonconformities = resultBaseline.concat(resultFollowup).concat(resultBoth);
|
|
const groupedNonConformities = this.groupNonConformities(nonconformities);
|
|
|
|
// Keep both? Group the data only on viewer/measurementTable views?
|
|
// Work with not grouped data (worse lookup performance on measurementTableRow)?
|
|
this.nonconformities.set(nonconformities);
|
|
this.groupedNonConformities.set(groupedNonConformities);
|
|
|
|
resolve(nonconformities);
|
|
});
|
|
});
|
|
}
|
|
|
|
groupNonConformities(nonconformities) {
|
|
const groups = {};
|
|
const toolsGroupsMap = this.measurementApi.toolsGroupsMap;
|
|
|
|
nonconformities.forEach(nonConformity => {
|
|
if (nonConformity.isGlobal) {
|
|
groups.globals = groups.globals || { messages: [] };
|
|
groups.globals.messages.push(nonConformity.message);
|
|
|
|
return;
|
|
}
|
|
|
|
nonConformity.measurements.forEach(measurement => {
|
|
const groupName = toolsGroupsMap[measurement.toolType];
|
|
groups[groupName] = groups[groupName] || { measurementNumbers: {} };
|
|
|
|
const group = groups[groupName];
|
|
const measureNumber = measurement.measurementNumber;
|
|
let measurementNumbers = group.measurementNumbers[measureNumber];
|
|
|
|
if (!measurementNumbers) {
|
|
measurementNumbers = group.measurementNumbers[measureNumber] = {
|
|
messages: [],
|
|
measurements: []
|
|
};
|
|
}
|
|
|
|
measurementNumbers.messages.push(nonConformity.message);
|
|
measurementNumbers.measurements.push(measurement);
|
|
});
|
|
});
|
|
|
|
return groups;
|
|
}
|
|
|
|
validateTimepoint(timepointId, trialCriteriaType, data) {
|
|
const evaluators = this.getEvaluators(timepointId, trialCriteriaType);
|
|
let nonconformities = [];
|
|
|
|
evaluators.forEach(evaluator => {
|
|
const maxTargets = evaluator.getMaxTargets(false);
|
|
const maxNewTargets = evaluator.getMaxTargets(true);
|
|
if (maxTargets) {
|
|
this.maxTargets.set(maxTargets);
|
|
}
|
|
|
|
if (maxNewTargets) {
|
|
this.maxNewTargets.set(maxNewTargets);
|
|
}
|
|
|
|
const result = evaluator.evaluate(data);
|
|
nonconformities = nonconformities.concat(result);
|
|
});
|
|
|
|
return nonconformities;
|
|
}
|
|
|
|
getEvaluators(timepointId, trialCriteriaType) {
|
|
const evaluators = [];
|
|
const trialCriteriaTypeId = trialCriteriaType.id.toLowerCase();
|
|
const evaluation = evaluations[trialCriteriaTypeId];
|
|
|
|
if (evaluation) {
|
|
const evaluationTimepoint = evaluation[timepointId];
|
|
|
|
if (evaluationTimepoint) {
|
|
evaluators.push(new CriteriaEvaluator(evaluationTimepoint));
|
|
}
|
|
}
|
|
|
|
return evaluators;
|
|
}
|
|
|
|
/*
|
|
* Build the data that will be used to do the conformance criteria checks
|
|
*/
|
|
getData(timepointType) {
|
|
return new Promise((resolve, reject) => {
|
|
const data = {
|
|
targets: [],
|
|
nonTargets: []
|
|
};
|
|
|
|
const studyPromises = [];
|
|
|
|
const fillData = measurementType => {
|
|
const measurements = this.measurementApi.fetch(measurementType);
|
|
|
|
measurements.forEach(measurement => {
|
|
const { studyInstanceUid } = measurement;
|
|
|
|
const timepointId = measurement.timepointId;
|
|
const timepoint = timepointId && this.timepointApi.timepoints.findOne({ timepointId });
|
|
|
|
if (!timepoint || ((timepointType !== 'both') && (timepoint.timepointType !== timepointType))) {
|
|
return;
|
|
}
|
|
|
|
const promise = OHIF.studies.loadStudy(studyInstanceUid);
|
|
promise.then(study => {
|
|
const studyMetadata = OHIF.viewerbase.getStudyMetadata(study);
|
|
|
|
data[measurementType].push({
|
|
measurement,
|
|
metadata: studyMetadata.getFirstInstance(),
|
|
timepoint
|
|
});
|
|
});
|
|
studyPromises.push(promise);
|
|
});
|
|
};
|
|
|
|
fillData('targets');
|
|
fillData('nonTargets');
|
|
|
|
Promise.all(studyPromises).then(() => {
|
|
resolve(data);
|
|
}).catch(reject);
|
|
});
|
|
}
|
|
|
|
static setEvaluationDefinitions(evaluationKey, evaluationDefinitions) {
|
|
evaluations[evaluationKey] = evaluationDefinitions;
|
|
}
|
|
|
|
}
|
|
|
|
OHIF.measurements.ConformanceCriteria = ConformanceCriteria;
|