Enable Cobb Angle Tool (angleTool.js/angle) step by step instructions

432 views
Skip to first unread message

Ricardo Borjas

unread,
Jan 30, 2019, 10:34:18 AM1/30/19
to cornerstone platform
I've been trying to enable the Cobb Angle Tool (cornerstoneTools.angle) but there are problems regarding naming conventions.
The SimpleAngle Tool is renamed (to 'angle') in the Tools Manager and the Measuring Tools listeners. 
Is there a step-by-step manual or tutorial to enable both tools without the naming interference?

Diego Angulo

unread,
Jan 31, 2019, 3:29:42 PM1/31/19
to cornerstone platform
In the latest version they are called

cobbAngle and angle

Ricardo Borjas

unread,
Mar 27, 2019, 10:33:00 AM3/27/19
to cornerstone platform
My question was incorrect from the beginning. I should ask specifically for the procedure using OHIF Viewer.
Anyway, it was solved.

I used the actual names of the tools (angle and simpleAngle) in the tool manager and all related scripts, included a new rule (schema) to the measurement table client and changed the angle tool render because it only drew one line with three pullers forming a simple angle instead of two separated lines with 4 pullers.


Sin título.png

joeymich...@gmail.com

unread,
Feb 4, 2021, 9:02:24 PM2/4/21
to cornerstone platform
Hello, 
I've been trying to setup Cobb Angle for a while now and have been unsuccessful so far. When you successfully did it was this in The Legacy v1 meteor code of OHIFViewer or the react v2? Also exactly which files have to be edited and how? The most I was able to do was adding an icon to the list of tools but not much more. Any help would be appreciated. Thank you.

ricardo....@gmail.com

unread,
Feb 5, 2021, 8:52:36 AM2/5/21
to cornerstone platform
It was enabled on OHIF VIewer 1.0 (Meteor).
I have no tried to enable it on OHIF Viewer 2.0 (React) yet.
Maybe in March or April because of my schedule.

joeymich...@gmail.com

unread,
Feb 7, 2021, 11:51:17 AM2/7/21
to cornerstone platform
Thank you for the reply. Do you happen to remember which files need to be edited in Viewer 1.0? (Meteor) and what exactly to put?

ricardo....@gmail.com

unread,
Feb 11, 2021, 9:31:25 AM2/11/21
to cornerstone platform
These are files affected by the tool:

\Viewers\OHIFViewer\client\components\toolbarSection\toolbarSection.js
\Viewers\OHIFViewer\node_modules\cornerstone-tools\dist\cornerstoneTools.js
\Viewers\OHIFViewer\node_modules\cornerstone-tools\dist\cornerstoneTools.js.map
\Viewers\OHIFViewer\node_modules\cornerstone-tools\dist\cornerstoneTools.min.js
\Viewers\OHIFViewer\node_modules\cornerstone-tools\dist\cornerstoneTools.min.js.map
\Viewers\Packages\ohif-cornerstone\.npm\package\node_modules\cornerstone-tools\dist\cornerstoneTools.js
\Viewers\Packages\ohif-cornerstone\.npm\package\node_modules\cornerstone-tools\dist\cornerstoneTools.js.map
\Viewers\Packages\ohif-cornerstone\.npm\package\node_modules\cornerstone-tools\dist\cornerstoneTools.min.js
\Viewers\Packages\ohif-cornerstone\.npm\package\node_modules\cornerstone-tools\dist\cornerstoneTools.min.js.map
\Viewers\Packages\ohif-measurement-table\client\schema\angle.js (Brand New File, Tool definition, different to Simple Angle Tool)
\Viewers\Packages\ohif-measurement-table\client\configuration\measurementTools.js
\Viewers\Packages\ohif-viewerbase\client\lib\toolManager.js

I cannot provide the full and exact code because of a contract NDA,  but I can give some general advice:

in \Viewers\OHIFViewer\node_modules\cornerstone-tools\dist\cornerstoneTools.js

/***/ "./imageTools/angleTool.js":
/*!*********************************!*\
  !*** ./imageTools/angleTool.js ***!
  \*********************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.angleTouch = exports.angle = undefined;

var _externalModules = __webpack_require__(/*! ../externalModules.js */ "./externalModules.js");

var _externalModules2 = _interopRequireDefault(_externalModules);

var _mouseButtonTool = __webpack_require__(/*! ./mouseButtonTool.js */ "./imageTools/mouseButtonTool.js");

var _mouseButtonTool2 = _interopRequireDefault(_mouseButtonTool);

var _touchTool = __webpack_require__(/*! ./touchTool.js */ "./imageTools/touchTool.js");

var _touchTool2 = _interopRequireDefault(_touchTool);

var _drawTextBox = __webpack_require__(/*! ../util/drawTextBox.js */ "./util/drawTextBox.js");

var _drawTextBox2 = _interopRequireDefault(_drawTextBox);

var _roundToDecimal = __webpack_require__(/*! ../util/roundToDecimal.js */ "./util/roundToDecimal.js");

var _roundToDecimal2 = _interopRequireDefault(_roundToDecimal);

var _toolColors = __webpack_require__(/*! ../stateManagement/toolColors.js */ "./stateManagement/toolColors.js");

var _toolColors2 = _interopRequireDefault(_toolColors);

var _drawHandles = __webpack_require__(/*! ../manipulators/drawHandles.js */ "./manipulators/drawHandles.js");

var _drawHandles2 = _interopRequireDefault(_drawHandles);

var _toolState = __webpack_require__(/*! ../stateManagement/toolState.js */ "./stateManagement/toolState.js");

var _lineSegDistance = __webpack_require__(/*! ../util/lineSegDistance.js */ "./util/lineSegDistance.js");

