Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Having sop instance in a per-frame or shared attribute breaks load #4560

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
76 changes: 46 additions & 30 deletions platform/core/src/utils/combineFrameInstance.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { vec3 } from 'gl-matrix';
import { dicomSplit } from './dicomSplit';

/**
* Combine the Per instance frame data, the shared frame data
Expand All @@ -16,23 +17,13 @@ const combineFrameInstance = (frame, instance) => {
SharedFunctionalGroupsSequence,
NumberOfFrames,
SpacingBetweenSlices,
ImageType,
} = instance;

instance.ImageType = dicomSplit(ImageType);

if (PerFrameFunctionalGroupsSequence || NumberOfFrames > 1) {
const frameNumber = Number.parseInt(frame || 1);
const shared = SharedFunctionalGroupsSequence
? Object.values(SharedFunctionalGroupsSequence[0])
.filter(Boolean)
.map(it => it[0])
.filter(it => typeof it === 'object')
: [];

const perFrame = PerFrameFunctionalGroupsSequence
? Object.values(PerFrameFunctionalGroupsSequence[frameNumber - 1])
.filter(Boolean)
.map(it => it[0])
.filter(it => typeof it === 'object')
: [];

// this is to fix NM multiframe datasets with position and orientation
// information inside DetectorInformationSequence
Expand Down Expand Up @@ -73,26 +64,51 @@ const combineFrameInstance = (frame, instance) => {
ImagePositionPatientToUse = [position[0], position[1], position[2]];
}
}

const newInstance = Object.assign(instance, { frameNumber: frameNumber });

// merge the shared first then the per frame to override
[...shared, ...perFrame].forEach(item => {
Object.entries(item).forEach(([key, value]) => {
newInstance[key] = value;
});
});

// Todo: we should cache this combined instance somewhere, maybe add it
// back to the dicomMetaStore so we don't have to do this again.
return {
...newInstance,
ImagePositionPatient: ImagePositionPatientToUse ??
newInstance.ImagePositionPatient ?? [0, 0, frameNumber],
};
const sharedInstance = createCombinedValue(instance, SharedFunctionalGroupsSequence?.[0]);
const newInstance = createCombinedValue(
sharedInstance,
PerFrameFunctionalGroupsSequence?.[frameNumber]
);
newInstance.ImagePositionPatient = ImagePositionPatientToUse ??
newInstance.ImagePositionPatient ?? [0, 0, frameNumber];
newInstance.frameNumber = frameNumber;
return newInstance;
} else {
return instance;
}
};

function createCombinedValue(parent, functionalGroups) {
const newInstance = Object.create(parent);
if (!functionalGroups) {
return newInstance;
}
if (functionalGroups._sharedValue) {
return functionalGroups._sharedValue;
}
const shared = functionalGroups
? Object.values(functionalGroups)
.filter(Boolean)
.map(it => it[0])
.filter(it => typeof it === 'object')
: [];

// merge the shared first then the per frame to override
[...shared].forEach(item => {
if (item.SOPInstanceUID) {
// This sub-item is a previous value information item, so don't merge it
return;
}
Object.entries(item).forEach(([key, value]) => {
newInstance[key] = value;
});
});
Object.defineProperty(functionalGroups, '_sharedValue', {
value: newInstance,
writable: false,
enumerable: false,
});
return newInstance;
}

export default combineFrameInstance;
5 changes: 5 additions & 0 deletions platform/core/src/utils/dicomSplit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function dicomSplit(value) {
return (
(Array.isArray(value) && value) || (typeof value === 'string' && value.split('\\')) || value
);
}
Loading