682 lines
15 KiB
TypeScript
682 lines
15 KiB
TypeScript
const DEFAULT_COLORMAP = '2hot';
|
|
const toolGroupIds = {
|
|
pt: 'dynamic4D-pt',
|
|
fusion: 'dynamic4D-fusion',
|
|
ct: 'dynamic4D-ct',
|
|
};
|
|
|
|
function getPTOptions({
|
|
colormap,
|
|
voiInverted,
|
|
}: {
|
|
colormap?: {
|
|
name: string;
|
|
opacity:
|
|
| number
|
|
| {
|
|
value: number;
|
|
opacity: number;
|
|
}[];
|
|
};
|
|
voiInverted?: boolean;
|
|
} = {}) {
|
|
return {
|
|
blendMode: 'MIP',
|
|
colormap,
|
|
voi: {
|
|
windowWidth: 5,
|
|
windowCenter: 2.5,
|
|
},
|
|
voiInverted,
|
|
};
|
|
}
|
|
|
|
function getPTViewports() {
|
|
const ptOptionsParams = {
|
|
colormap: {
|
|
name: DEFAULT_COLORMAP,
|
|
opacity: [
|
|
{ value: 0, opacity: 0 },
|
|
{ value: 0.1, opacity: 1 },
|
|
{ value: 1, opacity: 1 },
|
|
],
|
|
},
|
|
voiInverted: false,
|
|
};
|
|
|
|
return [
|
|
{
|
|
viewportOptions: {
|
|
viewportId: 'ptAxial',
|
|
viewportType: 'volume',
|
|
orientation: 'axial',
|
|
toolGroupId: toolGroupIds.pt,
|
|
initialImageOptions: {
|
|
preset: 'middle', // 'first', 'last', 'middle'
|
|
},
|
|
syncGroups: [
|
|
{
|
|
type: 'cameraPosition',
|
|
id: 'axialSync',
|
|
source: true,
|
|
target: true,
|
|
},
|
|
{
|
|
type: 'voi',
|
|
id: 'ptWLSync',
|
|
source: true,
|
|
target: true,
|
|
},
|
|
],
|
|
},
|
|
displaySets: [
|
|
{
|
|
id: 'ptDisplaySet',
|
|
options: { ...getPTOptions(ptOptionsParams) },
|
|
},
|
|
],
|
|
},
|
|
{
|
|
viewportOptions: {
|
|
viewportId: 'ptSagittal',
|
|
viewportType: 'volume',
|
|
orientation: 'sagittal',
|
|
toolGroupId: toolGroupIds.pt,
|
|
initialImageOptions: {
|
|
preset: 'middle', // 'first', 'last', 'middle'
|
|
},
|
|
syncGroups: [
|
|
{
|
|
type: 'cameraPosition',
|
|
id: 'sagittalSync',
|
|
source: true,
|
|
target: true,
|
|
},
|
|
{
|
|
type: 'voi',
|
|
id: 'ptWLSync',
|
|
source: true,
|
|
target: true,
|
|
},
|
|
],
|
|
},
|
|
displaySets: [
|
|
{
|
|
id: 'ptDisplaySet',
|
|
options: { ...getPTOptions(ptOptionsParams) },
|
|
},
|
|
],
|
|
},
|
|
{
|
|
viewportOptions: {
|
|
viewportId: 'ptCoronal',
|
|
viewportType: 'volume',
|
|
orientation: 'coronal',
|
|
toolGroupId: toolGroupIds.pt,
|
|
initialImageOptions: {
|
|
preset: 'middle', // 'first', 'last', 'middle'
|
|
},
|
|
syncGroups: [
|
|
{
|
|
type: 'cameraPosition',
|
|
id: 'coronalSync',
|
|
source: true,
|
|
target: true,
|
|
},
|
|
{
|
|
type: 'voi',
|
|
id: 'ptWLSync',
|
|
source: true,
|
|
target: true,
|
|
},
|
|
],
|
|
},
|
|
displaySets: [
|
|
{
|
|
id: 'ptDisplaySet',
|
|
options: { ...getPTOptions(ptOptionsParams) },
|
|
},
|
|
],
|
|
},
|
|
];
|
|
}
|
|
|
|
function getFusionViewports() {
|
|
const ptOptionsParams = {
|
|
colormap: {
|
|
name: DEFAULT_COLORMAP,
|
|
opacity: [
|
|
{ value: 0, opacity: 0 },
|
|
{ value: 0.1, opacity: 0.8 },
|
|
{ value: 1, opacity: 0.8 },
|
|
],
|
|
},
|
|
};
|
|
|
|
return [
|
|
{
|
|
viewportOptions: {
|
|
viewportId: 'fusionAxial',
|
|
viewportType: 'volume',
|
|
orientation: 'axial',
|
|
toolGroupId: toolGroupIds.fusion,
|
|
initialImageOptions: {
|
|
preset: 'middle', // 'first', 'last', 'middle'
|
|
},
|
|
syncGroups: [
|
|
{
|
|
type: 'cameraPosition',
|
|
id: 'axialSync',
|
|
source: true,
|
|
target: true,
|
|
},
|
|
{
|
|
type: 'voi',
|
|
id: 'ctWLSync',
|
|
source: false,
|
|
target: true,
|
|
},
|
|
{
|
|
type: 'voi',
|
|
id: 'fusionWLSync',
|
|
source: true,
|
|
target: true,
|
|
},
|
|
{
|
|
type: 'voi',
|
|
id: 'ptFusionWLSync',
|
|
source: false,
|
|
target: true,
|
|
options: {
|
|
syncInvertState: false,
|
|
},
|
|
},
|
|
{
|
|
type: 'hydrateseg',
|
|
id: 'sameFORId',
|
|
source: true,
|
|
target: true,
|
|
options: {
|
|
matchingRules: ['sameFOR'],
|
|
},
|
|
},
|
|
],
|
|
},
|
|
displaySets: [
|
|
{
|
|
id: 'ctDisplaySet',
|
|
},
|
|
{
|
|
options: { ...getPTOptions(ptOptionsParams) },
|
|
id: 'ptDisplaySet',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
viewportOptions: {
|
|
viewportId: 'fusionSagittal',
|
|
viewportType: 'volume',
|
|
orientation: 'sagittal',
|
|
toolGroupId: toolGroupIds.fusion,
|
|
initialImageOptions: {
|
|
preset: 'middle', // 'first', 'last', 'middle'
|
|
},
|
|
syncGroups: [
|
|
{
|
|
type: 'cameraPosition',
|
|
id: 'sagittalSync',
|
|
source: true,
|
|
target: true,
|
|
},
|
|
{
|
|
type: 'voi',
|
|
id: 'ctWLSync',
|
|
source: false,
|
|
target: true,
|
|
},
|
|
{
|
|
type: 'voi',
|
|
id: 'fusionWLSync',
|
|
source: true,
|
|
target: true,
|
|
},
|
|
{
|
|
type: 'voi',
|
|
id: 'ptFusionWLSync',
|
|
source: false,
|
|
target: true,
|
|
options: {
|
|
syncInvertState: false,
|
|
},
|
|
},
|
|
{
|
|
type: 'hydrateseg',
|
|
id: 'sameFORId',
|
|
source: true,
|
|
target: true,
|
|
options: {
|
|
matchingRules: ['sameFOR'],
|
|
},
|
|
},
|
|
],
|
|
},
|
|
displaySets: [
|
|
{
|
|
id: 'ctDisplaySet',
|
|
},
|
|
{
|
|
options: { ...getPTOptions(ptOptionsParams) },
|
|
id: 'ptDisplaySet',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
viewportOptions: {
|
|
viewportId: 'fusionCoronal',
|
|
viewportType: 'volume',
|
|
orientation: 'coronal',
|
|
toolGroupId: toolGroupIds.fusion,
|
|
initialImageOptions: {
|
|
preset: 'middle', // 'first', 'last', 'middle'
|
|
},
|
|
syncGroups: [
|
|
{
|
|
type: 'cameraPosition',
|
|
id: 'coronalSync',
|
|
source: true,
|
|
target: true,
|
|
},
|
|
{
|
|
type: 'voi',
|
|
id: 'ctWLSync',
|
|
source: false,
|
|
target: true,
|
|
},
|
|
{
|
|
type: 'voi',
|
|
id: 'fusionWLSync',
|
|
source: true,
|
|
target: true,
|
|
},
|
|
{
|
|
type: 'voi',
|
|
id: 'ptFusionWLSync',
|
|
source: false,
|
|
target: true,
|
|
options: {
|
|
syncInvertState: false,
|
|
},
|
|
},
|
|
{
|
|
type: 'hydrateseg',
|
|
id: 'sameFORId',
|
|
source: true,
|
|
target: true,
|
|
options: {
|
|
matchingRules: ['sameFOR'],
|
|
},
|
|
},
|
|
],
|
|
},
|
|
displaySets: [
|
|
{
|
|
id: 'ctDisplaySet',
|
|
},
|
|
{
|
|
options: { ...getPTOptions(ptOptionsParams) },
|
|
id: 'ptDisplaySet',
|
|
},
|
|
],
|
|
},
|
|
];
|
|
}
|
|
|
|
function getSeriesChartViewport() {
|
|
return {
|
|
viewportOptions: {
|
|
viewportId: 'seriesChart',
|
|
},
|
|
displaySets: [
|
|
{
|
|
id: 'chartDisplaySet',
|
|
options: {
|
|
// This dataset does not require the download of any instance since it is pre-computed locally,
|
|
// but interleaveTopToBottom.ts was not loading any series because it consider that all viewports
|
|
// are a Cornerstone viewport which is not true in this case and it waits for all viewports to
|
|
// have called interleaveTopToBottom(...).
|
|
skipLoading: true,
|
|
},
|
|
},
|
|
],
|
|
};
|
|
}
|
|
|
|
function getCTViewports() {
|
|
return [
|
|
{
|
|
viewportOptions: {
|
|
viewportId: 'ctAxial',
|
|
viewportType: 'volume',
|
|
orientation: 'axial',
|
|
toolGroupId: toolGroupIds.ct,
|
|
initialImageOptions: {
|
|
preset: 'middle', // 'first', 'last', 'middle'
|
|
},
|
|
syncGroups: [
|
|
{
|
|
type: 'cameraPosition',
|
|
id: 'axialSync',
|
|
source: true,
|
|
target: true,
|
|
},
|
|
{
|
|
type: 'voi',
|
|
id: 'ctWLSync',
|
|
source: true,
|
|
target: true,
|
|
},
|
|
],
|
|
},
|
|
displaySets: [
|
|
{
|
|
id: 'ctDisplaySet',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
viewportOptions: {
|
|
viewportId: 'ctSagittal',
|
|
viewportType: 'volume',
|
|
orientation: 'sagittal',
|
|
toolGroupId: toolGroupIds.ct,
|
|
initialImageOptions: {
|
|
preset: 'middle',
|
|
},
|
|
syncGroups: [
|
|
{
|
|
type: 'cameraPosition',
|
|
id: 'sagittalSync',
|
|
source: true,
|
|
target: true,
|
|
},
|
|
{
|
|
type: 'voi',
|
|
id: 'ctWLSync',
|
|
source: true,
|
|
target: true,
|
|
},
|
|
],
|
|
},
|
|
displaySets: [
|
|
{
|
|
id: 'ctDisplaySet',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
viewportOptions: {
|
|
viewportId: 'ctCoronal',
|
|
viewportType: 'volume',
|
|
orientation: 'coronal',
|
|
toolGroupId: toolGroupIds.ct,
|
|
initialImageOptions: {
|
|
preset: 'middle',
|
|
},
|
|
syncGroups: [
|
|
{
|
|
type: 'cameraPosition',
|
|
id: 'coronalSync',
|
|
source: true,
|
|
target: true,
|
|
},
|
|
{
|
|
type: 'voi',
|
|
id: 'ctWLSync',
|
|
source: true,
|
|
target: true,
|
|
},
|
|
],
|
|
},
|
|
displaySets: [
|
|
{
|
|
id: 'ctDisplaySet',
|
|
},
|
|
],
|
|
},
|
|
];
|
|
}
|
|
|
|
const defaultProtocol = {
|
|
id: 'default4D',
|
|
locked: true,
|
|
// Don't store this hanging protocol as it applies to the currently active
|
|
// display set by default
|
|
// cacheId: null,
|
|
hasUpdatedPriorsInformation: false,
|
|
name: 'Default',
|
|
createdDate: '2023-01-01T00:00:00.000Z',
|
|
modifiedDate: '2023-01-01T00:00:00.000Z',
|
|
availableTo: {},
|
|
editableBy: {},
|
|
imageLoadStrategy: 'default', // "default" , "interleaveTopToBottom", "interleaveCenter"
|
|
protocolMatchingRules: [
|
|
{
|
|
attribute: 'ModalitiesInStudy',
|
|
constraint: {
|
|
contains: ['CT', 'PT'],
|
|
},
|
|
},
|
|
],
|
|
// -1 would be used to indicate active only, whereas other values are
|
|
// the number of required priors referenced - so 0 means active with
|
|
// 0 or more priors.
|
|
numberOfPriorsReferenced: -1,
|
|
displaySetSelectors: {
|
|
defaultDisplaySetId: {
|
|
// Unused currently
|
|
imageMatchingRules: [],
|
|
// Matches displaysets, NOT series
|
|
seriesMatchingRules: [
|
|
// Try to match series with images by default, to prevent weird display
|
|
// on SEG/SR containing studies
|
|
{
|
|
attribute: 'numImageFrames',
|
|
constraint: {
|
|
greaterThan: { value: 0 },
|
|
},
|
|
},
|
|
],
|
|
// Can be used to select matching studies
|
|
// studyMatchingRules: [],
|
|
},
|
|
ctDisplaySet: {
|
|
// Unused currently
|
|
imageMatchingRules: [],
|
|
// Matches displaysets, NOT series
|
|
seriesMatchingRules: [
|
|
{
|
|
attribute: 'Modality',
|
|
constraint: {
|
|
equals: {
|
|
value: 'CT',
|
|
},
|
|
},
|
|
required: true,
|
|
},
|
|
{
|
|
attribute: 'isReconstructable',
|
|
constraint: {
|
|
equals: {
|
|
value: true,
|
|
},
|
|
},
|
|
required: true,
|
|
},
|
|
],
|
|
// Can be used to select matching studies
|
|
// studyMatchingRules: [],
|
|
},
|
|
ptDisplaySet: {
|
|
// Unused currently
|
|
imageMatchingRules: [],
|
|
// Matches displaysets, NOT series
|
|
seriesMatchingRules: [
|
|
{
|
|
attribute: 'Modality',
|
|
constraint: {
|
|
equals: 'PT',
|
|
},
|
|
required: true,
|
|
},
|
|
{
|
|
attribute: 'isReconstructable',
|
|
constraint: {
|
|
equals: {
|
|
value: true,
|
|
},
|
|
},
|
|
required: true,
|
|
},
|
|
{
|
|
attribute: 'SeriesDescription',
|
|
constraint: {
|
|
contains: 'Corrected',
|
|
},
|
|
},
|
|
{
|
|
weight: 2,
|
|
attribute: 'SeriesDescription',
|
|
constraint: {
|
|
doesNotContain: {
|
|
value: 'Uncorrected',
|
|
},
|
|
},
|
|
},
|
|
|
|
// Should we check if CorrectedImage contains ATTN?
|
|
// (0028,0051) (CorrectedImage): NORM\DTIM\ATTN\SCAT\RADL\DECY
|
|
],
|
|
// Can be used to select matching studies
|
|
// studyMatchingRules: [],
|
|
},
|
|
chartDisplaySet: {
|
|
// Unused currently
|
|
imageMatchingRules: [],
|
|
// Matches displaysets, NOT series
|
|
seriesMatchingRules: [
|
|
{
|
|
attribute: 'Modality',
|
|
constraint: {
|
|
equals: {
|
|
value: 'CHT',
|
|
},
|
|
},
|
|
required: true,
|
|
},
|
|
],
|
|
},
|
|
},
|
|
stages: [
|
|
{
|
|
id: 'dataPreparation',
|
|
name: 'Data Preparation',
|
|
viewportStructure: {
|
|
layoutType: 'grid',
|
|
properties: {
|
|
rows: 1,
|
|
columns: 3,
|
|
},
|
|
},
|
|
viewports: [...getPTViewports()],
|
|
createdDate: '2023-01-01T00:00:00.000Z',
|
|
},
|
|
|
|
{
|
|
id: 'registration',
|
|
name: 'Registration',
|
|
viewportStructure: {
|
|
layoutType: 'grid',
|
|
properties: {
|
|
rows: 3,
|
|
columns: 3,
|
|
},
|
|
},
|
|
viewports: [...getFusionViewports(), ...getCTViewports(), ...getPTViewports()],
|
|
createdDate: '2023-01-01T00:00:00.000Z',
|
|
},
|
|
|
|
{
|
|
id: 'roiQuantification',
|
|
name: 'ROI Quantification',
|
|
viewportStructure: {
|
|
layoutType: 'grid',
|
|
properties: {
|
|
rows: 1,
|
|
columns: 3,
|
|
},
|
|
},
|
|
viewports: [...getFusionViewports()],
|
|
createdDate: '2023-01-01T00:00:00.000Z',
|
|
},
|
|
|
|
{
|
|
id: 'kineticAnalysis',
|
|
name: 'Kinetic Analysis',
|
|
viewportStructure: {
|
|
layoutType: 'grid',
|
|
properties: {
|
|
rows: 2,
|
|
columns: 3,
|
|
layoutOptions: [
|
|
{
|
|
x: 0,
|
|
y: 0,
|
|
width: 1 / 3,
|
|
height: 1 / 2,
|
|
},
|
|
{
|
|
x: 1 / 3,
|
|
y: 0,
|
|
width: 1 / 3,
|
|
height: 1 / 2,
|
|
},
|
|
{
|
|
x: 2 / 3,
|
|
y: 0,
|
|
width: 1 / 3,
|
|
height: 1 / 2,
|
|
},
|
|
{
|
|
x: 0,
|
|
y: 1 / 2,
|
|
width: 1,
|
|
height: 1 / 2,
|
|
},
|
|
],
|
|
},
|
|
},
|
|
viewports: [...getFusionViewports(), getSeriesChartViewport()],
|
|
createdDate: '2023-01-01T00:00:00.000Z',
|
|
},
|
|
],
|
|
};
|
|
|
|
/**
|
|
* HangingProtocolModule should provide a list of hanging protocols that will be
|
|
* available in OHIF for Modes to use to decide on the structure of the viewports
|
|
* and also the series that hung in the viewports. Each hanging protocol is defined by
|
|
* { name, protocols}. Examples include the default hanging protocol provided by
|
|
* the default extension that shows 2x2 viewports.
|
|
*/
|
|
|
|
function getHangingProtocolModule() {
|
|
return [
|
|
{
|
|
name: defaultProtocol.id,
|
|
protocol: defaultProtocol,
|
|
},
|
|
];
|
|
}
|
|
|
|
export default getHangingProtocolModule;
|