== 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: '''surface''' (TkRegRAS) -> '''data''' (un-user-transformed RAS) -> '''world''' (user-transformed RAS) In the simple case where there is no user transform: '''surface''' (TkRegRAS) -> '''data''' (RAS) == '''world''' (RAS) 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.