RAS Coordinates in Scuba

This document is current as of 10/4/07.

Surface coordinates

The SurfaceCollection class is wrapper for an MRIS struct. It attempts to be as 'thin' as possible, that is, it doesn't attempt to replicate any functionality that doesn't already exist in libutils. It maintains a pointer to an MRIS struct and two transforms that concatenate the data->surface and world->surface transformations.

In SurfaceCollection, surface space is whatever coordinates are in the v->{x,y,z} fields for a surface. Data space is an intermediate space that allows a user-transform (i.e. a display transform) to be inserted between this space and the final world space. World space is equivalent to RAS space, since in Scuba, everything that is drawn on the screen is meant to be in RAS space.

You can think of the three spaces as:

In the simple case where there is no user transform:

Note that the actualy transform objects in ScubaCollection are mDataToSurfaceTransform, mWorldToSurfaceTransform, and in the super class DataCollection, mDataToWorldTransform. The first two are the inverse of what you might expect.

In SurfaceCollection, the LoadSurface() function reads a surface with an MRISLoader, a class that eventually calls MRISread(). It then looks for a transform in mris->lta, and if found, populates its data->surface transform this way:

SurfaceCollection.cpp::LoadSurface():152

    // Get transform.
    if ( NULL != mMRIS->lta ) {

      // This is our RAS -> TkRegRAS transform.
      mDataToSurfaceTransform.SetMainTransform
      ( 1, 0, 0, -mMRIS->lta->xforms[0].src.c_r,
        0, 1, 0, -mMRIS->lta->xforms[0].src.c_a,
        0, 0, 1, -mMRIS->lta->xforms[0].src.c_s,
        0, 0, 0, 1 );
    }

The subsequent call to CalcWorldToSurfaceTransform() will concatenate any user transform, but initially there will be none, so the world->surface transform is identical to the data->surface.

So that's what you'll get if you just load up a surface in scuba. However, tkmedit does another transform automatically in which it 'associates' a surface with a volume. Since Scuba was designed to be totally flexible, it doesn't do this automatically. To associate a surface with a volume, show the Data panel, select the surface name in the Data Collection pull down menu, check the "Set RAS Transform from Volume" checkbox,, and select the proper volume in the Volume pull down menu right below it. This will cause the SetDataToSurfaceTransformFromVolume() function in SurfaceCollection to be called.

SetDataToSurfaceTransformFromVolume() has always been an uncertain part of Scuba since it was originally based on some instructions from Tosa, but stopped working at some point. Check the actual code for the old version. What it does now is:

SurfaceCollection.cpp::SetDataToSurfaceTransformFromVolume():631

  MATRIX* RASToTkRegRASMatrix = surfaceRASFromRAS_( mri );
  if ( NULL == RASToTkRegRASMatrix ) {
    throw runtime_error( "Couldn't get surfaceRASFromRAS_ from MRI" );
  }

  mDataToSurfaceTransform.SetMainTransform( RASToTkRegRASMatrix );
  MatrixFree( &RASToTkRegRASMatrix );

It replaces the data->surface transform with the surfaceRASFromRAS_() transform from the MRI the user selects in the pull down menu.

Excluding the new terminology of surface, data, and world space, the surface RAS transforms are actually very simple, and rely on the mrisurf.c code. Any future changes should be made in mrisurf.c, and SurfaceCollection should be kept as thin a wrapper as possible.