* Added docs with new screenshots * Added doc to architecture * Added documentations to various extension modules * Added more documentation to modes * Added docs to managers * Added docs for services * Fixed deployment docs * Added white labelling documentation * Added i18n docs and measurement export
157 lines
5.3 KiB
Markdown
157 lines
5.3 KiB
Markdown
# Measurement Service
|
|
|
|
|
|
## Overview
|
|
`MeasurementService` handles the internal measurement representation inside `OHIF` platform.
|
|
Developers can add their custom `sources` with `mappers` to enable adding measurements inside OHIF.
|
|
Currently, we are maintaining `CornerstoneTools` annotations and corresponding mappers can be found
|
|
inside the `cornerstone` extension. However, `MeasurementService` can be configured to work with any
|
|
custom tools given that its `mappers` is added to the `MeasurementService`.
|
|
We can see the overall architecture of the `MeasurementService` below:
|
|
|
|
|
|
|
|

|
|
|
|
|
|
## Events
|
|
There are seven events that get publish in `MeasurementService`:
|
|
|
|
|
|
|
|
| Event | Description |
|
|
| --------------------- | ------------------------------------------------------ |
|
|
| MEASUREMENT_UPDATED | Fires when a measurement is updated |
|
|
| MEASUREMENT_ADDED | Fires when a new measurement is added |
|
|
| RAW_MEASUREMENT_ADDED | Fires when a raw measurement is added (e.g., dicom-sr) |
|
|
| MEASUREMENT_REMOVED | Fires when a measurement is removed |
|
|
| MEASUREMENTS_CLEARED | Fires when all measurements are deleted |
|
|
| JUMP_TO_MEASUREMENT | Fires when a measurement is requested to be jump to |
|
|
|
|
|
|
|
|
## API
|
|
|
|
- `getMeasurements`: returns array of measurements
|
|
|
|
- `getMeasurement(id)`: returns the corresponding measurement based on the provided Id.
|
|
|
|
- `remove(id, source)`: removes a measurement and broadcasts the `MEASUREMENT_REMOVED` event.
|
|
|
|
- `clearMeasurements`: removes all measurements and broadcasts `MEASUREMENTS_CLEARED` event.
|
|
|
|
- `createSource(name, version)`: creates a new measurement source, generates a uid and adds it to the `sources` property of the service.
|
|
|
|
- `addMapping(source, definition, matchingCriteria, toSourceSchema, toMeasurementSchema)`: adds a new measurement matching criteria along with mapping functions.
|
|
We will learn more about [source/mappers below](#source--mappers)
|
|
|
|
- `update`: updates the measurement details and fires `MEASUREMENT_UPDATED`
|
|
|
|
- `addRawMeasurement(source,definition,data,toMeasurementSchema,dataSource = {}` : adds a raw measurement into a source so that it may be
|
|
converted to/from annotation in the same way. E.g. import serialized data
|
|
of the same form as the measurement source. Fires `MEASUREMENT_UPDATED` or `MEASUREMENT_ADDED`.
|
|
Note that, `MeasurementService` handles finding the correct mapper upon new measurements; however, `addRawMeasurement` provides more flexibility.
|
|
You can take a look into its usage in `dicom-sr` extension.
|
|
|
|
- `source`: The measurement source instance.
|
|
- `definition`: The source definition you want to add the measurement to.
|
|
- `data`: The data you wish to add to the source.
|
|
- `toMeasurementSchema`: A function to get the `data` into the same shape as the source definition.
|
|
|
|
- `jumpToMeasurement(viewportIndex, id)`: calls the listeners who have subscribed to `JUMP_TO_MEASUREMENT`.
|
|
|
|
|
|
|
|
|
|
## Source / Mappers
|
|
To create a custom measurement source and relevant mappers for each tool, you can take a look
|
|
at the `init.js` inside the `cornerstone` extension. In which we are registering our
|
|
`CornerstoneTools-v4` measurement source to MeasurementService. Let's take a peek at the
|
|
*simplified* implementation together. To achieve this, for each tool, we need to
|
|
provide three mappers:
|
|
|
|
- `matchingCriteria`: criteria used for finding the correct mapper for the drawn tool.
|
|
- `toAnnotation`: tbd
|
|
- `toMeasurement`: a function that converts the tool data to OHIF internal representation of measurement data.
|
|
|
|
|
|
```js
|
|
// extensions/cornerstone/src/utils/measurementServiceMappings/Length.js
|
|
|
|
function toMeasurement(
|
|
csToolsAnnotation,
|
|
DisplaySetService,
|
|
getValueTypeFromToolType
|
|
) {
|
|
const { element, measurementData } = csToolsAnnotation
|
|
|
|
/** ... **/
|
|
|
|
const {
|
|
SOPInstanceUID,
|
|
FrameOfReferenceUID,
|
|
SeriesInstanceUID,
|
|
StudyInstanceUID,
|
|
} = getSOPInstanceAttributes(element)
|
|
|
|
const displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID(
|
|
SOPInstanceUID,
|
|
SeriesInstanceUID
|
|
)
|
|
|
|
/** ... **/
|
|
return {
|
|
id: measurementData.id,
|
|
SOPInstanceUID,
|
|
FrameOfReferenceUID,
|
|
referenceSeriesUID: SeriesInstanceUID,
|
|
referenceStudyUID: StudyInstanceUID,
|
|
displaySetInstanceUID: displaySet.displaySetInstanceUID,
|
|
label: measurementData.label,
|
|
description: measurementData.description,
|
|
unit: measurementData.unit,
|
|
length: measurementData.length,
|
|
type: getValueTypeFromToolType(tool),
|
|
points: getPointsFromHandles(measurementData.handles),
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////
|
|
|
|
// extensions/cornerstone/src/init.js
|
|
|
|
const Length = {
|
|
toAnnotation,
|
|
toMeasurement,
|
|
matchingCriteria: [
|
|
{
|
|
valueType: MeasurementService.VALUE_TYPES.POLYLINE,
|
|
points: 2,
|
|
},
|
|
],
|
|
}
|
|
|
|
const _initMeasurementService = (MeasurementService, DisplaySetService) => {
|
|
/** ... **/
|
|
|
|
const csToolsVer4MeasurementSource = MeasurementService.createSource(
|
|
'CornerstoneTools',
|
|
'4'
|
|
);
|
|
|
|
/* Mappings */
|
|
MeasurementService.addMapping(
|
|
csToolsVer4MeasurementSource,
|
|
'Length',
|
|
Length.matchingCriteria,
|
|
toAnnotation,
|
|
toMeasurement
|
|
);
|
|
|
|
/** Other tools **/
|
|
return csToolsVer4MeasurementSource;
|
|
};
|
|
|
|
|
|
```
|