How to transform distance in world coordinates to distance in display coordinates?

Hi All,
I am implementing a custom circle-shaped cursor using SVG and CSS. The radius of the circle should be calculated dynamically based on a given size in world coordinates (eg. 1mm). It should be calculated in place where I have rendered imageslice actor. Is it possible to calculate radius in pixels having information from:

  • imageSlice and imageMapper
  • renderWindow and renderer (activeCamera).

I was trying to use view.worldToDisplay(x,y,z,renderer) by

  1. picking two points from the imageslice plane distant of 1mm from each other in World Coords,
  2. by transforming these points to display coords and calculating distance between them,
    but it did not work precisely.

Any idea how can I compute it


Thank you
Andrzej

Hi Andrej,

Instead of using WorldToDisplay, the information can be extracted from the camera:

// Given a specific world point, return the scale factor
// from display coords to world coords at that point.
double DisplayToWorldScale(const double position[3], vtkRenderer *renderer)
{
  // Start by computing the height of the window at the cursor position.
  double worldHeight;
  vtkCamera* camera = renderer->GetActiveCamera();
  if (camera->GetParallelProjection())
  {
    worldHeight = 2*camera->GetParallelScale();
  }
  else
  {
    vtkMatrix4x4* matrix = camera->GetViewTransformMatrix();
    // Get a 3x3 matrix with the camera orientation
    double cvz[3];
    cvz[0] = matrix->GetElement(2, 0);
    cvz[1] = matrix->GetElement(2, 1);
    cvz[2] = matrix->GetElement(2, 2);

    double cameraPosition[3];
    camera->GetPosition(cameraPosition);

    double v[3];
    v[0] = cameraPosition[0] - position[0];
    v[1] = cameraPosition[1] - position[1];
    v[2] = cameraPosition[2] - position[2];

    worldHeight = 2*(vtkMath::Dot(v,cvz)
                     * tan(0.5*camera->GetViewAngle()/57.296));
  }

  // Compare world height to window height.
  int windowHeight = renderer->GetSize()[1];
  double scale = 1.0;
  if (windowHeight > 0)
  {
    scale = worldHeight/windowHeight;
  }

  return scale;
}

Of course you can probably find ways to simplify my old code above, for example by calling GetDirectionOfProjection() instead pulling the camera’s Z vector from the view transform matrix…

1 Like

Hi David,
Thank you very much for reply. I will try to implement your approach in vtk js (I forgot to mention about javascript;-), but as far as I remember vtk.js API, it should be doable.

I am using MANDATORY Parallel Projection, so in my case it is as simple as that:

function displayToWorldScale (renderer)
{   let camera = renderer.getActiveCamera();
    let scale = 1.0;
    let windowHeight = renderer.getRenderWindow().getViews()[0].getSize()[1];
    let worldHeight = 2*camera.getParallelScale();
    if (windowHeight > 0)
    {
        scale = worldHeight/windowHeight;
    }
    return scale;
};

Thank you again

Glad to hear that it worked. I gotta try out vtk.js one of these days.

I needed to solve a similar problem. I took and adapted vtk.js widget code to get pixel to world ratio:

    /**
     * Get pixel height at provided world coordinate.
     * Adapted from getPixelWorldHeightAtCoord() in vtk-js/Sources/Widgets/Representations/WidgetRepresentation/index.js
     * and updateDisplayScaleParams() in vtk-js/Sources/Widgets/Core/WidgetManager/index.js
     */
    getPixelHeightInWorld(point: Vector3) {
        const camera = this.renderer.getActiveCamera();
        const direction = camera.getDirectionOfProjection();
        const isParallel = camera.getParallelProjection();
        const position = camera.getPosition();

        const displayHeightFactor = isParallel
            ? 2 * camera.getParallelScale()
            : 2 * Math.tan(radiansFromDegrees(camera.getViewAngle()) / 2);

        const [rwW, rwH] = this.renderWindow.getViews()[0].getSize();
        const [vxmin, vymin, vxmax, vymax] = this.renderer.getViewport();
        const rendererPixelDims = [rwW * (vxmax - vxmin), rwH * (vymax - vymin)];

        let scale = 1;

        if (isParallel) {
            scale = displayHeightFactor;
        } else {
            const pointCopy = [...point] as Vector3;
            subtract(pointCopy, position, pointCopy);
            scale = dot(pointCopy, direction) * displayHeightFactor;
        }

        return scale / rendererPixelDims[1];
    };