var _lineSegDistance2 = _interopRequireDefault(_lineSegDistance);

var _drawing = __webpack_require__(/*! ../util/drawing.js */ "./util/drawing.js");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var toolType = 'angle';

// /////// BEGIN ACTIVE TOOL ///////
function createNewMeasurement(mouseEventData) {
  // Create the measurement data for this tool with the end handle activated
  var angleData = {
    visible: true,
    active: true,
    color: undefined,
    handles: {
      start: {
        x: mouseEventData.currentPoints.image.x - 20,
        y: mouseEventData.currentPoints.image.y + 10,
        highlight: true,
        active: false
      },
      end: {
        x: mouseEventData.currentPoints.image.x,
        y: mouseEventData.currentPoints.image.y,
        highlight: true,
        active: true
      },
      start2: {
        x: mouseEventData.currentPoints.image.x - 20,
        y: mouseEventData.currentPoints.image.y + 10,
        highlight: true,
        active: false
      },
      end2: {
        x: mouseEventData.currentPoints.image.x,
        y: mouseEventData.currentPoints.image.y + 20,
        highlight: true,
        active: false
      }
    }
  };

  return angleData;
}
// /////// END ACTIVE TOOL ///////

function pointNearTool(element, data, coords) {
  if (data.visible === false) {
    return false;
  }

  return (0, _lineSegDistance2.default)(element, data.handles.start, data.handles.end, coords) < 5 || (0, _lineSegDistance2.default)(element, data.handles.start2, data.handles.end2, coords) < 5;
}

// /////// BEGIN IMAGE RENDERING ///////
function onImageRendered(e) {
  var eventData = e.detail;

  // If we have no toolData for this element, return immediately as there is nothing to do
  var toolData = (0, _toolState.getToolState)(e.currentTarget, toolType);

  if (toolData === undefined) {
    return;
  }

  // We have tool data for this element - iterate over each one and draw it
  var context = (0, _drawing.getNewContext)(eventData.canvasContext.canvas);

  var config = angle.getConfiguration();
  var cornerstone = _externalModules2.default.cornerstone;

  var _loop = function _loop(i) {
    var data = toolData.data[i];

    if (data.visible === false) {
      return 'continue';
    }

    (0, _drawing.draw)(context, function (context) {
      // Configurable shadow
      (0, _drawing.setShadow)(context, config);

      // Differentiate the color of activation tool
      var color = _toolColors2.default.getColorIfActive(data);

      (0, _drawing.drawLine)(context, eventData.element, data.handles.end,  data.handles.start,  { color: color });
      (0, _drawing.drawLine)(context, eventData.element, data.handles.end2, data.handles.start2, { color: color });

      // Draw the handles
      (0, _drawHandles2.default)(context, eventData, data.handles);

      // Need to work on correct angle to measure.  This is a cobb angle and we need to determine
      // Where lines cross to measure angle. For now it will show smallest angle.
      var columnPixelSpacing = eventData.image.columnPixelSpacing || 1;
      var rowPixelSpacing = eventData.image.rowPixelSpacing || 1;
      var dx1 = (Math.ceil(data.handles.start.x) - Math.ceil(data.handles.end.x)) * columnPixelSpacing;
      var dy1 = (Math.ceil(data.handles.start.y) - Math.ceil(data.handles.end.y)) * rowPixelSpacing;
      var dx2 = (Math.ceil(data.handles.start2.x) - Math.ceil(data.handles.end2.x)) * columnPixelSpacing;
      var dy2 = (Math.ceil(data.handles.start2.y) - Math.ceil(data.handles.end2.y)) * rowPixelSpacing;

      var angle = Math.acos(Math.abs((dx1 * dx2 + dy1 * dy2) / (Math.sqrt(dx1 * dx1 + dy1 * dy1) * Math.sqrt(dx2 * dx2 + dy2 * dy2))));

      angle *= 180 / Math.PI;

      var rAngle = (0, _roundToDecimal2.default)(angle, 2);
      var str = '00B0'; // Degrees symbol
      var text = rAngle.toString() + String.fromCharCode(parseInt(str, 16));

      var handleStartCanvas = cornerstone.pixelToCanvas(eventData.element, data.handles.start2);
      var handleEndCanvas = cornerstone.pixelToCanvas(eventData.element, data.handles.end2);

      var textX = (handleStartCanvas.x + handleEndCanvas.x) / 2;
      var textY = (handleStartCanvas.y + handleEndCanvas.y) / 2;

      (0, _drawTextBox2.default)(context, text, textX, textY, color);
    });
  };

  for (var i = 0; i < toolData.data.length; i++) {
    var _ret = _loop(i);

    if (_ret === 'continue') continue;
  }
}
// /////// END IMAGE RENDERING ///////

// Module exports
var angle = (0, _mouseButtonTool2.default)({
  createNewMeasurement: createNewMeasurement,
  onImageRendered: onImageRendered,
  pointNearTool: pointNearTool,
  toolType: toolType
});

var angleTouch = (0, _touchTool2.default)({
  createNewMeasurement: createNewMeasurement,
  onImageRendered: onImageRendered,
  pointNearTool: pointNearTool,
  toolType: toolType
});

exports.angle = angle;
exports.angleTouch = angleTouch;

/***/ }),

Try to figure out how other tools work, and how they relate to the measurements logic. And be very careful in your naming conventions. I hope it helps.

joeymich...@gmail.com

unread,
Feb 11, 2021, 8:42:17 PM2/11/21
to cornerstone platform
Thank you very much, having a starting point is already very helpful
Reply all
Reply to author
Forward
0 new messages