###################################
csurf help panels (Help menu order)
###################################

This is all 40K lines of help (462 helpfiles)
     to search:  alt/cmd-f
      find next:  alt/cmd-g
    one panel:  click any word at left
  tkinterfaces:  R-click button/entry


####################
csurf
####################

-------------------------------------------
 Csurf -- cortical surface program manager
-------------------------------------------
#############
tardate=260525
#############

Overview

The csurf program generates and records command
lines to run freesurfer cortical surface analysis
and display programs (e.g., tkmedit, fourier,
paint, tksurfer, mri_surf2surf).  It serves the
function of an analysis and display shell script,
but with more convenient interactivity.

Csurf saves analysis and rendering parameters for
each scandir in a session to make it easy to
redo, adjust, re-display, or re-batch-run
analyses (see SessionTools -> Run Batch Process).
The next time the session is opened, the saved
display parameters will be used.

Any sequence of user interface actions in
tksurfer and tkmedit can be automated using a tcl
script.  See R-click help on the "tcl:" label in
tksurfer and tkmedit to find out how to record
the tcl commands executed by interface actions.
A tcl script can be run interactively from
tksurfer and tkmedit, but can also be run
completely non-interactively from the command
line:

  tksurfer marty rh inflated -tcl myscript.tcl ...
  tkmedit marty orig.mgz -tcl myscript.tcl ...

Typical Use

First reconstruct a single subject's surface
(MGHTools or manual SubjectsTools).

Then, one or more functional sessions can be
associated with each subject and analyzed
(SessionTools).  Single subject activations can
then be viewed on the surface or as 2D slice
overlays with SessionTools -> View Functional
Data.

See Help -> Retinotopy HOWTO for step-by-step
instructions.

Cross-subject complex-valued surface averages can
be computed in a spherically morphed common
surface coordinate system analagous to 3D
Talairach coordinates (CrossSessTools).  There is
some support for 3-D cross subject complex-valued
average (manual registration).

Help/Instructions

Help files are available for each analysis step
in the csurf Help menu, arranged in typical order
of use.

The small "h" buttons at one corner of csurf,
tksurfer, tkmedit, and tkregister bring up
general help for that application).

In addition, every button, checkbox, and text
entry in csurf, tksurfer, tkmedit, and tkregister
has a context-sensitive R-click popup help panel.
Each help panel can be searched for keywords
using Cmd-f (linux: Alt-f) in the help panel (use
<Return> or Cmd/Alt-g for 'find next').

The csurf menu item:

  Help -> All Help Contents (clickable)

makes a clickable table of contents of all csurf,
tksurfer, tkmedit, and tkregister help panels.

Finally, all help panels are gathered into a
single file (35K lines) here:

  $CSURF_DIR/lib/help/CSURF_HELP.txt

To get that entire file (35K lines) into one,
searchable help window, middle-click the lower
right "h" button on csurf.

Image Outputs

By default, rendered images are saved as 3 byte
per pixel tiffs by tksurfer and tkmedit.  To
restore the old behavior of saving images as SGI
rgb files, unclick:

  Preferences -> Save .tiff (else SGI rgb)

For surface views, to obtain a 4 byte per pixel
tiff with pure black background areas changed to
transparent, use:

  Preferences -> Black to Transparent

Since some programs may not be able to display or
use 4 byte per pixel tiffs, this option is off by
default (no effect on SGI rgb output).

Directory Structure

The data base consists of two main directories:

(1) subjects tree (e.g., /usr1/subjects)

  Permanent home of structural MRI data, filtered
  MRI data, and folded, unfolded, and flattened
  surfaces for subjects.  The startup value of
  this must be set with:

    setenv SUBJECTS_DIR <whatever>  # csh/tcsh
    export SUBJECTS_DIR=<whatever>  # sh/bash

  The directory (database) name for each subject
  is typically a first name plus last initial
  (e.g., martys).  This root of the subjects tree
  can be interactively changed with csurf.

  For ease of navigation, any string typed into
  the "subject:" entry that doesn't exactly match
  a subject brings up a panel of partial matches.

  Here is a shortcut to start csurf for a
  particular subject:

    csurf <subject>

(2) functional sessions tree (e.g., /usr1/sessions)

  Directory containing individual functional
  sessions.  The startup value of this must be
  set with:

    setenv FUNCTIONALS_DIR <whatever>  # csh/tcsh
    export FUNCTIONALS_DIR=<whatever>  # sh/bash

  A session is defined as a set of scans taken
  with one subject, in one position, in one RF
  coil.  Individual sessions can be saved
  anywhere.  A convenient style for a session
  name is a 6 numeral date, then initials.  Use a
  date in year/month/day order (YYMMDD) so 'ls'
  or file browsers sort them chronologically
  (e.g., 190928MS).  This root of the sessions
  tree can be interactively changed with csurf.

  As with the subjects dropdown, any string typed
  into the "session:" entry that doesn't exactly
  match a session brings up a panel of partial
  matches (e.g., with default sesson names, MS
  matches all scans on subject MS, while 1906*MS
  matches June 2019 scans on subject MS).

  Here is a shortcut to start csurf for a
  particular session:

    csurf <session>

A new subject directory is initially created with
either:

  File -> New Subject
  MGHTools -> Run recon-all

A new empty sessions or cross-subject spherical
average session directory is initially created
with:

  File -> New Functional
  File -> New Spherical Avg

Avoid spaces within paths and names

Csurf programs can now correctly deal with
pathnames (e.g., CSURF_DIR, SUBJECTS_DIR,
FUNCTIONALS_DIR) that have spaces in them (e.g.,
the impractical default brand names given to some
removeable disks).  However, spaces in paths will
break many MGH freesurfer 5.3 scripts and
programs (e.g., recon-all, mris_pmake [for
geodesics]).  If at all possible, just remove
spaces from paths.

Subject/Session Association

Each functional session directory (e.g.,
120928MS) is associated with a particular subject
directory (e.g., marser) chosen when the session
is created.  Several different functional
sessions may point to the same subject.

The association between a functional session and
a particular subject is completely determined by
the (relative) subject directory name stored in
an ASCII file, "name".  For example:

  $FUNCTIONALS_DIR/120928MS/image/name

To change this (e.g., if a new surface is created
for a subject), edit the name file or use:

  Preferences -> Change Subject for Curr Session

Note that if you do this, all scandirs in this
session have to be re-registered to the T1 data
used to make the new surface, and stats have to
to be re-PAINT'ed onto the new surface.  If you
want to save the original analysis, first make a
copy of it (File -> Copy Functional), before you
update the name file.

If the contents of the subjects or sesssions
directories are updated outside of csurf, use
File -> Update Subjects & Functionals to refresh
the dropdowns.

Scripts Directory

The csurf interface generally runs programs from
the "scripts" subdirectory inside the currently
selected session or subject.  The current working
directory is shown in the csurf window title bar.
A flat ASCII file of current configs -- csurf.dat
-- is stored in the scripts dir.  It is read by
csurf upon selecting that session or subject, and
written when you press SAVE or SAVE/CLOSE on one
of the csurf configuration panels, or when you
actually perform an action.  If you remove or
move aside the csurf.dat file, the current
configuration of a session or subject directory
will be forgotten, but no data files will be
affected.

The scripts directory is also the directory in
which ASCII notes are conventially made:

  File -> Open Subject NOTES
  File -> Open Functional NOTES

automatically open (or create) the current
subject or session's scripts dir NOTES file in a
text editor to encourage this practice.

MGHTools and SubjectsTools

UCSD/UCL csurf has two different processing
streams for making surfaces.

The MGHTools menu provides an easy way to run a
separately-installed MGH freesurfer distribution
to make, flatten, and register (spherically
morph) surfaces in the csurf-maintained
SUBJECTS_DIR.  This is the default processing
stream for making surfaces for csurf.  To run MGH
freesurfer from csurf, set the environment
variable, FSURF_DIR, to the location of the MGH
install directory before starting csurf.  Subject
directories created elsewhere by MGH freesurfer
are also csurf-useable without change.

Second, the SubjectTools menu contains a set of
items ending in "... (hi-res)" for making high
resolution surfaces from 512^3/0.5mm^3 data.
(N.B.: the "hi-res" tools also work with
256^3/1.0mm^3 data sets, where the flexible
initialization can be useful for non-standard
brains). This processing stream currently
requires manual intervention (in Expert
Preferences panels) to set thresholds, cutting
planes, and fill seeds.

SessionTools and CrossSessTools

There are two menu items for operating on
functional session directories.

The SessionTools menu contains items arranged in
the order in which they are typically used for
single subject (first level) analysis.  Cross
session but within-subject averages can also be
made using SessionTools -> Combine Surface Stats.

The CrossSessTools menu manipulates spherically
morphed cross subject (second level) average
directories, which are stored in FUNCTIONALS_DIR
alongside the single subject sessions.  Cross
session dirs are similar to functional sessions
but can only contain one scandir.

Double-clicking the "subject:", "surface:",
"session:" or "scandir:" labels on the main csurf
panel will bring any currently open panel back to
the front.

Log View

As csurf runs command-line programs in the
background, it pipes the command lines as well as
the resulting outputs into a log.  These log
outputs can be viewed at any time with
Preferences -> View Logs (Linux: Alt-l, Mac:
Cmd-l).  There are three parts of the log -- one
for tkmedit, one for tksurfer, and one for all
other command line programs.  When you quit
csurf, the entire contents of the log is saved
into a file in the current scriptsdir, csurf.log
(full path echoed to stdout on quit).

To save *just* the commands executed by csurf to
a separate file (e.g., as the basis for your own
shell script), use:

  Preferences -> Open csurf cmds-only file
  Preferences -> Close csurf cmds-only file

See also tksurfer.log and tkmedit.log which save
tcl commands below.

User Setup

The csurf program tree can be installed anywhere.
There is a patch setup command that needs to be
sourced (different versions for csh/tsh and
sh/bash).

The least invasive way to setup your environment
variables is via an alias in your .cshrc or
.tcshrc file (so each new window won't
automatically have its path and environment
reset).  Then, in a new window, to start up, you
would type:

  fs         -> setup csurf/FreeSurfer0.8 paths
  csurf      -> start csurf interface (or: csurf &)

Here is an example of an alias, 'fs', that could
be added to your Linux .cshrc (or .tcshrc) file
that assumes you installed MGH freesurfer in the
standard place, csurf in your home directory, and
that you have subjects and sessions directories
in your home directory:

alias fs \
   "setenv FSURF_DIR /usr/local/freesurfer; \
    setenv SUBJECTS_DIR ~/subjects; \
    setenv FUNCTIONALS_DIR ~/sessions; \
    pushd ~/csurf; \
    source FreeSurferEnv.csh; \
    popd"

Here is how to add a .bashrc function to achieve
the same effect (or use a sh/bash alias):

fs() {
  export FSURF_DIR=/usr/local/freesurfer
  export SUBJECTS_DIR=~/subjects
  export FUNCTIONALS_DIR=~/sessions
  pushd ~/csurf
  source FreeSurferEnv.sh
  popd
}

On Mac, the FSURF_DIR path line for tcsh and
bash would typically instead be:

  setenv FSURF_DIR /Applications/freesurfer   # tcsh
  export FSURF_DIR=/Applications/freesurfer   # bash

If you want the csurf text editor to be vi in a
gterm or xterm (instead of a default graphical
editor like gedit), you can also add one of these
to your .cshrc:

  setenv CSURFEDITORVIGTERM   # or bash: export ...
  setenv CSURFEDITORVIXTERM   # or bash: export ...

Other useful aliases

  ## cd to subj/sess scriptsdir with just name
  alias cds  'cd $SUBJECTS_DIR/\!*/scripts'
  alias cdf  'cd $FUNCTIONALS_DIR/\!*/*/scripts'

Keyboard shortcuts

There are a few csurf keyboard shortcuts for the
most commonly used menu items (N.B.: on Linux,
the shortcut command key is "Alt" while on Mac,
the shortcut command key is "command", both usu.
immediately left of the space bar).

 Alt/Cmd-u   File -> Update Sessions/Subjects
 Alt/Cmd-f    SessionTools -> View Functional Data
 Alt/Cmd-b   SessionTools -> View Saved Bitmaps
 Alt/Cmd-l    Preferences -> View/Hide Logs
 Alt/Cmd-o   Preferences -> Don't Ask to Overwrite

The panels presenting lists of saved bitmaps to
view (e.g., from Alt/Cmd-b) have another
shortcut (documented on the panels):

 Alt/Cmd-e   select all (every)

Binary File Byte Order

All FreeSurfer generated data files are stored in
most-significant byte first (MSB first) order.
This is (was!) the native byte order on
SGI/Sun/PowerPC.  On Linux and Intel Mac, the
byte order is swapped on file read and write.

Surface Format Read

  native freesurfer tri or quad (binary)
  native freesurfer tri or quad (ASCII)
  ICO tri (ASCII)
  VTK tri (ASCII)
  OFF tri (ASCII)
  GIFTI tri (base64 ASCII)
  OBJ tri (ASCII)
  SRF tri (binary)

Surface Format Write

  native freesurfer format (binary)
  freesurfer format (ASCII)
  vtk 3.0 format (ASCII)
  object file format: OFF,COFF (ASCII)
  stereolithography format: 3D printer (ASCII)
  glTF 2.0: GL transmission format (binary)


##############################
Volume Binary File Formats
##############################

 COR directory:
    ------- COR-.info header file -----------
    imnr0 1	# zmin
    imnr1 256	# zmax
    ptype 2	# planetype (0=hor,1=sag,2=cor/def)
    x 256	# zsize
    y 256	# ysize
    fov 0.256000	# FOV (meters)
    thick 0.001000	# slice thick (meters)
    psiz 0.001000	# pix size (meters)
    locatn 0.000000	# def=0
    strtx -0.128000
    endx 0.128000
    strty -0.128000
    endy 0.128000
    strtz -0.128000
    endz 0.128000
    tr 0.000000
    te 0.000000
    ti 0.000000
    xform talairach.xfm
    ------- COR-??? byte images -------------
    COR-001
    ...
    COR-256 (256x256)
	*or*
    COR-512 (512x512)
    -----------------------------------------

 AFNI BRIK (see AFNI docs for full spec):
    ------------ header file ----------------
    header: <stem>+orig.HEAD (ASCII)
        ...
        type = string-attribute
        name = TYPESTRING
        count = 15
        '3DIM_HEAD_ANAT~

        type = integer-attribute
        name = SCENE_DATA
        count = 8
         0 2 0 -999 -999
         -999 -999 -99

        type = integer-attribute
        name = ORIENT_SPECIFIC
        count = 3
         0 3 4

        type  = float-attribute
        name  = ORIGIN
        count = 3
         -81.500008 -15.857000 77.750862

        type  = float-attribute
        name  = DELTA
        count = 3
         1.697917 1.697917 1.697917

        type = integer-attribute
        name = DATASET_RANK
        count = 8
         3 1 0 0 0
         0 0 0

        type = integer-attribute
        name = DATASET_DIMENSIONS
        count = 5
         96 96 30 0 0

        type = integer-attribute
        name = BRICK_TYPES
        count = 1
         3     => 0=byte,1=short,3=float

        type = float-attribute
        name = BRICK_FLOAT_FACS
        count = 1
         0

        type = string-attribute
        name = BYTEORDER_STRING
        count = 10
        'MSB_FIRST~
        ...
    ------------- volume file -----------------
    data:  <stem>+orig.BRIK (binary, any byteorder)
    -------------------------------------------

 MGH .mgh/.mgz file (.mgz is gzipped .mgh):
    --- header (284 bytes) -------------------
    (int) 1		# version
    (int) 256		# width
    (int) 256		# height 
    (int) 256		# depth
    (int) 1		# nframes
    (int) type		# 0=uchar,1=int,3=float,4=short
    (int) dof		# degress of freedom
    (float) spacingX		# pix dim (usu. 0.0!)
    (float) spacingY		# pix dim (usu. 0.0!)
    (float) spacingZ		# pix dim (usu. 0.0!)
    (short) goodRASFlag	# 0/1
    (float) -1.0		# x_r (def)
    (float) 0.0		# x_a
    (float) 0.0		# x_s
    (float) 0.0		# y_r
    (float) 0.0		# y_a
    (float) -1.0		# y_s
    (float) 0.0		# z_r
    (float) 1.0		# z_a
    (float) 0.0		# z_s
    [...zero pad to byte 283 (0-based)]
    --- image data begins -------------------
    ...
    --- optional footer ---------------------
    (float) 0.0		# TR
    (float) 0.0		# flip
    (float) 0.0		# TE
    (float) 0.0		# TI
    (float) 256.0		# FoV
    --- optional tags -----------------------
    (int) 31		# tagID example
    (int) 74		# length example
    (variable)		# tag content
    ... [additional tags]
    -----------------------------------------

##############################
Surface Geometry Binary File Formats
##############################

All of the following formats are auto-detected by
the tcl/C function:

  read_binary_surface

There are two main types of surface formats for
individual brains in FreeSurfer.  The first
format contains quadrangles, which come from the
faces of the voxels categorized as white matter
touching not-white-matter.

  Quad Surface File Format (short vtx coords):
    -------------- header ---------------------
      3-byte magic number (16777215)
      3-byte int vertex count (~150,000)
      3-byte int face count (~150,000)
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      2-byte int vertex x-position (mm x 100)
      2-byte int vertex y-position (mm x 100)
      2-byte int vertex z-position (mm x 100)
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      [vtx nums here implicit from above, 0-based]
      [num each face ordered CCW from outside]
      corner1 corner2 corner3 corner4
      ... [quadruples up to face count]
    -------------------------------------------

  New Quad Surface File Format (float vtx coord):
    -------------- header ---------------------
      3-byte magic number (16777213)
      3-byte int vertex count (~150,000)
      3-byte int face count (~150,000)
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      4-byte float vertex x-position (mm)
      4-byte float vertex y-position (mm)
      4-byte float vertex z-position (mm)
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      [vtx nums here implicit from above, 0-based]
      [num each face ordered CCW from outside]
      corner1 corner2 corner3 corner4
      ... [quadruples up to face count]
    -------------------------------------------

  ASCII Quadrangle Surface File Format (ASCII):
    -------------- header ---------------------
      #!ascii ... quadrangles  ... (magic=2302305)
      vertexcount facecount
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      x y z
      x y z
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      corner1  corner2  corner3  corner4
      corner1  corner2  corner3  corner4
      ... [quadruples up to face count]
    -------------------------------------------

The second surface file format contains triangles.
These are initially made by subdividing each
voxel-face quadrangle into two triangles.

  Triangle Surface File Format:
    -------------- header ---------------------
      3-byte magic number (16777214)
      less-than-200-char '\n'-terminated string
      [e.g., "created by %s=user on %s=time\n"] 
      4-byte int vertex count (~150,000)
      4-byte int face count (~300,000)
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      4-byte float vertex x-position (mm)
      4-byte float vertex y-position (mm)
      4-byte float vertex z-position (mm)
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      [vtx nums here are implicit ones above]
      [vtx nums here implicit from above, 0-based]
      corner1 corner2 corner3
      ... [triples up to face count]
    -------------------------------------------

  ICO Triangle Surface File Format (ASCII):
    ---------- vertex positions ---------------
      163842  (e.g., ico7  ASCII vertex count)
      1   x1   y1   z1      (ic7.tri: radius=1)
      2   x1   y1   z2
      ... [numbered x,y,z triples to vtx count]
    ---- vertex numbers around each face ------
      327680   (e.g., ico7 ASCII face count)
      1   corner1  corner2  corner3
      2   corner1  corner2  corner3
      [vtx nums here are explicit nums above]
      [num each face ordered CCW from outside]
      ... [numbered triples to face count]
    -------------------------------------------

  ASCII Triangle Surface File Format (ASCII):
    -------------- header ---------------------
      #!ascii ... [triangles] ... (magic=2302305)
      vertexcount facecount
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      x y z
      x y z
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      corner1  corner2  corner3
      corner1  corner2  corner3
      ... [triples up to face count]
    -------------------------------------------

  VTK Triangle Surface File Format (ASCII):
    -------------- header ---------------------
      # vtk DataFile Version 3.0
      <filename or other single-line info>
      ASCII
      DATASET POLYDATA
      POINTS <vertexcount> float
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      x y z
      x y z
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      POLYGONS <facecount> <totaltokens>
      [faces are implicitly numbered]
      3  corner1  corner2  corner3
      3  corner1  corner2  corner3
      ... [4-tuples up to face count]
    -------------------------------------------
      [optional columns of vertex overlay data]
      [ignored if file read as surface]
      POINT_DATA <vertexcount>
      SCALARS EmbedVertex float <columncount>
      LOOKUP_TABLE default
      column1value column2value ... [columncount entries]
      column1value column2value ... [columncount entries]
      ... [implicitly num'd tuples to vertexcount]
    -------------------------------------------

  OFF Triangle Surface File Format (ASCII):
    -------------- header ---------------------
      OFF (or COFF)
      # comment line ...
      <vertex-count> <face-count> <edge-count>
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      x y z
      x y z
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      3  corner1  corner2  corner3
      3  corner1  corner2  corner3
      ... [4-tuples up to face count]
    -------------------------------------------

  GIFTI Triangle Surface File Format (ASCII)
    -------------- header ---------------------
      <?xml version="1.0" encoding="UTF-8"?>
      <GIFTI xmlns:xsi="http://www.w3.org/...
         ...
         Version="1"
         NumberOfDataArrays="2">
        ...
        <DataArray Intent="NIFTI_INTENT_POINTSET"
                   DataType="NIFTI_TYPE_FLOAT32"
                   ArrayIndexingOrder="RowMajorOrder"
                   Dimensionality="2"
                   Dim0="32492"
                   Dim1="3"
                   Encoding="GZipBase64Binary"
                   Endian="LittleEndian"
                   ExternalFileName=""
                   ExternalFileOffset="0">
              ...
          <Data>
            [usu: base64 encoded gzipped binary floats]
          </Data>
        </DataArray>
        <DataArray Intent="NIFTI_INTENT_TRIANGLE"
                   DataType="NIFTI_TYPE_INT32"
                   ArrayIndexingOrder="RowMajorOrder"
                   Dimensionality="2"
                   Dim0="64980"
                   Dim1="3"
                   Encoding="GZipBase64Binary"
                   Endian="LittleEndian"
                   ExternalFileName=""
                   ExternalFileOffset="0">
          ...
          <Data>
            [usu: base64 encoded gzipped binary ints]
          </Data>
        </DataArray>
      </GIFTI>
    -------------------------------------------

  OBJ (Wavefront) Triangle Surface File Format (ASCII):
    -------------- header ---------------------
      # comment line (no req'd header)
      [vertex triples implicitly numbered]
      "v"  x  y  z  [r  g  b]
      "v"  x  y  z  [r  g  b]
      ... [x,y,z triples or sextuples up to vertex count]

      [normal triples implicitly num'd, norm maybe!=1]
      [N.B.: currently ignored here and recalc'd as usual]
      "vn"  x  y  z
      "vn"  x  y  z
      ... [x,y,z triples up to vertex count]

      [face triples implicitly num'd]
      [entries: vtx, vtx/tex, vtx//norm, vtx/tex/norm]
      [N.B.: vtx/tex/norm nums are 1-based!]
      [N.B.: ignores tex/norm nums]
      "f" vtx1 vtx2 vtx3
               *or*
      "f" vtx1/tex1 vtx2/tex2 vtx3/tex3
               *or*
      "f" vtx1//norm1 vtx2//norm2 vtx3//norm3
               *or*
      "f" vtx1/tex1/norm1 vtx2/tex2/norm2 vtx3/tex3/norm3
      ... [triples up to face count]
    -------------------------------------------

  SRF (BrainVoyager) Triangle Surface File Format (binary):
    -------------- header ---------------------
     4-byte float version (4)
     4-byte int reserved (must be 0)
     4-byte int vertexcnt
     4-byte int facecnt
     4-byte float centx
     4-byte float centy
     4-byte float centz
     vertexcnt*4-byte floats x (N.B.: left-handed coords!)
     vertexcnt*4-byte floats y
     vertexcnt*4-byte floats z
     vertexcnt*4-byte floats normal x (inward pointing!)
     vertexcnt*4-byte floats normal y
     vertexcnt*4-byte floats normal z
     4*4-byte float convex curv color r,g,b,a
     4*4-byte float concave curv color r,g,b,a
     vertexcnt*4-byte int vertex colors
     foreach vertex
       4-byte int neighbor count [N.B.: varies]
       count*4-byte int neighbors
     facecnt*3*4-byte int face corner vtx numbers
     [optional triangle strips] 
    -------------------------------------------


Notes

For GIFTI surface, csurf/tksurfer currently reads
encodings:

  Base64Binary
  GZipBase64Binary

but not:

  ASCII
  ExternalFileBinary

For details of the GIFTI format, see:
https://www.nitrc.org/projects/gifti/

GIFTI surfaces will appear in the "surface:"
dropdown if they are in the "surf" subdir of an
otherwise empty new subject made by:

  File -> New Subject (Manual Recon)

and if they match the following pattern:

  *.{L,R}.*.surf.gii

OBJ (Wavefront) surfaces will appear if they
match the following pattern:

  *.obj

To make a *.vtk (or other .obj) surface appear in
the "surface:" dropdown, add a hemisphere and
freesurfer surface-type prefix, for example,
rename

  <some_arbitrary_long_filename>.vtk

to

  rh.orig.<some_arbitrary_long_filename>.vtk


##############################
Per-Surface-Vertex Binary/ASCII File Formats
##############################

  The format of some of the per-vertex files was
  updated from the original FreeSurfer.  The
  curvature file (*.curv, *.sulc) format was
  updated from short*100 to float.  The old area
  file format (*.area) was discontinued (new area
  and thickness files are same format as new
  curvature).  The patch file format
  ($hemi.$name.patch.flat/3d), which contains
  patch vertex x,y,z positions for a subset of
  vertices in a full/parent surface, was updated
  from short*100 to float.  The value file format
  (e.g., paint output files, *.w) is unchanged,
  although curv format files or 1-D .mgh formats
  are often used for value files.  The fieldsign
  and fieldsign mask files are unchanged.

  The curvature and area files list data for
  every vertex and contain no vertex numbers.
  The patch file contains a subset of one-based
  surface vertices with the sign used as a flag
  for boundary vertices.  The value files
  (wfiles) contain a list of vertex/value pairs
  so a subset of vertices may be specified.  The
  wfile vertex numbers are zero-based.  The
  fieldsign and fieldsign mask files require all
  vertices and have a single float datum per
  vertex.  The byte sizes for the different file
  types are:

  file type                old         new
  --------------------------------------------
  curv (*.curv,*.sulc)    33{2},..    344{4},..
  patch (*.*.patch.*)     4{4222},..  44(4444),..
  area (*.area)           33{4},..    344{4},..
  val (*.w)               23{34},..   23{34},.. 
  fieldsign (*.fs,*.fm)   4{4},...    4{4},...
  --------------------------------------------

Details of binary file formats are as follows
(byte sizes in brackets, repeating group
indicated by "...", byteorder MSB):

  --------------------------------------------
  oldcurv  [no magic]
    header:  vertexcnt[3],facecnt[3]
    data:    floatcurv*100[2], ...
  --------------------------------------------
  newcurv  [magic: -1 => 16777215 read in 3bytes]
    header:  -1[3],vcnt[4],fcnt[4],valspervtx[4]
    data:    floatcurv[4], ...
  --------------------------------------------
  oldarea  [no magic]
    header:  vertexcnt[3],facecnt[3]
    data:    floatarea[4], ...
  --------------------------------------------
  newarea, thickness
    [same as newcurv]
  --------------------------------------------
  oldpatch  [no magic]
    header:  vcnt[4]
    data:    vtx[4], floatx*100[2], y, z, ...
               [vtx=[+,-]1-based: neg->border]
  --------------------------------------------
  newpatch  [magic: -1 read as 4byte int]
    header:  -1[4],vcnt[4]
    data:    vtx[4], floatx[4], y, z, ...
               [vtx=[+,-]1-based: neg->border]
  --------------------------------------------
  valfile  [no magic]
    header:  latency[2],vertexcnt[3]
    data:    {vtxnum[3],floatval[4]}, ...
  --------------------------------------------
  fieldsign files  [no magic]
    header:  vcnt[4]  (must be full)
    data:    floatval[4], ...
  --------------------------------------------
  .mgh file [no magic]
    format: 1frame, nx1x1 .mgh file -- see above
  --------------------------------------------
  _000.bfloat file [no magic]
    header:  matching 1-line ASCII *.hdr file: 1 <vtxcnt> 1 0
    data:    floatval[4], ...
  --------------------------------------------

Details of ASCII vertexwise file formats:

  --------------------------------------------
  .vtk files [magic: 2302070 (read "# vtk" as 3byte int)]
    format: optionalsurf + overlaydata -- see above
  --------------------------------------------
  .gii files [magic: 3948408 (read "<?xml" as 3byte int)]
             [format: single frame vertex list]
    <?xml version="1.0" encoding="UTF-8"?>
    <GIFTI ...
           NumberOfDataArrays="1">
    ...
      <DataArray Intent="NIFTI_INTENT_NORMAL"
                 DataType="NIFTI_TYPE_FLOAT32"
                 ArrayIndexingOrder="RowMajorOrder"
                 Dimensionality="1"
                 Dim0="32492"
                 Encoding="GZipBase64Binary"
                 Endian="LittleEndian"
                 ExternalFileName=""
                 ExternalFileOffset="0">
        ...
        <Data>
          [usu: base64 encoded gzipped binary data]
        </Data>
      </DataArray>
    </GIFTI>
  --------------------------------------------

N.B.: see the R-click help for the entry on the
"label:" line for the format of MGH annotation
files (*.annot), BV patches-of-interest (*.poi)
files, and GIFTI annotation files (*.gii).

##############################
"Template" Binary File Format
##############################

The morph target "template" files are multi-frame
uncompressed 256x512 pixel TIFF files, with 32
bits per pixel, one sample per pixel.  The
standard morph target files:

  rh.average.curvature.filled.buckner40.tif
  lh.average.curvature.filled.buckner40.tif

are stored in $FSURF_DIR/average (subdir in MGH
freesurfer distribution), and contain 3 kinds of
data, with 3 frames for each kind, for a total of
9 (zero-based) frames:

  0: average inflated.H -- mean curvature = (kmin+kmax)/2
  1: variance of inflated.H
  2: degrees of freedom (dof=39 means 40 subjects)
  3: average sulc
  4: variance of sulc
  5: degrees of freedom
  6: average curv
  7: variance of curv
  8: degrees of freedom

The file represents a Mercator projection (yup)
of the curvature values for the registered
sphere.  The degrees of freedom (number of
subjects minus 1) is stored as a floating point
value in the single bottom-left pixel in an
otherwise black third image.

If FSURF_DIR is defined, these frames can be
viewed on sphere.reg surface by loading them from
tksurfer as a "curv:" file (at bottom of list).

##############################
[end file format specifications]
##############################


Default variable values and overrides

The various csurf panels save the state of many
different variables passed to FreeSurfer command
line programs.  For example, the SessionTools ->
View Functional Data panel saves the state of
many (but not all) tksurfer rendering variables.

These values can be overridden in a large number
of ways.  Here are the gory details of what
happens when a functional scan is rendered with
the SURFACE-STATS button.

All of the possible places places where default
values of variables can be overriden are
identified (like this: **2**, **3**, ...)

csurf (on open View Functional Data panel):

  1) csurf reads parm vals from csurf.dat in
       the scripts dir, defaulting most if
       missing

tksurfer (on click SURFACE-STATS button):

  2) tksurfer.c: starts up with default value C
       global variables (before read cmdline opts)

  3) tksurfer.c: reads any known-by-tksurfer vars
       from environment, may reset C vars: **2**

       (N.B.: since MacOSX 10.11+ breaks
       /usr/bin/env by making it not pass
       PATH/DYLD vars, csurf now writes env vars
       to tmpfile, /tmp/TmpEnvCsurf.$pid, and
       tksurfer reads them from there with
       readenv.tcl, which still reads env vars)

  4) tksurfer.c: reads its command line options,
       may reset C vars: **3** (this is how csurf
       passes most variable values from csurf.dat
       to tksurfer)

  5) tksurfer.c: starts tcl interpreter which
       imports curr values of many C global
       variables into tcl interpreter and sets
       up two-way mirroring of tcl<=>C vars

  6) tksurfer.c: runs tksurfer.tcl to make
       interface, can reset some now-joined
       tcl<=>C vars from tcl script **4**

  7) clicks/typing on surfer tools interface
       window may reset joined tcl<=>C vars 
       from tcl **5**

  8) rendering script (e.g., polar-views.tcl)
       may reset tcl<=>C vars from tcl **6**

  9) rendering script calls readenv.tcl to
       (re)-read current state of environment
       **7** (this is the original mechanism of
       controlling render variables from cmdline
       shell scripts in a terminal window, now
       rare)

 10a) if var nosave set (="test" clicked),
        render script calls saveviews.tcl
        to just redraw surface, which may
        reset vars **8**

             *or*
              
 10b) if var nosave *not* set ("save" clicked
        or batch run), render script calls
        saveviews.tcl to redraw *and* save
        bitmap, which may reset vars **8**

             *or*

 10c) manually click WRITE rgb button which
        saves current window after popping it
        and redrawing (to make sure on top)

Explicitly setting a variable in saveviews.tcl,
the last step in this chain (or saveflat.tcl), is
thus the surest way to set the values of a
tcl<=>C variable.  However, this is particularly
inflexible because it will affect all subsequent
renders.

Custom Tcl Scripts

To get complex control of all variables you can
write a custom render script (use polar-views.tcl
and saveviews.tcl as a model), and put it in the
current scripts dir.  Any scriptsdir file ending
in *.tcl will appear at the top of the list in
the "3D" or "Flat" dropdown scripts fields at the
bottom of View Functional Data panel (in addition
to the default scripts in $CSURF/lib/tcl).

If the script is general enough, it can be put
into $CSURF/lib/tcl and added to the list of
scripts in $defscriptlist in tksurfer.tcl that
always appear in the tksurfer tools tcl script
dropdown.

Such a script can be run by specifying it as
a command line option to tksurfer:

  tksurfer marty rh smoothwm -tcl zz.tcl

or it can be sourced from the tcl prompt
after starting tksurfer in a terminal:

  tksurfer marty rh smoothwm
  % source zz.tcl

or it can be sourced from the tksurfer.tcl
interface.  First enter the path to the script in
the "tcl:" entry with the following conventions:

  zz.tcl => look in curr session "scripts" dir
  #/zz.tcl => look in $CSURF_DIR/lib/scripts
  /full/patch/zz.tcl => anywhere

then click:

  EDIT => if you want to view/edit script
  GO => to run script

Here is a simple tcl script example that opens a
window, displays the curvature on the currently
selected surface, slightly zooms in, and then
saves a bitmap of it:

  set overlayflag 0
  read_binary_curv
  open_window
  make_lateral_view
  scale_brain 1.3
  redraw
  set rgb /tmp/zz.tiff
  save_rgb

Here is how to start with the rendered results of
one of standard scripts, and then modify it with
additional tcl commands:

  setfile script #/eccen-views.tcl
  source $script
  ... [your additional tcl code here]
  ... [your additional tcl code here]
  redraw
  set rgb /tmp/zz.tiff
  save_rgb

To find the names of all tcl variables and procs'
understood by the tksurfer tcl interpreter, type
"tksurfer -help".

See tksurfer R-click popup for "tcl:" entry for
more help and more examples.

HOWTO render very high resolution images

To render and save an image with a higher pixel
resolution than the screen, open an offscreen
window using a tcl script.  Here is a bare-bones
script to do this:

  set renderoffscreen 1
  resize_window 3500  ;# pixels
  open_window
  make_lateral_view
  ## cmds here to read data, adj pose
  redraw
  set rgb /tmp/zz.tiff
  save_rgb 

To run this script, save the script above into a
file and run:

  tksurfer <subj> <hemi> <surf> -tcl <scriptname>

For a more detaled example with overlay data, see
the right-click help for the "rgb:" entry.

Record Tcl Commands for Interface Actions

To get a file containing all the tcl commands
that have been executed as tksurfer or tkmedit
interface buttons and entries were interactively
manipulated, use:

  Preferences -> Log tksurfer actions as tcl cmds
  Preferences -> Log tkmedit actions as tcl cmds

This will dump all the tcl commands into:

  $FUNCTIONALS_DIR/$session/image/scripts/tksurfer.log
  $FUNCTIONALS_DIR/$session/image/scripts/tkmedit.log

N.B.: if these menu items are enabled, every time
tksurfer or tkmedit is restarted from csurf, the
previous tksurfer.log or tkmedit.log in the
scripts dir in this session is erased and a new
clean one is begun.

To see the tcl commands as they are deposited to
one of these logs after each click, use 'tail -f'
(i.e., watch end of file for additions):

  cd $FUNCTIONALS_DIR/$session/image/scripts
  tail -f tksurfer.log
    *or*
  tail -f tkmedit.log

Csurf Hacking

The csurf tcl/tk/tix program is a single 24K-line
ASCII file that can be viewed and modified in a
text editor.  Its only dependency is a small
utility script, wrappers.tcl, that is sourced at
startup ($CSURF_DIR/lib/tcl/wrappers.tcl, also
sourced by tksurfer, tkmedit, tkregister).

Csurf saves scandir-specific parameters for a given
session in:

  $CSURF_DIR/$session/image/scripts/csurf.dat

which contains ASCII dumps of configuration
parameters.  These are in the form of a parameter
arrayname on one line (e.g., functscanlists)
followed by a list of name-value pairs on the
next (long) line, where the format of name is:

  <iscandir>,<parmeter-name>

and the format of value is text or a number.  For
example:

  % cat csurf.dat
  ...
  csurf arrayname: functscanlists
  image/1-pol1,regdat register.dat image/1-pol1,fmid 2.2 ...
  ...

To get terminal window access to the csurf tcl
interpreter for debugging, inspection, or
hacking, do:

  cd $CSURF_DIR
  source FreeSurfer.{c}sh
  wish8.5
  % source $env(CSURF_DIR)/bin/noarch/csurf

You will now be able to see and modify/run all
csurf tcl vars and procs/commands.  For example:

  % info vars [patt]			=> list all vars [or subset]
  % info commands [patt]			=> list all cmds [or subset]
  % set <var>			=> see curr value
  % set <var> <value>			=> set new value
  % <command> <args ...>			=> run command
  % info commands .*			=> list interface win parts
  % .main.right.label config			=> see state this widget
  % .main.right.label config -text FunctionalBLAH	=> mod

--------------
References
--------------

Sereno, M.I., A.M. Dale, J.B. Reppas, K.K. Kwong,
  J.W. Belliveau, T.J. Brady, B.R. Rosen, and
  R.B.H. Tootell (1995) Borders of multiple
  visual areas in human revealed by functional
  magnetic resonance imaging. Science
  268:889-893.

Dale, A.M., B. Fischl, and M.I. Sereno (1999)
  Cortical surface-based analysis I: Segmentation
  and surface reconstruction. NeuroImage
  9:179-194.

Fischl, B., M.I. Sereno and A.M. Dale (1999)
  Cortical surface-based analysis II: Inflation,
  flattening, and a surface-based coordinate
  system. NeuroImage 9:195-207.

Fischl B., M.I. Sereno, R.B.H. Tootell and A.M.
  Dale (1999) High-resolution inter-subject
  averaging and a surface-based coordinate
  system.  Human Brain Mapping 8:272-284.

Hagler, D.J. Jr., A.P. Saygin, and M.I. Sereno
  (2006) Smoothing and cluster thresholding for
  cortical surface-based group analysis of fMRI
  data. Neuroimage 33:1093-1103.

Hagler, D.J. Jr., L. Riecke, and M.I. Sereno
  (2007) Pointing and saccades rely on common
  parietal and superior frontal visuospatial
  maps.  Neuroimage 35:1562-1577.

Sereno, M.I., A. Lutti, N. Weiskopf, and F. Dick
  (2012) Mapping the human cortical surface by
  combining quantitative T1 with retinotopy.
  Cerebral Cortex 23:2261-2268.

Huang, R.-S. and M.I. Sereno (2013) Bottom-up
  retinotopic organization supports top-down
  mental imagery.  The Open Neuroimaging Journal
  7:58-67.

Sood, M. and M.I. Sereno (2016) Areas activated
  during naturalistic reading comprehension
  overlap topological visual, auditory, and
  somatotomotor maps. Human Brain Mapping
  37:2784-2810.

Sereno, M.I., J. Diedrichsen, M. Tachrount, G.
  Testa-Silva, H. d'Arceuil, and C. De Zeeuw
  (2020) The human cerebellum has almost 80% of
  the surface area of the neocortex.  Proceedings
  of the National Academy of Sciences USA
  117:19538-19543.


####################
defnotes
####################

[put notes for this scan here]

======================================
Default NOTES on first selecting:

   File -> Open NOTES (Subject)
   File -> Open NOTES (Functional)
   File -> Open NOTES (SphereAvg)

These user-edited subject- and session-specific
files are stored here:

   $subject/scripts/NOTES
   $session/image/scripts/NOTES
   $sphsession/image/scripts/NOTES

This editable template file is stored here:

   $CSURF_DIR/lib/help/csurf/defnotes

Or users can set up their own default NOTES:

   ~/.csurfnotes
======================================

####################
HOWTO
####################


Basic retinotopy HOWTO -- Martin Sereno 2015

======================================
1) Update to Latest Csurf
======================================

The latest tarfiles for the UCSD/UCL
retinotopy-enabled csurf are here:

  http://www.cogsci.ucsd.edu/~sereno/.tmp/dist/csurf

On Mac, make sure XQuartz (X11) is installed
(e.g., version 2.7.7).

To update to most recent csurf distribution, open
a Terminal, move aside previous csurf directory
(if any), and download and unpack appropriate
tarfile (which unpacks to just "csurf").  For
example:

  mv csurf csurf-150601
  cd ~
  tar xvfz ~/Downloads/csurf0.8-mac-150922.tgz

Make sure MGH freesurfer (e.g., version 5.3) is
installed and licensed, for example:

  cp ~/csurf/.license /Applications/freesurfer

======================================
2) Setup Paths and Start csurf 
======================================

Decide on default directories for subjects and
sessions (these directories must exist), and tell
csurf where MGH freesurfer is installed.  For
example:

  [csh/tcsh]
  mkdir ~/subjects ~/sessions
  setenv SUBJECTS_DIR ~/subjects
  setenv FUNCTIONALS_DIR ~/sessions
  setenv FSURF_DIR /Applications/freesurfer
      *or*
  [sh/bash]
  mkdir ~/subjects ~/sessions
  export SUBJECTS_DIR=/bigdisk/subjects
  export FUNCTIONALS_DIR=/bigdisk/sessions
  export FSURF_DIR /usr/local/freesurfer

Next, setup your path:

  cd ~/csurf
  source FreeSurferEnv.csh

and finally, start the csurf interface:

  csurf

The 5 setup lines (before "csurf") should be put
into an alias in .cshrc or .bash_profile.  Here
are examples for csh and bash:

[csh/tcsh]
alias fs \
  "setenv FSURF_DIR /Applications/freesurfer; \
   setenv SUBJECTS_DIR ~/subjects; \
   setenv FUNCTIONALS_DIR ~/sessions; \
   pushd ~/csurf; \
   source FreeSurferEnv.csh; \
   popd"

[sh/bash]
alias fs="\
  export FSURF_DIR=/Applications/freesurfer; \
  export SUBJECTS_DIR=~/subjects; \
  export FUNCTIONALS_DIR=~/sessions; \
  pushd ~/csurf; \
  source FreeSurferEnv.sh; \
  popd"

That way, for a new terminal/xterm, you will only
need to type:

  fs
  csurf

======================================
3) Get Structural Scan(s) and Reconstruct Surfaces
======================================

Collect a high-resolution T1-weighted scan or two
(see example scan parameters in Help -> Run
Recon-all).  Convert the scan(s) to nifti or to
AFNI BRIK(s).

  MGHTools -> Run Recon-all

  type new subj name in "new/redo subject"
  <Return> to verify no name overlap
  click FIND for browser to select files
    expand directories in left browser column by double-clk
    select *.nii or *.BRIK file in right browser column
  if more than one scan, do ADD SCAN, FIND again
  click RECON-ALL => wait 8 hours

When done, examine surfaces by selecting the
newly made subject from the "subject:" dropdown,
and clicking SURFACE.

You can look at other data sets for this subject
by clicking one of them from dropdowns (e.g.,
"orig", "T1", "brain" for VOLUME, or "folded",
"inflated" for SURFACE).

Optionally, cut and flatten surfaces:

  MGHTools -> Make Full Surface Cuts
  MGHTools -> Make Occip Surface Cuts

and then:

  MGHTools -> Flatten Surface Patch

For details on how to make cuts, see:

  Help -> Make Relaxation Cuts

======================================
4) Collect Functional Scans
======================================

Mac and linux X11/OpenGL stimulus software,
mapper, for generating these and other stimuli,
can be found here:

  http://www.cogsci.ucsd.edu/~sereno/.tmp/dist/mapper

A typical retinotopy run might have two polar
angle scans and one eccentricity scan.  For
example, multiband accel=4, 2.3mm^3, TR=1, 512
repetitions.  The two polar angle scans should be
counter-clockwise starting at right and
clockwise, starting at right.  The eccentricity
scan should be expanding.

For ease of alignment, you should collect a short
T1-weighted scan collected with the same block
center and block orientation (e.g., 1x1x2mm
MPRAGE) as the functional scans.

Convert the functional scan DICOMs to AFNI BRIKs
(e.g., using AFNI to3d or the csurf to3d-runner
script, ima2brik).

======================================
5) Import Functional Data into csurf
======================================

First, create a new empty Functional scan:

  File -> New Functional

This queries you for subject name (N.B.: must
already be reconstructed).  Name the functional
session so that it sorts chronologically, for
example, year/month/day/initials:

  150901MS

Now import/rename the functional data scans
into csurf using:

  SessionTools -> File Make Scandirs, Find/Copy Raw

This provides a spreadsheet like interface to
specify the raw scan filenames (use FIND), their
(one hopes, more informative) imported filenames,
and how many throw-away TR's to strip from the
beginning of each run.

Make sure to expose the directory containing the
NIFTI's or AFNI BRIK's (raw 3D) scans in the
column at the left of the file chooser.

Take time picking good scandir names (e.g., use
stimulus program script name).  These names will
be what you will see from now on.  As you add
more empty lines, they will be auto-numbered, so
scans sort in order they were performed (auto
numbers can be removed if you insist).  When
first three columns are all filled in, follow
instructions on panel:

  click MAKE SCANDIRS
  click STRIP/COPY-RAW

======================================
6) Align Functional Data with Surface Scan
======================================

Now open first panel in SessionTools:

  SessionTools -> Setup Align/Funct Scans

select the alignment scan (from the list at the
left), and declare it to be one with "Align Scan
Dir" button at the top of the panel, then fill in
panel:

  click READ HEADER
  [verify parmeters auto-filled-in parms]
  click INIT/FLIP to initialize transform

Now start up tkregister to manually/interactively
rotate and translate the alignment scan to bring
it into register with the original scans the
surface was made from using the button:

  ALIGN=>SUBJ

After tkregister comes up, click COMPARE to blink
between TARGET and MOVEABLE, change "fmov:"
(up/down arrows) to make brightness of MOVEABLE
match TARGET, click in troughs of sliders for
TRANSLATE BRAIN and ROTATE BRAIN to get small
movements, and click CORONAL, SAGITTAL, and
HORIZONTAL to change planes (good to do this
often).

Though window can be enlarged (type 1,2,3),
registering is easiest with the smallest window.
For more help:

  Help -> tkregister

When done with the manual alignment, hit SAVE REG
on tkregister (saves 4x4 transformation matrix,
register.dat, to current scandir) and quit the
tkregister application

Now configure all functional scans by selecting
each one in the left column, and declaring it to
be a "Funct Scan Dir" (button at top), and then
click:

  READ HEADER

to fill in the panel (check if correct).

After all scans configured, run AFNI motion
correction (3dvolreg) on the functional scans.
It's best to align all functional scans to a
single target functional scan that was closest in
time to the T1 alignment scan.  For each scan:

  select "Targ:" scan from dropdown (at middle)

When all selected, click the button:

   ALL=>T    (takes a few min)

which aligns every TR from every scan to the
selected TR (right) from the "Targ:" scan.

Now go back to the Align Scan directory and copy
the transformation matrix into all the functional
directories (automatically accounting for the
difference in voxel size) with the button:

  COPY ALIGN TO ALL FUNCTS

You may want to touch up the transformation
matrix using the functional scans themselves
by starting tkregister in one of the functional
scan directories with the button:

  FUNCT=>SUBJ

To propagate that touched-up transformation, you
can use the button:

  CP TO OTHERS

======================================
7) Raw Average of Unreversed+Reversed Scans
======================================

To combine oppositely phase-encoded scans that
start at the same point in a periodic stimulus
(e.g., counter-clockwise and clockwise rotating
wedges that both start at the right), use:

  SessionTools -> Combine 3D Raw Images

First, make a new scandir to contain the average.
Type in an informative name at the top by
appending to the default suggestion, which will
be "image/rawavg".  For example, use at least
something like "image/rawavg-polar".  Then click
the button:

  Make Avg/Concat Dir

Select scans to combine using the "Select to Add:"
dropdown (at middle).  

To time-reverse one or more scans, select one in
"Rev--ScansToCombine" and hit a <Return>.

Timeshift is in TRs, and should estimate time to
hemodynamic delay peak (e.g., 2 or 3).

To average click COMBINE at top right.

======================================
8) Fourier Analysis
======================================

Now, run the Fourier analysis:

  SessionTools -> Calculate 3D Fourier Stats

Default for most panel entries are fine.

  Enter num stimulus cycles (e.g., 8)
  Enter TR (e.g., 2)
  Choose "eccen" or "polar" phase encode type

To run Fourier transforms and calculate
statistics (3D data), click FOURIER.  This
generates a set of BRIKs (viewable with the AFNI
button, top right).

To sample the data to the surface and filter the
stats using surface-based cluster exclusion, use
PAINT.

The parameters controlling the sample-to-surface
process are at the bottom of the panel:

  SessionTools -> Setup Align/Funct Scans

for the corresponding scandir on the "NormSearch
line.  By default, the data is sampled using the
"white" surface with no normal search.  This is
convervative but can miss stronger responses
higher up in the cortical column.

To turn on normal search, select either the "mm"
switch will update the "mn/mx:" fields (min/max
search along surface normal).  The defaults
(adjustable after defaulting) are:

  mm: search 0.0 mm to 2.0 mm in steps of 0.25 mm
  frac: search 0.0-0.8 (1.0=pial) in steps of 0.1

The default operation is "mx" (max complex
amplitude found).

Details of StatFile Outputs, Cluster Exclusion

The FOURIER button runs the program fourier,
which generates 6 different statistical BRIKs:

  ### complex pair: phase angle w/amp stimfreq power
  <stem>_x+orig.BRIK
  <stem>_y+orig.BRIK

  ### complex pair: phase angle w/amp sqrt(F)
  <stem>_r+orig.BRIK
  <stem>_i+orig.BRIK

  ### real-valued F stat
  <stem>_f+orig.BRIK

  ### optional real-valued 3D cluster-filtered F stat
  <stem>_h+orig.BRIK

The Fourier panel parameter:

  "3D  and Surf Clust: PreThre (F/p):"

is the hard statistical threshold before the
cluster filters are applied.  This threshold
applies to both volume (3D) and surface-based
(2D) cluster filters.

The volume (3D) cluster filter is implemented by
AFNI 3dmerge, and is controlled by the paramters:

  "3DCluster: min rad (mm)":
              "min vol (mm^3)":

After 5 of the 3D stats files (_r,_i and _x,_y
and _f) have been sampled to the surface by
PAINT, the PAINT button will then also optionally
run a surface-based 2D cluster filter implemented
by surfclust (runs if following parameter is
bigger than 0.0):

  "SurfCLuster: min area (mm^2)"

Surfclust filters out surface clusters smaller
than this from the already-sampled-to-surface
vertex list wfile:

  <stem>_f-$hemi.w

to generate a second surface file:

  <stem>_h-$hemi.w

See Help -> Cross Session Spherical Average for
details on using the cmdline line program,
randsurfclust, to estimate this parameter.

======================================
9) Optional Fieldsign
======================================

If both polar and eccentricity data are
available, optionally calculate visual field sign
(or find borders where visual field is
duplicated) with:

  SessionTools -> Calc Visual Fieldsign, Borders

Select one polar and one eccentricity scan (these
can be averages) from dropdowns and click
FIELDSIGN and/or GROWBORD (takes much longer).

======================================
10) Render Data on Surface
======================================

Open the rendering panel:

  SessionTools -> View Functional Data

The row of "ResetToDefault:" buttons
will reset the many parameters in this
panel to sane values for several main
types of scans (e.g., "polar", "eccen").

Minimally, you have to:

  select hemi (upper left)
  select surface or patch (dropdowns)
  select stat to view ("Paintfile:" dropdown)
  SURFACE-STATS -> starts tksurfer

Any changes made to the parameters on the
tksurfer panel that opens when SURFACE-STATS is
clicked will *not* be saved.  To save parameters
for next time, enter them on the View Functional
Data panel and click Save or Save/Close.

Stats Files

The data displayed on the surface is typically a
<stem>_<infixletter>-$hemi.w file, which is a
list of values to display at each numbered
surface vertex for one hemisphere.  The file
content type is indicated by the underscore infix
near the end.  Some typical ones are:

  _x  real comp. Fourier transform at stim freq
  _y  [imaginary comp. same]

  _r  as above, but amplitude replaced by sqrt(F)
  _i  [imaginary comp. same]

  _f  F-ratio (not sqrt)
  _h  surface-based cluster-filtered F-ratio

Color Scales for Complex-Valued Data

There are many different color scales.  With
complex valued data, color is usually used to
indicate response phase (angle of complex
vector), not response amplitude.  Response
amplitude (length of complex vector) is indicated
by color saturation, which fades into the
background gray below the set threshold.

The two main thresholding parameters that control
the saturation are "fthresh:" (hard cutoff if
amplitude at vertex is below entry), and "fmid:"
(soft cutoff, same units).  For fourier-analyzed
data, the amplitude will be the complex
amplitude.  The "fslope:" entry controls the
sharpness of the "fmid:" threshold.

Optional Stat Mask

If a real-valued statistical mask has also been
read in (e.g., _f or _h infix), and "mask" is
ticked, it can secondarily be used to modulate
color saturation.  In this case, the "fthresh:",
"fmid:" and "fslope:" entries will each be
replaced by a pair of entries.

The first (leftmost) entry of each set controls
color saturation using the amplitude as before.
The second (rightmost) entry is a second control
on color saturation.  If the *statistic* at this
vertex is below the setting in the entry, the
color saturation will roll off to background.

Surface Smoothing

Data and stats can be smoothed on the surface
with the SMOOTH button (lower left).  10 steps of
surface smoothing is very nearly identical to
convolution with a 3 mm full-width half maximum
Gaussian.

When smoothing stats, it is advantageous to use
the stat mask plus complex data rather than only
the complex data with 'built-in' statistic (i.e.,
_r,_i, which has complex amplitude substituted by
sqrt(F)).  This is because phase differences in
the _r,_i vectors for nearby vertices will cause
the 'built-in' significance to be reduced more
quickly during complex-valued vector smoothing
than will smoothing of the *real-valued* _f mask.

======================================
11) Render Retinotopy Data in the Volume
======================================

Retinotopy responses/stats calcuated by the
fourier program in 3D at the functional image
resolution can also be *viewed* in 3D, using many
of the same phase color scales available for the
surface display:

  SessionTools -> View Functional Data
  VOLUME-STATS -> starts tkmedit in overlay mode

The high-resolution structural underlay is the
"orig" data set (typically 1x1x1 mm).  The lower
resolution funct/stat data is registered and
upsampled to structural resolution on the fly
using register.dat.  The matrix in register.dat
transforms 3D vertex or hi-res structural
coordinates to funct/stat voxel indices.

There are three different classes of 3D overlay
files:

  val -- real or complex values (e.g., _r,_i or _x,_y)
  msk -- real-valued statistical mask (e.g., _f,_h)
  roi -- binary label (tkmedit FILL, tksurfer conv label)

The bold labels of the three entry dropdowns
in the middle of the tkmedit panel (val, msk,
roi) can be toggled between two states:

  "valn:"  <==>  "valup:"
  "mskn:"  <==>  "mskup:"
  "roin:"  <==>  "roiup:"

The "n" suffix means "native" (i.e., original
functional resolution), while the "up" suffix
means "upsampled" (upsampled to structural
resolution).

In the "native" state (valn, mskn, roin), the "R"
button on the line will read, register, and
upsample the file to structural resolution.  In
the "upsample" state (valup, mskup, roiup), the
already upsampled file is merely read.  The "W"
button (only available in the "upsample" state)
allows writing the upsampled file for later use.

The "val" line "R" buttons will automatically
attempt to read the other member of a pair of
complex data sets (e.g., _r,_i or _x,_y).

View (complex) Values Directly

The value files can be viewed directly and
thresholded by (complex) amplitude using
"fthresh" and "fmid" ("fslope" controls the
sharpness of the soft threshold, fmid).  As on
the surface, hue is used to indicate phase, while
color saturation indicates amplitude.

Statistical Mask

A separate statistical mask can be read in (e.g.,
<stem>_f+orig.BRIK) using "R" on the "msk" line
and used to independently modulate the
saturation.

To toggle the effect of the mask, use the
unmarked tickbox at the left of the "msk" line.
When the mask is engaged, there will be two
entries each for fthresh, fmid, and fslope; the
first is in value units (e.g., complex amplitude
of sqrt(F) for _r,_i files) and the second is in
statistic units (e.g., F-ratio for _f files).

3D Gaussian Smoothing

When smoothing (SMOOTH STATS button), it is
advantageous to use a real-valued statistical
mask instead of directly vector-smoothing the
complex-valued data because local phase
differences in the first case will cause
significance to reduce more rapidly.

ROI labels

A third kind of 3D file is an ROI label, which is
conceptually parallel to a surface label.  An
upsampled ROI can be generated by using the
tkmedit FILL button to fill regions in 3D up to a
threshold specified by "fthresh" and optionally
subject to a maximum radius specified by the
entry next to FILL (if that number is bigger than
0.0).

A native resolution ROI can also be generated
from a surface label (see help for tksurfer
"label:" line "D" button).

To toggle the visibility of an ROI label as a
white overlay, use the "roi" tickbox above the
FILL button.  To toggle the effect of the same
ROI label as a mask on the overlay data (data
only shown where ROI label is 1), use the
adjoining "m" tickbox instead.

======================================
12) Batch Redo
======================================

If you redo your registration done back at the
beginning, you need to re-paint and re-render
everything.  If you want to redo your
registration and then re-paint and re-render,
run:

  SessionTools -> Run Batch Process

select Run All Paint Surfaces and Run All
Rendering Panels, and hit Start.  This will open
all the panels of currently configured scans (as
configured when you hit Save or Save/Close for
each panel), run the PAINT button in each one,
and then run the SURFACE-STATS button in each
one.

In addition, it will save bitmaps for any folded
or flat views you have configured on View
Functional Data panels.

======================================
13) More Help
======================================

The Help -> ... menu items have more detailed
information for all the extra panels. You can
never leave too many ASCII notes in:

  File -> Open Subject NOTES
    (in $subject/scripts/NOTES)

  File -> Open Functional NOTES
    (in $session/image/scripts/NOTES)

Most buttons and entries and tickboxes in csurf,
tksurface, tkmedit, and tkregister have pop up
help on right-click (over 300 pop-up panels).

####################
helpbutton
####################

Help/Instructions

Help files are available for each analysis step
in the csurf Help menu, arranged in typical order
of use.

The small "h" buttons at one corner of csurf,
tksurfer, tkmedit, and tkregister bring up
general help for that application.

In addition, every button, checkbox, and text
entry in csurf, tksurfer, tkmedit, and tkregister
has a R-click popup help panel.  Each help panel
can be searched for keywords using Cmd-f (Mac) or
Alt-f (Linux) in the help panel (use <Return> or
Cmd/Alt-g for 'find next').

The csurf menu item:

  Help -> All Help Contents (clickable)

makes a clickable table of contents of all csurf,
tksurfer, tkmedit, and tkregister help panels.

Finally, all help panels are gathered into a
single file (24K lines) here:

  $CSURF_DIR/lib/help/CSURF_HELP.txt

To get that entire file (24K lines) into one
searchable help window, middle-click the lower
right "h" button on csurf.

####################
rc-subjects
####################

Csurf "subject:" entry/dropdown (left)

This entry contains the current subject.  The
dropdown contains a list of all the subjects in
the current $SUBJECTS_DIR, typically with
first3-last3 names (avoid spaces!):

  marser

Selecting a subject from this dropdown is
equivalent to:

  File -> Open Subject.

Entering text plus <Return> here pops up a list
of partial matches.  Glob-style patterns can be
used (but are not required).  This allows simple
searches:

  mar -> means find all names containing "mar"

All the subjects in $SUBJECTS_DIR are loaded at
csurf startup time.  To update the dropdown if a
subject has been added after starting csurf, use
File -> Update Subjects/Sessions or Cmd-u (Mac)
or Alt-u (Linux).

Since the csurf program stores configuration
information for the current subject in:

  $SUBJECTS_DIR/<subj>/scripts/csurf.dat

it will complain if you try to select a subject
directory in $SUBJECTS_DIR that does not contain
a "scripts" subdirectory.

####################
rc-patches
####################

Csurf "patch:" entry/dropdown (middle)

This entry contains the current patch (part of a
surface, typically flattened).  The dropdown
contains a list of all the patches in the current
$SUBJECTS_DIR, such as:

  full.patch.3d
  full.patch.flat
  occip.patch.3d
  occip.patch.flat

Selecting a patch from this dropdown auto-sets
the "Hemisphere Surf:" radio to either "viewcuts"
or "flattened" (and vice versa).

Since a patch is a subset of a complete surface,
and since it does not contain the full surface
specification (it has no face list), a full
surface must first be loaded (typically
"inflated").

All the patches in $SUBJECTS_DIR/<subj>/surf are
loaded into the dropdown on selecting a new
subject.  To update the dropdown if a patch has
been added after selecting the subject, reselect
the subject (<Return> in the "subject:" entry).

The "patch:" entries have had their hemisphere
prefixes stripped, so selecting RIGHT and
"occip.patch.flat" loads this surface and patch:

  $SUBJECTS_DIR/<subj>/surf/rh.inflated
  $SUBJECTS_DIR/<subj>/surf/rh.occip.patch.flat

===================================
Startup Details
===================================

Here is the command line that is typically used
to start tksurfer with a patch:

cd $SUBJECTS_DIR/<subj>/scripts
env \
  doublebufferflag=1 \
  dividequadsflag=1 \
  undividequadsflag=0 \
  newquadoutputflag=0 \
  writefloatpatchflag=1 \
  smallscreenflag=0 \
  tiffoutflag=1 \
  black2transparentflag=0 \
  tksurferinterface=mini \
  patchname=occip.patch.flat \
  /full/patch/to/tksurfer martys09 rh inflated \
  -tcl /tmp/TmpTclSurf.64484

The tmp tcl script referenced above looks like
this:

 source $CSURF_DIR/lib/tcl/setdefpatchview.tcl
 setfile patch ~/surf/rh.occip.patch.flat
 read_binary_curv
 read_binary_patch
 open_window
 restore_zero_position
 rotate_brain_x -90
 rotate_brain_z $flatzrot
 translate_brain_x $flatxtrans
 translate_brain_y $flatytrans
 scale_brain $flatscale
 set cslope 3.0
 set offset 0.30
 set cvfact 1.30
 set light2 0.8
 redraw

####################
rc-sessions
####################

Csurf "session:" entry/dropdown (right)

This entry contains the current session.  The
dropdown contains a list of all the sessions in
the current $FUNCTIONALS_DIR, typically with
chronologically-sorting names (avoid spaces!):

  120827MS

Selecting a session from this dropdown is
equivalent to File -> Open Functional.

Selecting a session from the sessions dropdown
automatically looks up the matching subject in
the current $SUBJECTS_DIR (using the "name" file
in this session), and sets the "subject:" field
to that subject (if found).

Entering text plus <Return> here pops up a list
of partial matches.  Glob-style patterns (* for
anything including nothing, ? for a single
character) can be used to narrow search (but are
not required).  If the suggested session-naming
convention above has been followed, simple
searches by date or subject can quickly be
performed:

 MS		all sessions containing "MS"
 12*MS		all 2012 sessions on MS
 1206????		all June 2012 sessions

All the sessions in $FUNCTIONALS_DIR are loaded
at csurf startup time.  To update the dropdown if
a session has been added after starting csurf,
use File -> Update Subjects/Sessions or Cmd-u
(Mac) or Alt-u (Linux).

Since the csurf program stores configuration
information for the current subject in:

  $FUNCTIONALS_DIR/<sess>/image/scripts/csurf.dat

it will complain if you try to select a session
directory in $FUNCTIONALS_DIR that does *not*
contain a "scripts" subdirectory (in the image
subdirectory).

####################
rc-scandirs
####################

Csurf "scandir:" entry/dropdown (right)

On selecting a session, this entry will contain
the first scandir in the current session.  The
dropdown contains a list of all the scandirs in
the current session.

Selecting a scandir from the dropdown has no
effect, but provides a quick way to examine the
scandirs in the this session.

####################
rc-VOLUME
####################

The VOLUME button starts up tkmedit for the
currently select subject, and loads the currently
selected 3D data set (radio buttons to the
right).  Can also start tkstrip (see below).

If, for example, "wm" is selected, csurf first
looks for the first file in COR dir "wm":

  $SUBJECTS_DIR/<subj>/mri/wm/COR-001

If that file is not found, it looks for:

  $SUBJECTS_DIR/<subj>/mri/wm.mgz

To load a 3D volume data set not listed in the
radio buttons, type it into the entry at the
right.

Clicking the VOLUME button when it is purple
kills tkmedit (without asking to save anything).

Any text output generated by tkmedit is put
into the bottom log panel (when Preferences ->
View/Hide Logs has made the logs visible).

When csurf is closed, the entire contents of all
the logs since csurf was first opened are saved
into csurf.log in the current scripts dir (full
path reported on csurf quit), overwriting the
previous logfile (if any).

===================================
Startup Details
===================================

Here is the command line that is typically used
to start tkmedit:

cd $SUBJECTS_DIR/<subj>/scripts
/full/path/to/tkmedit martys09 orig \
  -tcl /tmp/TmpTclMed.64187 \
  -tkmeditinterface mini \
  -all3flag 0

Depending on how csurf Preferences have been set,
the following additional parameters may be
passed:

  -followglwinflag 0
  -doublebufferflag 0
  -glxdepth 12
  -wmfillthresh 30

The tmp tcl script referenced above looks like
this:

 open_window
 set plane $cor		;# starting plane (or $sag, $cor)
 set prad 1		;# brush radius
 set tiffoutflag 1		;# tiff, not SGI
 setfile insurf rh.orig	;# potential surface to load
 redraw

Starting tkstrip

A non-default shift-middle-click on the VOLUME
button will instead start up tkstrip, an
interactive skull stripping application, using
default parameters, on the current volume:

  tkstrip <current_subject> <current_volume>

####################
rc-surfload
####################

Csurf "load2surf:" tickbox (right)

checkbutton -- load 3D vol into tksurfer
default: off

When this checkbutton is ticked, the 3D volume to
the left (on the VOLUME line) is loaded into
tksurfer when the lower-left SURFACE button is
clicked.

The 3D image goes into the primary buffer used
for re-positioning surfaces to generate, for example,
white and pial surfaces.

This check is immediately unticked, whether or
not the volume was successfully loaded.

####################
rc-surfload23
####################

Csurf "load2surf filled,T2" tickbox (right)

Load 2nd/3rd 3D tksurfer Volumes

When this checkbutton is ticked (default is off),
the second and third 3D volumes (currently fixed
names):

  2nd: filled[.mgz] and
  3rd: T2[.mgz]

are loaded into tksurfer when the lower-left
SURFACE button is clicked.

This only works if the first volume is also being
loaded ("surfload" checkbutton just above).

The auxiliary 3D image are used to help
re-positioning surfaces mainly controlled by the
data in the primary buffer.

The filled image prevents migration across the
callosum and out of the cut brainstem.

The T2 image is mainly used to prevent migration
out of inferotemporal cortex into the cerebellum.

This check is immediately unticked, whether or
not the volume(s) were successfully loaded.

####################
rc-SURFACE
####################

The SURFACE button starts up tksurfer for the
currently select subject, and loads the currently
selected hemisphere (RIGHT/LEFT "hemi:" buttons)
and currently selected surface ("surface:
dropdown entry and/or radio buttons to the
right).

If "hemi:" BOTH is selected, each hemisphere is
loaded in turn.

The "surface:" entries have had their hemisphere
prefixes stripped (except GIFTI), so selecting
RIGHT and "inflated" loads this surface:

  $SUBJECTS_DIR/<subj>/surf/rh.inflated

Clicking the SURFACE button when it is purple
kills tksurfer (without asking to save anything).

Any text output generated by tksurfer is put into
the bottom log panel (use Cmd-L or Preferences ->
View/Hide Logs to toggle the visibility of the
log panels visible).

When csurf is closed, the entire contents of all
the logs since csurf was first opened are saved
into csurf.log in the current scripts dir (full
path reported on csurf quit), overwriting the
previous logfile (if any).

===================================
Startup Details
===================================

Here is the command line that is typically used
to start tksurfer:

cd $SUBJECTS_DIR/<subj>/scripts
env \
  doublebufferflag=1 \
  dividequadsflag=1 \
  undividequadsflag=0 \
  newquadoutputflag=0 \
  writefloatpatchflag=1 \
  smallscreenflag=0 \
  tiffoutflag=1 \
  black2transparentflag=0 \
  tksurferinterface=mini \
  patchname=full.patch.3d \
  /full/path/to/tksurfer martys09 rh inflated \
  -tcl /tmp/TmpTclSurf.64187

On Ubuntu, doublebufferflag=0 will be used.

The tmp tcl script referenced above,
/tmp/TmpTclSurf.64187, looks like this:


 setfile patch ~/surf/rh.full.patch.3d      ;# glob patchname
 open_window
 read_binary_curv
 make_lateral_view
 set cslope 3.0		;# red/green curvature contrast
 set offset 0.30		;# brightness gray bg (no curv)
 set cvfact 1.30		;# light/dark gray contrast (overlay)
 set light2 0.8		;# upper right light
 redraw

####################
rc-hemi
####################

Csurf current hemisphere (upper middle)

This chooses the which hemisphere to display
(LEFT, RIGHT) upon clicking SURFACE.  It also
picks which surface to load initially when VOLUME
is used to display a 3D MRI volume.

If BOTH is clicked, the hemispheres will be
displayed in sequence starting with the RIGHT.
To see the LEFT, kill tksurfer (purple button or
upper left 'x' on tksurfer interface).

Finally, the "hemi:" select picks which
hemisphere to present saved bitmaps (tiffs) for,
when using:

  SubjectTools -> View Saved Subj Bitmaps
  SessionTools -> View Saved Funct Bitmaps
  CrossSessTools -> View Saved Avg Bitmaps

To present all saved bitmap files, even those not
containing a hemisphere specification, select
"hemi:" BOTH.

####################
rc-volradio
####################

Csurf current 3d volume select (next to bottom line)

The set of radio buttons to the right of the
VOLUME button picks the 3D volume dataset to load
when VOLUME is clicked.  The standard volumes, in
the order in which they are generated, are:

  orig -- original (can be avg of several)
  T1 -- normalized (wm -> std value)
  PD -- proton density (optional)
  PDbrain -- skull-stripped PD (optional)
  brain -- skull-stripped T1
  wm -- wm-only segmentation
  filled -- binary fill of wm (surf made from this)

The *.mgz suffix is omitted.  For example, if
"orig" is clicked, these files are looked for
in this order:

  1) $subject/mri/orig/COR-001, etc
  2) $subject/mri/orig.mgz

A volume (CORdir or .mgz file) in $subject/mri
with a non-standard name can be loaded by
selecting it from the dropdown to the right (or
typing its name into the entry).

####################
rc-vol
####################

Csurf current 3d volume (right)

This entry is auto-updated when one of the "3D:"
radio buttons to the right of the VOLUME button
is clicked.

The entry will accept either a COR dir (e.g.,
orig, containing COR-??? files), or an
.mgz file.  If suffix is omitted, and there
is no COR dir, the suffix will be auto-appended.

To load a non-standard volume (one not included
in the set of "3D:" radio buttons), select it
from the dropdown, or type its name into the
entry and hit VOLUME (or <Return>).

####################
rc-surfradio
####################

Csurf current surface select (bottom line)

This set of radio buttons to the right of the
SURFACE button picks the hemisphere surface to
load when SURFACE is clicked.  The standard types
of surfaces are:

  folded -- e.g., smoothwm
  inflated -- inflated without stretching
  viewcuts -- 3D patch before flattening
  flattened -- patch after flattening

The radio buttons select default surfaces of each
type.  Other surfaces can be loaded by selecting
them from the "surface:" dropdown before clicking
SURFACE.

Patches (3D and flattened) can be loaded by
selecting them from the "patch:" dropdown before
clicking SURFACE.

The list of possible surfaces includes:

  orig -- made from "filled" 3D data set
  smoothwm -- refined orig (near GM/WM border)
  white -- estimate of exact GM/WM border
  pial -- non-intersecting est. pial surface
  inflated -- inflate smoothwm w/o stretching
  sphere -- inflate to 10 cm radius sphere
  sphere.reg -- register/morph sphere to avg

The hemisphere prefix (rh. or lh.) is omitted
from the surface filenames in the dropdown.

####################
makenewsubj
####################

-------------------------------------------
 The File -> New Subject menu creates a new
 blank subject and its standard subdirectories
-------------------------------------------
This is the first step when making a new
*manually-reconstructed* (e.g., hi-res) subject.

Note that this step is *not* necessary for a
subject made with the standard MGH pipepline
using MGHTools -> Run Recon-all.  For help
with that, see Help -> Run Recon-all.

The subject directory (either made here or by
recon-all) must exist *before* a new csurf
functional session can be made for this subject.

The default location in which to create the new
empty subject directory is the current setting of
the environment variable, SUBJECTS_DIR, but a
subject directory can be made anywhere.  If the
parent directory of the new subject is not the
current SUBJECTS_DIR, SUBJECTS_DIR will be
changed to the new parent for this copy
of csurf.

To permanently change the startup SUBJECTS_DIR,
edit its definition in your shell startup file
(for csh/tcsh edit .cshrc/.tcshrc, or for
sh/bash, edit .bashrc/.bash_profile).

Finding subjects is easiest with csurf if they
are stored together in the same SUBJECTS_DIR.
Multiple functional sessions for a single subject
can access a single SUBJECTS_DIR subject's
surfaces, labels, etc.

The standard subject directory structure is:

SUBJECTS_DIR		root of a subjects database
   subjname/		e.g., first3/last3 initials
      scripts/		NOTES, configs, special scripts
      mri/		3D MRI data
         orig.mgz		original scan
         orig/		[CORdir equiv, incl's 001.mgz]
         T1.mgz		brightness-norm'd T1
         T1/		[CORdir equiv]
         PD.mgz		for strip skull (optional)
         PD/		[CORdir equiv]
         PDbrain.mgz		skull-stripped PD
         PDbrain/		[CORdir equiv]
         brain.mgz		skull-stripped T1
         brain/		[CORdir equiv]
         wm.mgz		filtered white matter
         wm/		[CORdir equiv]
         filled.mgz		rh,lh filled white matter
         filled/		[CORdir equiv]
         tmp/		tmp images
         transforms/		Talairach, etc
      surf/		surface/curv/area/etc files
      bem/		stripskull ico, EEG/MEG ico
      label/		subject-specific labels
      rgb/		saved subject bitmaps
      mpg/		saved subject movies
      tmp/		send/goto point, etc

There are four additional directories created by
recon-all:

      src/		src
      stats/		stats
      touch/		cmdlines
      trash/		trash

Manual Hi-Res Reconstruction

Once the subject has been made, T1-weighted raw
scan(s) (e.g., 1mm^3 or higher res) should be
copied into separate subdirectories of the
mri/orig directory of that subject.  The
subdirectories you make in there can have any
name.  For example:

  $SUBJECTS_DIR/somesubject/mri/orig/mprage1/*
  $SUBJECTS_DIR/somesubject/mri/orig/mprage2/*

The Setup Struct Scans menu looks in the mri/orig
directory to find subdirectories, each of which
should contain a single scan, and averages them.

MGHTools -> Run Recon-all

Setup Struct Scans is *not* necessary to average
scans with MGHTools -> Recon-all.  See HOWTO
instructions for averaging scans on the Run
Recon-all panel when it is opened.


####################
mkorigdirs
####################

-------------------------------------------
 The SubjectsTools->Make Origdirs,Find/Copy Raw
 menu creates mri/orig subdirs, and copies
 converted-to-COR format 3d scans into them.
-------------------------------------------

Getting Started

This panel is designed to be the first panel
accessed after running File -> New Subject.  It
requires a virgin subject directory tree
containing no mri/orig subdirectories.   If
mri/orig subdirectories have already been created
(even if they are empty), you won't even be able
to open this panel.   First manually remove
existing orig subdirectories.

Click the Find Raw Structs button at the top of
the panel to begin.  Click SETUP NEW ORIGDIR one
or more times to create blank scan configuration
lines.  DELETE LAST ORIGDIR deletes the most
recently added line, whether or not you have
altered it.

Create mri/origSubdirectdories and Find Raw Scans

The proposed mri/orig subdirectories are named
mprage1, mprage2, etc, but can be renamed to
anything unique.

For each new scan directory, click the FIND
button to locate a single raw structural scan.
Subsequent FIND button clicks start the directory
browser in the parent directory of the most
recently selected Raw Scan.

Once you are satisfied with the mapping between
scan directory names and raw scan names, click
MAKE ORIGDIRS at the top of the panel.  If all
the fields are complete, the name list is unique,
and the raw scans all exist, the new mri/orig
subdirectories should appear on the left of this
panel (if not, fix things and click MAKE ORIGDIRS
again).  Text files documenting the raw scans
will be made in each of the scan directories.  If
you want to redo this, remove the just-created
mri/orig subdirectories (which will contain only
the small text files).

Copy Raw Scans

When the MAKE ORIGDIRS button is clicked
successfully, default unique scan names will be
inserted into the right-most column (New Scan
Names).

Finally, click COPY-RAW at the upper right.
After checking the list of new names for
completeness and uniqueness, this copies the raw
structural scans into each mri/orig subdirectory.

####################
setupstruct
####################

-------------------------------------------
 The SubjectTools -> Setup Structural Scans menu
 sets up to convert and average raw data sets
 in preparation for surface reconstruction.
-------------------------------------------
When this panel opens, it scans $subject/mri/orig
for subdirectories and makes of list of them at
the left of the panel.  If there are no subdirs,
the list will be blank.

Select an mri/orig subdir containing a single
scan (typically an AFNI BRIK containing short or
float data) and press the Structual Scan Dir
button.  This configures it as a directory to
convert and possibly average.  At any time, you
can press Unset Dir to ignore a directory.  Unset
Dir doesn't touch anything inside the directory.

To first convert a nifti file to a BRIK, use AFNI
utility 3dcopy:

  3dcopy somefile.nii somefile+orig

The AFNI button can be used to view a selected
input data set (if it is a BRIK).

Now, select a scan or scan file in the combo box
labeled "Image File:", and press READ HEADER.
This should fill in all the fields below.  Verify
that the fields are correct.

CONVERT/AVERAGE

First go to Preferences -> Expert Preferences ->
Conv and verify that "Auto align with AFNI
3dvolreg (-heptic)" is clicked, then OK/Save.

After configuring one or more directories,
press CONVERT/AVERAGE.  This will generate the
following images:

 images: $SUBJECTS_DIR/$name/mri/orig/COR-???
 header: $SUBJECTS_DIR/$name/mri/orig/COR-.info

If the checkbutton at the bottom of the panel
"Generate .mgz output" is clicked, the output
format will instead be:

 images:  $SUBJECTS_DIR/$name/mri/orig.mgz

Back at the Setup Structural Scans panel, after
several scans have been configured, pressing
CONVERT/AVERAGE will first align each scan and
average it before finally converting it to CORdir
or .mgz format.

Headerless data

To read headerless data sets or data sets for
which the header is not recognized, set the Scan
Type to:

  noheadbrik   => headerless 2-byte xyz images
  noheader     => headerless 2-byte xy images
  ignoreheader => read x*y*2 bytes from file end

For slice formats, the "Image Name Format:" field
accepts C-style formats (e.g., zz_%03d.im).

In these cases, the pixel size and slice
thickness has to be entered manually.

High Resolution Surface Reconstruction

Same as above but on the "Other Options:" line,
add "-hires" in order to cause brik2cor to
generate a subsampled-to-0.5mm^3 CORdir (COR-001
to COR-512) or .mgz file.

To read the .mgz output of this step in MGH
tkmedit, add another option, "-zeropixwidth",
which sets the pixel width to 0.0.  This is a
workaround to an MGH tkmedit bug that incorrectly
reads the direction cosines in .mgz files and
quits with a zero determinant (will eventually be
fixed).  No need to add this option for csurf
tkmedit.

The command line program calcimg can be used to
read or reset the pixel width field in .mgz
files:

 calcimg -spacing <im.mgz>            => read
 calcimg -setspacing <1.0> <im.mgz>   => to 1mm

Other useful parameters that can be added to
"Other Options:" is "-prescale <divisor>".  This
will divide the value of each pixel by the
divisor to better scale it into the range of
0-255.  There is also "-floatfac <factor>".
Finally, to stop resampling to 1x1x1mm, use
"-noresamp".  This is useful for post-mortem
reconstructions with sub-1-mm voxels.

=========================
 brik2cor command line
=========================
Use: [convert/resamp brik to 256^3/1mm^3
          or 512^3/0.5mm^3 bytecube]

 brik2cor <in:brik> <out:CORdir/mgzfile> [opts..]

Options: (usu. just -prescale/-p if input *.BRIK)

  -xysize <x> <y>
     (-xy) pix cnt input slices (def:256x256)
  -xfov <mm>
     (-f) slice xFOV (def:256)
  -nslices <n>
     (-z) number input slices (def:160)
  -thick <mm>
     (-t) slice thickness (def:1.0)
  -ori <inner1> <2> <3>
     (-d) inp loop ord: 0=RL,1=LR,2=PA,3=AP,4=IS,5=SI
  -briktype <n>
     (-b) 1=short or 3=float (def:1=short)
  -swap
     (-s) swap shorts (def:no)
  -floatfac <f>
     (-c) multiply (usu. short) brikdata by (def:1.0)
  -prescale <f>
     (-p) divide by before trunc=>byte (def:3.0)
  -offset <int>
     (-o) add after prescale (def:0.0)
  -invert
     (-i) invert image contrast (def:no)
  -nneigh
     (-n) nearest neigh resample (def:trilinear)
  -hires 
     (-h) sample to 512^3 (def:256^3)
  -noresamp
     (-m) ignore HEAD pixsize, set->1.0 (hires->0.5)
  -zeropixwidth
     (-w) mgz outheader spacXYZ->0 MGH tkmedit bug
  -ignorehead
     (-r) requires: xysize/xfov/nslices/thick/[ori]

 Notes:

 outformat by suff: .mgz, else COR (does mkdir)
 reads AFNI BRIK (float or short, auto-detect)
 read barebrik w/opts: xysize/fov/nslices/thick
 order: => [swap] => [prescale] => [offset] =>
         trunc2byte => [inv] => interp
 can't convert non-square in-plane pix

Examples:

 brik2cor zz+orig.BRIK zz -p 4.5

 brik2cor zz+orig.BRIK zz \
    -p 4.5 \
    -r \
    -xy 280 320 \
    -f 224 \
    -z 208 \
    -t 0.8 \
    -d 3 4 1

======================================
Manual import (e.g., PD for skullstrip)
======================================

Example of how a proton density scan could be
manually importing and subsampled to hi-res:

 cd /rawdata
 3dcopy sMA0419-01.nii PD+orig
 brik2cor PD+orig.BRIK PD.mgz -hires -prescale 1.0

==========================
Rarely-used, older options
==========================

Manual Register Before Average

For manual alignment (e.g., for very different
images, partial images) go to Preferences ->
Expert Preferences -> Conv.  Then choose "Manual
align with tkregister" and OK/Save.  Back at the
Setup Structural Scans panel, after several scans
have been configured, pressing CONVERT/AVERAGE
will convert each scan to COR format, flip it if
necessary (see below), start Register possibly
multiple times, and finally, average after
registration is done.

The first Register will start with the first
configured scan as the TARGET and the second scan
as the MOVEABLE.  After manually registering and
saving the matrix (SAVE REG), quit that register
(double-click register interface at upper left).
If there is a third scan, this will start another
Register set up to align the third scan with the
first.

When the last Register is quit, the registered
scans will then be averaged (*don't* click the
purple QuitCONVERT/AVE button or you will kill
the averaging before it finishes--that button
will turn gray again when the averaging is
done).

If the mid-sagittal plane of the first (TARGET)
scan is badly skewed, click "Adjust Target
Scan..." before CONVERT/AVERAGE.  This will bring
up the first scan as both the MOVEABLE and TARGET
allowing you to adjust it before doing any
alignments between scans.

Higher Res Surface Recon by faking 1x1x1mm data

To reconstruct a less-than-1x1x1mm scan as
if it was a 1x1x1mm scan (in order obtain a
higher resolution surface with more vertices and
smaller faces), start with an AFNI brik (or other
x-y-z data brik), READ HEADER, and then use the
following roundabout method to fool FreeSurfer
into thinking the scan is actually 1x1x1mm.
This example is for a 240x320 inplane 0.75mm
x 0.75mm x 0.75mm sagittal Siemens MPRAGE with
208 slices/partitions:

     Scan Type: noheadbrik   [was brik]
   Slice Count: 208          [leave as is]
  Image X Size: 240          [leave as is]
  Image Y Size: 320          [leave as is]
 In Plane (mm): 1.0          [leave as is]
Thickness (mm): 1.0          [leave as is]
 Other Options: -fov 256 -t 1.0 ... [e.g.,-p 2.5]
          Flip: x=>-z  y=>y z=>x

After the surface has been reconstructed, to
use it for standard functional overlays, first
duplicate the subject (to preserve the high
resolution data).  Then resample the 3D data to
1x1x1 by running CONVERT/AVERAGE the standard way
(*without* resetting Scan Type to noheadbrik,
and after removing the -fov and -t entires from
Other Options).  Delete the copied directories
of the other processing stages (T1, brain, wm,
filled) and move the "orig" data set to the
"T1" directory, which is the Target scan for
tkregister when you click Align=>Struct in Setup
Functional Scan Parameters for an Align scan.
Finally, rescale the surfaces to match.  Here is
how to do that with a tcl script. First make a
file TmpTclScript.tcl:

open_window
read_binary_curv
make_lateral_view
set cslope 3.0
redraw
really_scale_brain 0.75 0.75 0.75
redraw
set outsurf $insurf
write_binary_surface
exit              

Then run the tmp tcl script on all 12 surfaces
(example in csh):

#! /bin/csh -f
set name = marty
set tmpscript = TmpTclScript.tcl
foreach hemi ( lh rh )
  foreach surf ( orig smoothwm inflated \
                 white graymid pial )
    tksurfer -${name} $hemi $surf -tcl $tmpscript
  end
end

The supplied script, scalesurfaces, can do
this for all surfaces of a subject.  Remember,
this permanently alters the surface, so you will
typically want to run it on a copy.

The new (copied) subject will now have a higher
resolution surface aligned with a 1x1x1mm
Target scan.  Note that the effective width
of the smoothing kernel for a given number of
Smoothing Steps (in View Functional Data) will
now be reduced.

Input and Output Files (in $SUBUECTS_DIR)


   [for two AFNI BRIKs]

 raw images1:   $name/mri/orig/mp1/scan1+orig.BRIK
 raw images2:   $name/mri/orig/mp2/scan2+orig.BRIK

 output images: $name/mri/orig.mgz
 

   [for two old format Siemens input subdirs]
 
 raw images1:   $name/mri/orig/scan1/165-2-10.ima
 input images1: $name/mri/orig/scan1/COR-???
 input header1: $name/mri/orig/scan1/COR-.info
 input xform1:  $name/mri/orig/scan1/register.dat

 raw images1:   $name/mri/orig/scan1/165-3-171.ima
 input images2: $name/mri/orig/scan2/COR-???
 input header2: $name/mri/orig/scan2/COR-.info
 input xform2:  $name/mri/orig/scan2/register.dat

 output images: $name/mri/orig/COR-???
 output header: $name/mri/orig/COR-.info


If you redo a manual register average, it will
start with the previously saved transformation
matrix.  To redo a manual register average from
scatch, go into each of the raw scan directories
and remove (or move aside) the register.dat
file.

Flipping

N.B.: the following is now rarely required with
AFNI BRIK input since brik2cor properly reads the
ORIENT_SPECIFIC field from a (properly
configured) HEAD file.

At conversion time, the data set can be flipped.
Be cautious since this can mirror-image the data
set (but this is sometimes necessary).  Also,
since there are a large number of possible flips
of a 3D data set (48), it is easy to get
confused.  The data cube can be viewed from 6
different faces times 4 rotations of each face
times 2 enantiomers (non-mirror-image and
mirror-image) = 48.

Typically, this is done after the data set has
already been converted once without any flipping.
Set the view to CORONAL first.  The 3 directions
are defined in the CORONAL view as:

  x => left   -> right
  y => bottom -> top
  z => near   -> far

Then determine which direction you would like
the current x (left-right) to be flipped to.
You can use a negative sign.  For example,
to left right mirror-image a data set, set
the fields like this:

  x => -x
  y => y
  z => z

This should be done for each page/directory.

To flip a sagittal acquired right->left to
coronal, use:

  x => -z
  y => y
  z => x

Data sets can also be interactively flipped by running
tkmedit on the command line and typing:

  flip <[-]{x,y,z}> <[-]{x,y,z}> <[-]{x,y,z}>

at the tcl prompt.

Some flips we have used:

  -> Siemens sagittal -> coronal: -z  y  x
  -> Varian mp axial  -> coronal:  x -z  y
  -> GE FSPGR axial   -> coronal:  x -z -y


####################
handnormalize
####################

-------------------------------------------
 HOWTO hand pre-normalize an "orig" dataset
-------------------------------------------
In cases where the automatic normalization
results in an eroded-looking brain surface, you
may have to pre-normalize the "orig" data set by
hand, and then re-run the entire process starting
with Process Volume.

Load the orig[.mgz] Data Set

First, start up tkmedit with the "orig" data set.
You may first want to make a copy of the original
data, for example:

  cd $SUBJECTS_DIR/marty/mri
  cp -r orig orig0

    *or*

  cp -r orig.mgz orig0.mgz

tkmedit Piecewise Linear Normalization Panel

Hit F3 in the medit tools window to bring up the
extended tkmedit panel (F1 goes back to the
default view).  The new subpanel on the right
allows you to test and then apply a piecewise
linear ramp of brightness correction factors
(ffrac0-3) at four control points (lim0-3).  For
example, if you click I/S (inferior/superior
direction) and set lim2 => 145, and ffrac2 =>
1.2, this means multiply the brightness value of
pixels at inferior/superior position 145 (0-255)
by 1.2.  Thus, if the pixel value was 134 (view
pixel value in upper border of display window)
the new pixel value will be 134 * 1.2 = 161.

There are 4 control points (lim0-3, 0-255 pixel
coords) that can be applied to one of the 3 main
directions in the image: posterior/anterior,
inferior/superior, or right/left.  The correction
factors are linearly interpolated between the
control points, and remain flat beyond the first
and last control points.

Try Test Normalizations using the Back Buffer

The TEST button applies the piecewise linear ramp
to the whole data set and puts the result into
the back buffer so that you can use COMPARE to
blink between it and the original image.  If you
change any settings, and hit TEST again, it will
redo the test normalization with the new
settings.

To make the eventual effect of the normalization
more obvious, it is best to turn on WMTRUNC
(e.g., with the low limit set to 90, which is the
default for mri_wmfilter), which truncated the
image to black below 90.

A <Return> in any of the lim? or frac? entries is
the same as hitting TEST, so you quickly change
the scale factors or control points in small
steps and immediately see the effects.

For example, to brighten a dim superior sagittal
region, set one control point (e.g., lim3) to the
pixel coordinate of the top of the skull (e.g.,
around 210 -- look in the lower entry of each
pair to the right of the CORONAL, SAGITTAL and
HORIZONTAL buttons for the pixel coordinates).
Now set another control point (e.g., lim2) to the
pixel coordinate just inferior to the dimmed
region (that is, where no correction needs to be
applied, for example, around 180).  Turn on
WMTRUNC, set low=90, and gradually increase
ffrac3 above 1.0, hitting a <Return> each time in
ffrac3 to see the effects.  You can use COMPARE
to see what the truncated original looks like.

Spherical Normalization

The "sph" checkbutton toggles the state of hand
normalization done by the TEST and ALL buttons
between:

  OFF=0: a piecewise 4-control-point ramp along
  one of the major axes (above)

  ON=1: a spherical field around the current
  cursor

In the second case, the current cursor sets the
center of a spherical normalization field.  The
radius of the field is set by lim0 (directly to
the left of "lim0").  The normalization factor at
the center is set by ffrac0.  There is a linear
ramp in the normalization factor (in 3D) from the
center point to the lim0 radius (no change).  In
this state, lim1-3 and ffrac1-3 are ignored.

Apply Normalization to Input Data Set (front buffer)

Once you are satisfied with your settings, apply
them to all of the images in the front (editable)
buffer of tkedit by clicking ALL.  The images
will not yet have been saved, so if you want to
go back, quit without SAVEIMG.

Save the Normalized Images

Finally, to save the modified images into the
$SUBJECTS_DIR/marty/mri/orig directory, hit
SAVEIMG.  You should now re-run the surface
reconstruction from the beginning.

Tips

You can apply several ramps in succession in
different directions (e.g., superior/inferior,
left/right), by hitting ALL several times (after
the proper setting of lim0-3 and ffrac0-3 for
each direction have are determined in
succession).

N.B.: since ALL replaces the front (editable)
buffer images with the normalized images, hitting
ALL twice with the same settings will apply that
ramp twice.  This is in contrast to the behavior
of TEST, which applies the ramp just once and
stores (overwrites) the image into the back
buffer with the result.

####################
processvolume
####################

-------------------------------------------
 The Tools -> Process Volume menu item starts a
 four-part background process to prepare the 3-D
 MRI data to make a surface.
-------------------------------------------

[old Linux-only FreeSurfer0.8]

(1) Normalize Intensities

The output files written by this procedure are:

 images: $SUBJECTS_DIR/$name/mri/T1/COR-???

(2) Compute Talairach (uses MINC tools)

 xform: $SUBJECTS_DIR/$name/mri/transforms/
                                 talairach.xfm
(3) Strip Skull

A subtessellated icosahedron is expanded shrunk
to reach the surface of the brain using the
normalized data set.  At each point on the
surface a 'core sample' is used to search for the
first black lamina that corresponds to the inner
surface of the inner table of bone in a
T1-weighted scan, while at the same time,
preserving neighbor relations.  Once this surface
is found, it is used to strip the skull off of
the T1 data set.  The output files written by
this procedure are:

 shrinksurf: $SUBJECTS_DIR/$name/bem/brain.tri
 images: $SUBJECTS_DIR/$name/mri/brain/COR-???

Inspect this output to see that no gyri have
been trimmed.  If they have, open Preferences ->
Expert Preferences => RmSkull tab, reduce fzero
and increase fmax, and re-run.

(4) White Matter Filter

An oriented filter is applied to the stripped
data set to 'floss' and 'spackle' small defects.
Filter coefficients are computed for each 5x5x5
volume in order to determine which plane is most
likely to be parallel ot the cortical surface,
and then a modified median filter is applied.
The output files written by this procedure are:

 images: $SUBJECTS_DIR/$name/mri/wm/COR-???

####################
createsurface
####################

-------------------------------------------
 The Tools -> Create Surface menu item starts a
 six-part background process to create the left
 and right hemisphere cortical surfaces
-------------------------------------------
[old Linux-only FreeSurfer0.8]

(1) Fill White Matter

Start a 3-D region growing process from a
starting point within the white matter in order
to generate the starting point for a surface.
The output files written by this procedure are:

 images: $SUBJECTS_DIR/$name/mri/filled/COR-???

(2) Tessellate White Matter

Connect the surfaces of the filled white matter
voxels into a continuous surface.  The output
files written by this procedure are:

 surface: $SUBJECTS_DIR/$name/surf/rh.orig
 surface: $SUBJECTS_DIR/$name/surf/lh.orig

(3) Smooth Right Hemisphere White Matter
(4) Smooth Left Hemisphere White Matter

The reconstructed white matter surface of the
right and left hemispheres is smoothed.  The
output files written by this procedure are:

 surface: $SUBJECTS_DIR/$name/surf/rh.smoothwm
 surface: $SUBJECTS_DIR/$name/surf/lh.smoothwm

(5) Inflate Right Hemisphere
(6) Inflate Left Hemisphere

Inflate the right and left hemisphere surfaces
while attempting to preserve local angles and
area.  The output files written by this procedure
are:

 surface: $SUBJECTS_DIR/$name/surf/rh.inflated
 surface: $SUBJECTS_DIR/$name/surf/lh.inflated

================================================
Binary format (non-topo-corrected, short, quads)
================================================
Binary file format:
    [header]
  3bytes: 16777215
  3bytes: number of vertices
  3bytes: number of faces
    [vertex list--implicit vertex numbering]
  2bytes: x[vertex0]*100
  2bytes: y[vertex0]*100
  2bytes: z[vertex0]*100
  ...
    [face list--vertex numbers of corners]
  3bytes: face1: vertex number 1st corner
  3bytes: face1: vertex number 2nd corner
  3bytes: face1: vertex number 3rd corner
  3bytes: face1: vertex number 4th corner
  ...

[see Help -> csurf for all/new surf formats]

================================================
Obtaining ASCII representation of a surface
================================================
writing out ASCII representation
of any surface in FreeSurfer (e.g., rh.orig,
lh.smoothwm, etc).

1) COR coordinate system (lower box in tkmedit)

  0-255  Right -> Left
  0-255  Post -> Ant
  0-255  Inf -> Sup

2) Talairach (higher box with decimal point)

  [standard]

3) Surface coordinate system.  Surface coords
    are written to the log (3 numbers, x,y,z,
    after the "x =" ...)--or to tcl prompt if
    you run tksurfer from the command line--when
    you click a surface point (the surface
    normals are also written out "n=").

  0,0,0 in center of 256x256x256 volume
  x    positive -> Right
  y    positive -> Ant
  z    positive -> Sup


To write out ASCII file of x,y,z of points on any
surface (including topology-corrected):

tksurfer -marty rh smoothwm
% set vrmlsurf /tmp/zz.wrl
% write_vrml 0         ;# 0=points

This will write out a long list of of 3-D
coordinates of each vertex in the surface.

To write out ASCII file that also specifies the
vertices that are the corners of each face:

tksurfer -marty rh smoothwm
% set vrmlsurf /tmp/zz.wrl
% write_vrml 1

This will write out 2 concatenated lists.  The
first are the vertex x,y,z coordinates as
before.  This is followed by a list of vertex
number quadruples.  These numbers are the
implicit vertex numbers (followed by a -1).
write_vrml 1 *doesn't* work with topology
corrected surface currently.

To write out vrml 2.0 format files (the current
version read by plugin like Cortona from
parallelgraphics for windows), do the following
before write_vrml:

% set vrml2flag 1   ;# default is 0 => vers1.0

This only currently works for points.

Examples:

-----------------
VRML 1.0 points:
-----------------
#VRML V1.0 ascii
Coordinate3 {
        point [
12.72 -94.53 -32.12,
12.39 -94.58 -32.13,
11.64 -94.64 -32.22,
11.02 -94.43 -32.13,
...
19.78 -24.83 -29.55,
19.68 -25.31 -29.20,
20.87 -26.00 -28.69
        ]
}

----------------------------------
VRML 1.0 surface (quad surf only):
----------------------------------
#VRML V1.0 ascii
Coordinate3 {
        point [
8.23 -97.32 -19.20,
7.70 -97.32 -19.19,
7.24 -97.26 -19.22,
...
15.33 62.33 2.21,
14.67 62.38 2.09,
14.19 62.37 2.08
        ]
}
IndexedFaceSet {
        coordIndex [
0, 1, 6, 5, -1,
0, 21, 22, 1, -1,
0, 5, 29, 21, -1,
...
129668, 129672, 129673, 129669, -1,
129669, 129673, 129674, 129670, -1,
129670, 129674, 129675, 129671
        ]
}

-----------------
VRML 2.0 points:
-----------------
#VRML V2.0 utf8
Collision { collide FALSE
children [ Group { children [ Shape {
appearance Appearance {
  material DEF _DefMat Material {
    emissiveColor 1 1 1 } }
geometry PointSet { coord Coordinate {
        point [
8.23 -97.32 -19.20,
7.70 -97.32 -19.19,
7.24 -97.26 -19.22,
...
15.33 62.33 2.21,
14.67 62.38 2.09,
14.19 62.37 2.08
        ]
} } } ] } ] }


-----------------
VRML 2.0 surface
-----------------
 => not currently working


####################
fixtopology
####################

-------------------------------------------
 The Tools -> Fix Topology menu item starts a
 four-part background process to create the left
 and right hemisphere cortical surfaces
-------------------------------------------
[old Linux-only FreeSurfer0.8]

(1) Quick Sphere Right Hemisphere Surface
(2) Quick Sphere Left Hemisphere Surface

Inflate each hemisphere to an area-preserving
sphere to identify topological defects.  The
output files are:

 outsurf: $SUBJECTS_DIR/$name/surf/rh.qsphere
 outsurf: $SUBJECTS_DIR/$name/surf/lh.qsphere

(3) Fix Topology Right Sphere'd Surface
(4) Fix Topology Left Sphere'd Surface

Remove defects by finding sphere locations that
have more than one layer (e.g., a "handle" or
"wormhole").  Then, cut out these defects and
re-tessellate them.  The output files are:

 surface: $SUBJECTS_DIR/$name/surf/rh.orig
 surface: $SUBJECTS_DIR/$name/surf/lh.orig

These overwrite the originally reconstructed
surfaces.

(5) Re-Smooth Right Hemisphere White Matter
(6) Re-Smooth Left Hemisphere White Matter

The reconstructed white matter surface of the
right and left hemispheres is smoothed.  The
output files written by this procedure are:

 surface: $SUBJECTS_DIR/$name/surf/rh.smoothwm
 surface: $SUBJECTS_DIR/$name/surf/lh.smoothwm

(7) Re-Inflate Right Hemisphere
(8) Re-Inflate Left Hemisphere

Inflate the right and left hemisphere surfaces
while attempting to preserve local angles and
area.  The output files written by this procedure
are:

 surface: $SUBJECTS_DIR/$name/surf/rh.inflated
 surface: $SUBJECTS_DIR/$name/surf/lh.inflated


####################
mkfinalsurf
####################

------------------------------------------------
 The Tools -> Make Final Surface menu item starts
 a two-part background process to create the
 final left and right hemisphere cortical
 surfaces (after removal of topological defects)
------------------------------------------------
[old Linux-only FreeSurfer0.8]

(1a) Make Final Right Hemisphere Surfaces
(1b) Make Final Left Hemisphere Surfaces

The output files written by this procedure are:

 surface: $SUBJECTS_DIR/$name/surf/rh.white
 surface: $SUBJECTS_DIR/$name/surf/rh.graymid
 surface: $SUBJECTS_DIR/$name/surf/rh.pial

 surface: $SUBJECTS_DIR/$name/surf/lh.white
 surface: $SUBJECTS_DIR/$name/surf/lh.graymid
 surface: $SUBJECTS_DIR/$name/surf/lh.pial

####################
processcreatefixfinal
####################

-------------------------------------------
 The SubjectTools -> Process/Create/Fix/Final
 menu item starts twenty-part background process
 to create a default set of RH and LH surfaces 
-------------------------------------------
[old Linux-only FreeSurfer0.8]

Shortcut for:

  Preferences -> Don't Ask Overwrite

  Process Volume
  Create Surface
  Fix Surface Topology
  Make Final Surface

This makes a default set of surfaces for both
hemispheres.  The complete set of output files
written by these procedures for the RH are:

 images: $SUBJECTS_DIR/$name/mri/T1/COR-???
 xform: $SUBJECTS_DIR/$name/mri/transforms/###
 shrinksurf: $SUBJECTS_DIR/$name/bem/brain.tri
 images: $SUBJECTS_DIR/$name/mri/brain/COR-???
 images: $SUBJECTS_DIR/$name/mri/wm/COR-???
 images: $SUBJECTS_DIR/$name/mri/filled/COR-???
 surface: $SUBJECTS_DIR/$name/surf/rh.orig
 surface: $SUBJECTS_DIR/$name/surf/rh.smoothwm
 surface: $SUBJECTS_DIR/$name/surf/rh.inflated
 surface: $SUBJECTS_DIR/$name/surf/rh.qsphere
 surface: $SUBJECTS_DIR/$name/surf/rh.orig
 surface: $SUBJECTS_DIR/$name/surf/rh.smoothwm(2)
 surface: $SUBJECTS_DIR/$name/surf/rh.inflated(2)
 surface: $SUBJECTS_DIR/$name/surf/rh.white
 surface: $SUBJECTS_DIR/$name/surf/rh.graymid
 surface: $SUBJECTS_DIR/$name/surf/rh.pial

A corresponding set of surfaces are made for
the LH.


####################
stripskullhires
####################

-------------------------------------------
 The SubjectTools -> Strip Skull (hi-res) starts
 a two-part background process to generate a T1
 image of just the brain (incl cerebellum and
 brainstem).
-------------------------------------------
An elliptical surface (4th or 5th geodesic
subtessellation of an icosahedron) is inflated
from the inside of the brain looking for the
first dark surface it finds -- typically the CSF
and/or the inner table of bone of the skull.

The set of voxels that intersect faces of the
resulting surface is then flood filled from the
outside.  The data set to be stripped (typically
T1-weighted) is read in the flood-filled voxels
are used to set the corresponding voxels in that
dataset to zero.

The preferred input is the "PD" data set but
"orig" is tried if it is not found:

 input3D: $SUBJECTS_DIR/$name/mri/PD[.mgz]
    or, if above not found:
 input3D: $SUBJECTS_DIR/$name/mri/orig[.mgz]

 output3D: $SUBJECTS_DIR/$name/mri/brain[.mgz]

Four Adjustable Parameters

"fzero" sets the point at which the outward force
the surface goes to zero.  Decreasing this
decreases the amount of erosion.

Increasing "fmax" decreases the the amount of
erosion.

"dfrac" sets the starting surface diameter as a
fraction of the brain (defineds as voxels
brighter than 50).  This should be entirely
within the brain to avoid getting the surface
"hung up" on the skin.

"istilt" sets an inside stilt height (where the
data set is sampled relative to the surface,
measured along the inward surface normal at each
vertex).

Multi-stage user-editable tcl script

If "use tkstrip tcl script instead" is chosen, a
more complex, user-editable multi-stage procedure
is used:

  $CSURF_DIR/lib/tcl/stripskullPD.tcl

but any other script can be used instead if an
absolute path name is used, or if another script
is placed in $CSURF_DIR/lib/tcl.

The stripskullPD.tcl script requires two inputs
data sets, "orig" and "PD".  A surface is
inflated from inside the "PD" data set to find
the edge of the brain, and a skull-stripped data
set "PDbrain" written out.  This data set is then
used to strip the the skull from the "orig" data
set to generate the "brain" data set.

Rationale

This procedure was devised for quantitative T1
data, which has a lot of noise in the skull.  The
skull is normally dark in a T1-weighted scan
since there is very little signal from the skull
because of the ultra short T2 there.  However,
this results in a noisy quantitative T1 estimate.


####################
wmfilterhires
####################

-------------------------------------------
 The SubjectTools -> WM Filter (hi-res) starts a
 background process to generate anisotropically
 filtered images of the white matter
-------------------------------------------
A 5x5x5 anisotropic "plane filter" is moved pixel
by pixel through the input volume.  At each
pixel, a geodesic set of directions are searched
to find the set of parallel planes in which the
variance in brightness is minimized.  This is a
rough estimate of the local tangent plane to the
cortex.

A median filter is then applied within each plane
to eliminate spiky artifacts.

The resulting data set is then thresholded to
zero below the "white low limit" and above the
"white high limit".

The preferred input is the "brain" data set but
"T1" and finally "orig" are tried in that order
if "brain" is not found:

 input3D: $SUBJECTS_DIR/$name/mri/brain[.mgz]
    or, if above not found:
 input3D: $SUBJECTS_DIR/$name/mri/T1[.mgz]
    or, if above not found:
 input3D: $SUBJECTS_DIR/$name/mri/orig[.mgz]

 output3D: $SUBJECTS_DIR/$name/mri/wm[.mgz]

Regions That May Need Manual Edits

By its design, this filter will tend to
over-erode the attachment point of a thin
perpendicular sheet to a flat plane.

One such region (viewed in the CORONAL plane) is
the thin white matter sheet just under the
hippocampus that connects entorhinal cortex with
the main body of white matter in the temporal
lobe.

This program is multi-threaded to run faster by
using all available cores (8 threads).

####################
editsegmentation
####################

-------------------------------------------
 The "Edit -> Edit Segmentation" menu item
 starts both medit and surfer so that the
 segmented white matter can be edited to
 correct topological defects
-------------------------------------------

Inspect the surface for topological defects or
'wormholes'.  These typically occur along the
midline near the hippocampus and fornix, along
narrow sulci (e.g., calcarine, central), and
where there is only a very thing sheet of white
matter overlying the ventricle in the fundus of
the calcarine sulcus.

To correct a wormhole, first select a vertex on
it in the surface view with a left-click.  Then
click surfer's SEND button to make the medit
slice view to go to the corresponding point (this
work the other way, too, for medit clicks sent to
surfer with medit's SEND PNT button).

Then edit the 'wm' data set with the middle (edit
to white) and right (edit to black) mouse
buttons. The radius of the editing brush is set
with the 'rad' entry.  The 3Dbrush button toggles
between within-slice brush (default) and 3D
brush.  Use the 3D brush with care because you
are editing pixels you can't see.  Brush radius=0
is 1x1x1 mm (Alt-b returns radius to this);
radius=1 is 3x3x1 mm (or 3x3x3 if 3D button), and
so on (Alt-B increases radius by 1).

For small edits, rad=0 is fine; otherwise, a good
default is rad=1.  Large radii (4-7) are useful
for filling the basal ganglia or ventricles.

When all wormholes have been are corrected,
re-run Create Surfaces (for one or both
hemisphere).

To abandon a segmentation but also save it (e.g.,
to start with a new prenormalized data set):

  cd $SUBJECTS_DIR/<somesubject>/mri
  cp -r wm wm1
  cp -r orig orig1

Hints

If the wormhole is not clearly visible at first
in the initial slice view, change the slice plane
before moving the cursor; it is often possible to
see it more clearly this way.

To see black edits: contr: ($bwslope) = 255
                    midpt: ($bwmid) = 0.001

When selecting vertices on a wormhole, you may
have to try several times until you get a vertex
that has an edge in the wormhole itself.  This is
because (1) the body of the wormhole may be
partly under the surface, and (2) clicking only
selects the vertex nearest the viewer.

Touchup extensive edits in another plane to
neaten the inevitably ragged edges due to the
difficulty of editing the same location in
successive slices.

Detailed Instructions and Typical Problems

(1) fornix and hippocampus

First, find a slice containing an extensive view
of the hippocampus (easiest to find initially
with all3views turned on).  Then in SAGITTAL
view, edit out the hippocampus and the fornix.

Start at the anterior hippocampus, working your
way first posteriorly, then superiorly behind the
thalamus, up toward the lateral ventricle,
connecting up with it, and then anteriorly under
the corpus callosum until the fornix disappears
near the septum.  Repeat for the other
hemisphere.  Brush radius of 1 works well.

(2) calcarine sulcus joins occipital ventricle

There is a very thin white matter sheet between
the posterior extension of the lateral ventricles
and the calcarine.  The reconstructed surface
sometimes protrudes through this into the
ventricle, creating a large sub-calcarine
'wormhole'.  Also, a 3 slice-thick 'baffle' can
be put into the posterior lateral ventricle just
after it closes.

(3) ventromedial anterior temporal gyrus detached

Near the anterior end of temporal lobe, just
before it separates from the rest of the brain in
CORONAL view, there is a medioventrally pointing
parahippocampal gyrus that sometimes gets
detached at its base.  This usually only occurs
in a few slices.

(4) fill basal ganglia

Depending on the pulse sequence, the striatum
(caudate/putamen, globus pallidus, claustrum) may
be partly interpreted as gray matter (which it
mostly is!).  To fill striatum efficiently, use a
larger diameter brush (e.g., 10).

(5) small wormholes across sulci

Locate the wormhole in the data set and widen the
sulcus where it occurs.  It is best to do this
for one or two slices in either way from the
problem slice.  Fix Topology gets most of these.
These can occur across medial occipital sulci in
a brain with a markedly crinkled calcarine
sulcus.

(6) fill escapes down optic nerve

The optic nerve is a strand of white matter that
goes into the brain.  Edit it out in 3 coronal
slices just before it enters the brain.

(7) fill escapes into orbits

There is very little CSF between orbitofrontal
cortex and the orbits, and the white matter fill
may escape into the tops of the orbits, which
sometimes remain in the 'brain' image set even
after stripskull.  This is easy to fix.

(8) small posterior orbitofrontal sulci close

There are two thin anterior-posterior sulci in
medial orbitofrontal cortex than often have to be
opened manually.  This is easiest to see in a
CORONAL plane.  However, it is much faster to
edit these sulci in a HORIZONTAL view.


####################
fillhires
####################

-------------------------------------------
 The SubjectTools -> Fill WM (hi-res) menu item
 starts a background process to generate a white
 matter volume differently colored for the left
 and right hemisphere
-------------------------------------------
A 3-D region growing process is started from
specified right and left hemisphere points within
the white matter volume (wm/ COR dir, or wm.mgz),
which can be either 256^3 or 512^3.

 input3D: $SUBJECTS_DIR/$name/mri/wm[.mgz]

 output3D: $SUBJECTS_DIR/$name/mri/filled[.mgz]

Overview

First, RH and LH white matter seed starting
locations are manually defined by clicking points
in tkmedit (viewing the "wm[.mgz] data set) and
reading out native coordinates (N.B.: versus
Talairach coords in MGH freesurfer).  The seeds
can be anywhere in the respective white matter
halves.

Midbrain and callosal "cutting planes" are then
defined (see below for details).

Finally, fill algorithm parameters can be
adjusted (best not to change the conventional RH
and LH seed colors).

Region-growing algorithm

There are three stages to the "flood fill"
operation for each seed.  In the first stage, a
the region-growing algorithm builds up a
connected 3D volume from the inside-out.

Since this may result in internal voids, in the
second stage, the region-growing is performed
from the outside-in, up to the previously filled
volume.  This eliminates internal voids.

Finally, in the third stage , the volume is
refilled once more from inside-out to eliminate
any external voids that might have been
introduced in step two.

Specifying Cutting Planes -- details

To restrict the fill to the upper brainstem and
cortical white matter of a single hemisphere, two
"cutting planes" (actually thin 3D volumes) must
be specified.  These two volumes are each
specified by their bounding boxes (three pairs of
limits in the AP, IS, RL directions).  In each
case, one pair of limits will be only 3 voxels
wide.

First open the "wm[.mgz]" data set in tkmedit.
Then open the Expert Preferences -> WMFill tab to
enter the numbers you find.  The bounding boxes
are easily and quickly found and recorded by
using the following procedure.

Callosum Cut

  1) go to CORONAL view, click on mid callosum
  2) go to SAGITTAL view
  3) P/A:  posterior, anterior ends of callosum
  4) I/S:  zero to superior/top edge of callosum
  6) R/L:  one pix right and left of current R/L

Midbrain Cut

  1) go to near-midline SAGITTAL view, click just
       *below* inferior colliculus, just *above*
       where cerebellar white matter joins brainstem
  2) go to HORIZONTAL view
  3) P/A:  posterior, anterior ends of midbrain
  4) I/S:  one pix above and below current I/S
  5) R/L:  right and left of brainstem

For each pair of numbers, the second number
should be larger than the first.  Don't forget
that the CORONAL and HORIZONTAL views are
radiological, so smaller coords (the first entry
in each pair) are to the right in the display.

Adjustable Fill Parameters

These include the maximum number of back and
forth cycles for each fill, and the minimum
number filled per cycle before quitting (e.g.
100).  These two determine how many "wiggles" can
be filled (because the fill algorithm makes back
and forth passes, filling one additional "wiggle"
each pass).

Another adjustment is to the maximum same
neighbors during fill (the "wormhole filter").
With high quality data, a more accurate surface
can be obtained by turning Max Same Neigh down to
8.  If the data is noisy, this will introduce
more artifactual "wormholes".

Special cases

To fill a single volume, set the seed for one
hemisphere to a position outside the object in a
dark region with a voxel value below the fill
threshold ("thr:").

To disable the callosum and/or midbrain cutting
plane, set their inferior and superior limits to
0 and 1 (I=0, S=1).


####################
surfhires
####################

-------------------------------------------
 The SubjectTools -> Create Orig Surface menu
 item starts a two-part background process to
 create the left and right hemisphere cortical
 surfaces
-------------------------------------------
This "surf" program is run twice with two
different color targets on the same input 3D
volume (filled/ COR dir, or filled.mgz), which
can be either 256^3 or 512^3.

Each run connects the vertices of the faces of
the voxels of a specified color into a continuous
mesh.  If there are multiple disconnected volumes
of a single color, there will be multiple
disconnected output surfaces for one input color.

This program can be used to generate more than
two surfaces if the input volume has more than
two colors in it.

 input3D: $SUBJECTS_DIR/$name/mri/filled[.mgz]

 outsurf: $SUBJECTS_DIR/$name/surf/rh.orig
 outsurf: $SUBJECTS_DIR/$name/surf/lh.orig

The binary format of the orig output surfaces can
be quad short or quad float:

  Quad Surface File Format (short vtx coords):
    -------------- header ---------------------
      3-byte magic number (16777215)
      3-byte int vertex count (~150,000)
      3-byte int face count (~150,000)
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      2-byte int vertex x-position (mm x 100)
      2-byte int vertex y-position (mm x 100)
      2-byte int vertex z-position (mm x 100)
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      [vtx nums here are implicit ones above]
      [num each face ordered CCW from outside]
      corner1 corner2 corner3 corner4
      ... [quadruples up to face count]
    -------------------------------------------

  New Quad Surface File Format (float vtx coord):
    -------------- header ---------------------
      3-byte magic number (16777213)
      3-byte int vertex count (~150,000)
      3-byte int face count (~150,000)
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      4-byte float vertex x-position (mm)
      4-byte float vertex y-position (mm)
      4-byte float vertex z-position (mm)
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      [vtx nums here are implicit ones above]
      [num each face ordered CCW from outside]
      corner1 corner2 corner3 corner4
      ... [quadruples up to face count]
    -------------------------------------------

ASCII Export of Surface Geometry

The command line program "paint" with option
"-dump" can be used to export surface vertex,
face, and normal data to ASCII:

  paint -dump vtx   <name> <hemi> <surfsuff>
  paint -dump norm  <name> <hemi> <surfsuff>
  paint -dump neigh <name> <hemi> <surfsuff>
  paint -dump thick <name> <hemi> <surfsuff>
  paint -dump pvtx  <name> <hemi> <surfsuff> <patchsuff>
  paint -dump lnorm <name> <hemi> <surfsuff> <labelinf>

In each case, the output is an ASCII file (with
one initial comment line), and a single
tab-separated line of numbers for each uniquely
numbered surface vertex:

   vtx   => <hemi>.<surf>.vtx   => vtxnum  x  y  z
   norm  => <hemi>.<surf>.norm  => vtxnum nx ny nz
   neigh => <hemi>.<surf>.neigh => vtxnum n1 n2 n3 ..
   thick => <hemi>.<surf>.thick => vtxnum thickness
   pvtx  => <hemi>.<surf>.pvtx  => vtxnum  x  y  z
   lnorm => <hemi>.<labinfix>.lnorm => vtxnum nx ny nz

The first four options are for folded (or
inflated, sphere) surfaces.  The fifth is for a
patch (typically a flattened subset of a full
surface) and the last is for dumping the surface
normals of a label.

The surface normals are not saved in the surface
files and are only computed after the surface has
been read in.

N.B.: all ASCII output files are written into
the surf subdirectory of the current subject:

  $SUBJECTS_DIR/<name>/surf


####################
smoothcurvinflatesulchires
####################

-----------------------------------------
 The SubjectTools -> Smooth(Curv)/Inflate(Sulc)
 (hi-res) menu makes two deformations of the
 "orig" surface data and three data files from
 the deformation process
-------------------------------------------

This performs the same operations as MGHTools ->
Smooth(Curv)/Inflate(Sulc), but passes modified
parameters in order to properly unfold higher
resolution (~1M vertex) tessellations.  See Help
-> Smooth(Curv)/Inflate(Sulc) for details of input
and output files.

MGHTools -> Smooth(Curv)/Inflate(Sulc) still
works on a hi-res surface if you want to use
standard parameters anyway.

Parameter Hack For Unfolding Hi-res Surfaces

The program mris_inflate always stops when it
reaches rms_height = 0.15, even if more steps are
requested (desired_rms_height is not settable,
and there is no effect of reducing geom vs.
smooth parm).  For a high resolution surface, the
rms_height criterion is not low enough to allow
unfolding to finish.  This is because higher
resolution surfaces are locally smoother.  By
increasing the value of the undocumented
parameter -nbrs (neighborhood) to 5, the measured
height is increased (cost: ~5x computation time),
more iterations are preformed, and the surface is
more completely unfolded.

To redo the entire surface-making sequence
starting from an edited white matter volume
(wm[.mgz]), use SubjectTools -> Re-Make Surf

####################
mkfinalsurfshires
####################

-------------------------------------------
 The SubjectTools -> Make Final Surfaces (hi-
 res) menu item a starts a background process to
 create the final left and right hemisphere
 cortical surfaces and calculate cortical
 thickness.
-------------------------------------------
This can either use the MGH facilities
(mris_make_surfaces) or a tcl script that
controls tksurfer (see Preferences -> Expert
Preferences -> Final tab) ($CSURF_DIR/lib/tcl/
pialwhitethk.tcl).

(1a) Make Final Right Hemisphere Surfaces
(1b) Make Final Left Hemisphere Surfaces

The input files required are:

 volume: $SUBJECTS_DIR/$name/mri/brain[.mgz]
 volume: $SUBJECTS_DIR/$name/mri/wm[.mgz]
 volume: $SUBJECTS_DIR/$name/mri/filled[.mgz]
 surface: $SUBJECTS_DIR/$name/surf/rh.orig
 surface: $SUBJECTS_DIR/$name/surf/lh.orig

The tksurfer tcl script may also use a T2* scan:

 volume: $SUBJECTS_DIR/$name/mri/T2s[.mgz]

The output files written by this procedure are:

 surface: $SUBJECTS_DIR/$name/surf/rh.white
 surface: $SUBJECTS_DIR/$name/surf/rh.graymid
 surface: $SUBJECTS_DIR/$name/surf/rh.pial
 vtxdata: $SUBJECTS_DIR/$name/surf/rh.thickness

 surface: $SUBJECTS_DIR/$name/surf/lh.white
 surface: $SUBJECTS_DIR/$name/surf/lh.graymid
 surface: $SUBJECTS_DIR/$name/surf/lh.pial
 vtxdata: $SUBJECTS_DIR/$name/surf/lh.thickness

Cortical thickness algorithm (mris_thickness)

 (1) foreach vertex -> search opposite surface

   (a) pick pial surface vertex
   (b) find distance to same-numbered
          vertex in white matter surface
   (c) find neighbors of same-numbered
          white matter vertex
   (d) check distance from pial surface
          vertex to neighbors, too
   (e) find minumum distance of all these pairs

 (2) foreach vertex -> same search inverted

   (a) pick same-number white matter surface vertex
   ... search neighbors on pial as above

   Since surfs same topo, needn't re-find neighbors

 (3) average results of two above

Note that this doesn't refer to the normal,
which is only used to calculate a dot product
to determine if it is pointing in or out.

####################
inflatepatchhires
####################

-----------------------------------------
 The SubjectTools -> Inflate Surface Patch
 (hi-res) inflates (usually 3d) surface patch
-------------------------------------------

This takes a 3d surface patch as an input and
uses the function area_shrink() from tksurfer to
inflate it (Dale and Sereno, 1993).

The output of area_shrink() is similar, tho not
identical to that of mris_inflate.  Note that
mris_inflate which won't accept a cut surface.

The output can be used as a preprocessing stage
before further cutting the surface for difficult
flattenings (e.g., cerebellum).

To use this to inflate a full surface, first
write out a patch from a full surface without
making any cuts.

The output patch file will have "-inflated"
appended after the patch stem.  For example,
assuming we started with a patch made from
smoothwm:

  input -- lh.smoothwm.patch.3d

The output will be named:

  output -- lh.smoothwm-inflated.patch.3d

Each vertex is moved according to a geometry
preserving term that uniformly distributes
vertices in a tangential direction (tangential
vector sum -- strength set by $ws), a term that
reduces curvature (projection of neigbor-vector
sum onto vertex normal -- strength set by $wn),
and a term that reduces the directional log area
ratio (log area ratio is smoothed before use to
help unpack squished regions -- strength set by
$wa).

Since the curvature-reducing force will shrink
the surface, after each shrink cycle, the average
original area of the surface is restored
(normalize_area).  Since the default original
area ($hemi.area) calcuated by recon-all (based
on ($hemi.white) sets the area of vertices in the
cut medial wall to 0, these are first
recalculated/restored (initial pop-up).

These inflation parameters can be adjusted in
Preferences -> Expert Preferences -> InflateP
(defaults in parentheses):

  steps per cycle (15) 
  total cycles (tiffs) (100)
  dump tiff every cycle (0=OFF)
  weight tangential ($ws=0.5)
  weight normal/curv ($wn=0.5)
  weight logareaaratio ($wa=0.5)
  weight negar2norm ($wc=0.0) (def=OFF)
  bord mv uses nonbord nei ($bordneiflag, 1=def=ON)
  rm vtx w/no nonbord 2nd nei ($rmvtx2nonbordflag,def=ON)
  weight radial bord ($wt=0.5, $bordneiflag overrides)

The surface may contain holes.  Since the
tangential update component at a border vertex
will be biased inward, the movement of border
vertices is treated as a special case.

The default setting of $bordneiflag (1) moves
border vertices using the average of neighboring
non-border vertex movements.  If no neighboring
vertices are non-border, the average of second
order neighbor movements are used.  If no second
order neighbors are non-border, the vertex is
deleted from the patch if $rmvtx2nonbordflag is
set to 1 (default, else the vertex remains).

If $bordneiflag is 0, border vertices are moved
in a radial direction (strength set $wt).

Movie

To save tiffs of the inflation, set "dump tiff
every cycle" to 1.  To increase the number of
tiffs for the same inflation, reduce "steps per
cycle" and increase "total cycles".  The default
total number of steps is 1500 (100 cycles
multiplied by 15 steps per cycle).

####################
reconall
####################

-------------------------------------------
 The MGHTools -> Run recon-all menu runs
 MGH recon in the current SUBJECTS_DIR
-------------------------------------------
This minimal, self-explanatory panel is a small
wrapper to conveniently run MGH recon-all in the
current SUBJECTS_DIR.  It uses the MGH freesurfer
distribution pointed to by the current setting of
your environment variable, FSURF_DIR.  The
installation is typically in one of these
locations:

bash:
  export FSURF_DIR=/Applications/freesurfer
  export FSURF_DIR=/usr/local/freesurfer

tcsh:
  setenv FSURF_DIR /Applications/freesurfer
  setenv FSURF_DIR /usr/local/freesurfer

N.B.: recon-all requires tcsh (not just csh).

HOWTO Create New Surface in SUBJECTS_DIR

Collect one or more T1-weighted scans.  For
example, on a Siemens 1.5T machine, one or two
repetitions of a basic 10 minute 1x1x1mm MPRAGE:

  slices per slab (partitions):  160
  FoV read:  256 mm
  FoV phase:  87.5% => phase dir matrix=224
  Slice thickness:  1.00 mm
  TR:  2730 ms (=inversion pulse spacing)
  TE:  3.57 ms
  Filter:  Prescan Normalize => body coil norm
  TI:  1000 ms
  flip angle:  7 deg
  base resolution:  256
  phase resolution:  100%
  slice resolution:  100%
  phase partial Fourier:  Off
  slice partial Fourier:  Off
  orientation:  Sagittal
  bandwidth:  190 Hz/Px
  echo spacing:  8.4 ms (=standard def TR)
  excitation:  Non-sel
  Adjust vol (same as scan):  256x224x160mm

At 3T, you can use one or two repetitions
of an accelerated MPRAGE.  For example:

  slices per slab (partitions):  176
  FoV read:  256 mm
  FoV phase:  100.0% => phase dir matrix=256
  Slice thickness:  1.00 mm
  TR:  2300 ms (=inversion pulse spacing)
  TE:  2.98 ms
  Filter:  Prescan Normalize => body coil norm
  TI:  900 ms
  flip angle:  9 deg
  base resolution:  256
  phase resolution:  100%
  slice resolution:  100%
  phase partial Fourier:  Off
  slice partial Fourier:  Off
  accel: GRAPPA=2
  reference lines PE: 24
  orientation:  Sagittal
  bandwidth:  240 Hz/Px
  echo spacing:  7.1 ms (=standard def TR)
  excitation:  Non-sel
  Adjust vol (same as scan):  256x256x176mm

To create a new subject, first type name of new
subject into "new/redo subject:" followed by
Return.  This checks that a new subject doesn't
overlap an existing one (before doing this, you
can check for which name already exist in the
dropdown).

Next click FIND to select a NIFTI (or an AFNI
BRIK) scan to reconstruct (double-click folders
under "Directories:" in the left column in the
pop-up to see subfolders).  To average multiple
scans for a more accurate reconstruction, use
"ADD SCAN" (or "DEL LAST" if you have added too
many) and FIND again.

The panel will ask to auto-convert a BRIK or
you can convert from BRIK to nifti with:

  3dAFNItoNIFTI scan01+orig.BRIK

and from many other formats to nifti with
MGH mri_convert:

  mri_convert <otherformat> scan01.nii

Finally, click RECON-ALL and wait (~6 hours).  To
monitor progress, use Preferences -> View Logs.
To kill a reconstruction, click the purple
QuitRECON button.

With a single input file and no non-default
flags, this simply runs a command like:

  recon-all -subjid <newsubj> -all -i mprage.nii

HOWTO Redo Reconstruction of a Surface (edit wm.mgz)

First edit the wm data set.  Then select "re-run
starting with edited wm".  Then select an
existing subject in the "new/redo subject:"
dropdown and click RECON-ALL.

HOWTO Redo Reconstruction of a Surface (edit orig.mgz)

If too much of the brain is missing, you may want
to manually normalize the *original* data set
before passing it to recon-all (which performs 3
additional normalizations).  See Help -> Hand
Prenormalize and R-click help for the tkmedit
SMOOTHSTRUCT button for hints.

For example, you may have substantial erosion of
inferotemporal cortex (e.g., misclassified as
cerebellum), which can be fixed by very lightly
smoothing the structural data (e.g., 1 mm FWHM
Gaussian).

Another typical problem is that the anterior
temporal lobes may be very dark, causing parts of
them to be lost, which can be fixed by using
spherical normalization ("sph" tickbox on tkmedit
F3 interface).

To start recon-all from the very beginning, after
editing orig.mgz, convert it back to a nifti with
mri_convert (on the command line), and then use
the nifti to create a brand new subject.

Alternatively, to (more conveniently) continue
with the existing subject, edit orig.mgz, then
open:

  MGHTools -> Run Recon-all

tick "start from edited orig.mgz", select the
edited subject from the "new/redo subject:"
dropdown, hit <Return>, and click RECON-ALL.
This uses the already computed, alignment (if
more than one input scan), and the already
computed Talaiarch transform.  N.B.: currently,
this works if $FSURF_DIR points to an install of
MGH FreeSurfer 5.3, 6.0, or 7.1 (it uses a tiny
hack to the respective recon-all's).

HOWTO Run 'n' Copies of Recon-all in Background

The script "runra" (tcl, csh, and sh versions:
runra.tcl, runra.csh, and runra.sh) runs up to
the requested number of copies of recon-all in
the background to reconstruct the cortical
surfaces of an arbitrarily long list of subjects.
This is in order to take full advantage of a
machine with multiple cores (and enough RAM!).

Make a copy of one of the scripts and then edit
the setting of the variables at the top:

 $sublist	=> space sep list raw/reconned subj names
 $rawdir	=> contains subjname directories w/raw scan
 $rawscan	=> e.g., MPRAGE1.nii (must be all same)
 $maxprocs	=> max num background processes to run

The raw data should be in subject-named
directories, for example:

 /tmp/rawdata/marty/MPRAGE1.nii
 /tmp/rawdata/trevor/MPRAGE1.nii
 /tmp/rawdata/tessa/MPRAGE1.nii

The reconstructed subject directories will be
created in the current SUBJECTS_DIR, for example,
if SUBJECTS_DIR equals /usr0/subjects, then:

 /usr0/subjects/marty
 /usr0/subjects/trevor
 /usr0/subjects/tessa

The runra script starts up the requested number
of copies of recon-all in the background, and
then periodically monitors whether any have
finished.  If one has finished, a new recon-all
is started for the next subject, until the
subject list is finished.  To kill all running
background processes, use Ctrl-C.

After editing a copy of one of the scripts, just
type the name of the script with no arguments to
see the current setting of the lists.

To go, add option "-go"


####################
smoothcurvinflatesulc
####################

-----------------------------------------
 The MGHTools -> Smooth(Curv)/Inflate(Sulc) makes
 two deformations of the "orig" surface data and
 three data files from the deformation process
-------------------------------------------

(1a) Smooth Right Hemisphere White Matter
(1b) Smooth Left Hemisphere White Matter

The reconstructed white matter surface of the
right and left hemispheres is smoothed using
mris_smooth.  The output files written by this
procedure are:

Input files:

 surface: $SUBJECTS_DIR/$name/surf/rh.orig
 surface: $SUBJECTS_DIR/$name/surf/lh.orig

Output files:

 surface: $SUBJECTS_DIR/$name/surf/rh.smoothwm
 surface: $SUBJECTS_DIR/$name/surf/lh.smoothwm
 vertexdata: $SUBJECTS_DIR/$name/surf/rh.curv
 vertexdata: $SUBJECTS_DIR/$name/surf/lh.curv
 vertexdata: $SUBJECTS_DIR/$name/surf/rh.area
 vertexdata: $SUBJECTS_DIR/$name/surf/lh.area

The $hemi.curv files record slightly smoothed
local curvature.  Note that this may be convex
deep inside a sulcus because most sulci have
secondary crinkles.

(2a) Inflate Right Hemisphere
(2b) Inflate Left Hemisphere

The right and left hemisphere gray/white matter
surfaces are inflated using mris_inflate, while
while attempting to preserve local angles and
area.  The output files written by this procedure
are:

 surface: $SUBJECTS_DIR/$name/surf/rh.inflated
 surface: $SUBJECTS_DIR/$name/surf/lh.inflated
 vertexdata: $SUBJECTS_DIR/$name/surf/rh.sulc
 vertexdata: $SUBJECTS_DIR/$name/surf/lh.sulc

The $hemi.sulc files record the summed
perpendicular movement of each vertex and are
used by mris_register for cross subject surface
alignment.

See Help -> Smooth/Curv/Inflate/Sulc for details
of parameter hack for unfolding hi-res surfaces.

####################
mkfinalsurfs
####################

-------------------------------------------
 The MGHTools -> Make Final Surface menu item
 starts a two-part background process to create
 the final left and right hemisphere cortical
 surfaces and calculate cortical thickness
-------------------------------------------
(1a) Make Final Right Hemisphere Surfaces
(1b) Make Final Left Hemisphere Surfaces

The input file required are:

 volume: $SUBJECTS_DIR/$name/mri/brain[.mgz]
 volume: $SUBJECTS_DIR/$name/mri/wm[.mgz]
 volume: $SUBJECTS_DIR/$name/mri/filled[.mgz]
 surface: $SUBJECTS_DIR/$name/surf/rh.orig
 surface: $SUBJECTS_DIR/$name/surf/lh.orig

The output files written by this procedure are:

 surface: $SUBJECTS_DIR/$name/surf/rh.white
 surface: $SUBJECTS_DIR/$name/surf/rh.graymid
 surface: $SUBJECTS_DIR/$name/surf/rh.pial
 vtxdata: $SUBJECTS_DIR/$name/surf/rh.thickness

 surface: $SUBJECTS_DIR/$name/surf/lh.white
 surface: $SUBJECTS_DIR/$name/surf/lh.graymid
 surface: $SUBJECTS_DIR/$name/surf/lh.pial
 vtxdata: $SUBJECTS_DIR/$name/surf/lh.thickness

Cortical thickness algorithm

 (1) foreach vertex -> search opposite surface

   (a) pick pial surface vertex
   (b) find distance to same-numbered
          vertex in white matter surface
   (c) find neighbors of same-numbered
          white matter vertex
   (d) check distance from pial surface
          vertex to neighbors, too
   (e) find minumum distance of all these pairs

 (2) foreach vertex -> same search inverted

   (a) pick same-number white matter surface vertex
   ... search neighbors on pial as above

   Since surfs same topo, needn't re-find neighbors

 (3) average results of two above

Note that this doesn't refer to the normal,
which is only used to calculate a dot product
to determine if it is pointing in or out.


==========================
internal parameters
==========================
#define MAX_WHITE 120
#define MAX_BORDER_WHITE 105
#define MIN_BORDER_WHITE 85
#define MIN_GRAY_AT_WHITE_BORDER 70

#define MAX_GRAY 95
#define MIN_GRAY_AT_CSF_BORDER 40
#define MID_GRAY   \
  ((MAX_GRAY + MIN_GRAY_AT_CSF_BORDER) / 2)
#define MAX_GRAY_AT_CSF_BORDER 75
#define MIN_CSF 10
#define MAX_CSF 40

static int
  max_border_white_set = 0,
  min_border_white_set = 0,
  min_gray_at_white_border_set = 0,
  max_gray_set = 0,
  max_gray_at_csf_border_set = 0,
  min_gray_at_csf_border_set = 0,
  min_csf_set = 0,
  max_csf_set = 0;

static  float
  max_border_white = MAX_BORDER_WHITE,
  min_border_white = MIN_BORDER_WHITE,
  min_gray_at_white_border =
                   MIN_GRAY_AT_WHITE_BORDER,
  max_gray = MAX_GRAY,
 max_gray_at_csf_border=MAX_GRAY_AT_CSF_BORDER,
  min_gray_at_csf_border=MIN_GRAY_AT_CSF_BORDER,
  min_csf = MIN_CSF,
  max_csf = MAX_CSF;


####################
compat
####################

-------------------------------------------
 SubjectsTools -> Back Compat Curv/3d
 SubjectsTools -> Undo Back Compat Curv
 SubjectsTools -> Forward Compat 3d
 SubjectsTools -> Undo Forward Compat 3d
-------------------------------------------
MGH freesurfer changed the data
formats for curvature and sulcus files
({rh,lh}.{curv,sulc}: 2-byte => 4-byte) and 3D
files (directories containing COR files ->
single-file *.mgz files).  These menu items
support basic forward and backward compatibility
between the old and new formats.

#########################################
 N.B.: No longer needed because csurf0.8 (and
 FreeSurfer0.8) now read curr MGH volume,
 curvature formats (as well as older formats)
#########################################

Back Compat Curv/3d 

If a subject's surface has been reconstructed
using new freesurfer and you want to view it
with this older distribution, copy the subject
into a $SUBJECTS_DIR, select the subject, and use
"Back Compat Curv/3d" to generate the new format
curvature files and 3d files.

For 3d files, the new format files (*.mgz files)
are left in place and old format files
(directories containing single-byte, single slice
COR- files) are regenerated alongside them.

For curvature files, new format (4 byte) files
are moved aside to {rh,lh}.{curv,sulc}FLOAT and
old style (2 byte) files are generated from the
4 bytes files.  Re-run OK.

Undo Back Compat Curv

To restore the new format curvature and
sulcus files, this menu item moves the
old format curvature and sulcus files to
{rh,lh}.{curv,sulc}OLD and restores the
new format files to their original names:
{rh,lh}.{curv,sulc}.  The 3d files are not
touched.  Re-run OK.

Forward Compat 3d

Current MGH freesurfer has a bug that prevents
it from reading COR format files (faulty path
manipulation relating to COR-.info file).
To work around this bug, click this menu item
for a subject before operating on it with MGH
freesurfer.

New format *.mgz files are generated from
COR file directories, and then the COR file
directories are moved aside to <dir>COR to
prevent new freesurfer from finding them (and
failing before it looks for *.mgz files).

The following files are generated and renamed:

Generated:

  orig/COR-*    =>  orig.mgz
  T1/COR-*      =>  T1.mgz
  brain/COR-*   =>  brain.mgz
  wm/COR-*      =>  wm.mgz
  filled/COR-*  =>  filled.mgz

Renamed/Moved-aside:

  orig/COR-*    =>  origCOR/COR-*
  T1/COR-*      =>  T1COR/COR-*
  brain/COR-*   =>  brainCOR/COR-*
  wm/COR-*      =>  wmCOR/COR-*
  filled/COR-*  =>  filledCOR/COR-*

Re-run OK (asks choice of whether to write
over *.mgz file -- e.g., if COR files have been
re-made and need to be re-exported).

Undo Forward Compat 3d

To undo the renaming of the COR file directories
use this menu item.  The *.mgz files generated by
a previous "Forward Compat 3d" will not be
touched.  Re-run OK.  Note that FreeSurfer0.8 can
now directly read *.mgz files.


####################
makerelaxationcuts
####################

--------------------------------------------
 The MGHTools -> Make Full/Partial Surface Cuts
 menu item starts up tksurfer with a medial view
 of the inflated surface and a default output
 patch name in preparation for making relaxation
 cuts.  But note that any surface or surface
 portion (patch) can be cut, in any view.
--------------------------------------------

--------------------------------------------
CUTS FOR FULL HEMISPHERE FLATTENING
--------------------------------------------
(1) make relaxation cuts:
      ==> RIGHT-CLICK to clear all marks
      ==> LEFT-CLICK sequence
      ==> open-line cut with LINE
            [repeat above]
      ==> one standard 5-cut set:
  cut 1: medial, along fundus calcarine
  cut 2: amygdala to temporal pole
  cut 3: ant. corpus callosum to frontal pole
  cut 4: anterior cingulate to dorsal convexity
  cut 5: posterior cingulate to dorsal convexity
      ==> extend past planned midline removal

(2) encircle midline region to remove:
      ==> RIGHT-CLICK to clear all marks
      ==> LEFT-CLICK sequence

(3) make closed-line cut
      ==> AREA button

(4) seed region(s) to fill/save
      ==> single LEFT-CLICK 

(5) fill seeded region
      ==> FILL button

(6) save patch
      ==> patch: WRITE

The default names for the full cortical surfaces
with the midline removed (following instructions
above) are:

 rh.full.patch.3d
 lh.full.patch.3d

Replace the "full" with some other informative
name for other cuts (don't modify other parts of
the names).

If you want the pose settings for FULL/CORTEX in
the Preferences -> Expert Preferences -> Views
tab to apply to the flattened output, retain
"full" (or "cortex") in the name, but add some
characters (not including '.'), for example:

  rh.full-v1.patch.3d

Be sure that the surface is completely cut apart
at the point where the relaxation cuts end at the
midline cut-out.  To eliminate stray connections,
click on a few vertices on one corner of the cut
and do LINE to remove any stray attachments.
This can be verified with the MESH button (check
for even a single stray edge).

--------------------------------------------
CUTS FOR OCCIPITAL PATCH FLATTENING
--------------------------------------------
(1) make calcarine sulcus relaxation cut:
      ==> RIGHT-CLICK to clear all marks
      ==> LEFT-CLICK sequence
      ==> open-line cut with LINE

(2) specify cutting plane
      ==> RIGHT-CLICK to clear all marks
      ==> 3 LEFT CLICK's
      ==> for a patch including most of visual:
   click 1: medial, splenium corpus callosum
   click 2: lateral, intraparietal
   click 3: lateral, anterior inferotemporal

(3) mark region to keep
      ==> 1 LEFT-CLICK

(4) make the cut
      ==> PLANE button

(5) optional trim around callosum
      ==> RIGHT-CLICK to clear all marks
      ==> LEFT-CLICK sequence
      ==> open-line cut with LINE
            [repeat if necessary]

(6) save patch
      ==> patch: WRITE

The default names for the occipital patches with
a calcarine relaxation cut are:

 rh.occip.patch.3d
 lh.occip.patch.3d

Replace the "occip" with some other informative
name for other cuts (don't modify other parts of
the names).

Be sure to check for stray attachments across
the end of the relaxation cut as above.

--------------------------------------------
TIPS
--------------------------------------------

(1) HOWTO re-do cuts

To re-do a set of cuts using the previous set as
a guide, open the previous cut surface and save a
label.  Then open the original, uncut surface and
display the label with "D" before re-cutting.

(2) HOWTO make complex cuts

To cut a complexly-shaped surface, you may have
to adjust the view.  Upon redraw, the currently
selected set of vertices (previously cyan) will
become white -- but they will remain selected.
Continue selecting vertices, clicking AREA or
LINE when done.

(3) HOWTO make complex closed-line cut in stages

A complex closed-line (AREA) cut can be made as a
series of open-line (LINE) cuts.  In this case,
to avoid stray connections, start each new line
segment by first selecting a vertex on either
side of the end of the last already-cut line.


####################
flattensurface
####################

-------------------------------------------
 The MGHTools -> Flatten Surface menu item starts
 a two-part background process to create the
 flattened left and right hemisphere cortical
 surfaces (or surface portions)
-------------------------------------------
(1a) Flatten Right Hemisphere Surfaces
(1b) Flatten Left Hemisphere Surfaces

The input files are specified by the current
selection in the "patch:" entry.  For example,
"full.patch.3d" in the entry means, use these
input surfaces:

  $SUBJECTS_DIR/$name/surf/rh.full.patch.3d
  $SUBJECTS_DIR/$name/surf/lh.full.patch.3d

The output files in this case, will be:

  $SUBJECTS_DIR/$name/surf/rh.full.patch.flat
  $SUBJECTS_DIR/$name/surf/lh.full.patch.flat

To flatten only one hemisphere, first select
"RIGHT" or "LEFT".

To re-flatten a surface patch, select an
already-flattened surface in the "patch:" entry.
There will be a warning that you are
re-flattening an already flat surface (in case
this was not what you intended).  Note that in
this case, the final output will overwrite the
already flat input file, so copy it aside, or
start with a differently named copy if this is
not what you want.


Save/review flattening steps

For large complex-shaped surfaces (e.g., cut
cerebellum) it may help to re-flatten the
surface.  In addition, you may want to use an
intermediate step (e.g., of a re-flattening)
instead of the final result, which sometimes gets
stuck in a crinkled local minimum.  To save the
surfaces for intermediate steps, use a non-zero
value for:

  Expert Preferences -> Flatten tab -> write every x iter

When this is set to 0 (default), only the final
patch is saved.  If you are re-flattening, note
that this overwrite the input patch if you didn't
first copy it aside.  If this entry is instead
set to 10, for example, then given an input file:

  ~/surf/rh.ant.patch.flat

MGH Tools -> Flatten Surface Patch will write out
a series of patches named as follows:

  ~/surf/rh.ant.patch.flat0000
  ~/surf/rh.ant.patch.flat0010
  ~/surf/rh.ant.patch.flat0020
  . . .

as well as the final non-numbered output:

  ~/surf/rh.ant.patch.flat

To review the intermediate stages, use
flattenmovie.tcl to render some or all of them to
tiffs.  The relevant adjustable parameters in
flattenmovie.tcl are:

  f
  minflat
  maxflat
  every

where "f" is the starting frame number (so you
can append to a movie frame series by setting it
to a non-zero value), "min/maxflat" are the
beginning and ending appended numbers on the
intermediate patches above, and "every" is like
"write every x iter" (but it can be even less
often than that).

Note that flattenmovie generates a series of
sequentially numbered (%04d) frames so they can
be recognized as a frame sequence by QuickTime.
Note that this inconveniently requires
multiplying the frame number of the tiff by
"every" to find the patch number suffix.

####################
spheresurface
####################

-------------------------------------------
 The Tools -> Sphere/Register Surface menu item
 starts a four-part background process to create
 the spherical left and right hemisphere cortical
 surfaces and then registers them to an average
-------------------------------------------
(1a) Sphere Right Hemisphere Surface
(1b) Sphere Left Hemisphere Surface

The output files written by this procedure are:

 surface: $SUBJECTS_DIR/$name/surf/rh.sphere
 surface: $SUBJECTS_DIR/$name/surf/lh.sphere

(2a) Register Right Hemisphere Surface
(2b) Register Sphere Left Hemisphere Surface

 surface: $SUBJECTS_DIR/$name/surf/rh.sphere.reg
 surface: $SUBJECTS_DIR/$name/surf/lh.sphere.reg

Morph Targets

Two of the several sets of average spherical
target surfaces in the standard MGH distribution
directory:

  $FSURF_DIR/average

are accessible from the csurf Expert Preferences
interface (SphereReg tab).  Note that these two
targets are *not* aligned with each other (!) and
should never be mixed within one analysis:

  rh.average.tif
  lh.average.tif

  rh.average.curvature.filled.buckner40.tif
  lh.average.curvature.filled.buckner40.tif

The first set was used in older MGH FreeSurfer,
FreeSurfer0.8, and csurf0.8, and is still
accessible for back compatibility.

The 'buckner40' average, used in the default
recon-all pathway, is now (starting Feb 2015) the
default in csurf Expert Preferences.

Parameters (Expert Preferences -> SphereReg)

The main adjustable parameter is the coefficient
on the geometry-preserving term (-dist), which
has the strongest effect on the output.

The coefficient on the area-preserving term
(-parea) can also be adjusted, but even when
high, it allows 'taffy-like' deformations.

Finally, the coefficient on the sulcus error
(-corr), can be adjusted independently, but is
usually kept at default=1.0 for ease of parameter
comparison.

The defaults are:

 align to group targ: dist=0.1, parea=0.2
 align to indiv targ: dist=0.5, parea=0.1  (stiffer)

In summary, to get a less deformed morph (but one
that as a whole will less closely match the
target sulc), turn up dist.

####################
tkmedit
####################

-------------------------------------------
 tkmedit -- display and edit MRI slice data
-------------------------------------------
The tkmedit program  is started either by the
VOLUME botton on the main csurf panel, by the
VOLUME-STATS button on the SessionTools -> View
Functional Data panel, or from the command line
(see below).

It reads one or more series of images and
displays them in the coronal, sagittal, or
horizontal plane, or in all 3 planes at once
along with a sagittal maximum intensity
projection.  Images must be in one of two
formats:

  (1) COR dir: 256 (or 512) 1-byte 256x256
      (or 512x512) coronal slices images

  (2) 256^3 or 512^3 .mgh/.mgz format

Images in the first (edit) buffer can be edited
and saved (in same format as read).  Images read
into the second buffer cannot be edited.  Edits
applied while viewing the second buffer affect
the first buffer (useful when edit buffer has
segmented white matter and second buffer has
original full orig/T1 images which have more
content and context, which makes edits easier).

There is a 4-step undo (alt/cmd-z) and a 1-step
redo (alt/cmd-Z).  Alternate image window
shortcuts for undo and redo are ctrl-left-click
and shift-ctrl-left-click).

Up to two surfaces from the same hemisphere can
be read and the intersection of the surfaces with
the current slice displayed in yellow (first) and
green (second).

A real- or complex-valued stats overlay can be
displayed using the same color scales as
tksurfer.

If a scan directory contains rawdata, hand-made
ROIs or MGH 3D segmentation ROIs can be used to
extract raw timecourses for further analysis.

Context-dependent help

Every interface element (button, tick, entry,
bold label title) has a R-click help panel, which
are also all gathered in the csurf -> Help -> All
Help Contents panel.  For any button or tickbox
with multiple hotkey functions (some up to 5),
R-click help also brings up a button bar with
verbosely named buttons to control each alternate
function.

Workaround for MGH tkmedit (which req's pixwidth=0.0)

MGH tkmedit currently requires that the
voxelsize/spacing fields in the *.mgz header
(spacingX,Y,Z, in mm) all be 0.0.  If any are
non-zero (e.g., they will be 0.5 in a hi-res
512^3, 0.5mm^3 voxel data set generated by
brik2cor here), MGH tkmedit will return the
following error:

  MRIresample(): source matrix has zero determinant

As a workaround, verify that the spacing fields
are non-zero, and them reset them to 0.0 with:

  calcimg -spacing <file>.mgz            # read
  calcimg -setspacing 0.0 <file>.mgz   # change

This saves aside the original dataset for safety.

Running tksurfer from a bash/tcsh shell script

N.B.: on MacOS 10.11+, the environment variable
DYLD_LIBRARY_PATH is *not* passed into a shell
script, which will prevent tkmedit from seeing
the csurf X11 tcl/tk libraries.  To use tkmedit
in a MacOS 10.11+ shell script, include the
following line before the first call to tkmedit:

csh/tcsh:
  setenv DYLD_LIBRARY_PATH $CSURF_LIBRARY_PATH

sh/bash:
  export DYLD_LIBRARY_PATH=$CSURF_LIBRARY_PATH

-------------------------------------------
Volume Image Window Clicks
-------------------------------------------

(1) Left-Click: Select point

  On change plane, this click determines which
  other-plane slice will be shown.  For example,
  in CORONAL view, to view a SAGITTAL slice
  through the hippocampus, first click the
  hippocampus in CORONAL view, then click
  SAGITTAL.  This also prints data about this
  point to the log.

(2) Middle-Click: Edit to white

  Used to fill in missing part of the white
  matter -- N.B.: this always edits the main
  buffer even when viewing the second buffer.

(3) Right-Click: Edit to black

  Used to cut away parts of image that aren't
  white matter -- N.B.: this always edits the
  main buffer even when viewing the second
  buffer.

(4) Shift-Left-Click: Edit to targval if im/(im2) in bounds

  If image pix is within bounds (set by two
  entries right of TRUNC), it is edited to the
  target value (set by entry to right of PF).
  Middle clicking lower right "la" tickbox uses
  im2 (instead of the editable image) for the
  bounds test (but edits still go to im).
  Finally, when using im2 bounds, a second set of
  bounds can block the im edit to preserve
  structure.  R-click on TRUNC or the entries to
  make a popup with all the parameters.

(5) Shift-Middle-Click: Print histogram of 3D region

  First set "rad:" to pick the radius of a the
  sampling sphere.  If gnuplot is installed, a
  shift-middle-click on a selected vertex prints
  a very lightly smoothed histogram.

(6) Shift-Right-Click: Dump single voxel timecourse

  If a timecourse overlay has been loaded with
  -rawdata (and -regdat), this will dump clicked
  voxel timecourse to the bottom of the slice
  viewer.  Additional shift-right-clicks in this
  slice overlay additional voxel timecourses.
  Left-click to clear.

(7) Double-Middle-Click: Report pixval

  A pop-up reports the value of the underlay pixel.
  If an MGH segmentation have has been loaded, the
  label name, idnum and rgb values are also reported.

(8) Ctrl-Left-Click: Undo last edit

  Undoes most recent edit (click or click-drag in
  image window).  Cmd-z in image window is
  equivalent.

(9) Ctrl-Right-Double-Click: This help

[no longer needed: use "no double-clk" tickbox on
F4 tkmedit interface ($blockdoubleclickflag)].

-------------------------------------------
 Keyboard shortcuts -- for both image,tk windows
-------------------------------------------
Single key

  # interface size (see also far left "i" button)
  F1 -- basic interface     (Mac=fn-F1)
  F2 -- overlay interface   (Mac=fn-F2)
  F3 -- normalize interface (Mac=fn-F3)
  F4 -- electrode interface (Mac=fn-F4)
  F5 -- thin horiz interface (Mac=fn-F5)

  # move slice
  R/L arrow   -- slice up/down
  up/dn arrow -- slice up/down

  # cursor
  k  -- one-time switch to large cursor
  K  -- toggle cursor visibility
  O  -- toggle open center cursor

  # fmid control
  i  -- fmid down (more permissive)
  I  -- fmid up (less permissive)

  # resize image window (only works in img win)
  1  -- 1 underlay pix -> 1 screen pix
  2  -- 1 underlay pix -> 2x2 screen pix
  3  -- 1 underlay pix -> 3x3 screen pix
  4  -- 1 underlay pix -> 4x4 screen pix

Modifier + key (LinuxMod="Alt", MacMod="Cmd")

  # cursor
  Mod-k  -- one-time switch to lg cursor
  Mod-K  -- toggle cursor visibility
  Mod-O  -- toggle open center cursor

  # edit brush
  Mod-b  -- return to single pix brush
  Mod-B  -- increase brush radius (wraps)
  Mod-l  -- go back to last brush size
  
  # underlay contrast
  Mod-asterisk -- contrast up (times)
  Mod-slash    -- contrast down (divide)

  # underlay brightness
  Mod-plus   -- brightness up
  Mod-minus  -- brigthness down

  # underlay back to default contr/bright
  Mod-equals  -- contr=>12,midpt=>0.35

  # COMPARE button
  Mod-0 [zero] *or* Mod-singlequote

  # SEND/GOTO
  Mod-f  -- SEND (forward) point
  Mod-g  -- GOTO point

  # surface
  Mod-d  -- toggle surface visibility

  # maximum intensity projection
  Mod-p  -- toggle max intens proj

  # stat overlay
  Mod-o  -- toggle stats visibility

  # fmid control
  Mod-i  -- fmid down (more permissive)
  Mod-I  -- fmid up (less permissive)

  # SAVE IMG
  Mod-e  -- save (edit) images
-------------------------------------------


F1 Interface (default)

The default F1 interface is described from upper
left to lower right.

CORONAL/SAGITTAL/HORIZONTAL button/slider/field

 button:           switch to this view
 slider:           change slice in this view
 slider field:     enter/view slice number
 talairach field:  enter/view coord (MNI)

When switching planes, the new plane will pass
through the current cursor location.  This is the
location of most recent left-click (default at
startup is center).

To move one slice, use the arrow keys or click in
a slider well to the left or right of a slider.

A non-default middle-click on the CORONAL button
pops up a panel to allow performing one of 48
different possible 3D transposes on the data
(using tcl/C function flip_corview_xyz -- see
below for details).

Display parameters (overlay/surf/contrast/midpnt)

The "overlay" checkbutton toggles display of
functional data over an anatomical slice image.
Overlay data is controlled by fthr/fslope/fmid
fields at the lower middle right (not the
immediately adjacent "contrast" and "midpoint"
fields).  Load an overlay using the VOLUME-STATS
button at the top of the SessionTools -> View
Functional Data panel.  Look in log to see
additional options given to tkmedit.

The "surface" checkbutton toggles whether or not
the intersection of the currently-read-in surface
with the current slice is displayed.

The "contr" and "midpt" fields control the
(editable) underlay.  Higher "contr" increases
the steepness of the sigmoid multiplying the data
before display (default=12.0).  The "midpt" field
sets the mri data number that appears at half-max
brightness, in units of 0.0-1.0, so a midpoint
setting of 0.35 (default) means that image data
that has a value of 0.35 * 255 = 89 will be
displayed at half-max (=128).

To see points that you have edited to black
(actually to an image value of 1, not 0), set
contrast and midpoint to:

  contrast = 200
  midpoint = 0.01

FILL/ROI controls

The FILL button does a 3D region-growing fill
down of 4 different kinds of overlay data, in
order of precedence:

  last-clicked 3D annotation region
  stat mask > $sfthresh
  overlay data > $fthresh
  struct data between WMTRUNC limits

If the entry immediately to the right is not 0.0,
the fill will be limited to a maximum spherical
radius (mm).  Also, edits to black (e.g.,
temporary) are respected.

A shift-left-click on the FILL button reports the
volume of the currently filled region.

The "roi" tick toggles visibility (in white) of
the ROI (occludes overlay data) while the "m"
tick toggles using the ROI (where it equals 0) as
a mask for the overlay data.

"SAVE IMGS" button

This button saves edited images (COR files or
.mgh/.mgh file) in the editable buffer back to
the file and format that was read in at tkmedit
startup.

N.B.: SAVE IMGS ignores any change you might have
made to the image name in "im:" field (SAVE IMGS
uses the filename read in at startup -- that is,
it always overwrites the input file).

By contrast, the "W" (write) button on the "im:"
line respects any change made to the filename on
that line, so this can be used for "Save As..."
(the "im:" field is *not* visible in F2/overlay
view, but is visible in F1 and F3/F4 view).

The tilde (~) in the "im" (and "surf") entry
field is an abbreviation of the path of the
current subject directory such as:

  /machine1/usr2/subjects/marty

You can substitute an absolute path if you want
to save the images somewhere else.  Save whenever
you are satified so far.

SEND PNT, GOTO PNT

SEND PNT saves the current 3D location of the
cursor while GOTO PNT moves the display (in the
current slice plane view) to a previously saved
3D location (saved in either medit or surfer).
Note that GOTO PNT in medit goes to a 3D location
while GOTO on the surfer panel requires a search
for nearest surface point (see Surfer help for
details).

Edit Brush Control (rad, 3Dbrush)

The "rad" field sets the radius of the editing
brush.  The default is a one pixel brush.  At
larger radii, the brush is circular.  A radius of
1 is a useful brush size.  By default, the brush
is 2D, which means that it only affects pixels in
the current slice.  The "3Dbrush" checkbutton
toggles back and forth between a 2D and a 3D
brush.  Use the 3D brush with care since you are
editing slices you cannot see.

Editing (middle/right-click)

  LEFT-CLICK    just select a point
  MIDDLE-CLICK  set to white matter (255)
  RIGHT-CLICK   erase (set intensity to 1)

all3views

The "all3views" checkbutton toggles whether one
view is shown or whether 3 views (coronal,
sagittal, and horizontal) as well as a sagittal
maximum intensity projection is shown.  Clicking
in one of the views when "all3views" is selected
causes the other two views to go to the
corresponding point.  Clicking in the maximum
intensity projection view at the lower right
re-centers the 3 views.

When "all3views" is selected, an additional
checkbutton, "z", appears which toggles a 2x zoom
of the central portion of each of the 3 images.
This makes subcortical structures (and functional
overlays on them) easier to see.  The zoomed view
cannot be panned.  If "all3" is unclicked, the "z"
button disappears.

3D/surface File Entries

Slightly different interface lines are visible
with different interface sizes.  Also, clicking
val{n,s} and msk{n,s} toggles between the "n"
(native) and "s" (upsampled) entries.

  surf	-- read surface ("cpx" affects overlay)
  im	-- read/write editable 3D images
  roin	-- read and register native ROI
  roiup	-- read/write upsampled ROI, to get timecourse
  valn	-- read and register native res overlay data
  valup	-- read/write upsampled overlay data
  mskn	-- read and register native res mask
  mskup	-- read/write upsampled mask
  rgb	-- write tiff bitmap (or SGI rgb)

The "surf" entry specifies the surface to read
("R").  The intersection of the surface with the
current slice is drawn in yellow.  Ticking the
"2" checkbutton before reading a surface causes a
second surface to be read and displayed in green.
Visibility of surfaces is toggled by the lower
left "surface" checkbutton.

The "im" entry reads and write images to and from
the editable buffer.  Note that the "R" button on
the "im" entry can read another dataset into the
editable buffer, destroying any edits that
haven't been saved (with either SAVE IMGS, or
equivalently with the "W").

The "roi{n,up}" two-state entry (toggle by
clicking the bold label) reads and writes an AFNI
ROI/label file with voxel value of 1 or 64 to
indicate where the filled/connected label is.
Can be either in native/rawdata resolution or
upsampled and registered to the 256^3/1mm^3
underlay resolution.  This can be used to extract
rawdata time courses ("T") or mask overlay data
("m").  If an MGH 3D segmentation has been
loaded, a region idnum can be typed into this
entry to extract timecourses.

The "val{n,up}" two-state entry (toggle by
clicking the bold label) reads and writes real or
complex overlay activations in either
native/rawdata resolution or upsampled and
registered to the 256^3/1mm^3 underlay
resolution.

The "msk{n,up}" two-state entry (toggle by
clicking the bold label) reads native/rawdata or
upsampled and registered stat masks.

The "rgb" entry writes the current view into a
tiff (or an SGI rgb file if the unlabeled
checkbox to the right of the entry is unchecked).

WMTRUNC

This button toggles whether the image is
truncated to zero below the low and high limits
in the entries to the right.  The truncation is
applied to both the editable view as well as the
second buffer if another dataset has been loaded.
It is useful for inspecting the images for small
brightness ramps which are often hard to see
(because the visual system is so good at
autonormalization).

TRUNC is typically turned on when using the ramp
or spherical correction utilities of the extended
interface (F3).  These allows piecewise linear
test correction ramps or variable radius
spherical field corrections to be applied to the
image in the second buffer.  Generally, it is
good to check if the rough segmentation is
improved before applying the corrections to the
entire data set (see below).

The two entries also have an overloaded use to
set bounds and pixel value targets for pixel
range-dependent editing (shift-right-click in
image window - see R-click help for the two TRUNC
entries).

PF, PFGAU (anisotropic plane filters)

The PF and the PFGAU apply truncating or
anisotropic Gaussian 'wormhole' filters to the
image in the editable buffer.  The output is
either saved into the second bufer for
comparison, or into the editable buffer for
saving.  See the R-click help for the PF and
PFGAU buttons for more details.

The entries also has an overloaded use to set the
target value for pixel range-dependent editing
(shift-right-click in image window - see R-click
help for the PF entry).

Second Comparison Image Set (im2:)

By clicking the adjoining "R", the dataset
specified in "im2" is read into the second
(non-editable) buffer.  Successive "R's" simply
replace the dataset in the non-editable buffer.
The field expects a COR directory or .mgz file
that is relative to:

  $SUBJECTS_DIR/$subject/mri

You can also put an absolute (or tilde
abbreviated) path to a COR directory or an
.mgz file into this field.

Finally, an 3D MGH segmentation file (byte or
int) can be read using the same dropdown and "R"
button.  In this case, it will be used to
construct a transparent overly for the main
(editable) buffer using the idnum->colors map
found in:

  $CSURF_DIR/lib/lut/FreeSurferColorLut.txt

The label ransparency can be adjusted using the
"tran:" entry on the large F4 tkmedit interface.
(the "no double-clk" tick immediately below
disables double click pop-ups for fast editing).

Generalized Transpose of 3D Image Data

A general flipping operator (the C/tcl function
flip_corview_xyz) is accessible from a pop-up
after a middle-click on the CORONAL button.  This
allows you to rearrange the axes of a data set,
starting from whatever is displayed in CORNONAL
view.  Thus:

  flip_corview_xyz  x  z  -y

changes the x-direction currently viewed in
CORONAL view to the x-direction in the new data
set, the y-direction in the current view into the
new z-direction, and the current z-direction (the
direction you move when y ou change CORONAL
slice) into the minus y-direction in the new data
set.  This command checks for degenerate flips.

Not that there are 48 different 3D transposes for
viewing a 3D data set: 6 cube face views x 4
rotations of each face x 2 mirror-images (so it
is easy to get lost).

COMPARE

This toggles between the volumes in the two
buffers.  You can edit in the second buffer view;
remember that in this case, edits are applied to
the now invisible first editable buffer.

Alternate clicks allow swapping the contents of
the editable and im2 buffers (C/tcl function,
swap_imim2), and copying im2 edits to the
editable buffer (C/tcl funct, im2wmedits_to_im).


F2 Interface (add overlay display)

You can toggle between different interface sizes
using either F1 to F5 (add "fn" key on Mac), or
from a small pop-up available from the far left
"i" button.

Use F2 (Mac: fn-F2) in the tkmedit panel to add a
small overlay control panel to the right.  The F2
panel is automatically displayed if an overlay has
been loaded from csurf.  Use F1 to get back to the
default panel.

The "fthresh", "fslope", and "fmid" fields (on
the main panel) have the same effect as the
fthresh, fslope, and fmid fields on the tksurfer
panel.  See the R-click help for the tickbox
immediately left of "mskn:", which enables
masking of the overlay by a stat file (this
doubles each of the entries above).

The SMOOTHSTATS button performs a convolution
with a 3D Gaussian with settable kernel width
(unlabeled left field) and FWHM in mm.  If
"overlay" is unclicked, the SMOOTHSTATS button
changes to SMOOTHSTRUCT so that 3D smoothing can
be applied to the structural data.

Next are radio buttons for 6 different color
scales.  The first three are for complex-valued
stats: w1=Wheel1, h=Heat, and b=BiRedGreen.  The
last three are for real valued stats:
BR=BlueRedWhite, BRy=BlueRedCyanYellow, and
lt=LookUpTable.  The next line of widgets allows
editing, reading, and writing color look up
tables (suffix: .lut).

Complex-valued data are controlled with the same
truncate, reverse, angle cycles and offset, and
ipsilateral fade/yellow controls as in tksurfer.

Run Tcl Script

At the bottom right is an entry to edit (click
ED) and run (click GO) a tcl tkmedit tcl script,
such as phasemovie.tcl or mri2mpg.tcl.  Use a "#"
as an abbreviation for the standard tcl scripts
directory (or an absolute path like /tmp/zz.tcl).

Logging Interface Actions as Tcl Commands

Clicking the "tcl:" label near bottom right of
the tkmedit interface turns on the logging of
all interface actions as tcl commands to the
file, tkmedit.log, in:

  $FUNCTIONALS_DIR/<session>/image/scripts

These can be used to record actions to make a
command line tcl script to automate tkmedit
actions.  The "tcl:" label turns bold during 
logging.  To finish logging, click the label
again.  Or you can startup tkmedit from csurf
with the log already on by selecting:

  Preferences -> Log tkmedit actions as tcl cmds

Note that in both cases, any previous log of tcl
commands in tkmedit.log in this session's script 
dir is overwritten so each log starts fresh.


F3 Interface (rm overlay, add hand normalize)

Clicking F3 (Mac: fn-F3) in the medit panel
expands it (F1 goes back to the default view or
F2 back to the default plus overlay view).  The
new subpanel on the right allows you to test and
then apply a piecewise linear ramp of brightness
correction factors (ffrac0-3) at four control
points (lim0-3).  See Help -> Hand Pre-Normalize
for more details on how to use this facility.


F4 Interface (add SURFPAINT, electrode align)

This panel contains controls for interactive
electrode positioning (less well supported), and
display of curvature, fieldsign, and annotation
files along the cortical ribbon of a slice.


F5 Interface (long thin minimal horizontal)

This long thin panel is designed to take up as
little screen space as possible while editing a
complex surface (e.g., cerebellum) where a large
surface view as well as a large slice view is
required.

-------------------------------------------
 Standalone Commandline and Script Operation
-------------------------------------------
tkmedit can also be run as a standalone program
from the command line (as long as SUBJECTS_DIR
and FUNCTIONALS_DIR are set):

Use: [edit MRI, optional img2/surf/stats]

 tkmedit subj COR/mgz [surfname] [-tcl script] [opts..]
 tkmedit CORdir/mgzfile
 tkmedit -help,-h   => more verbose help

   subjname:  subject name     (in $SUBJECTS_DIR)
   CORdir:    orig, T1, ...    (in $subject/mri)
      *or*
   mgzfile:   orig.mgz, T1.mgz, ...
   surfname:  ?h.smoothwm, ?h.inflated, ...

   {256,512}^3 byte-img or .mgz/.mgh byte/short/int/float
   overlay activations upsampled to {256,512}^3

 Examples:

   [display SUBJECTS_DIR CORdir volume, from any dir]
   tkmedit martys09 orig

   [display SUBJECTS_DIR .mgz volume, from any dir]
   tkmedit martys09 orig.mgz

   [display local .mgz volume]
   cd $SUBJECTS_DIR/martys09/mri
   tkmedit orig.mgz

   [read/reg/upsamp/overlay native res complex stats]
   cd /usr0/sessions/120101MS/image/scripts
   tkmedit martys09 orig rh.orig \
     -scandir ecc1 \
     -real pol1-vreg+orig_r+orig.BRIK \
     -imag pol1-vreg+orig_i+orig.BRIK \
     -regdat register.dat \
     -rawdata ecc1-vreg+orig.BRIK \
     -colscale 0 \
     -angle_cycles 1.0  \
     -angle_offset 0.75  \
     -fslope 1.5 \
     -fmid 1.1

Type "tkmedit -h" to get a verbose list of
options, tcl commands, and more examples.

The program has an embedded tcl interpreter and
most of its functions (including some not exposed
to the medit tools interface, as well as some
that are obselete...) can be accessed through it,
either interactively at the tcl prompt, %, that
appears in the terminal from which tkmedit is
started, or offline using a tcl script in a file
whose name follows the -tcl option on the command
line.  If you include an "exit" at the end of the
tcl script, tksurfer will quit when the script
finishes.  You can find commands available from
inside the tcl interpreter using "help" or "info"
(info accepts wildcards):

  % help
  % info command flip*

Here is an example of a small command line tcl
script that reads in the data on the command
line, and then saves a flipped data set into
a new directory:

flip_corview_xyz -y x z
set abs_imstem /subjects/bill/mri/T1-new/COR-
write_images
exit

If you put the commands above into a file
flip.tcl, you could run it like this:

  tkmedit john T1 -tcl flip.tcl

There is a built-in script (mri2mpg.tcl) to make
3 mpg movies (coronal, sagittal, horizontal)
that can be accessed by typing F12 anywhere in
the medit tools interface.  It asks for slice
limits (min,max) in the three slice planes and
dumps the mpegs in $SUBJECTS_DIR/$name/mpg.

As noted above, you can record the tcl commands
for all interface actions by clicking the "tcl:"
label at the lower right.

####################
tkregister
####################

------------------------------------------
 tkegister -- interactively blink-register two volumes
------------------------------------------
Register reads two series of images, a TARGET set
(e.g., orig.mgz) and a MOVEABLE set (e.g., a
volume from an fMRI series), and displays them in
coronal, sagittal, horizontal, planes.  The
images in the the TARGET buffer are fixed while
the images in the MOVEABLE buffer can be modified
with a linear transformation--which includes
rotation, translation, and stretching.

Volume to Surface

The primary goal of register is to generate a 4x4
linear transformation matrix (register.dat) that
can be used by other programs (e.g., paint,
tksurfer) to associate 3D statistics made from
the MOVEABLE image to individual vertices of a 2D
surface made from the TARGET image set.

The register.dat matrix can also be used by
tksurfer to extract raw functional data
timecourses (ASCII) given a surface point, or a
surface label (see R-click help for the "T"
button on the "label:" line).

Volume to Volume

The register.dat matrix can be used to overlay
stats from the MOVEABLE image set onto the TARGET
image set in 3D, using tkmedit (csurf -> View
Functional Data -> VOLUME-STATS).

Finally, tkregister can be used for quick and
dirty hand registration of one *.mgz to another
(e.g., tkregister orig1.mgz orig2.mgz).

Register.dat Matrix

The transformation matrix that is generated
transforms a point in the TARGET data set (e.g.,
a T1 image from which the orig.mgz surface was
made) to a point in the MOVEABLE data set (e.g.,
a functional MRI scan, corner based voxel
coordinates).

Transformations (rotations, translations,
stretchings) are applied to the MOVEABLE data set
relative to its current view/transformation.
They will be immediately visible in other planes
or other slices of the MOVEABLE data set.
Rotations take place around the last left-clicked
point.

Blink comparison

The image sets are compared to each other by
pressing the COMPARE button.  Once the
registration is satisfactory, it can be saved
with SAVE REG (asks before overwrite).  To go
back to the original registration, quit without
saving and restart, or use READ REG before saving
(in extended F3 interface).

Usage from a MacOS 10.11+ shell script

N.B.: on MacOS 10.11+, the environment variable
DYLD_LIBRARY_PATH is *not* passed into a shell
script, which will prevent tkregister from seeing
the csurf X11 tcl/tk libraries.  To use
tkregister in a MacOS 10.11+ shell script,
include the following line before the first call
to tkregister:

csh/tcsh:
  setenv DYLD_LIBRARY_PATH $CSURF_LIBRARY_PATH

sh/bash:
  export DYLD_LIBRARY_PATH=$CSURF_LIBRARY_PATH

-------------------------------------------
 Keyboard shortcuts -- for both image,tk windows
-------------------------------------------
Single key

  # interface size
  F1 -- small interface    (Mac=fn-F2)
  F2 -- standard interface (Mac=fn-F2)
  F3 -- large interface    (Mac=fn-F3)

  # move slice
  R/L arrow   -- slice up/down

  # COMPARE button
  0 [zero]    -- swap target and moveable

  # target (struct) brightness
  Mod-plus   -- target brightness up
  Mod-minus  -- target brigthness down

  # target (struct)  contrast
  Mod-asterisk -- target contrast up (times)
  Mod-slash    -- target contrast down (divide)

  # moveable (EPI) brightness
  up arrow -- moveable brightness up
  dn arrow -- moveable brightness down

  # fmid (basic threshold)
  Mod-b  -- toggle blur moveable
  Mod-i  -- toggle invert moveable

  # SEND/GOTO
  Mod-f  -- SEND (forward) point
  Mod-g  -- GOTO point
-------------------------------------------

Alignment Strategies

There are two basic alignment strategies for
functional data.

 Functional Scan => Surf Scan
 Functional Scan => Alignment Scan => Surf Scan

In the first, a single repetition from the
functional data set (typically t=0) is directly
registered to the high-resolution structurals
that were used to reconstruct the cortical
surface.  The difficulty with this is that the
functional contrast is low and reversed relative
to the hi-res T1's.

In the second strategy, a T1-weighted alignment
scan taken in the same plane as the functional
scans is first aligned to the hi-res structural
used to make the surface.  The resulting
transformation matrix is then copied onto the
register.dat file in the functional scan
directory.  A direct Functional => Subject
register can then be run to touch up the
alignment (or add shear--see below).

Aligning Two High-Resolution Data Sets

Register can also be used to manually align two
high resolution data sets prior to averaging, or
to quickly visually compare them:

  tkregister scan1.mgz scan2.mgz

There are many automatic algorithms to do this.
Register can be useful when the two data sets
were collected on different days with different
coverage or contrast, or with markedly different
neck, jaw, and scalp position.

Display Parameters

The default setting for "contrast" (12.0 -- up
for more contrast) increases contrast of the raw
data.  The default setting for "midpoint" (0.35,
meaning midpoint is 35% of maximum, so turn it
down to make images lighter), is designed for
images  normalized using mri_normalize.  These
affect both TARGET and MOVEABLE.

The "fmov" field adjusts the brightness of just
the MOVEABLE images, which should be adjusted to
be approximately the same as the TARGET image.

The "masktarg" button masks out the part of the
TARGET images that extend beyond the edge of the
MOVEABLE images volume.  This is typically used
for fine adjustments on data sets collected with
a surface coil where the MOVEABLE functional
images cover only a part of the brain and the
size change during COMPARE is distracting.

The unmarked entry to the left of the TARGET
button controls the rate of blinking between
TARGET and MOVEABLE when the COMPARE button is
continuously depressed (in milliseconds, minimum
is one frame per dataset, about 15 msec).

The "blurmov" check button does a 3D nearest
neighbor blur of the MOVEABLE data set at the
typically subsampled pixel resolution of the
TARGET dataset.  This takes effect with the next
COMPARE.  It will be recalculated on changing the
slice number or plane.

The "invertmov" check button inverts the contrast
of the MOVEABLE data set.  For typical EPI data,
this will make it easier to visually compare the
data sets.

The SAGMIRR button flips the chirality of the
MOVEABLE data set.  It is easiest to see the
effect of this in the HORIZONTAL or CORONAL
planes.

Tips

If the data sets are roughly aligned, a good
strategy is to adjust the MOVEABLE in coronal
view, change to sagittal and re-adjust, change to
horizontal and re-adjust, and so on -- that is,
change planes often.

It may be difficult to guess how to transform the
MOVEABLE data set if it is oriented very
differently than the TARGET data set (e.g., the
TARGET image is coronal but the MOVEABLE image
looks like a sideways horizontal slice).  A
simple strategy here is to transform the MOVEABLE
by rotating 90 degrees around a center point, and
then change to another plane.  If the MOVEABLE
still appears to be in the wrong plane, rotate 90
degrees again and change plane again.  Eventually
you will only need an in-plane rotation to
roughly align the data sets (N.B.: you can
quickly rotate 90 deg by 3 ctrl-clicks in the
left or right trough of the rotate slider).

To get a shearing transformation, use a rotation
combined with stretching.  For example, rotate 30
deg, stretch vertically, rotate back 30 deg (like
an SVD!), and finally, shrink vertically.  Don't
resort to stretching/shrinking until the data
sets are reasonably well aligned.

Format of register.dat (8 or 9 lines, ASCII)

 arthur   [name in subjects database]
 3.0      [pixel size (mm) of MOVEABLE]
 4.0      [slice thickness (mm) of MOVEABLE]
 0.2      [starting brightness of MOVEABLE]
   [transformation matrix]
 9.9915e-01  2.9973e-02 -4.6041e-02  6.5897e-02
 -5.7313e-03 -7.7659e-01 -6.2997e-01 -3.5452e+01
 5.4680e-02 -6.2928e-01  7.7525e-01 -6.6141e+00
 0.0000e+00  0.0000e+00  0.0000e+00  1.0000e+00
 round

Since the pixel size is included in the file, the
homogeneous 4x4 matrix can be directly used for
data sets with different pixel sizes.

How register.dat is used by paint.c (and others)

The linear registration matrix in register.dat
transforms a 3D surface coordinate vector to a 3D
functional data coordinate vector.  That is:

  Ax = b

where A is the 4x4 transformation matrix, x is
the surface coordinates vector, and b is the
functional data coordinates vector.

The original version of tkregister and paint
truncated the resulting floating point
coordinates of b before nearest neighbor sampling
of the moveable volume.

Newer MGH tkregister2 and bbregister round before
nearest neighbor sampling.  A register.dat file
of this kind will contain "round" on the line
following the transformation matrix (as above).

These two methods generate slightly different
transformation matrices in register.dat (they
differ by half a voxel in all 3 directions).

Csurf tkregister/paint/tkmedit/tksurfer can
automatically properly display and use *either*
kind of register.dat file.  That is, there will
be *no* off-by-half error in the surface data in
either case.  The "round" case is the default.

To manually convert between these two types of
sampling, use the F3 interface to change the
setting of the "round" checkbutton (initial state
taken from the current register.dat) adjust the
registration, and then SAVE REG.

-------------------------------------------------
 Outline C-code showing how register.dat is used
-------------------------------------------------

******************************************************/
/* paint.c: sample 3D data -> surface vtx list */

#include <math.h>

/* functional volume */
int nslices=24;     /* funct data */
int ydim=64;        /* funct data */
int xdim=64;        /* funct data */
int usethickness=1; /* use thickness (in curv)*/
float ***fim;       /* functimg vol (malloc) */
float distmm=2.0;   /* mm/frac along normal */
float distfrac=0.8; /* mm/frac along normal */

/* obtained from register.dat */
float ps;         /* inplane   register.dat:2 */
float st;         /* thickness register.dat:3 */
float tmat[4][4]; /*[row][col] register.dat:5-8*/
int roundregflag; /* sample meth: 0=trunc,1=round */

/* from reading surface */
int nvertices=130000;

typedef struct vertex_type_
{
   float  x, y, z;     /* position */
   float  nx, ny, nz;  /* curr normal */
   float  val;         /* scalar data */
   float  curv;        /* scalar data */
   /* etc */
} vertex_type;

vertex_type *vertices;

void paint_surface(void)
{
  int     k;
  int     i, j, imnr;
  float   surfx, surfy, surfz;
  float   centx, centy, centz;
  float   x, y, z;
  float   f, fydim=ydim;
  float   dist=0.0;
  vertex_type  *v;

  centx =  ps*xdim/2.0;
  centy = -st*nslices/2.0;
  centz =  ps*ydim/2.0;

  for (k=0; k<nvertices; k++) {
    v = &vertices[k];
    f = 0.0;
    if (usethickness) dist = distfrac * v->curv;
    else              dist = distmm;
    surfx = v->x + dist*v->nx;  /* along normal */
    surfy = v->y + dist*v->ny;
    surfz = v->z + dist*v->nz;
    xform(surfx,surfy,surfz,&x,&y,&z,tmat);
    if (roundregflag) {  /* new round sample */
      imnr = rint((y-centy)/st);
      i = rint(fydim-1.0-(centz-z)/ps);
      j = rint((centx-x)/ps);
    }
    else {  /* old trunc sample */
      imnr = floor((y-centy)/st);
      i = ydim-1-(centz-z)/ps;
      j = (centx-x)/ps;
    }
    if (imnr >= 0 && imnr <= nslices-1 &&
        i    >= 0 && i    <  ydim  &&
        j    >= 0 && j    <  xdim) { /*vtx in vox*/
      f = fim[imnr][ydim-1-i][j];
    }
    v->val = f;
  }
}

void xform(float x1, float y1, float z1,
   float *x2, float *y2, float *z2, float M[4][4])
{
   *x2 = x1*M[0][0]+y1*M[0][1]+z1*M[0][2]+M[0][3];
   *y2 = x1*M[1][0]+y1*M[1][1]+z1*M[1][2]+M[1][3];
   *z2 = x1*M[2][0]+y1*M[2][1]+z1*M[2][2]+M[2][3];
}
******************************************************/

Extended Interface

Several levels of interface are available by
typing the following commands while in the
interface or image window:

[fn]-F1   micro (just rotate/translate)
[fn]-F2   mini  (default, add stretching,
                 SEND/GOTO, blur, invert, mirror)
[fn]-F3   macro (add ALIGN, re-read register.dat,
                 SAVE RGB)

-------------------------------------------
 Standalone Commandline
-------------------------------------------
tkregister can also be run as a standalone
program (type "tkregister" to see full usage).

Here is the basic usage:

  tkregister <fullmovfile> <fulltargfile> req'd-opts...
  tkregister -mkdefault

 Example:

  tkregister \
    /sess/100729MS/image/1-ecc/ecc-vreg+orig.BRIK \
    /subj/martys09/mri/T1.mgz \
    -reps 256 \
    -nslices 26 \
    -imres 64 64 \
    -regdat /sess/100729MS/image/1-ecc/register.dat

However, for quick-and-dirty registration of two
*.mgz data sets, something like this will work
anywhere:

  tkregister orig1.mgz orig2.mgz

####################
tksurfer
####################

-------------------------------------------
tksurfer -- display surface & activation data
-------------------------------------------
The tcl-scriptable tksurfer program is started
either by the SURFACE button on the main csurf
panel, by the SURAFCE-STATS button on the
SessionTools -> View Functional Data panel, or
from the command line (see below).

It reads a surface file, a volume file, and
optionally, an area file, a curvature file, a
thickness file, a patch file, a label file, a
color lookup table file, and one or more
functional data overlay files, and then renders
an interactive view of the surface.  The surfer
tools panel is described from upper left to lower
right.

Context-dependent help

Every interface element (button, tick, entry,
bold label title) has a R-click help panel, which
are also all gathered in the csurf -> Help -> All
Help Contents panel.  For any button or tickbox
with multiple hotkey functions (some have up to
10), R-click help also brings up a button bar
with verbosely named buttons to control each
alternate function.

HOWTO display hi-res surface in MGH tksurfer

MGH tksurfer (now deprecated in MGH release)
requires a zero x,y,z voxelsize/spacing in the
mgz header, else it gives the error:

  "MatrixMultiply: m2 is null!."

Hi-res surfaces manually reconstructed from a
512^3 data set with csurf will have a voxel
size/spacing in the mgz header of 0.5 mm.  Use
calcimg to temporarily reset this to 0.0 to allow
MGH tksurfer to work:

  calcimg -spacing orig.mgz            # read
  calcimg -setspacing 0.0 orig.mgz   # change

Running tksurfer from a bash/tcsh shell script

N.B.: on MacOS 10.11+, the environment variable
DYLD_LIBRARY_PATH is *not* passed into a shell
script, which will prevent tksurfer from seeing
the csurf X11 tcl/tk libraries.  Therefore, to
use tksurfer in a MacOS 10.11+ shell script,
include the following line before the first call
to tksurfer:

sh/bash:
  export DYLD_LIBRARY_PATH=$CSURF_LIBRARY_PATH

csh/tcsh:
  setenv DYLD_LIBRARY_PATH $CSURF_LIBRARY_PATH

-------------------------------------------
Surface Image-Window Clicks
-------------------------------------------

(1) Select vertex, add to marked list (left-click)

   Left-click (select) on the surface selects the
   nearest vertex (defined relative to a point
   near the viewer, perpendicular to the clicked
   point) and adds it to the marked list (e.g.,
   to set up a cut).  On redraw, the vertices in
   the current marked list will appear white.  On
   a one-button Mac, a simple click is a
   left-click.

   Normally, the first vertex within 2mm of a
   perpendicular line from the screen surface to
   the cortical surface is selected.  This makes
   it hard to 'miss' a vertex.  However, in
   special cases (e.g., a 'deep canyon' in a
   highly folded cerebellar surface), this can
   end up selecting a vertex on one of the
   'canyon walls'.  To decrease the nearness
   criterion to 0.25 mm, click the "clo" button
   at the bottom middle (adjusts $selectdmax,
   N.B.: some clicks may now miss).

   This can be done in a tcl script by either:

     1) left_click <xpix> <ypix>
     2) leftclick_vertex <vertexnum>

(2) Unselect one vertex (middle-click)

   Remove a single vertex from the currently
   selected (ordered) list.

(3) Clear all selections/marks (right-click)

   Right-click (unselect/unmark) clears all the
   currently selected/marked vertices.  On a Mac
   laptop without a 3-button mouse (default
   X11.app setup), use cmd-click to get a
   right-click.  To remove a single point from
   the current list, use middle-click (opt-click
   on a one-button Mac).

   This can be done in a tcl script by:

     clear_vertex_marks_list

   If you accidentally clear a carefully-clicked
   list of selected vertices, Alt/Cmd-z will undo
   the clear and restore your selections.

(4) Rotate/Scale/Translate brain (shift click-drag)

   With shift depressed, you can rotate,
   translate, or scale the brain with a left,
   middle, or right click-drag.  N.B.: first
   focus on the brain surface window *before*
   depressing Shift (else the window can't detect
   that Shift has been pressed).  Unlike one-step
   scaling by crtl-left-click, scaling here does
   not center around the initial click point (too
   confusing).

   Can also rotate and translate from keyboard:
      Rotate -> L/R/up/down arrows
      Translate -> Shift-L/R/up/down arrows
      In-plane Rotate -> Ctrl-Shift-L/R arrows

(5) Zoom/Unzoom around point (ctrl-left/right click)

   For quick zoom, ctrl-left-click a surface
   point to zoom brain 200% around the clicked
   point.  To unzoom, use ctrl-right-click
   (ctrl-cmd-click on 1-button Mac)

(6) Dump voxel time course (ctrl-middle-click)

   If a stats overlay has been loaded and the
   current scandir also contains a raw time
   series data, a ctrl-middle-click will load the
   time series from the rawdata voxel that was
   painted onto the selected surface vertex.  The
   time series data will *not* be spatially
   smoothed (e.g., even if the surface stats have
   been smoothed).

   If the scan has been fourier-analyzed, the
   data for each stimulus cycle period (e.g.,
   eight 64 sec periods in an 8-cycle 512-sec
   scan) will be averaged and duplicated for each
   cycle in a thicker, lower-contrast line under
   the time course.  The color of the lines
   corresponds to the phase color of the stats
   at that vertex.  Note that a phase or surface
   average scandir typically *won't* contain raw
   data (a rawavg scandir *will*).

   An additional ctrl-middle-click loads a new
   single time courses.  Right-click to clear.

   N.B.: to do the same thing for all the
   vertices in a label, shift-left-click the
   "label:" line "T" button.

(7) Raise buttons interface window (double-left-click)

   A left double-click on the surface window will
   raise the tksurfer buttons interface window.

(8) Sphere img(s) val this vertex (shift-left-click)

   If surface data has been 'reverse painted'
   into a volume (used to drive multi-factor
   spherical morphing), a shift-left-click will
   sample the data voxel in which the current
   vertex resides (for sphere_morph operations).

(9) Popup name of annotation region (middle-double-click)

   If an annotation has been read onto the
   surface, a middle-double-click will popup the
   name (e.g., R_MT_ROI), rgb values (e.g.,
   31,99,108), idnum (e.g., 23), and neighbor
   count (e.g., 4).  To count neighbors,
   ctrl-mid-click "D" on the "label:" line
   (reports 0 before that).

(10) Click help (double-right-click)

   Pop-up help for all these different clicks

-------------------------------------------

Tools Interface Window Clicks

  Left-click results in the default action for a
  button, radiobutton, or tickbox in the lower
  tksurfer tools interface window.

  Right-click on any interface element pops up a
  help window for it (there are almost 200
  pop-ups).  For some of the buttons with (too
  many) overloads using key-click combinations,
  R-click help also pops up a button menu with
  all the options.

  Less-used options are overloaded on buttons,
  radiobuttons, and tickboxes as a middle-click
  or a shift-middle-click (see right-click help
  for each button).

One Button Mouse or Trackpad

  On Mac, to get a middle or right click out of a
  1-button mouse or a trackpad, open X11 ->
  Preferences -> Input (Tab), tick "Emulate 3
  button mouse", and use:

    opt-click    =>  gives middle-click
    cmd-click  =>  gives right-click

  Thus, for direct click-drag manipulation of a
  surface on a one-button Mac:

    rotate      =>  shift, then click-drag
    translate  =>  shift-opt, then click-drag
       [N.B.: req's order: 1=opt,2=click,3=shift]
    scale      =>  shift-cmd, then click-drag

  or to dump timecourses from a clicked vertex:

    ctrl-opt-click

Window Resizing

  This is best and most repeatably done by typing
  in a new window size in pixels in the "winxy:"
  entry at the lower left.  Interactive resizing
  on Mac OS X causes too many redraws (difficult
  to constrain to square window with quartz-wm).

-------------------------------------------
Keyboard shortcuts -- for both image,tk windows
-------------------------------------------

Single key

  # interface size
  F2 -- basic interface   (Mac=fn-F2)
  F3 -- large interface   (Mac=fn-F3)

  # rotate,scale brain (interface win: add Mod)
  R/L arrow      -- rotate around vert axis
  up/down arrow  -- rotate around horiz axis
  Control-Shif-R/L arrow  -- rotate in plane
  Shift-R/L arrow      -- translate right/left
  Shift-up/down arrow  -- translate up/down
  plus (+)      -- scale up 1%
  equals (=)    -- same as plus
  minus (-)     -- scale down 1%

Modifier + key (LinuxMod="Alt", MacMod="Cmd")

  # SEND/GOTO
  Mod-f  -- SEND (forward) point
  Mod-g  -- GOTO point

  # REDRAW/RESTORE
  Mod-r  -- REDRAW (usu. automatic)
  Mod-R  -- RESTORE to original view

  # stat overlay
  Mod-l  -- (el) toggle overlay stats visibility

  # surface cursor size
  Mod-k  -- toggle big cursor

  # fmid (main threshold)
  Mod-i  -- lower fmid by 0.1 (sqrtF)
  Mod-I  -- raise fmid by 0.1 (sqrtF)
  Mod-u  -- lower fmid by 10.0 (raw fourieramp)
  Mod-U  -- raise fmid by 10.0 (raw fourieramp)

  # fslope (contrast)
  Mod-s  -- lower fslope by 0.5
  Mod-S  -- raise fslope by 0.5

  # angle_offset (rotate color wheel)
  Mod-o  -- (oh) lower angle_offset by 0.01
  Mod-O  -- (oh) raise angle_offset by 0.01

  # angle_cycles (compress hemi color wheel)
  Mod-y  -- lower angle_cycles by 0.1
  Mod-Y  -- raise angle_cycles by 0.1

  # misc
  Mod-L  -- thicken isocontour lines 1 pix
  Mod-F  -- kill ongoing FILL/ROI operation
-------------------------------------------

The tksurfer interface parts are described below
in two columns, starting from the top left.

-------------------------------------------
LEFT COLUMN OF TKSURFER INTERFACE
-------------------------------------------

Top left "surf:", "tcl:" entries, GO/EDIT buttons

The currently loaded data can be displayed on a
different surface for the same hemisphere by
selecting a surface from the dropdown or entering
the surface suffix (e.g., smoothwm, inflated) in
the "surf:" entry and hitting <Return>.  This
retains the current pose (magnification,
orientation).  The "inflated" surface will be
re-loaded if a bad surface is requested.  Don't
leave an invalid surface typed in *without* a
<Return>.

If tksurfer was started with a tcl script, the
script will be shown in the "tcl:" entry field.
The GO button executes the tcl script that is
specified there (re-running a standard script
will harmlessly complain if it tries to open
another OpenGL window).  A "#" in that "tcl:"
field is used as an abbreviation for the standard
script directory:

  $CSURF_DIR/lib/tcl

The "tcl:" dropdown shows standard library
scripts (see below) as well as any
session-specific scripts saved in
$session/image/scripts.

The EDIT button opens the current script (or
creates a new empty script if the named script
doesn't yet exist) in a text editor.  This is an
easy way to get access to the tcl interpreter
from the interface: EDIT a new script file (a
relative name like "test.tcl" will go to the
scripts directory for the current session), put a
command in it, save it, click GO to run it,
re-edit and repeat.  Return values and errors
appear in a popup window.  To work intensively
with the tcl interpreter, it is more convenient
to start up tksurfer from the command line (see
below).

See "Logging Interface Actions as Tcl Commands"
below for more information on writing your own
tcl scripts.

See tksurfer right-click pop-up help for the
"tcl:" entry for detailed explanations of what
the standard movie-making scripts do (they will
be visible in the "tcl:" dropdown):

  offsetmovie.tcl
  phasemovie.tcl
  movie360.tcl
  inflatemovie.tcl
  flattenmovie.tcl

For example, phasemovie.tcl, is useful for
visualizing the details of phase contour lines in
complex-valued data.

Surface Data File Entries/Dropdowns Overview

  curv  -- curv or sulc file (every vertex)
  area  -- original area file (every vertex)
  patch -- subset of surface, maybe flattened
  label -- labeled subset of vertices w/data
  lut   -- color look-up-table (LUT): val->r,g,b
  fs    -- fieldsign and fsmask files
  val   -- value overlay file (maybe vtx subset)
  rgb   -- tiff or SGI rgb output bitmap

The formats of these files are as follows (bytes
for each file element in brackets):

 old curv (binary, 2-byte int every vertex):
   vnum[3],fnum[3],{curv*100[2]}, ...

 new curv (binary, 4-byte float every vertex):
   -1[3],vnum[4],fnum[4],npervtx[4],{curv[4]},...

 old area (binary, 4-byte float every vertex):
   vnum[3],fnum[3],{area[4]}, ...

 new area (binary, every vertex):
   [same as new curv]

 old 2-byte short patch (binary, vertex subset):
   vnum[4],{vtx[4],x*100[2],y*100[2],z*100[2]}, ..

 new 4-byte float patch (binary, vertex subset):
   -1[4],vnum[4],{vtx[4],x[4],y[4],z[4]}, ...

 label file (ASCII, vertex subset, real or cmplx):
    #!ascii label , from subject marty <CR>
    <labeled-vtx-count> <CR>
    <vnum> <x> <y> <z> <realval> [imagval] <CR>
    <vnum> <x> <y> <z> <realval> [imagval] <CR>
    ...

 lut file (ASCII, variable number of line)
    #val   red   green   blue  (comment line)
    0.0    255     0      0
    1.0     0     255     0 
    ...

 fieldsign (binary, every vertex):
   fs (fieldsign): vnum[4],{float[4]}, ...
   fm (fssigmask): vnum[4],{float[4]}, ...

 val (binary, maybe vertex subset):
   latency[2],vnum[3],{vtx[3],val[4]}, ...

The binary formats are autodetected by tksurfer,
which will also accept a new curv format file as
a val file (N.B.: unlike val files, curv files
must contain every vertex).  See Help -> Csurf
for more details and a description of surface
formats and the end of this file for machine
independent C functions that read/write
Linux/IRIX/Darwin binary compatible FreeSurfer
files that contain 4-byte float, 4-byte ints,
3-byte ints, and 2-byte ints in MSB order (most
significant byte first).

The command line program, calcvert, can be used
to convert between formats, and to dump binary
vertex-wise formats to ASCII.  To dump surface
geometry data to ASCII, use paint -dump ...
(type "paint" for details).

In all the entry fields just described, a tilde
(~) can be used as an abbreviation of the path of
the current subject directory, such as:

  /usr0/subjects/marty

and an asterisk (*) can be used as an
abbreviation of the current functional session
(sub)directory, such as:

  /usr0/sessions/040115MS/image

Surface Data Example: "curv:"

The default curvature file displayed is
"$hemi.curv" -- the local curvature -- which is
measured with respect to the immediately
neighboring vertices around each vertex.  To read
in the "sulc" file instead of the "curv" file,
select it from the dropdown.  The sulc data is
the summed perpendicular movement of each vertex
during inflation.  It is used to drive morphing,
and is closer to sulcus-vs-gyrus than curvature,
which is a strictly local measure of the one
vertex in relation to its immediate neighbors
(concave-vs-convex).  An arbitrary curvature file
can be read by entering it and clicking "R" (full
path OK, too).

Surface Data Example: "area:"

The default area file read in is "$hemi.area" --
the original vertex-wise area calculated on the
$hemi.white surface.  The dropdown may also
include $hemi.area.mid and $hemi.area.pial.  The
original area is used and reported in the log and
a popup after a FILL operation.  By contrast,
writing a new area file with "W" calculates the
vertex-wise area of the *current* surface, and
writes it out to the file in the entry (there is
a warning if you try to overwrite the original
'original area').  The area at a vertex is
defined as the sum of 1/3 the area of each
adjacent triangular face.  The "D" button
displays log areal distortion of current surface
compared to original area ($hemi.area from
$hemi.white).

Surface Data Example: "patch:"

If flat patch(es) have been generated for this
surface, their names will appear in the patch
entry dropdown.  To view the patch and any data
currently displayed, select one from the "patch:"
dropdown.  The pose of this surface will respect
settings in Preferences -> Expert Preferences ->
Views tab (if the patch infix is "occip" or
"full").  To reload a full surface, select one
from the "surf:" dropdown.

Surface Data Example: make "label:" (label+data)

The buttons on the label line are overloaded.
The default action/function is a left-click.  A
different function is called with a middle-click,
or shift-middle-click, etc.  The R-click popup
helps for the label buttons have a summary of the
default and alternate actions at the top.

A label can be generated by:

  (1) cutting and filling a region
  (2) filling to statistical threshold
  (3) selecting vertices nearest curr selection
  (4) combinations of above

(1) To generate a label by cut and fill, first
outline a region with LEFT-Clicks (N.B.: cuts
done in order of clicks!) and use AREA to cut,
and then FILL to select it so that only the
labeled part is visible.  FILL respects cuts, but
also any any other currently displayed (D'd)
label (e.g., to make adjoining labels).

(2) To select a connected region based on the
current stats overlay up to the currently set
"fthresh", and use ROI.  Disconnected regions can
be combined into one label file by clicking
multiple points before clicking ROI.  This
respects cuts and other currently D'd labels.

(3) Finally, a label can be generated that
contains vertices nearest (in Euclidean distance
on current surface) to the currently selected
vertex.  The total number of vertices is
specified by either number ("N" button, entry
specifies vertex count), by area ("A", entry
specifies sq mm), or by radius ("R" button, entry
specifies mm).  See right-click help for those
buttons for more details.

Select a name for the label file and write it
with "W".  This saves the label location as well
as any currently displayed real or complex-valued
overlay data (it ignores D'd labels).  To undo
all cuts, use "INIT" (lower right).

Surface Data Example: display "label:" (label location)

To display just the location of the label, use
"D", which shows label as a transparent overlay
(transparency adjustable with "tran").  This uses
only the vertex numbers in the label file (vertex
x,y,z and value are ignored).  To toggle labels
display, use checkbutton to left of "label:".  To
clear all displayed labels, use "CLR".  The
tickbox is overloaded (e.g., shift-middle-click
to toggle viewing only label borders vs. filled
in labels).

Surface Data Example: display "label:" (MGH annotation)

The "D" button can also read an MGH annotation
file (e.g., rh.HCP-MMP1.annot) that contains
multiple labels and corresponding colors and ID
numbers (but no data).

Surface Data Example: find overlap of "label:" (2+)

To generate a new label from the overlap of two
(or more) labels, display and re-cut a first
label with "C", then display and re-cut a second
label (or a third, etc) with "C".  The end
result, which can be saved with "W", is just the
overlap.

Surface Data Example: use "label:" (label+data)

The "R" button reads *the data* in a label file
(real or complex -- last or two last entries each
line) into the val (and if complex, val2) vertex
field(s).  The adjoining "RC" button is similar,
but reads the label data and also re-cuts the
label (e.g., for re-edit or re-save with
different overlay data).  To completely clear the
*data* read in from one or more labels, use "CLR"
on the "val:" line.

The "T" button uses the current label to extract
the raw timecourse data (via register.dat,
assuming a rawdata file has been specified with
-rawdata) into an ASCII file in the current
scandir (these arguments are automatically given
to tksurfer if it is run from SessionTools ->
View Functional Data).

The "S" button performs the same operation as the
"T" button but also includes samples of 3D volume
stats file (possibly complex-valued) in the ASCII
output file (immediately before the timecourse).
See the right-click popup help for the S and T
buttons for more detals.

Left-click "label:" to get a "NormSamp (PAINT),
Cluster Filter Controls" pop-up for interactively
controlling the details of the norm search
(search along the normal at each surface vertex)
parameters for the "S" and "T" buttons.  These
parameters will be preset according to last saved
values in csurf SessionTools -> Setup Align/Funct
Scan panel for this scandir.  The 15 controls on
this panel are:

Ticks/Flags:

  normdsampsearchflag -- toggle search (else 1pnt)
  normdsampuniqvoxflag -- sample each *funct* vox once
  normdsampallflag -- dump full timecourse for each depth

  normdfracflag -- ON=thicknessfraction, OFF=mm
  bokflag -- modulate thickness depth frac by curvature

Numerical parameters:

  normdsamp -- 1pnt samp depth, or min depth (mm)
  normdmax -- max samp depth (mm) (1pnt:same as prev)

  normdfracsamp -- 1 samp depth, or min depth (fraction)
  normdfracmax -- max depth (fraction) (1pnt:same as prev)

  normddstep -- mm or depth fraction
  normdop -- operation on samples (0=max,1=avg,2=min)

  preclustfthr -- hard F thresh before surfclust
  clustarea -- min surfclust area to survive filter

  sulfrac -- strength of sulc Bok correction (-0.12)
  gyrfrac -- strength of gyrus Bok correction (0.16)

Here is how the Bok-like layer depth correction
is implemented (outline C-code) for the sampling
along the normal at one vertex:

/******************************************************/
for (dist=min; dist<=max; dist+=normddstep) {
  dist2 = dist;
  if (bokflag) { /*cosfunct: inp:0-1 out:0->1->0*/
    if (curv>0.0)
      dist2 += curv/curvmax * sulfrac*thickness *
              -cos(M_PI*dist/thickness + 0.5*M_PI);
    else
      dist2 += curv/curvmin * gyrfrac*thickness *
              -cos(M_PI*dist/thickness + 0.5*M_PI);
  }
  /* sample at dist2 up on normal to this vertex */
}
/******************************************************/

The "X" button uses the current label to define a
region over which to calculate the Pearson
correlation (or circular correlation) between two
vertexwise data sets for a set of searchlights
that each include nearest neighbors extending to
a radius defined by simple vertex count, surface
area (mm^2), or radius (mm).  See the "X"
right-click help for details on how to load the
two data sets.

Surface Data Example: "lut:" (color lookup table)

If activation overlay data is currently
displayed, you can dump out the current color
look up table as an ASCII file to the filename in
the "lut:" entry with the nearby "W" button.
"ED" can be used to edit the file, and "R" can be
used to re-read the edited file.  Each line in
the color look up table (LUT) maps data in the
val field of each vertex to r,g,b colors (0-255
for each color), interpolating intermediate value
(interpolation can be turned off with "intplut").
For real data, the first column is val; for
complex data, the first column is phase angle
where 0 -> 2Pi is 0.0 to 1.0 (the color scale
wraps around in this case).

Surface Data Example: "fs:" (fieldsign)

The fieldsign and fieldsign mask files are
automatically generated using the SessionTools ->
Calculate Visual Fieldsign panel.  Gradients (on
curvature, real, or complex data) and fieldsign
can be manually read, written, and calculated
with the "R", "W", "F" (fieldsign) and "GR"
(gradient) buttons.  See R-click popup help for
each button for details.

Surface Data Example: "val:" (vertex value)

Value files (*.w files) are generated when PAINT
is clicked on several different panels.  They may
be real or complex.  Use the "val:" CLR to clear
the value field (both real and imaginary) to 0.
Any value file with a *.w suffix will be
selectable from the dropdown.  Use "R" to read
the file.  By default, the file is assumed to be
real-valued.  If the file contains an infix
indicating it is complex-valued (_r,_i, or
_x,_y), both members of the pair will be read
(whichever is selected).

Finally, optionally smooth real or complex data
with SMOOTH.  This sequence of actions is
typically performed by the standard scripts that
read complex data such as polar-views.tcl.  To
save the smoothed data, use "W" (usu. better to
resmooth).

The "S/V" button on the "val:" line swaps the
values at the stat and val fields at each vertex.
To read in a data file and mask it with a
statistics file, first enter the stat file name
and click "R", then click "S/V", then enter the
val file name (real or complex) and click "R"
again.

Surface Data Example: "rgb:"

This field saves a bitmap of the current view, by
default a tiff.  To get a classic SGI rgb file,
unlick the check just to the left of WRITE, or
unclick Preferences -> Save .tiff in csurf and
restart tksurfer.

On Linux/IRIX, when WRITE'ing an rgb file, make
sure that the surfer display window must be
completely onscreen.  Partly offscreen is OK
w/Darwin.

The window will be raised to the front
immediately before saving to avoid capturing
overlapping windows.  The mouse cursor is
ignored.  To preserve cyan vertex selections, use
"W", which doesn't raise or redraw first (in that
case, be sure the window is in front of other
windows before saving).

Logs

Clicking on a vertex displays some of the data
associated with it, either at the tcl prompt if
tksurfer was started from the command line, or in
the csurf window, if Preferences -> View Logs is
clicked.  See also Preferences -> Bigger Logs.

Note that after surfer tools operations, these
values may differ from what was read in from from
curv/sulc and *.w files.  For example, smoothing
changes the real (and imaginary) values, while
curvature is typically slightly changed when it
is rescaled to half convex and half concave.

For complex-valued data, the log reports (among
other things):

  val   => real stat value (top pos data stack)
  val2  => imaginary stat value (2nd pos stack)
  amp   => amplitude   -- hypot(val,val2)
  angle => phase angle -- atan2(val2,val)=>deg

Logging Interface Actions as Tcl Commands

Clicking the "tcl:" label near the top left of
the tksurfer interface turns on the logging of
all interface actions as tcl commands to the
file, tksurfer.log, in:

  $FUNCTIONALS_DIR/<session>/image/scripts

These can be used to record actions to make a
command line tcl script to automate tksurfer
actions.  The "tcl:" label turns bold during
logging.  To finish logging, click the label
again.  Or you can startup tksurfer from csurf
with the log on by selecting

  Preferences -> Log tksurfer actions as tcl cmds

Note that in both cases, any previous log of tcl
commands in tksurfer.log in this session's script
dir is overwritten so each log starts fresh.

ROTATE/TRANSLATE/SCALE Sliders

  ROTATE
    horizontal slider -- rotate around vertical
    vertical slider -- rotate around horizontal
    yrot field -- rotate around y axis (deg)
    xrot field -- rotate around x axis (deg)
    zrot field -- rotate around z axis (deg)

  TRANSLATE
    horizontal slider -- translate left-right 
    vertical slider   -- translate up-down
    x field -- translate in x axis
    y field -- translate in y axis

  SCALE
    vertical slider -- scale larger-smaller
    % field -- scale in percent

Clicking in the trough on either side of the
slider makes a small movement (one unit).  A
ctrl-click in the trough moves all the way to the
end of the scale (e.g., to quickly do a 180
flip).

The pose can be more quickly changed by direct
manipulation (Shift-click drag).

The "winxy:" entry in the ROTATE panel can be use
to change/return the display window to a known
size (default startup size: 600x600 pixels).  It
can't be larger than the current screen.  See
R-click help to the "rgb:" entry for instructions
on how to render very high resolution bitmaps
offscreen.

Use the "Save" button (inside the TRANSLATE
panel) to save one particular pose, which can be
restored at any time with the "Goto" button.  The
previous saved pose is overwritten with each new
"Save".  Middle-click "Save/Goto" to add a
suffix.  Click "View" to see currently saved.

The DIST button in the TRANSLATE panel calculates
the Euclidean distance between the last 2 clicks
on the surface and displays the result in the
log.  The "Dijk" button calculates a geodesic
distance and generates a label of the path.

The "isocont" tick below the DIST button reads
$hemi.sphere.reg (if there) in order to display
isocontours of canonical spherical coordinates on
top of any current data (Right-click on "isocont"
to get more details).

-------------------------------------------
RIGHT COLUMN OF TKSURFER INTERFACE
-------------------------------------------

REDRAW/RESTORE/SEND/GOTO [F3: FlipHemi]

The REDRAW button manually redraws the screen.
This is rarely needed now, since most interface
changes do an auto-redraw on clicking a button or
hitting Return after adjusting a value in an
entry.  Alternate clicks on REDRAW (middle- and
shift-middle) display divergent or convergent
stereo (plain left-click REDRAW to undo either).

RESTORE reestablishes the original, lateral
viewing orientation and scale (it is easy to get
lost after several non-orthogonal rotations).  An
alternate click re-calculates center.

SEND saves the coordinates of a surface point in
a file that can be read by tkmedit GOTO in order
to display the 3D slice position of that vertex.
The folded surface position of the vertex is used
(regardless of which surface is being viewed).

GOTO finds the nearest (Euclidian distance)
surface point to the last point that was saved by
a SEND or SEND PNT in surfer tools, medit tools,
or tkregister.  This can be used in tksurfer to
return to a vertex on the same (or different)
surface.

FlipHemi (F3 interface) fixes surface read from
software that uses a left-handed coordinate
system (e.g., Brain Voyager).

Note that the GOTO operation is not equivalent
for surface (2D) and volume (3D) data sets.  Any
surface point can always be located (to within a
voxel) in a volume data set; however, a point
selected in a volume often lies outside of the
corresponding cortical surface, so a search must
be performed.  This can lead to counterintuitive
results.  For example, assume you are displaying
the right hemisphere surface.  If a volume point
is accidentally selected in the opposite (left)
hemisphere of a 3D data set, and you GOTO that
point on the surface the nearest (Euclidean)
surface point will typically lie somewhere on the
midline, and will not even be visible in lateral
view.

Colors: ("Col:")

If "curv" is unticked, the curvature dataset is
not displayed.  The default is ticked.  If
curvature is displayed without an overlay, it is
represented using red and green.  When curvature
is displayed under activations ("overlay"
checked), curvature is represented as two shades
of gray.  The overall brightness of the
dark/light gray background can be controlled with
the first entry to the right of "curv" (variable:
offset, default=0.30).  The second entry controls
the contrast between the two shades of gray
(variable: cvfact, default=1.30).

"intp", "bot", and "sym" ticks

These control how the entries in a color look up
table (LUT) are interpreted:

  intp -- interpolate between entries
  bot  -- entry specifies bottom (not center)
  sym  -- thresh cuts in symmetrically around 0

Color Scales: ("w1", "ht", etc radio buttons)

  w1  -- color wheel (complex data, pol or ecc)
  ht  -- heat (brown->white, complex amplitude)
  bi  -- red/grn (complex data, sign from phase)
  BRy -- blue/red/yellow (signed real data)
  BR  -- blue/red/white (signed real data)
  lt  -- color look up table ($val2rgblut)
  fs  -- fieldsign ($hemi.fs masked by $hemi.fm)

For much more detail on the behavior of these
different color scales, see SessionTools -> View
Functional Data or their R-click help popups.
Left-click "Col:" to get a more verbose
radiobutton popup with all the color scales (all
have R-click help).

MESH and "rect","cm" Buttons

MESH toggles between viewing and not viewing the
vertices and edges of each polygon in the
surface.  The mesh is too dense to resolve unless
the brain is first SCALE'ed up.  The r/g/b fields
can set the color of the mesh.  Update mesh color
by changing r/g/b and typing Return.

The r/g/b fields are also used to specify what
color a label will be be displayed with.  To
change the color of a label, reset r/g/b and
re-display the label with "D".

The "rect" button toggles between a rectangular
and circular display of different phases in the
color disk inset at the lower right (only
relevant for the color disk, which is displayed
with complex-valued color scales).  The circular
display is more familiar; the rectangular display
also illustrates the effects of changing fthresh
and fmid.  With polar angle data (non-integral
angle_cycles), only 180 deg of phase are
displayed.  A third click toggles off the inset.

The "cm" button toggles the visibility of both:
(1) the color disk inset if complex (or vertical
colorbar if non-complex) and (2) a 1 cm
horizontal gray scale bar at the lower right.

Display Parameters (middle part of tksurfer right column)

Left SubColumn Ticks and "fthresh:" Entry Field

 truncphase -- only display positive values
   => phase limits settable if complex-valued
 invphase   -- reverse positive/negative values 
 ovlay      -- display functional data (gray curv)
 cpx        -- complex-valued data (usu. autoset)
 mask       -- mask amplitude data by stat
 mult       -- multiply amp data by stat
 fthresh -- hard stat thresh (stat values under
              this value display underlying gray
              curvature instead)

Middle SubColumn Box -- phase contours

Ticking "phc" displays isophase contours whose
number and width are controlled with the "n" and
"w" entries immediately below.  The sharp edge of
each phasecontour points in the direction of the
phase gradient (steepest uphill direction).

The unmarked tick and entry at the bottom of this
box control gradient arrow displays (see R-click
help for "GR" button).

Right SubColumn Entry Fields

 fslope -- contrast (steepness sigmoid, or double
             sigmoid steepness w/2-ended scales)
 fmid   -- set where sigmoid changes fastest (use
              this to set effective threshold
              but avoid truncation edges)
 cslope -- contrast of R/G curvature colorscale
 cmid   -- midpoint of R/G curvature colorscale
 iy     -- ipsiyellowfact (0-1) for polar angle
 fad    -- fadef (~0.7) ipsi fade for polar angle
 anglecycles -- complex: eccen=1.0, polar ~2.2
 rev    -- reverse time axis (complex data)
 angleoffset -- complex: 0-1 => phaseangle 0-2pi

If "mask" is ticked (and a statistical mask has
be read in), the fthresh (hard thresh), fslope
(contrast), and fmid (soft thresh) fields are
each doubled.  The first set in each pair uses
the amplitude (e.g., cut out vertices with low
amplitudes) and the second set uses the
statistical mask (e.g., cut out vertices with low
statistic).

For more detail on the meaning of these fields as
a function of different color scales, see
SessionTools -> View Functional Data.

Surface Cut/Fill/Roi Operations

  AREA -- closed-line cut using most recent
             list of LEFT-CLICK'd points
  FILL -- fill region selected by single
            LEFT-CLICK, then delete unfilled
  PLANE -- 3 LEFT-CLICK's define plane, 4th
                indicates which side to keep  
  LINE -- open-line cut using most recent
               list of LEFT-CLICK'd points
  ROI -- fill connected region with val above
            fthresh (complex->use complex amp)
  N -- select <n> vertices closest to curr click
  A -- select nearest vertices up to area (sqmm)
  R -- select nearest vertices up to radius (mm)
  UNDO -- undo most recent cut
  INIT -- reset surface to initial state read in
  ALL -- undo all cuts, even initially read

Once an operation has been performed, the current
list of selected/marked points is cleared in
preparation for the next operation.  You can
clear the marked list at any time with a
right-click.  Click "erode" to make FILL perform
an eroding fill (see FILL right-click help for
more details).

Data and Curvature Smoothing

The SMOOTH button performs the requested number
of nearest-neighbor smoothing steps on either the
curvature ("cv") or the data on the top of the
value stack ("val") if real, or on both real and
imaginary components if complex.  The approximate
mapping from smoothing steps to full width at
half max 2D Gaussian filter is:

   5 steps => 2.2 mm FWHM
  10 steps => 3.2 mm FWHM
  20 steps => 4.5 mm FWHM

Because this is a 2D filter, a given kernel size
will result in less smoothing than a 3D kernel of
the same size.

Two additional rarely used smoothing types are:
"w" (weighted), which uses $halfweightdist
(0.5*FWHM), the distance in mm where the Gaussian
weight drops to 0.5, and "sp" (sparse), which
ignores vertices without data and interpolates
across them at the 'speed of light' (one vertex
per smoothstep, which will have no effect on full
rank data).

See Help -> View Functional Data for more details
on smoothing (also, right-click help for these
radio buttons).

Finally, alternate middle and shift-middle clicks
on the SMOOTH button make popups to control
searchlight smoothing operations (C/tcl funct
searchlightop_val2stat) and and the generation of
non-overlapping 'paintball' regions (C/tcl funct
neighop_val2stat).

-------------------------------------------
 Standalone Commandline and Script Operation
-------------------------------------------
tksurfer can also be run as a standalone program
from the command line (as long as SUBJECTS_DIR and
FUNCTIONALS_DIR are set):

Use: [disp surf w/curvature and/or stats overlay]

 tksurfer [+]name hemi surf [-tcl script] [-opts]
 tksurfer -help,-h ["help" at prompt, R-click item]

  name:   subject (+ prefix => read T1.[mgz])
  hemi:   lh, rh
  surf:   orig,smoothwm,inflated,sphere,sphere.reg
  tclscript:  first local, then $CSURF_DIR/lib/tcl

The program has an embedded tcl interpreter and
most of its C functions (including some not
exposed to the surfer tools interface) can be
accessed through it, either interactively at the
tcl prompt, %, that appears in the terminal from
which tksurfer is started, or offline using a tcl
script in a file whose name follows the -tcl
option.  If you include an "exit" at the end of
the tcl script, tksurfer will quit when the
script finishes.  You can find commands available
in the tcl interpreter using "help":

  % help

which also lists settable variables and commands.
To find tcl variables and commands, use:

  % info vars
  % info commands

Set the value of a variable like this:

  % set cslope 5.0

To find the current value, omit the value

  % set cslope
  3.0

You can also search for commands by pattern
matching:

  % info command rotate*
  rotate_brain_x rotate_brain_y rotate_brain_z

Commands have some minimal error checking/usage:

  % rotate_brain_y
  Wrong # args: rotate_brain_y <deg>

Unix shell commands can be executed directly from
the tcl prompt (but to get csh-style globbing,
you have to do it explicitly):

  % cd /tmp
  % ls -al
  % eval ls -al [glob *.rgb]

Here is an example of a small command line tcl
script that reads in a surface, and then saves 90
bitmap images of the brain, each one rotated 4
degrees around the vertical axis from the
previous image (i.e., a rotating brain movie).

open_window
make_lateral_view
read_binary_curv
set cslope 5.0
set i 0
while {$i < 90} {
  redraw
  set rgb /tmp/brain-[format "%03d" $i].tiff
  save_rgb
  incr i
  rotate_brain_y 4
}
exit

You could either paste the script into the
tcl prompt or put the commands in a file,
rotbrain.tcl, run it like this:

  tksurfer john rh smoothwm -tcl rotbrain.tcl

Finally, you could also execute the script from
the surfer tools interface by entering its name
in the "tcl:" entry and clicking "GO".  The name
in the entry can be: (1) the full pathname to the
script, (2) if the script is put in the scripts
dir of the current session, just its relative
name, or (3), if the script has been put in the
standard scripts directory, using a "#" as an
abbreviation for the standard scripts dir.

-------------------------------------------
 C-code for machine-independent MSB read/write
-------------------------------------------

/*** global */
#ifdef Darwin
int LSBfirst = 1;   /* runtime endian flag */
#endif

/*32bit: int=4, long=4, long long=8, float=4, double=8*/
/*64bit: int=4, long=8, long long=8, float=4, double=8*/

/*** typdefs */
typedef union
{
  short  s;
  char   buf[sizeof(short)];
} SWAP_SHORT;

typedef union
{
  float  f;
  int    i;
  unsigned int  ui;
  char   buf[4];
  short  s[2];
} SWAP_FLOATINT;

/*** function declarations */
void setdarwinbyteorder(void);
short swapShort(short s);
int swapInt(int i);
unsigned int swapUInt(unsigned int ui);
long long swapLong(long long l);
float swapFloat(float f);
double swapDouble(double d);
int fread1(int *v, FILE *fp);
int fread2(int *v, FILE *fp);
int fread3(int *v, FILE *fp);
int fread4(float *v, FILE *fp);
short freadShort(FILE *fp);
int freadInt(FILE *fp);
unsigned int freadUInt(FILE *fp);
long long freadLong(FILE *fp);
float freadFloat(FILE *fp);
double freadDouble(FILE *fp);
int fwrite2(int v, FILE *fp);
int fwrite3(int v, FILE *fp);
int fwrite4(float v, FILE *fp);
int fwriteShort(short s, FILE *fp);
int fwriteInt(int v, FILE *fp);
int fwriteLong(long long v, FILE *fp);
int fwriteFloat(float f, FILE *fp);
int fwriteDouble(double d, FILE *fp);

/*** functions */
void setdarwinbyteorder(void)
{
#ifdef Darwin  /* else no-op */
  const NXArchInfo *archinfo;

  archinfo = NXGetLocalArchInfo();
  if (archinfo->byteorder==NX_BigEndian)
    LSBfirst = 0;
  else if (archinfo->byteorder==NX_LittleEndian)
    LSBfirst = 1;
  else {printf("### NXGetLocalArchInfo fail\n");}
#endif
}

short swapShort(short s)
{
  char        c;
  SWAP_SHORT  ss;

  ss.s = s;
  c = ss.buf[0];
  ss.buf[0] = ss.buf[1];
  ss.buf[1] = c;

  return(ss.s);
}

int swapInt(int i)
{
  short          s;
  SWAP_FLOATINT  sfi;

  sfi.i = i;
  sfi.s[0] = swapShort(sfi.s[0]);
  sfi.s[1] = swapShort(sfi.s[1]);
  s = sfi.s[0];
  sfi.s[0] = sfi.s[1];
  sfi.s[1] = s;
 
  return(sfi.i) ;
}

unsigned int swapUInt(unsigned int ui)
{
  short          s;
  SWAP_FLOATINT  sfi;
 
  sfi.ui = ui;
  sfi.s[0] = swapShort(sfi.s[0]);
  sfi.s[1] = swapShort(sfi.s[1]);
  s = sfi.s[0];
  sfi.s[0] = sfi.s[1];
  sfi.s[1] = s;

  return(sfi.ui);
}

long long swapLong(long long l)
{
  char    *pVar=(char *)(&l);
  char    tmp;
  size_t  typeSize=sizeof(long long);
  size_t  i;
  long long  w;  /*double  w;*/

  for (i=0; i<typeSize/2; ++i) {
    tmp = *(pVar + 2*i);
    *(pVar + 2*i) = *(pVar + typeSize - 1 - 2*i);
    *(pVar + typeSize - 1 - 2*i) = tmp;
  }
  w = *((long long *)(pVar));
  return w;
}

float swapFloat(float f)
{
  short          s;
  SWAP_FLOATINT  sfi;

  sfi.f = f;
  sfi.s[0] = swapShort(sfi.s[0]);
  sfi.s[1] = swapShort(sfi.s[1]);
  s = sfi.s[0];
  sfi.s[0] = sfi.s[1];
  sfi.s[1] = s;

  return(sfi.f);
}

double swapDouble(double d)
{
  char    *pVar=(char *)(&d);
  char    tmp;
  size_t  typeSize=sizeof(double);
  size_t  i;
  double  w;

  for (i=0; i<typeSize/2; ++i) {
    tmp = *(pVar + 2*i);
    *(pVar + 2*i) = *(pVar + typeSize - 1 - 2*i);
    *(pVar + typeSize - 1 - 2*i) = tmp;
  }
  w = *((double *)(pVar));
  return w;
}

{
  unsigned char  c;
  int            ret;

  ret = fread(&c,1,1,fp);
  *v = c;
  return(ret);
}

int fread2(int *v, FILE *fp)  /* short */
{
  short  s;
  int    ret ;

  ret = fread(&s,2,1,fp);
#ifdef Linux
  s = swapShort(s);
#endif
#ifdef Darwin
  if (LSBfirst) s = swapShort(s);
#endif
  *v = s;
  return(ret);
}

int fread3(int *v, FILE *fp)  /* unsigned int */
{
  unsigned int  i=0;
  int           ret;

  ret = fread(&i,3,1,fp);
#ifdef Linux
  i = (unsigned int)swapInt(i);
#endif
#ifdef Darwin
  if (LSBfirst) i = (unsigned int)swapInt(i);
#endif
  *v = ((i>>8) & 0xffffff);
  return(ret) ;
}

int fread4(float *v, FILE *fp)  /* float */
{
  int    ret;
  float  f;

  ret = fread(&f,4,1,fp);
#ifdef Linux
  f = swapFloat(f);
#endif
#ifdef Darwin
  if (LSBfirst) f = swapFloat(f);
#endif
  *v = f;
  return(ret);
}

short freadShort(FILE *fp)
{
  int    nread;
  short  s;

  nread = fread(&s,sizeof(short),1,fp);
#ifdef Linux
  s = swapShort(s);
#endif
#ifdef Darwin
  if (LSBfirst) s = swapShort(s);
#endif
  return(s);
}

int freadInt(FILE *fp)
{
  int  i, nread;

  nread = fread(&i,sizeof(int),1,fp);
#ifdef Linux
  i = swapInt(i) ;
#endif
#ifdef Darwin
  if (LSBfirst) i = swapInt(i);
#endif
  return(i);
}

unsigned int freadUInt(FILE *fp)
{
  unsigned int  i;
  int           nread;

  nread = fread(&i,sizeof(int),1,fp);
#ifdef Linux
  i = swapUInt(i);
#endif
#ifdef Darwin
  if (LSBfirst) i = swapUInt(i);
#endif
  return(i);
}

long long freadLong(FILE *fp)
{
  int        nread;
  long long  i;

  nread = fread(&i,sizeof(long long),1,fp);
#ifdef Linux
  i = swapLong(i);
#endif
#ifdef Darwin
  if (LSBfirst) i = swapLong(i);
#endif
  return(i);
}

float freadFloat(FILE *fp)
{
  float  f;
  int    ret;

  ret = fread(&f,4,1,fp);
#ifdef Linux
  f = swapFloat(f);
#endif
#ifdef Darwin
  if (LSBfirst) f = swapFloat(f);
#endif
  return(f);
}

double freadDouble(FILE *fp)
{
  int     ret;
  double  d;

  ret = fread(&d,sizeof(double),1,fp);
#ifdef Linux
  d = swapDouble(d);
#endif
#ifdef Darwin
  if (LSBfirst) d = swapDouble(d);
#endif
  return(d);
}

int fwrite2(int v, FILE *fp)  /* short */
{
  short  s;

  if (v > 0x7fff)    /* don't let it overflow */
    v = 0x7fff;
  else if (v < -0x7fff)
    v = -0x7fff;
  s = (short)v;
#ifdef Linux
  s = swapShort(s);
#endif
#ifdef Darwin
  if (LSBfirst) s = swapShort(s);
#endif
  return(fwrite(&s,2,1,fp));
}

int fwrite3(int v, FILE *fp)  /* unsigned int */
{
  unsigned int  i=(unsigned int)(v<<8);

#ifdef Linux
  i = (unsigned int)swapInt(i) ;
#endif
#ifdef Darwin
  if (LSBfirst) i = (unsigned int)swapInt(i) ;
#endif
  return(fwrite(&i,3,1,fp));
}

int fwrite4(float v, FILE *fp)  /* float */
{
#ifdef Linux
  v = swapFloat(v);
#endif
#ifdef Darwin
  if (LSBfirst) v = swapFloat(v);
#endif
  return(fwrite(&v,4,1,fp));
}

int fwriteShort(short s, FILE *fp)
{
#ifdef Linux
  s = swapShort(s);
#endif
#ifdef Darwin
  if (LSBfirst) s = swapShort(s);
#endif
  return(fwrite(&s,sizeof(short),1,fp));
}

int fwriteInt(int v, FILE *fp)
{
#ifdef Linux
  v = swapInt(v);
#endif
#ifdef Darwin
  if (LSBfirst) v = swapInt(v);
#endif
  return(fwrite(&v,sizeof(int),1,fp));
}

int fwriteLong(long long v, FILE *fp)
{
#ifdef Linux
  v = swapLong(v);
#endif
#ifdef Darwin
  if (LSBfirst) v = swapLong(v);
#endif
  return(fwrite(&v,sizeof(long long),1,fp));
}

int fwriteFloat(float f, FILE *fp)
{
#ifdef Linux
  f = swapFloat(f);
#endif
#ifdef Darwin
  if (LSBfirst) f = swapFloat(f);
#endif
  return(fwrite(&f,sizeof(float),1,fp));
}

int fwriteDouble(double d, FILE *fp)
{
#ifdef Linux
  d = swapDouble(d);
#endif
#ifdef Darwin
  if (LSBfirst) d = swapDouble(d);
#endif
  return(fwrite(&d,sizeof(double),1,fp));
}

####################
tkstrip
####################

------------------------------------------
 tkstrip -- interactively strip skull
------------------------------------------
Tkstrip reads a volume data set and attempts to
strip the skull off of it.  This can be started
from csurf for the currently selected volume data
set with shift-middle-click on the VOLUME button.

The basic usage is:

    tkstrip <subj> <somevol.mgz>

The primary output is another skull-stripped 3D
dataset, which can be a different data set than
the one used to find the skull.  The stripping
surface and tiffs of it can also be saved.

N.B.: on MacOS 10.11+, the environment variable 
DYLD_LIBRARY_PATH is not passed into a shell
script, which will prevent tkstrip from seeing
the csurf X11 tcl/tk libraries.  To use tkstrip 
in a MacOS 10.11+ shell script, include the
following line before the first call to tkstrip:

csh/tcsh:
  setenv DYLD_LIBRARY_PATH $CSURF_LIBRARY_PATH

sh/bash:
  export DYLD_LIBRARY_PATH=$CSURF_LIBRARY_PATH

-------------------------------------------
 Keyboard shortcuts -- for both image,tk windows
-------------------------------------------
  # rotate view of surf (interface win: add Mod)
  R/L arrow      -- rotate around vert axis
  up/down arrow  -- rotate around horiz axis
  Shift-R/L arrow      -- translate right/left
  Shift-up/down arrow  -- translate up/down
-------------------------------------------

Main parameters

 -fzero <0-255>  (40) norm MRIforce=0 this val (lo->plump)
 -fmax <0-255> (130)sm1:if MRI>fmax,inforce=0(hi->plump)
 -dfrac <0.1-2.0>  (0.7) start ellipsoid rel to avg MRI radius
 -istilt <mm>         (1.0) inside stilt
 -fsteepness <0.1-8>   (0.5) steepness MRI->force sigmoid
 -fstrength <~1>     (1.0) sm4 only: scale pnt-force tanh
 -flattenflag <0,1>  (0) smooth surface
 -momentumflag <0,1>   (1) add fraction of previous move 
 -update <frac>  (0.9) update:d{x,y,z} += update*d{x,y,z}
 -decay <frac>  (0.9) momentum:d{x,y,z} += decay*m{x,y,z}

Shrinkmodes (where to sample along vertex normal)

 -shrinkmode <1,3,4>  (def=1)
     1 = samp-in/out
     3 = samp-out
     4 = samp-pnt

Built-in scripts

---------------------------------------------------------------
action mode insurf     outsurf       outim         dat (cwd)
---------------------------------------------------------------
   0  ===> default=0: *don't* run a builtin script <====
   1     1     ic4.tri     brain.tri         brain        brain.dat
   2     4     ic4.tri  inner_skull.tri    [none]    inner_skull.dat
   3     3     ic4.tri  outer_skull.tri    [none]    outer_skull.dat
   4     4     ic4.tri   outer_skin.tri    [none]    outer_skin.dat
   5     4     ic4.tri   brainPD.tri          tmp           [none]
   6     4     ic4.tri   brainPD.tri          tmp           [none]
---------------------------------------------------------------
N.B.: for action=6, after shrink on inim, reads orig.mgz to strip it

Basic usage:

 tkstrip subj CORdir/mgzfile [-action <n>] [-tcl script] [-opt..]

Simple examples:

 tkstrip marty T1.mgz            (interactive)
 tkstrip marty T1.mgz -action 5  (strip to tmp.mgz)

How to strip noise in air from quantitative T1 image

Quantitative T1/PD images contain noise in the
air because, roughly, two extremely small noisy
signals are being divided by each other.  To
strip this noise from an quantitative T1 image
named orig.mgz, use one of the raw T1- or
PD-weighted input images with action-6, or
interactively as follows (pd.mgz in example
below):

  startup interface:

    tktrip marty pd.mpg

  [interactive commands follow]
  use finer insurf: -> ic5.tri, READ
  tick ACTION "outskin"
  reduce istilt: 3.0 -> 0.0
  click "SCALE SURF TO MRI"
  click "SHRINK"
  change inmri: ~/mri/pd.mgz => ~/mri/orig.mgz
  click "PEEL"
  
This will strip the noise off of the quantititive
T1 image, orig.mgz, overwriting the original
image (first save original aside if desired).

---------------------------------------------------------------
C-code for actions
---------------------------------------------------------------
/** file,parm defaults for built-ins: before read data files */
if (action==1) {
  shrinkmode = 1;
  sprintf(dfname,"brain.dat");
  sprintf(gfname,"%s/lib/bem/ic4.tri",csurfdir);
  sprintf(ofname,"%s/%s/surf/brain.tri",
    lsubjectsdir,lpname);
  if (!outimoptflag)
    sprintf(bfname,"%s/%s/mri/brain",lsubjectsdir,lpname);
}
else if (action==2) {
  shrinkmode = 4;
  sprintf(dfname,"inner_skull.dat");
  sprintf(gfname,"%s/lib/bem/ic4.tri",csurfdir);
  sprintf(ofname,"%s/%s/surf/inner_skull.tri",
    lsubjectsdir,lpname);
  if (!outimoptflag)
    sprintf(bfname,"%s/%s/mri/tmp",lsubjectsdir,lpname);
}
else if (action==3) {
  shrinkmode = 3;
  sprintf(dfname,"outer_skull.dat");
  sprintf(gfname,"%s/%s/surf/inner_skull.tri",
    lsubjectsdir,lpname);
  sprintf(ofname,"%s/%s/surf/outer_skull.tri",
    lsubjectsdir,lpname);
  if (!outimoptflag)
    sprintf(bfname,"%s/%s/mri/tmp",lsubjectsdir,lpname);
}
else if (action==4) {
  shrinkmode = 4;
  sprintf(dfname,"outer_skin.dat");
  sprintf(gfname,"%s/lib/bem/ic4.tri",csurfdir);
  sprintf(ofname,"%s/%s/surf/outer_skin.tri",
    lsubjectsdir,lpname);
  if (!outimoptflag)
    sprintf(bfname,"%s/%s/mri/tmp",lsubjectsdir,lpname);
}
else if (action==5) {
  shrinkmode = 4;
  dfrac = 0.4;
  sprintf(gfname,"%s/lib/bem/ic4.tri",csurfdir);
  sprintf(ofname,"%s/%s/surf/brainPD.tri",lsubjectsdir,lpname);
  if (!outimoptflag)
    sprintf(bfname,"%s/%s/mri/tmp",lsubjectsdir,lpname);
}
else if (action==6) {
  shrinkmode = 4;
  dfrac = 1.2;
  sprintf(gfname,"%s/lib/bem/ic4.tri",csurfdir);
  sprintf(ofname,"%s/%s/surf/brainPD.tri",lsubjectsdir,lpname);
  if (!outimoptflag)
    sprintf(bfname,"%s/%s/mri/tmp",lsubjectsdir,lpname);
}

/** read data files */
check_infiles(mfname,gfname);
read_geometry(gfname);
read_images(mfname);
read_datfile(dfname);
init_surf_to_image();

/** run built-in, no-graphics scripts, maybe exiting */
if (action==1) {   /* skull stripping -- write surf and images */
  momentumflag = 1; MRIflag = 1; flattenflag = 0; shrink(100);
  momentumflag = 0; MRIflag = 0; flattenflag = 1; shrink(10);
  write_geometry(ofname);
  peel_brain();
  write_images(bfname);
  if (getenv("noexit")==NULL) exit(0);
}
else if (action==2) {    /* inner skull -- just write surf */
  momentumflag = 1; MRIflag = 1; flattenflag = 0; shrink(100);
  momentumflag = 1; MRIflag = 0; flattenflag = 0; shrink(50);
  momentumflag = 1; MRIflag = 1; flattenflag = 0; shrink(100);
  momentumflag = 0; MRIflag = 0; flattenflag = 1; shrink(10);
  write_geometry(ofname);
  if (getenv("noexit")==NULL) exit(0);
}
else if (action==3) { /* outer skull -- just write surf */
  move_vertices(istilt);
  write_geometry(ofname);
  if (getenv("noexit")==NULL) exit(0);
}
else if (action==4) { /* outer skin -- just write surf */
  momentumflag = 1; MRIflag = 1; flattenflag = 0; shrink(200);
  momentumflag = 0; MRIflag = 0; flattenflag = 1; shrink(10);
  write_geometry(ofname);
  if (getenv("noexit")==NULL) exit(0);
}
else if (action==5) { /* raw 1st echo PD -- write surf,imgs */
  fzero = 75.0; istilt = 0.0;
  fsteepness=50.0; momentumflag=1; update=0.1; decay=0.1;
  fstrength = 0.1; MRIflag = 1; flattenflag = 0; shrink(10000);
  fstrength = 0.5; MRIflag = 1; flattenflag = 1; shrink(100);
                   MRIflag = 0; flattenflag = 1; shrink(10);
  write_geometry(ofname);
  peel_brain();
  write_images(bfname);
  if (getenv("noexit")==NULL) exit(0);
}
else if (action==6) { /* raw 1st echo PD, strip orig to tmp */
  fzero = 75.0; istilt = 0.0;
  fsteepness=50.0; momentumflag=1; update=0.1; decay=0.1;
  fstrength = 0.1; MRIflag = 1; flattenflag = 0; shrink(10000);
  fstrength = 0.5; MRIflag = 1; flattenflag = 1; shrink(100);
                   MRIflag = 0; flattenflag = 1; shrink(10);
  write_geometry(ofname);
  sprintf(mfname,"%s/%s/mri/orig.mgz",lsubjectsdir,lpname);
  read_images(mfname);
  peel_brain();
  write_images(bfname);
  if (getenv("noexit")==NULL) exit(0);
}


####################
makenewfunct
####################

-------------------------------------------
 The File -> New Functional menu creates a new
 blank functional session directory and its
 standard subdirectories
-------------------------------------------
This is the first step in making a new session.
A new functional session directory and a standard
set of subdirectories in it is created.  The
default location for the new session is the
current setting of the environment variable,
FUNCTIONALS_DIR, but a functional session can be
made anywhere.

Finding sessions by date or initials is much
easier with the csurf interface if multiple
sessions are stored in the same FUNCTIONALS_DIR.

The standard functional session directory
structure is:

 FUNCTIONALS_DIR (root of a sessions database)
    sessionname		usu. year+month+day+initials
       name                ASCII file (SUBJECTS_DIR directory)
       image		   directory of scans
          scripts		      configs, NOTES file
          rgb		      saved tiff or SGI-rgb bitmaps
          mpg		      saved mpeg movies
          alignscan		      T1-weighted alignment scan
          functscan1		      functional scan1
          functscan2		      functional scan2
          . . .

When the functional session is made, it prompts
you to find a subject somewhere that contains the
surface for this functional.  The subject must
already exist somewhere.  This linkage is saved
in a file, "name", inside the session directory
containing only the SUBJECTS_DIR directory name
of the subject (e.g., martys).

Once the functional session has been made, a
subdirectory for each functional scan should be
made in the image subdirectory.  Then, the
individual scans for that session should be
copied into the separate subdirectories.  The
tools in the SessionTools menu provide a
graphical interface to do this.

You can give the scan subdirectories any name
besides the names of the standard subdirectories
but it is extremely helpful to number them so
they sort in the order in which were acquired.
Also, it helps to add an informative suffix to
each name (e.g., the name of the stimulus
program), since the directory names are what are
used to select scans in the interface.  For
example:

  $FUNCTIONALS_DIR/somesession/image/1-smfaces/*
  $FUNCTIONALS_DIR/somesession/image/2-bigfaces/*
  $FUNCTIONALS_DIR/somesession/image/3-words/*
  ...

The alignment scan (in directory "alignscan"
above, but can be any name) is a T1-weighted scan
taken in the same orientation and with the same
slice block center as the functional scans.
Typically, it has thinner slices, smaller
in-plane pixels, and more coverage than the
functional scan.

The alignment scan is used as an initializer step
in aligning the functional data with the scans in
the subjects database that were used to make the
surfaces for this subject.  This initial easier
registration can then be copied to the functional
scan directories and refined.  This end result of
this procedure is a transformation matrix that
allows 3D statistical measures calculated from
the functional scans to be 'painted' onto the
cortical surface (possibly after first moving
along the local surface normal).

When functional data covers the entire brain,
this step can be skipped, and functional scans
can be directly registered to the T1-weighted
scans used to make the surface.  However, when
functional scans only cover a portion of the
brain, this step is quite helpful to initialize
the rotation.

FUNCTIONALS_DIR and SUBJECTS_DIR

It is possible to keep subject directories and
functional directories together in the same
directory -- that is, to set FUNCTIONALS_DIR and
SUBJECTS_DIR to the same directory.

It is also possible to embed a functional session
inside of the subject it refers to.  This is done
by first making the subject (File -> New Subject,
or MGHTools -> Run recon-all) and then
subsequently making the session (File ->
Functional), but choosing the already existing
subjectdir as the functional session.  This works
because the functional data and all the panel
configurations will all be inside the "image"
subdirectory.

HOWTO view/render bare vertexlist files (wfiles) with csurf

Here is how to make a set of bare wfiles (assumed
to be for subject "marty", and assumed to be
currently sitting in /tmp/wfiles/*), conveniently
csurf-accessible for rendering and saving
rendering parameters in a new session named
110601MS, inside of a scandir named "polar".

Note that in order for a wfile to appear in the
SessionTools -> View Functional Data "Paintfile:"
dropdown, it must end in either "-rh.w" or
"-lh.w":

  cd $FUNCTIONAL_DIR
  mkdir 110601MS
  cd 110601MS
  mkdir image
  echo marty > name
  cd image
  mkdir scripts rgb mpg polar
  cp /tmp/wfile/*-?h.w ./polar

Then, using csurf:

  csurf (or File -> Update Subjects & Functs)
  File -> Open Functional  => pick 110601MS
  SessionTools -> Setup Align/Funct Scans
    click "FunctScan Dir" for "polar"
    [leave all parms blank]
    Save/Close
  SessionTools -> View Functional Data

This can be useful for saving/documenting
detailed rendering parameters in the csurf
SessionTools -> View Functional Data panel.

####################
mkscandirs
####################

-------------------------------------------
 The SessionsTools->Make Scandirs,Find/Copy Raw
 menu names and creates scan directories,
 documents source of the files, strips initial
 TRs, and copies stripped scans into the new scan
 directories with meaningful, unique names.
-------------------------------------------

Getting Started

This panel is designed to be the first panel
accessed after running File -> New Functional.
It requires a virgin session directory tree
containing no scan directories.   If scan
directories have already been created (even if
they are empty), you won't even be able to open
this panel.   First manually remove existing scan
directories (the panel ignores the "rgb",
"scripts", and "tmp" directories in a newly-made
session).

Click the Find Raw Scans button at the top of the
panel to begin.  Click SETUP NEW SCANDIR one or
more times to create blank scan configuration
lines.  DELETE LAST SETUP deletes the most
recently added line, whether or not you have
altered it.

Create Scan Directories and Find Raw Scans

The scan directory name is the main text label
used in the rest of the interface for each scan,
and so it helps to choose informative names and
use them consistently.  One good name for a scan
is the name of the stimulus program that was
used.

By default, the first scan directory is the
alignment scan directory, and it is auto-named
"alignscan".  Directories after that are given
default prefixes: "1-", "2-", etc.  You can
change the names of the proposed scan directories
to whatever you like, but the names must be
unique (the default number prefixes guarantee
this, even if the stimulus exactly repeats --
e.g., "1-polar", "2-polar", etc).

For each new scan directory, click the FIND
button to locate a single raw alignment or
functional scan.  Subsequent FIND button clicks
start the directory browser in the parent
directory of the most recently selected Raw
Scan.

Once you are satisfied with the mapping between
scan directory names and raw scan names, click
MAKE SCANDIRS at the top of the panel.  If all
the fields are complete, the name list is unique,
and the raw scans all exist, the new scan
directories should appear on the left of this
panel (if not, fix things and click MAKE SCANDIRS
again).  Small text files containing the source
of the data will be created in each of the scan
directories.  If you want to redo this stage,
remove the just-created scan directories (which
will contain only small text files).

Strip Initial TRs and Copy/Rename Raw Scans

When the MAKE SCANDIRS button is clicked
successfully, default unique scan names will be
inserted into the right-most column (New Scan
Names).  These names must be unique because they
are used as the prefix for saved bitmaps, which
all reside in the same rgb directory.  These
names can be adjusted if necessary.  You may also
want to reset the number of repetitions ("rmTRs")
to strip off the begining of the functional
scans.  The defaults are to strip 0 for the first
(alignment) scan and strip 4 initial repetitions
off of subsequent functional scans.

Finally, click STRIP/COPY-RAW at the upper
right.  After checking the list of new names for
completeness and uniqueness, this strips TRs and
copies the raw functional scans into each scan
directory.

The STRIP/COPY-RAW function currently only works
with AFNI BRIKS. For now, if the fastest changing
index in the scan is not in the right/left
direction, the internal data order of the BRIK
will be flipped into this order and the HEAD is
updated to reflect this change (because some
later analysis steps do not yet read the AFNI
HEAD file).


####################
setupfunct
####################

-------------------------------------------
 The SessionsTools -> Setup Align/Funct Scans
 menu sets up the basic image parameters for
 functional and alignement scans in preparation
 for statistical analysis and rendering.
-------------------------------------------
On the left of this panel is a list of the
subdirectories in the current scan session.  On
the right are a set of pages of buttons and
entries -- a separate set for each alignment or
functional scan directory.

The first time you bring up this panel, all the
pages on the right of the panel will be blank
(regardless of which scan directory is selected,
no parameters appear on the right).

To configure a particular directory, select it
from the list on the left (it should be marked
green) and then click one of the buttons at the
top center of the panel to declare it to be
either a "Funct Scan Dir" or an "Align Scan Dir".

A "Funct Scan Dir" should contain one functional
scan, with multiple images/timepoints for each
slice.  An "Align Scan Dir" should contain a
T1-weighted scan that is (1) taken in the same
plane as the functional scans, and (2) also has
the same slice block center as the functional
scans.  It will usually have a higher resolution
that the functional scans (e.g., 1x1x2 mm for a
3x3x3 mm functional scans).

To save the current configuration of all of the
scan directories in the current session, hit Save
or Save/Close at the bottom of the panel.  You
can move between directories without losing any
configuration information as long as you do not
exit the panel.  Hitting Cancel will exit the
panel and leave the configuration in whatever
state it was when you first opened the panel.

The bottom buttons only affect the configuration
metadata for the the scan directories.  This
information is stored in an ASCII file:

  csurf.dat

which is located in the funct scripts directory:

  $FUNCTIONALS_DIR/$session/image/scripts

The Save/Close and Save buttons do not affect any
of the data files in the scan directories.

Ignored directories

The following directories are ignored by
Setup Align/Funct scan:

  scripts  (and scripts~)
  rgb  (and rgb~)
  tmp  (and tmp~)
  mpg
  irp
  shim
  raw

-------------------------------------------
(1) Configure the Alignment Scan
-------------------------------------------

Once a directory has been declared to be an
"Align Scan Dir", the first step is to read the
header of a file (or an example file if
slice-based).  All the files within the current
scan directory will be present in the "Image
File:" dropdown combo box.  Select one of the
files (e.g., alignscan+orig.BRIK).  Then click
"READ HEADER" to attempt to read the parameters
for this file.  Verify that all the fields have
been filled in correctly.  Any fields that say
"-unset-" need to be set manually.

Now click the INIT button near the bottom of the
panel to create an initial default transformation
matrix (the identity matrix).  This is equivalent
to assuming that the Align scan and the Subject
scan used to make the surface are already aligned
(they often are *not* aligned).  A panel will say
this was done automatically if you forget to do
this before hitting the "Align=>Subj" button.
You can also use the INIT button to start over.

The adjacent INIT/FLIP button does the particular
3D transpose needed for a typical (e.g., Siemens)
transverse EPI scan (or an alignment scan with
slice orientation and block center copied from a
functional scan).  If you use INIT/FLIP, verify
that the L/R flip done is correct (you can tell
it is wrong if it is impossible to accurately
register to the target).

tkregister Sampling Policy

The original tkregister *truncated* the
transformed floating point coordinates before
doing a nearest neighbor sampling of the moveable
volume.  MGH tkregister2 and bbregister *round*
before sampling (better, b/c invertible).  The
tkregister in csurf can do either kind of
sampling (as can paint, tkmedit, and tksurfer).

To the right of the INIT and INIT/FLIP buttons is
a checkbutton, "init round".  If no register.dat
yet exists, the default is for it to be selected.
If register.dat already exists, the button state
will be determined by reading the file.  INIT or
INIT/FLIP will create either type of register.dat
depending on the state of the "init round"
checkbutton.  All later programs will read the
register.dat to determine what to do.

The sampling policy is specified in register.dat
by an optional line following the transformation
matrix.  If the line is empty or contains
"tkregister", this means truncate.  If the line
contains "round", this means round.  Use "round"
for new data.

-------------------------------------------
(2) Register the Alignment Scan to the original Struct
-------------------------------------------

Now use the "Align=>Subj" button starts up the
registration program (tkregister) with the scans
used to make the surface for this subject as the
TARGET scan, and the alignment scans in the
currently selected directory as the MOVEABLE
scan.

The sole purpose of the tkregister application is
to generate a transformation matrix that maps the
alignment scan onto the scans used to make the
subject's surface.  The only file that tkregister
affects is:

  register.dat

one of which will be located in each scan dir:

  $FUNCTIONALS_DIR/$session/image/$scan

This file contains a 1mm => 1mm linear
transformation matrix (4x4 including rotation,
scaling, and in the fourth column, translation)
and an optional sampling policy line (see above).
During PAINT operations, the register.dat matrix
is used to map the x,y,z location of each surface
vertex into functional voxel coordinates.

See the "Register" Help menu item for tips on
how to register data sets.

Once the data sets have been aligned to your
satisfaction, hit the SAVEREG button on the
tkregister application to save it (it will backup
the previous registration matrix to the file
register.dat~).  Then quit the tkregister
application (using same now-purple button you
started it with).

-------------------------------------------
(2) Configure the Functional Scans
-------------------------------------------

Now select each functional scan in the listbox at
the left and configure each one as a "Funct Scan
Dir" (top left button).  Click READ HEADER and
check for missing or "-unset-" parameters.

Don't run the FUNCT=>SUBJ register button yet.
Check that the combox box labeled "SamePlane
AlignDir:" has auto-selected the alignment scan
(select it from the dropdown if it wasn't).

Slice time correction

There are two alternate methods for doing this,
which may be optionally used in the later
"Calculate 3D Fourier Stats" panel for correcting
the calculated response phase.  The default is no
correction (assume slices all within a TR were
collected at same time).  No correction is a safe
choice.

Slice time: explicit order specification

The first method is to explicitly specify the
order of slice acquisition using the row of
"Slice Ord:" buttons in the middle of the panel:

  simul  odev  evod  odevr  evodr  asc  desc

which mean:

  simul -- no correction (default: assume simultaneous)
  odev  -- interleaved, odd then even, start lownum slice
  odevr -- interleaved, odd then even, start highnum slice
  evod  -- interleaved, even then odd, start lownum slice
  evodr -- interleaved, even then odd, start highnum slice
  asc   -- ascending, start lowest num slice
  desc  -- descending, start highest num slice

For Siemens product EPI (NON-multiband)
transverse slices, the correct settings are:

  odd number of slices:  odev
  even number of slices:  evod

N.B.: this method does NOT (yet) work for
multiband (SMS) acceleration > 1.

Slice time: read TAXIS_OFFSETS

The second, alternate, method is to read the
within-TR slice time offsets for each slice out
of the AFNI HEAD file for a data BRIK
(TAXIS_OFFSETS field) and put the results into
the "Slice Time Offsets List:" field.  The
"Multiband Accel Factor:" if set by looking for
the number of repeat times in that list.

These will only be correct if the BRIK has been
generated from the IMA (DICOM) file by AFNI to3d
using tpattern equals "FROM_IMAGE".  Using, e.g.,
tpattern "seq+z", "alt+z", etc., will NOT
generate correct TAXIS_OFFSETS.  Versions of
ima2brik >= 0.4b work correctly.

The slice onset times can also be manually pasted
into "Slice Time Offsets List:" as a list of
space-separated times (in sec) beginning from the
start of the TR with slice 1.

If TAXIS_OFFSETS is absent in the AFNI HEAD file,
these fields will be blank (OK to leave them
blank).  Note that some versions of AFNI programs
(e.g., 3dvolreg) do not propagate this field from
input to output.

Slice time: how information is used

Slice time correction information can optionally
be used in the later "Calculate 3D Fourier Stats"
panel for correcting the calculated response
phase.  The ON/OFF buttons for each method are
there -- the default is no correction.  If one or
the other method is selected, the appropriate
option (-slicetiming or -taxisoffsets) will
passed to the "fourier" program when it runs in
the Fourier panel.

Volreg: 3D Motion Correct/CrossScanReg w/AFNI

The AFNI tool, 3dvolreg, should be used for
within scan motion correction and cross-scan
registration using the buttons in the line
labeled "Volreg:".  The combo box labeled "Targ:"
picks the target scan.  It can be the current
scan (default) or any other scan currently
configured as a functional scan.  The field "TR:"
picks the target TR (default 10).

Clicking "CURR" aligns all the other TR's in the
current functional scan with the target TR.

Clicking "ALL" aligns all the TR's in every
currently configured functional scan to the
target TR, which is the typical use if all the
functional prescriptions are the same.

The volume-registered BRIK's are then written
back into the respective scan directories with a
"-vreg" infix.  For example:

 infile:  scandir1/scanname1+orig.BRIK
 outfile: scandir1/scanname1-vreg+orig.BRIK

 infile:  scandir2/scanname2+orig.BRIK
 outfile: scandir2/scanname2-vreg+orig.BRIK

The original BRIK's will be untouched.  The name
of the new volume-register BRIK's will be
inserted into the "Image Name Format" field in
the Setup Align/Funct scans panels.  Note that
this operation doubles the size of the functional
data in each affected scandir.

This program will only run on a bona fide *.BRIK
as an input.  To go back to the original
non-motion corrected data (or to re-run the
3dvolreg program with a different target),
re-select a non-vreg'd "Image File:" and redo
READ HEADER.

Viewing Functional Scans (check motion/register)

If the functional scan is a bona fide *.BRIK
file, you can view it with AFNI by using the AFNI
button (or typing Alt-f in the panel).  This will
start AFNI in the currently selected functional
scan directory.

-------------------------------------------
(4) Copy Alignment Registration to Functionals
-------------------------------------------

Go back to the previously configured Alignment
directory and use the "Copy Align To All Functs"
button to copy the alignscan-to-subjectscan
transformation matrix into each configured
functional scan directory.  This copies the
transformation, taking into account the fact that
the slice thickness and inplane resolution
typically differs between the alignment and
functional scans (specifically: the thickness and
inplane parameters in register.dat are updated;
the transformation matrix is copied unchanged
since it is always 1x1x1mm -> 1x1x1mm).

(4) Verify/Touch-up Functional Scan Registration

Select the first functional scan at the left.
Now register the functional scan directly to the
surface reconstruction scan using the FUNCT=>SUBJ
register button, which starts tkregister again.
Since the functional and alignment scans were
collected in the same plane, the rotation of the
functional scan will be correct.

Alignment/Functional Offset

Any offset between the block centers of the
functional and alignment scans will not be
accounted for.  To correct this, use only the
TRANSLATE buttons from tkregister.  Since the
scan has already been rotated, there will be an
x, y, and z component to the translation.  Change
planes and translate until the functional scan is
aligned.

SubjectsDir Target ImageSet

This is normally the "orig" data set (a COR dir
or an mgz file) used to make the surface:

   $subject/mri/orig
   $subject/mri/orig.mgz

To use a different target data set (path relative
to $subject/mri), change this entry.

Non-Rigid Transformations

Lower-bandwidth, higher signal-to-noise scans may
have additional shearing (e.g., rhomboidal)
distortion.  To correct for a shear, you have to
use a combination of a rotation and a scaling --
a rotation alone won't work.  For example, to
correct a shear in which the left side of the
image is too high and right side too low, do
something like this:

  1) choose a rotation point near the center
  2) rotate 30 degrees to the right
  3) scale 95% in the vertical direction
  4) rotate 30 degrees to the left
  5) scale 105% in the vertical direction

Apply shear or scaling with discretion, only
after completely exhausting attempts to align the
images using rigid body translation and rotation.

Register: Copy Registration Between Functionals

After finishing with one functional, you can copy
the final functional alignment transformation
matrix between functional scans using the CP PREV
button.  Select one scan, then a second, then
click the button.  It will ask you to verify that
you are copying the registration matrix from the
first to the second scan.  To copy the current
directory functional registration to all the
other functionals, use the CP TO OTHERS button.

Same Plane Struct Dir

The drop down chooses the alignment scan
directory.  This is automatically set because
currently there can only be one alignment scan
per session.

BlkCentOff (avoid)

The value (in mm) in "BlkCentOff" is added to the
register.dat file when it is copied between the
alignment scan and the functional scans.  Try to
avoid having to reset this from 0.0 by collecting
alignment scans whose block center is the same as
functional scans.

Sample-to-Surface and Extract Timecourses Options

During the PAINT process (in several different
later panels) and the time course extraction
process (the "label:" line "T" button, see
below), a 3D statistic or rawdata timecourse is
associated with each vertex on the surface by
finding which voxel the vertex lies within.

NormSearch: Vertex Normal Search Op (PAINT, t-course)

First select the normal search type: "mm"
(absolute distance) or "frac" (fraction of
cortical thickness).  Then by entering different
values into the "mn/mx:" field (minumum, maxium)
fields, a search will be performed between those
limits in increments of "dx:" size.

Possible operations (radio buttons at far right)
on the set of statistics recovered in the search
are: "mx" (find largest absolute-valued statistic
along the vertex normal), "av" (find average
statistic), or "mn" (find minimum absolute-valued
statistic).  If the data is complex-valued, the
comparisons are based on the complex magnitude.
There is an identical set of controls on the
Import 3D Stats panel (imported stats typically
won't have functional scans to setup).

NormSrch,Same,UniqVox,UniqVtx,Alldx (Paint/t-course)

The NormalSearch operations are used for:

(1) standard PAINT operations

(2) interactive PAINT of 3D data
     sets (click "val:" to toggle to "val3d:")

(3) generating vertex-wise ASCII output files
     during surface label based timecourse
     extraction -- the "T" button on the "label:"
     line in tksurfer

Csurf passes these along with the parameters
described above to tksurfer using command line
parameters (see log).  The timecourses are
written to ASCII output files:

  $hemi.LABEL_NAME.raw  (vertices and raw t-courses)
  $hemi.LABEL_NAME.xyx  (uniq rawdata vox coords)

The state of the first three "NormSrch", "Same",
and "UniqVox" checkbuttons allows for different
behaviors during the generation of the *.raw,
*.raw,stat, and *.stat files.  The main four
types are:

  NormSearch = OFF
  UniqVox = OFF

    1 sample point halfway between min/max
    1 vox timecourse appears on multiple vtx lines
    each surf vertex appears 1 time in *.raw file
    no holes in surface vtx coverage

  NormSearch = OFF
  UniqVox = ON

    1 sample point halfway between min/max
    1 vox timecourse appears at most on 1 vtx line
    each surf vertex appears 1 time in *.raw file
    holes in surface vtx coverage

  NormSearch = ON
  UniqVox = OFF

    multiple samples along norm between min/max
        i.e., same *vtx* may appear on multiple lines
    1 vox timecourse appears 1 time *along norm*
    1 vox timecourse can appear on diff vtx lines
    no holes in surface vtx coverage

  NormSearch = ON
  UniqVox = ON

    multiple samples along norm between min/max
        i.e., same *vtx* may appear on multiple lines
    1 vox timecourse appears at most on 1 vtx line
    holes in surface vtx coverage

UniqVtx

If "UniqVtx" is ticked (N.B.: requires
"UniqVox"), then the vertex that 'owns' the
unique voxel in the timecourses output file will
be the one closest to the average location of all
the vertices that sampled it.  This contrasts
with "UniqVox" only, where the first vertex to
sample/hit the voxel 'owns' it.

Ticking this box will also pass -uniqsampvtxs to
paint.c, causing the Fourier and ExtStats PAINT
button to also write out a uniq sample label in
the current scandir named:

  ?h-UniqSampVtxs.label

This label will contain the single vertices that
were closest to the average location of each set
of vertices that sampled one voxel during the
paint operation.  This file can be used when an
offline statistic needs to be calculated on the
same number of vertices as there are sampled
voxels.

The same uniqsamp vertex operation can be done
interactively in tksurfer using the three
operations on the "val3d:" line (if not visible,
click "val:" to toggle to it):

 (1) load at least one 3D native stats file "R"
 (2) sample 3D file to surf w/"PAINT" (finds uniq vox)
 (3) run "UQ" to find uniqsamp vertices

The result (stored live in memory) can be used
for sampling timecourses, for constraining the
cross-correlation spotlight ("label:" line "X"
button), and can be interactively saved
(middle-click UQ instead of left-click).

The advantage of the interactive version from the
tksurfer NormSearch/PAINT pop-up is that it can
be used to quickly visualize the effects of
different sampling regimes and settings, which
can then finally be saved in the Setup Funct
panel.

Same

The above 4 NormSearch/UniqVox possibilities
above can also be modified by the "Same" tickbox.
With "Same" OFF, distance (mm) or fraction of
cortical thickness is measured along the local
surface perpendicular.  If "Same" is ticked, the
local surface normal is replaced by a unit 1
vector along the line between same-numbered
vertices (e.g., white and pial), and the fraction
of thickness is replaced by the fraction of the
distance to the same-numbered vertex.

Alldx

Finally, the third "Alldx" checkbutton removes
the unique-ing operation during normal search so
that a time course will be written for each
"dx"-sized search step.  This can be used for
offline weighted averaging of normal samples.
Note that this option is overridden if "UniqVox"
is checked.

The state of the mx/av/mn radio button is ignored
during timecourse extraction.  To obtain a
linearly-weighted average of the timecourse along
a surface normal, set:

  NormSearch = ON
  UniqVox = OFF
  Alldx = ON

and then average (offline) the timecourses for
each dx step.

All the NormSearch options can also be adjusted
interactively from the tksurfer popup available
by left-clicking "label:" (text to the left of
the label entry) in tksurfer (N.B.: changes there
won't affect saved csurf values here).

The full names of the tksurfer tcl
variables/options are:

  NormSrch		$normdsampsearchflag
  Same		$samevtxthickflag
  UniqVox		$normdsampuniqvoxflag
  UniqVtx		$normdsampuniqvtxflag
  Alldx		$normdsampallflag

AllVtxs

Normally, the *.w files generated by PAINT only
contain surface vertices intersecting functional
data/stats (vertices not painted are by default
set to 0.0 upon read).  To obtain a full-rank
wfile that contains every surface vertex, click
this box (tksurfer tcl variable/option:
$allverticesflag).

Clone Funct Dir

The CLONE FUNCT button creates a complete copy of
the currently-selected functional dir and appends
the specified suffix to it (so inheritance is
clear).  It copies everything in the directory
(N.B.: it used to just make links to the big
files -- now everything is copied, including raw
data and motion-corrected data).

This is to make it possible to run and save
alternate analyses on the same data, or merely to
save alternate rendering parameters in the Render
panel for the same data set.


-------------------------------------------
Common Layout of SessionTools Panels
-------------------------------------------

Most of the rest of the SessionTools panels are
arranged in a similar way.

 (1) center-top buttons that configure the
     current directory as a directory of a
     certain kind or tell the program to ignore a
     directory by Unset-ing it (a previously
     configured, then Unset directory, recovers
     its sets when re-configured)

 (2) settable parameters in the main part
     of the panel

 (3) action buttons at the top right with bold
     lettering that read the parameters you have
     set and actually perform computations that
     affect data files.  Those buttons turn
     purple during computations.

Some panels have smaller bold-font actions button
in the main body of the panels, mostly for
(re-)reading headers.

####################
setuprawavg
####################

-------------------------------------------
 The SessionsTools -> Combine 3D Raw Images
 menu averages/concatenates raw funct data
-------------------------------------------
The basic layout of this panel (scan directories
to the left, common action button at the top,
pages of parameters to the right) is similar to
the other SessionTools panels.  For more details,
see Help -> Setup Align/Funct.

This panel creates a new scan directory that
will contain averaged scans.

Configuration Buttons--Make Avg Dir, Unset Dir

First carefully choose a name for the average
directory in the entry to the right of the Make
Avg Dir button (you'll be stuck with it).
Clicking Make Avg Dir creates that directory.  If
the directory already exists, it will be re-used
rather than re-created.

To ignore an existing raw avg/concat directory,
use Unset Dir.  The files the unset directory
will not be altered and any saved parameters will
re-appear if you Make Avg Dir with that directory
name again.

Operation

Selected scans can either be averaged, time point
by time point, or concatenated.

Choosing Scans to Combine

A list of currently available functional scans
can be found in the "Select to Add" dropdown
combobox.  Selecting one of them will add it to
the "Dirs to Average" list.  To delete (or
re-order) directories from that list, select it
in the list and use the Delete or Backspace key.

Reversing time

For the 'Average' operation (but not for the
'Concatenate' operation), the direction of time
can be reversed on a scan-by-scan basis (e.g., to
obtain average time courses for reversed
phase-encoded scans) by ticking the checkboxes
(by selecting a ScanToCombine and hitting
<Return>).

Time Offset of Reversed Scans

Time-reversed scans can also be time-shifted to
compensate for hemodynamic delay before
averaging.  The units are TR's (default is 0, no
time shift).  All reversed scans are time-shifted
by the same amount.  The number entered must be
an integer.

Since only the reversed scans are time-shifted,
twice the estimated hemodynamic delay (in integer
units of TRs) should be entered.

A positive number -- e.g. 4 -- means that the
reversed time series will be shifted by 4 TR's
(moved back in time before averaging) to
compensate for hemodynamic delay.  Un-reversed
scans are never altered.  A negative number of
TR's is accepted (e.g., for an asymmetrical
reversed paradigm).

Empty values in the reversed scans after
time-shifting are padded with the average of the
two end values (versus wrapping time, which can
introduce an artifactual step, since there will
in general be an uncorrected ramp in the raw
data).

Note that the resulting average will still
contain a hemodynamic delay equivalent to that of
a single unreversed run.  This can be compensated
for at display time by incrementing the value of
$angle_cycles.  Since the units of angle_cycles
are 0.0 to 1.0, where 1.0 equals the time of 1
cycle, if the cycle time was 64 secs/cycle, then
a 4 sec hemodynamic delay equals 1/64 cycles/sec
* 4 sec equals an angle_offset of 0.0625 (this
offset should be added onto the default
angle_cycles, which is 0.0 or 0.5 depending on
hemisphere).

The hemodynamic delay may not be the same at
every voxel.  By reversing time, fixed per-voxel
*differences* in hemodynamic delay are cancelled.
However, the bulk hemodynamic delay itself must
still be estimated (or measured).

Action Button--COMBINE

This button performs averages or concatenates the
3D time series data sets and writes the result
into the current raw average directory as a set
of BRIK's.  Also works on old-style
<stem>_%03d.bshort files, each of which contains
all the timepoints for a single slice (first
slice is 000).  Each *.bshort must have a
matching single-line ASCII *.hdr file:

  <y> <x> <t> 0

The registration matrix from the first scan is
copied into the raw avg/concat directory and by
convention, the first scan in the average is used
as the output file stem:

 infiles (several x-y-z-t images):

   scandir1/scanname1[-vreg]+orig.BRIK
   scandir2/scanname2[-vreg]+orig.BRIK

 outfile (one x-y-z-t image):

   avgdir/scanname1[-vreg]+orig.BRIK

If the scans have been volume-registered with
3dvolreg ("vreg" infix), those will automatically
be used.  Otherwise, the original raw scans are
used.  The averaging is done in 3D without any
additional registration.  Note that register.dat
files are ignored.

Other Files Generated by "Concatenate"

If the COMBINE operation is concatenate, an AFNI
boundary file, runs.1D, is automatically created
(units are TRs).  If the time series is analyzed
using deconvolution, this file is consulted to
prevent stimulus events at the end of one run
from accounting for variance at the beginning
of the next run.

If motion correction has been run on the
individual scans, a concatenated motion.1D file
will also automatically be generated.

Finally, if paradigm files are present in a
paradigm subdirectories (default: stim1Ds/) of
each scan to be concatenated, the paradigm files
for each condition will be separately
concatentated and placed in a paradigm directory
in the new concatenated scandir.  For the
automatic concatenation of paradigm 1D files to
work correctly, the paradigm files in the stim1Ds
subdir in each of the scan dirs to be
concantentated *must* be named as follows:

  scan1
    face1.1D
    house1.1D
  scan2
    face2.1D
    house2.1D
  ...

That is, the condition name stem (up to the
number before the .1D suffix) much be exactly
the same across all scans to be concatentated.
The stem must be immediately followed by a single
numeral before the .1D suffix.

The list of conditions (1D files) to concatenate
is taken from the first directory in the list.
That is, each successive scan should have
the same set of conditions in it.  It's OK if
numerals are the same across scans (e.g., same
randomization in those scans).  The concatenated
paradigm file will be given a name that has the
numeral position replaced by a 'C'.

Touch up

If you averaged the data, at this point you
may want to go back to SessionTools -> Setup
Align/Funct Scans to touch up the FUNCT=>SUBJ
registration for the averaged scan.


####################
setupfour
####################

-------------------------------------------
 The SessionsTools -> Calculate 3D Fourier Stats
 sets up and calculates Fourier-based statistics
 on 3D volume data sets
-------------------------------------------
When FOURIER is clicked, the program "fourier"
runs FFT's on the time course at each 3D voxel,
and then calculates phase and significance of the
periodic activation.  When PAINT is clicked, the
3D data is sampled to the surface using the
current register.dat and sampling distance (from
Setup Align/Funct panel).

This panel normally remains "Unset" for a pseudo
scan directory that contains statistics generated
by averaging statistics across multiple scans
with Combine 3D Phase Statistics (there is no raw
time series data in such a dir).

The Image Name Format

This is automatically entered from the Setup
Functional panel.  To refresh this field, go back
to the corresponding Setup Functional Scan
Parameters scandir, re-select the correct Image
File, and click READ HEADER.

Stimulus Program Notes

An arbitrary length string of ASCII characters
(can include carriage returns) for informational
purposes.

"cp prev" Button

This button copies parameter values from the
previously selected scandir (left column) into
the current scandir.  All parameter values from
"Stim Cycles per Scan" and below are copied.

Stim Cycles Per Scan

This is the most important parameter on the
panel.  To analyze a polar angle mapping stimulus
(rotating wedge) with 8 cycles, enter 8.  You
would also enter 8 if there were 8 ON blocks and
8 OFF blocks.  This number does *not* have to be
a power of two, but it *does* have to be an
integer.

Use Slice Timing

The "UseSliceOrd" and "UseTAXIS" ticks turn on
alternate methods for correcting the fourier
domain output phase of voxels in individual
slices.

If "UseSliceOrd" is clicked (-slicetiming option
for the "fourier" program), the "Slice Ord:"
buttons are used specify the slice order.  N.B.:
this method does NOT work for multiband > 1.

If "UseTAXIS" is clicked (-taxisoffsets option
for the "fourier" program), slice-by-slice time
offsets from "Slice Time Offsets List" (in the
Setup Functional Scans Parameters panel) will be
used for the correction.

If either method is used, be sure to verify that
the slice order specification matches reality.
The effects of this correction are quite subtle
for standard short-TR multiband acquisitions.

Since the slice time corrections (for non-sparse
scans) will, on average, retard the output phase
by 1/2 the duration of TR, after the corrections
are applied, all phases are advanced by the same
amount (TR/2).  This allows direct blink
comparison between corrected and uncorrected
scans.

TR

The TR must be entered (if not auto-entered).  It
is used by the optional/deprecated "UseSliceOrd"
slice timing correction.

3D (Pre)Smoothing FWHM (mm)

3D spatial smoothing can be applied to AFNI raw
time series data sets before calculating Fourier
statistics, using AFNI 3dmerge:

  3dmerge -1blur_fwhm <fwhm> -doall -prefix <outbrik> <inbrik>

The default is no smoothing (=0.0).  Use gingerly
since this is 3D smoothing.  It is *much* more
effective to instead smooth the complex
statistics in 2D on the surface (e.g., 20 steps
~= 4 mm FWHM 2D kernel) than it is to smooth the
raw data with a similar sized 4 mm FWHM *3D*
kernel before calculating the phase of the
response.

Low-Freq Cutoff (cyc/scan)

Frequencies below this cutoff (default: 3 cycles
per scan) are ignored for when calculating
signal-to-noise as the ratio of amplitude at the
stimulus frequency to amplitudes of other (noise)
frequencies.  Very low frequencies are dominated
by movement artifacts, and this procedure is
similar to regressing out signals correlated with
movement (N.B. the "fourier" program removes the
linear term from the time series *before*
calculating the FT).

Hi-Freq Cutoff

Frequencies above this cutoff are ignored in the
same way as just described.  In this case, the
default value is -1, which is a flag to allow
noise frequencies up to the Nyguist limit (1/2
the sampling rate) -- that is, no high frequency
cutoff.

Omit Freq

Frequency (cycles per scan) of an additional
periodic nuisance signal to discard when
calculating signal-to-noise.  Typically, this is
used to ignore a periodic activation due to a
regularly performed task during a phase-encoded
mapping experiment (e.g., a periodic auditory
cue).  The default value is -1, which is to
disable this option.

Permute Test Count (0=off)

If the number in this entry is bigger than zero,
a permutation test is used to directly estimate
the p-value of the F-ratio.

This test permutes the labels of the frequencies
in the fourier transform of the timecourse and
recalculates F the requested number of times.

The estimated p-value is the fraction of times
that permuted frequencies result in an F-ratio
larger than the non-frequency-permuted F-ratio
calculation.

This test is computationally expensive (see
Preferences -> View/Hide Logs for progress and
elapsed time).  It is written multi-threaded so
it will run faster with more cores.   The minimum
number of permutations for reasonable results is
about 1000 (maximum possible significance
p=0.001) but 5000 is best (about about 30 min
computation on 4 cores).

Since this test generates p-values directly, if
you enter a number of permutations and hit
<Return> the "Phase Stat Type" (see below) will
be changed to "p-val" (from default "sqrt-F").
The resulting complex-valued output statfiles
(infixes: _r,_i) will contain vectors whose
length is -log10(p) and whose phase is the phase
of the signal at the stimulation frequency.
Thus, the units of fthresh and fmid will be
-log10(p), for example (with 256 or 512 TRs):

   fthresh/fmid=1.3  => p < 0.05
   fthresh/fmid=2.0  => p < 0.01
   fthresh/fmid=3.0  => p < 0.001

The p-value (in the form of -log10(p)) is also
written out directly into a BRIK with a _p infix.

If no smoothing is done at surface render time, a
hard amplitude threshold ($fthresh, single or
leftmost threshold entry) on the _r,_i files will
be equivalent to a hard stats threshold
($sfthresh, rightmost threshold entry) on the
_r,_i files using _p file as a mask (with a
permissive $fthresh).

However, if surface smoothing has been done at
render time, the results of those two procedures
will differ since complex-valued smoothing of the
_r,_i values will reduce the complex amplitude as
a function of the phase dispersion of adjacent
vertices.  Smoothing the real-valued _p file
ignores phase and results in no amplitude
reduction from phase dispersion (preferred).

3D/Surf Cluster: PreThr (F/p)

The "PreThr" parameter sets the hard,
pre-clustering threshold for *both* the 2D
surface-based (surfclust) cluster exclusion
filter as well as the 3D (AFNI 3dmerge) cluster
exclusion filters.  Note, however, that the final
output of 3D and surface-based clustering will
differ (see below).

The units of PreThr are usually F, but may also
be -log10(p) in the case where a permutation test
has been run.  Use an F table (see table at end
of Help -> View Functional Data) to determine the
F value to enter for the desired p-value (e.g.,
0.05), or enter -log10(p) directly if permutation
test.  This parameter is passed as:

  surfclust ... -thresh <prethr> ...
  3dmerge ... -1clip <prethr> ...

3DClust (units=vox):  connected=___  and minvol=___

After FOURIER has generated the 3D _r,_i BRIK's
(phase w/sqrt F inserted as amplitude), and the
_x,_y BRIK's (phase w/raw Fourier amplitude at
stimulus frequency), and _f BRIK (F calculated
from stimulus frequency vs.  noise frequencies),
the F-stats BRIK is run through a 3D cluster
filter using AFNI 3dmerge for cluster-filtered
statistical masking (e.g., for maps in brainstem
structures.

These two parameters control the minumum cluster
size for the separate 3D cluster filter output
(BRIK with a _h infix).  These parameters are
passed as:

  3dmerge ... -dxyz=1 -1clust_order <connectdist> <minvol> ...

The first option means that units are one voxel
width and one voxel volume (*not* mm and mm^3).
The first argument to -1clust_order is the
minimum Euclidean distance between voxels for
them to be considered to be in the same cluster
during region growing (units are one voxel
width).  For standard region growing with no gaps
during cluster growth, use 1 (meaning the
distance of one voxel width).  To allow voxels
that separated by one subthreshold voxel to be
added to the same cluster, use 2, and so on.

The second parameter clips off clusters that are
below this volume (units are one voxel volume,
*not* mm^3).  For example, using the default of
40 with 3x3x3 mm voxels results in a minimum
cluster volume of 1080 mm^3 (about 1 cm^3).

Note that the parameters have opposite polarity:
increasing the first makes the filter *less*
stringent while increasing the second makes it
*more* stringent.

The -1clust_order option (in the family of
-1clust options, where -1clust is the basic
option to just clip) numbers the clusters in
order of size.

N.B.: 3D, Surface-Based Clusters NOT the Same!

The *output* of the 3D cluster filter is ignored
during the independently calculated surface-based
clustering (see next), and in general, the
results will be somewhat different, This can be
seen if 3D clustered stats from the _h BRIK are
sampled to the surface, or surface-clustered
stats from _h vertex list files (wfiles) are
mapped back to 3D voxels.

SurfCluster: min area (mm^2)

When PAINT is clicked, after the five 3D data
sets (with infixes: _r,_i and _x,_y and _f), have
been resampled to the surfaces of each
hemisphere, a surface-based cluster filter is run
on the surface-sampled F-statistic using
surfclust (Hagler, Saygin, and Sereno, 2006,
Neuroimage 33: 1093-1103).  This generates a
sixth set of surface files for each hemisphere
that have _h infixes.

The "SurfCluster: min area" entry sets the the
minimum area of a surface-based cluster that will
be passed by the filter and written into the left
and right hemisphere output files with an _h
infix.  The default of 150 mm^2 is roughly the
surface area of 16 standard 3x3x3 mm fMRI voxels.
If you smooth your data less, this will need to
be reduced to avoid removing significant
activations.

This parameter is passed as:

  surfclust ... -minarea <prethr> ...

See Help -> Cross Session Spherical Average for
more details on how to run randsurfclust to
determine cluster area thresholds for non-default
amounts of smoothing.

HOWTO disable 3D/Surf Clustering

Set 3DClust "minvol" to 0 to disable 3D
clustering.

Set SurfCluster "min area" to 0.0 to disable
surface clustering.

Phase Stat Type

This switch controls which value is inserted as
the amplitude (modulus) of the complex-valued
statistics generated when FOURIER is clicked.
The statistics are output as a real/imaginary
pair of files with infixes, _r and _i.  The phase
of this complex number, atan2(y,x)), is the phase
at the stimulus frequency taken from the Fourier
transform of the time course.

The first button, sqrt-F, tells the "fourier"
program to generate a vector whose amplitude is
the square root of the F-ratio calculated by
comparing the signal amplitude at the stimulus
frequency to the signal at other noise
frequencies.

Low frequencies, the second and third harmonics
of the stimulus frequency, one frequency to
either side of the 1st, 2nd, and 3rd harmonics,
and the optional "Omit Freq" are discarded as
neither signal nor noise.  If the "harm23" button
is clicked, harmonics 2 annd 3 are included as
part of the signal.

The p-val button calculates a p-value saved as a
negative of power of 10: -log10(p) -- thus,
p=0.01 will be saved as 2.0) from the F ratio by
taking into consideration the number of degrees
of freedom.

The p-FA calculated the probability of false
acceptance (also saved as -log10(p)).

In every case, the real and imaginary
coefficients of the Fourier transform at the
stimulus frequency are in addition saved as a
pair of files with infixes, _x and _y.

Finally, the coherence is saved as a file with
infix _c.  The coherence is defined as:

  stimfreq_amp / sqrt(sum(noisefreq_amps^2))

Stat Format, full FT, rm full FT

The original FOURIER program generated stats in
the form of bfloat slices.  The new default is to
generate AFNI BRIKs, which are more convenient to
view.  PAINT and phase COMBINE now accept AFNI
BRIK stats in addition to bfloat slices stats.
Here are the new standard outputs:

  <stem>_r+orig.BRIK -> real, sig/amp=sqrt(F)
  <stem>_i+orig.BRIK -> imaginary, sig/amp=sqrt(F)
  <stem>_x+orig.BRIK -> real, power at stim freq
  <stem>_y+orig.BRIK -> imaginary, power at stim freq
  <stem>_f+orig.BRIK -> F-stat -- N.B.: F not sqrt(F)
  <stem>_p+orig.BRIK -> if permutation test, -log10(p)
 <stem>_c+orig.BRIK->coher:stimfreq/sqrt(sum(noisefreqs^2))

The "full FT" check box in the middle causes the
entire Fourier transform to be dumped out in the
form of three additional (large!) float BRIKS:

  <stem>_xf+orig.BRIK -> real, all freqs
  <stem>_yf+orig.BRIK -> imaginary, all freqs
  <stem>_af+orig.BRIK -> amplitude, all freqs

Note that full FT files occupy a total of 6x as
much space as the original raw time-series data
(short->float times real+imaginary+amplitude).
They can be viewed in AFNI; "Index" (normally for
time points) can be used to scroll through
frequencies, and "Graph" can be used to see the
full (symmetric) Fourier spectrum (lowfreq ->
highfreq -> highfreq -> lowfreq).

The full FT's can be averaged across scans within
one session using the "Combine 3D Phase Stats"
panel (Combine Operation: "vect avg full FT's, do
sig"), which subsequently performs the same
significance calculation done here, but on the
average FT (programs: "rcxcombine -fullFT ..."
and "fourier" -juststats ...).

To save space, they can safely be removed with
the far right "rm full FT" button when the
combine operations are done.

Phase Encode Type

The radio button chosen specifies which set of
rendering defaults (color map type, color map
parameter settings, tcl scripts) to use when the
View Functional Data panel is first opened to
render surface images.  All the default values
can be overridden there.  The setting here also
tells the Fieldsign panel what kind of scan this
is (polar vs. eccen, or neither).

Truncphase

If Truncphase is checked, some phase angles will
be set to zero during the PAINT operation which
associates 3D statistics with each surface
vertex.  Generally, it is easier to do this
interactively in tksurfer, and save settings in
the View Functional Data panel.  The default
settings reflect the fact that stimuli typically
start on the horizontal meridian, which is
halfway through the right hemifield.

Fourier Format (minus infixes)

This is the tcl variable $bfloatpatt, which is
used to construct the stems of later files.  This
*omits* the infixes which would be situated in
the position of "$infix" in bfloat files and
BRIKs as follows:

  <stem>-vreg+orig{$infix}_%03d.bfloat
  <stem>-vreg+orig{$infix}+orig.BRIK

This should normally be set automatically and is
exposed here for debugging purposes.

Surface for Sampling 3D Data

This is the inner surface that the PAINT button
uses to sample 3D data onto the surface.  The
default is "orig".  In the original freesurfer,
the orig surface was the faces of the 1x1x1 cubes
classified as white matter.  In current
freesurfer distributions, the orig surface is a
smoother surface with better behaved surface
normals.

Painted Vertex List Files

These fields merely provide user feedback for the
names of the vertex list files (wfiles) generated
when PAINT is run to sample the 3D stats
calculated here onto the surface.

Action Button--FOURIER

When FOURIER is run, the panel will check whether
the number of repetitions in the corresponding
Setup Functional panels are powers of 2.  FOURIER
will not run unless this is the case (typically
128, 256, or 512 repetitions).

Action Button--PAINT

This button samples the Fourier analyzed data
onto the surface specified in "Surface for
Sampling 3D Data".  The result is 14 (or 16 if
permuation test) files, whose names appear
schematically in the bottom two entries on the
fourier panel.

There are seven (or seven) vertex-wise PAINT
output files for each hemisphere.  These consist
of the real and imaginary components of the
Fourier transform at the stimulus frequency
(infixes: _x,_y), the real and imaginary
components where the complex amplitude has been
replaced by a significance statistic (infixes:
_r,_i, where amplitude equals square root of the
F-ratio, or -log10(p) if a permutation test has
been run to calculate significance), the F-ratio
and the surface-based cluster-filtered F-ratio
(infixes: _f,_h), and the coherence (infix: _c).
Finally, if a permutation test has been run, the
-log10(p) is also output as a single file:

  <stem>-vreg+orig_x-{lh,rh}.w
  <stem>-vreg+orig_y-{lh,rh}.w

  <stem>-vreg+orig_r-{lh,rh}.w  # amp: sqrt(F) or -log10(p)
  <stem>-vreg+orig_i-{lh,rh}.w  # amp: sqrt(F) or -log10(p)

  <stem>-vreg+orig_f-{lh,rh}.w  # F (not sqrt(F))
  <stem>-vreg+orig_h-{lh,rh}.w  # cluster filtered F
  <stem>-vreg+orig_c-{lh,rh}.w  # coherence
  <stem>-vreg+orig_p-{lh,rh}.w  # if permutation test

See Help -> Register for details of how the
register.dat file generated by tkregister is used
to sample 3D statistics to the surface, including
code examples.

N.B.: the _f paint file is normally generated by
paint.c by squaring the amplitude of the
complex-valued _r and _i paint files (which is
sqrt(F)), as opposed to running a separate
instance of paint.c to sample the equivalent 3D
_f file onto the surface.

N.B.: the 3D _p file is only generated and
painted when a permutation test has been
performed.  In this case, the '_f' paintfile
mentioned above (made from complex-valued _r and
_i paint files) is overwritten by sampling the 3D
_f file (for subsequent cluster filter).

Action Button--AFNI

View raw and possibly smoothed timeseries BRIKs
(no infix), full Fourier transforms (infixes:
_xf, _yf, _af), and complex valued statistics
(infixes: {_r,_i}, _{x,_y}, _a) in the current
scan dir.

View 3D Stats overlaid on structural images

Use the VOLUME-STATS button on the View
Functional Data panel, which allows viewing
complex-valued statistics in 3D using the same
color scales as used for the surface display.

VOLUME-STATS supercedes the unsupported,
IRIX-only tkanalyse, which used to be startable
(in the Paleolithic) from this panel with Alt-v.

####################
setuprand
####################

-------------------------------------------
 The SessionsTools -> Calc 3D Rand Block Stats
 sets up and runs deconvolution on 3D volume
 data set using AFNI 3dDeconvolve (by Doug Ward)
-------------------------------------------
This panel configures files and runs Doug Ward's
3dDeconvolve on functional time-series BRIKs.
Normally, you then use SessionTools -> Import 3D
Stats to extract the output files and PAINT them.
It requires that single-column 1D paradigm files
have been previously generated and placed within
each paradigm dir, which typically a directory
named "stim1Ds" within each scandir (see below).

The full 3dDeconvolve command line passed to
sh/bash is saved in the current scandir as:

  deconv.sh

The Image Name Format

This will typically be a concatenated,
motion-corrected time-series BRIK.  This is
automatically entered from the Setup Functional
panel.

Paradigm Dir

The standard subdirectory name is "stim1Ds".
This is the directory containing single-condition
1D files that together specify the columns of the
paradigm (design matrix) for a single scan.
Since these files are small, and since a central
paradigm file store may get out of sync with an
already-performed expt, make a "stim1Ds"
subdirectory in each scandir, and then copy the
paradigm files used for each scan into each
subdirectory (the only kind of files in there
should be paradigm files).  The directory tree
should look like this:

session
    image
        scan1
            stim1Ds
                face1.1D
                house1.1D
        scan2
            stim1Ds
                face2.1D
                house2.1D
        . . .

You must use a relative path for the Paradigm Dir
(i.e., the path *cannot* start with a "/").

Paradigm Files

These are single-column (n x 1) files, one for
each condition.  The filename should be a short
lower-case word followed by a .1D suffix (e.g.,
face.1D, house.1D, scramb.1D).  See below on
naming rules for files that are going to be
auto-concatentated by Combine 3D Raw Images.

The short names for the condition 1D files should
be 7 chars or less before the ".1D" suffix (incl.
the concatenation number -- see below).  For
example, use "animal2.1D" rather than a verbose
filename like Animal_Pictures_2.1D").  This makes
the auto-generated contrast names (esp. when a
contrast includes multiple conditions) easier to
read.  It also allows tabs in the Random Block
Statistics panel to space out the conditions
properly.  Finally, it is the only way to silence
a nagging pop-up :-}

Each line in the text files should end in
unix-style newline character, '\n'.  Some
programs may insert different or multiple
end-of-line characters.  For example, the Excel
output "export to space-separated" has DOS
carriage returns, '\r', not unix newlines, '\n'.
Fix them by using, for example, tr (translate):

  tr '\r' '\n' < condfiles.prn > condfiles.txt

That command line converts DOS carriage returns
to unix newlines.  If you have *two* invisible
end-of-line characters -- e.g., both DOS carriage
returns (\r) *and* unix newlines (\n) -- use this
tr command instead to strip the \r's:

  tr '\r' < condfiles.prn > condfiles.txt

Be sure to use a different file name for the
output file because a unix command line ending in
"> filename" will first create an empty output
file, destroying the input file (unix gotcha).

To see explicitly what is in a text
file, use

  od -cv textfile

This will print out the actual bytes in the
file 16 to a line, with spaces between each byte
(N.B.: space characters also show up as spaces
[separated by spaces]).  There should only be
numbers (0 and 1) and newlines (\n) (and possibly
spaces or tabs (\t) in the paradigm file.  Spaces
and tabs will be ignored.  Any other characters
will cause csurf or 3dDeconvolve errors.

The filename stem (e.g., face, house, scramb)
will be used in the interface and the resulting
saved bitmaps as the condition name.  Inside
the file, there should be a 1 when its named
condition is present and a 0 when it is not
(an error panel will come up if something other
than 0 or 1 is found).

The baseline condition is defined by the presence
of a 0 in all of the condition files.  Thus,
there is no 1D file for the OFF-condition.
Except for the off-condition case, for a given
TR, there should be a 1 in exactly one paradigm
file.  Here is an example of a portion of a
paradigm file:

====== cut here ==========================
0
0
1
1
1
...
====== cut here ==========================

If the scandir was generated by concatenating
raw data files from separate runs (COMBINE
on the SessionTools -> Combine 3D Raw Images
panel) prior to opening this panel, the COMBINE
concatentation process should already have
automatically generated the following files:

 concat'd BRIK/HEAD raw data timeseries file
 concat'd motion.1D file (if runs volreg'd)
 boundsfile: run1.1D (so HDRs don't cross runs)
 a stim1Ds subdirectory
 concat'd paradigm files put in stim1Ds/

N.B.: for the automatic concatenation of paradigm
1D files by Combine 3D Raw Images to work
correctly, the paradigm files in the stim1Ds
subdir in each of the scan dirs to be
concantentated *must* be named as follows:

  scan1
    face1.1D
    house1.1D
  scan2
    face2.1D
    house2.1D
  ...

That is, the condition name stem (up to the
number before the .1D suffix) much be exactly
the same across all scans to be concatentated.
The stem must be immediately followed by a single
numeral before the .1D suffix.

The list of conditions (1D files) to concatenate 
is taken from the first directory in the list.
That is, each successive scan should have 
the same set of conditions in it.  It's OK if
numerals are the same across scans (e.g., same
randomization in those scans).  The concatenated
paradigm file will be given a name that has the
numeral position replaced by a 'C'.

TR (sec)

Repetition time between successive images of
the same slice in seconds.

Maximum Lag (-maxlag)

The maximum lag (in TRs) to allow when solving
for the hemodynamic response function for a
each trial type.

Polynomial Fit Order (-polort)

This specifies the order of the polynomial used
to fit the low frequency drift in the signal.
The default is 2.

Motion Params File (-dfile)

This should contain a 6-parameters-per-timestep
estimate of motion artifact.  This is typically
generated by 3dvolreg after motion correction is
run in the Setup Functional panel.

Scans, Total TRs

The number of scans that were concatenated to
generate the input file named at the top, and the
total number of TRs that it contains.

Paradigm Panel

When "READ 1Ds" is clicked, the individual
condition paradigm files are each read and
assembled into a paradigm matrix, where each
column comes from one 1D file.  The stems of the
paradigm filenames are substituted for 1's and
"----" is substituted the 0's in the 1D file.
This step verifies that the 1D files all have
the same length.

Automatically-Included Contrasts (cond vs. OFF)

A comparison of each condition to the OFF
condition (a '0' for that TR in every 1D file) is
automatically computed and given a label based on
the stem of the corresponding 1D file.

Pairwise Contrasts (old subpanel)

N.B.: this subpanel is only visible if
Preferences -> Simple Rand Block Diffs is ticked
*before* opening SessionTools -> Calculate 3D
Random Block Stats.  The default is not ticked.

To add a subtraction, select a block type from
the "Condition A:" and  "Condition B:" dropdown
menus and then click "ADD SUBTRACTION" which
should add it to the Subtractions list below.  To
omit a subtraction, use Backspace.  This panel
can only generate contrasts between pairs of
single conditions.

User-defined GLT Contrasts (new subpanel)

Use "ADD CONTRAST" to add a line of entries, one
for each condition.  All entries will initially
be defaulted to 0.  Use 1, -1 and sometimes 2,
-2, to arrange a comparison between any two
groups of conditions.  If there are positive and
negative numbers, they should add to 0.  The
"DELETE LAST" button removes the last contrast
line.  The configuration is saved on Save or
Save/Close.

After the contrasts have been setup, click "AUTO
NAMES" to generate names for them.  The
auto-generated names will look like this:

  {cnd1,cnd2}-VS-{cnd3,cnd4} => contrast
  {cnd1,cnd2}                 => add 2 conds
  VS-{cnd3,cnd4}           => opposite sign above

where cnd1, cnd2, etc are the stems of the 1D
filenames.

These names will serve as stems for files for
later Import and Render steps.  Note that AFNI
3Ddeconvolve has a 32-char limit on the length of
any individual label name.  With a large number
of conditions, the automatically generated names
can breach the 32-char limit.  In that case, a
warning will come up, and then the name in the
"GLT name" field can be manually trimmed.  It
will be tested again on clicking DECONVOLVE.

General linear test matrices

The generated GLT matrices (single-row files for
each condition vs. OFF plus single-row files for
each optional subtraction/contrast) are saved in
a subdirectory in each scandir (both old and new
subpanels):

  $scandir/gltmats/*.mat

The first set of 0's in each file corresponds to
the number of baseline parameters (polorts+1).
If the run has been concatenated, the total
number of entries here will be number of runs
times number of polorts+1.

The second set of 0's, 1's, -1's (and maybe 2's
and -2's) correspond to a series of conditions,
arranged in same order (alphabetical) as in the
panel.  Each condition contains maxlags+1
entries.  In this section, contrasts between
conditions may be specified.

The last set of values are the 6 motion
parameters from running 3dvolreg.  If the run
been concatenated, a concatenated motion.1D file
will be used.

Action Button--DECONVOLVE

When DECONVOLVE is clicked, 3dDeconvolve will be
run according to the mode radio buttons just
above the paradigm window (test/F/t-stats).  The
output stats file will be written into the
current scan directory.  If Test is selected, the
parameters are checked for completeness and the
design matrix is tested for singularity.

Stats Output File

The output stats BRIK name appears here after
DECONVOLVE has been run.  This takes a while
for a concatenated scan.  Correct settings for
rendering will depend on the paradigm.  For the
blue/red scale, try starting with:

  smooth:   10
  thresh:   0.0
  contrast: 0.15
  midpoint: 7

####################
setupsigavg
####################

-------------------------------------------
 The SessionsTools -> Combine 3D Phase Stats
 menu averages fourier-analyzed 3D stats
-------------------------------------------
This panel creates a new scan directory that will
contain averaged 3D fourier-based statistics.

Configure Buttons--Make CombineDir, Unset Dir

First carefully choose a name for the average
directory in the entry to the right of the Make
CombineDir button (you will be prompted to change
the default name, "phavg").  Then, click the Make
CombineDir button to create the directory.  If
the directory already exists, it will be re-used
rather than re-created.

To ignore an existing 3D phase average directory,
use Unset Dir.  The files in the unset directory
will not be altered and any saved parameters will
re-appear if you click Make CombineDir with that
directory name again.

The 3D stats files are combined voxel-by-voxel.
This ignores the funct=>struct transformation
matrix (register.dat) and relies on accurate 3D
cross scan alignment (typically via 3dvolreg run
in the Setup Align/Funct panel).

The transformation matrix for the combined file
is copied from the *first* scan in the scans to
combine list.  This transformation matrix gets
used when the combined file is PAINT'ed onto the
surface.  Be sure to re-COMBINE in order to redo
this copy register operation if you go back and
touch up the transformation matrix from the first
input scan (adjustments to later stat sets in the
list are ignored) and you want the that modified
transformation matrix to be used for PAINT in
this panel.

Choosing Stat Files to Average

A list of currently available fourier-analyzed
functional scans can be found in the "Select to
Add" dropdown combobox.  Selecting one of them
will add it to the "ScansToCombine" list.  To
delete (or re-order) a directory from that list,
select it in the list and then use the Delete or
Backspace key.

The input files for this panel are generated by
the "Calculate 3D Fourier Stats panel".  They can
either be:

  (1) a real/imaginary pair of bfloat slice
      series containing complex-valued
      significance calculations for each run
      (usu. sqrt-F)

  (2) the same data put into a real/imaginary
      AFNI BRIK pair aligned with the raw data
      (easier to manipulate and view)

  (3) a full Fourier transform of the time
      series data without any significance
      calculation, put into a real/imaginary pair
      of 4D AFNI BRIKs (relevant for operation:
      average full FT)

In the first two cases, the *output* files
will be the same format as the input (bfloat
or BRIK).  In the third, case, the output is
always a BRIK.

Reversing Phase of Stat Files

If scans to be combined do not have the same
phase direction (e.g., clockwise vs. counter-
clockwise direction of the moving sector in a
polar angle mapping experiment), the phase of one
or more scans can be reversed by selecting the
scan to be reversed, and then typing Return.
"Reversing the phase" means taking the negative
of the phase angle calculated for each voxel.
This is equivalent to reversing the direction of
time in the time domain.

Combine Operations

Next select a combine operation.  The operation
"vect avg complex sigs" (original default)
calculates the voxel-by-voxel vector average of
the the complex-valued significance calculation
(i.e., separately average real and imaginary
components).

The operation "phasecancel 2 cpx sigs" calculates
the voxel-by-voxel angular average of 2 opposite
phase-direction scans and then separately
averages the amplitudes (separately average phase
and amplitude components).

In the first case, if two vectors with large
amplitude have very different angles, the
amplitude of their vector average will be small;
in the second case, it will be large.  Thus, the
'phaseaverage' operation more strongly penalizes
voxels with inconsistent phase in the component
scans.  Currently, the 'phasecancel' operation
can only combine two scans.

The advantage of both of these methods is that
they can combine data from scans with different
numbers of timepoints and different stimulus
frequencies.

The third operation, "vect avg full FT's, do sig"
is a better method of combining scans with
identical numbers of data points and identical
stimulus frequencies.  It first averages the full
Fourier transforms of each individual time course
(this requires that the FOURIER button was run
with "full FT" clicked).  Then, in a second step,
the significance is calculated as before (F-ratio
computed from Fourier amplitude at the stimulus
frequency compared to fourier amplitude at
other/noise frequencies).  It uses the settings
(stim cycles, noise cutoffs) from the Fourier
panel from the first scan in the average.

It takes advantage of the fact that the noise
frequencies generally have different phases in
different runs, while the stimulus frequency will
have the same phase -- which increases the
contrast between signal and noise in the average.

This method is similar to averaging raw time
courses (with or without time reversal).  The
advantage is that a hemodynamic delay in the
stimulus frequency phase can be properly
introduced when combining scans with opposite
phases -- namely, *before* reversing the phase.
This is harder to do in the time domain.

Phase Offset

The measured response phase consists of a
stimulus phase plus a hemodynamic delay phase.
If scans are combined with opposite directions of
phase, the hemodynamic delay phase can be
subtracted out.  However, if the operation
'phaseaverage' is used, this will reduce the
amplitude of the vector average (there is no
effect of a hemodynamic delay on the
'phasecancel' operation and no effect of a
non-zero offset in this panel).  To avoid this
reduction in amplitude, an estimated average
hemodynamic delay (in units 0.0 to 1.0, where 1.0
equals one full stimulus cycle) can be applied
prior to the 'phaseaverage' operation.

Action Button--COMBINE

This button performs the 3D phase average of the
fourier-analyzed data sets that you have selected
using the operation selected, and writes the
result into the current sig average directory as
a new set of 3D files.

Action Button--PAINT

This button samples the combined data onto the
surface specified in "Surface for Sampling 3D
Data" in the Fourier panel.  The result is four
new files, two for each hemisphere, which consist
of the real and imaginary components of the
combined Fourier statistics (*.w files) which can
be directly displayed on the surface with View
Functional Data panel.  Note that this button
generates files for both hemispheres, regardless
of which hemisphere is currently selected.

##############################
Input File Formats -- 3D/Volume
##############################

 (1) Fourier-analyzed complex sig (bfloat):
     [o riginal slice-based format]
   ---------------------------------------
   sess/scan1/<stem>_r_000.bfloat 
   sess/scan1/<stem>_i_000.bfloat 
   sess/scan1/<stem>_r_001.bfloat 
   sess/scan1/<stem>_i_001.bfloat 
   ...
   sess/scan1/<stem>_r_029.bfloat 
   sess/scan1/<stem>_i_029.bfloat 
   ---------------------------------------
   sess/scan2/<stem>_r_000.bfloat 
   sess/scan2/<stem>_i_000.bfloat 
   sess/scan2/<stem>_r_001.bfloat 
   sess/scan2/<stem>_i_001.bfloat 
   ...
   sess/scan2/<stem>_r_029.bfloat 
   sess/scan2/<stem>_i_029.bfloat 
   ---------------------------------------
   ...

 (2) Fourier-analyzed complex sig (BRIK):
     [new style: volume, easier to view]
     [these BRIK's contain floats]
   ---------------------------------------
   sess/scan1/<stem>_r+orig.BRIK
   sess/scan1/<stem>_r+orig.HEAD
   sess/scan1/<stem>_i+orig.BRIK
   sess/scan1/<stem>_i+orig.HEAD
   ---------------------------------------
   sess/scan2/<stem>_r+orig.BRIK
   sess/scan2/<stem>_r+orig.HEAD
   sess/scan2/<stem>_i+orig.BRIK
   sess/scan2/<stem>_i+orig.HEAD
   ---------------------------------------
   ...

 (3) Full complex Fourier transform (BRIK)
     [N.B.: sig/F-ratio calc not yet done]
     [these BRIK's contain floats, 4x raw]
   ---------------------------------------
   sess/scan1/<stem>_xf+orig.BRIK
   sess/scan1/<stem>_xf+orig.HEAD
   sess/scan1/<stem>_yf+orig.BRIK
   sess/scan1/<stem>_yf+orig.HEAD
   ---------------------------------------
   sess/scan2/<stem>_xf+orig.BRIK
   sess/scan2/<stem>_xf+orig.HEAD
   sess/scan2/<stem>_yf+orig.BRIK
   sess/scan2/<stem>_yf+orig.HEAD
   ---------------------------------------
   ...

##############################
Output File Formats -- 3D/Volume
##############################

 (1) Average complex sig (bfloat):
     [original slice-wise format]
   ---------------------------------------
   sess/phavg/<stem>_r_000.bfloat 
   sess/phavg/<stem>_i_000.bfloat 
   sess/phavg/<stem>_r_001.bfloat 
   sess/phavg/<stem>_i_001.bfloat 
   ...
   sess/phavg/<stem>_r_029.bfloat 
   sess/phavg/<stem>_i_029.bfloat 
   ---------------------------------------

 (2) Average complex sig (BRIK):
     [new style: volume, easier to view]
     [these BRIK's contain floats]
   ---------------------------------------
   sess/scan1/<stem>_r+orig.BRIK
   sess/scan1/<stem>_r+orig.HEAD
   sess/scan1/<stem>_i+orig.BRIK
   sess/scan1/<stem>_i+orig.HEAD
   ---------------------------------------

##############################
Output File Formats -- 2D/vertexlist
##############################

  (1) output of PAINT (avg complex sig):
   ---------------------------------------
   sess/phavg/<stem>_r-rh.w
   sess/phavg/<stem>_i-rh.w
   ---------------------------------------


####################
setupsurfavg
####################

-------------------------------------------
 The SessionsTools -> Combine Surface Stats
 menu averages already-painted surface stats
-------------------------------------------
This panel creates a new scan directory that
will contain averaged surface-based statistics
(possibly cross-session).

Configure Buttons--Make SurfAvg Dir, Unset Dir

First carefully choose a name for the average
directory in the entry to the right of the Make
Avg Dir button.  Clicking Make SurfAvg Dir
creates that directory.  If the directory already
exists, it will be re-used rather than
re-created.

To ignore an existing surface average directory,
use Unset Dir.  The files in the unset directory
will not be altered and any saved parameters will
re-appear if you click Make SurfAvg Dir with that
directory name again.

Choosing Stat Files to Average

Choosing the pre-painted stats to average is a
three-part process.

First select a session from which a scan will be
chosen, by selecting a session using the
"Functional Sessions to Choose From" dropdown
combo box at the top.  This allows you to average
scans across different sessions, as long as they
are in the current Functional Sessions directory
($FUNCTIONALS_DIR).  The statistics to average
must have been painted using a single subject's
surface (the same version of it!).  If you want
to select a scan from the currently open session,
you have to hit 'Enter' in the combo box.

Second, once you have selected a session, the
dropdown combo box on the next line at the left
("Select Both", meaning both hemispheres) will
now contain the individual scan directories in
that session.  Select one scan directory.  If the
scan directory contains pre-painted data, the
dropdown combo box immediately to the right
("Vertex List Prefix") will be updated.

Finally, select one of the pre-painted vertex
list prefixes in the "Vertex List Prefix"
dropdown combo box to the right.  If the paint
file is from a retinotopy session, the real and
imaginary infixes will be automatically stripped
(you only need to select either the real or
imaginary file).

Once you have selected one of the paint files,
the full path to it will be added to the central
"Fullpath Vertex Lists to Combine" panel.  To
delete (or re-order) directories from that list,
select one in the list and use the Delete or
Backspace key.

Reversing Phase of Stat Files

If scans to be combined do not have the same
phase direction (e.g., clockwise vs. counter-
clockwise direction of the moving sector in a
polar angle mapping experiment), the phase of one
or more scans can be reversed by selecting the
scan to be reversed, and then typing Return (or
double-clicking).  "Reversing the phase" means
taking the negative of the phase angle calculated
for each voxel.  This is equivalent to reversing
the direction of time in the time domain.

Combine Operations

Now select a combine operation.  The operation
'realaverage' simply averages two real-valued
data sets (e.g., F-stats).  The other three
operations average complex data sets and differ
only in how they setup the default color scale
options in the View Functional Data panel.  For
complex data sets, you can introduce a phase
offset for each data set that differs from zero
(see below).

Use Script, New Script checkbox

If the "Use Script" checkbox is selected, a
editable combine script will be created (IRIX
only, using binary: surfcombine).  Checking "New
Script" overwrites/re-generates a fresh version
of this file if it already exists.

Action Button--SURFCOMBINE

This button performs a surface-based average of
the pre-painted stats data sets that you have
selected and writes the result into the current
surf average directory as a new set of painted
files (*.w files) which can be directly displayed
on the surface with View Functional Data panel.
Note that this button operates on the files for
both hemispheres, regardless of which hemisphere
is currently selected.

When you click the SURFCOMBINE button with "Use
Script" *un*-checked, the selected paintfiles are
combined (using binary: rcxcombine).

When you click the SURFCOMBINE button with "Use
Script" checked, a small text file with a *.scom
suffix is created and opened using the default
text editor.  This file will be used by the
surfcombine program to do the averaging after you
click "OK" on the alert panel.

You can edit the file in the editor before it
is used.  For example, you can use non-zero
angle_offsets for each file (OK to have a
different angle offset for each file) or the
phase can be reversed for one or more input
files.  Do this by changing the default arguments
of the transform_angles command:

  transform_angles <revphaseflag> <angle_offset>
                     default=0     default=0.0

The commands that can be placed in the *.scom
file and their arguments are:
-----------------------------------------
[set data source directory]

  setdir <directory_path>

[read data onto top of stack, multiple reads push]

  read_real    <stem-hemi.w>
  read_complex <stem_r-hemi.w> <stem_i-hemi.w>

[operate on data on top of stack, in place]

  smooth_real    <steps>
  smooth_complex <steps>
  transform_angles <revphaseflag:0,1> <angle_offset:0-1>
  thresh_real <thresh>
  sigmoid_real <fmid> <fslope>  [f=(1+tanh(fslope*(f-fmid)))/2]
  sigmoid_complex <fmid> <fslope>  [operate on, scale amp]
  abs_real
  abs_complex

[operate on data across stack, output pushed onto top]

  average_real    <numfiles>
  average_complex <numfiles>
  max_real    <numfiles>
  max_complex <numfiles>

[write data, top of stack -- orig format wfiles]

  write_real <stem-hemi.w>
  write_complex <stem_r-hemi.w> <stem_i-hemi.w>

[write data, top of stack -- curv format wfiles]

  write_real_cv <stem-hemi.w>
  write_complex_cv <stem_r-hemi.w> <stem_i-hemi.w>
-----------------------------------------

Input and Output Files

 infiles (paint files--complex data example):

   ----------------------------------
   session1/scandir1/scanname1_r-rh.w
   session1/scandir1/scanname1_i-rh.w
   session1/scandir1/scanname1_r-lh.w
   session1/scandir1/scanname1_i-lh.w
   ----------------------------------
   session2/scandir1/scanname1_r-rh.w
   session2/scandir1/scanname1_i-rh.w
   session2/scandir1/scanname1_r-lh.w
   session2/scandir1/scanname1_i-lh.w
   ----------------------------------

 outfiles (paint files--complex data example):

   ----------------------------------------
   currentsession/surfavg/scanname1_r-rh.w
   currentsession/surfavg/scanname1_i-lh.w
   ----------------------------------------
   currentsession/surfavg/scanname1_r-lh.w
   currentsession/surfavg/scanname1_i-lh.w
   ----------------------------------------


####################
setupfield
####################

-------------------------------------------
SessionsTools -> Calc Visual Field Sign, Borders
-------------------------------------------
This panel uses eccen/polar pairs of Fourier
analyzed surface data sets to calculate the
visual field sign (mirror vs.  non-mirror image
representation), and/or retinotopic borders as
defined by region-growing to find where RF
positions repeat.

Input Files

The same set of eight Fourier-analyzed input
files are used for both of these operations.
These will have already have been painted onto
the left and right hemisphere surfaces from the
Fourier, Combine 3D Phase, or Combine Surface
Stats panels:

Right hemisphere
 $FUNCTIONALS_DIR/sess1/image/eccdir/ecc_r-rh.w
 $FUNCTIONALS_DIR/sess1/image/eccdir/ecc_i-rh.w
 $FUNCTIONALS_DIR/sess1/image/poldir/pol_r-rh.w
 $FUNCTIONALS_DIR/sess1/image/poldir/pol_i-rh.w

Left hemisphere
 $FUNCTIONALS_DIR/sess1/image/eccdir/ecc_r-lh.w
 $FUNCTIONALS_DIR/sess1/image/eccdir/ecc_i-lh.w
 $FUNCTIONALS_DIR/sess1/image/poldir/pol_r-lh.w
 $FUNCTIONALS_DIR/sess1/image/poldir/pol_i-lh.w

Eccentricity Scan and Polar Angle Scan comboboxes

Select an eccentricity functional scandir in the
"Scan Directory" combo box.  A *.w file must
appear in the "Vertex List Prefix" combo box
immediately to the right.  Do the same for a
polar angle functional scan.  Make sure it is
the correct one.

In both cases, the complex infixes, (_r, _i or
_x, _y) as well as the hemisphere infix (-lh or
-rh) will have been stripped from complex-valued
pairs.

=========================
Borders by Visual Field Sign
=========================

The first two parameters below the file selection
dropdowns control the field sign calculation.

This panel calculates the visual field sign using
two Fourier-analyzed data sets--one for in which
eccentricity was mapping and the other in which
polar angle was mapped.

The gradients in retinal eccentricity and polar
angle with respect to cortical x and y are
computed.  These two gradients are vector
quantities whose norms have units deg/mm (the
reciprocal of magnification factor).  They are
computed by fitting a plane to the r (or theta)
values of the current vertex and its immediate
neighbors using least squares.

In the original presentation (Sereno et al.,
1994), the clockwise angle between them (the
fieldsign angle) was measured to determine
whether the local representation of the visual
field at that vertex was non-mirror-image (angle
near Pi/2) or mirror-image (angle near -Pi/2).

Here, a cross product between the gradients is
calculated.  In the original version of tksurfer
compute_fieldsign, the signed magnitude of the
cross product was clamped to {-1,0,1} before
saving.  The current version saves the unclamped
value.  Its distribution peaks at 0 and falls off
approximately exponentially.  Truncating the
signed magnitude data to between -0.05 and 0.05
captures 99% of it (stdev of truncated data =
0.0070).  Note that this measure is sensitive to
both mapping signal gradient magnitude as well as
the fieldsign angle.

Finally, the intensity of the field sign coloring
is adjusted using the average significance from
the eccentricity and polar angle data sets.

By setting nonbinaryfsflag=1, an additional
modulation of the yellow/blue fieldsign color
toward gray is added to fieldsign values near
zero (ambiguous), in addition to the main
modulation by fsmask.  The width of the near-zero
valley is controlled by fsslope ("sl" entry to
left of main fieldsign file entry) -- higher
fsslope's give a narrower valley (back to binary
around fsslope=10000).

Smoothing Steps

Since the fieldsign calculation involves
gradients (derivatives), standard 3mm^3 data
needs to be heavily smoothed to reduce noise
(default: 50 steps).  Reduce this for higher
resolution data.

Flat Surface for Fieldsign Calc

The gradients are calculated on a flattened
surface.  In general, the smaller the surface
patch, the less distorted it will be.

Action Button--FIELDSIGN

This generates four files in the current
fieldsign scandir, two for each hemisphere.  The
fieldsign itself is stored in {rh,lh}.fs while
the fieldsign significance mask is in {rh,lh}.fm.

 $FUNCTIONALS_DIR/sess1/image/fs/rh.fs
 $FUNCTIONALS_DIR/sess1/image/fs/rh.fm

 $FUNCTIONALS_DIR/sess1/image/fs/lh.fs
 $FUNCTIONALS_DIR/sess1/image/fs/lh.fm

=================================
Borders by Retinotopic Region Growing
=================================

The next 6 parameters control the border
definition by region growing calculation.

The algorithm works by placing a seed at a
vertex, adding vertices in order of distance from
the seed to see if they have RF's different from
any in the current list, and then marking a
vertex if an RF is close to any RF in the current
list.  This operation is performed across
vertices in label, resulting in a "detected
border count" at each vertex.

Surf Smoothsteps Before Calc

The eccentricity and polar angle data is first
smoothed.  Less smoothing is required than for
the field sign calculation (default: 30 steps)

Label for Retin Seeds

Because the searchlight procedure is
computationally intensive, a label defining
(restricting) the search region is required for
each hemisphere in the standard directory:

  $SUBJECTS_DIR/$subject/label

The label name format should be the UCSD/UCL
label format, with a dash, not a period, after
the $hemi.  Here are the default label names:

  rh-retinseeds.label
  lh-retinseeds.label

Since this algorithm will generate noise when run
on retinotopic noise, you can create a suitable
signal containing label by using the tksurfer ROI
button.

Search Distance Each Seed Vtx (mm)

The search (searchight) is truncated at this
distance/radius (default: 5 mm) from each seed.
Increasing this parameter increases search time
quadratically.

RF Dist Below This Marks Repeat

This defines the criterion for when a border has
been detected because an RF position has
overlapped one already in the list.  The units
are distances between receptive field centers on
a circle of radius 2Pi radians.

Frac Label Vtxs to Seed (0-1)

This is a second method for reducing computation
time.  This parameter controls the randomly
selected fraction of the total number of vertices
in the search label to seed for searches.  The
default is all of the vertices (1.0).  The
computation time is about a minute per 15K
vertices (full hemisphere: ~150K vertices).

Output files

Two real-valued output wfiles are written, one in
the eccentricity directory used for the
calculation and the other in the polar angle
directory used.  The name format in both cases
is:

  <eccenstem>+<polarstem>_k-$hemi.w

The file in the eccentricity directory is simply
the count of border detections at each vertex.
For an exhaustive search of seeds in a 15K vertex
label, this count will be in the range of 2000
for a retinotopic border.

The file in the polar angle directory has the
same count multipled by fraction of the number of
seeds divided by the total number of vertices
tested.  This number will be near 1.0 for
detected borders.

These files are best displayed with the BRy color
scale, using fmid to adjust the exact position of
the yellow borders.

The tksurfer C/tcl border-finding function,
find_retin_borders, is set up and called from
csurf using the standard tcl library script,
borders.tcl, which is similar to the fieldsign
library script, fs-make.tcl

####################
setupimport
####################

-------------------------------------------
 The SessionsTools -> Import 3D Stats sets up
 to import statistical data set that have already
 been analyzed with AFNI (or SPM)
-------------------------------------------
This panel imports externally calculated native
resolution statistics (usu. calculated with AFNI
3dDeconvolve) and paints them onto the surface
using the register.dat file.

For BRIKs with multiple conditions generated by
3dDeconvolve, there are options for running a
cluster exclusion mask (3dmerge) and using the
resulting clustered t- or F-stat files to mask
the coefficient files (3dcalc) to a selected
(corrected) significance threshold (entered as t-
or F-values).

Select Input Data Set

First select the input data set to extract and
convert from the "External Stats Image Set"
dropdown.  The interface will guess at the
StatType using the input file suffix:

  <stem>.BRIK/HEAD   => AFNI-SINGLE
  <stem>.BRIK/HEAD   => AFNI-MULTI
  <stem>_%03d.bfloat => BFLOAT

This will be a single-frame bfloat or AFNI BRIK,
or a multi-frame AFNI BRIK (bucket) containing,
for example, amplitude coefficient estimates
(area under the estimated hemodynamic response
functions) and corresponding F- or t-stats for
each condition and optional contrasts.

The output BRIK from 3dDeconvolve run via csurf
will contain a "-stats" infix in the filename.
If pre-smoothing has been done, there will also
be an infix indicating this (e.g., "-sm4.0-").

AFNI BRIK Format

First read the HEAD file by pressing READ HEADER

If a BRIK contains no labels (BRICK_LABS field in
*.HEAD file) or only a single default label
('#0~), it will be treated as an AFNI-SINGLE
import, which allows the extraction of a single
subbrik ("Briks to Skip" selects which subbrik to
extract, if there are more than one).

AFNI 3dDeconvolve labels (BRICK_LABS)

The label numbers auto-generated by AFNI
3dDeconvolve have changed over the years
including at least these:

  Version 1: label delimited by "'" and "~" with
  subbrik number enclosed in brackets (e.g.,
  [0]), and using spaces (" ") to separate stem from
  LC[0] and LC[0] from "coef" or "F-stat" suffix

  Version 2: label delimted by "'" and "~" with
  number preceded by "#" and using underscores
  (_) to separate stem (e.g., up-VS-down) from
  GLT#0 infix and from "Coef" and "Fstat" suffix

Csurf changes both brackets and the "#" to "@" in
the csurf label display and in the stems of the
output BRIK (or bfloat) filenames.  Avoiding
brackets avoids shell problems, and the "#" is
avoided because MGH nmovie won't display a
filename containing that character.

Multi-frame BRIK Subpanel

An extra sub-panel appears when a BRIK containing
multiple labels is selected.  After pressing the
READ HEADER button in the sub-panel, you should
then be able to choose which sub-briks to extract
(typically all), and which sub-briks to use as
maskfiles (typically, all again).

Coef files masked by cluster-filtered t- or
F-stats will be dumped out from line with a Coef
"ValueFile" and a t- or F-stat "MaskFile".
Cluster-filtered t- or F-stat files will be
dumped out from lines with a t- or F-stat in both
"ValueFile" and "MaskFile" (i.e., mask stat file
with cluster exclusion derived from same file).
These files are written so that thresholds can be
interactively set at display time.

Finally, the mask thresh can be set.  The mask
threshold is entered as a t- or F-value.  For
AFNI stats, use the AFNI viewer with the "Define
Overlay ->" side panel open to map t- or F-values
to p values (AFNI will automatically consider the
degrees of freedom).  To interactively mask data
in tksurfer, set a low threshold (0.01), which
can conveniently be done by using "Gobal
MaskThresh <Ret>" at the top of the MaskThresh
column.

If "cluster" is ticked, t- or F-stats will first
be run through a cluster exclusion filter using
3dmerge (to correct for multiple comparisons)
with two requested cluster parameters set in the
interface.  These parameters are passed as:

 3dmerge ... -dxyz=1 -1clust_order <connected> <minvol> ...

The first parameter, "connected=", parameter
means the minimum Euclidean distance between
voxels for them to be considered to be in the
same cluster during region growing (N.B.: units
are voxel width, *not* mm).  To filter using
clusters with no gaps, use 1.  To allow one-voxel
holes in clusters, use 2, and so on.

The second "minvol=" parameter clips off clusters
that are below this volume (N.B.: units are voxel
volume, *not* mm^3). For example, using the
default of 40 with 3x3x3 mm voxels results in a
minimum cluster volume of 1080 mm^3 (about 1
cm^3).

Default values are entered here, but can be
recalculated using AlphaSim or 3dClustSim.  To
view the resulting cluster filter itself, open
AFNI and examine the files with a "-clustmask"
infix.  The values in the file are the numerical
order of size of the clusters found.

Extracted file names

The extracted and masked coeff/amplitude files
have names like:

---------------------------
 older 3dDeconvolve
---------------------------
  [old bfloat slice format]
    <cond1>_LC@0@_coef-clust+orig_%03d.bfloat
    <cond2>_LC@0@_coef-clust+orig_%03d.bfloat
    ...
  [BRIK format]
    <cond1>_LC@0@_coef-clust+orig.BRIK
    <cond2>_LC@0@_coef-clust+orig.BRIK
    ...

---------------------------
 newer 3dDeconvolve
---------------------------
  [old bfloat slice format]
    <cond1>_GLT@0_Coef-clust+orig_%03d.bfloat
    <cond2>_GLT@0_Coef-clust+orig_%03d.bfloat
    ...
  [BRIK format]
    <cond1>_GLT@0_Coef-clust+orig_%03d.bfloat
    <cond2>_GLT@0_Coef-clust+orig_%03d.bfloat
    ...
---------------------------

The corresponding extracted and clustered
statistics look like:

---------------------------
 older 3dDeconvolve
---------------------------
  [old bfloat slice format]
    <cond1>_F-stat-clust+orig_%03d.bfloat
    <cond2>_F-stat-clust+orig_%03d.bfloat
    ...
  [BRIK format]
    <cond1>_F-stat-clust+orig.BRIK
    <cond2>_F-stat-clust+orig.BRIK
    ...

---------------------------
 newer 3dDeconvolve
---------------------------
  [old bfloat slice format]
    <cond1>_GLT_Fstat-clust+orig_%03d.bfloat
    <cond2>_GLT_Fstat-clust+orig_%03d.bfloat
    ...
  [BRIK format]
    <cond1>_GLT_Fstat-clust+orig.BRIK
    <cond2>_GLT_Fstat-clust+orig.BRIK
    ...
---------------------------

After checking the configuration, then press
EXTRACT/CONVERT.  Check for errors in the log.

Extracting stats *without* cluster filter

If "Cluster" is unticked, stats files can be
extracted and thresholded directly.  In this
case, the infixes will be "-thresh" instead of
"-clust".  Thus, there are 6 possible
extract/mask operations:

Coef operations

 1. coef/nocluster/nothresh -> dump coef
 2. coef/nocluster/thresh -> thresh coef
 3. coef/cluster/thresh ->
     a. cluster stat for given thresh
     b. mask coef with it

Stat operations

 4. stat/nocluster/nothresh -> dump stat
 5. stat/nocluster/thresh -> thresh stat
 6. stat/cluster/thresh ->
     a. dump unclustered stat (-thresh)
     b. cluster stat for given thresh
     c. mask stat with it

Minimum Required HEAD Parameters

Here are the absolute minimal required parameters
for import of a *single* frame of external
statistics.  This example is for a 64x64x24
3.2mm^3 dataset with 256 time points:

  type  = float-attribute
  name  = DELTA
  count = 3
    3.203125 3.203125 3.2

  type = integer-attribute
  name = DATASET_RANK
  count = 8
    3 1 0 0 0
    0 0 0

  type = integer-attribute
  name = DATASET_DIMENSIONS
  count = 3
    64 64 24 0 0
  
  type  = float-attribute
  name = BRICK_FLOAT_FACS
  count = 1
    0.03051851

Note that additional fields (e.g., label names)
are read out of the HEAD file for mulitple frame
statistics BRIK.

PAINT

Pressing PAINT, paints all the extracted 3D files
onto the chosen cortical surface, using the
current vertex normal operation (same operations
as on Setup Align/Funct Scans panel, for
explanation, see Help for that panel).  You can
then view all of the painted files later on in
the rendering panel:

  SessionTools -> View Functional Data

where there is a set of radiobuttons near the top
of the panel that allow the rendering of multiple
extracted sub-briks from a single scan directory.
The options are:

 one  -- render selected (single) vertex file
 last -- render all vertexfiles from last extract
 all  -- render all vertexfiles (except complex)

When the multiple-render options are clicked, the
selected vertex file changes to "-multiple-".
The stems of the output rgb files in that case
are the same as the stems of the sub-briks.

The .bfloat format

The old .bfloat format -- now deprecated in favor
of AFNI BRIK's which are easier to view and less
clutter -- is a slice-based format (headerless
data with a matching minimal ASCII header file)
that can be used internally by FreeSurfer
programs, and is easily generated by an external
C program.  The filename format for each slice
file and header file is:

  <stem>_%03d.bfloat
  <stem>_%03d.hdr

The slice numbering is zero-based.  The first
slice is therefore:

  <stem>_000.bfloat
  <stem>_000.hdr

The bfloat file is a headerless string of floats
with x as the inner loop (x is the R->L direction
in tkregister when a default (identity matrix)
register.dat is loaded).  The hdr file is an
ASCII file that contains 4 strings:

  <ysize> <xsize> <numtimepoints> <other>

For example:

  64 64 1 0

Note that for binary compatibility across all
platforms, the BRIK and bfloat files are stored
in MSB byte order (SGI/Sun/PPC-Mac) byte order.
All the FreeSurfer programs automatically swap
bytes on read and write on Linux.  For this
reason, if bfloat files are generated by a simple
C program in Linux using fwrite(), you should
swap the bytes as the last step.  For example,
you could run AFNI 4swap on each bfloat after
generating it.  The oldstyle *.hdr files are
ASCII and therefore don't need to be swapped.


####################
setuprender
####################

------------------------------------------
 SessionsTools -> View Functional Data views
 3D stats on high resolution 3D underlay
 (tkmedit) or cortical surface (tksurfer)
-------------------------------------------
The basic layout of this panel (scan directories
to the left, common action button at the top,
pages of parameters to the right) is similar to
the other SessionTools panels.  For more details,
see Help -> Setup Align/Funct.

First select a scan directory at the left and
click "Render Stats Dir" at the top to get a new
page of parameters.  Select/verify hemisphere,
and surface or patch, and then click
SURFACE-STATS or VOLUME-STATS to start tksurfer
or tkmedit for surface or volume render using
current parameters.  See log for (verbose!)
command line arguments generated for tksurfer and
tkmedit.

Startup rendering parameters can be interactively
adjusted in tksurfer and tkmedit, but will not be
saved there.  Enter final choices in View
Functional Data panel and use "Save" or
"Save/Close" at bottom panel for correct new
startup.

Double-click between the bottom 3 buttons to
raise the main csurf panel (useful with multiple
csurf's).

Clicking the "fsavg" checkbutton at top right
before clicking SURFACE-STATS causes current
paintfile (and optionally statmask paintfile) to
be resampled onto the icosahedral fsaverage
surface (resampled paintfiles will have an
"fsavg-" prefix), and then displayed on one of
those surfaces.  This is a one-time operation
(checkbutton auto-unclicks when done).  To pick
an fsaverage display surface type not present in
dropdown for current subject (e.g., inflated_avg)
type into "surface:" (or "patch:") entry and hit
Return.  R-click help explains other options
(resample to other hemi, other subject).

The panel is described top to bottom.

Paintfile (amplitude or statmask)

This is the stem (minus real/imaginary infixes,
hemisphere, and .w suffix) for files that are
generated when you click the PAINT button on the
Fourier panel (after FOURIER) or the PAINT button
on the Import 3D Stats panel (after EXTRACT/
CONVERT), or the cross subject surface stats
generated when you click SPHEREAVG or SAMP2SUBJ
on the Cross Sess Spherical Average panel.  The
full files (for, rh, the right hemisphere) usu.
have one of the following forms:

Real-Valued  (csurf output, often stats from complex data)

 <stem>-rh.w		generic real data (no infix)
 <stem>_a-rh.w		amplitude of complex _r,_i vector 
 <stem>_b-rh.w		xsub t-stats for power, _a^2, vs. num
 <stem>_c-rh.w		stimfreq_amp/sqrt(sum(noisefreq_amps^2))
 <stem>_d-rh.w		vector dispersion index (0-1)
 <stem>_e-rh.w		xsub Rayleigh pos -log10(p)
 <stem>_f-rh.w		Hagler xsub cpx F-stats from _x, _y
 <stem>_f-rh.w		real or cplx F-stats for single subj
 <stem>_g-rh.w		Hagler xsub cpx F-stats from _r,_i
 <stem>_h-rh.w		xsub cluster-filtered F-stats (_x, _y)
 <stem>_h-rh.w		single subj cluster-filtered F-stats
 <stem>_j-rh.w		TODO: like _h but from _g (vs. _f)
 <stem>_k-rh.w		find_retin_borders vtxwise border cnt
 <stem>_p-rh.w		singsub cplx permutation test -log10(p)
 <stem>_q-rh.w		singsub cluster-filtered _p
 <stem>_t-rh.w		t-stats for ampl, _a, vs. num
 <stem>_%-rh.w 		raw FT amplitude conv. to percent resp
 <stem>.mgh             FSL/freesurfer file (N.B.: no hemi!)
 -----------------------------------------------------
 <stem>f-rh.w		DEFUNCT:signed 1sub F-stat exp(no _)

Real-Valued  (3dDeconvolve output, conv'd to vertex list)

   [vers1, old]
 <cnd>_@LC@_coef-thresh+orig				thresh'd HDR area
 <cnd>_F-stat-clust+orig				clustered F
 <cnd>_t-st-clust+orig				clustered t

   [vers2, current]
 <cnd>_GLT@0_Coef-clust+orig			clustmasked HDRarea
 <cnd>_GLT_Fstat-clust+orig				clustered F
 <cnd>_GLT@0_Tstat-clust+orig				clustered t

Complex-Valued  (csurf phase data)

 <stem>_r-rh.w		phase stats (real), amp=sqrtF
 <stem>_i-rh.w		phase stats (imag), amp=sqrtF
 <stem>_x-rh.w		raw Fourier (real) at stim freq
 <stem>_y-rh.w		raw Fourier (imag) at stim freq

These files contain lists of vertex-number/value
pairs.  These values can be rendered onto any
transformation of a surface (folded, unfolded,
flattened partial patch, etc) that has the same
number of vertices and vertex neighbor lists.

When one of the stems with a complex-component
infix is selected (e.g., _r or _i), the infix is
stripped off because the polar, eccen and twocond
scripts use the infix-stripped stem to read two
files).

The {_i, _ r, _a}, {_x, _y}, and {_f, _h, _p, _c}
files may either be single subject data or cross
subject averages.  The other infixes (_t, _b, _g,
_d, _k) usually signify other cross subject,
second level statistics.

The file here can have one of three data formats
that are auto-detected by the tksurfer function,
read_binary_values:

 .w -- valfile fmt: vtxnum/floatval pairs, maybe vtx subset
 .w -- curvfile fmt: just floatvals, all vtxs, implicit nums
 .mgh -- pseudovol fmt: 1frame, 1D, float, all vtxs

The set of radiobuttons directly to the right of
the Painted VtxList Pref selector allow the the
rendering of multiple extracted sub-briks from a
single scan directory.  The options are:

 one  -- render selected (single) vertex file
 last -- render all vertexfiles from last extract
 all  -- render all vertexfiles (except complex)

When the multiple-render options are clicked, 
the selected vertex file changes to "-multiple-".
The stems of the output rgb files in that case
are the same as the stems of the sub-briks.

StatMask Paintfile

This is the stem (minus hemisphere, and .w
suffix) for files that are generated by one
of the following panels:

  SessionTools -> Calculate 3D Fourier Stats
  SessionTools -> Calculate 3D Rand Block Stats
  SessionTools -> Import 3D Stats
  CrossSessTools -> Cross Sess Sphere Avg

These files may thus contain real-valued
statistics for either single- or cross-subject
amplitude data (the data can be either real- or
complex-valued, see examples above).

These files will be used to mask real- or
complex-valued Paintfile data, but will not be
directly visible as such.  To display/view these
files directly, they can instead be read in as a
Paintfile (see above).

Saved Images Prefix

This is the name of the stem of the bitmap(s)
that will be generated when SURFACE-STATS or
VOLUME-STATS is run.

ResetToDefault

These buttons ("eccen", "polar", "2cond",
"fstat", "real", "fs") reset all the color scale
variables on the panel below to sane defaults for
each experiment type.  These are the values that
intially appear when the panel is first created.

The last button on this line, "cp prev" copies
parameter values from the previously selected
scandir (left column) into the current scandir.
All parameter values below the "ResetToDefault"
line are copied.

Data Type

These five button choose one of five different
types of functions that set the color of each
surface vertex -- "phase", "real", "real+Fmsk",
"real+tmsk", and "fs+msk".

The first button (phase) displays the phase using
color and the significance by modulating the
color saturation.  This is the original
retinotopic color scale.  There are an additional
set of buttons (off/repl/mask/mult) further down
the panel for alternative statistical masks for
complex valued data (see below).  The original
default was to replace the vector amplitude with
the (sqrt F) significance.

The second and third button ("real+Fmsk",
"real+tmsk") perform a double-sigmoid masking of
the visible amplitude (color saturation) of the
data.  The first sigmoid squashes the displayed
amplitude (controlled by fslope/fmid/fthresh in
amplitude units).  The second sigmoid *also*
squashes the displayed amplitude, but now by
considering statfile (F or t) (controlled by
sfslope/sfmid/sfthresh in F or t stat units).  To
squash using only amplitude, set sfmid/sfthresh
to zero; to squash only using the statmask, set
fmid/fthresh to zero.

The last button, "fieldsign+mask", similarly
combines fieldsign (signed) and fsmask (a
geometric average of the eccen and polar
significances).

PhaseMask (SessionTools only - single subject)

When this panel is opened via SessionTools ->
View Functional Data (single subject data), there
will be a line of 3 buttons below "Data Type:"
that control the source of the mask (or if there
is one) for complex-valued single subject data --
"none:sig,amp=sqrtF", "sig+(clust)Fmask", and
"sig+coher".  N.B.: these buttons only affect
complex-valued data ("phase" Data Type).

The first button, "none:sig,amp=sqrtF", means no
mask -- i.e., just control color saturation with
the complex amplitude, which for Paintfiles _r,_i
is the sqrt F and for Paintfiles _x,_y, the raw
fourier amplitude at the stimulus frequency.

The second button, "sig+(clust)Fmask", displays
the Paintfile (subject to the first soft
threshold), but then also does a second soft
threshold by comparison to the surface-based
cluster-corrected F stat (the StatMask
Paintfile).

In this case, the first set (left column) of
entries (fthresh/fmid/fslope) are in signal
amplitude units for the Paintfile.  If the
Paintfiles are _r,_i Paintfile (i.e., complex
amplitude replaced by sqrtF), typical values are
~1-5.  If the Paintfiles are _x,_y (raw fourier
amplitude), typical complex amplitude values will
be 100-300.

The second column of entries immediately to right
of fthresh/fmid/fslope (sfthresh/sfmid/sfslope)
independently modulate the saturation of the
overlay color by making a comparison with the F
mask value at that vertex (e.g., 2-10).

Finally, to use the coherence (instead of F) as a
mask, select "sig+coher" (which will auto-set _c
as a mask).  Note that sfmid/sfthresh values
appropriate for coherence (0.20 to 0.25) are much
lower than for F (2.0 to 10.0)

Clicking back and forth between these three
buttons enables/disables the extra stat threshold
entries, toggles stat mask on/off, auto-sets the
appropriate StatMask Paintfile (if it's there),
puts up a popup to query whether to reset signal
and mask thresholds to sane values.  The last
popup also comes up if "FTamp" (use raw Fourier
amplitude, _x,_Y, instead of sqrtF, _r,_i) is
ticked/unticked.

XSubPhasePhaseMsk (CrossSessTools only)

When this panel is opened via CrossSessTools ->
View SphereAvg Data, there will be a line of 6
different buttons below Data Type that control
the source of the mask for complex valued cross
subject data -- "sig", "cxF-amp", "cxF-sig",
"cxR-ang", "t-sig", "t-pow".  These buttons only
affect complex-valued subject averages ("phase" Data
Type).

The average unmasked amplitude displayed is
either the average of single subject sqrt F if
Paintfiles are _r,_i (orig csurf) or the average
of the single subject raw Fourier amplitude at
the stimulus frequency if Paintfiles are (_x,
_y}.  The first button (sig) means no mask --
i.e., just show average amplitude.

N.B.: as above, the {_r, _i} amplitudes [sqrt F]
are typically in the range of 1-5 while the {_x,
_y} amplitudes are in the range of 100-300, so
fmid has to be adjusted accordingly.

The second (cxF-amp) and third (cxF-sig) buttons
use a complex-valued F mask (Hagler et al., 2007)
calculated either with the single subject raw
fourier amplitude (_f) or the single subject sqrt
F (_g).  The cross-subject statistical units
(second set of slope/mid/thresh entries) in both
cases are raw F's, not p-values.

The fourth (cxR-ang) uses the result of a
Rayleigh test on the phase angle at each vertex
across subjects (Rayleigh R) converted to a
p-value.  Thus, sfthresh/sfmid in this case is in
absolute value of power-of-10 units (e.g.,
sfthresh=2.0 means truncate vertices with p >
10^-2).

The fifth (t-sig) uses a one-sample t-statistic
made by comparing the sqrtF amplitude of a fixed
value (set at compute-time in the Cross Sess
Sphere Avg panel).

The sixth and final (t-pow) uses a t-statistic
made by comparing the F amplitude to a fixed
value (again set at computer-time in the Cross
Sess Sphere Avg panel).

On selecting these buttons (except the first,
sig), the CplxAmpMod is reset to mask, and the
appropriate StatMask Paintfile is looked for,
generating an error if it doesn't exist in the
current directory.

See Help -> New Spherical Average for more
details on how the cross-subject complex-valued
statistical masks (and other indices) are
calculated.

Color Scale ($colscale)

For each data type above, several different color
scales can be chosen.  Csurf saves seven
different colscales that work with the following
data types:

  phase+sig (complex)
    wheel	($colscale = 0)
    [none]	($colscale = 13) (cplx amp)
    lutw	($colscale = 14)
    heat	($colscale = 1)
    bi	($colscale = 4)

  real
    bl/redY	($colscale = 11)
    bl/redW	($colscale = 6)
    lut	($colscale = 12) (real)
    jet	($colscale = 15)

  fieldsign+mask
    fs	($colscale = 9)

Note that colors may be displayed, even if you
chose the wrong color scale.  For example, if you
display real, one-component data with a color
scale designed for complex-valued data, zeros or
junk in the imaginary data field will result
in non-meaningful colors.  Conversely, displaying
complex data with a real color scale will only
show the real component.

Some less common color scales can be found on the
large version of the surfer tools panel ([fn]-F3
in tksurfer interface window; [fn]-F2 to get
back).

Here are the main types of color scales:

  (1) w1: Color Wheel Complex (colscale=0)

  This color scale is designed for complex-valued
  phase-encoded data (e.g., retinotopic mapping).
  The hue represents the phase and the saturation
  represents the strength of the response.

  With integral angle_cycles (1,2,3), the scale
  is red(early)->blu(intermed)->grn(late)
  wrapping around (through orange) back to red.
  This can be used for eccentricity data,
  tonotopy, or somatotopy data or two-condition
  data.  With angle_cycles=1 each phase has a
  unique color.  To compensate for hemodynamic
  delay, angle_offset should be decreased (-0.1
  same as 0.9).  To convert angle_offset into
  seconds, multiply it by the time for one cycle.
  For a thin expanding ring stimulus starting
  from the center, the angle_offset should be set
  to 0.75 to color the central representation
  red.

  With angle_cycles set to a non-integral number,
  there is only one red->blu->grn cycle.  In this
  mode, phase values below red are clamped to red
  and phase values above green clamped to green
  as the phase enters the ipsilateral field.
  Each then fades to gray at mid-ipsilateral
  phases.  The fade ramp extent is set by fadef
  ("fad" in Surfer Tools).  Ipsilateral phases
  can be also be colored yellow (strongest yellow
  at mid ipsilateral) with ipsiyellowfact ("iy"
  in Surfer Tools).

  To completely remove a portion of the phases in
  the red->blu->grn, use truncphase.  The low and
  high truncation limits are adjustable for the
  RH and LH (default: 0.25 to 0.75; variables:
  truncphasemin and truncphasemax).  For
  non-integral angle_offset between 1 and 2,
  there is an additional 1/6 of a cycle offset
  not seen with angle_offset between 2 and 3 (the
  original design target).  Thus, these pairs
  will color phases (in the first cycle)
  equivalently:

             angle_cycles  angle_offset
  --------------------------------------
  integral       1.0             0.0
  non-int.     1.0001          0.1666
  
  integral       2.0             0.0
  non-int.     2.0001          0.0
  --------------------------------------

  With angle_cycles set below 2.0, this scale can
  be used for eccentricity, tonotopy, or
  somatotopy data as well.  The color scale will
  fade to gray at the wrap around point.

  To see relatively only moderately strongly
  activated regions with default sqrtF, set fmid
  to 1.5 (F=2.25), fslope to 1.5, and fthresh to
  0.3.  If the absolute threshold (fthresh) is
  kept low, fmid can be used to adjust the
  effective threshold without introducing
  artifactual edges.

  The units of fthresh and fmid are the same;
  fthresh is a hard threshold and fmid is a soft
  threshold.  Setting fthresh equal to fmid will
  truncate the sigmoid tanh curv controlling
  color saturation to the background gray in the
  middle most-rapidly changing part of the tanh
  sigmoid.

  It is difficult to represent the full range of
  exact values of phase using color alone; a
  large number of colors are hard to parse, while
  fewer, easier-to-parse colors (as here) do not
  represent phase finely enough.  A fine-grained
  representation can be obtained by running the
  phasemovie.tcl script (in tksurfer "tcl:"
  dropdown).  This steps through each phase
  (total number of steps adjustable), drawing a
  white contour line for a small range of phases
  (width of phase range is adjustable).  With
  invphase and revphase off, the white phase
  marker progresses from regions responding best
  to the beginning of each stimulus cycle toward
  regions responding to the end of the cycle.

  Mapping stimuli that start horizontal

  For a counter-clockwise rotating polar angle
  stimulus that starts at the right (zero deg),
  the default settings for Phase/Rev,Offset in
  the View Functional Data panel are (ignoring
  hemodynamic delays):

  Phase/Rev,Offset: [ ] "RH" 0.0   [x] "LH" 0.5

  Note that the offset for the right hemisphere
  is zero when the stimulus starts in the right
  hemifield, which is counterintuitive, but,
  unfortunately now conventional.

  These settings result in brain regions
  representing the contralateral upper field
  being colored red, brain regions representing
  the contralateral lower field colored green,
  and the brain regions representing the
  contralateral horizontal meridian colored blue,
  in *both* hemispheres.

  These settings need to be adjusted if the
  stimulus not counter-clockwise, start right.
  For example, for a *clockwise* rotating polar
  angle stimulus that also starts right, reverse
  the opposite hemisphere:

  Phase/Rev,Offset: [x] "RH" 0.0   [ ] "LH" 0.5

  For a counter-clockwise rotating stimulus that
  starts on the left, use RH offset=0.5 and LH
  offset=0.0, and so on.

  Mapping stimuli that start vertical

  For a clockwise rotating polar angle stimulus
  that starts at the *top* (e.g., a stimulus that
  first enters the top right hemifield or the top
  right side of the face), you have to add a
  quarter cycle to the values above.  Since one
  hemisphere is reversed, the quarter cycles make
  the angle offsets the same for both hemispheres
  (again assuming no hemodynamic delay).

  Phase/Rev,Offset: [x]"RH" 0.75  [ ]"LH" 0.75

  If a clockwise stimulus starts at the bottom,
  then the offsets should both be set to 0.25

  The included program "wheel" is an interactive,
  standalone program that renders a color disk or
  rectangle (which additionally shows the effect
  of fthresh and fmid on the y-axis) that can be
  controlled by the same parameters as the
  eccen/polar color wheel scale (fthresh, fmid,
  fslope, angle_cycles, angle_offset, offset,
  cvfact, fadef, ipsiyellowfact).  Start it like
  this:

    wheel <0-3> [opts]

  and adjust rendering parameters with F1-F12 or
  by adding command line options (for help, type
  "wheel" without arguments).  The same code is
  used to draw the color wheel/disk inset.

  Pseudocode for non-integral angle_cycles:
    find amplitude from real/imaginary trunc
    if stat{repl,mult}ampflag, replace,multiply
    if mask, if stat below fthresh, backgrnd col
    else     if amp below fthresh, backgrnd col
    non-trunc'd amplitude through sigmoid
    find phase from real/imag in -0.5 to 0.5
    if reverse => take negative of phase angle
    if inverse => add 0.5 to phase angle
    subtract angle_offset from phase angle
    fmod/add-1-to-neg => phase back in 0-1
    if truncphase => zero outside bounds
    subtract 0.5 from phase angle
    multiply phase angle by angle_cycles
    if less than -1/3 => red fade to gray
    if less than 0    => red to blue
    if less than 1/3  => blue to green
    greater than 1/3  => green fade to gray
    ipsi fade to gray control: fadef (def=0.7)
    low amps fade into two background grays

  (2) w2: GBRY Color Wheel Complex (colscale=8)

  This color scale is designed for complex-valued
  phase-encoded data (e.g., retinotopic mapping).
  The hue represents the phase and the saturation
  represents the strength of the response.

  Color smoothly changes across 360 deg from:
  green -> blue -> red -> yellow.

  (3) w4: Fred Tonotopy Color LUT (colscale=18)

  This color scale is designed for complex-valued
  phase-encoded tonotopy data.

  (4) lutw: Look-Up Table, Complex Phase (colscale=14)

  Read arbitrary phaseval->RGB color lookup
  table.  For automatic read, put file named
  "val2rgb.lut" in current scandir.  This scale
  requires that complexvalflag is set ("cpx").
  The format of the ASCII lookup table is:

    # comment
    phaseval1 red green blue
    phaseval2 red green blue
    ...

  where the phaseval's are in ascending order
  (not necessarily evenly spaced), and 0-255 for
  red/green/blue.  If interpolatelutflag is set
  ("intplut"), then the r,g,b's are linearly
  interpolated for intermediate phaseval's, else
  the colors stay the same to halfway to the next
  phaseval in the lookup table.

  This color scale expects the phasevals to be in
  the range of 0-1 and expects them to wrap
  around (interpolating around the wrap point if
  "intplut" ticked).  If rgb2val.lut doesn't
  exist, a default version (for real, eccen, or
  polar data (depending on current setting of
  "Reset To Default") will be created.

  (5) heat: Heatscale Complex (colscale=1)

  The heat color scale requires complex-valued
  fourier-analyzed data.  It runs from dark brown
  to white and displays any brain region
  significantly activated in a periodic fashion
  (i.e., all phases).  Truncphase can be used to
  truncate half of the phases and angle_offset
  controls the exact half that are truncated.
  The angle_offset for two condition expt with
  20s ON and 20s OFF should be something like 0.1
  (this is in units of one cycle: 0.1 * 40 sec =
  4 sec delay).

  (6) bi: Red/Green Complex (colscale=4)

  The red/green bipolar scale requires
  complex-valued Fourier-analyzed data as well.
  This scale is for displaying the results of a
  two-condition experiment.  It divides the
  phases into two halves, colored red and green,
  with the boundary between half red and half
  green settable with angle_offset ((0-Pi is red,
  Pi-2Pi is green).  At fslope=1.0, the color
  saturation of each phase is approximately the
  sine of the phase angle:

    y = tanh(fslope*(phaseangle -   0)) *
       -tanh(fslope*(phaseangle -  Pi)) *
       -tanh(fslope*(phaseangle - 2Pi))

  Thus, phases near the boundary between red and
  green will fade to gray, and full saturation
  will only be reached at a phase of Pi/2 and
  3Pi/2.  With fslope > 10, all the colors in
  each half of the phase wheel will be almost
  fully saturated.

  To use colors other than red and green for the
  two phase ranges, open the large version of the
  surfer tools panel ([fn]-F3; [fn]-F2 to get
  back) and set r,g,b values in the 6 entries
  just below the colscale buttons headed "col1"
  and "col2" (plus <Return>).

  (7) BRy: Blue/Red->yellow/cyan (colscale=11)

  This scale is designed for real-valued, signed
  (e.g., two-condition) amplitudes or statistics.
  This scale can be truncated with truncphase and
  reversed with invphase (surfer tools).

  Unlike any of the complex-valued color scales,
  (where the units of fthresh and fmid are the
  same) fthresh and fmid here control different
  parts of the range of colors.  There are two
  'knobs'. The first is fthresh, which controls
  the data value at which red fades into the
  background gray, and the negative of fthresh
  controls the negative data value where blue
  fades into the background.  The second is fmid,
  which controls data value above which red
  transitions to yellow, and the negative of
  fmid, where blue transitions to cyan.

  The scale bar color transition points are:

    threshold        = fthresh
    full red/blue    = fthresh + fmid
    full yellow/cyan = fthresh + fmid + 1/fslope

  (N.B.: if used with complex data, this scale
  will only display the real component.)

  (8) BRw: Blue/Red->white (colscale=6)

  This scale is designed for real-valued, signed
  (e.g., two condition) amplitudes or statistics.
  Positive data is red and negative is blue.
  Reversible with revphaseflag.  As the absolute
  value of the data increases, scale goes to
  white for both positive and negative
  correlations.  Not affected by angle_offset,
  angle_cycles, invphase. (N.B.: if used with
  complex data, this scale will only diplays the
  real component.)

  Unlike other color scales, the sense of fmid is
  reversed -- turning fmid up makes the
  representation of a given data value move *up*
  the color scale (toward white).

  (9) fs: Fieldsign (colscale=9)

  This binary color scale is designed for field
  sign data only.  Yellow is mirror-image field
  sign and blue is non-mirror-image fieldsign.
  Reversible with revphaseflag.

  (10) lut: val->RGB look-up table (colscale=12)

  Read arbitrary val->RGB color lookup table,
  typically in current scandir (val2rgb.lut).
  This is designed to color a single real value.
  The format of the ASCII lookup table is:

    # comment
    val1 red green blue
    val2 red green blue
    ...

  where the val's are in ascending order (not
  necessarily evenly spaced, negative val's OK)
  and the red, green, and blue are 0-255.  If
  interpolatelutflag is set ("intplut"), then the
  r,g,b's are linearly interpolated for
  intermediate val's, else the colors stay the
  same to halfway to the next val in the lookup
  table.

  (11) jet: MATLAB Jet (colscale=15)

  The MATLAB Jet colscale: dark-blue -> blue ->
  cyan -> yellow -> red -> dark-red (flip with
  invphase).  For signed or unsigned real data,
  or complex amplitude.  Endpoints of scale
  (clamped) set using left and right entries
  under truncphase.

  Extreme values are dark, so best adapted to
  full rank data (near zero will be light
  yellowish-green).  Responds to fthresh/sfthresh
  (absolute-value of hard thresh to background
  curvature), fmid/sfmid (absolute-value of fade
  to background curv), and fslope/fslope, so for
  completely unthresholded with full color
  saturation, set fthresh and fmid to 0.0.

  If complex data has previously been read onto
  the surface, the complex amplitude will be
  displayed and the endpoints of the scale set to
  ($fthresh, $fmid*4).

  (12) vd: CARET Videen-Style (colscale=17)

  For real data (signed or unsigned) or complex
  amplitude.  Like the MATLAB Jet scale,
  endpoints of scale controlled by bottom and top
  values in unmarked entries under truncphase
  button.   Data values outside that range
  clamped to end colors.  Negative entries OK.
  Left entry should be smaller than right.

  Bottom of color scale can be truncated (allows
  BG gray(s) to show through) with fthresh.
  N.B.: set fthresh negative to avoid truncating
  signed data.  No effect of fmid and fslope.

  If the colorscale is interactively changed to
  this one interactively in tksurfer, the end
  ($truncphasemin, $truncphasemax) will be reset
  to 0-1, but can then be interactively adjusted.
  Once "vd" has selected in csurf, the saved
  'TrnPh' limits entered in the csurf panel
  will be respected on next tksurfer startup.

  If complex data has previously been read onto
  the surface, the complex amplitude will be
  displayed and the endpoints of the scale set to
  (0.0, $fmid*4).

Smoothing (of overlay data, stat mask): Surface-based

The first entry on the "Smooth: Surf(val,stat)"
line controls how many nearest-neighbor smoothing
steps are done on the val(,val2) data before
surface display of overlay data in tksurfer.  The
second entry controls smoothsteps on the stat
mask (if present). These smoothing operations are
performed on the finer mesh of the surface, not
on the coarser mesh of the functional scan.  To
see the effects interactively, use the surfer
tools SMOOTH button with the radio button set to
'val'.  If the data is complex, both components
will automatically be smoothed.

The unlabeled tickbox immediately to the left of
the first smooth steps entry toggles the tcl
variable, $cpxangrealampflag, which switches
between two different smoothing functions.  If
unticked (default), the the standard vector
average of complex values of the center point and
its neighbors is used (C/tcl funct: smooth_val).
If ticked, an alternate function that ignores
vector dispersion is used instead (C/tcl funct:
smooth_complexang_realamp).  That function
ignores vector dispersion by averaging complex
angles, but real-valued amplitudes.  To
interactively use it, select smooth type "cr" on
large F3 panel (or middle click the "val" radio
button).

An empirically derived correspondence (Hagler et
al., 2006) between the number of smoothing steps
using the C/tcl function smooth_val (using
surfaces reconstructed from 1 mm^3 struct scans)
and the average full-width-at-half-max filter
result starting with a single non-zero vertex is:

  steps   FWHM (mm)
 --------------------
    5      2.22
   10      3.20
   20      4.49
   30      5.36
   50      6.99
   70      8.31
  100     10.15
  230     ~1.5 cm
  400     ~2 cm
  900     ~3 cm
 --------------------

A power function fit to this empirical map
(r^2 = 0.9987) is:

  fwhm = 0.9921 * steps^0.5018

Smoothing (of data/stat overlay): 3D Gaussian

The entries to the right of "3D(cells,fwhm)"
control the width of the 3D Gaussian smoothing of
3D overlay data in tkmedit (VOLUME-STATS).  This
type of smoothing does not interact in any way
with surface smoothing just described.

The first entry (must be an odd number) is the
number of cells in the Gaussian kernel, in
voxels.  The second floating-point entry, fwhm
(should be smaller than first number) is the full
with at half maximum of the smoothing kernel,
again in voxels.  For no 3D smoothing, Set the
second entry to 0.0.

The 3D smoothing specified here is implemented on
first display by VOLUME-STATS.  After startup,
the equivalent fields in tkmedit will be reset to
the default gentle smoothing (5 cells, 1.5mm
fwhm) regardless of the settings here.

Statistical Contrast ($fslope, $sfslope)

The "Contrast: DataAmpli.,StatMask" entries
control the steepness of the thresholding sigmoid
(or a double sigmoid in the case of two-ended
color scales).  Larger values make the color
scales ramp more rapidly for a given change in
data/stat amplitude.  At a steep slope of
fslope>10, the effect of fmid (the soft
threshold) is essentially the same as fthresh,
the hard threshold.

The second entry has a similar function except
that is is in statistical mask units.  It will be
grayed out for color scales that have no separate
statistical mask file.

Statistical Midpoint ($fmid, $sfmid)

The "Midpoint: DataAmplitude,StatMask" entries
set the location of the fastest rising part of
the sigmoid (or of a double sigmoid for two-ended
scales).  These are used to set an effective
threshold, but with a smooth fall-off into the
background color.

The second entry has a similar function except
that is is in statistical mask units (e.g.,
F-ratio).  It will be grayed out for color scales
that have no separate statistical mask file.

CpxAmpMod (only affects complex-valued data)

These buttons (off,repl,mask,mult) select whether
the amplitude of complex data is modulated by a
separate stat file -- a third vertex-wise value
read into the .stat field.  The stat file is
loaded automatically by this panel, but can also
be manually loaded using tksurfer tools panel as
follows:

  select stat wfile from "val:" dropdown
  R    (read: to .val field)
  [optionally SMOOTH]
  S/V    (swap .stat and .val)
  select real (or imag) wfile from "val:" dropdown
  R    (read: both real,imag given either)
  [optionally SMOOTH]

or by explicit commands in a tcl script:

  # stat (read to .stat field)
  set val <path-of-stat-wfile>
  read_binary_values
  smooth_val <smoothsteps>
  swap_stat_val
  # imaginary (read to .val2 field)
  set val <path-of-imaginary-wfile>
  read_binary_values
  smooth_val <smoothsteps>
  swap_val_val2
  # real (read to .val field)
  set val <path-of-real-wfile>
  read_binary_values
  smooth_val <smoothsteps>

If the "off" button is selected, no modulation is
done (e.g., for original freesurfer
complex-valued data that had amplitude replaced
by sqrt F).  If "repl" is selected, the data
amplitude is replaced by the vertex-wise values
from the stat file.  If "mask" is selected (the
most useful), the second set of entries (sfslope,
sfmid, sfthresh) apply a second sigmoid
modulation of the color saturation based on the
stat value (sfslope/sfmid/sfthresh units are stat
value units, whatever they may be -- e.g., F, t,
or power-of-ten-p-value).  Finally, if "mult" is
selected, the data amplitude is multipled by the
vertex-wise stat file value.  In each case, the
data *phase* is unaffected.

Hard Thresholds ($fthresh, $sfthresh)

The "(fthresh,sfthr.)" entries set the hard
cutoffs (to background surface color).  For
complex valued color scales the units for
$fthresh and $sfthresh the same as for $fmid and
$sfmid, respectively.

For some real-valued scales (e.g., BRy), $fthresh
sets the data value where the displayed color
rolls off to background gray, while $fmid sets
the red->yellow and blue->cyan transition points.

For real or complex-valued scales where a
statistical mask will be used (CplxAmpMod "mask"
selected), the second fthresh entry will be
enabled.  This performs a second hard threshold
if the *stat* value is below the setting in the
second entry.  The second threshold is typically
in units of raw F (or t).

TruncFS ($nonbinaryfsflag)

If "TruncFS" ($nonbinaryfsflag), is ticked,
near-zero *fieldsign* values are faded to
background gray, as controlled by $fsslope ("sl"
entry in surfer tools).  The nonbinaryfsflag is
the unlabeled checkbox to the left of the "sl"
entry in surfer tools.

Ipsi Fade, Ipsilateral Yellow ($fadef, $ipsiyellowfact)

The "fadef:" entry controls the speed at which
ipsilateral phases smoothly approach background
surface grays.  This only affects non-intergral
$angle_cycles color scales that are designed for
polar angle stimuli should mainly generate
activity for 50% of a stimulus cycle (there
should be less/no activity when the stimulus is
in the ipsilateral visual field).

The "ipsiyel:" entry changes the ipsilateral
phase 'fade' target from the default gray to
various amounts of yellow (maximum yellow will be
opposite maximum blue -- see effects in color
scale disk inset).

Angle Cycles ($angle_cycles)

Integral values for the color wheel cycles cause
the color wheel of phases to wrap around one or
more times while non-integral values cause there
to be exactly one cycle through the color wheel
with phases off the ends clamped to the ending
color (see 'Colwheel' above).

Angle Offset ($revphaseflag, $angle_offset)

A $revphaseflag and an $angle_offset can be saved
independently for the two hemispheres.  These
affect which colors are displayed for which
phase.  Both of these are only relevant for
complex-valued color scales (colwheel=w1/w2/w4,
heat, bi).

The (unlabeled) $refphaseflag tickbox reverses
the color wheel -- e.g., to accomodate reversed
stimulus order such as clockwise vs.
counterclockwise polar angle rotation, or left
vs. right hemifield order).

The $angle_offset rotates the color wheel --
e.g., to account for hemodynamic delay.  The
$angle_offset value ranges from 0.0 to 1.0,
where 1.0 equals the time for one stimulus cycle
-- e.g., an angle_offset of 0.02 with a 64 sec
cycles corresponds to a time offset of 0.02 * 64
= 1.28 seconds.  The (uneditable) entry to the
far right of this line shows the $angleoffset
that is equal to 1 sec.

InvPh + TrnPh + Sft + 2 RH + 2 LH entries

The "InvPh" button ($invphaseflag) adds pi to the
time course: f(t) -> f(t+pi).  This contrasts
with the previously described Rev tickboxes
($revphaseflag), which reverses the time axis:
f(t) -> f(-t).

The "TrnPh" button ($truncphaseflag) uses limits
(possibly wrapped), set separately for left and
right hemispheres (4 entries to right).

The "Sft" ($softtruncphaseflag) has linear ramps
(which themselves may wrap) beyond the truncphase
limits, instead of a hard cutoff.  The width of
the ramp is set by the tcl var $softtruncwidth
(def=0.05 which is 5% of a cycle).

For the standard color wheel, the order of all
the operations mentioned is:

  f = sqrt(r*r + i*i);            /* get complex ampl */
  a = atan2(r,i)/(2*M_PI);  /* phase: -0.5 to 0.5 */
  if (revphaseflag) a = -a;
  if (invphaseflag) a += 0.5;
  a -= angle_offset;
  a = fmod(a,1.0);             /* -1 to 1 */
  if (a<0.0) a += 1.0;         /*  0 to 1 */
  if (truncphaseflag) {
    /* f=0.0 beyond limits, maybe wrapped */
  }
  if (softtruncphaseflag) {
    /* linear ramp to 0.0 (maybe wrapped) beyond limits */
  }

where f=0 allows the background color to show
through completely, and where r and i are the
real and imaginary components of the phase vector
(amplitude is e.g., sqrt F) read from wfiles
output by fourier.

Checkbuttons (cpx,FTamp,mm,scl,cv,intp,bot,sym)

 cpx	complex val data ($xomplexvalflag, usu. autoset)
 FTamp   disp raw Fourier transform amp vs. sqrtF
 mm	turn on millimeter scale ($scalebarflag)
 scl	turn on color scale inset ($colscalebarflag)
 cv	turn on background curvature grays ($surfcolor=1)
 intp	interpolate opt. color LUT ($interpolatelutflag)
 bot	LUT entries set col bott vs. cent ($botedgelutflag)
 sym	two-sided (pos/neg) thresh ($zerosymmfadeflag)

These can be controlled from tcl using the
variables listed above.

Views

These buttons select which views will have a
bitmap saved for them when SURFACE-STATS is
clicked.  The 'cust' view (custom) is a special
case.  Clicking it will expose an additional 12
fields than can be used to define a custom view
for each hemisphere.  If this is done for the
current scan dir, the next scan dir that is
defined as a "Render Stats Dir" will
automatically start with the current 'cust'
values. The transformations listed are applied
left to right.

3D and Flat Tcl Scripts

These tcl scripts control the startup of the
surfer tools.  These scripts are found in
FreeSurfer/lib/tcl/*.tcl.  For retinotopy, use
eccen, polar, and fs.  For phase analysis of two
condition, use eccen or twocond.  For real-valued
data read in from external programs (e.g.,
correlation coefficients), use real.

To convert standard sqrt-F fmid to p in MATLAB:

  fmid = 0.0:0.1:5.0;
  plot(fmid, -log10(1-fcdf(fmid.^2,sdf,ndf))

where sdf and ndf are signal and noise degrees of
freedom.  Here is a fmid -> neg-exponent-of-p
table for sdf=2 and ndf=245:

sqrtF
fmid	F	neg exp p
-------------------------------
0.5	0.25	0.1085
0.6	0.36	0.1561
0.7	0.49	0.2124
0.8	0.64	0.2772
0.9	0.81	0.3506
1.0	1.00	0.4325
1.1	1.21	0.5229
1.2	1.44	0.6217
1.3	1.69	0.7289
1.4	1.69	0.8445
1.5	2.25	0.9683
1.6	2.56	1.1003
1.7	2.89	1.2405
 ============== 1.3000 => p=0.05
1.8	3.24	1.3888
1.9	3.61	1.5451
2.0	4.00	1.7094
2.1	4.41	1.8816
 ============== 2.0000 => p=0.01
2.2	4.84	2.0615
2.3	5.29	2.2492
2.4	5.76	2.4445
2.5	6.25	2.6474
2.6	6.76	2.8577
 ============== 3.0000 => p=0.001
2.7	7.29	3.0754
2.8	7.84	3.3003
2.9	8.41	3.5325
3.0	9.00	3.7717
3.1	9.61	4.0180
3.2	10.24	4.2711
3.3	10.89	4.5309
3.4	11.56	4.7975
3.5	12.25	5.0706
3.6	12.96	5.3502
3.7	13.69	5.6361
3.8	14.44	5.9283
3.9	15.21	6.2266
4.0	16.00	6.5309
4.1	16.81	6.8412
4.2	17.64	7.1572
4.3	18.49	7.4789
4.4	19.36	7.8062
4.5	20.25	8.1389
4.6	21.16	8.4770
4.7	22.09	8.8203
4.8	23.04	9.1687
4.9	24.01	9.5221
5.0	25.00	9.8804
-------------------------------

The noise degrees of freedom (245) are 256
frequencies (positive and negative) minus real
and imaginary at the stimulus frequency minus the
amplitudes of the nuisance frequencies, which are
defined by fourier.c as the 3 lowest frequencies
(assumed to be movement), one frequency above and
below the stimulus frequency, two higher
harmonics of the stimulus frequency, and one
frequency above and below each harmonic.

For 512 TRs instead of 256, the p-values are
slightly more significant for a given fmid.
Here are the increments in -log10(p):

  fmid=1.75: -log10(p): 1.3 => 1.31
  fmid=2.15: -log10(p): 2.0 => 2.02
  fmid=2.65: -log10(p): 3.0 => 3.04

Converting phase-encoded responses to percent

There are three ways in csurf to obtain percent
response measures from Fourier transformed
timecourses (described in more detail in
the relevant R-click helps):

(1) single vertex:

  First, load the 3D _x,_y Fourier transform data
  BRIKs.  To do this, click "val:" label to
  change it to "val3d:".  Then select _x (or _y)
  BRIK from dropdown and click "R" (will read
  both, given either).  Finally,
  ctrl-middle-click a vertex to see the
  timecourse and look in the csurf log for
  percent response.

(2) avg percent response across a label

  Find or make a label.  Then load the 3D _x,_y
  Fourier transform data BRIKs as above.
  Finally, shift-left-click "T" on "label:" line
  and find percent resp in log and on final
  popup.

(3) vertexwise percent 

  First load 3D rawdata time series
  (ctrl-middle-click on any surface vertex will
  auto-load the rawdata timecourse).  Then load
  2D _x,_y Fourier transform data wfiles by
  selecting the _x (or _y) wfile on the "val:"
  line dropdown and clicking "R" (will read both
  given either).  Finally, middle-click "W" on
  the "val:" line to get FOURIER TO PERCENT
  RESPONSE popup, and click:

    COMPUTE AVG t-SERIES EACH VTX

  to average the timecourse at each voxel, and
  then:

    COMPUTE PERCENT RESP
    
  to display vertexwise percent and also write
  out vertexwise percent a wfile with a _% infix.
  If no rawdata is available (e.g., cross subject
  phase average), enter the skip the first step
  and enter the average brightness and number of
  timepoints.


####################
fsavg
####################

-------------------------------------------
left-click: re-sample current scan to fsaverage
-------------------------------------------
middle-click: re-sample to opp hemi (IN PROG)
-------------------------------------------
shift-middle-click: re-samp to another subject
-------------------------------------------


Detailed Description of Label "fsavg" Actions

The "fsavg" checkbutton is only present on the
single-subject View Functional Data panel (not on
the View SphereAvg Data panel).

-------------------------------------------
Left-click
-------------------------------------------

Left-clicking the "fsavg" checkbutton at the top
right before clicking SURFACE-STATS will cause
the current paintfile (and optionally the
statmask paintfile) to be resampled onto the
icosahedral fsaverage surface (resampled
paintfiles will have an "fsavg-" prefix), and
then displayed on one of those surfaces.

This is one-time operation (checkbutton
auto-unclicks itself after each SURFACE-STATS
use).  To display on an fsaverage surface or
patch type not present in dropdown for current
subject (e.g., inflated_avg) type into "surface:"
or "patch:" entry and hit <Return>.

Note that the re-sampled *.w files *cannot* be
directly re-displayed on the current subject.  To
re-use them (e.g., to save rendering parameters
for them), move/copy the re-sampled *.w files
into a new scandir within a new Functional scan
session that is set up to display on subject
fsaverage.  For example:

  File -> New Functional
    [create new empty session dir]
    [link session dir to subject fsaverage]
  cd $newsession/image
  mkdir marty2fsavg-scan1
  [copy resampled *.w files into there]
  SessionTools -> Setup Align/Funct
    [click FUnct Scan Dir]
    [just Save/Close -- leave entries blank]
  SessionTools -> View Functional Data
    [clicke Render Stats Dir]
    [set up display parameters]
    [SURFACE-STATS]

-------------------------------------------
Middle-click (alternate)
-------------------------------------------

IN PROG: resample to opp hemi
IN PROG: resample to opp hemi

-------------------------------------------
Shift-middle-click (alternate2)
-------------------------------------------

Shift-middle-clicking the "fsavg" checkbutton
before clicking SURFACE-STATS works like a left
click, except that a second re-sampling is
performed:

  current subject -> fsaverage -> another subject

This will pop up a small panel to allow selecting
another subject in the current SUBJECTS_DIR onto
which to sample the data.

Note that the re-re-sampled files *cannot* be
directly re-displayed on the current subject.  To
re-use them (e.g., to save rendering parameters
for them), move/copy the re-sampled *.w files
into a new scandir within a new Functional scan
session that is set up to display on the subject
that the files were resampled to.  For example:

  File -> New Functional
    [create new session dir]
    [link session dir to subject claudia]
  cd $newsession/image
  mkdir marty2claudia-scan1
  [copy resampled *.w files into there]
  SessionTools -> Setup Align/Funct
    [click FUnct Scan Dir]
    [just Save/Close -- leave entries blank]
  SessionTools -> View Functional Data
    [clicke Render Stats Dir]
    [set up display parameters]
    [SURFACE-STATS]

####################
viewscandirs
####################

-------------------------------------------
 The SessionsTools -> View All Scandirs menu
 provides a quick way to browse the entire set of
 scan dirs in the current functional dir.
-------------------------------------------
Choosing View All Scandirs makes a popup that
contains all the previously configured scandirs
in the current FUNCTIONALS_DIR.  This may take a
second or two.

The scandirs are sorted by subject (with a note
if the subject was not found in the current
SUBJECTS_DIR).  The sessions for each subject are
then arranged alphabetically.

Quick scandir access

Double-clicking a scandir opens the View
Functional Data panel for the session that
contains it, and renders activations onto the
currently selected surface with currently saved
parameters.

If a surfer tools panel is already open, you have
to do two double-clicks on a new scandir to close
the currently rendering (and its surfer tools)
and to open a new one.

Double-clicking a session just opens the the View
Functional Data panel without rendering
anything.

####################
batch
####################

-------------------------------------------
 SessionsTools -> Run Batch Process runs
 through each SessionTools panel that is
 currently configured and presses the action
 buttons at the top right to re-perform the
 actions of the panel.
-------------------------------------------
Once an initial analysis of the data has been
performed, it is often necessary to re-run parts
of the analysis.  The Run Batch Process panel
automates this.

On the first pass through the analysis, each
panel is manually configured and action buttons
are pressed to generate data files.

The Batch Process panel is used to redo all or
parts of the analysis.

Examples

1) If motion correction is redone (e.g., using
   a different TR), all actions on all the
   subsequent panels need to be redone.  In this
   case, select all the boxes in the BATCH
   PROCESS panel.

2) If the FUNCT=>STRUCT registration is touched
   up, select Paint Surface, Calculate Surface
   Stats and Run Rendering Panels.

3) To use a different delay in the Fourier panel
   (affect F-stats), select Fourier and all
   following boxes

The Batch Process panel actually opens the
individual panels and presses the button, so you
can see the individual steps that are performed.
To skip a directory, Unset it (the previously
saved configuration will be retrieved if you
re-declare the directory).

The Batch Process Panel Saves Bitmaps

The one difference between running actions using
Batch Process and actually clicking the buttons
is that on the View Functional Data panel, the
bitmaps you have configured (Views: radio buttons
near the bottom of the panel) will actually be
saved into the <session>/image/rgb directory.

Run Each Panel Manually the First Time

It is currently not possible to run Batch process
initially because some files and directories
needed for configuring subsequent actions won't
yet exist the first time through the analysis.


####################
viewrgb
####################

-------------------------------------------
 The SessionsTools -> View Save Funct Bitmaps
 provides a quick way to browse save images
 for the current session
-------------------------------------------
shortcut: Cmd-b (Mac), Alt-b (Linux)

This pops up a list of saved bitmaps (usu.
tiffs) currently saved into the default bitmap
directory for the current session:

  $FUNCTIONALS_DIR/<session>/image/rgb

After picking one or more images:

  one:   click it
  some:   click drag
  all:   Cmd-e (Mac), Alt-e (Linux) selects all
  toggle:   Ctrl-click to select/deselect

click OK to open them in nmovie, a tiff and rgb
viewer.  Click-drag right and left (or arrows) in
the window (or use arrows) to scroll through the
images, or use space bar to run as a movie (N.B.:
use mpeg_play to play mpeg's).  Here is the
nmovie usage:

Use: nmovie [opts] <img1> [<img2> ...]

  [play tiffs/rgbs as movie]

  L-click, space bar:    stop/start movie loop
  hor. L/R-click-drag:   stop, scroll imgs
  L/R arrow keys:        stop, scroll imgs (don't wrap)
  up/down arrows:        change framerate (init: 15 fps)
  curr image filename:   in window title

 Options:

   -scale <~1.0-3.0>     (-s) scale movie (def=1.0)
   -redrawframes <n>     (-f) redraws per frame (def=4: 15fps)

 Input Formats:

   tiff: (suffix: *.tiff, *.tif, *.TIF, *.TIFF)
   rgb: (suffix: *.rgb, *.sgi, *.RGB, *.SGI -- color,nonRLE)

####################
makenewsphavg
####################

-------------------------------------------
 The File -> New Spherical Avg menu creates a
 new blank directory to hold a cross-session
 cross-subject spherical average
-------------------------------------------
This is the first step in making a cross-subject
spherical average.  The structure of the
directory and subdirectories is nearly identical
to that of a functional session directory.
The only difference is that a Spherical Average
directory can only contain one scandir.

When the new spherical average session is made,
it prompts you to find a subject somewhere
that will be used to display the average data.
The subject must exist somewhere.  This linkage
is saved in a file, "name", inside the session
directory containing only the SUBJECTS_DIR
directory name of the subject (e.g., johns).

The display subject can be easily changed later
on the CrossSessTools -> Cross Session Fourier
Average panel.


####################
setupsphavg
####################

---------------------------------------------
 The CrossSessTools -> Cross Sess Spherical Avg
 menu creates cross-session, cross-subject
 complex- or real-valued averages and stats using
 spherical morph surfaces.  Can also perform
 *volume* avg/stats on complex-valued data.
---------------------------------------------
Before running these commands, use File -> New
Spherical Avg to create a new empty cross-session
session.

The SPHEREAVG button samples complex-valued data
(real and imaginary) from each individual
subject's morphed sphere ($hemi.sphere.reg) to
the canonical icosahedral sphere (7th icosahedral
sub-tessellation) surface.  It then averages the
components in this common coordinate system and
calculates a dispersion index.  Finally, it
calculates a (scalar) cross-subject F-ratio from
the complex data.

The AVGSURF button generates an fsaverage-like
average surface from the current set of subjects.
This button can be skipped if you only intend to
display average data back on individual subjects,
or the standard MGH average surface, fsaverage.

The SAMP2SUBJ button resamples all the cross-subj
average data back onto an individual subject's
morphed sphere (sphere.reg, which allows that
data to be displayed on any of that subject's
surfaces).  The sample-back display subject can
also be set to "fsaverage" (the MGH average
surface), or to an average of the current
subjects make with AVGSURF.

The SAMP2SUBJ button also runs a surface-based
cluster exclusion mask to correct for multiple
comparisons (see description of "F:" and "mm^2:"
fields below).

It can also average and sample-back
single-component (real-valued) data.  In this
case, the only output is the mean and tstat.

The VOLAVG button averages Fourier-analyzed
upsampled stat BRIK's and calculates the
cross-subject F-ratio from the complex data (same
calculation as above).  This requires that (1)
each subject has been first hand-aligned to the
same single structural underlay target, and (2)
registered upsampled real and imaginary stat
BRIKs have been written out using tkmedit (see
below).

This provides a low-level-controllable method of
obtaining complex-valued averages for visualizing
small maps in subcortical structures from high
resolution data (e.g., pulvinar).


--------------------------------------------------
SPHEREAVG -- complex-valued surface avg/stats
--------------------------------------------------
Spherical surface averages (or volume averages)
are performed within a scandir (e.g., "polar12")
inside a session dir (e.g., "130325XS-pol").

Create Average Scandir

Decide upon an informative scandir name, enter it
at the top of the panel, and click Make SphereAvg
Dir to create it.  Currently, there can only be
one cross-session scandir per cross-average
session (don't use "image/prf").

Select data to average

Click the ADD SESS button one or more times to
create blank session configuration lines.  The
DEL LAST button deletes the most recently added
line, whether or not you have altered it.

Then on each line, select Session, Scandir, and
VtListPref in that order from the dropdowns to
select the files to average.  Complex-valued
files typically have _r and _i infixes, which
won't be visible in the dropdown, but which will
be used.

To average single-component, real-valued data
instead, select phasetype "w" at the far right
(instead of the complex-valued ecc/pol/2cn
options).  In this case, only the .w suffix will
be stripped (if this directory contains complex
valued data, the _r and _i infixes of each wfile
will now be visible).

If phasetype is changed to "w" or from "w" in the
middle of configuring the panel, re-select each
Scandir and VtxListPref dropdown to make sure
that valid file choices are shown (single and
double-component data can't be averaged within
one panel).

Normally, each scan to average should be
the same kind of scan (though they may all
have different names).  There is currently no
procedure for reversing the phase (e.g., for
counter-clockwise scans versus clockwise scans),
so the phase direction should be the same for
all subjects (any reversed phase scans should
be first averaged within subjects using one of
the following:

  SessionTools -> Combine 3D Phase Stats
  SessionTools -> Combine Surface Stats

Adjustable parms -- Hemispheres ("hemi:")

First select the hemisphere(s) on which to
operate (right, left or both).  This choice is
saved after the average runs to completion.

Adjustable parms -- Smooth Steps ("smooth2ico:")

This is the number of smoothing steps during the
initial morphed-sphere to icosahedral-sphere
sampling.  The default is 1.  This smoothing is
done *after* resampling (on the isocohedral
surface: -nsmooth-out as opposed to -nsmooth-in).

There is no smoothing on the way back to a single
subject (SAMP2SUBJ) (that is, no additional
smoothing beyond that implied by nearest neighbor
resampling -- see next).  The data can be further
smoothed interactively during display on the
individual subject surface.

Adjustable parms -- Sample Method ("nnfr/nnf")

To sample data onto the target surface, for each
target vertex, the closest vertex in the source
surface is found (this is the forward map).  If
the sample method is set to "nnf" (nearest
neighbor, forward), the sampling is now done.
This, however, can leave some source vertices
unrepresented in target (i.e., 'holes').

If "nnfr" (nearest neighbor, forward and reverse)
is chosen, then each hole is assigned to the
closest target vertex. If a target vertex has
multiple source vertices, then the source values
are averaged together.

The default sampling method is "nnfr".  This
applies in both directions (individual subject ->
icosahedral, and icosadedral average -> display
subject).  This choice does not make much
difference for standard fMRI data.

Adjustable parms -- Phasetype/Colscale

Finally, select the phasetype ("ecc/pol/2cn") at
the far right.  This presets the correct color
scale in the View SphereAvg Data panel ("2cn"
refers to two condition data analyzed by fourier
methods).

If the last option, "w" is selected, all of the
*.w files in the current scandir are shown in
the VtxListPref dropdowns.  This contrasts with
the default situation (ecc/pol/2cn selected)
where only complex-valued data files are shown,
and only one entry is shown per pair of files
(i.e., the the _r and _i infixes are stripped).
Select this option to average single-component
real-valued data.

Adjustable parameters -- t-test comparison value

Numerical value that the sample mean will be
tested/compared against with a 1-sample t-test
("tcp").  The sample mean is typically the
complex amplitude:

  _a = hypot(_r,_i)

which is usually the sqrt() of the single subject
F-ratio.  The default "tcp" value is 0.0

Run Sphere Average

Once every empty scan line is configured, click
SPHEREAVG at the top right to sample each
subject's data onto the spherical (7th
icosahedral sub-tessellation) surface, average it
(complex valued vector average), and calculate
cross-subject (2nd level) statistics.

All the fields on each configured line have to be
filled in before SPHEREAVG will run.  The subject
field can't be edited (it is looked up from what
is found in each $session/image/name file).  The
morphed surface can't be edited either, so the
surfaces $hemi.sphere.reg must exist for every
subject (first run SubjectTools -> Register
Surface for each subject).  The existence of the
8 potential input files for each line are
rechecked (in case they have changed after the
last panel configure):

  $prefix-vreg+orig{_r,_i,_x,_y}-{rh,lh}.w

These include the left and right hemisphere files
for raw real and imaginary Fourier coefficients
at the stimulus frequency (filename infixes: _r,
_i), and the left and right hemisphere files for
the real and imaginary components of complex
significance signal at the stimulus frequency
(filename infixes: _x, _y; phase is same as raw
Fourier coefficients, but amplitude is
sqrt of F-ratio).

If a file is missing, go back to the
Calculate/Paint Fourier Statistics panel and run
FOURIER and PAINT for that scan.

If everything is there, a progress window pops
up, noting when the processing for each input
file has been completed.  The progress window is
reset during each of the 3 passes through the
data described below.

The first pass samples data for each subject onto
the icosahedral spherical coordinate system using
the sphere.reg surface of each subject and
reformats it as a pseudo-image for later
calculations using AFNI utilities.

The second pass calculates component-wise,
cross-subject averages (vector averages) of the
complex-valued data (_r,_i and _x,_y).  It also
calculates a dispersion index (using the _r,_i
data), which is saved as left and right
hemisphere wfiles (paintfiles) with the infix
"_d".  This index is:

          amplitude of vector average
d  =   ----------------------------------
       average amplitude of indiv vectors

This index is 1.0 in the limit of perfectly
aligned vectors, independent of their amplitude
(the _d file is not generated for real-only
data).  It can distinguish a vector average that
was generated by a set of large but inconsistent
signals (lower d) from a same-sized vector
average that was generated by a set of smaller
but more consistent signals (higher d).

The third pass through the data calculates a
cross-subject F-ratio based on the complex
coefficients at the stimulus frequency from each
subject (infixes: _x,_y).

The calculation of the complex F is as follows:

            [xav^2 + yav^2]/2
 ------------------------------------------------
 [Sum(_x-xav)^2)/n + Sum(_y-yav)^2/n] / [2*n-2]

where _x and _y are the raw Fourier coefficients
at the stimulus frequency, xav and yav are the
average of them, and n is the number of subjects.
This is described and demonstrated in Hagler,
Riecke, and Sereno (2007).

Here is an F table for DF-numerator=2 (real,
imaginary) for p<0.05 and p<0.01 with different
DF-denominators (subjects):

	F for	F for
 df	p<0.05	p<0.01
------------------------------
 3	9.55	30.82
 4	6.94	18.00
 5	5.79	13.27
 6	5.14	10.93
 7	4.74	9.55
 8	4.46	8.65
 9	4.26	8.02
 10	4.10	7.56
 11	3.98	7.21
 12	3.89	6.93
 13	3.81	6.70
 14	3.74	6.52
 15	3.68	6.36
 16	3.63	6.23
 17	3.59	6.11
 18	3.56	6.01
 19	3.52	5.93
 20	3.49	5.85
------------------------------

The third pass also calculates a cross-subject
p-value for the null hypothesis that the cross
subject distribution of phases is a uniform
circular distribution, using a Rayleigh test.

The per-vertex calculation of the Rayleigh p from
the Rayleigh R is as follows:

  p = exp(sqrt(1 + 4*n + 4*(n^2-R^2)) - (1+2n))

where R is n times the complex amplitude of the
vector average of the normalized phase angle for
each subject (r/a, i/a).

For convenience, the p value is converted to
-log10(p) so that fthresh is in units of positive
p exponents (i.e., fthresh=2 means p >= 10^-2).

Interrupt

Clicking the purple QuitSPHER button once will
interrupt the process.  This will take a moment,
since the processing (sampling, averaging, format
conversion) for the current file will continue
until it is complete.

Here is a schematic overview of the commands
that are run by SPHEREAVG (minus all the error
checking):

  ## pass1: for each member of average
  foreach subject/hemisphere/_r,_i,_x,_y
    mri_surf2surf -- sample wfile to ico bfloat
    bresize   -- wrap 1D ico bfloat to '2D'
    to3d      -- convert pseudo 2D to BRIK
    3dcalc    -- calc subj-wise sig ampl, _a

  ## pass2: mean-sigF/tstat-sigF/dispersion
  3dttest     -- xsubj avg,ttest (_x,_y,_r,_i,_a)
  3dcalc      -- calculate dispersion index, _d
  brik2bfloat -- conv to folded bfloats
  bresize     -- unfold bfloats

  ## pass3: cmplx-F (_x,_y)(_r,_i), Ray-p (_r,_i)
  3dcalc      -- calculate numerator
  foreach (subject,hemisphere,real/imaginary)
    3dcalc    -- add sq resids to running tots
    3dcalc    -- add normalized _r,_i to run tots
  3dcalc      -- calc complex cross subj F-rat
  brik2bfloat -- conv to folded bfloat
  bresize     -- unfold bfloat
  3dcalc      -- calc Rayleigh p value
  brik2bfloat -- conv to folded bfloat
  bresize     -- unfold bfloat

To see the detailed arguments to and verbose
output of each of these programs, click the
SPHEREAVG button, let if finish, quit csurf, and
then look in the csurf.log file (which is
generated in the current session scripts dir on
quitting).

Output files

The vertex-wise output files (paintfiles, wfiles)
for a SphereAvg directory named "avg", for one
hemisphere, are as follows:

  ### cross-subject means
  avg-mean-sph-sm1_r-lh.w  (sqrtF real)
  avg-mean-sph-sm1_i-lh.w  (sqrtF imag)
  avg-mean-sph-sm1_a-lh.w  (amplitude _r,_i)
  avg-mean-sph-sm1_x-lh.w  (raw Fourier real)
  avg-mean-sph-sm1_y-lh.w  (raw Fourier imag

  ### cross-subject 1-samp t-stat vs. tcp
  avg-tstat-sph-sm1_a-lh.w

  ### cross-subject complex F-stat (Hagler)
  avg-stat-sph-sm1_g-lh.w  (from _r,_i)
  avg-stat-sph-sm1_f-lh.w  (from _x,_y)

  ### cross-subject Rayleigh pos p-exponent
  avg-stat-sph-sm1_e-lh.w  (from _r,_i)

  ### cross subject dispersion
  avg-stat-sph-sm1_d-lh.w

  ### cross subject t (phasetype="w")
  avg-tstat-sph-sm1-rh.w  (no _infix)


--------------------------------------------------
AVGSURF -- Make Average Surf from Current Subjects
--------------------------------------------------

Click AVGSURF to make an average surface for the
current set of subjects analogous to the
fsaverage surface.  This uses Doug Greve's
script, make_average_subject, from standard MGH
freesurfer, and requires that the environment
variable FSURF_DIR is pointing to a separate full
MGH freesurfer installation when csurf starts.

The first step is to pick a new name for the
average surface subject directory, which (1) must
not yet exist (e.g., fsavg-polar1), and (2) must
be in the same SUBJECTS_DIR that contains the
individual subjects.

When AVGSURF finishes, it will offer to reset the
display subject (used by SAMP2SUBJ) to the
newly-made average surface.  Run time is about 3
min per subject.

After finishing the average, small regions
containing giant triangles in the north and south
'poles' of the inflated_avg surface will be
auto-fixed.  This step uses the following label
files:

 $CSURF_DIR/fsaverage-ADDITIONS/label/rh-FIX-POLES.label
 $CSURF_DIR/fsaverage-ADDITIONS/label/lh-FIX-POLES.label

The same operation can be performed on a surface
average generated outside of csurf using the
csurf shell script:

  fixinflatedavg <average_subject>

Surface Areas of Different Average Surfaces

The idiosyncratic pattern of secondary folding in
different brains means that any average of folded
surfaces (e.g., fsaverage $hemi.orig) will have a
simpler folding pattern than any of the
individual subject surfaces that went into it.
This in turn means that the surface area of the
average surface will be less than than the
surface area of any individual surface (about 1/3
less).  An area-preserving inflation of the
average surface will be similar, which explains
why the width and height of fsaverage
$hemi.inflated is smaller than any individual
inflated surface.

One way to avoid this loss of area in an average
surface is to construct it from individually
already-inflated surfaces.  For cross-subject
averages computed on the morphed sphere
(CrossSessTools), the average of the inflated
surfaces ($hemi.inflated_avg) is the preferred
display subject, since absolute measures of area
on it will much more closely resemble
measurements on an individual brain.

For analyses in which 3D data has been combined
across subjects before being sampled onto the
2/3-of-full-area fsaverage folded surface, it
makes more sense to use corresponding shrunken
inflated surface ($hemi.inflated) for display.
In general, that analysis procedure -- though
simpler to adapt to existing 3D processing
pipelines -- generates inferior results to a
thoroughgoing surface-based average approach,
where individual subject statistics are sampled
to each individual's surface, and then to the
morphed sphere before averaging across subjects
(as implemented here).


--------------------------------------------------
SAMP2SUBJ -- Sample to Single Subject Surface
--------------------------------------------------
To sample the average and dispersion index onto
the surfaces of a single subject and write out
the result as a displayable wfile, click
SAMP2SUBJ. To change the display subject, select
a different subject from the "display subject"
dropdown.  This will edit the name file for the
current cross session average scandir.

The display subject can be "fsaverage" (or any
other subject, including subjects not in
average).

The SAMP2SUBJ button also runs a surface-based
cluster exclusion filter (Hagler, Saygin, and
Sereno, 2006, Neuroimage 33:1093-1103) on the
cross-subject _f file (after it has been sampled
back to a display surface) to correct for
multiple comparisons (binary: surfclust).

Taking the left hemisphere as an example, the
vertex list input file (_f infix):

  avg-stat-sph-sm1_f-lh.w    (orig cross-sub F)

is filtered and using the display subject surface
to generate an output file (_h infix):

  avg-stat-sph-sm1_h-lh.w  (cluster-filtered _f)

The cluster filter is also applied to cross
subject t-stats from real-valued data if they
have been generated with phasetype "w"

N.B.: an input t-stats wfile without an
underscore infix (e.g., avg-tstat-sph-sm1-rh.w)
generates a cluster filtered file with the same
_h infix (e.g., avg-tstat-sph-sm1_h-rh.w).

The two parameters controlling the cluster filter
are located at the extreme right near the top of
the panel -- "F:" and "mm^2:".  The value in "F:"
sets the pre-cluster stat threshold (actually t
for real-valued phasetype="w" stats).  Use an F
table (see above) to determine the F value to
enter for the desired p-value (e.g., 0.01).  The
minimum area of the surface-based cluster passed
by the filter is set by the value in "mm^2:"

To determine the proper surface area to enter
based on pre-cluster threshold, smoothing, and
desired corrected prob value, run randsurfclust
on the command line:

 Usage: randsurfclust -subj name [options]

  Required parameter:
    -subj <name>		(can be ico)

  Optional parameters:
    -hemi <rh,lh>		default is rh
    -surf <suff>		for area calc (smoothwm)
    -niter <num>		iterations (100)
    -pval <val>		prob value (0.001)
    -smooth <num>		smoothing steps (10)
    -alpha <val>		corrected prob value (0.05)
    -egfw		est. gauss filterwidth (no)
    -quiet		suppress messages

For -pval, use the p-value for the uncorrected
hard threshold.  For -alpha, use the desired
corrected p-value.  If there is an error
complaining about not enough iterations, increase
-niter from the default 100.

To view and mask the average data, and to save
bitmaps, use CrossSessTools -> View SphereAvg
Data, which brings up a copy of the SessionTools
-> View Functional Data, and which has an almost
identical layout and function to it.


--------------------------------------------------
VOLAVG -- complex-valued volume avg/stats
--------------------------------------------------
This 'manual Talairach' procedure is designed
only for focal averages of brainstem retinotopy
data (not cortical retinotopy data, which is
better analyzed on the surface).

There is currently no facility in VOLAVG for
reversing phase, so all analyzed scans must have
the same phase order (i.e., all counter-clockwise
pol1 *or* all clockwise pol2).  A scan can be
reversed by using SessionTools -> Combine 3D Raw
Images (this works even on a single scan).

Before proceding, first make a copy of each of
the single-subject session intended for the
average so the initial native analyses and
register.dat files are not overwritten using:

  File -> Copy Functional

Then, for each subject, hand-register the
functional data to a single structural underlay.
To do this replace the native subjectdir name in
this file:

  $FUNCTIONALS_DIR/$session/image/name

with the name of the single target subject (e.g.,
one of the subjects in the average) using:

  Preferences -> Change Subj for Curr Session

Note that is is considerably easier to manually
align small brainstem structures with a single
subject target than it is to align them with an
average (blurry) target.

Opening the functional scandir in tkregister
using SessionTools -> Setup Align/Funct ->
FUNCT=>SUBJ now allows you to align this
subject's functional data with the target subject
structural scan (the underlay subject).  This
'manual Talaiarching' may require scaling in
addition to rotation and translation.

Next, display the complex-valued re-registered
data using SessionTools -> View Functional Data
-> VOLUME-STATS.  This reads the 3D native
resolution Fourier stats (by default, the _r,_i
pair) and upsamples them to the resolution of the
structural.

By default the surface Paintfile for retinotopic
data will be the _r/_i pair of sqrt(F) stats.
This will load the corresponding 3D native
resolution stat files and upsample them.  Smooth
these to taste with tkmedit SMOOTH STATS.

Then write out the upsampled complex-valued files
for averaging.  To write out the first pair,
click the tkmedit "valn:" entry label ("n" stands
for native resolution) and it will change to
"valup:" ("up" stands for upsampled).  Write out
the pair of upsampled stat BRIKs using the "W"
button to the right of the tkmedit "val:" entry.
The name in the entry is auto-generated but can
be changed as long as it ends in "_r+orig.BRIK".

To write out the second pair, click "valup:" to
toggle back to the "valn:" and read in and auto
upsample the native raw Fourier amplitude files
(_x,_y infixes).   Smooth these the same way and
then write them out by clicking "valn:" again to
go back to "valup:" and click "W".  The name in
the entry is auto-generated by can be changed as
long as it ends in "_x+orig.BRIK".

Finally, create and setup a cross session panel
with:

  File -> New Spherical Avg
  CrossSessTools -> Cross Sess SphereAvg

For each new line created with ADD SESS, select
Session, Scandir, and StatBrikStem in that order
from the dropdowns to select the files to
average.  Complex-valued files typically have _x
and _y infixes, which won't be visible in the
dropdown, but which will be used (the VtxListPref
and MorphSurf columns are ignored).

Now, click the VOLAVG button at the upper right.
This generates the following files for a
SphereAvg directory named "avg":

  ### 2-BRIK volumes: avg, t-stat
  avg-stats-vol_r+orig.BRIK
  avg-stats-vol_i+orig.BRIK
  avg-stats-vol_x+orig.BRIK
  avg-stats-vol_y+orig.BRIK

  ### 1-BRIK volume: complex-F
  avg-stat-vol_f+orig.BRIK

Here are the commands run by VOLAVG (minus error
checking):

  ## pass1: mean/tstat
  3dttest     -- xsubj 3D avg,ttest (_x,_y,_r,_i)

  ## pass2: cmplx-F from (_x,_y)
  3dcalc      -- calculate numerator
  foreach (subject,real/imaginary)
    3dcalc      -- add sq resids to running tots
  3dcalc      -- calc complex cross subj F-rat

The first pass can also be performed on
real-valued (no infix) stat files.  In that case,
the second pass is skipped.

Finally, view results in tkmedit with
CrossSessTools -> View SphereAvg Data ->
VOLUME-STATS.  This should automatically read in
complex-valued overlay files with names like
$stem-stat-vol{_x,_y}+orig.BRIK as well as the
appropriate statistical mask file.

####################
setuprendersphavg
####################

-------------------------------------------
 The CrossSessTools -> View SphereAvgData
 View 3D stats on high resolution 3D underlay
 (tkmedit) or cortical surface (tksurfer)
-------------------------------------------
Similar to SessionTools -> View Functional Data.

#################################
 ==> OPENING THAT HELP NOW <==
#################################


#########################################
tkmedit R-click pop-ups (interface order)
#########################################
####################
clks
####################

### Volume-Image Window Clicks ###

(1) Left-Click: Select point (rot center, change plane slice)

(2) Middle-Click: Edit main image point to white/fill
      => middle-click-drag edits continuous path to white

(3) Right-Click: Edit main image point to black/remove
      => right-click-drag edits continuous path to black

(4) Shift-Left-Click: Edit main img point to targval if in bounds
      => bounds set by TRUNC entries, targval by PF entry
      => if $im2boundsflag (mid-clk "la") bounds test on im2

(5) Shift-Middle-Click: Dump histogram of 3D sphere
      => set "rad:" in pix, requires gnuplot installed

(6) Shift-Right-Click: Dump single voxel timecourse

(7) Double-Middle-Click: Report underlay pixval
      => and MGH segmentation name/idnum/rgb if loaded

(8) Ctrl-Left-Click (or alt/cmd-z): Undo up to 4 sequential edits

(9) Shift-Ctrl-Left-Click (or alt/cmd-Z): Redo up to 1 prev. undo

(10) Ctrl-Double-Right-Click: This help (ctrl so no accid. edit)


### Volume-Image Window HotKeys ###

R/L arr	slice up/down
up/dn arr	slice up/down (also)
1,2,3,4	resize image window
k	1-time large cursor
K	toggle cursor visibility
O (oh)	toggle open cent cursor (large cursor only)
b	return to single pix brush
B	increase brush radius (wraps at rad=10)
l	go back to last brush size
+,-	brightness up/down ('=' same as '+')
*,/	contrast up/down (times/divide, '8' same as '*')
r	reset contrast=12, midpoint=0.35
Cmd-f	SEND (forward) point
Cmd-g	GOTO point
Cmd-d	toggle surface visibility
o (oh)	toggle stats visibility
i,I	adjust fmid 0.1 up/down
e	save (edit) images

####################
talcoords
####################

-------------------------------------------
entry variable: $xtalairach -- Right/Left
entry variable: $ytalairach -- Posterior/Anterior
entry variable: $ztalairach -- Inferior/Superior
-------------------------------------------

The coordinates in the three entries in the left
middle column:

  "yTal P/A:"
  "xTal R/L:" 
  "zTal I/S:"

are updated upon a left-click on the displayed
image.  Entering a number plus <Return> will move
the cursor to that coordinate (keeping current
display plane).  Left-click the middle "xTal R/L"
label to go to the pixel nearest Talairach x=0,
y=0, z=0.  Left-click the bottom "zTal I/S" label
to report Talaiarch coordinates in x,y,z order
(N.B.: Talairach x is in middle).

For brains reconstructed with (old/ancient)
SubjectTools in FreeSurfer0.8, the linear
transformation matrix for these Talairach
coordinates is generated using the Montreal
Neurological Institute Automated Linear
Registration Package described in:

  DL Collins, P Neelin, TM Peters, AC Evans (1994)
  J. Comp. Assist. Tomogr. 18:192-.

The software was downloaded from:

  ftp://ftp.bic.mni.mcgill.ca/pub/mni_autoreg/

For brains reconstructed with MGH freesurfer, the
Talairach coords can be generated using several
different procedures depending on the arguments
to recon-all.

The internal coords -> Talairach coords
transformation matrix is read by default from
<subject>/mri/transforms/talairach.xfm.  The
inverse matrix (for converting Talairach ->
internal coords) is automatically calculated
upon reading it (see below).

For .mgz/.mgh files, the volume center is read
from the last line of the direction cosine
transformation matrix in the header (c_r, c_a,
c_s) and is added to the currently selected
intrinsic coordinate before applying the
Talairach transformation matrix.  Conversely, the
inverse Talairach transformation matrix is first
applied to a Talairach point and then the
intrinsic center subtracted afterward.

The unlabeled entries below each Talairach
coordinate (immediately to the right of the
sliders) are the integer internal coordinate
pixel indices.  These are formatted slightly
differently in MGH tkmedit.  The equivalent
("Volume index") for MGH tkmedit is always
written into the tkmedit title bar.

Tcl commands

To read an MNI-style Talairach transform from a
different file, use:

  set transform /some/other/talairach.xfm
  read_invert_mni_tal

To interactively read an arbitrary 3x4 (rows by
cols) Talairach transformation matrix, use:

  read_invert_12_tal <r1c1> <r1c2> ... <r3c4>

which has 12 arguments (3 concatenated rows).
Accepts scientific notation (e.g., -1.80802e-02)

####################
pixcoords
####################

-------------------------------------------
entry variable: $newjc -- Right/Left
entry variable: $newimc -- Posterior/Anterior
entry variable: $newic -- Inferior/Superior
-------------------------------------------

The unlabeled entry below each Talairach
coordinate (immediately to the right of the
sliders) are the pixel indices into the 256 mm^3
structural COR volume (COR dir or COR mgz file).

These are updated upon a left-click on the
displayed image.

Entering a number plus <Return> will move the
cursor to that coordinate and change to this
display plane.

These coords are similar to the "Volume index" in
MGH tkmedit, but are in a different order and
have one axis flipped.  The equivalent MGH
numbers are written into the tkmedit interface
window title bar on each click (or available in a
pop-up by left-clicking the top "yTal P/A"
label).

####################
interface
####################

-------------------------------------------
tcl functs (left-click): make interface size popup
  mini, mini2, mini3, macro, micro
  keyboard equiv: <[fn-]F1 to [fn-]F5>
-------------------------------------------
tcl bind (mid-click): invert contrast
  set bwslope [expr -$bwslope]
    => toggle sing of $bwslope ("midpt:")
-------------------------------------------

Left-clicking the small "i" button at the extreme
left makes small pop-up for controlling size and
arrangement of the tkmedit tools interface.

The interface size can also be controlled with
using the [fn-]F1 to [fn-]F5 buttons (focus must
be in the tkmedit tools window).

Interface sizes

  F1 -- default interface (basic editing)
  F2 -- add functional overlay tools (right)
  F3 -- add ramp, spherical edit tools (bottom right)
  F4 -- everything (EEG, cortical ribbon colors, 2D color)
  F5 -- minmal, long thin (e.g., to edit cerebellum)

-------------------------------------------
tcl bind (mid-click): invert contrast
  set bwslope [expr -$bwslope]
    => toggle sing of $bwslope ("midpt:")
-------------------------------------------

A non-default middle-click of the "i" button
toggles the sign of $bwslope ("midpt:").  When
$bwslope is negative, contrast is inverted
(default is positive).


####################
undoedit
####################

-------------------------------------------
tickbox variable: $undoeditflag -- toggle enable undo
-------------------------------------------
keyboard equiv: cmd-z OR ctrl-left-click in image window

The "un" tickbox toggles whether a 4-step image
edit undo function is enabled (default=ON).  This
can undo any series of sequential edits, up to 4
in a row.  There is also a 1-step redo.

This slightly slows down a series of rapid single
right- or middle-click edits (virtually no effect
on a right- or middle-click-drag), and can be
turned off if individual-click edit interface
response speed is critical (and no undo is OK).

A cmd-z *OR* a ctrl-left-click on the image
window undoes the latest right- or middle-click
edit or right/middle click-drag edit.  cmd-Z for
1-step redo.


####################
xfm305to152
####################

-------------------------------------------
tickbox variable: $xform_mni_305to152_flag -- MNI 305/152
-------------------------------------------
keyboard equiv: none

The "152" tickbox toggles between using MNI 305
Talairach coordinates (default) and MNI 152
coordinates.

The MNI 305 coordinates are converted to MNI 152
coordinates using the following transformation
matrix:

   0.9975  -0.0073   0.0176  -0.0429
   0.0146   1.0009  -0.0024   1.5496
  -0.0130  -0.0093   0.9971   1.1840
   0.0000   0.0000   0.0000   1.0000

####################
overlay
####################

-------------------------------------------
tickbox var: $overlayflag -- toggle visibility stats
-------------------------------------------
keyboard equiv Linux: <Alt-o>
keyboard equiv Mac: <Cmd-o>

The "overlay" tickbox toggles visibility of
amplitude (val) data overlay.  It is autoset when
an overlay data set is read with the tkmedit
command line arguments:

  -real <format>
  -complex <cformat_r> <cformat_i>

####################
surf_ck
####################

-------------------------------------------
tickbox variable: $surfflag -- toggle visibility surf
-------------------------------------------
keyboard equiv Linux: <Alt-d>
keyboard equiv Mac: <Cmd-d>

If a surface has been read in with the "surf:"
entry, this toggles its visibility.  The
intersection of the surface with the current
slice is drawn in yellow.

####################
bwslope
####################

-------------------------------------------
entry variable: $bwslope -- contrast adj sigmoid slope
default: 12.0
-------------------------------------------
left-click "contr:" label -- toggle $linearflag
-------------------------------------------

The "contr:" entry sets the slope of the contrast
sigmoid function used to map image data to
display brightness.

A higher number for "midpt:" increases contrast.
Use midpoint ($bwmid, "midpt:" entry) to set
inflection point of sigmoid.  For linear map, set
linearflag TRUE

                         1.0
display =  -----------------------------------
            1.0 + exp(-bwslope*(image-bwmid))

To invert contrast, use a negative number for
$bswlope ("contr:" entry).

A left-click on the bold "contr:" label toggles
between the standard sigmoid function vs. a
linear function mapping image data to display
brightness.

####################
bwmid
####################

-------------------------------------------
entry variable: $bwmid -- midpoint adj sigmoid slope
-------------------------------------------
default: 0.35

The "midpt:" entry sets the inflection point of
the contrast sigmoid.

A higher number increases midpoint of inflection
point of sigmoid -- that is, darkens the image.
For linear map, set linearflag TRUE

                         1.0
display =  -----------------------------------
            1.0 + exp(-bwslope*(image-bwmid))

To invert contrast, use a negative number for
$bwslope ("contr:" entry).

####################
roi_ck
####################

-------------------------------------------
tickbox variable: $labelflag -- toggle visibility 3D ROI
-------------------------------------------
keyboard equiv: <none>

The "roi" tickbox toggles visibility of 3D ROI.
It is autoset when an ROI is filled with FILL, or
when a previously filled ROI is read in by
clicking "R" on the "roi:" entry line.

####################
roi_fill
####################

-------------------------------------------
funct (left-click): fill 3D ROI around cursor
  fill_roi
-------------------------------------------
funct (middle-click): clear FILL
  clear_rois
-------------------------------------------
funct (shift-left-click): volume current ROIs
  vol_rois
-------------------------------------------


Detailed Description FILL button

A default left-click of the FILL button performs
a region-growing 3D fill starting from the
current cursor location and filling all connected
points that also pass one of 4 following
criteria.  The criteria are described in order of
precedence.

Criterion: SegID (SegID at last click)

If a 3D annotation file has been loaded and "la"
($imtolutoverlay) is checked, the criterion is
that the connected points must have the same
SegID as the SegID at the last click.

Criterion: Mask Threshold ($sfthresh)

If both a stats/amplitude overlay as well as a
mask overlay has been loaded, and "overlay"
checkbox ($overlayflag) as well as the mask
checkbox ($overlaymaskflag) on the mskn/mskup
line are both checked, the criterion is that the
connected points must must have a mask value
above the current setting of $sfthresh (the
second entry labeled "thr").

This will ignore the value of the real or complex
overlay itself.

Criterion: Stat/Amplitude Threshold ($fthresh)

If a stats/amplitude overlay has been loaded and
"overlay" is checked (and the mask checkbox and
"la" are both *unchecked*), the criterion is that
the connected points must be above the current
setting of $fthresh.

If the data currently displayed is complex, the
complex amplitude of the data is compared to
$fthresh.

Criterion: Anatomical Underlay Limits (WMTRUNC)

If "overlay", the overlay mask tickbox, and "la"
are all *unchecked*, the criterion is instead
that the connected points must have an *underlay*
value between the limits set in the two entries
just to the right of WMTRUNC ($white_lolim,
$white_hilim).

AND Criterion: Maximum Radius ($fillrad)

This applies (logical AND) to whichever of the
above is being used.  If the entry to the right
of FILL is set above 0.0, the fill region (stat
threshold *or* mask threshold *or* WMTRUNC
anatomical limits) will also be contrained not to
go beyond this radius (in mm) from the cursor
seed point.

AND Criterion: Edit Cuts

To further constrain a FILL (another logical
AND), use temporary right-click edits (to black)
of the underlay image, which will be respected
in addition to the optional maximum radius).

Appending a Region to an Existing FILL

If the current FILL has not been cleared (see
below), you get a pop-up option to append a
region to it by clicking on a new seed point in
the volume and clicking FILL again.  The pop-up
also gives you the option to clear first, in
order to make a new FILL.

Saving and Using an ROI Mask

The resulting fill ROI mask (0,1) can be written
out as a 256x256x256 AFNI BRIK using the "W"
button on the "roi:" line in the middle of the
panel.  Once saved, it can be used to mask
overlay data (see "m" checkbutton help) or to
extract raw data timecourses (see "T" button help
on "roi:" line).

-------------------------------------------
Alt funct (middle-click): clear FILL
  clear_rois
-------------------------------------------

To clear the current FILL, use middle-click on
the FILL button.  (N.B.: this will not restore
any edits-to-black -- to restore those, re-read
the underlay image using "R" on the fn-F1
interface "im:" line).

-------------------------------------------
Alt2 funct (shift-left-click): volume current ROIs
  vol_rois
-------------------------------------------

A second alternate shift-left-click on the FILL
button measures the volume of the currently
FILL'ed ROIs in mm^3.  The result is written to
the log, shown in a popup, and also written to
$genstrret_1k (so it can be used in a tcl
script).


####################
roi_rad
####################

-------------------------------------------
entry variable: $fillrad -- max fill radius
-------------------------------------------
default: 0.0 (off)

The unmarked entry to the right of the FILL
button controls the maximum radius (in mm) of an
ROI generated by FILL, if set above zero.

When FILL is clicked, fthresh (or WMTRUNC limits
if "overlay" is unclicked) are always respected,
so to fill a complete sphere, first set fthresh
to 0.0 (or WMTRUNC limits to 0 to 255).

####################
saveimg
####################

-------------------------------------------
var,funct (left-click): save edited images
  set inoutim <outfile>
  write_images
-------------------------------------------

If images are edited, the SAVEIMG button asks to
confirm overwrite of the originally-read-in image
set using the original filename.

If tkmedit is quit with unsaved edits, you have a
chance to save them (N.B.: quitting tkmedit by
ctrl-C or "exit" at tcl prompt doesn't ask).

N.B.: SAVEIMG ignores any change you might have
made to the image name in the "im:" field (e.g.,
by reading in a different image set!).  If you
want to change the name you are saving to, enter
a new name in the "im:" entry and use the "W"
button there.

####################
brush
####################

-------------------------------------------
entry variable: $prad -- edit brush radius
-------------------------------------------
keyboard equiv Linux: <Alt-b,B>
keyboard equiv Mac: <Cmd-b,B>

Radius of white (middle-mouse) and black
(right-mouse) editing brush.  3D button toggles
between within-slice brush (default) and 3D brush
($inplaneflag=0). Brush radius=0 is 1x1x1 mm (one
pixel).  Alt-b (Mac:Cmd-b) returns radius to
this.  Increasing to radius=1 increases brush to
3x3x1 mm (or 3x3x3 if 3D button clicked), and so
on.  Alt-B (Mac:Cmd-B) increases radius by 1.
Write edited images with SAVEIMG (or "W" on the
"im:" line to Save As).

To see black edits: contr: ($bwslope) = 255
                    midpt: ($bwmid) = 0.001

Finally, to get a square/cubical brush (e.g., to
delete whole slice), click the "rad:" label to
toggle between circular/spherical and
square/cubical (toggles $circleflag).

####################
inplane
####################

-------------------------------------------
tickbox variable: $inplaneflag -- toggle 2D/3D brush
-------------------------------------------
keyboard equiv: [none]

The "3Dbrush" tickbox toggles between
within-slice brush (default=OFF) and 3D brush
(ON).  Use 3D editing brush with care at larger
radii.

####################
sendpnt
####################

-------------------------------------------
function: write_point -- save 3D location
-------------------------------------------
keyboard equiv Linux: <Alt-f>
keyboard equiv Mac: <Cmd-f>

The "SEND PNT" button writes the coordinates of
the last selected 3D location (left-click) to the
file $SUBJECTS_DIR/<subj>/tmp/edit.dat for
tkmedit, tkregister, or tksurfer.

Those other programs can read this file to go to
the same point.

####################
gotopnt
####################

-------------------------------------------
function: goto_point -- goto saved vertex location
-------------------------------------------
keyboard equiv Linux: <Alt-g>
keyboard equiv Mac: <Cmd-g>

The "GOTO PNT" button reads coordinates in the
file $SUBJECTS_DIR/<subj>/tmp/edit.dat, which
contains a vertex location written by "SEND PNT"
(from either tkmedit, tkregister, or tksurfer).

The pixel corresponding to the saved point is
located and the cursor is put there (current
plane unchanged).

####################
all3
####################

-------------------------------------------
tickbox variable: $all3flag -- toggle 1 <-> 3 views
-------------------------------------------
keyboard equiv: <none>

The "all3views" tickbox toggles state of display
between 1 fullsize view and smaller views of all
3 planes plus max view.  (CORONAL->upper left,
HORIZONTAL->upper right SAGITTAL->lower left).

Clicking in one view updates the 2 other views
and changes the focus of the arrows keys to the
clicked plane.

Clicking anywhere in maximum intensity projection
view (lower right) returns other 3 views to
center.  OK to edit any plane in this state.


####################
all3zoom
####################

-------------------------------------------
tickbox variable: $zoomflag -- toggle zoom all3views
-------------------------------------------
keyboard equiv: <none>

The "z" tickbox is only visible when "all3views"
is ticked.  This doubles the magnification of
coronal, horizontal, and sagittal views and moves
cursor to match unzoomed location (currently
selected slice plane indicated by max intens
projection).

Clicking cursor in any plane correctly updates
other two slice planes (struct and overlay) as
with unzoomed all3(views).

This is a quick hack for easier viewing of
brainstem activations.  It has shortcomings:

 1) it is not possible to pan the individual
    centered slice views (only the central
    +/- 128mm of the FOV is accessible)

 2) slice plane slider numbers (and Talaiarch
    coords) change to centered units of 1/2 mm
    for 1mm^3 data (or 0.25mm for 0.5mm^3 data)

 3) because of 2), intrinsic and Talairach coord
    entries, and SEND PNT and GOTO PNT are
    disabled during zoom.  To use these
    functions, unzoom, use them, then re-zoom.

####################
complexval
####################

-------------------------------------------
tickbox variable: $complexvalflag -- real/cplx data
-------------------------------------------
keyboard equiv: <none>

The "cpx" tickbox at the upper middle (under SEND
PNT) is normally autoset on read real or complex
overlay data with tkmedit command line arguments:

  -real <format>
  -complex <cformat_r> <cformat_i>

This flag toggles between expecting real-valued
data and complex-valued data.

It also affects how the filename argument in the
"valn:" (or "valnup:") entry is treated .  If
complexvalflag is set, a "R" on the "valn:" entry
line will attempt to read a pair of files.  An _r
(or _x) infix will result in an attempt to also
read a matching file with an _i (or _y) infix.

####################
surf
####################

-------------------------------------------
entry variable: $insurf -- surface overlay
-------------------------------------------
default: ~/surf/?h.orig

The "surf:" entry shows the current surface (usu.
unloaded at startup).

The current subject directory can be abbreviated
as a tilde (~). Absolute name OK, too.  Relative
name appended to path to subject's surf
directory.

####################
surf_read
####################

-------------------------------------------
vars,funct (left-click): read surface
  set readsurf2flag <0,1>
  set insurf <surface:tri/quad>
  read_binary_surf
-------------------------------------------

Read binary surface (quads or triangles) in entry
to left to either primary or secondary surface,
depending on whether the adjoining "2" is ticked.

If a previous primary or secondard surface has
already been read, it is replaced.

####################
surf2col
####################

-------------------------------------------
tickbox variable: $readsurf2flag -- read 2nd surface
-------------------------------------------
keyboard equiv: none

If the "2" checkbutton is ticked, clicking the
"R" button just to the left of it reads in (or
re-reads) a second surface (read_binary_surface2)
and colors it green.

If the "2" button is unticked (default at
startup), a first surface is read in (or re-read)
and colored yellow.

HOWTO display lh.orig (yellow) and lh.pial (green)

  0) untick "2" (default)
  1) select lh.orig from "surf:" dropdown
  2) click "R" on "surf:" line
  3) tick "2"
  4) select lh.pial from "surf:" dropdown
  5) click "R" on "surf:" line

####################
imentry
####################

-------------------------------------------
entry variable: $inoutim -- editable image set
-------------------------------------------
keyboard equiv: [none]

Main/Editable Image Set

The "im:" entry (not visible on fn-F2 data
overlay interface), shows the name of the
editable 3D data set.

On startup, this entry will contain the data set
initially read when tkmedit was started, which
will typically be read from:

  $SUBJECTS_DIR/<subject>/mri

N.B.: this entry is not visible on the fn-F2
(data overlay) interface.

The initial part of the path will be abbreviated
using a tidle (~) to represent the current
$SUBJECTS_DIR.

To re-read that data set (e.g., to revert to
original), click "R" to the right of the entry.

To read in a different editable data set, enter
either:

(1) a COR dir (containing 256 256x256x1byte
    or 512 512x512x1byte COR-??? images in
    coronal orientation, and COR-.info file)

       *or*

(2) an .mgh/.mgh format file (with similar
    orientation, datasize, and imagesize)

and click the "R" to the right of the entry.

The file name can be entered as a relative,
abbreviated, or absolute path.  Assuming
SUBJECTS_DIR equals /fmri/subjects, the following
3 names refer to the same COR dir data set:

  orig
  ~/mri/orig
  /fmri/subjects/martys/mri/orig

and the following 3 names refer to the same .mgz
data set:

  orig.mgz
  ~/mri/orig.mgz
  /fmri/subjects/martys/mri/orig.mgz

A <Return> is same as "R".  Edits always affect
this image set, even when it is not visible.

To write out the initial dataset, use SAVEIMG or
"W".  Change the name in the entry before
clicking "W" to write out edited data set with a
different name.

================================================
COR dir format (coronal slices)
 --256 256x256x1byte imgs, COR-001 to COR-256
       *or*
 --512 512x512x1byte imgs, COR-001 to COR-512
================================================
### COR-.info (1x1x1mm or 0.5x0.5x0.5mm)
imnr0 1
imnr1 256 *or* 512
ptype 2
x 256 *or* 512
y 256 *or* 512
fov 0.256000
thick 0.001000
psiz 0.001000
locatn 0.000000
strtx -0.128000
endx 0.128000
strty -0.128000
endy 0.128000
strtz -0.128000
endz 0.128000
tr 0.000000
te 0.000000
ti 0.000000
xform talairach.xfm

================================================
mgh/mgz format -- single-file 1byte brik
================================================
/*** tkmedit.c: read mgh/mgz file to im[ ][ ][ ] ***/

#define FIRST_IMG_BYTE 284 /*0-based (hdr=byte0-283)*/
#define MATCH_SUFFIX(S,A) \
  ((strlen(A)>=strlen(S) && \
  !strncmp(A+strlen(A)-strlen(S),S,strlen(S))))

unsigned char  **im[512];  /* 3D img */
size_t bufsize;
float ps;        /* pix size */
float st;        /* slice thick */
float xx0, xx1;  /* img xmin,xmax */
float yy0, yy1;
float zz0, zz1;

void read_images(char *fpref)
{
  char   cmd[MAXNAMELEN];
  int    version, width, height, depth, nframes;
  int    type, dof, used, bpv= -1;
  short  goodRASFlag;
  float  spacingX, spacingY, spacingZ;
  float  x_r, x_a, x_s, y_r, y_a, y_s;
  float  z_r, z_a, z_s, c_r, c_a, c_s;
  FILE   *fp, *pfp;

  if (MATCH_SUFFIX(".mgz",fpref) ||
      MATCH_SUFFIX(".mgh",fpref)) {
    if (MATCH_SUFFIX(".mgh",fpref))
      sprintf(cmd,"cat %s",fpref);
    if (MATCH_SUFFIX(".mgz",fpref))
      sprintf(cmd,"gunzip -c %s",fpref);
    pfp = popen(cmd,"r");
    version = freadInt(pfp);
    printf("medit: version = %d\n",version);
    width = freadInt(pfp);
    printf("medit: width = %d\n",width);
    height = freadInt(pfp);
    printf("medit: height = %d\n",height);
    depth =  freadInt(pfp);
    printf("medit: depth = %d\n",depth);
    nframes = freadInt(pfp);
    printf("medit: nframes = %d\n",nframes);/*briks*/
    type = freadInt(pfp);
    printf("medit: type = %d\n",type);
    dof = freadInt(pfp);
    printf("medit: dof = %d\n",dof);
    spacingX = freadFloat(pfp);
    printf("medit: spacingX = %f\n",spacingX);/*1*/
    spacingY = freadFloat(pfp);
    printf("medit: spacingY = %f\n",spacingY);
    spacingZ = freadFloat(pfp);
    printf("medit: spacingZ = %f\n",spacingZ);
    goodRASFlag=freadShort(pfp);
    printf("medit: goodRASFlag = %d\n",goodRASFlag);
    x_r = freadFloat(pfp);
    x_a = freadFloat(pfp);
    x_s = freadFloat(pfp);
    y_r = freadFloat(pfp);
    y_a = freadFloat(pfp);
    y_s = freadFloat(pfp);
    z_r = freadFloat(pfp);
    z_a = freadFloat(pfp);
    z_s = freadFloat(pfp);
    c_r = freadFloat(pfp);
    c_a = freadFloat(pfp);
    c_s = freadFloat(pfp);
    printf("medit: x_r=%f x_a=%f x_s=%f\n",x_r,x_a,x_s);
    printf("medit: y_r=%f y_a=%f y_s=%f\n",x_r,x_a,x_s);
    printf("medit: z_r=%f z_a=%f z_s=%f\n",x_r,x_a,x_s);
    printf("medit: c_r=%f c_a=%f c_s=%f\n",x_r,x_a,x_s);
    if (type==0) bpv = sizeof(char);  /* MRI_UCHAR */
    if (type==1) bpv = sizeof(int);   /* MRI_INT   */
    if (type==3) bpv = sizeof(float); /* MRI_FLOAT */
    if (type==4) bpv = sizeof(short); /* MRI_SHORT */
    used = 7*sizeof(int) +
           3*sizeof(float) +
           1*sizeof(short) +
           12*sizeof(float);
    for (i=0; i<FIRST_IMG_BYTE-used; i++)
      fgetc(pfp);  /* can't fseek a pipe */
    if (((width==256 && height==256 && depth==256) ||
         (width==512 && height==512 && depth==512)) &&
         nframes==1 && bpv==1) {
      imnr0 = 1; imnr1 = width;
      ptype = 2;  /* N.B.: assumes COR orientation! */
      xnum = ynum = width;  /* force cube */
      ps = st = 1.0;
      xx0 = yy0 = zz0 = -128.0;
      xx1 = yy1 = zz1 =  128.0;
    }
    else {
      printf(
      "medit: ### %s not 256^3 or 512^3 1frm byteimg\n",fpref);
      exit(1);
    }
    numimg = imnr1-imnr0+1;
    bufsize = ((unsigned long)xnum)*ynum;
    buf = (unsigned char *)lcalloc(bufsize,sizeof(char));
    for (k=0; k<numimg; k++) {
      im[k] = (unsigned char **)lcalloc(ynum,sizeof(char *));
      for (i=0;i<ynum;i++)
       im[k][i] = (unsigned char *)lcalloc(xnum,sizeof(char));
    }
    for (k=0; k<numimg; k++) {
      changed[k] = 0;
      fread(buf,sizeof(char),bufsize,pfp);
      buffer_to_image(buf,im[k],xnum,ynum);
    }
    pclose(pfp);
  }
}

void buffer_to_image(
  unsigned char *buf, unsigned char **im,
  int ysize, int xsize)
{
  int            i,j;
  unsigned long  k=0;
  float          sum=0;

  for (i=0;i<ysize;i++)
  for (j=0;j<xsize;j++) {
    im[i][j] = buf[k++];
    sum += im[i][j];
  }
}

####################
imread
####################

-------------------------------------------
var,funct (left-click): read mgz (or COR dir)
  set inoutim <CORdir *or* mgz>
  read_images
-------------------------------------------

The "R" button re-reads the startup set of
editable images (COR dir or .mgz file), warning
if edited but not saved.

If a different imageset than the startup one is
specified in the entry, that will be read in
instead.

If a second set of images read ("R" button to
read imageset in "im2:" entry), COMPARE can be
used to blink between first and (non-editable)
second.

The images that have been read in are not
saved/overwritten until "SAVE IMGS" is clicked.

####################
imwrite
####################

-------------------------------------------
var,funct (left-click): read mgz (or COR dir)
  set inoutim <CORdir *or* mgz>
  write_images
-------------------------------------------

The "W" button writes out the current state of
the editable image buffer to either a COR dir or
an .mgz/.mgh file.

Currently, this won't convert between the COR dir
and .mgz/.mgh formats.  That is, if COR dir was
read in, only a COR dir can be written and vice
versa.

####################
roin2up
####################

-------------------------------------------
toggle roi type: "roin:" vs. "roiup:" (native vs. upsample)
-------------------------------------------
keyboard equiv: <none>

This entry has two different states, "roin:" (3D
label, *native* resolution) and "roiup:" (3D
label, *upsampled* to structural resolution).

On startup, the default stat is "roiup:", which
is used to read ("R" button) and write ("W"
button) upsampled-resolution 3D labels.  These
are typically short (2-byte) files generated
within tkmedit by fill operations on the smoothed
upsampled data.  Rawdata timecourses from this
label can be dumped ("T" button).

Clicking on the label "roiup:" (bold to indicate
it is button-like) swaps in the "roin:" entry,
which is used to read ("R" button) a native
resolution 3D ROI label (same dimensions as
rawdata), register it to the structural underlay,
and upsample it to structural resolution.

Clicking again toggles back to "roiup:"

####################
roin
####################

-------------------------------------------
entry variable: $rawlabel -- ROI/label file (BRIK)
-------------------------------------------
default: */<scandir>/rh-MY_AREA+orig.BRIK

The "roin:" entry shows the name of the current
native-resolution 3D ROI/label (usu. not loaded
at startup).  This might have been generated, for
example, by converting a surface label to a
native-resolution 3D label in tksurfer (using the
"D" button on the "label:" line).

The current session directory can be abbreviated
as an asterisk (*). Absolute name OK, too.
Relative name appended to current scandir.

The ROI/label file is a native resolution
(dimensions, etc, inherited from rawdata), usu.
hemisphere-specific, short (2-byte) AFNI BRIK
with a voxel value of 1 to indicate where the
label is and 0 elsewhere.

The native ROI/label is typically generated from
a tksurfer surface label, and used here for
viewing/verification prior to export to another
data analysis program.

####################
roin_read
####################

-------------------------------------------
tcl function: readnativeroi -- read native roi
-------------------------------------------
keyboard equivalent: none

The "R" button reads native resolution ROI from
the file in the entry to the left (tcl filename
variable=$uplabel), registers it to the struct
volume using the matrix specified by option
-regdat (typically register.dat in current
$scandir), and then upsamples it to the current
struct resolution (1mm^3/256^3 or 0.5mm^3/512^3)
for display or smoothing.

Here is the tcl code for the "R" (read) button
function, which calls the tcl-linked-C-functions,
read_native_roi and do_regupsamp_roi:

# read real or complex native stats
proc readnativeroi { } {
  global rawlabel labelflag
  setfile rawlabel [.mri.main.right.fi.roin.cbx subwidget entry get]
  read_native_roi
  do_regupsamp_roi
  set labelflag 1
  redraw
}

####################
roiup
####################

-------------------------------------------
entry variable: $uplabel -- ROI/label file (BRIK)
-------------------------------------------
default: */<scandir>/MY_AREA+orig.BRIK

The "roiup:" entry shows the name of the current
upsampled-resolution 3D ROI/label (usu. not
loaded at startup).  This label will typically
have been previously generated by tkmedit (using
the "W" button on the "roiup:" line, for time
course extraction, or masking).

The current session directory can be abbreviated
as an asterisk (*). Absolute name OK, too.
Relative name appended to current scandir.

The ROI/label file is a 256^3 (or 512^3) short
(2-byte) AFNI BRIK with a voxel value of 64 to
indicate where the filled/connected label is and
0 elsewhere.

The ROI/label file is currently used it two ways:

 (1) fill ROI, then use it to extract raw data
      timecourse with "T" button on "roi:" line

 (2) fill ROI, then use it to mask overlay
      activations outside of ROI ("m" check)

####################
roiup_read
####################

-------------------------------------------
function: read_roi -- read 3D ROI/label
-------------------------------------------
keyboard equivalent: none

The "R" button reads a 256x256x256 AFNI BRIK
containing a 3D ROI using the filename in the
entry to the left.  The read-in ROI is initially
displayed in white.  The "roi" check (auto-ticked
on reading an ROI) can be used to toggle the
visibility of the white ROI.

Reading an ROI replaces any currently displayed
ROI or previously read-in ROI.

To mask displayed overlay data using an ROI,
untick "roi" and tick the neighboring "m".  The
overlay data will then only be visible in regions
where the 3D ROI mask is *not* equal to 0.

N.B.: if "roi" is also ticked, the white display
of the ROI will occlude the overlay data.

####################
roiup_write
####################

-------------------------------------------
funct(s) (left-click): write current 3D ROI/mask
  write_roi
  [write_roi_label] -> if overlay data
-------------------------------------------
funct (mid-click): write all 3D MGH seg idnums
  write_allsegids
-------------------------------------------


Detailed Description "W" button

A default left-click on the "W" button writes out
the currently displayed 3D ROI mask (C/tcl funct:
write_roi) as a 256x256x256 AFNI BRIK (2-byte
short) to the file shown in the entry to the left
(filename variable: $uplabel).  ROI voxels have a
value of 64 while non-ROI voxels are 0.

If overlay data is currently displayed, this
button also writes out the real or complex
overlay data (function: write_roi_label) into an
ASCII file with a name similar to the ROI mask
filename (filename variable: $label2).  For
example:

  maskfile:  MY_AREA+orig.BRIK
  datafile:  MY_AREA.3dlabel

Each line of the ASCII output file contains the
tkmedit intrinsic coordinates of the voxel in the
256x256x256 mask BRIK followed by either a single
real value or a complex value, written
redundantly as real, imaginary, and amplitude,
angle (radians).  For example:

Real-valued overlay data ASCII file:
 
  #!ascii , from subject martys, P/A I/S R/L real
  1058
  113 179 162 8.412699
  113 179 163 9.071663
  113 179 164 8.819065

Complex-valued overlay data ASCII file:

  #!ascii , from subject martys, P/A I/S R/L r i amp ang
  1058
  113 179 162 -8.412699 8.789361 12.166609 2.334302
  113 179 163 -9.071663 8.672894 12.550464 2.378664
  113 179 164 -8.819065 8.496123 12.245816 2.374843

-------------------------------------------
Alt funct (mid-click): write all 3D MGH seg idnums
  write_allsegids 
-------------------------------------------

An alternate middle-click on the "W" button
creates an AFNI BRIK containing the int idnums
from every 3D region in the currently loaded MGH
FreeSurfer int segmentation.

The BRIK has the resolution of the underlay
(typically 1x1x1mm).  The filename is taken from
the entry to the left (filename variable:
$uplabel).

####################
roiup_time
####################

-------------------------------------------
funct (left-click): ASCII rawdata timecourses for ROI
  write_roi_timecourses
-------------------------------------------
funct (mid-click): ASCII rawdata timecourses for segid
  write_segid_timecourses <idum>
-------------------------------------------


Detailed Description "T" button

The "T" button reads a 3D ROI/label file (which
is usually located in the current scandir, but
can be anywhere) using the name in the "roi:"
entry to the left (variable: $label).  The
rawdata time series for each voxel in the ROI
file is extracted using the register.dat
transformation matrix in the current scandir.

Since the ROI file is at the same resolution as
the statistical overlay, which wll have been
upsampled to the higher resolution of the
anatomical underlay (1x1x1mm), multiple ROI
voxels will typically sample a single rawdata
voxel (typically 3x3x3mm).  Duplicate timecourses
are removed and a tally of the number of times
each rawdata voxel timeseries has been sampled by
the ROI file is noted in the output file (on
average, this will be the function/structural
volume ratio).  The ASCII output file is written
in the current scan directory (see below).

Output files

One ASCII output files has a name constructed
from the name of ROI label file.  For example:

  MT+orig.BRIK -> MT.raw

This file has a one-line header (format, data
size, sources) followed by a series of lines, one
for each voxel.  Each line contains the raw data
xyz indices, the number of times this voxel has
been upsampled by the ROI file, and finally the
rawdata voxel brightness values for each time
point.  For example:

 #!ascii , fmt: rawx rawy rawz upsampvotes \
      t1 t2 ... t256 \
      (subj=marty, lab=/tmp/MT+orig.BRIK, n=22)
 19 48 39 4 1531 1498 1569 1616 1563 1593 ...
 19 47 39 15 1269 1280 1368 1421 1390 1388 ...
 ...
 [foreach sampled voxel in rawdata file]

The rawx,rawy,rawz coordinates are in raw BRIK
order, ignoring any orientation information in
the HEAD (so BRIK can be read by itself using
the following code):

  for (t=0; t<rawdata_tdim; t++)
    for (z=0; z<rawdata_zdim; z++)
      for (y=0; y<rawdata_ydim; y++)
        for (x=0; x<rawdata_xdim; x++)
          rawdata[t][z][y][x] = one_time_point;

If the surface vertex location is off the edge of
the rawdata block, the integer x,y,z indices are
all set to -1, and the rawdata voxel values are
all set to 0.

Args for tkmedit

  -real <format>          [stats at rawdata res]
  -complex <cformat_r> <cformat_i>    [ditto]
  -scandir <dir_usu_in_image>
  -regdat <registerdatfile>
  -rawdata <rawdata>+orig.BRIK
  -label <some-area>+orig.BRIK
  -statmask <cformat_s>

The procedure can also be performed from the
tkmedit tcl prompt (or a tcl script) where
$scandir is name of scan directory inside "image"
subdir inside the current session.  The current
scandir can be abbreviated with a '*' and the
current subject dir with a '~' using setfile (a
globbing 'set').  For example:

  setfile regdat */$scandir/register.dat
  setfile rawdata */$scandir/<rawdata>+orig.BRIK
  read_rawdata
  setfile label */$scandir/MT+orig.BRIK
  write_roi_timecourses

    => output files: */$scandir/MT.raw

-------------------------------------------
Alt funct (mid-click): ASCII rawdata timecourses for segid
  write_segid_timecourses <idnum>
-------------------------------------------

Same as above, except, get ROI for extracting
timecourses from the idnum of a 3D segmentation
region.

An MGH segmentation must first be loaded using
"R" on the "im2:" line.  Look in dropdown for
files like:

  aparc.a2009s+aseg

To find the idnum of a segmentation region,
double-middle-click one of the colored regions in
the image window in the F2 interface.

A table of all the idnums and corresponding names
is written into the csurf log, written when the
segmentation is read.

Finally, type the idnum into the "roiup:" entry
(N.B.: at startup, this field will contain a
default name for an roi RRIK).

The ASCII output file in the current scandir will
have a name like:

  segid-12120.raw

and will have the same format as described above.

####################
valn2up
####################

-------------------------------------------
toggle val type: "valn:" vs. "valup:" (native vs. upsample)
-------------------------------------------
keyboard equiv: <none>

This entry has two different states, "valn:"
(real or complex valued, *native* resolution) and
"valup:" (real or complex valued, *upsampled* to
structural resolution).

On startup, the default stat is "valn:", which is
used to (re-)read ("R" button) native-resolution
stats (bfloat or float BRIK format), register
them to the structural underlay, and upsample to
structural resolution.  This are the same steps
performed by the VOLUME-STATS button on the csurf
SessionTools -> View Functional Data panel.

Clicking on the label "valn:" (bold to indicate
it is button-like) swaps in the "valup:" entry,
which is used to read ("R" button) *and* write
("W" button) already-registered and
upsampled-to-structural (1mm^3 or 0.5mm^3)
resolution stats (float BRIKs only).  Note that
these are considerably larger files than the
native stats (64M for 1mm^3), but compress well.

Clicking again toggles back to "valn:"

####################
valn
####################

-------------------------------------------
entry variable: $statpatt -- native stats file
-------------------------------------------
default: */scandir1/scan1_r_%03d.bfloat

The "valn:" entry shows the name of the current
native-resolution 3D statistical amplitude (val)
overlay file.  This will have been loaded,
registered to, and upsampled to structural
resolution if tkmedit was started from csurf with
the View Functional Data panel VOLUME-STATS
button.

Session directory can be abbreviated as an
asterisk (*).  Absolute name OK, too.  Relative
name appended to session.

Examples:

  pol1-vreg_r+orig.BRIK
  pol1-vreg_i+orig.BRIK
 
  pol1-vreg_r_%03d.bfloat
  pol1-vreg_i_%03d.bfloat

Requires float data (float BRIK or bfloat file
set).

Contains real-valued activations, complex-valued
activations, or a statistical mask, all of which
are at native (typically EPI) resolution.

If the file infix immediately before +orig.BRIK
(or _%03d.bfloat) is either "_r" or "_x", and the
data is complex-valued as determined by "cpx"
being ticked ($complexvalflag=1), an attempt will
also be made to also read the corresponding "_i"
or "_y" BRIK file (by tcl funct readnativestat).

####################
valn_read
####################

-------------------------------------------
tcl function: readnativestats -- read native stats
-------------------------------------------
keyboard equivalent: none

The "R" button reads native resolution stats
(specified by options: -statnslices, -statyres,
and -statxres) from the entry to the left (tcl
filename variable=$statpatt), registers them to
the struct volume using the matrix specified by
option -regdat (typically register.dat in current
$scandir), and then upsamples them to the
current struct resolution (1mm^3/256^3 or
0.5mm^3/512^3) for display and smoothing.

The stats may be real or complex.  The files are
read as one (real) or two (complex) bfloat file
sets, or one (real) or two (complex) float BRIK
files.

This is the procedure performed by the View
Functional Data -> VOLUME-STATS button.

If the file in the entry contains an infix
indicating the data is complex (_r or _x), and if
"cpx" is ticked, the companion file for the
imaginary component (_i or _y) will also be read
automatically.

Here is the tcl code for the "R" (read) button
function, which calls the tcl-linked-C-function,
read_native_stat to (re-)read native stats, and
do_regupsamp_stat to upsample them:

# read real or complex native stats
proc readnativestats { } {
  global complexvalflag statpatt
  setfile statpatt [.mri.main.right.fi.valn.cbx subwidget entry get]
  read_native_stat 0   ;# (0=real,1=imag,2=stat)
  if {$complexvalflag} {
    if [string match *_%03d.bfloat $statpatt] {
      set infix [getstatbfloatinfix $statpatt]
    }
    if [string match *+orig.BRIK $statpatt] {
      set infix [getstatbrikinfix $statpatt]
    }
    if {$infix == "_r"} {
      set imaginfix "_i"
    } elseif {$infix == "_x"} {
      set imaginfix "_y"
    } else { return }
    set origstatpatt $statpatt
    if [string match *_%03d.bfloat $statpatt] {
      set stem [string range $statpatt 0 \
        [expr [string length $statpatt] - 15]]
      setfile statpatt ${stem}${imaginfix}_%03d.bfloat
    }
    if [string match *+orig.BRIK $statpatt] {
      set stem [string range $statpatt 0 \
        [expr [string length $statpatt] - 13]]
      setfile statpatt ${stem}${imaginfix}+orig.BRIK
    }
    read_native_stat 1
    set statpatt $origstatpatt
  }
  do_regupsamp_stat
}

####################
valup
####################

-------------------------------------------
entry variable: $upstatpatt -- upsampled stats file
-------------------------------------------
default: */scandir1/scan1_r+orig.BRIK

The "valup:" entry shows the name of the current
registered and upsampled-to-structural-resolution
3D statistical amplitude (val) overlay file.
This file will usually not exist initially,
unless the displayed image (upsampled for display
from a native-resolution stats input) has been
previously saved using "W".

Session directory can be abbreviated as an
asterisk (*).  Absolute name OK, too.  Relative
name appended to session.

Examples:

  pol1-vreg_r+orig.BRIK
  pol1-vreg_i+orig.BRIK

Read and write 256x256x256 AFNI float BRIK
format (BRICK_TYPE=3) only.

Contains real-valued activations, complex-valued
activations, or a statistical mask, all of which
have been upsampled to 1x1x1mm (resolution of
structural underlay) and possibly 3D-smoothed.

If the file infix immediately before +orig.BRIK
is either "_r" or "_x", and the data is
complex-valued as determined by "cpx" being
ticked ($complexvalflag=1), an attempt will also
be made to also read (or write) the corresponding
"_i" or "_y" BRIK file.

Since BRIKs must end in "+{orig,acpc,mtlrc}.BRIK"
to be seen by AFNI, "+orig.BRIK" is always
appended when constructing the initial value of
the $upstatpatt filename from the native
resolution (un-upsampled) 3D input stat
filenames.  For complex data with an infix, this
can result in a harmless duplication of "+orig":

Native (EPI) resolution input file names like:

  eccletdilim2sm-1-vreg+orig_r_%03d.bfloat

generate initial upsampled stat ($upstatpatt)
names like:

  eccletdilim2sm-1-vreg+orig_r+orig.BRIK

####################
valup_read
####################

-------------------------------------------
tcl function: readupsampstats -- read upsamp stats
-------------------------------------------
keyboard equivalent: none

The "R" button reads stats that have already been
upsampled to 1x1x1mm resolution from file(s)
(variable=$upstatpatt) in entry to the left.
The stats may be real or complex, and possibly
3D-smoothed.  The files are read as one (real) or
two (complex) 256x256x256 float BRIK files.

For a single-subject session, this is typically
used to re-read saved smoothed upsampled data.

For a cross-session 3D average, this can be used
read an overlay file containing a cross-subject
average of upsampled data.

If the file in the entry contains an infix
indicating the data is complex (_r or _x), the
companion file for the imaginary component (_i or
_y) will also be read automatically.

Here is the tcl code for the "R" (read) button
function, which calls the tcl-linked-C-function,
read_regupsamp_stat:

# read real or complex upsampled stats
proc readupsampstats { } {
  global complexvalflag upstatpatt
  setfile upstatpatt [.mri.main.right.fi.val.e get]
  read_regupsamp_stat 0  ;# (0=real,1=imag,2=stat)
  if {$complexvalflag} {
    set infix [getstatbrikinfix $upstatpatt]
    if {$infix == "_r"} {
      set imaginfix "_i"
    } elseif {$infix == "_x"} {
      set imaginfix "_y"
    } else { return }
    set origupstatpatt $upstatpatt
    set stem \
      [string range $upstatpatt 0 \
        [expr [string length $upstatpatt] - 13]]
    setfile upstatpatt ${stem}${imaginfix}+orig.BRIK
    read_regupsamp_stat 1
    set upstatpatt $origupstatpatt
  }
}


####################
valup_write
####################

-------------------------------------------
tcl function: writeupsampstats -- write upsamp stats
-------------------------------------------
keyboard equivalent: none

The "W" button writes currently visible
upsampled stats to the file(s) in the entry to
the left (variable=$upsampstat).  The stats may
be real or complex, and possibly 3D-smoothed.
The files are written as one (real) or two
(complex) 256x256x256 float BRIK files.

For a single-subject session, this is typically
used to save smoothed upsampled data.

For a cross-session 3D average, this can save a
file containing additional post-average
smoothing.

If the file in the entry contains an infix
indicating the data is complex (_r or _x), the
companion file for the imaginary component (_i or
_y) will also be written automatically.

Here is the tcl code for the "W" (write) button
function, which calls the tcl-linked-C-function,
write_regupsamp_stat:

# write real or complex upsampled stats
proc writeupsampstats { } {
  global complexvalflag upstatpatt
  setfile upstatpatt [.mri.main.right.fi.val.e get]
  write_regupsamp_stat 0  ;# (0=real,1=imag,2=stat)
  if {$complexvalflag} {  ;# also write imaginary
    set infix [getstatbrikinfix $upstatpatt]
    if {$infix == "_r"} { 
      set imaginfix "_i"
    } elseif {$infix == "_x"} { 
      set imaginfix "_y"
    } else { return }
    set origupstatpatt $upstatpatt
    set stem \
      [string range $upstatpatt 0 \
        [expr [string length $upstatpatt] - 13]]
    # setfile is csurf-specific glob
    setfile upstatpatt ${stem}${imaginfix}+orig.BRIK
    write_regupsamp_stat 1
    set upstatpatt $origupstatpatt
  } 
}

####################
mask_ck
####################

-------------------------------------------
tickbox variable: $overlaymaskflag -- toggle mask
-------------------------------------------
keyboard equiv: <none>

The unmarked tickbox next to "mskn:" (or
"mskup:") toggles application of statistical mask
to a real or complex-valued amplitude overlay.

If ticked ($overlaymaskflag is 1), the fthresh,
fmid, and fslope entries are each doubled (and
their labels are abbreviated to "thr", "md", and
"sl").

The first entry in each pair controls the
threshold and contrast of the values themselves.
For example, if a value is below current
$fthresh, it will not be visible in the overlay.

The second set of entries in each pair controls
whether the values are masked based on what is
found in the currently read-in stat mask.  For
example, if a the value of of the .stat field for
this pixel is below the current $sfthresh, the
*value* will be masked.

If unticked, the interface toggles back to one
set of "fthresh", "fmid", and "fslope" entries
for controlling the overlay amplitude threshold
and contrast directly.

Loading Stat Mask

The stat mask field can be loaded with either
native (EPI) resolution stats or already
upsampled stats:

  (1) a native (EPI) resolution stat mask is
  read, registered (w/register.dat), upsampled
  to structural res with:

    setfile statpatt <statvolume>
    read_native_stat 2
    do_regupsamp_stat

  where statfile is either a C printf-style
  bfloat filename pattern, or a stat BRIK.

  (2) An already registered and upsampled BRIK is
  read with:

    read_regupsamp_stat <statbrik>

####################
maskn2up
####################

-------------------------------------------
toggle mask type: "mskn:" vs. "mskup:" (native vs. upsamp)
-------------------------------------------
keyboard equiv: <none>

This entry has two different states, "mskn:"
(*native* resolution mask stats) and "mskup:"
(registered and *upsampled* to structural
resolution mask stat).

On startup, the default stat is "mskn:", which is
used to (re-)read ("R" button) native-resolution
stats (bfloat or float BRIK format), register
them to the structural underlay, and upsample to
structural resolution.

Clicking on the label "mskn:" (bold to indicate
it is button-like) swaps in the "mskup:" entry,
which is used to read ("R" button) *and* write
("W" button) already registered and upsampled to
structural (1mm^3 or 0.5mm^3) resolution stats
(float BRIKs only).  Note that these are
considerably larger files than the native stats
(64M for 1mm^3), but compress well.

Clicking again toggles back to "mskn:"

####################
maskn
####################

-------------------------------------------
entry variable: mskn: $statpatt_m -- native stat
-------------------------------------------
default: */scan1/NO_STAT_f+orig.BRIK

The "mskn:" entry shows the name of the current
native-resolution 3D statistical mask overlay
file.  If present, this will have been generated
by FOURIER or DECONVOLVE.  If loaded (e.g., by
the View Functional Data panel VOLUME-STATS
button), it will have been registered to and
upsampled to structural resolution for display
(or writing).

This entry controls the filename for the
statistical mask at native (typically EPI)
resolution (entry label is: "mskn:").

The entry state can be toggled to read upsampled
data by clicking the bold label ("mskn:").

The file name must be a printf-style pattern (for
bfloat files) or a float BRIK.

The current session directory (typically
YYMMDDII/image) can be abbreviated as an asterisk
(*). Absolute name OK, too.  Relative name
appended to current scandir.

####################
maskn_read
####################

-------------------------------------------
tcl funct: readnativemask -- read native mask
-------------------------------------------
keyboard equivalent: none

The "R" button reads a native resolution
(typically EPI) mask stats file (bfloat or float
BRIK), registers it to the structural, and
upsamples it to the structural resolution.

To save the upsampled file (for example, after
smoothing), first click the bold label to change
the entry labeled "mskn:" to "mskup:".

The functs used by the readnativemask tcl wrapper
are:

  forcebrikMSBfirst
  read_native_stat 2
  do_regupsamp_stat

####################
maskup
####################

-------------------------------------------
entry variable: mskup: $upstatpatt_m -- reg/upsamp
-------------------------------------------
default: */scan1/NO_SUBSTAT_f+orig.BRIK

The "mskup:" entry shows the name of the current
registered- and upsampled-resolution 3D
statistical mask volume (e.g., F-value) that
accompanies a statistical amplitude (val) file.
This mask will typically have been previously
generated by tkmedit (using the "W" button on the
"mskup:" line).

This entry controls the filename for the
statistical mask data that has already been
registered to the structural and upsampled to
the same resolution (1mm^3 or 0.5mm^3) (entry
label is: "mskup:").

The entry state can be toggled to read native
resolution data by clicking the bold label
("mskup:").

The file name must be a float BRIK.

The current session directory (typically
YYMMDDII/image) can be abbreviated as an asterisk
(*). Absolute name OK, too.  Relative name
appended to current scandir.

####################
maskup_read
####################

-------------------------------------------
tcl funct: readupsampmask -- read upsamp mask
-------------------------------------------
keyboard equivalent: none

The "R" button reads a previously saved,
registered, upsampled, possibly 3D smoothed stat
mask from the file in the entry to the left.  The
file is a 1mm^3 or 0.5mm^3 float BRIK.

####################
maskup_write
####################

-------------------------------------------
tcl funct: writeupsampmask -- write upsamp mask
-------------------------------------------
keyboard equivalent: none

The "W" button writes out the current current
data in the registered, upsampled, stat mask
buffer to a 1mm^3 or 0.5mm^3 float BRIK using the
file name in the entry to the left.

Note that this will be a much larger file
than the native resolution stat mask.

####################
rgb
####################

-------------------------------------------
entry variable: $rgb -- abs name output bitmap file
-------------------------------------------
default: */rgb/<scandir>-cor.tiff

The "rgb:" entry shows the proposed name of a
saved bitmap (usu. tiff).

Session directory can be abbreviated as an
asterisk (*).  Absolute name OK, too.  Relative
name appended to $session/rgb.  Must confirm
overwrite, or use save_rgb directly (doesn't
ask).  Alternatively, set target rgb directory
($named_rgbdir) and write rgb file with function:
save_rgb_named <relative_name>.

The default bitmap output format is now tiff (3
bytes per pixel, lossless LZW compression, no
transparency).  To obtain an SGI rgb file, unset
$tiffoutflag by unlicking the unlabled check at
end of entry, which will update output file
suffix), or restart tkmedit from csurf with
Preferences -> Save .tiff selected.

The csurf Preferences -> Black->Transparent
option has no effect on tkmedit (the background
of a structural scan is not exactly black).

####################
tiffout
####################

-------------------------------------------
tickbox variable: $tiffoutflag -- tiff vs. rgb
-------------------------------------------
default: 0 (FALSE)

The unlabeled tickbox to the right of the "rgb:"
entry controls $tiffoutflag.  When it is ticked
(=1, the default), the bitmap output file format
is a 3 bytes per pixel, LZW compressed, tiff
file.  If unticked (=0), the original SGI rgb
bitmap format is used instead (rarely used).

####################
rgb_write2
####################

-------------------------------------------
function: save_rgb -- write TIFF or RGB file
-------------------------------------------
keyboard equivalent: none

This unlabeled button same as "W" button, except
doesn't pop/redraw window first, so tmp overlays
(e.g., time courses) are also saved into bitmap.

####################
rgb_write
####################

-------------------------------------------
var,funct (left-click): write TIFF (or RGB) file
  set rgb <outfile>
  save_rgb
-------------------------------------------

Write out current view in GL window as a tiff
file (or an SGI rgb file, if $tiffoutflag if
first set to 0) using name in entry to left
(after expansion if abbreviated).

Interface click must confirm overwrite (save_rgb
doesn't ask).  Mouse pointer is ignored.  Window
is popped to front and redrawn before saving.
Saves cursor.

The unlabeled button to the left of "W" button
doesn't pop/redraw window first, so tmp overlays
(e.g., time courses) are also saved into bitmap.

####################
wmtrunc
####################

-------------------------------------------
funct (left-click): toggle temporary truncate buf1,buf2
-------------------------------------------
funct (mid-click): actually truncate editable buffer
  run_wmfilter stdtrunc to_buf1
-------------------------------------------
funct (shift-middle-click): count voxels between lims
  countvox <low> <high>
-------------------------------------------
funct (ctrl-mid-click): truncate editable w/im2 colrange
  crop_im_using_im2cols
-------------------------------------------
funct (ctrl-right-click): as above, but only im outside colrange
  crop_im_using_im2cols_save
-------------------------------------------
funct (shift-right-click): cp im->im2 replacing range cols
  cp_im_to_im2_replacing_cols
-------------------------------------------
funct (no hotkey): trunc editable w/2d colspace ellipse
  imim2op <0=inside2off,1=outside2off>
-------------------------------------------


Detailed Description TRUNC button

A default left-click of the TRUNC button toggles
a temporary truncation to white matter (affects
both editable and second buffer).

Set low ($white_lolim) and high ($white_hilim)
limits for the white matter using the entries to
the right of the TRUNC button.  Pixels that are
above or below these numbers go to black.

To test manual normalizations using the controls
on the lower right part of the F3 panel, engage
TRUNC to see what will be the basic final
truncation-to-white-matter result (minus the
plane filter refinement).

Alternate functions below easiest to access via
popup from R-click help.

-------------------------------------------
Alt funct (middle-click):
  run_wmfilter stdtrunc to_buf1
-------------------------------------------

To apply the current truncation to the editable
buffer (so it can be saved), middle-click the
TRUNC button.  This runs the tcl function:

  run_wmfilter <operation> <targbuf>

as follows:

  run_wmfilter justtrunc to_buc1

For reference, the full set of possible arguments
to run_wmfilter are:

  operation:  justtrunc, stdtrunc, gauss
  targbuf:     to_buf1, to_buf2

See help for the PF and PFGAU buttons for
interactively running the plane filter (stdtrunc,
gauss).

-------------------------------------------
Alt2 funct (shift-middle-click):
  countvox <low> <high>
-------------------------------------------

To count voxels that have values between the low
and high limits shift-middle-click TRUNC.  Voxels
equal to the limits are included, so to count
voxels with a single value, set low and high
limits to the same value.

-------------------------------------------
Alt3 funct (ctrl-middle-click):
  crop_im_using_im2cols
-------------------------------------------

This can crop an edtabale image using another
imageset.  This requires that a second image has
been loaded using "R" on the bottom middle "im2:"
line.

A control-mid-click on the TRUNC button truncates
the editable buffer (im) using locations in the
second buffer (im2) that have colors
within/including $while_lolim to $white_hilim
(entries immediately right of TRUNC button) to a
new color, $gray_hilim (entry to right of PF
button):

  for im2 range:
    lo: $white_lolim
    hi: $white_hilim
  im new:
    $gray_hilim

The editable buffer can then be saved with SAVE
IMGS (overwrites editable image), or "W" on "im:"
line (F1 interface) if you want to SaveAs/rename
the result.

To duplicate the result of a hand-edit to black,
use target color 1 (EDITED_TO_OFF).

This can be used, for example, to crop the
background of the editable image set using a
different (already processed, e.g., skull
stripped) image set.

To undo, alt/cmd-z in image window (or tools 
window).

-------------------------------------------
Alt4 funct (ctrl-right-click):
  crop_im_using_im2cols_save
-------------------------------------------

Similar to crop_im_using_im2cols above, but only
edits image if im (not im2!) is outside the range
of:

  lo: $edit_lolim2
  hi: $edit_hilim2

This second pair of limits allows saving more
structure in the editable image.  Do a R-click on
the TRUNC button (or the entries to the right of
it) to get a popup, tick $im2boundsflag, to
enable the second bounds, and set them.

For a mouse-driven version of the same thing, use
shift-left-click in the image window.

To undo, alt/cmd-z in image window (or tools 
window).

-------------------------------------------
Alt5 funct (shift-right-click):
  cp_im_to_im2_replacing_cols
-------------------------------------------

This can edit a range of colors in an editable
image to a single color, allowing a before/after
blink comparison.

A shift-right-click copies the entire contents of
the editable buffer to im2, replacing a range of
colors (including range limit values) in the
editable buffer with a single im2 color.
shift-right-click TRUNC.  The im color range to
replace is specified by the values in the 2
entries to the right of the TRUNC button, and the
new/replaced im2 color by the entry to the right
of the PF button:

  for im range:
    lo: $white_lolim
    hi: $white_hilim
  im2 new:
    if within range: $gray_hilim
    else: same as im
 
To save the color-replaced im2 buffer, first swap
it to editable buffer:

   middle-click-COMPARE
   SAVE IMGS *or* "W" on "im:" line 

In contrast to the in-place operation above that
also uses im2 (crop_im_using_im2cols), this funct
allows a blink comparison using the COMPARE
button, because only one image is initially
loaded.

To duplicate the result of a hand-edit to black,
use target color 1 (EDITED_TO_OFF).

This can be used, for example, to edit bright
fluid to black in place.

For a mouse-driven version of the same thing, use
shift-left-click in the image window (with
$im2boundsflag unticked).

-------------------------------------------
Alt6 funct (no hotkey): trunc editable w/2d colspace ellipse
  imim2op <operation=0,1>
  $imcolcent
  $imcolrad
  $im2colcent
  $im2colrad
-------------------------------------------

[also avail. from "OP" button on F3 panel]

This runs a 2D color space operation (edit if
pixel inside or outside 2D color ellipse) using
the data currently in the main/editable buffer
(im) and the second/compare (im2) buffer.

Visualize the color space ellipse (at each pixel)
in a 2D space with im color on the x-axis and im2
color on the y-axis.

To see the result as a transparent overlay
without actually doing the truncation, click bold
"im2:" label to get a test popup.

N.B.: the truncation result is applied to the
editable buffer (im).  To undo, alt/cmd-z in
image window (or tools window).

The operations:

  $imim2opnum

currently available are:

   0: set colors INSIDE ellipse to OFF
   1: set colors OUTSIDE ellipse to OFF

The ellipse size and center is set with:

  $imcolcent
  $imcolrad
  $im2colcent
  $im2colrad

In more detail, the operation are:

-------------------------------------------
0:  edit ellipse *inside* im,im2 space to OFF
-------------------------------------------

   (x-m)^2      (y-n)^2
   --------  +  --------   <   1
     w^2           h^2

where (x,y) is current color, (m,n) is center
color, and (w,h) are color radii.  If < 1, edit.

TODO:
  x' = x*cos(th) + y*sin(th)
  y' = y*cos(th) - x*sin(th)

-------------------------------------------
1:  edit ellipse *outside* im,im2 space to OFF
-------------------------------------------

Same as 0, but save stuff inside ellipse.

To save the edits, set the desired output name in
the "im:" field and use "W".

N.B.: using SAVEIMG will save the edited images
over the originally-read-in set of images
(probably not wanted, so be sure to first change
name).


####################
truncparms
####################

-------------------------------------------
entry variable: $white_lolim -- 1st entry right of TRUNC
entry variable: $white_hilim -- 2nd entry right of TRUNC
entry variable: $gray_hilim -- 1st entry right of PF
-------------------------------------------
   [next appear on popup from R-click TRUNC/entries]
entry variable: $im2boundsflag -- bounds test on im2 (vs. im)
entry variable: $edit_lolim2 -- structure-saving im low limit
entry variable: $edit_hilim2 -- structure-saving im hi limit
-------------------------------------------

The pixel values in these three entries mainly
control the behavior of the TRUNC (truncate) and
PF (plane filter) buttons (see help for TRUNC and
PF).

These three entries also have an overloaded use
to set bounds and pixel value targets for
pixel-range-dependent editing (either batch or
mouse-based).  A right-click on the TRUNC button
or any of these entries makes a more convenient
popup.

The two entries to the right of the TRUNC button
set the lower and upper bounds of the pixel
values that indicate that the pixel should be
edited to the target value, which is set in the
entry to the right of the PF button.

The bounds test can either be done on the current
editable image (im) or on the second image (im2).
There are also whole-data-set and mouse cursor
controlled versions of these functions.  Here are
the 5 different, slightly asymmetric,
possibilities:

Bounds-dependent edit (all) on im
  -----------------------------------
  (shift-right-click-TRUNC)
  tclfunct: cp_im_to_im2_replacing_cols
  -----------------------------------
  Copy im -> im2, in the process editing pixels
  that are within the bounds ($white_lolim,
  $white_hilim) to the target value
  ($gray_hilim).  To save the result, swap
  editable and im2 using middle-click-COMPARE,
  and save images.  The copy to im2 allows blink
  comparison of the result with the original
  before committing.

Bounds-dependent edit (all) on im using im2
  -----------------------------------
  (ctrl-middle-click-TRUNC)
  tclfunct: crop_im_using_im2cols
  -----------------------------------
  Edit pixels in im for which im2 has pixels
  within the specified bounds ($white_lolim,
  $white_hilim) to the target value
  ($gray_hilim).  This requires first loading
  im2.  N.B.: edits appled to im, not im2!

Bounds-dependent edit (all) on im using im2, save struct
  -----------------------------------
  (ctrl-right-click-TRUNC)
  tclfunct: crop_im_using_im2cols_save
  -----------------------------------
  Same as previous, except edits are only applied
  if the im (editable) voxel is outside a second
  set of bounds ($edit_lolim2, $edit_hilim2).  To
  control the second set of bounds, R-click on
  TRUNC to get a popup (IMAGE BOUNDS DEP EDITING)
  with the second bounds.

Bounds-dependent edit (mouse) on im
  -----------------------------------
  (shift-left-click edit in image window)
  -----------------------------------
  Edit pixels in the editable image (im) that are
  within specified bounds to the target value
  controlled by mouse and brush diameter and
  brush 2D/3D (like first batch function).

Bounds-dependent edit (mouse) on im using im2
  -----------------------------------
  (shift-left-click edit in image window)
  -----------------------------------
  If $im2boundsflag is ticked (on the IMAGE
  BOUNDS DEP EDITING popup), edit voxels in the
  editable image to the target value
  ($gray_hilim) if the corresponding im2 voxel is
  within the bounds ($white_lolim, $white_hilim),
  but only apply the edit if the im voxel is
  outside the second set of bounds ($edit_lolim2,
  $edit_hilim2).  This can be used to preserve
  structure in the editable image.  To ignore the
  structure-preserving bounds, set both
  $edit_lolim2 and $edit_hilim2 to the same value
  (e.g., 0).


####################
wmfilterstd
####################

-------------------------------------------
funct (left-click): wmfilter on editable
  run_wmfilter stdtrunc to_buf1
-------------------------------------------
funct (mid-click): wmfilter on editable -> im2
  run_wmfilter stdtrunc to_buf2
-------------------------------------------


Detailed Description PF button

This button calls the tcl function run_wmfilter:

  run_wmfilter <operation> <targbuf>

where operation is "stdtrunc" and targbuf is
either "to_buf1" or "to_buf2".  The tcl function
runs the standalone C binary, wmfilter, and loads
the result.

The source data is the current state of the
editable buffer.  The truncation settings are
taken from the entries just to the right of the
TRUNC button (tcl variables: $white_lolim and
$white_hilim) and the gray matter setting from
the entry to the right of the PF button (tcl
variable: $gray_hilim).

The  wmfilter binary implements an anisotropic
filter that searches directions in the 5x5x5 or
7x7x7 volume around each voxel for the plane of
least variance, then does a median-like filter in
that plane to "floss" and "spackle" white matter
segmentations.  The size of the volume is
controlled by the value in the unmarked left
entry under the SMOOTHSTRUCT button in the fn-F2
interface (default=5).  7x7x7 takes three times
as long as 5x5x5.

The wmfilter binary is multithreaded (8 threads)
and may cause processor fans to run faster.

The data is truncated (set by $white_lolim,
$white_hilim) before (and after) the anisotropic
filter operation.  The value of $gray_hilim
adjusts a second truncation of gray matter based
on the fraction of zeros in the 5x5x5 or 7x7x7
volume.

-------------------------------------------
funct (left-click): wmfilter on editable
  run_wmfilter stdtrunc to_buf1
-------------------------------------------

A default left-click loads the result back into
the editable buffer.

To save the result, go to the [fn]-F1 interface
and use "W" on the "im:" line.  The default
filename will initially be set to (but can be
changed from):

 <original-editable-file>-pf.mgz  (mgz file)
        *or*
 <original-editable-file>-pf        (CORdir)

To undo, alt/cmd-z in image window (or tools
window).

-------------------------------------------
Alt funct (middle-click):
  run_wmfilter stdtrunc to_buf2
-------------------------------------------

An alternate middle-click on the PF button puts
the output of the planefilter instead into the
im2 buffer so that left-click COMPARE can be used
for blink comparison with the original data.

N.B.: the data in the im2 buffer can't be saved
directly.  However, it can be saved after a
middle-click on the COMPARE button, which swaps
the contents of the editable and im2 buffers.


-------------------------------------------
Trunc/PlaneFilter Summary:
-------------------------------------------

See PFGAU help for description of a Gaussian
version of the original planefilter, and TRUNC
help for reversible truncation of display (for
viewing) or truncation of editable data (for
saving).

To speed up these 3D convolution operations, 
voxels surrounded by a 5x5x5 (or 7x7x7) voxel
volume with values all less than 5 (near black)
are not modified.

The filter may underperform at locations where a
thin 1D stalk or a thin 2D wall attaches to a
large plane.


 Left-click TRUNC -- toggle tmp Trunc editable,COMPARE
 Middle-click TRUNC -- Trunc editable in place

 Left-click PF -- WmFilter+Trunc editable in place
 Middle-click PF -- WmFilter+Trunc to COMPARE

 Left-click PFGAU -- GaussFilter editable in place
 Middle-click PFGAU -- GaussFilter to COMPARE

 Shift-Left-click PFGAU -- Gauss+Trunc editable in place
 Shift-Middle-click PFGAU -- Gauss+Trunc to COMPARE


####################
wmfiltergau
####################

-------------------------------------------
funct (left-click): Gauss wmfilter on editable
  run_wmfilter gauss to_buf1
-------------------------------------------
funct (mid-click): Gauss wmfilter editable -> im2
  run_wmfilter gauss to_buf2
-------------------------------------------
funct (shift-left-click): Gauss/trunc wmfilter
  run_wmfilter gausstrunc to_buf1
-------------------------------------------
funct (shift-mid-click): Gauss/trunc wmfilter -> im2
  run_wmfilter gausstrunc to_buf2
-------------------------------------------


Detailed Description PFGAU button

This button calls the tcl function run_wmfilter:

  run_wmfilter <operation> <targbuf>

where operation is "gauss" or "gausstrunc" and
targbuf is either "to_buf1" or "to_buf2".  The
tcl function runs the standalone C binary,
wmfilter.

The source data is the current state of the
editable buffer.  The width of the Gaussian
filter is set by two entries (tcl variables:
$kcnt and $kfwhm) on either side of "fwhm:" (on
[fn]-F2 interface under the SMOOTHSTRUCT button).

N.B.: the PFGAU operation is 5-10x slower than
the PF operation.

N.B.: the only currently allowed $kcnt values are
5 (default) and 7 (2.7x slower).

The wmfilter binary implements an anisotropic
filter that searches directions in the 5x5x5 (or
7x7x7, three times slower) volume around each
voxel for planes of least variance, then does a
2D convolution with a normalized Gaussian in the
min var plane.

This smooths data sets parallel to locally planar
features such as the cortical surface or the
surface of a brainstem nucleus.  This preserves
the location and visibility of boundaries much
better than an equivalant width 3D Gaussian
filter (SMOOTHSTRUCT button).

-------------------------------------------
funct (left-click): Gauss wmfilter on editable
  run_wmfilter gauss to_buf1
-------------------------------------------

With a default left-click, the PFGAU operation
does no truncation (the values of $white_lolim,
$white_hilim, and $gray_hilim are ignored).

To save the result, go to the [fn]-F1 interface
and use "W" on the "im:" line.  The default
filename (which can be changed) will be:

 <original-editable-file>-pf.mgz  (mgz file)
        *or*
 <original-editable-file>-pf        (CORdir)

To undo, alt/cmd-z in image window (or tools
window).

-------------------------------------------
Alt funct (mid-click): Gauss wmfilter editable -> im2
  run_wmfilter gauss to_buf2
-------------------------------------------

To instead put the output of the Gaussian
planefilter into the im2 buffer so COMPARE can be
used for blink comparison with the original data,
use a middle-click on PFGAU instead of a
left-click.

N.B.: the data in the COMPARE buffer can't be
saved (unless first swapping it with the editable
buffer using a middle-click on the COMPARE
button).

-------------------------------------------
Alt2 funct (shift-left-click): Gauss/trunc wmfilter
  run_wmfilter gausstrunc to_buf1
-------------------------------------------

To truncate the output of the full Gaussian
planefilter using the current TRUNC settings, use
Shift-left-click (modify editable).

To undo, alt/cmd-z in image window (or tools
window).

-------------------------------------------
Alt3 funct (shift-mid-click): Gauss/trunc wmfilter -> im2
  run_wmfilter gausstrunc to_buf2
-------------------------------------------

To do the same but put the output in im2,
Shift-middle-click the PFGAU button.


-------------------------------------------
Trunc/PlaneFilter Summary:
-------------------------------------------

See PF help for description of original
planefilter, and TRUNC help for reversible
truncation of display (for viewing) or truncation
of editable data (for saving).

To speed up these 3D convolution operations,
voxels surrounded by a 5x5x5 (or 7x7x7) voxel
volume with values all less than 5 (near black)
are not modified.

The filter may underperform at locations where a
thin 1D stalk or a thin 2D wall attaches to a
large plane.


 Left-click TRUNC -- toggle tmp Trunc editable,COMPARE
 Middle-click TRUNC -- Trunc editable in place

 Left-click PF -- WmFilter+Trunc editable in place
 Middle-click PF -- WmFilter+Trunc to COMPARE

 Left-click PFGAU -- GaussFilter editable in place
 Middle-click PFGAU -- GaussFilter to COMPARE

 Shift-Left-click PFGAU -- Gauss+Trunc editable in place
 Shift-Middle-click PFGAU -- Gauss+Trunc to COMPARE


####################
fthresh
####################

-------------------------------------------
entry variable: $fthresh -- overlay hard threshold
-------------------------------------------
default: 0.3

(1) threshold simple amplitude statistic

An overlay amplitude statistic below this value
is thresholded -- i.e., the background gray
surface color is displayed.

Use "fmid" to achieve a smoother roll-off into
the background color.  The units are the same as
those of fmid.  The rapidity of the fmid roll-off
is controlled by "fslope".  Setting a large
fslope makes fmid behave like fthresh.

(2) amplitude masked by second statistic

If, in addition to an amplitude, a statistical
mask has also been read in with the "msk{n,s}:"
field (or csurf VOLUME-STATS with Data Type set
to "real+Fstat" or "real+tstat"), then a more
complex masking takes place.  The masking can be
toggled on and off with the unmarked checkbutton
next to "msk{n,s}:" ($overlaymaskflag).

When masking is toggled on, 3 extra entries
appear -- one extra beside fthresh, fmid, and
fslope (truncating the labels to "th", "md", and
"sl").

In this case, the amplitude is subject to *two*
sigmoidal masks.   The first entry in each pair
behaves identically to "fthresh", "fmid" and
"fslope", rolling off the amplitude using the
amplitude itself.

The second entry in each pair masks the amplitude
by an independent sigmoid that uses the value of
the mask statistic to roll off the amplitude.

Bugs

The BRy color scale misbehaves if you set "fmid"
(soft thresh) lower than "fthresh" (hard thresh).

####################
sfthresh
####################

-------------------------------------------
entry variable: $sfthresh -- statmask hard threshold
-------------------------------------------
default: 0.3

This entry is only visible if overlaymaskflag is
ticked (to left of "mskn:" or "mskup:").

If the stat mask for a pixel is below this
number, the *value* (e.g., coef) is masked to
background.

The units of this mask threshold ($sfthresh) will
*not* in general be the same as the units of the
amplitude thresh ($fthresh).

See $fthresh and $fmid help for more details.

####################
fmid
####################

-------------------------------------------
entry variable: $fmid -- overlay sigmoid threshold
-------------------------------------------
default: 1.1
keyboard adjust Linux: <Alt-i,I>  -- down/up 0.1
keyboard adjust Mac: <Cmd-i,I> -- down/up 0.1

Adjust position (in amplitude statistic units --
e.g., sqrt F-ratio) where color contrast sigmoid
changes the fastest (see "fslope" to adjust
contrast).  In double-ended scales, there are two
sigmoids at equal distances from zero.  Fmid is
effectively a soft threshold (setting fthresh
equal to fmid truncates lower half of sigmoid).

If an additional masking statistic has been read
in ($overlaymaskflag is set), two fmid entries
will appear (re-labeled "md"). The first is the
same as before (in amplitude units), and the
second is a soft threshold in mask statistic
units.

Details

Code outline for set real-valued color given
input: real, stat, bgcol:

  /* hard thresh on amplitude */
  if (fabs(ampl)<fthresh) {
    color = bgcol;
    return;
  }

  /* hard thresh if below stat */
  if (overlaymaskflag && fabs(stat)<sfthresh) {
    color = bgcol;
    return;
  }

  /* second sigmoid for soft stat thresh */
  real *=
   (1.0 + tanh(sfslope*(fabs(stat)-sfmid)))/2.0;

  /* use real to set hue (sigmoid here) */
  ...


Code outline for set complex-valued color given
input: real, imag, stat, bgcol

  /* get ampl,phase from real,imag */
  ampl = sqrt(real*real + imag*imag);
  phase = atan2(imag,real);

  /* hard thresh on amplitude */
  if (fabs(ampl)<fthresh) {
    color = bgcol;
    return;
  }

  /* hard thresh if below stat */
  if (overlaymaskflag && fabs(stat)<sfthresh) {
    color = bgcol;
    return;
  }

  /* first sigmoid for soft ampl thresh */
  ampl = (1.0 + tanh(fslope*(ampl-fmid)))/2.0;

  /* second sigmoid for soft stat thresh */
  if (statmaskampflag)
    ampl *= (1.0 + tanh(sfslope*(stat-sfmid)))/2.0;

  /* use ampl to set saturation */
  ...

  /* use phase to set hue */
  ...

####################
sfmid
####################

-------------------------------------------
entry variable: $sfmid -- statmask sigmoid threshold
-------------------------------------------
default: 0.0

This entry is only visible if overlaymaskflag is
ticked (to left of "mskn:" or "mskup:").

This entry defines the soft threshold for masking
the value (e.g., coef) at a pixel using the stat
mask (same units as $sfthresh).

The units of this mask threshold ($sfmid) will
*not* in general be the same as the units of the
amplitude thresh ($fmid).

See $fmid help for more details.

####################
fslope
####################

-------------------------------------------
entry variable: $fslope -- overlay contrast
-------------------------------------------
default: 1.5

Controls steepness of contrast sigmoid (or double
sigmoids with two-ended/signed color scales).
Smaller values give a more linear relation
between statistic and color saturation.  At large
values (>10), a hard threshold is approached.  At
statistic values below fmid, overlay colors fade
smoothly into light and dark background grays.

If an additional masking statistic has been read
in ($overlaymaskflag is set), two fslope entries
will appear (re-labeled "sl").  The first is the
same as before (affects abruptness of
thresholding of amplitude), and the second
affects abruptness of thresholding using mask
statistic units.

####################
sfslope
####################

-------------------------------------------
entry variable: $sfslope -- statmask contrast
-------------------------------------------
default: 1.5

This entry is only visible if overlaymaskflag is
ticked (to left of "mskn:" or "mskup:").

Controls sharpness of stat masking.  See $fslope
and $fmid help for more details.

####################
im2label
####################

-------------------------------------------
tickbox variable: $imim2elloverlayflag -- 2D colmask
popup entry variable: imcolcent       => im target color
popup entry varibale: imcolrad        => im2 col radius
popup entry variable: im2colcent     => im2 target color
popup entry variable: im2colrad       => im2 col radius
popup entry variable: overlayalpha  => overlay transparency
-------------------------------------------
keyboard equiv: <none>

Color Conjunction Overlay

A left-click on the "im2:" label brings up a
popup panel for testing 2D color space
conjunction masking.  To use color space
conjunction as a mask, see below.

To mark regions (with a transparent overlay) that
fall within an elliptical region of (im,im2)
color space, first read in a second image set
with different contrast than the first.

Then set the variables on the popup to control
whether the overlay is active, the center and
size of the ellipse, and the overlay
transparency:

  imim2elloverlayflag
  imcolcent     => im target color
  imcolrad
  im2colcent   => im2 target color
  im2colrad
  overlayalpha

The variables $imcolcent and $im2colcent control
the position of the target color in each of the
images.  The dimensions of the ellipse are set by
$imcolrad and $im2colrad.

Units for all 4 are are grayscale colors (0-255).
Any voxel whose pair of colors lie within that
ellipse will be given a transparent green
overlay.

The transparent overlay is always displayed over
the first image set.  To toggle the visibility of
the overlay, use the $imim2elloverlayflag
checkbutton.

Use $overlayalpha to adjust the transparency of
the green acceptance mark (255 is opaque):

Equivalent/redundant F4 interface

The popup variables are also available on the
large interface (fn-F4) as two pairs of entries
just to the right of the COMPARE button:

    im:cent,rad:  ____   ____
  im2:cent,rad:  ____   ____

On that panel, $imim2elloverlayflag is
abbreviated "2Dcol".

Using the Color Conjunction As Mask

To use the areas detected by 2D color conjunction
to mask the editable data set, R-click the TRUNC
button and select the last button on the button
bar:

  Truncate Using 2D Color Space Ellipse

This make a popup that allows truncating editable
buffer colors that are either inside or outside
of the color space ellipse.  This operation is
also available (more opaquely) on the F3
interface using the lower right "OP" button right
(0=trunc-inside, 1=trunc-outside).


####################
im2entry
####################

-------------------------------------------
entry variable: $im2abbrev -- comparison image set
-------------------------------------------
keyboard equiv: [none]

Second/Comparison Image Set (also MGH Seg Overlay)

On startup, the "im2:" entry will contain "T1"
but no second/comparison data set will have been
loaded.  Enter either:

(1) a COR dir (containing 256 256x256x1byte
    or 512 512x512x1byte COR-??? images in
    coronal orientation, and COR-.info file)
    (orig freesurfer format, now rare)

       *or*

(2) an .mgh/.mgh format file (with similar
    orientation, datasize, and imagesize,
    (also typically 256x256x256 byte image)

(3) an .mgh/.mgh format file containing
    a 3D parcellation (int idnum's)

and click the "R" to the right of the entry to
read in a second/comparison data set.  See the
help for the "im:" entry for more details on the
acceptable image format details.

The file name can be entered as a relative,
abbreviated, or absolute path.  Assuming
SUBJECTS_DIR equals /fmri/subjects, the following
3 names refer to the same COR dir data set:

  T1
  ~/mri/T1
  /fmri/subjects/martys/mri/T1

and the following 3 names refer to the same .mgz
data set:

  T1.mgz
  ~/mri/T1.mgz
  /fmri/subjects/martys/mri/T1.mgz

A <Return> is same as "R".  N.B.: edits are
*always* applied to the first/editable image set,
not this second image set, even when the second
image is being viewed.  This is useful, for
example, for editing the wm.mgz data set while
viewing the orig.mgz data set.

Only the first image set can be edited and saved.
However, the "editable" and "second" image can be
swapped.  Also, previous edits made to an image
that is then read into the "second" image can be
copied to the current first/editable image (see
R-click help for the COMPARE button).

MGH Segmentation/ROIs Overlay

This "im2:" entry can also be used to read a 3D
MGH segementation ROI volume as a transparent
overlay.  This is done by the tkmedit.tcl
function, detectshowlabel (after the segmentation
volume has been read into the second buffer).  If
the *.mgz filename stem is one of:

  aseg
  aseg.auto
  aseg.auto_noCCseg
  aparc+aseg
  aparc.a2005s+aseg
  aparc.a2009s+aseg
  wmparc
  wm.asegedit
  wm.seg
  ribbon
  lh.ribbon
  rh.ribbon
  CsurfMaps1
  MY_ANNOT
  HCP-MMP1

the file (containing either byte or int region id
numbers), will be also used to generate a
transparent label overlay onto the image in the
primary (editable) buffer, in most cases using
the region number -> color lookup table in the
text file:

  $CSURF_DIR/lib/lut/FreeSurferColorLUT.txt

If the image filename starts with "Csurf" or
"MY_ANNOT", the overlay colors will instead be
read from:

  $CSURF_DIR/lib/lut/CsurfColorLUT-both.txt

If the image filename start with "HCP-MMP1", the
overlay colors will instead be read from:

  $CSURF_DIR/lib/lut/HCP-MMP1ColorLUT-both.txt

The last two color tables were generated using
the standalone tcl script:

  $CSURF_DIR/bin/noarch/mkbothlut

from single hemisphere Csurf and HCP color tables
(see usage). For more information, do a R-click
to get help on the popup from running the
tksurfer annot2roi.tcl script (also: csurf ->
Help -> All Help Contents -> TkSurfer ->
TclScript -> annot2ROIs.

To add to the list of allowed overlays, update
$mghseglabstemlist at the top of tkmedit.tcl.

Double-middle-click a region to get a popup with
the region name, idnum, and color for an overlay
region.

The byte or integer values in the 3D segmentation
volume will also be loaded as gray-scale bytes
(0-255) into the second single-byte comparison
buffer.  These will only be visible if you untick
"la" (overlay) and click "COMPARE". N.B.: if the
segmentation file contains ints, the single-byte
gray-scale colors in the comparison buffer may be
truncated.

Color Conjunction Overlay and Mask

To mark regions that fall within an elliptical
region of the 2D (im,im2) 'color' (brightness)
space, or to use this as a mask, see R-click help
for the bold "im2" label.  A default left-click
on the bold "im2:" label brings up a color
conjuction popup.

This is a way of examining whether a second image
with a different contrast may be helpful for
segmentation in conjunction with a first image.

####################
im2read
####################

-------------------------------------------
function: read_second_images <CORdir *or* .mgz>
-------------------------------------------
keyboard equivalent: none

The "R" button on the "im2:" line reads in a
second set of images to allow them to be blink
COMPARE'd with the first, editable image set.

It can also be used to read a segmentation
overlay (*.mgz format, see below, handled by the
tkmedit.tcl function, detectshowlabel).

The second image buffer cannot be edited or
directly saved, but can be swapped.

N.B.: edits done while viewing the secondary
"im2:" COMPARE buffer will be applied invisibly
to primary, editable "im:" image set (useful, for
example, when editable=wm and image2=orig).

The default output of PF (planefilter) or PFGAU
(gaussian planefilter) is to "im2:".

Reading a different data set with "R" on the
"im2:" line displaces any data currently in the
secondary buffer without question.

To swap the contents of the "im:" (editable) and
"im2:" (compare) buffers, do an alternate
middle-click on the COMPARE button.

If the image in the secondary "im2:" buffer has
been previously edited, you can apply those edits
to the primary buffer with shift-middle-click
COMPARE (edits-to-black are not completely
black).

3D Segmentation/ROIs Overlay

A byte or int-containing MGH 3D segmentation file
(e.g., aparc+aseg) can also be read by "R" to
generate a transparent ROI label overlay of the
data in the primary (editable) buffer, if the
second image set filename stem is:

  aseg
  aseg.auto
  aseg.auto_noCCseg
  aparc+aseg
  aparc.a2005s+aseg
  aparc.a2009s+aseg
  wmparc
  wm.asegedit
  wm.seg
  ribbon
  lh.ribbon
  rh.ribbon
  CsurfMaps1
  MY_ANNOT
  HCP-MMP1

in most cases, the colors will be specified by
also reading:

  $CSURF_DIR/lib/lut/FreeSurferColorLUT.txt

If the image filename starts with "Csurf" or
"MY_ANNOT", the overlay colors will instead be 
read from:

  $CSURF_DIR/lib/lut/CsurfColorLUT-both.txt

If the image filename start with "HCP-MMP1", the
overlay colors will instead be read from:

  $CSURF_DIR/lib/lut/HCP-MMP1ColorLUT-both.txt

For more information, do a R-click to get help on
the popup from running the tksurfer annot2roi.tcl
script (also: csurf -> Help -> All Help Contents
-> TkSurfer -> TclScript -> annot2ROIs.

Double-middle-click a region to get a popup with
the region name, idnum, and color for an overlay
region.

See R-click help for the "im2:" entry for
details.  To add to the list, update
$mghseglabstemlist at the top of tkmedit.tcl.

To use the segmentation to extract timecourses,
see the R-click help for the "T" button on the
"roiup:" line (F2 interface).

####################
seglabel
####################

-------------------------------------------
tickbox variable (left-click):
  $im2lutoverlayflag -- toggle visibility labels
-------------------------------------------
tickbox variable (middle-click):
  $im2boundsflag -- toggle use im2 (vs. im)
-------------------------------------------

The tickbox at the lower right labeled "la" has
two different functions.


-------------------------------------------
Left-click (toggle $im2lutoverlayflag)
-------------------------------------------

A default left click on the "la" tickbox to the
right of the "im2:" entry toggle visibility of a
transparent overlay of an MGH 3D segmentation
label file.

First read an MGH 3D segmentation label file
(e.g., aparc+aseg.mgz) into "im2:" using the
dropdown to select a file followed by the
adjoining "R" button.  These files may contain
bytes or ints (this will auto-tick "la").

The numbers in the 3D label file (bytes or ints)
are translated into transparent overlay colors by
using the tkmedit tcl/C function,
read_sort_mghval2rgblut, to read the file:

  $CSURF_DIR/lib/lut/FreeSurferColorLUT.txt

which is a 6-column file that looks like this:

#No.	Label Name:		R	G	B	A
#-------------------------------------------------------------------
12	Left-Putamen		236	13	17	0
13	Left-Pallidum		12	48	255	0
 [etc]
#-------------------------------------------------------------------

To use a different MGH-format (6 column) color
lookup table, enter it into the color lookup
table entry (just above "interpolLUT" at the far
right of the F2 tkmedit interface), and click the
"R" there.  This entry can also read 4-column
csurf color lookup tables (for stats overlays).

A double-middle-click on a displayed overlay
region will generate a pop-up with the region
name, idnum, rgb value, and the (0-255) pixel
value of the underlying data set.

The csurf log reports the (byte or int) MGH
segmentation label number (if loaded) when a
pixel is selected:

  tkmedit: val=110 (segid=2022) pixcoords: ...

The transparency of the overlay colors is
controlled by $overlayalpha (default=127), which
can be adjusted using the "tran:" entry at the
lower right of the large F4 tkmedit interface.

The "randlut256" tickbox under "tran:" will
generate a new 256-entry color lookup table (for
byte values 0-255) each time it is clicked to on
(only useful for segmentation overlay containing
bytes, not ints).

To block double-clicks from generating pop-ups
(e.g., for fast editing), use the "no double-clk"
tickbox on the F4 tkmedit interface
($blockdoubleclickflag).

-------------------------------------------
Mid-click (toggle $im2boundsflag)
-------------------------------------------

An alternate middle-click on the "la" tickbox
toggles $im2boundsflag, which causes
bounds-dependent editing (shift-left-click
editing in the image window) to use the second
image (instead of the editable image).  The
bounds are set by the two entries to the right of
the TRUNC button and the target value by the
entry to the right of PF button.



####################
compare
####################

-------------------------------------------
var,funct (left-click): toggle view editable/im2
  set drawsecondflag 1
  redraw
  keyboard equiv Linux:
    keyboard equiv: <Alt-'>
    keyboard equiv: <Alt-Shift-C>      [b/c cmd-c reserved]
    keyboard equiv: <Alt-0>
  keyboard equiv Mac:
    keyboard equiv: <Cmd-'>
    keyboard equiv: <Cmd-Shift-C>      [b/c cmd-c reserved]
    keyboard equiv: <Cmd-0>
-------------------------------------------
funct (middle-click): swap contents editable/im2
  swap_imim2
-------------------------------------------
funct (shift-middle-click): copy im2 edits to editable
  im2wmedits_to_im
-------------------------------------------
funct (shift-left-click): copy contrast-adj'd to editable
  visible_to_im
-------------------------------------------


Detailed Description COMPARE button

A default left-click of the COMPARE button blinks
back and forth between first and second image set
(sunken button with 2nd image).  First, must READ
second imageset (re-read OK) (or use function:
read_second_images <cordir/mgzfile>).

Any image editing actions (middle/right clicks,
flip, smooth) are applied only to first (command
line) image set, regardless of which image set is
visible.  This can be helpful when the second
image is an "orig" image with better contrast and
context than the already-truncated white matter.

-------------------------------------------
Alt funct (middle-click): swap contents editable/im2
  swap_imim2
-------------------------------------------

An alternate middle-click of the COMPARE button
swaps the CONTENTS of the editable and im2
buffers.  This makes it possible to save out the
contents of the im2 buffer.  There is a warning
whenever this alternate function is called.  If
the editable buffer has been edited, there is a
second warning to confirm this is really what you
want to do.

-------------------------------------------
Alt2 funct (shift-middle-click): copy im2 edits to editable
  im2wmedits_to_im
-------------------------------------------

A second alternate shift-middle-click of the
COMPARE button applies edits from im2 to the
current editable buffer.  "Edits" are defined as
pixels that have the value 255 (edited to white)
or 1 (edited to black).

This can be used when in the course of a manual
reconstruction, if after already having edited a
white matter (wm) data set, you want to go back
and make additional local hand-normalization
steps (e.g., using spherical Gaussian: "sph" tick
in F3 panel), without losing the edits made so
far.  The procedure is:

  (0) already did many edits on wm.mgz
  (1) copy prev edited wm.mgz to new name
  (2) hand normalize, remake wm.mgz, load new one
  (3) load wm-old.mgz into "im2:" w/"R"
  (4) shift-middle-COMPARE
  (5) SAVE IMGS

-------------------------------------------
Alt3 funct (shift-left-click): cp contr-adj'd to editable
  visible_to_im
-------------------------------------------

A third alternate shift-middle-click of the
COMPARE button copies the contrast-adjusted
visible pixel values (N.B.: currently in the
editable buffer) to the editable buffer,
overwriting its current contents.

N.B.: the contrast-adjusted image is typically
the result of a non-linear (e.g., sigmoid)
function.

To avoid applying the contrast adjustments
recursively, $linearflag is set to 1 (see
interface button on lower right of large F4
interface panel).

This can be used, for example, to save a
contrast-reversed image (negative value for
"contr:").

N.B.: SAVE IMGS will overwrite the initial
dataset, so to save the contrast-adjusted images 
to a new file, enter a name in the upper right
"im:" entry and click "W".

To undo, alt/cmd-z in image window (or tools
window).

####################
smoothstats
####################

#### 3D smoothing and gradient calc ####
-------------------------------------------
function: (left-click SMOOTH STSATS)
  smooth_stats_3d <kernelcells> <fwhm>
-------------------------------------------
function: (left-click SMOOTHSTRUCT)
  smooth_3d <kernelcells> <fwhm>
-------------------------------------------
functions: (available from tcl script)
  smooth_3d_dx <cells> <fwhm>
  smooth_3d_dy <cells> <fwhm>
  smooth_3d_dz <cells> <fwhm>
-------------------------------------------


The SMOOTHSTRUCT or SMOOTH STATS button is only
visible on fn-F2 interface.  With just a
structural scan, SMOOTHSTRUCT appears.  If an
overlay is loaded (and lower left "overlay" is
ticked), SMOOTH STATS appears.


-------------------------------------------
function: (left-click SMOOTHSTSATS)
  smooth_stats_3d <kernelcells> <fwhm>
-------------------------------------------

Smoothing stats overlay

When a statistical overlay data set is loaded, it
is first registered to the structural dataset
using register.dat, and is then upsampled to the
resolution of the structural underlay (1x1x1 mm
or 0.5x0.5x0.5 mm) without smoothing (nearest
neighbor sampling).

The SMOOTHSTATS button performs a 3D Gaussian
smoothing (convolution) using an integer kernel
cell size set up by $kcnt (unlabeled entry to the
left of "fwhm:" label), and a full width half
maximum kernel width set by the "fwhm:" field.
This is implemented as three 1D convolution
passes.  The units of fwhm and kernel cell size
are underlay dataset pixels, which are either mm
(256x256x256 underlay) or half mm (512x512x512
underlay).

The effective kernel radius, r, resulting from
successive applications of radius r1 and r2 can
be calculated using:

  r = sqrt(r1^2 + r2^2 + ... )

For n repeated applications of the same radius
kernel, r1, that reduces to:

  r = sqrt(n) * r1

Thus, 6 clicks on SMOOTHSTATS with the default
1.5 width kernel on a default 1x1x1mm underlay
gives the following FWHM smoothing on the
overlay stats:

  1 -> 1.50 mm
  2 -> 2.12 mm
  3 -> 2.60 mm
  4 -> 3.00 mm
  5 -> 3.35 mm
  6 -> 3.67 mm

The computation time scales linearly with the
(1D) kernel cell size.

No undo (but you can re-read orig stats).

-------------------------------------------
function: (left-click SMOOTHSTRUCT)
  smooth_3d <kernelcells> <fwhm>
-------------------------------------------

Smoothing editable structural underlay

To perform a 3D Gaussian smoothing of the
structural underlay itself, hit [fn-]F2 (if
tkmedit panel not already enlarged), or unlick
"overlay" (if overlay loaded).  The name of the
smooth button now changes to "SMOOTHSTRUCT".
This operation can only be done on the editable
image (not on the "im2" image).  The units are
pixels as before.

The auto-segmentation algorithms used in
recon-all sometimes fail to segment the
cerebellum and overlying inferotemporal cortex
properly when given a single high quality
MPRAGE.  This results in erosion of parts of
inferotemporal cortex.  This can usually be
fixed by light pre-smoothing of the orig data
set in tkmedit:

   open orig.mgz data set in tkmedit
   F2 (expand tkmedit interface)
   set kernel width ("fwhm:") to 1.0 or 1.5
   SMOOTHSTRUCT
   F1 (back to small interface)
   set "im:" field to: orig1mm.mgz
   "W" button (at right)

Finally, on command line, convert back
to nifti and re-run recon-all with the
smoothed input:

   cd $SUBJECTS_DIR/<subjectname>/mri
   mri_convert orig1mm.mgz orig1mm.nii

To immediately compare to unsmoothed, you can
read the unsmoothed (orig[.mgz]) back into the
second tkmedit buffer and then use the COMPARE
button:

   im2: -> orig[.mgz]
   READ
   COMPARE (toggles between the two buffers)

To undo, alt/cmd-z in image window (or tools
window).

-------------------------------------------
functions: (available from tcl script)
  smooth_3d_dx <cells> <fwhm>
  smooth_3d_dy <cells> <fwhm>
  smooth_3d_dz <cells> <fwhm>
  smooth_3d_nn <steps>
-------------------------------------------

Calculate gradients on editable structural underlay

To calculate the image gradient of the editable
image, there are three functions to convolve with
a partial derivative of a Gaussian in the x, y,
and z directions:

  smooth_3d_dx <cells> <fwhm>
  smooth_3d_dy <cells> <fwhm>
  smooth_3d_dz <cells> <fwhm>

The results are saved in 3 internal image buffers
(gradx, grady, gradz) for use in other image
calculations.

No undo needed since editable image is put back
after calc.

Nearest neighbor smoothing on editable

There is a third rarely used smoothing function,
smooth_3d_nn, that operates on the editable
underlay.  It does a boxcar average of the center
voxel and its 26 neighbors.

To undo, alt/cmd-z in image window (or tools
window).

####################
kernelsize
####################

-------------------------------------------
entry variable: $kcnt -- integer cell size of 3D kernel
-------------------------------------------
default: 5 (unit are 1 pixel cells)

The unlabeled entry to the left of the "fwhm:"
field sets the integer cell size of the 3D
Gaussian smoothing kernel.  The units are
structural underlay pixels.  These are usually 1
mm wide with standard 'conforming' 256x256
structural scans (but 0.5 mm wide in the case of
512x512 data sets).

For the default FWHM of 1.5 pixels, the kernel
cell size is 5 (5x5x5).  If the FWHM is increasd,
the cell size should be increased, too (to about
3x the FWHM).

Computation time scales linearly with this
variable.

N.B.: this variable is also used by the local
plane of least variance (anisotropic) filter
functions (PF, PFGAU) in which case, the only
allowed values are 5 and 7.

####################
fwhm
####################

-------------------------------------------
entry variable: $kfwhm -- full width halfmax 3D kernel
-------------------------------------------
default: 1.5 pixels

The "fwhm:" field sets the width of the 3D
Gaussian smoothing kernel applied to the
functional statistics, after they have been
upsampled to pixel resolution of structural
underlay (1x1x1mm or 0.5x0.5x0.5mm).  Thus, the
default setting of fwhm (1.5 pixels) is 1.5mm for
a 256^3 underlay, but 0.75mm for a 512^3 underlay.

If the FWHM of the Gaussian kernel is increased,
the kernel cell size (unlabeled entry to left,
also in pixels) should be increased, too, to
avoid truncating the edge of the Gaussian (kernel
cells should be ~3x fwhm pixels).

####################
smoothmask
####################

-------------------------------------------
tickbox variable: $smoothoverlaymaskflag -- toggle smooth mask
-------------------------------------------
default: 1 (TRUE)

The "m" tickbox at the upper right side of the F2
panel under the SMOOTH STATS button toggles
$smoothoverlaymaskflag.  This controls whether
the overlay mask will be smoothed when SMOOTH
STATS is clicked.  Default is ticked.

If unticked, when smoothing is applied to the real
or complex data, the stat mask will *not* be smoothed.

N.B.: no effect if stat mask not loaded

N.B.: no effect if structural scan loaded

####################
colscale
####################

-------------------------------------------
switch variable: $colscale -- overlay color
-------------------------------------------
switch value: 0-13

The radio buttons at the right side of the fn-F2
interface set the overlay color scale.

See R-click help for individual radio buttons for
more information.

####################
val_w1
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 0 => RBG wheel1 (complex data)

This color scale designed for phase-encoded data
(e.g., retinotopic mapping).  With integral
angle_cycles (1,2,3), the scale is red->blu->grn
wrapping around at red.  With non-integral
angle_cycles there is only one red->blu->grn
cycle (phase values below red clampled to red and
phase values above green clamped to green).

####################
val_ht
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 1 => pos heat scale (complex data)

The scale requires complex-valued data.  It runs
from dark brown to white and displays any brain
region significantly activated in a periodic
fashion (i.e., all phases).  Truncphase can be
used to truncate half of the phases and
angle_offset controls the exact half that are
truncated.

The angle_offset for two condition expt with 20s
ON and 20s OFF should be something like 0.1 (this
is in units of one cycle: 0.1 * 40 sec = 4 sec
delay).

####################
val_bi
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 4 => two-cond red-grn (complex data)

This color scale designed for two condition,
phase-analyzed data (standard OFF/ON design).
The first half of the phases (correlated with
the odd stim) are colored grn and the second half
(correlated with the even stim) are colored red.
A *positive* angle_offset cancels a delay in
the functional signal.

####################
val_BRw
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 6 => blu/red to white (real data)

Two-condition statistic color scale for real
signed data.  Red positively correlated, blue
negatively correlated (reversible with
revphaseflag).  As significance increases, scale
goes to white for both positive and negative
correlations.  Not affected by angle_offset,
angle_cycles.

####################
val_BRy
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 11 => blue/red to yellow/cyan

Two-condition statistic color scale for real
signed data.  Red is positive and blue is
negative correlation (can be reversed with
revphaseflag).  As significance increases, scale
goes red->yellow and blue->cyan (saturates more
slowly than BRw scale).  Not affected by
angle_offset, angle_cycles.

Unlike other scales, fmid should always be higher
than fthresh (fmid < fthresh gives green).  The
roll off to background is set by fthresh while
fmid sets the red->yellow (and blue->cyan)
transition points.

####################
val_lt
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 12 => real-val'd color lookup table

This color scale is designed for user-entered
real-valued custom val->rgb color look up table
(see entry immediately under color scale radio
buttons).

To display complex *phase* data using a custom
color scale, use colscale=14 (use tcl script to
set).

####################
val2rgb
####################

-------------------------------------------
entry variable: $val2rgblut -- abs name color LUT file
-------------------------------------------
default: */$scandir/val2rgb.lut

The unmarked entry at the right of the fn-F2
interface, under the color scale radio buttons
contains the filename of the color look-up table
(LUT) for use with colscale=12 (color scale radio
button "lt", real-valued color scale),
colscale=13 (complex amplitude, script-only), and
colscale=14 (complex phase: "lt" then "cpx", or
read LUT with "cpx" clicked).

This file can have any name and be saved to and
read from anywhere, but by default, and in order
to be automatically read on tkmedit startup, it
is inside the current scandir, e.g.:

 $FUNCTIONALS_DIR/110219MS/image/mov1/val2rgb.lut

Here is an example of the ASCII file format for a
positive real-valued color scale ranging from
gray->red->blue->green:

## default val->color lookup table
# val   red     green   blue
0.0     88      88      88
1.0     255     0       0
2.0     0       0       255
3.5     0       255     0

The val's are floating point numbers, possibly
negative, that have to be in ascending order (tho
not necessarily evenly spaced).  The r,g,b's are
0-255.  Empty lines and comment lines (lines
starting with '#') are ignored.

Interpolated LUT

If $interpolatelutflag is 1 ("intplut" check at
upper right), the r,g,b entries in the table are
linearly interpolated for intermediate val's.
Val's off the top end of the scale are clamped to
the top entry; val's below the bottom edge fade
to the background curvature.  The fthresh (N.B.:
*not* absolute value of fthresh) is respected.

Non-interpolated LUT 

If $interpolatelutflag is 0, the r,g,b color
stays the same for vals until halfway to the next
(possibly unevenly spaced) val in the table, and
reverts to background at at a similar spacing for
val's beyond both the bottom *and* the top end of
the LUT table.

Here is a tcl script that reads the real-valued
look-up table above and displays data with
interpolation first OFF, then ON:

   set val2rgblut /tmp/zz.lut
   read_val2rgblut
   set fthresh 0   ;# no trunc
   set colscale 12
   set interpolatelutflag 0
   redraw
   set interpolatelutflag 1
   redraw

Color LUT files complex-valued phase/amplitude

If $complexvalflag is true ("cpx" clicked), then
a *phase* color LUT file is expected ($colscale
14).  The val's (first column) should begin at
0.0 and end at 1.0, and the colors for 0.0 and
1.0 should typically be the same if you want the
phase colors to wrap around smoothly.  The
complex phase LUT always interpolates (no effect
of changing $interpolatelutflag).

You can write out an example file like this by
clicking the phase color wheel ("w1") and writing
out a LUT file ("W" to right of "lut:" entry).
Note that the *currently displayed* color scale
is written out -- i.e., incorporating any effects
of $revphaseflag, $angle_offset, and
$angle_cycles.

Here is an example of a LUT for complex phase
suitable for hand-editing (R->B->G):

## default val->color lookup table
# val   red     green   blue
0.0     255      0       0
0.3333  0        0     255
0.6667  0      255       0
1.0     255      0       0

The display of phase color LUT's is affected by
$revphaseflag and $angle_offset (but not by
$angle_cycles).  Because of this, to re-display a
phase color LUT just written without change, turn
off $revphaseflag and set $angle_offset to 0.0
after re-reading the LUT.

A color LUT for complex-valued *amplitude* is
also available from a script.  First read in the
color LUT (which now can range above 1.0), and
set $complexvalflag (click "cpx"), then as the
last step (since interface clicks on "cpx"
auto-pick real vs. complex phase colscale) set
the colscale to complex *amplitude* LUT with a
one-line tcl script:

  set colscale 13

####################
val2rgb_edit
####################

-------------------------------------------
tcl function: editfile <lutfile> -- edit current LUT
-------------------------------------------
keyboard equivalent: none

Edit the color lookup table (LUT) using a basic
editor (tries gedit,nedit,xedit in that order).
To cause the editor to be vi inside a popped-up
gterm or xterm, set this environment variable:

  setenv CSURFEDITORVIGTERM

If the file in the "lut:" field (by default,
*/$scandir/val2rgb.lut) doesn't exist when the
"E" button is clicked, a default one will be
contructed when the editor opens.

####################
val2rgb_read
####################

-------------------------------------------
function: read_val2rgblut -- read col LUT
-------------------------------------------
keyboard equivalent: none

Read color lookup table (LUT) from file whose
name is current value of $val2rgblut (entry at
left).

####################
val2rgb_write
####################

-------------------------------------------
function: write_val2rgblut -- write col LUT
-------------------------------------------
keyboard equivalent: none

Write color lookup table (LUT) for current
colscale containing $val2rgblutout (default=15)
entries.

####################
clear
####################

-------------------------------------------
function: clear_upsamp_stats -- clear overlay
-------------------------------------------
keyboard equivalent: none

Clear data from any up-sampled (underlay
resolution) buffers that have data in them (real,
imaginary, mask).  Re-read native or upsampled
stats to view overlay again.

####################
intplut
####################

-------------------------------------------
tickbox variable: $interpolatelutflag -- color LUT behavior
-------------------------------------------
default: 0 (FALSE)

The "interpolLUT" tickbox (right side of fn-F2
interface) controls color lookup table
interpolation.

If flag set, r,g,b's for val's in between table
entries are interpolated, else colors are
constant until val is midway between two table
entries.

See help for entry immediately above for more
details.

####################
revphase
####################

-------------------------------------------
tickbox variable: $revphaseflag -- reverse time axis
-------------------------------------------
default: 0 (FALSE)

The "rev" tickbox (just left of "angoff:" entry
on fn-F2 interface) reverse phase as well as real
valued color scales.

When revphaseflag is TRUE (revphase is selected),
the time axis is reversed, i.e. f(t) -> f(-t).
In general, this is not equivalent to multiplying
by -1.

####################
truncphase
####################

-------------------------------------------
tickbox variable: $truncphaseflag -- show only
-------------------------------------------
positive phase
default: 0 (FALSE)

When truncphaseflag is TRUE (truncphase is
selected), only the positive phase (0 to Pi) is
shown.  For example, when using the red-green
coloring (colscale=4), only the red is shown.

####################
truncphasemin
####################

-------------------------------------------
entry variable: $truncphasemin -- truncate phase min
-------------------------------------------
default: 0.25

Used if "truncphase" is set ($truncphaseflag).
Adjusts min phase angle where color scale is hard
truncated to background grays.  Applied *after*
$revphaseflag, $invphaseflag, and $angle_offset.
For gradual fade out, use fadef.

####################
truncphasemax
####################

-------------------------------------------
entry variable: $truncphasemax -- truncate phase max
-------------------------------------------
default: 0.75

Used if "truncphase" is set ($truncphaseflag).
Adjusts max phase angle where color scale is hard
truncated to background grays.  Applied *after*
$revphaseflag, $invphaseflag, and $angle_offset.
For gradual fade out, use fadef.

####################
angle_cycles
####################

-------------------------------------------
entry variable: $angle_cycles -- adjust phase colscale
-------------------------------------------
default: 2.2

The "anglecycles:" entry (on lower right of fn-F2
panel) adjusts phase color scales.

Integral values (1,2,3) result in one or more
red-green-blue wraps of across 360 deg of phase.
Non-integral values result in one red-green-blue
cycle (e.g., 2.2 is one cycle slightly tighter
than 2 cycles per 360 deg).  Phases just beyond
that are clamped to the ending colors while
phases opposite the center (blue) approach gray.

####################
angle_offset
####################

-------------------------------------------
entry variable: $angle_offset -- rotate phase colscale
-------------------------------------------
default: 0.0

The "angoff:" entry (on lower right of fn-F2
panel) adjusts the rotational offset of phase
color scales.

Values from 0.0 to 1.0 rotate the color scale in
a clockwise direction from 0 to 360 degrees.  For
a default polar angle stimulus slowly rotating in
the clockwise direction, slightly increasing the
value above 0.0 will compensate for a longer
hemodynamic delay.

####################
fadef
####################

-------------------------------------------
entry variable: $fadef -- ipsilateral fade out
-------------------------------------------
default: 0.7

The "fadef:" field controls the fraction of the
colorscale that is *not* grayed-out (yellowed-out
if ipsiyellowfact>0.0).  No effect on integral
angle_cycles.  At 0.99, ipsilateral graying-out
is disabled.  Lower fadef's result in a larger
percentage of phases being grayed-out.  At
fadef=0.0, 2/3 of color wheel is grayed out.

####################
ipsiyellowfact
####################

-------------------------------------------
entry variable: $ipsiyellowfact -- ipsi yellowing
-------------------------------------------
default: 0.0

The "iy:" field changes the ipsilateral fade
out from gray to various amounts of yellow.  0.0
gives pure gray and 1.0 gives pure yellow.  The
range of phase angles or both gray and yellow is
controlled with fadef.

####################
script
####################

-------------------------------------------
entry variable: $script -- absolute name curr tclscript
-------------------------------------------
default: /tmp/TmpTclMed.[pid]

The "tcl:" entry (lower right on the fn-F2
interface) contains the name of the current tcl
script.  On startup from csurf, this will
typically contain an autogenerated script in
/tmp.

Relative name assumes same dir as default.  Home
dir for tcl scripts ($MRI_DIR/lib/tcl) can be
abbreviated as poundsign (#).  Absolute name OK,
too.  Default overridden with command line
script.

To see the tcl commands corresponding to each
interface action (also generates a log), click
the "tcl:" label itself.

See the documentation for the "tcl:" entry in
tksurfer for more details on how to write tcl
scripts to automate actions.

####################
script_edit
####################

-------------------------------------------
tcl function: editfile <file> -- edit current tcl script
-------------------------------------------
keyboard equivalent: none

Edit the tcl script using a basic editor (tries
TextEdit, gedit, nedit, xedit in that order).  To
cause the editor to be vi inside a popped-up
gterm or xterm, set this environment variable:

  export CSURFEDITORVIGTERM=1
       *or*
  setenv CSURFEDITORVIGTERM


####################
script_run
####################

-------------------------------------------
tcl function: source $script -- run current tcl script
-------------------------------------------
keyboard equivalent: none

Run the script specified above.  It is up to the
script to read lower case enviroment vars into
the tcl interpreter (or use READENV).

####################
script_record
####################

-------------------------------------------
tcl function: enabledisablelog -- toggle log
-------------------------------------------
default: OFF

Record Tcl Commands for Interface Actions

To get a file containing all the tcl commands
that have been executed as tkmedit interface
buttons and entries were interactively
manipulated, simply click the "tcl:" label.

The "tcl:" label turns bold to indicate that tcl
command recording is enabled.  Clicking it again
unbolds it and closes the log file.  The tcl
commands will be dumped into:

  $FUNCTIONALS_DIR/$session/image/scripts/tkmedit.log

N.B.: every time recording is enabled, the
previous tkmedit.log in the scripts dir in this
session is erased and a new clean log is begun.

On clicking "tcl:", an xterm will also pop-up, 
which echoes the commands as they are written into
the script.  The xterm runs:

  cd $FUNCTIONALS_DIR/$session/image/scripts
  tail -f tkmedit.log

The tcl logging function can be turned on or off
(default off) for each new tkmedit started by the
current csurf session with:

  Preferences -> Log tkmedit actions as tcl cmds

####################
test1
####################

-------------------------------------------
funct (left-click): piecewise linear hand norm
  norm_allslices_toim2 <dir:0=PA,1=IS,2=LR>
-------------------------------------------
funct (mid-click): experimental local norm
 locnorm_allslices <rad> <0=med,1=histmx> <1=ed,2=im2>
-------------------------------------------


Piecewise linear hand normalization

Left-clicking the TEST button tests the effect of
piecewise linear norm (or sphere norm if "sph" is
checked) on using current values lim's, ffrac's
(dir=0 is Post/Ant, dir=1 is Inf/Sup, dir=2 is
Left/Right (radiological).

The normalized volume is written into the
comparison/non-saveable buffer (im2) for blink
comparison using COMPARE.  To normalize the
editable/saveable dataset in place, use the APPLY
button instead (norm_allslices).

A L-click on the "PieceWiseLInNorn" label brings
up a pop-up to control piecewise linear
brightness-dependent ramps in contrast (in
addition to L/R, I/S, or P/A position-dependent
ramps).  The $contrastnochange variable sets the
image value for no change; image values above and
below are linearly increased or decreased with
slope set by $contrastslope (default is 0.0,
which is brightness-dep contrast ramps OFF).


Alternate/Experimental functions

If the TEST button is middle-clicked, a different
tcl function is run:

  locnorm_allslices <rad> <0=med,1=histmx> <1=ed,2=im2>

This performs experimental local normalization
algorithms on the 3D data currently in the
editable buffer.  The normalized images go to
im2.  Middle-click COMPARE to swap editable and
im2 in order to save them.

These routines are multi-threaded (8 threads) and
may cause an increase in CPU fans speed.

Parameters:

  operation = 0 (3D median)

    $prad (radius in pixels)
    $white_lolim (low cutoff brain)
    $white_lolim (hi cutoff brain)

  operation = 1 (3D hist max)

    $prad (radius in pixels)
    $white_lolim (low cutoff brain)
    $white_lolim (hi cutoff brain)

Voxel target value is average brain value between
$white_lolim and $white_lolim.

These are designed for ex vivo samples.  The
freesurfer normalization works better for
standard human brain scans.

####################
all
####################

-------------------------------------------
function: norm_allslices <dir:0=PA,1=IS,2=LR>
-------------------------------------------
keyboard equivalent: <none>

The APPLY button does a piecewise linear
normalization on all slices in the
editable/saveable buffer (im) using either:

  (1) current values lim's, ffrac's (dir=0
  is Post/Ant, dir=1 is Inf/Sup, dir=2 is
  Left/Right (radiological) (optional add'l
  image brightness-based contrast ramp by
  R-click on "PieceWiseLinNorm").


or, if "sph" is checked:

  (2) current value of "lim0" (radius) and
  "ffrac0" (correction factor of spherical
  ramp centered at most recent left-click
  location

To undo, alt/cmd-z in image window (or tools
window).  To test effect of either style of
correction without affecting the editable image,
use the TEST button instead
(norm_allslices_toim2, see its help).

####################
sphnorm
####################

#### toggle sphere norm, linear/Gaussian ####
-------------------------------------------
tickbox variable (left-click):
  $sphnormflag -- toggle ramp vs. sph
-------------------------------------------
tickbox variable (middle-click):
  $gaussnormflag -- toggle linear vs. gauss
-------------------------------------------


The "sph" checkbutton (lower left on F3 panel)
toggles 1D vs. 3D ramp ($spherenormflag) and
linear versus Gaussian 3D ramp ($gaussnormflag).
This affects the operation done by the TEST and
APPLY buttons.

-------------------------------------------
Left-click (toggle $sphnormflag)
-------------------------------------------

A default left-click on the F3-panel-only "sph"
checkbutton toggles the state of manual
normalization done by the TEST and APPLY buttons
between:

  OFF=0:  a piecewise 4-control-point ramp along
  one major (sagittal/coronal/horizontal) axis

  ON=1:  a spherical field around the most recent
  click/cursor

In the first case, normalization is controlled by
4 control points (lim0-3, intrinsic coords) and 4
corresponding normalization factors (ffrac0-3,
where 1.0 is no change).

In the second case, the current cursor sets the
center of a spherical normalization field.  The
radius of the field is set by lim0 (directly to
the left of "lim0").  The shape of the field
(linear vs. Gaussian) is controlled by the next
flag ($gaussnormflag).  The default is linear
($gaussnormflag=0).

-------------------------------------------
Middle-click (toggle $gaussnormflag)
-------------------------------------------

A non-default middle-click on the F3-panel "sph"
checkbutton toggles the shape of the spherical
normalization field between:

  OFF=0:  linear ramp
  ON=1:  Gaussian ramp

Since $gaussnormflag has no effect unless
$sphnormflag is ON, turning it on will also
auto-set $sphnormflag to ON.

In both cases, the normalization factor at the
center of the field (most recent left-click), is
set by ffrac0.

When $gaussnormflag if OFF, the normalization
field is a linear ramp starting from no change at
a radius of $lim0 to a factor of $ffrac0 at the
center (a 3D "cone").

When $gaussnormflag is ON, the normalization
field is a gaussian ramp starting again from no
change at a radius of $lim0 to a factor of
$ffrac0 at the center.  The gaussian function
used is:

  existing *= 1.0 + (ffrac0-1.0)*exp(-(d/flim0*2.3)^2);

where d is the distance in pixels from the
center/cursor.  The factor of 2.3 results in the
Gaussian scaling reaching no change (in a 0-255
byte image) when d equals $ffrac0, which results
in a FWHM of 0.36198*ffrac0.

####################
imim2op
####################

-------------------------------------------
function: imim2op <opnum> -- 2Dcol edit
-------------------------------------------
keyboard equivalents: none

The "OP" button (lower right on the F3, lower
middle on F4 panel) makes a popup to run a 2D
color operation (edit if inside or outside 2D
color ellipse) using the data currently in the
main/editable buffer (im) and the second/compare
(im2) buffer.

Before doing this, it can help to plan the
truncation by viewing what will be selected as a
transparent green overlay using another popup
available from a left-click of the bold "im2:"
label.

N.B.: the result is applied to the editable
buffer (im).  To undo, alt/cmd-z after clicking
the image window (or tools window).

The number in the entry next to the OP button
selects the operation (currently 0 or 1).  The
ellipse center and radii are set using the
"im:cent,rad:" and "im2:cent,rad:" entries on the
bottom mid-right of the the F4 panel.

This operation is also available from the TRUNC
R-click buttonbar from the smaller interfaces.

The current operations are:

-------------------------------------------
0:  edit ellipse *inside* im,im2 space to OFF
-------------------------------------------

   (x-m)^2      (y-n)^2
   --------  +  --------   <   1
     w^2           h^2

where (x,y) is current color, (m,n) is center
color, and (w,h) are color radii.  If < 1, edit.

TODO:
  x' = x*cos(th) + y*sin(th)
  y' = y*cos(th) - x*sin(th)

-------------------------------------------
1:  edit ellipse *outside* im,im2 space to OFF
-------------------------------------------

Same as 0, but save 2D colors inside ellipse.

To save the edits, set the desired output name in
the "im:" field and use "W".

N.B.: using SAVEIMG will save the edited images
over the originally-read-in set of images
(probably not wanted).


####################
smooth
####################

-------------------------------------------
function: smooth_3d_nn <steps=1> -- 3D smooth
-------------------------------------------
keyboard equivalent: none

Smooth images in 3D.  Replaces each pixel with
average of its 26 nearest neighbors and the
current pixel.  Write out edited images with
SAVEIMG button (asks to confirm write) or
function:  write_images (doesn't ask).

####################
surfpaint
####################

-------------------------------------------
entry variable: $oneidnum ("an:") -- show only 1 annot
default: -1 (show all annot idnums/regions)
-------------------------------------------
entry variable: $curv -- curv filename (surface)
default: ~/surf/$hemi.curv
-------------------------------------------
entry variable: $fs -- fieldsign filename (surface)
default: */fs/$hemi.fs
-------------------------------------------
entry variable: $anlabel -- annotation filename (surf)
default: ~/label/$hemi.HCP-MMP1.annot
-------------------------------------------

N.B.: only visible in tkmedit [fn-]F4 panel.

The lower right "curv:", "fs:", and "annot:"
entries and corresponding "R" (read) buttons
display data as colors along the surface ribbon.

All three require first loading a surface using
the tkmedit "surf:" dropdown.

Loading one kind of data toggles off the other
two.

Since the curvature ($hemi.{curv,sulc}) and the
MGH annotation files ($hemi.*.annot) are stored
in the subject's directory (in $SUBJECTS_DIR),
these will always be accessible when opening a
subject from either the VOLUME button or the
VOLUME-STATS button.  The "annot:" dropdown will
contain all .annot files in the subject's label
directory.

The fieldsign data, by contrast, is stored in a
scandir within a session directory (in
$FUNCTIONALS_DIR).  To display fieldsign data on
the surface ribbon, first select a fieldsign
scandir in View Functional Data and open it with
VOLUME-STATS.  Then do [fn-]F4, load a surface,
and load surface-color data onto it.

Show only one MGH annotation region/idnum

The entry "an:" (just right of SURFPAINT), allows
displaying only one annotation region (picked by
its idnum) at a time.  To find the idnum of an
annotation region: (1) display all the regions on
the surface in tksurfer and double-middle-click
one region to get a pop-up, or (2) consult the
complete table of idnums (and their names and
colors) printed in the tkmedit log when the
annotation file is first read.

The cursor will move to the average position of
surface vertices in this annotation region.

The default is -1, which means, show all regions.
Region 0 is Unknown.  Requesting an out of range
idnum shows all regions.

####################
linewidth
####################

-------------------------------------------
entry entry variable: $surflinewidth -- pix
-------------------------------------------
default: same as magnification

The "linewidth:" entry (only visible on fn-F4
interface) sets the thickness of the line used to
display surface(s) in pixels.

By default, this will be set to the current
magnification (default magnification of 2 sets
$surflinewidth to 2).

A thicker line can be useful when SURFPAINT
(fn-F4 only) is used to display curvature or
fieldsign data on the line.

####################
linear
####################

-------------------------------------------
tickbox variable: $linearflag -- vs. bright/contrast
-------------------------------------------
default: OFF

The "linear" tickbox toggles the default
sigmoidal brightness display to linear (useful if
actual brightness numbers are desired in a bitmap
image).

Default if OFF (brightness sigmoid controlled by
"contr:" and "midpt:")

####################
hbutt
####################

-------------------------------------------
tcl funct: helpwin <helpfile> (left-click):
-------------------------------------------

A left-click on the far upper right "h" button on
tkmedit pops up general application help (same as
csurf: Help -> tkmedit).

For detailed help, R-click any interface button,
entry, or tickbox.

####################
coronal
####################

-------------------------------------------
functions,var: (left-click): change to CORONAL view
  raise_window
  set plane 0
  pixvaltitle 0 0 0
  redraw
  unzoomcoords
-------------------------------------------
function: (middle-click): flip 3D data
  flip_corview_xyz <[-]{x,y,z}> <[-]{x,y,z}> <[-]{x,y,z}>
-------------------------------------------


Detailed Description CORONAL button

If the view is not CORONAL, a default left-click
of the CORONAL button changes to the CORONAL
slice that goes through the current cursor in
SAGITTAL or HORIZONTAL view.

The "un" tickbox toggles enabling undo-ing of up
to 4 previous sequential edits.  Edits slightly
faster with this off.

-------------------------------------------
Alt funct (middle-click): flip 3D data
-------------------------------------------

An alternate middle-click on the CORONAL button
brings us a pop-up to allow flipping the 3D data
set (after first forcing the image into the
CORONAL view if it wasn't there).  This is useful
for fixing data that had incorrect headers.

N.B.: this can mirror-image the data set
(sometimes necessary).  Also, since there are a
large number of possible flips of a 3D data set
(48), it is easy to get confused.  The data cube
can be viewed from 6 different faces times 4
rotations of each face times 2 enantiomers
(non-mirror-image and mirror-image) = 48.  The
flips are done in the order:

  flip_curr_x_to
  flip_curr_y_to
  flip_curr_z_to

Since the coordinates on the pop-up refer only to
the CORONAL view, this view is forced before
flipping.

The three x,y,z directions are defined in CORONAL
view as:

  x   => left -> right
  y   => bottom -> top
  z   => near -> far

Determine which direction you would like the
current x (left-right) to be flipped to.  You can
use a negative sign.  For example, to left-right
mirror-image a data set, set the entries to:

  flip_curr_x_to   => -x
  flip_curr_y_to   => y
  flip_curr_z_to   => z

and hit READY.  To rotate the data set, you have
to swap coordinates.  The following example
rotates the data 90 deg in the CORONAL plane:

  flip_curr_x_to   => y
  flip_curr_y_to   => x
  flip_curr_z_to   => z

Note that this will make the SAGITTAL button view
appear to be a rotated horizontal slice, and the
HORIZONTAL button view will appear to be a
rotated sagittal slice (this makes sense when you
consider what a taking a sagittal or horizontal
slice through the rotated CORONAL data set would
give you).

When satisfied (be sure to check all 3 views!),
the data can be saved/overwritten with SAVE IMGS,
or "Saved As..." with "W" on the "im:" line.

Volumes and surfaces

To flip and exactly align a surface previously
made from an unflipped volume to a flipped
volume, use the following tcl commands (L/R flip
example) for a 256^3/1mm data set:

  really_flip_brain_x
  really_translate_brain 1 0 0
  setfile outsurf ~/mri/$hemi.orig
  write_binary_surface

or like the following commands for a 512^3/0.5mm
data set:

  really_flip_brain_x
  really_translate_brain 0.5 0.0 0.0
  setfile outsurf ~/mri/$hemi.orig
  write_binary_surface

####################
sagittal
####################

-------------------------------------------
functions,var: (left-click): change to SAGITTAL view
  raise_window
  set plane 2
  pixvaltitle 0 0 0
  redraw
  unzoomcoords
-------------------------------------------

If the view is not SAGITTAL, a default left-click
of the SAGITTAL button changes to the sagittal
slice that goes through the current cursor in
CORONAL or HORIZONTAL view.

####################
horizontal
####################

-------------------------------------------
function,var: (left-click): change to HORIZONTAL view
  raise_window
  set plane 1
  pixvaltitle 0 0 0
  redraw
  unzoomcoords
-------------------------------------------

If the view is not HORIZONTAL, a default
left-click of the HORIZONTAL button changes to
the horizontal slice that goes through the
current cursor in CORONAL or SAGITTAL view.

#########################################
tkregister R-click pop-ups (interface order)
#########################################
####################
fsquash
####################

variable: $fsquash -- contrast adj sigmoid slope
default: 12.0

Higher number increases contrast.  Use midpoint
($fthresh) to set inflection point of sigmoid.
For linear map, set linearflag TRUE

                         1.0
display =  -----------------------------------
           1.0 + exp(-fsquash*(image-fthresh))

####################
fthresh2
####################

variable: $fthresh -- infl point display sigmoid
default: 0.35 (range: 0.0-1.0)

An image value of fthresh*maxval is displayed
at half-max brightness.  Use contrast to set
steepness of sigmoid.

####################
fmov
####################

variable: $fmov -- brightness of MOVEABLE
default: 0.1

Sets brightness of MOVEABLE image.  TARGET images
are usu. byte images with gray matter ~80 and
white matter ~120.  Functional images are usu.
short images around ~1000.  On clicking SAVE REG,
fmov is written into 4th line of register.dat.

####################
masktarg
####################

variable: $maskflag -- mask target scan w/moveable
default: 0 (FALSE)

When maskflag is 1 (masktarg is selected), if the
MOVEABLE scan is smaller than the TARGET, the
target is masked to the current boundaries of the
moveable.

This is esp. helpful for fine adjustments.

####################
sagmirr
####################

function: mirror_brain -- sagittal mirror brain

Flips current 4x4 transformation matrix by
inverting sign of its first row.  This may be
required since tkregister and paint read data
from raw BRIKs or bfloats, ignoring headers that
might indicate axis flips.

This button generates a flip with respect to the
sagittal plane if the MOVEABLE brain is already
approximately aligned.  If not, since there are
only two possible mirror-image states of a brain,
any remaining rotations can be corrected with the
TRANSLATE and ROTATE sliders.

Since it is difficult to determine the correct
left-right mirror-image flip of a brain, be sure
the TARGET brain is not flipped.  Tkregister
displays CORONAL and SAGITTAL images using
radiological convention (left=right).

####################
blurmov
####################

variable: $blurflag -- blur MOVEABLE scan
default: 1 (TRUE)

When blurflag is 1 (blurmov is selected), the
MOVEABLE scan (e.g., 3x3x3 mm) is blurred by 3D
nearest neighbor smoothing at the resolution of
the TARGET scan (1x1x1 mm) to aid visual
comparison of different resolution scans.

####################
invertmov
####################

variable: $invertmoveflag -- invert MOVEABLE scan
default: 1 (TRUE)

When invertmoveflag is 1 (invertmov is selected),
the contrast of the MOVEABLE scan (e.g., a
T2-weighted functional EPI scan) is inverted to
aid visual comparison with the TARGET scan (usu.
a T1-weighted FLASH).  Note that this also
inverts the operation of the "fmov:" field --
that is, higher fmov values make the MOVEABLE
scan *darker*.  Unclick to align two T1 scans.

####################
blinktime
####################

variable: $blinktime -- msec for each blink
default: 15

Sets number of msec (approx.) that TARGET and
MOVEABLE are shown before swapping to the other
one.  The default setting gives 2 frames for each
image (set to 0 to get one 1/60 sec frame per
image, or 250 to get one frame every 1/4 sec.

####################
target
####################

variable: $overlay -- which buffer to show
keyboard equivalent: [none]

Switch to the TARGET (set overlay 1; redraw).
Normally this is done with the COMPARE button.
This button remains depressed to indicate which
data set is being shown.

####################
moveable
####################

variable: $overlay -- which buffer to show
keyboard equivalent: [none]

Switch to the MOVEABLE (set overlay 2; redraw).
Normally this is done with the COMPARE button.
This button remains depressed to indicate which
data set is being shown.

####################
compare
####################

function: swapoverlay -- compare struct to EPI
keyboard equivalent: <Alt-0>

Click to toggle between MOVEABLE (usu. EPI) and
TARGET (usu. structural) scans.  Holding button
down flicks back and forth automatically with
blink interval set by blinktime.  Loads back
buffer for plane change as needed.

####################
sendpnt
####################

function: write_point -- save 3D location
keyboard equivalent: <none>

Last selected 3D location (left-click) is written
to the file: $SUBJECTS_DIR/<subj>/tmp/edit.dat.
Other programs can read this file to locate the
same point.  This button also messages other
copies of tkmedit, tkregister, and tksurfer to go
to the same (tksurfer: nearest) point.  For
messaging to work, deny access to all w/xhost.

####################
gotopnt
####################

function: goto_point -- goto saved vertex location
keyboard equivalent: <Alt-r>

The file $SUBJECTS_DIR/<subj>/tmp/edit.dat is
read.  It contains a vertex location written by
"SEND PNT" (from either tkmedit, tkregister, or
tksurfer).  The pixel corresponding to the saved
point is located and the cursor is put there
(current plane unchanged).

####################
align
####################

function: align_points -- translate EPI image
with 2 clicks
keyboard equivalent: <Alt-A>

Left-click to mark feature on moveable/EPI.
Change to target/structural with COMPARE or
TARGET.  Second left-click on structural marks
position to which EPI feature should be moved.
Button moves EPI.

####################
savereg
####################

function: write_reg -- save to register.dat
keyboard equivalent: none

The SAVE REG button saves the currently visible
registration (and the current sample method) to
the register.dat file.

To change the sample method (round vs. trunc),
access the larger interface with F3 (linux) or
fn-F3 (Mac) and read the help for the "round"
checkbutton (lower right).  The F3 panels also
contains READ REG, which can be used to revert
the registration to the last saved register.dat.

####################
readreg
####################

function: read_reg -- read saved register.dat
keyboard equivalent: none

The READ REG button re-reads the currently saved
register.dat file, discarding any unsaved
registration changes.  Use to revert to last
saved.

####################
round
####################

variable: $roundregflag -- sample round (vs. trunc)
default: none -- read from register.dat

When tkregister reads a register.dat file
containing a line, "round", following the
transformation matrix, the "round" checkbutton is
checked ($roundregflag=1) and tkregister rounds
the transformed floating point position before
nearest-neighbor sampling the moveable volume.

If register.dat lacks "round" (or contains
"tkregister"), then the original behavior of
sampling by truncating the transformed floating
point position is used.

In both cases, the overlay visible in tkregister
will be properly sampled to the surface when
PAINT is clicked in a later panel (i.e., paint.c
also changes its behavior depending on whether or
not register.dat "round" is present).

If the state of the "round" checkbutton is
changed after opening tkregister, the moveable
display will be updated (the moveable image will
move half a voxel in all three axes).  The first
time that register.dat is saved with SAVE REG
after such a change, there will be a popup
warning that the sampling method is being
changed.

The "round" line in register.dat affects the
behavior of tksurfer (rawdata sample) and tkmedit
(rawdata sample, stats overlay) similarly.

#########################################
tksurfer R-click pop-ups (interface order)
#########################################
####################
clks
####################

-------------------------------------------
### Surface Image-Window Clicks ###
-------------------------------------------
(1) Left-Click: Select vertex, add to 'marked' list

(2) Middle-Click: Unselect one vertex

(3) Right-Click: Clear all selections/marks (undo clear: Cmd-z)

(4) Shift-Left/Middle/Right-Click: Rotate/Translate/Scalebrain
      (also: Rotate -> arrows, Translate -> Shift-arrows)
      (also: In-plane Rotate -> Ctrl-Shift-L/R-arrows)

(5) Ctrl-Left/Right-Click: Zoom/Unzoom around clicked point

(6) Ctrl-Middle-Click: Dump voxel time course

(7) Left-Double-Click: Raise tools interface window

(8) Middle-Double-Click: Popup name of annotation region

(9) Right-Double-Click: This help

(10) Shift-Left-Click: Sample sphere img(s) at this vertex

---------------------------------------------
### Volume-Image Window HotKeys -- Single key ###
---------------------------------------------
# interface size
F2 -- basic interface   (Mac=fn-F2)
F3 -- large interface   (Mac=fn-F3)

# rotate,scale brain (interface win: add Mod)
R/L arrow           -- rotate around vert axis
up/down arrow    -- rotate around horiz axis
Control-Shif-R/L arrow  -- rotate in plane
Shift-R/L arrow    -- translate right/left
Shift-up/down arrow  -- translate up/down
plus (+)              -- scale up 1%
equals (=)          -- same as plus
minus (-)            -- scale down 1%
D-key (d)           -- re-select prev. selected (get over annot)

---------------------------------------------
### Volume-Image Window HotKeys -- Modifer + key ###
---------------------------------------------
(LinuxMod="Alt", MacMod="Cmd")

# SEND/GOTO
Cmd-f  -- SEND (forward) point
Cmd-g  -- GOTO point

# REDRAW/RESTORE
Cmd-r  -- REDRAW (usu. automatic)
Cmd-R  -- RESTORE to original view

# stat overlay
Cmd-l  -- (el) toggle overlay stats visibility

# surface cursor size
Cmd-k  -- toggle big cursor

# fmid (main threshold)
Cmd-i  -- lower fmid by 0.1 (sqrtF)
Cmd-I  -- raise fmid by 0.1 (sqrtF)
Cmd-u  -- lower fmid by 10.0 (raw fourieramp)
Cmd-U  -- raise fmid by 10.0 (raw fourieramp)

# fslope (contrast)
Cmd-s  -- lower fslope by 0.5
Cmd-S  -- raise fslope by 0.5

# angle_offset (rotate color wheel)
Cmd-o  -- (oh) lower angle_offset by 0.01
Cmd-O  -- (oh) raise angle_offset by 0.01

# angle_cycles (compress hemi color wheel)
Cmd-y  -- lower angle_cycles by 0.1
Cmd-Y  -- raise angle_cycles by 0.1

# misc
Cmd-L  -- thicken isocontour lines 1 pix
Cmd-F  -- kill ongoing FILL/ROI operation
Cmd-z  -- restore last selected vertex list

####################
surf
####################

-------------------------------------------
var,funct: load surface (topology must match startup)
  set insurf <surface>
  read_binary_surface
-------------------------------------------
N.B.: entry variable: $surfext -- surface suffix

Read/Load Surface

The "surf:" entry at the upper left shows the
*suffix* of the current surface (e.g., for
surface "rh.inflated", just "inflated" will be
shown).  To load a different surface for the
current subject and hemisphere, select a new
available surface (e.g., orig, smoothwm, white,
pial, inflated, sphere, sphere.reg) from the
"surf:" dropdown.

The new surface must have the same number of
vertices and faces as the surface tksurfer was
started up with.  The current surface pose,
magnification, and statistical overlay data (if
any) are preserved.

The suffix for a surface can also by typed into
the entry followed by <Return>.  An invalid entry
will reload the initial surface.  Finally, an
absolute path to a surface file can be entered
(it will be stripped to a suffix after it loads).

This entry uses the C/tcl function:

  read_binary_surface

to read the current surface in $insurf.  The
function can read native freesurfer triangular or
quadrangular surfaces in binary or ASCII format
(the C/tcl funct read_ascii_surface is a synonym
for read_binary_surface).  A number of other
surface formats are also auto-detected and
readable by this function:

  native FreeSurfer tri or quad: (binary)
  native FreeSurfer tri or quad: (ASCII)
  ICO tri: FreeSurfer icosahedral (ASCII)
  VTK tri: visualization toolkit format (ASCII)
  OFF tri: object file format (ASCII)
  GIFTI tri: NIFTI surface format (base64 ASCII)
  OBJ tri: Alias Wavefront (ASCII)
  SRF tri: Brain Voyager (binary)

The surface file format is auto-detected.  If
GIFTI surfaces are present matching the
case-sensitive pattern:

  *.{L,R}.*.surf.gii

their full names are loaded (since they usually
have no initial lh,rh prefix), and similarly for
OBJ files and SRF files matching these patterns:

  *.obj
  *.srf

If the tksurfer start-up surface is a triangular
surface, it can't be updated/changed to a
same-vertex-count quadrangular surface (can't
know which edges to remove) using this entry.
The reverse, however works (startup with quad
surface, update with same-vertex tri surface).

Since *.srf surfaces have left-handed coordinates
(PIL vs. freesurfer RAS coordinates), they will
appear mirror-imaged in tksurfer (a right hemi will
look like a left hemi, and vice versa, and you will
get a warning panel the first two times you open
the surface).  The surface coordinates can be
mirror-imaged (e.g., in order to save the surface
as a native freesurfer surface) with "FlipHemi" at
the upper right of the larger F3 interface (this
flips the sign of the x-coordinate).


Write Surface -- large interface panel ([fn]-F3)

The current state of a surface can be written
using the larger tksurfer interface available
with [fn]-F3 (typed with mouse focus on tksurfer
tools panel).  You can also toggle to the big
interface with the "i" button at the far upper
left on the smaller interface (and the far upper
right on the larger interface).

The upper right "outsurf:" entry has 7 buttons
(formats) on the right for writing out the
current surface:

  W	native freesurfer tri/quad formats (binary)
  ASC	native freesurfer format (ASCII)
  VTK	vtk 3.0 format (ASCII)
  OFF	object file fmt, incl color: OFF,COFF (ASCII)
  STL	stereolithography format: 3D printer (ASCII)
  GLB	glTF 2.0: GL transmission format (binary)
  OBJ	Alias/Wavefront object format (ASCII)

The corresponding tcl/C functions for writing
each of these six file types are:

  write_binary_surface
  write_ascii_surface
  write_vtk_surface
  write_off_surface
  write_stl_surface
  write_glb_surface
  write_obj_surface

See the R-click help for each button for more
details on each kind of output format.


Surface Geometry Binary Input File Formats

The following specification has been copied for
convenience from Help -> Csurf.  All of the
following surface formats are auto-detected by
the tcl/C function:

  read_binary_surface

There are two main types of surface formats for
individual brains in FreeSurfer.  The first
format contains quadrangles, which come from the
faces of the voxels categorized as white matter
touching not white matter.

  Quad Surface File Format (short vtx coords):
    -------------- header ---------------------
      3-byte magic number (16777215)
      3-byte int vertex count (~150,000)
      3-byte int face count (~150,000)
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      2-byte int vertex x-position (mm x 100)
      2-byte int vertex y-position (mm x 100)
      2-byte int vertex z-position (mm x 100)
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      [vtx nums here implicit from above, 0-based]
      [num each face ordered CCW from outside]
      corner1 corner2 corner3 corner4
      ... [quadruples up to face count]
    -------------------------------------------

  New Quad Surface File Format (float vtx coord):
    -------------- header ---------------------
      3-byte magic number (16777213)
      3-byte int vertex count (~150,000)
      3-byte int face count (~150,000)
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      4-byte float vertex x-position (mm)
      4-byte float vertex y-position (mm)
      4-byte float vertex z-position (mm)
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      [vtx nums here implicit from above, 0-based]
      [num each face ordered CCW from outside]
      corner1 corner2 corner3 corner4
      ... [quadruples up to face count]
    -------------------------------------------

  ASCII Quadrangle Surface File Format (ASCII):
    -------------- header ---------------------
      #!ascii ... quadrangles  ...
      vertexcount facecount
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      x y z
      x y z
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      corner1  corner2  corner3  corner4
      corner1  corner2  corner3  corner4
      ... [quadruples up to face count]
    -------------------------------------------

The second surface file format contains triangles.
These are initially made by subdividing each
voxel-face quadrangle into two triangles.

  Triangle Surface File Format:
    -------------- header ---------------------
      3-byte magic number (16777214)
      less-than-200-char '\n'-terminated string
      [e.g., "created by %s=user on %s=time\n"]
      4-byte int vertex count (~150,000)
      4-byte int face count (~300,000)
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      4-byte float vertex x-position (mm)
      4-byte float vertex y-position (mm)
      4-byte float vertex z-position (mm)
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      [vtx nums here implicit from above, 0-based]
      [num each face ordered CCW from outside]
      corner1 corner2 corner3
      ... [triples up to face count]
    -------------------------------------------

  ICO Triangle Surface File Format (ASCII):
    ---------- vertex positions ---------------
      163842  (ico7: ASCII vertex count)
      1   x1   y1   z1      (ic7.tri: radius=1)
      2   x1   y1   z2
      ... [numbered x,y,z triples to vtx count]
    ---- vertex numbers around each face ------
      327680   (ico7: ASCII face count)
      1   corner1  corner2  corner3
      2   corner1  corner2  corner3
      [vtx nums here are explicit nums above]
      [num each face ordered CCW from outside]
      ... [numbered triples to face count]
    -------------------------------------------

  ASCII Triangle Surface File Format (ASCII):
    -------------- header ---------------------
      #!ascii ... [triangles] ...
      vertexcount facecount
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      x y z
      x y z
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      corner1  corner2  corner3
      corner1  corner2  corner3
      ... [triples up to face count]
    -------------------------------------------

  VTK Triangle Surface File Format (ASCII):
    -------------- header ---------------------
      # vtk DataFile Version 3.0
      <filename or other single-line info>
      ASCII
      DATASET POLYDATA
      POINTS <vertexcount> float
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      x y z
      x y z
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      POLYGONS <facecount> <totaltokens>
      [faces are implicitly numbered]
      3  corner1  corner2  corner3
      3  corner1  corner2  corner3
      ... [4-tuples up to face count]
    -------------------------------------------
      [optional columns of vertex overlay data]
      [ignored if file read as surface]
      POINT_DATA <vertexcount>
      SCALARS EmbedVertex float <columncount>
      LOOKUP_TABLE default
      column1value column2value ... [columncount entries]
      column1value column2value ... [columncount entries]
      ... [implicitly num'd tuples to vertexcount]
    -------------------------------------------

  OFF Triangle Surface File Format (ASCII):
    -------------- header ---------------------
      OFF (or COFF)
      # comment line ...
      <vertex-count> <face-count> <edge-count>
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      x y z
      x y z
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      3  corner1  corner2  corner3
      3  corner1  corner2  corner3
      ... [4-tuples up to face count]
    -------------------------------------------

  GIFTI Triangle Surface File Format (ASCII)
    -------------- header ---------------------
      <?xml version="1.0" encoding="UTF-8"?>
      <GIFTI xmlns:xsi="http://www.w3.org/...
         ...
         Version="1"
         NumberOfDataArrays="2">
        ...
        <DataArray Intent="NIFTI_INTENT_POINTSET"
                   DataType="NIFTI_TYPE_FLOAT32"
                   ArrayIndexingOrder="RowMajorOrder"
                   Dimensionality="2"
                   Dim0="32492"
                   Dim1="3"
                   Encoding="GZipBase64Binary"
                   Endian="LittleEndian"
                   ExternalFileName=""
                   ExternalFileOffset="0">
              ...
          <Data>
            [usu: base64 encoded gzipped binary floats]
          </Data>
        </DataArray>
        <DataArray Intent="NIFTI_INTENT_TRIANGLE"
                   DataType="NIFTI_TYPE_INT32"
                   ArrayIndexingOrder="RowMajorOrder"
                   Dimensionality="2"
                   Dim0="64980"
                   Dim1="3"
                   Encoding="GZipBase64Binary"
                   Endian="LittleEndian"
                   ExternalFileName=""
                   ExternalFileOffset="0">
          ...
          <Data>
            [usu: base64 encoded gzipped binary ints]
          </Data>
        </DataArray>
      </GIFTI>
    -------------------------------------------

  OBJ (Wavefront) Triangle Surface File Format (ASCII):
    -------------- header ---------------------
      # comment line (no req'd header)
      [vertex triples implicitly numbered]
      "v"  x  y  z  [r  g  b]
      "v"  x  y  z  [r  g  b]
      ... [x,y,z triples or sextuples up to vertex count]

      [normal triples implicitly num'd, norm maybe!=1]
      [N.B.: currently ignored here and recalc'd as usual]
      "vn"  x  y  z
      "vn"  x  y  z
      ... [x,y,z triples up to vertex count]

      [face triples implicitly num'd]
      [entries: vtx, vtx/tex, vtx//norm, vtx/tex/norm]
      [N.B.: vtx/tex/norm nums are 1-based!]
      [N.B.: ignores tex/norm nums]
      "f" vtx1 vtx2 vtx3
               *or*
      "f" vtx1/tex1 vtx2/tex2 vtx3/tex3
               *or*
      "f" vtx1//norm1 vtx2//norm2 vtx3//norm3
               *or*
      "f" vtx1/tex1/norm1 vtx2/tex2/norm2 vtx3/tex3/norm3
      ... [triples up to face count]
    -------------------------------------------

  SRF (BrainVoyager) Triangle Surface File Format (binary):
    -------------- header ---------------------
     4-byte float version (4)
     4-byte int reserved (must be 0)
     4-byte int vertexcnt
     4-byte int facecnt
     4-byte float centx
     4-byte float centy
     4-byte float centz
     vertexcnt*4-byte floats x (N.B.: left-handed coords!)
     vertexcnt*4-byte floats y
     vertexcnt*4-byte floats z
     vertexcnt*4-byte floats normal x (inward pointing!)
     vertexcnt*4-byte floats normal y
     vertexcnt*4-byte floats normal z
     4*4-byte float convex curv color r,g,b,a
     4*4-byte float concave curv color r,g,b,a
     vertexcnt*4-byte int vertex colors
     foreach vertex
       4-byte int neighbor count [N.B.: varies]
       count*4-byte int neighbors
     facecnt*3*4-byte int face corner vtx numbers
     [optional triangle strips]
    -------------------------------------------


####################
script
####################

-------------------------------------------
entry variable: $script -- current tcl script
-------------------------------------------
default: $CSURF_DIR/lib/tcl/twocond-views.tcl

The "tcl:" entry contains the current tcl script
to EDIT or run (GO).  When tksurfer has been
started from csurf it will typically be set to
the small tcl script that was used to start
tksurfer (rather than the default above).

The tcl script can be entered as absolute path:

  /tmp/my_script.tcl

or a path beginning with a poundsign (#), which
is an abbreviation for the standard script
library directory, $CSURF_DIR/lib/tcl:

  #/phasemovie.tcl

or as a relative path:

  my_script.tcl

which will look in the current working directory.
If tksurfer was started from csurf, the current
working directory will be the scripts directory
for the current session (or subject):

  $FUNCTIONALS_DIR/$session/image/scripts

or:

  $SUBJECTS_DIR/$subject/scripts

which is a good place in which to save save
session-specific (or subject-specific) tcl
scripts.  Any tcl scripts in there at tksurfer
startup will also appear in the "tcl:" dropdown.

Finally, there will always be the following entry
at the bottom of the dropdown:

  ~/tmp/TmpTclScript.tcl

which is a path to the tmp dir in the subject's
directory.  To edit and run a tmp script, do:

  select ~/tmp/TmpTclScript.tcl from the "tcl:" dropdown
  "EDIT" to open it in an editor (initially empty)
  [add tcl commands]
  [save]
  "GO" to run the script

Here is a tiny tmp script that sets the value of
a single variable and then displays its current
value in a pop-up:

  # set fmid and display its value
  set fmid 3.0
  confirmalert "fmid = $fmid"
  
Leaving the tcl script up in the editor gives
access to the tcl interpreter (without having to
start tksurfer from the command line).  Use
"return" to return early from a tcl script (to
skip the rest of it).

-------------------------------------------
Using variables/functions in user tcl scripts
-------------------------------------------

To find out the name of built-in tcl variables
and functions (linked to tksurfer C variables and
functions) that can be referenced and set/used in
scripts, use:

  tksurfer -h

Most of these variables and functions are linked
to C variables in tksurfer.c, so setting them in
a tcl global scope will update the C variable.

Some of the most commonly used tcl/C variables
that can be used in scripts include:

  $hemi		curr hemi (rh or lh)
  $scandir		curr scandir in "image" subdir
  $val		curr input/ouput wfile (full path)
  $label		curr input/ouput label (full path)
  $rgb		curr rgb output file (full path)

A commonly used tcl interface variable (no C) is:

  $smoothsteps		interface tcl var

Some of the most commonly used tcl/C functions
that can be used in scripts include:

  make_lateral_view			RESTORE button
  rotate_brain_x <deg>
  rotate_brain_y <deg>
  translate_brain_x <mm/currscale>
  translate_brain_y <mm/currscale>
  scale_brain <factor>
  redraw
  read_binary_values			uses $val
  write_binary_values			uses $val
  read_label_to_val			uses $label
  read_label_to_annot_using_col <r> <g> <b>
  write_val_visible_vertices			uses $label
  save_rgb			uses $rgb

The functions for reading and writing files
typically take no arguments but rather use the
current setting of a particular tcl/C filename
variable.  This filename is typically globbed
using the tcl-only function, "setfile", a
csurf-specific glob that expands abbreviations in
the path such as tilde (~), which stands for the
current subject and an asterisk (*) which stands
for the current session,  For example:

  setfile val */$scandir/polar+orig-$hemi.w
  setfile label ~/label/$hemi.BA3b
  setfile label */$scandir/$hemi-UniqSampVtxs.label
  setfile rgb */rgb/polar-$hemi-inflated-lat.tiff

The R-click help panels list the tcl variables
and function(s) they control/call at the top.

Look at $CSURF_DIR/lib/tcl/zz-examples/*.tcl for
examples of special-purpose scripts.

-------------------------------------------
HOWTO automate a set of interactive steps
-------------------------------------------

To automate a sequence of interactive steps,
simply left-click the "tcl:" label text (see its
R-click help).

This will echo (and save) the tcl commands
executed by each interface click so that they can
be copied into an cmdline script.

-------------------------------------------
Non-interactive command line operation
-------------------------------------------

The tcl script examples above assume that
tksurfer has already been started.  It is also
possible to start tksurfer and pass it a tcl
script name as an argument so that it can be
completely controlled non-interactively from a
command line shell.

Here is an example of a complete tcl script to
open a graphics window, read in a particular
surface (inflated), a curvature data set (curv),
a complex-valued overlay statistic data set
(polar1{_r,_i}-$hemi.w), and then render a
slightly rotated lateral view of the brain and
exit:

  open_window
  setfile insurf ~/surf/$hemi.inflated
  read_binary_surface
  setfile curv ~/surf/$hemi.curv
  read_binary_curv
  make_lateral_view
  set overlayflag 1
  set complexvalflag 1
  set statprefix polar1
  setfile val */$scandir/${statprefix}_i-$hemi.w
  smooth_val 10
  push_val_val2
  setfile val */$scandir/${statprefix}_r-$hemi.w
  smooth_val 10
  make_lateral_view
  rotate_brain_y 20
  redraw
  setfile rgb ~/rgb/polar1-rh-inflated-lat2.tiff
  save_rgb
  exit

Put these commands into a file, test.tcl,
in a functional session scripts directory.
This script can be run from the command line
as follows:

  cd $FUNCTIONALS_DIR/130625MS/image/scripts
  tksurfer marty rh smoothwm -tcl test.tcl

This script will work for any subject, session,
or hemisphere.  The only variable that has to be
adjusted is $statprefix.  The variables $hemi,
$subject, $session, and $scandir are autoset from
the command line and context).

If no images need to be viewed or saved (e.g.,
read vertwise file, perform surface-based
operations, write output date), it is not
necessary to open a graphics (GLX) window
(open_window, make_lateral view, redraw, etc).

Running tksurfer from a MacOS 10.11+ shell script

N.B.: on MacOS 10.11+, the environment variable 
DYLD_LIBRARY_PATH is *not* passed into a shell
script, which will prevent tksurfer from seeing
the csurf X11 tcl/tk libraries.  To use tksurfer 
in a MacOS 10.11+ shell script, include the
following line before the first call to tksurfer:

csh/tcsh:
 setenv DYLD_LIBRARY_PATH $CSURF_LIBRARY_PATH

sh/bash:
 export DYLD_LIBRARY_PATH=$CSURF_LIBRARY_PATH

-------------------------------------------
Standard movie-making tcl scripts
-------------------------------------------

There are 8 tcl scripts in $CSURF_DIR/lib/tcl for
making movies that can be run after a surface has
been displayed:

 offsetmovie.tcl		=> test all settings of $angle_offset
 phasemovie.tcl		=> moving phase stripe movie
 movie360.tcl		=> rotating brain loops, diff axes
 inflatemovie.tcl		=> inflation loop movies
 flattenmovie.tcl		=> flatten movies (adj pos/scale)
 annot2roi.tcl		=> fsavg annot -> 1sub -> 3D ROIs
 searchlightdiff.tcl		=> searchlight diffs (avg,types,var)
 explodemovie.tcl		=> for SFN 1992 :-}

These will loaded into the dropdown along with
any local tcl scripts in the current session and
subject "scripts" directories.

For more details, consult the R-click pop-up help
after opening one of the "RUN SCRIPT" panels with
the "GO" button on the "tcl:" line.

With minor additions (commented-out examples
inside), these can also be run from the command
line using:

  tksurfer <subj> <name> <hemi> <surfext> -tcl <script.tcl>

####################
script_edit
####################

-------------------------------------------
tcl function: editfile $script
-------------------------------------------
keyboard equivalent: none

The "EDIT" button on the "tcl:" entry line edits
the tcl script named in the entry to the left
using a basic editor (tries TextEdit, gedit,
nedit, xedit in that order).

To cause the editor to be vi inside a popped-up
gterm or xterm, set this environment variable:

  setenv CSURFEDITORVIGTERM
         *or*
  export CSURFEDITORVIGTERM=1

####################
script_run
####################

-------------------------------------------
tcl function: source $script -- run current tcl script
-------------------------------------------
keyboard equivalent: none

The "GO" button on the "tcl:" entry line runs the
tcl script specified in the entry in the context
of the data currently displayed on the surface.

The script can modify any tksurfer tcl variable
and call any tksurfer tcl function.  To see a
list of variables and functions, use tksurfer -h

After executing a set of tcl commands, use
"redrawbutton" to see the effects, or "restore"
to go back to a sane view (equivalent to REDRAW
and RESTORE interface buttons).

The script will be automatically wrapped with
"catch" and any errors returned in a pop-up.

####################
script_record
####################

-------------------------------------------
tcl function: enabledisablelog -- toggle log
-------------------------------------------
default: OFF

Record Tcl Commands for Interface Actions

To get a file containing all the tcl commands
that have been executed as tksurfer interface
buttons and entries were interactively
manipulated, simply click the "tcl:" label.

The "tcl:" label turns bold to indicate that tcl
command recording is enabled.  Clicking it again
unbolds it and closes the log file.  The tcl
commands will be dumped into:

  $FUNCTIONALS_DIR/$session/image/scripts/tksurfer.log

N.B.: every time recording is enabled, the
previous tksurfer.log in the scripts dir in this
session is erased and a new clean log is begun.

On clicking "tcl:", an xterm will also pop-up,
which echoes the commands as they are written into
the script.  The xterm runs:

  cd $FUNCTIONALS_DIR/$session/image/scripts
  tail -f tksurfer.log

The tcl logging function can be turned on or off
(default off) for each new tksurfer started by
the current csurf session with:

  Preferences -> Log tksurfer actions as tcl cmds

####################
interface
####################

-------------------------------------------
tcl functs: mini, macro -- toggle interface size
-------------------------------------------
keyboard equivlalent: <[fn]-F2, [fn-]F3>

Left-clicking the small "i" button (far upper
left at startup) toggles the size and position of
the tksurfer tools interface between the startup
size (small, underneath surface window) and large
(vertical, to right of surface window).  In the
large interface, the "i" button is located at the
far upper right.

The tools interface size can also be controlled
with using [fn]-F2 to change to small and [fn-]F3
to change to large (focus must be in tksurfer
tools window), or by using the tcl functs, mini
and macro.

####################
script_offsetmovie
####################

-------------------------------------------
Standard tcl script: offsetmovie.tcl
-------------------------------------------

This script successively changes the
$angle_offset value (thus rotating the color map)
in 50 steps (defaultl), saving a bitmap for each
step.

This can be used to find the most visually
informative $angle_offset setting for color wheel
data (color scale "w1").

It can also be used to find the best delay
(=$angle_offset) for two condition data analyzed
with the fourier method, and visualized, for
example, with colorscale "bi".

####################
script_phasemovie
####################

-------------------------------------------
Standard tcl script: phasemovie.tcl
-------------------------------------------

The phasemovie.tcl script colors a small range of
phases white (default: 0.03=3%) and saves a
bitmap for each step (default: 50) of varying the
phase of the center of the white stripe between
selected phase limits (default: 0->1, which means
0->2Pi).

To reverse the order of the phase progression
(e.g., lower-to-upper vs. upper-to-lower for
polar angle data), swap $phasemin and $phasemax.

If the desired range of phases wraps around 1.0,
use a number above 1.0 for $phasemax.  Thus
phasemin=0.75 and phasemax=1.30 will show phases
from 0.75 to 1.0 followed by 0.0 to 0.30 (these
can be reversed as above).

The current brain pose and the color scale
settings are preserved underneath the moving
white phase contour.  This is essentially an
animation of successive isocontour lines in the
color phasemap.  It makes small variations in
phase much more apparent than color variation
alone does.

The default color of the white phase stripe (255)
can be controlled with phasecontour_bright
(0-255).  Setting colphasecontourflag to 1
inverts the coloring scheme -- the phase stripe
is now colored (with its usual phase color) and
the remainder of the activation that is not at
that phase is given the same color controlled by
phasecontour_bright.  To make the moving colored
phase stripe visible, use a dark color for the
overall activation (e.g., phasecontour_bright =
20; autoset when colphasecontourflag ticked).

By default, the frames are saved with verbose
names.  There is an option to convert the frames
to an mpeg1 and delete the individual frames, and
an option to write frames with simple number
names (e.g., better for making H.264-compressed
mp4, e.g., with QuickTime 7 Pro: File -> Open
Image Sequence...) or with ffmpeg.  Here is an
example ffmpeg cmdline:

  ffmpeg \
    -v 0 \
    -f image2 \
    -r 20 \
    -i f*.tiff \
    -vcodec libx264 \
    -pix_fmt yuv420p \
    out.mp4

Finally, there is an option (dontsaveframes = 1)
to not save anything (one-time view for test).

To run this as a standalone script from the
command line, add a few lines at the top
(commented-out example in script) to first load a
data set.

####################
script_movie360
####################

-------------------------------------------
Standard tcl script: movie360.tcl
-------------------------------------------

The movie360.tcl script is designed to make movie
loops of rotating (and possibly incrementally
zooming) folded and inflated surfaces.  The
adjustable parameters are, the movie (mpg1)
output name, the number of steps in the loop
(default: 180), whether to reverse rotation
direction, the loop type (see below), the scale
increment adjust (def scaling is 1.01x per step),
and whether or not to save individual frames.

The loop types are:

  ry: rotate 360 deg around the y (vert) axis
  rx: rotate 360 deg around the x (hor) axis
  s:  scale up the brain (neg adjscale to shrink)
  sx: scale up and rotate around the x (hor) axis
  sxs: scale up, then down, while rotating
  ryx: rotate 360 deg around a diagonal axis

If ffmpeg is on your $path, you can set
use_ffmpeg to 1 to make an .mp4 directly.

To kill a running script, click the purple
"RUNNING" button (or kill tksurfer via window
kill buttons, or purple csurf "QuitSURFA"
button). 

####################
script_inflatemovie
####################

-------------------------------------------
Standard tcl script: inflatemovie.tcl
-------------------------------------------

This script can make three different types of
movies of the inflation process.  This script
requires that surfaces for individual steps in
the inflation process have first been saved with
a non-zero value in:

  csurf -> Preferences -> Expert Preferences
    -> Inflate tab -> write every x iter

before (re)-running one of:

  csurf -> MGHTools -> Smooth(Curv)/Inflate(Sulc)
  csurf -> SubjectTools -> Smooth(Curv)/Inflate(Sulc) (hi-res)

Writing a surface every iteration produces a
series of surfaces like:

  $subject/surf/rh.inflated0000
  $subject/surf/rh.inflated0001
  $subject/surf/rh.inflated0002
  ...

Adjust the value of "skip" in the popup (from
default=0) if some iterations have been skipped.
For example, if a surface is written every 10
iterations, set the value of "skip" to 9.

There are options to adjust the initial pose and
scale, the total number of steps to use, and
various other parameters (see documentation
inside script).

The three movie loop types are:

 (1) simple -- one frame per inflate step

 (2) frontbak -- dual inflate/deflate loop

   rotate 360
   stop and inflate
   rotate 360
   stop and deflate
   rotate 180
   stop and inflate
   rotate 360
   stop and deflate
   rotate 180        # i.e., back to begin -> loop

 (3) rotpump -- slow rot w/faster inflate/deflate

To kill a running script, click the purple
"RUNNING" button (or kill tksurfer via window
kill buttons, or purple csurf "QuitSURFA"
button).

####################
script_flattenmovie
####################

-------------------------------------------
Standard tcl script: flattenmovie.tcl
-------------------------------------------

Makes a simple movie of the flattening process.

As with inflatemovie.tcl, this requires that
patches for individual steps in the flattening
process have first been saved with a non-zero
value in:

  csurf -> Preferences -> Expert Preferences
     -> Flatten tab -> write every x iter

before running (re)-flattening with:

  csurf -> MGHTools -> Flatten Surface Patch

There are options to adjust the initial pose and
scale, the total number of steps to use, and
various other parameters (see documentation
inside script).

To kill a running script, click the purple
"RUNNING" button (or kill tksurfer via window
kill buttons, or purple csurf "QuitSURFA"
button). 

####################
script_annot2roi
####################

-------------------------------------------
Standard tcl script: annot2roi.tcl
-------------------------------------------

Overview

This script resamples MGH style surface region
annotations files (*.annot) and can then generate
3D ROIs from them, for either a single-subject
scan or for fsaverage.

The primary input is an MGH-style annotation file
on the fsaverage subject, selected from the
dropdown in $SUBJECTS_DIR/fsaverage/labels.

The first step (skipped if subject is fsaverage)
is to sample the fsaverage annotation onto an
individual subject's surface using mri_surf2surf.
The resampled annotation is saved in the
subject's "label" subdirectory in $SUBJECTS_DIR.

The second, optional step is to generate AFNI
BRIKs containing 3D ROIs for each region in the
annotation at the resolution of the current
individual subject functional scan (and aligned
with it), along with an all-regions-in-one ROI
BRIK.  These signed short (2-byte) BRIKs will
contain the sequential integer region id numbers
taken from the annotation, which can also be
found in the corresponding ASCII file in:
$SUBJECTS_DIR/fsaverage/scripts/<annotation_infix>.ctab
When the subject is fsaverage, the ROIs will be
generated at 256^3, 1mm^3 resolution of the
$SUBJECTS_DIR/fsaverage/mri/orig.mgz file (rather
than at a typically lesser functional volume
resolution).

The ROI BRIK files are saved to the current
functional scan dir for single subjects, and to a
pseudo functional scandir for fsaverage.  For
fsaverage 3D ROIs, first use csurf -> File -> New
Functional to create an empty 'functional'
session in $FUNCTIONALS_DIR named
"fsaverage-3D-ROIs" before running the script.

For an individual subject, two additional
required inputs are a functional scan (in order
to determine ROI BRIK voxel size) and a
register.dat file (to align the data to the
individual subject's surface annotation).  If
used interactively, select the scan from the
"scandir:" dropdown in csurf before starting
tksurfer.

For fsaverage, the ROI BRIKs will be generated as
mentioned at the 256^3 1mm^3 resolution of the
$SUBJECTS_DIR/fsaverage/mri/orig.mgz file (so an
identity matrix register.dat will be used).

Other sub-options for the second ROI-making step
are to search along the surface normal (in either
mm or fraction of distance to local pial
surface).  Any functional voxel (or fsaverage
1mm^3 pseudo functional voxel) intersected by the
normal search will be included in the 3D ROI.
Region boundaries can also be optionally eroded
to make more focal ROIs.

Another sub-option is to fill any remaining
holes, which can be generated when searches
continue above the pial surface (e.g., where
surface normals can diverge on gyral crowns).

Finally, if both hemispheres have been processed,
the right and left hemisphere ROI BRIKs will
automatically be merged in a single BRIK without
an lh- or rh- prefix.

If subject is fsaverage, the right/left merged
all-in-one ROIs BRIK will be auto-converted to an
MGH compatible (single-hemisphere) 1x1x1mm
parcellation file that will saved to the
fsaverage mri subdir:

  $SUBJECTS_DIR/fsaverage/mri/<annotation_infix>.mgz

Interactive use, details

When used interactively (via the "GO" button near
the upper left "tcl:" dropdown) the script first
makes a pop-up.  The currently available
fsaverage .annot files are loaded into the
"annot:" dropdown (default CsurfMaps1).

If "make_3D_AFNI_ROIs_flag" is ticked, the bottom
part of the pop-up panel is enabled and 3D AFNI
ROI files are also generated at the resolution of
the current functional scan.  The additional
parameters below "make_3D_AFNI_ROIs_flag" control
sampling along the surface normal and final
touch-up 3D filling of the ROI(s).

When single-subject-specific 3D ROIs are
generated, the script should be run from a
functional scan dir, because resampling from an
annotation region on the surface to a 3D ROI
requires a functional scan (to determine voxel
size of output 3D ROI files), and a standard
register.dat file (to map 3D voxel indices to 3D
surface vertex coordinates).  To automatically
load the desired scandir, select a session and
a scandir in csurf before starting tksurfer.

To make fsaverage 3D ROIs, run the script from a
functional session named "fsaverage-3D-ROIs" (a
pseudofunct scan and an identity-matrix
register.dat will be auto-created).

The "erodesteps" entry (default=0=OFF) allows
eroding a given number of rings of single
vertices from the edges of the surface ROIs
before generating the 3D AFNI ROIs to make them
more focal.

Clicking the "normsampsearchflag" tickbox enables
additional entries on the popup for searching
along the local surface normal.  These can be
further toggled between search distance in mm vs.
search distance in fraction of cortical thickness
(dist to pial surface) using the "normfracflag"
tickbox.

If regions overlap during the making of the
all-in-one 3D AFNI ROI file (as a result of
intersecting normal searches), the later region
(in the annotation file) wins.

By default, $savesingleROIbriksflag is 0 (OFF),
so the BRIKs generated for each individual region
(e.g., a total of 7G for HCP-MMP1!) will be
deleted after they have been incorporated into
the ALL_ANNOT_ROIs BRIK (flag mainly useful for
debugging).

Finally, ticking "fill3Dholesflag" enables
running the C/tcl function fill_idnumbrik_holes
on the output ROI BRIK(s) (overwrites input).  If
a voxel has a zero for its region id (i.e.,
region "Unknown"), the 26 voxels surrounding that
voxel are examined to determine which region id
is most commonly represented (not counting id=0).
If the fraction of any immediately surrounding
non-zero neighbor ids exceeds the setting of
$neighfracthres (default=0.8), the voxel will be
filled.  Any voxel with a non-zero region id will
not be touched.  The conservative default setting
of $neighfracthresh = 0.8 requires 80% of the
surrounding 26 voxels to be filled to fill an
empty voxel.  Decrease $neighfracthresh for more
aggressive hole-filling.  The most conservative
setting of $neighfracthresh is 1.0, which
requires every surrounding voxel to be filled to
fill a central hole.

When all parameters are set, click "RUN SCRIPT".
It takes several sec to generate the (temp) ROI
BRIK for each region, and several sec to fill
holes in the completed ALL_ANNOT_ROIs BRIK
(assuming you are not saving individual region
BRIKs).

The ROI BRIKs can be viewed in AFNI as an overlay
(over a functional MRI underlay for a single
subject or over orig+orig.BRIK for fsaverage).
Once both hemispheres have been processed, the
BRIKs with single hemisphere ROIs will be merged
into one ROI BRIK without a rh- or lh- prefix,
using the C/tcl tksurfer function:

  merge_indum_briks <lh-in.BRIK> <rh-in.BRIK> <out.BRIK>

which will merge files that look like this:

  lh-ALL_ANNOT_ROIs-fr=0.0to1.1+orig.BRIK
  rh-ALL_ANNOT_ROIs-fr=0.0to1.1+orig.BRIK

into a single BRIK without an lh- or rh- prefix:

  ALL_ANNOT_ROIs-fr=0.0to1.1+orig.BRIK

This function expects short (2-byte) BRIKs
containing sequential idnum integers, each
starting with region=0=Unknown.  The first BRIK
(usu. LH) will be read in, and then any non-zero
voxels in the second BRIK (usu. RH) will replace
equivalent voxels in the first BRIK.  The idnums
for the second (RH) BRIK (which before
modification start with region idnum=1) will each
be incremented by the total number of regions in
the first (LH) BRIK (including 0=Unkonwn) so that
left and right region idnums do not overlap, are
sequential, and so that there is only one
"Unknown" region (same for both hemispheres).

If the subject is fsaverage, the all-in-one 3D
ROI BRIK will be auto-converted to an MGH *.mgz
file that will be saved in:

  $SUBJECTS_DIR)/fsaverage/mri/$annotinfix.mgz

This can be viewed in tkmedit by reading it in as
a second image, using the "im2:" dropdown at the
bottom middle (it will be auto-detected as an
overlay).  If the annotation file has a
non-standard name, you may have to untick and
re-tick "la" (show second image as a transparent
overlay instead of second blink comparison image)
just to the right of the "im2:" entry.

The 3D (tkmedit) display colors for each named
region in tkmedit will be read out of one of the
following ASCII color table files, by looking at
the prefix of the original annotation file that
was selected:

  $CSURF_DIR/lib/lut/FreeSurferColorLUT.txt (incl's lh/rh)
  $CSURF_DIR/lib/lut/CsurfColorLUT-both.txt
  $CSURF_DIR/lib/lut/HCP-MMP1ColorLUT-both.txt

The utilities for generating these files are
described below after explaining a number of
conflicting color table conventions.

ASCII color tables vs. annotation color tables

There are a number of different conventions for
the ASCII color tables that map region idnums to
region names and colors in 2D and 3D displays
that also differ from the conventions used in MGH
annotation files ($hemi-$parcellation_name.annot).

Standard single-hemisphere MGH annotation files
have sequential region idnums starting with
region 0=Unknown with no gaps.  Since
surface-based analysis is typically done
separately for each hemisphere, region idnums in
left and right hemisphere *.annot files can/will
overlap (even though the region names in the
annotation itself may be hemisphere-specific).
This is because any gaps in the ASCII color table
file used to direct construction of an annotation
are squeezed out in the output annotation file
(csurf tksurfer write_mgh_annot originally
retained the gap-containing idnums taken from the
master color table file, but had to change to
sequential because the gapped *.annot files
caused crashes in some MGH freesurfer utilities).

This means that the mapping between region idnums
and region names in the master ASCII color table
file are NOT preserved in the annotation file.
To avoid ambiguity, when any annotation file is
read (read_mgh_annot), its internal sequential
idnum color table is written out to the file:

  $SUBJECTS_DIR/$subject/scripts/$annotprefix.ctab

By contrast with hemisphere-specific, sequential
color tables in annotation files, the standard
master ASCII FreeSurfer color table:

  $CSURF_DIR/lib/lut/FreeSurferColorLUT.txt

contains a large number of named regions for both
hemispheres mapped to idnums that are not
required to be sequential.  The idnums begin with
region 0 (Unknown) and in FreeSurfer5.3 go up to
region 14175 (wm_rh_S_temporal_transverse).  Most
(but not all) of these regions have
hemisphere-specific infixes (with several
different naming conventions) and unique RGB
colors.  Finally, the regions are not always
sorted numerically by idnum in the file.

The CsurfMaps1 parcellation ASCII color table
file (used to generate rh/lh-CsurfMaps1.annot):

  $CSURF_DIR/lib/lut/CsurfColorLUT.txt

is similar to FreeSurferColorLUT.txt in that it
has gaps.  But it contain no hemisphere-specific
names (e.g., MT_upper), and is sorted
numerically.

Finally, the HCP parcellation was resampled to
fsaverage and used to generate left and right
hemisphere MGH annotation files.  The sequential
annotation color tables generated upon reading
the annotation for each hemisphere in csurf
tksurfer are found here:

  $CSURF_DIR/lib/lut/lh-HCP-MMP1ColorLUT.txt	
  $CSURF_DIR/lib/lut/rh-HCP-MMP1ColorLUT.txt	

The HCP parcellation has distinct left and right
hemisphere area names with a "L_" or "R_" prefix,
but the left and right hemisphere idnums overlap.

Generating both-hemisphere color tables for 3D display

To generate color tables containing unique left
and right hemisphere names, (sequential) idnums,
and unique region colors for displaying and using
3D ROIs, there is a standalone tcl script:

  $CSURF_DIR/bin/noarch/mkbothlut

that takes the ASCII color tables above as input
and generates a new color table with a "-both"
infix, as mentioned above:

  $CSURF_DIR/lib/lut/CsurfColorLUT-both.txt
  $CSURF_DIR/lib/lut/HCP-MMP1ColorLUT-both.txt

In the case of CsurfMaps1, the left-plus-right
color table is made by pre-appending "L_" and
"R_" to make left and right hemisphere versions
of the region names, adding the max left
hemisphere idnum to all right hemisphere areas,
and incrementing the red color by 1 (to make
similar but L/R unique colors for each bilateral
region).

In the case of HCP-MMP1, the left-plus-right
color table is made by keeping the already
hemisphere-specific names, adding the max left
hemisphere idnum to all right hemisphere areas,
and keeping the already unique-but-similar RGB
region colors.

Complete example for single subject ROIs

Starting with a functional scan (e.g., an AFNI
BRIK in /tmp), here is a minimal outline of what
is required starting with raw functional data:

  (1) create an empty functional dir:

    File -> New Functional

  (2) import at least one functional scan into it:

    SessionTools -> File Make Scandirs, Find/Copy Raw
    click DELETE LAST SCANDIR
       [just "alignscan" left, rename to "functscan"]
    click FIND
       [locate functional scan in /tmp]
    click MAKE SCANDIRS
    click STRIP/COPY RAW

  (3) align that functional scan with recon-all struct

    SessionTools -> Setup Align/Funct Scans
    click "Funct Scan Dir" (top)
    click READ HEADER
    click INIT/FLIP to initialize transform
    click FUNCT=>SUBJ
       [do manual alignment]
       tkregister -> click SAVE REG
    Save/Close

  (4) run annot2roi.tcl

    csurf -> SURFACE
    select annot2roi.tcl from tksurfer "tcl:" dropdown
    ["rawdata" should be preset to "functscan"]
    GO

See csurf -> Help -> Retinotopy HOWTO for hints
on manual alignment.

Tcl script equivalent

Here is an example set of tcl commands required
(example scandir is "polar1"):

### re-sample fsaverage annotation to this subj
set annotinfix HCP-MMP1
set fsavgannot \
$env(SUBJECTS_DIR)/fsaverage/label/$hemi.$annotinfix.annot
set subjannot \
  $env(SUBJECTS_DIR)/$subject/label/$hemi.$annotinfix.annot
set cmd "mri_surf2surf \
  --srcsubject fsaverage \
  --trgsubject $subject \
  --hemi $hemi \
  --mapmethod nnf \
  --sval-annot $fsavgannot \
  --tval $subjannot"
exec $cmd
### convert subj-specific annot to 3D ROI's
setfile regdat */polar1/register.dat		;# setfile expands abbrev
setfile rawdata */polar1/polar1+orig.BRIK
setfile anlabel $subjannot
set erodesteps 0
read_mgh_annot
for {set i 0} {$i < $erodesteps} {incr i} {
  erode_annot
}
# load sample surf (speeds write_annotcols_timecourses_stats)
set insurfCURR $insurf
setfile insurf $hemi.orig
read_binary_surface
# set sample parms
set normdsampsearchflag 1			;# turn on normal search
set normdfracflag 1			;# use fractional dist (vs. mm)
set normdfracsamp 0.0			;# frac thickness search begin
set normdfracmax  1.0			;# frac thickness search end
# make indiv plus all-in-one ROI BRIKs
write_annotcols_timecourses_stats 3     ;# 3=3D-ROIs
# restore init surface
setfile insurf $insurfCURR
read_binary_surface
# HOWTO fillholes:
#   fill_idnumbrik_holes <pref+orig.BRIK> <neighfracthresh[OK:0-1]>
# HOWTO merge L/R and convert to mgz:
#   merge_idnum_briks <lh-name+orig.BRIK> <rh-name+orig.BRIK> <name+orig.BRIK>
#   shortcorbrik2intmgz <name+orig.BRIK> <name.mgz>

####################
script_searchlightdiff
####################

-------------------------------------------
Standard tcl script: searchlightdiff.tcl
-------------------------------------------

This script runs full-hemisphere searchlight
operations on two sets of real-valued data and
then subtracts the first result from the second.

Running it interactively from the "tcl:" script
dropdown in csurf first generates a pop-up to
adjust parameters.  Clicking "RUN SCRIPT" on the
pop-up first runs the searchlight operations:

  Searchlight operations:

    0 -> average of searchlight data
    1 -> count num classes (assumes integer data)
    2 -> variance of searchlight data
    3 -> [not relevant: neighop_val2stat paintballs]
    4 -> sum each searchlight

and writes out the result of the seachlight
operation as two vertewise labels.  These
multithreaded operations take about 10
min/hemisphere on an Intel i7.

Then, the first searchlight result is subtracted
from the second searchlight result and saved as a
third vertexwise label (with a verbose name
indicating its origin).

The size, ${num,sqmm,mm}, of the approximately
geodesic surface searchlight circles can be
specified by vertex count (num), area (mm^2),
radius (mm), or by neighbor order (1=immediate
neighbors, 2=also include neighbors of neighbors,
etc):

  Searchlight size ($fillneartype):

    0 -> num vertices
    1 -> area (in mm^2)
    2 -> radius (in mm)
    3 -> neighbor order (1-6)

The first three searchlight size specifications
($fillneartype) use the C/tcl function,
searchlightop_val2stat (multi-threaded), while
the fourth specification uses the C/tcl function,
neighop_val2stat (similar result for similar
vertex count, goes up to 6th-order neighbors,
which is 127 vertices on fsaverage).

Adjustable parameters can be hard-coded in this
script (see commented-out example inside) in
order to run it non-interactively from the
command line as a tksurfer tcl script.

To kill a running script, kill tksurfer either
using its window kill buttons, or the purple
"QuitSURFA" button on csurf (the purple "RUNNING"
button on script popup window cannot kill the
script).

####################
script_searchlightarea
####################

-------------------------------------------
Standard tcl script: searchlightarea.tcl
-------------------------------------------

This script estimates local area differences by
resampling individual subject vertexwise area
data to fsaverage, and then running a
surface-based searchlight operation on the
resampled data using fsaverage sphere.

First, create a Cross-Subject Session (for
display subject, fsaverage) with:

  csurf -> File -> New SphereAvg 
  (pseudo-subject "XS" for "cross-session") 

Then, select subject "fsaverage" and the "sphere"
surface, the just-created empty session, and
click SURFACE.  After tksurfer starts, select
searchlightarea.tcl from the "tcl:" dropdown in
at the top left of the tksurfer interface.  This
generates a pop-up to select a subject and adjust
parameters.

Clicking "RUN SCRIPT" on the pop-up resamples the
area data, and then runs the searchlight
operation:

  4 -> sum of data in searchlight

The result is written out as a vertexwise
curvature-format file.  The multi-threaded
operation takes about 10 min/hemisphere on an
Intel i7.

The size, ${num,sqmm,mm}, of the approximately
geodesic surface searchlight circles can be
specified by vertex count (num), area (mm^2),
radius (mm), or by neighbor order (1=immediate
neighbors, 2=also include neighbors of neighbors,
etc):

  Searchlight size ($fillneartype):

    0 -> num vertices
    1 -> area (in mm^2)
    2 -> radius (in mm)
    3 -> neighbor order (1-6)

The first three searchlight size specifications
($fillneartype) use the C/tcl function,
searchlightop_val2stat (multi-threaded), while
the fourth specification uses the C/tcl function,
neighop_val2stat (similar result for similar
vertex count, goes up to 6th-order neighbors,
which is 127 vertices on fsaverage).

Adjustable parameters can be hard-coded in this
script (see commented-out example inside) in
order to run it non-interactively from the
command line as a tksurfer tcl script, for
example:

#! /bin/sh
sublist="marty sean jill sue"
hemlist="rh lh"
cd $SUBJECTS_DIR/fsaverage/scripts
cp $CSURF_DIR/lib/tcl/searchlightarea.tcl .
for sub in $sublist; do
  for hem in $hemlist; do
    export sampsubj=$sub    # tcl script reads env
    tksurfer fsaverage $hem sphere -tcl searchlightarea.tcl
  done
done

To kill a running script, kill tksurfer either
using its window kill buttons, or the purple
"QuitSURFA" button on csurf (the purple "RUNNING"
button on script window cannot kill the script).


####################
script_explodemovie
####################

-------------------------------------------
Standard tcl script: explodemovie.tcl
-------------------------------------------

This script re-creates the exploding brain shown
in a talk by Sereno and Dale at SFN in 1992.  The
default parameters are adjusted to explode a
smoothwm surface.

The explosion works by adding a constant outward
force along the perpendicular to each vertex
($mstrength).  Edges are then disconnected when
the stress goes above $stressthresh.  This
creates stress-concentrating fractures.

Running it interactively from the "tcl:" dropdown
in csurf first generates a pop-up to adjust
parameters.  Clicking "RUN SCRIPT" on the pop-up
generates a set of tiff frames (default: 1460) in
the current subject's bitmap directory:

  $SUBJECTS_DIR/$subject/rgb/f%05d.tiff

This is designed to be viewed at 30 fps.

####################
labelalpha
####################

-------------------------------------------
tickbox variable: $labelalpha -- label transparency
-------------------------------------------
default: 128

The "tran" entry (upper left) determines
transparency (alpha) of labels when they are
displayed as a single-color transparent overlay
using the label line "D" button, where 255 is
opaque and 0 is completely transparent
(invisible).

This transparency value is used when a label is
read in.  By changing the value before reading a
second label, that second label can be displayed
with a different transparency.

This is analogous to how the "r", "g", and "b"
fields to the right of MESH are used to get
different color labels during label reading with
the "D" button.

To reset the transparency of all labels (e.g., an
annotation) currently displayed to a single
value, enter that value and do a <Return> in the
"tran" entry (tcl function: set_annot_alpha
<alpha>).

Transparency/alpha values in annotation files
(typically 0) are ignored.

####################
curv
####################

-------------------------------------------
entry variable: $curv -- absolute name curv file
def: $SUBJECTS_DIR/name/surf/$hemi.curv
-------------------------------------------
aux variable: $template -- absolute name template
def: $FSURF_DIR/average/
          $hemi.average.curvature.filled.buckner40.tif
-------------------------------------------

Single Subject Curvature

The "curv:" entry at the upper left shows the
current file loaded as curvature.  To load a
different file, select one from the "curv:"
dropdown (or use "R"), for example:

 $hemi.curv -- standard local curvature file
 $hemi.sulc -- summed local perpendic. movement
 $hemi.thickness -- vertexwise gray matter thickness

Relative name assumes same dir as above.  Home
dir of subject can be abbreviated as tilde (~).
Absolute name OK, too.  Reads either old curv or
new curv file format.  New curv format files can
also be read by read_binary_values.

Average Morph Target Template

If FSURF_DIR is defined, the standard MGH morph
target template files (Mercator projections
stored in a multi-frame .tif) will be loaded at
the bottom of the dropdown, for example:

  $hemi.average.curvature.filled.buckner40.tif

On selecting one of these tif's, a pop-up will
first appear to allow selecting one of its
frames.  Useful frames are 3 (average sulc) and 6
(average curvature).

Binary Formats

Binary oldcurv file format:
  [no magic number]
  3-byte uint vertex count
  3-byte uint face count
  2-byte short curv[vtx0]*100
  2-byte short curv[vtx1]*100
   ...
  [implicit vtx numbering -- all vtxs req'd]

Binary newcurv file format (=newarea format):
  3-byte magic number: 16777215
  4-byte int vertex count
  4-byte int face count
  4-byte int values per vertex
  4-byte float data [vtx0]
  4-byte float data [vtx1]
  ...
  [implicit vtx numbering -- all vtxs req'd]

Binary template file format (Mercator projection)
  multi-frame uncompressed .tif
  width=256, height=512
  32 bits per sample
  1 sample per pixel

####################
curv_read
####################

#### display single or average curvature ####
-------------------------------------------
funct (left-click): read single subj curv
  set curv <infile>
  read_binary_curv
-------------------------------------------
alt funct (if *.tif): read morph target frame
  set template <some_template.tif>
  read_tif_template <frame>
-------------------------------------------

The "R" button on the "curv:" entry line reads
curvature from file whose name is current value
of $curv (entry at left).  In a tcl script, to
read the standard subject dir curvature file,
use:

  setfile curv ~/surf/$hemi.curv  ;# globs
  read_binary_curv

By contrast, to read in an arbitrary file as
curv, use:

  set curv /some/random/curvature/file
  read_binary_curv

If the selected file ends in *.tif, the file will
be assumed to be a multi-frame, 256x512, 32-bit
per pixel MGH template (tcl filename variable:
$template).  A pop-up will appear to allow
selecting one of the frames to load.  In a tcl
script, this could be done with:

  set template /Applications/freesurfer/average/$hemi.average.curvature.filled.buckner40.tif
  set templateframe 6
  read_tif_template

####################
curv_write
####################

-------------------------------------------
funct (left-click): write curvature
  set curv <outfile>
  write_binary_curv
-------------------------------------------

The "W" button on the "curv:" entry line
writes out current local surface curvature as
file: $curv (name in entry to left). Must confirm
overwrite, or use write_binary_curv (doesn't ask).

To make the sulc file, set sulcflag to 1, unfold
surface with SHRINK, set the output file name in
$curv, and write_binary_curv.

####################
area
####################

-------------------------------------------
entry variable: $area -- abs name orig area file
-------------------------------------------
default: $SUBJECTS_DIR/name/surf/$hemi.area

The "area:" entry shows the current filed loaded
as original area.  To load a different original
area file, select one from the "area:" dropdown
and use "R", for example:

 $hemi.area -- standard local area file (white)
 $hemi.area.mid -- area calculated at mid depth
 $hemi.area.pial -- area calculated on pial

The area at a vertex is defined as the sum of 1/3
the area of each adjacent triangular face.

Relative name assumes same dir as above.  Home
dir of subject can be abbreviated as tilde (~).
Absolute name OK, too.  Reads either old area or
new area file format.

Binary oldarea file format:
  [no magic number]
  3-byte uint vertex count
  3-byte uint face count
  4-byte float data [vtx0]
  4-byte float data [vtx1]
  ...
  [implicit vtx numbering -- all vtxs req'd]

Binary newarea file format (=newcurv format):
  3-byte magic number: 16777215
  4-byte int vertex count
  4-byte int face count
  4-byte int values per vertex
  4-byte float data [vtx0]
  4-byte float data [vtx1]
  ...
  [implicit vtx numbering -- all vtxs req'd]

The area files in the entry can be read into the
.origarea field or the .origarea2 field (see
R-click help for "area:" label).

####################
area_read
####################

-------------------------------------------
funct (left-click w/label="area"):
  set area <infile>
  read_binary_areas
-------------------------------------------
funct (left-click w/label="area2"):
  set area <infile>
  read_binary_areas2
-------------------------------------------


Detailed Description of Area "R" Button Actions

-------------------------------------------
function (left-click w/label="area"):
  set area <infile>
  read_binary_areas
-------------------------------------------

The "R" button on the "area:" entry line reads
the local area from file whose name is current
value of $area (entry at left).

Reading an area file defines the "original area"
of each vertex (the .origarea field).  An
original area file is typically generated at
surface-making time from the $hemi.white surface.
On startup, tksurfer loads this file ($hemi.area)
regardless of which surface is being displayed
(other original area files include:
$hemi.area.mid and $hemi.area.pial).

The "original area" values (in the .origarea
field) as well the the current surface area
values (in the .area field) are both reported
when doing a FILL to create a patch or label.

Note that unlike other entries, the "R" and "W"
buttons (which use functions read_binary_areas
and write_binary_areas) read to and write from
*different* data fields:

  read_binary_areas:    areafile -> .origarea field
  write_binary_areas:   .area field -> areafile

That is, "R" (read_binary_areas) reads an area
file as an "original area" (into the .origarea
field), while "W" (write_binary_areas) writes out
the "current surface local area" (the .area
field) to an areafile.

If you try to overwrite the original area file
($hemi.area) with the current area using the "W"
button without changing the output file name,
there will be a warning.

-------------------------------------------
Alt funct (left-click w/label="area2"):
  set area <infile>
  read_binary_areas2
-------------------------------------------

If the "area:" label is left-clicked so that it
changes to "area2", an alternate function,
read_binary_areas2, is used to read the selected
area file into the .origarea2 field.

This is used for calculating area ratios (see
R-click help for "area:" label).

####################
area_write
####################

-------------------------------------------
funct (left-click): write curr area to file
  set area <outfile>
  write_binary_areas
-------------------------------------------

The "W" button on the "area:" entry line writes
out vertex-wise local surface area for the
current surface to the file: $area (name
currently in entry to left).  The data written
out comes from the .area field (N.B.: *not* from
the .origarea field).

There is a warning if you try to overwrite
$hemi.area, the "original area" file, which is
generated at surface-making time, and which is
always read by tksurfer at startup, regardless of
which surface is displayed (in order to be able
to report original-surface areas of labels).

This is similar to the handling of the original
3D surface vertex coordinates.

N.B.: the write_binary_area function NO LONGER
copies the contents of the .area field to the
.origarea field (old confusing behavior where
current surface area is re-defined as "orig").
To do this, instead simply read in the file just
written with the "R" button.

####################
area_disp
####################

-------------------------------------------
funct: "Display Curr-to-Orig Log Area Ratio (left-click-D)"
  calcdisp_curr2orig_logarat (tksurfer.tcl)
-------------------------------------------
funct: "Display Curr-to-Orig Area Ratio (all pos) (mid-clk-D)"
  calcdisp_curr2orig_arat (tksurfer.tcl)
-------------------------------------------
funct: "Disp Area-to-AreaPial Area Ratio (shift-mid-clk-D)"
  calcdisp_arat (tksurfer.tcl)
-------------------------------------------


Detailed Description of Area "D" Button Actions

-------------------------------------------
funct: "Display Curr-to-Orig Log Area Ratio (left-click-D)"
  calcdisp_curr2orig_logarat (tksurfer.tcl)
-------------------------------------------

The "D" button on the "area:" entry line
calculate local areal distortion of the current
surface and display using curvature color scale.
Current local area is divided by the original
local area (from area file for $hemi.white), then
log taken before display (no distortion => zero).

Green is stretched, red is compressed, gray is
undistorted.  Color saturation indicates degree
of distortion.

Left-clicking the "D" button performs the
following operations (after confirm):

  (1) (re)load $hemi.area as .origarea
  (2) calc curr/orig area ratio (.area = .area/.origarea)
  (3) take log of .area, save back in .area
  (4) save result as $hemi.area.logarat
  (5) display result using curv color scale
  (6) adjust cslope/cmid (for inverted)
  (7) reinstate current surface area (to .area)

Here is a tcl script to do this same thing, and
then also save a tiff of the result in the rgb
dir of the current subject (setfile is a globbing
"set"):

  ### read first file area (redundant)
  setfile area ~/surf/$hemi.area
  read_binary_areas

  ### divide second by first (0 if orig=0), take log
  compute_curr2orig_area_ratio
  compute_logarea

  ### write area ratio file
  setfile area ~/surf/$hemi.area.arat
  write_binary_areas

  ### read in area file as a curvature
  setfile curv ~/surf/$hemi.area.arat
  read_binary_curv

  ### display: reset midpoint, flip red/green
  set cmid 0.0        ;# red/green midpoint
  set cslope -0.75  ;# minus -> flip red/grn
  smooth_curv 5
  redraw

  ### reinstate current surface area (to .area)
  compute_normals_areas

  ### save rgb
  setfile rgb ~/rgb/logaratio-$hemi-inflated-lat.tiff
  save_rgb

-------------------------------------------
funct: "Display Curr-to-Orig Area Ratio (all pos) (mid-clk-D)"
  calcdisp_curr2orig_arat (tksurfer.tcl)
-------------------------------------------

Same as above, except display all-positive area
ratio (instead of log area ratio).  Resets color
scale to change around 1.0 instead of 0.0.

Green is stretched, red is compressed, gray is
undistorted.

Middle-clicking the "D" button performs the
following operations (after confirm):

  (1) (re)load $hemi.area as .origarea
  (2) calc curr/orig arearatio (.area = .area/.origarea)
  (3) save result as $hemi.area.arat
  (4) display result using curv color scale
  (5) adjust cslope/cmid (for inverted/all-pos)
  (6) reinstate current surface area (to .area)

Here is a tcl script to do this same thing:

  ### read first file area (redundant)
  setfile area ~/surf/$hemi.area
  read_binary_areas

  ### divide second by first (0 if orig=0)
  compute_curr2orig_area_ratio

  ### write area ratio file
  setfile area ~/surf/$hemi.area.arat
  write_binary_areas

  ### read in area file as a curvature
  setfile curv ~/surf/$hemi.area.arat
  read_binary_curv

  ### display: re-center, flip red/green for all-pos
  set cmid 1.0      ;# red/green midpoint
  set cslope -1.0  ;# minus -> flip red/grn
  smooth_curv 5
  redraw

  ### reinstate current surface area (to .area)
  compute_normals_areas

-------------------------------------------
funct: "Disp Area-to-AreaPial Area Ratio (shift-mid-clk-D)"
  calcdisp_arat (tksurfer.tcl)
-------------------------------------------

Similar to above, but calculates area ratio
between .area and .area.pial:

  (1) (re)load $hemi.area as .origarea
  (2) load $hemi.area.pial as .origarea2
  (3) calculate area ratio (.area = .origarea2/.origarea)
  (4) save result as $hemi.area.arat
  (5) display result using curv color scale
  (6) adjust cslope/cmid (for inverted/all-pos)
  (7) reinstate current surface area to .area

Here is a tcl script to do this same thing:

  ### read first file area (redundant)
  setfile area ~/surf/$hemi.area
  read_binary_areas

  ### read second area file
  setfile area ~/surf/$hemi.area.pial
  read_binary_areas2

  ### divide second by first (0 if first=0)
  compute_area_ratio

  ### write area ratio file
  setfile area ~/surf/$hemi.area.arat
  write_binary_areas

  ### read in area file as a curvature
  setfile curv ~/surf/$hemi.area.arat
  read_binary_curv

  ### display: re-center, flip red/green for all-pos
  set cmid 1.5      ;# red/green midpoint
  set cslope -1.0  ;# minus -> flip red/grn
  smooth_curv 5
  redraw

  ### reinstate current surface area (to .area)
  compute_normals_areas


####################
area_lab
####################

-------------------------------------------
label: "area:" vs. "area2"
-------------------------------------------
keyboard equiv: <none>

This entry has two different states, "area:"
(read area file in entry into .origarea field),
and "area2" (read area file into .origarea2).

On startup, the default state is "area:", which
is used to (re-)read ("R" button) vertexwise
area, used when reporting the area of labels (or
during F3 interface shrink operations).

Clicking on the label "area:" (bold to indicate
it is button-like) swaps in the "area2" label,
which changes the function of the "R" button to
read the area file instead into the .origarea2
field.  The .origarea2 field can be used for
calculating area ratios.

Clicking the label again toggles it back to
"area:"

See the "area:" line "D" button help for how to
automatically generate an area ratio display
(either current area divided by original area, or
area file divided by area2 file).

####################
usecurr
####################

-------------------------------------------
select output labelfile coords-type (left-click):
  $usetalrcoordsflag -- toggle orig vs. Talairach surf coords
  $usecurrcoordsflag -- toggle orig vs. curr surf coords
  $xform_mni_305to152_flag -- toggle MNI 350 vs. 152
-------------------------------------------

The "| ta | cu |" selection bar controls which
x,y,z coordinates are used when writing any
subsequent label files (e.g., using a left-click
on the "W" button on the "label:" line).  There
are 3 possibilities:

  1) .orig surface vtx coords (default: "ta" and "cu" both off)
  2) Talairach coordinates ("ta" selected/depressed)
  2) current surface coordinates ("cu" selected/depressed)

N.B.: The exact coordinates saved in a label file
are also affected by $normdsampsearchflag (ON by
default), which moves along the local vertex
normal to specify a point within the gray matter.
R-click the "label:" label to get a popup to
adjust the parameters of this (small) movement.

N.B.: Regardless of the state of the "ta" button,
*both* MNI 305 coordinates as well as MNI 152
coordinates are always reported to the log when
clicking SEND.

-------------------------------------------
default=.orig: (both "ta" or "cu" not depressed)
  set usetalcoordsflag 0
  set usecurrcoordsflag 0
  [set xform_mni_305to152_flag 0]
-------------------------------------------

By default, the $origcoords file (typically
$hemi.orig) is read to find x,y,z coordinates
to write into the label file, regardless of
which surface is currently being viewed 
(e.g., $hemi.inflated, or a flat patch).

This will typically be a point near the
gray/white matter border.

-------------------------------------------
Talairach: ("ta" depressed, "cu" not depressed)
  set usetalcoordsflag 1
  set usecurrcoordsflag 0
  set xform_mni_305to152_flag 0 -> MNI 305
  set xform_mni_305to152_flag 1 -> MNI 152
-------------------------------------------

Clicking/depressing "ta" causes the .orig surface
x,y,z coordinates to be first converted to MNI
Talaiarch coordinates, which are then put as the
x,y,z coordinates into any subsequently written
label file.

A popup allows choosing MNI 305 (default,
$xform_mni_305to152_flag=0) vs. MNI 152
($xform_mni_305to152_flag=1).

If movement along the normal has been specified
by setting $normdsampsearchflag, that will also
be reflected in the Talaiarch coordinates.

A R-click help on the "ta" button reports which
type of Talairach coordinates are currently being
used.  To change, untick the "ta" button and
re-tick it to get the popup 305/152 chooser.

Here are a list of functions that are affected
when the "ta" button is depressed (with either
305 or 152 selected):

  write_val_visible_vertices
  write_val_annoted_vertices
  write_val_annotedcol_vertices
  write_val_idnum_vertices
  write_val_unmasked_vertices
  write_annotedcol_autoname
  write_selected_list_to_label
  write_annotcols_timecourses_stats
  write_annotcol_timecourses_stats
  write_label_timecourses_stats

The MNI 305 coordinates are converted to MNI 152
coordinates using the following transformation
matrix:

   0.9975  -0.0073   0.0176  -0.0429
   0.0146   1.0009  -0.0024   1.5496
  -0.0130  -0.0093   0.9971   1.1840
   0.0000   0.0000   0.0000   1.0000

N.B.: the last two functions call the function
write_label_timecourses_stats, which separately
performs the normal search and writes both .orig
as well as Talairach coords (MNI 305 or 152 as
chosen from "ta" popup) into its (non-label
format) ASCII output timecourse files.

N.B.: find_orig_vertex_coordinates (SEND button)
always reports both MNI 305 and MNI 152.

-------------------------------------------
Current Surface: ("ta" not depressed, "cu" depressed)
  set usetalcoordsflag 0
  set usecurrcoordsflag 1
  [set xform_mni_305to152_flag 0]
-------------------------------------------

In other cases, you might want to save inflated
or flat patch coordinates into a label file.  By
depressing "cu" (setting $usecurrcoordsflag to
ON/1), the current surface x,y,z coordinates are
used instead of .orig coordinates.

If a flat patch is the currently viewed surface,
the z coordinate of every vertex will be 0.0
exactly.

The variable $usecurrcoordsflag also affects the
operation of find_uniqsamp_vertices in a similar
fashion.  That function is called from the "UQ"
button, which becomes visible when "val:" is
clicked to toggle it to "val3d:".  See R-click
help for UQ for details.

Movement along the normal is disabled when using
coordinates from the current surface.

N.B.: If both $usetalcoordsflag and
$usecurrcoordsflag are ON (=1) in a tcl script,
$usecurrcoordsflag overrides $usetalcoordsflag.

N.B.: If you are writing timecourses with:

  write_label_timecourses_stats
  write_annotcols_timecourses_stats
  write_annotcol_timecourses_stats

AND both $normdsampsearchflag and
$usecurrcoordsflag are ON (=1), the first flag
(do normal search) cancels the second, and
normalsearch from .orig is done and written into
the ASCII output files.

####################
patch
####################

-------------------------------------------
entry variable: $patch -- absolute name patch file
-------------------------------------------
$SUBJECTS_DIR/$name/surf/$hemi.$type.patch.<3d,flat>

The "patch:" entry at the upper left shows the
current surface patch loaded (if any).  To load a
different patch for the current subject and
hemisphere, select a new available patch from the
"patch:" dropdown.  It will be auto-loaded (don't
have to click "R").

To select a new patch without loading it, do a
shift-select (e.g., to use a patch as a mask).

Relative name assumes same dir as above.  Home
dir of subject can be abbreviated as tilde (~).
Absolute name OK, too.

Patch files (binary, MSB) contain a list of
vertex numbers and 'replacement' 3D locations for
each listed vertex (possibly a subset) in the
base surface:

  header: [magic] vtxcnt
  vtxnum x y z
  vtxnum x y z
  ...

A negative vertex number indicates that the
vertex is on a cut border.  Any missing vertex
will not be shown.

Since a patch contain no information about faces,
a patch can only be read after first having read
a complete, base surface for a hemisphere (which
contains the specification of neighbor relations
and faces).

The patch naming convention is:

  $hemi.<patchtype>.patch.<3d,flat>

For example:

  rh.occip.patch.3d
  rh.occip.patch.flat
  rh.full.patch.3d
  rh.full.patch.flat

In order to get the settings (rot/scale/trans) in
the "Views" tab of Help -> Expert Preferences to
apply to a patch, the patchtype infix must start
with "full" or "occip" ("cortex" is a synonym for
"full", and "occ" is a synonym for "occip").

When a surface has been flattened, the
z-coordinate for all vertices is set to zero.

A patch can also be used like a label to "mask"
(show only vertices in patch) or "cut" (cut away
vertices in patch) (see "M" and "C" buttons on
"patch:" line).  This ignores the 'replacement'
3D vertex coordinates.

N.B.: a 2D patch won't be visible if its back
surface or one of its edges are toward the
viewer.  Therefore, to be sure a patch is visible
in tksurfer (given the default orientation of
patches in x,y,z space), be sure to first execute
the following two tcl commands:

  restore_zero_position
  rotate_brain_x -90

This is automatically done by the RESTORE button,
or when a patch is read with "R" on the "patch:"
line.

As mentioned above, the in-plane rotation,
scaling, and x-y position of the patch are
typically fine-tuned to fill the display window
using csurf -> Preferences -> Expert Preferences
-> Views (tab).  These entries will be filled
with useful starting values for full hemisphere
patches as well as smaller occipital patches.

================================================
HOWTO make cuts for full flattening
================================================

  (1) relaxation cuts -- LEFT-CLICK seq, LINE
  (2) remove midline -- LEFT-CLICK seq, AREA
  (3) fill keep region -- one LEFT-CLICK, FILL
  (4) save patch file -- WRITE (?h.full.patch.3d)

================================================
HOWTO touch-up a patch (use MESH to see dangling)
================================================

  (1) small trim: select list of vtxs, left-clk-PNTS
  (2) repair small cut: select edge vtxs, mid-clk-PNTS
  (3) repair big cut: make covering label, "label:" mid-clk-D

================================================
HOWTO flatten a 3D patch
================================================

  (1) select 3d patch in csurf ("patch:" combobox)
  (2) SubjectTools or MGHTools -> Flatten Surface

================================================
HOWTO use a patch to edit another surface/patch
================================================

A patch can be used to edit the current surface
(or another currently displayed patch).  The "M"
and "C" buttons on the "patch:" line will use the
patch in the entry to "M=mask" (delete anything
*not in* that selected patch) or "C=cut" (delete
anything *in* that selected patch).

Because selecting a patch from the "patch:"
dropdown normally auto-loads it, press left-Shift
when choosing the mask/cut patch to just select a
patch without auto-loading it.

These operations only use the vertex list in the
editing patch and ignore the vertex coordinates,
so a 3d patch from an inflated surface, for
example, can be used to edit any surface or patch
from that subject.


================================================
Binary patch file formats:

 old 2-byte short patch (binary, vertex subset):

  [no magic number]
  4-byte int patch vertex count
  [patch: vertex count sets of 4,2,2,2 bytes]
  4-byte int [+,-]1-based vertexnum (neg->border)
  [signed,1-based vtxnums -> pos,0-based to use]
  2-byte short patch vertex x-pos (mm*100)
  2-byte short patch vertex y-pos (mm*100)
  2-byte short patch vertex z-pos (mm*100)
   ...

 new 4-byte float patch (binary, vertex subset):

  4-byte int -1 magic number
  4-byte int patch vertex count
  [patch: vertex count sets of 4,4,4,4 bytes]
  4-byte int [+,-]1-based vertexnum (neg->border)
  [signed,1-based vtxnums -> pos,0-based to use]
  4-byte float patch vertex x-pos (mm)
  4-byte float patch vertex y-pos (mm)
  4-byte float patch vertex z-pos (mm)
   ...


####################
patch_read
####################

-------------------------------------------
var,funct (left-click): read patch
  set patch <infile>
  read_binary_patch
-------------------------------------------

The "R" button on the "patch:" entry line reads
binary patch from file whose name is current
value of $patch (entry at left).

It is assumed that the patch file comes from the
same base surface and hemisphere as that on the
tksurfer command line.

A patch can be read over any surface with the
same topology (e.g., orig, smoothwm, inflated,
white, pial, sphere).

####################
patch_write
####################

-------------------------------------------
var,funct (left-click): write current patch
  set patch <outfile>
  write_binary_patch
-------------------------------------------

The "W" button on the "patch:" entry line writes
out current cut/filled state of surface as
patchfile $patch (name in entry to left).  Must
confirm overwrite, or use write_binary_patch
(doesn't ask).  Naming convention:

  $hemi.<patchtype>.patch.<3d,flat>
  (e.g., rh.occip.patch.flat)

####################
patch_mask
####################

-------------------------------------------
var,funct (left-click): read patch to mask surface
  set patch <infile>
  read_binary_patch_to_mask
-------------------------------------------

The "M" button on the "patch:" entry line reads
binary patch from file whose name is current
value of $patch (entry at left) in order to mask
current surface -- "mask" means, show current
surface vertices that are in the masking patch.

N.B.: The 3D coords in the patch are ignored so
any patch can be used as a mask.  For example, a
flat patch can be used to display the equivalent
part of a folded surface:

  1) read surface to be masked
  2) select patch to use as mask by holding down Shift
  3) click "M" button to mask current surface with patch

N.B.: holding down shift during selection blocks
the normal behavior of immediately autoloading
the patch after it is selected.

This procedure is useful in cases where you want
to make a cut on the simpler inflated surface,
but then apply the cut to the more complex folded
surface (where it would be impossible to specify
that cut because of self-occlusion).

An alternate way to perform that same operation is
to make a label from the patch (by filling the
entire patch), then use it to cut out the part of
the surface you want to keep (shift-middle-click
"R" button -- was "RC").

The "patch:" line method here avoids creating an
extra label file that might get stale if a patch
is re-made/modified.

####################
patch_cut
####################

-------------------------------------------
var,funct (left-click): read patch to cut surface
  set patch <infile>
  read_binary_patch_to_cut
-------------------------------------------

The "C" button on the "patch:" entry line reads a
binary patch from file whose name is current
value of $patch (entry at left) in order to cut
away that part of the current surface (this has a
complementary effect to adjoining "M" button on
the "patch:" line).

This function can be used to create multiple,
non-overlapping/abutting patches.  For example,
if patches for the left and right posterior
cerebellar lobes have been created, those patches
can then be cut off from the full surface to
obtain the non-overlapping anterior cerebellum
remainder.

N.B.: The 3D coords in the patch are ignored so
any folded or flattened patch from the same
original surface can be used to cut away parts of
the current surface.

  1) read surface to be cut
  2) select patch to use as cut by holding down Shift
  3) click "M" button to mask current surface with patch

N.B.: holding down shift during selection blocks
the normal behavior of immediately autoloading
the patch after it is selected.

An alternate way to perform the same operation is
to make labels from the patches, then use them to
cut holes in the surface (middle-click on the
"label:" line "C" button).  The method here
avoids creating extra label files that might get
stale if patches are re-made/modified.


####################
label_toggle
####################

#### toggle labels, vtxcol, MGH borders ####
-------------------------------------------
toggle variable (left-click):
  $labelflag -- toggle displayed label visibility
-------------------------------------------
toggle variable (middle-click):
  $vtxcolflag -- toggle vtxcol visibility
-------------------------------------------
toggle variable (shift-middle-click):
  $annotbordflag -- toggle MGH border visibility
-------------------------------------------
  [next 2 only appear if g++ compile]
-------------------------------------------
toggle variable (no shortcut):
  $areanamesflag -- visibility of annot area names
-------------------------------------------
variable: $fontsize (popup) -- area names font size
-------------------------------------------
variable: $dthreshfact (popup) -- hack: adj label occlusion
-------------------------------------------
toggle variable (no shortcut, tcl-only):
  $newreadfulllabflag -- toggle new read shows full labels
-------------------------------------------
toggle variable (shift-right-click):
  $annotmaskflag -- toggle MGH masking-by-idnum(s)
-------------------------------------------
toggle variable (shift-left-click):
  $padlabelvtxsflag -- toggle show neigh of each label vtx
-------------------------------------------
toggle variable (ctrl-shift-middle-click):
  $annotborddotflag -- toggle white dots at borders
------------------------------------------- 
variable: $pointsize (popup) -- area names font size
-------------------------------------------
variable: $meshr (popup) -- area names font size
-------------------------------------------
variable: $meshg (popup) -- area names font size
-------------------------------------------
variable: $meshb (popup) -- area names font size
-------------------------------------------
funct (ctrl-shift-right-click): prune dot borders
  tcl/C funct: prune_annotbord
-------------------------------------------
funct (on labeltick pop-up): restore dot borders
  tcl/C funct: find_annot_borders
-------------------------------------------


The unlabeled tickbox to left of "label:" has six
different functions that affect how labels are
displayed.  This much-too-overloaded tixbox also
pops up a more convenient control panel on a
R-click help.

-------------------------------------------
toggle variable (left-click):
  $labelflag -- toggle displayed label visibility
-------------------------------------------

When $labelflag is 1 (checkbutton to left of
"label:" is selected), any labels that have been
displayed with "D" on the "label:" line, will be
shown as a transparent overlay on top of
curvature or other vertexwise data (if any).
This allows blinking between label(s) and
curvature and/or data.  Use "tran" at upper left
to control displayed label transparency
(opaque=255).

N.B.: displaying a label with "D" ignores any
overlay data values in the label.

-------------------------------------------
toggle variable (middle-click):
  $vtxcolflag -- toggle vtxcol visibility
-------------------------------------------

A non-default middle-click on this checkbutton
toggles $vtxcolflag, and thus visiblity of
vertex-color labels.  Vertex-color labels are
vertex-wise 'paint' with fixed colors (not
sensitive to color scale parameters), which can
be created from any label data.

These can be used to assemble activation patterns
from different experiments (e.g., visual areas
and somatosensory areas).

These colors are read in using middle-click on
the "label:" "R" button.  If $vtxcolflag is set
by a middle-click, they non-destructively
re-color/occlude the existing color of data
vertices.

The state of $labelflag (and the checkbutton
check) is unaffected by this middle-click.

-------------------------------------------
toggle variable (shift-middle-click):
  $annotbordflag -- toggle MGH border visibility
-------------------------------------------

A different non-default *shift*-middle-click on
this checkbutton toggles $annotbordflag, which
determines whether MGH annotation labels, or
standard displayed single labels, are shown
completely, or just at their borders.

This flag also effects the operation of the
functions that use displayed labels/annotations to
dump currently loaded .val's (surface data)
to another label:

for regular single labels:

  shift-middle-click "label:" line "W":
    =>  write_val_annoted_vertices

for MGH annotations:

  shift-left-click "label:" line "W":
    =>  write_val_annotedcol_vertices <r> <g> <b>

  shift-ctrl-left-click "label:" line "W":
    =>  write_val_annotedcols_vertices

The state of $labelflag (and the checkbutton
check) is unaffected by this middle-click.

-------------------------------------------
toggle variable (no shortcut):
  $areanamesflag -- visibility of annot area names
-------------------------------------------
[only appears if g++ compile]

Toggle visibility of brain region names for
any loaded MGH annotation (default OFF=0).

This requires that an MGH annotation has been
loaded.  If none loaded, first do:

  (1) select .annot from dropdown 
  (2) load with "D" button on "label:" line

The label names are centered on the vertex in
each annotation region that is closest to the 3D
average of the vertices in each region.  This 3D
average is calculated (by read_mgh_annot) on
whatever surface (folded, inflated, flattened)
that the annotation has been read onto (if
surface interactively changed, re-read annotation
to re-calc).

See next for manual control of fontsize.

-------------------------------------------
variable: $fontsize (popup) -- area names font size
-------------------------------------------
[only appears if g++ compile]

The fontsize is autoscaled along with brain by
the SCALE slider.

It is also scaled by the size of the GLX/OpenGL
display window (lower left "winxy:" entry).

Finally, it can be manually fine-tuned by using
$fontsize (default 9, for roughly 9 point at
initial startup).

-------------------------------------------
variable: $dthreshfact (popup) -- hack: adj label occlusion
-------------------------------------------

This is a hack to adjust the depth test threshold
for removing areanames that should be occluded.
The default is 1.0.  Turning it up (e.g., to
50.0) makes the occlusion test more permissive
(more possibly occluded labels will be visible),
while turning it down (<1.0) makes it more
restrictive (labels more likely to be removed).

In more detail, removing labels that should be
occluded works like this:

1) dot product of 3rd column of model view matrix
     with vertex normal to find if label location
     is facing away from viewer (but this leaves
     labels at vertices that face the viewer but
     are occluded by other parts of brain)
2) project vertex into image space using model
     view matrix, projection matrix, and viewport
     size
3) find vertex's depth in the image space
4) draw a transparent dot at that vtx location
5) use glReadPixels to find the depth of the
     final pixel drawn at that location
6) if the pixel is nearer to viewer, the dot was
     occluded by something else (add threshold to
     comparison - what $dthreshfact adjusts)
7) but (6) can still fail from depths being
     similar/noisy, causing flashing w/gradual
     pose change
8) modulate label brighness by dot product from
     (1) for depth cue, but also so flashy labels
     at the edges less apparent :-}

-------------------------------------------
toggle variable (no shortcut, tcl-only):
  $newreadfulllabflag -- toggle new read shows full labels
-------------------------------------------

If ticked, this causes subsequently read-in
labels to be displayed in full (by unticking
$annotbordflag upon reading a new label).  This
doesn't disable $annotbordflag, which still works
as expected.

The reason for this flag is that sometimes you
always want just borders, for example, when
looking at relationship between labels and
activations).  In other cases, you always want
full labels, for example, when cutting, viewing,
and editing labels.

-------------------------------------------
toggle variable (shift-right-click):
  $annotmaskflag -- toggle MGH masking-by-idnum(s)
-------------------------------------------

A different non-default *shift*-right-click on
this checkbutton toggles $annotmaskflag, which
determines whether MGH annotation labels will
be used to mask parts of the overlay.

The tcl/C functions controlling which annotation
regions are optionally masked are:

  set_idnum_visibility <idnum> <0=masked,1=visible>
  set_idnums_visibility <0=allmasked,1=allvisible>

Run these from popup at: shift-right-click-"D"

Masking by annot idnum(s) occurs whether or not
annotation label is visible.

-------------------------------------------
toggle variable (shift-left-click):
  $padlabelvtxsflag -- toggle show neigh of each label vtx
-------------------------------------------

Another non-default shift-left-click on this
checkbutton toggles $padlabelvtxflag.  When
ticked, when the *next* label is displayed, the
neighbors of each vertex will also be labeled.

This is designed to make labels consisting of
single vertices more visible.  There is always a
warning whenever a new label is read with this
ticked.

-------------------------------------------
toggle variable (ctrl-shift-middle-click):
  $annotborddotflag -- toggle white dots at borders
-------------------------------------------

Another non-default *control*-shift-middle-click
on this checkbutton toggles $annotborddotflag,
which determines whether dots are drawn at the
borders of currently loaded labels or an MGH
annotation (usu. turn off $annotbordflag when
using this).

The one-pixel dots may appear too prominent when
rendered at the standard 600x600 pixel window
resolution.  One way to to decrease relative
prominence of the dots is to increase the size of
the rendering window with "winxy:" at the lower
right.  Another way is to use the prune_annotbord
function (see next).

A right-click help on the tickbox at the far left
of the "label:" line brings up a pop-up with
controls for dotsize and color (mesh color
controls re-used here).

-------------------------------------------
variable: $pointsize -- for middle-click MESH button
-------------------------------------------

Sets the point size of vertex points (toggle on
with a middle-click on MESH).  This is mainly
useful for displaying sparse labels that don't
have enough vertices to be displayed as faces (at
re-cut time).  An example is when a uniq vtx
label is re-cut by a ctrl-left-click "C" on the
"label:" line.

-------------------------------------------
variable: $meshr (popup) -- area names font size
-------------------------------------------
variable: $meshg (popup) -- area names font size
-------------------------------------------
variable: $meshb (popup) -- area names font size
-------------------------------------------

These are copies of the entries to the right of
the upper left MESH button.  These rgb values
have multiple uses.

In addition to controlling the mesh (polygon
edges) color, they also control points color,
annot border dots color, isocontours
(spherical coordinates) color.

They also report color of clicked MGH annotation,
and can be set to extract .val(.val2) underlying
a particular annotation region color.

-------------------------------------------
Ctrl-Shift-Right-click (tcl/C funct: prune_annotbord)
-------------------------------------------

Another non-default control-shift-left-click on
this checkbutton prunes the density of displayed
annotation border dots using the tcl/C function,
prune_annotbord().

This works by eliminating dots with all or
all-minus-one neighbors already displaying a dot.

N.B.: to restore full borders, simply re-read the
annotation.

-------------------------------------------
tcl/C funct: find_annot_borders
-------------------------------------------

Another way to restore the original density of
border dots, is to run the tcl function,
find_annot_borders.  This can be accessed from
the "RESTORE ANNOT ODTS" button at the bottom of
the labeltick pop-up.

####################
label_label
####################

-------------------------------------------
tcl function: sampclustctrls
-------------------------------------------
keyboard equivalent: none

Do a default left-click on this text label
("label:") to obtain a popup for setting
parameters that control the process of sampling
3D data to the surface (the PAINT process), for
example, during the extraction of 3D timecourses,
stats, or a voxels-intersected mask.

The sampling process works as follows.  Starting
at each surface vertex x,y,z position, one or
more samples of an aligned 3D data set (rawdata
timecourse, statistic, anatomical dataset) is
sampled.

The single 4x4 matrix in register.dat multiplies
the x,y,z,1 surface vertex vector (linear
transformation) to obtain the x,y,z,1 coordinates
of the 3D data pixel that the surface point lies
within.

The process may be repeated at multiple vertical
offsets (positive or negative) along the surface
normal (vertical sample spacing controlled by
$normddstep), and there may be an operation
afterward on the samples (e.g., max), or all the
depths may be reported.

Since the surface mesh is typically smaller than
the data voxel grid, a given 3D data voxel will
typically by sampled by more than one surface
point (more than one surface point will lie
within it), even if only one sample is taken per
vertex.  There will be even more redundant (i.e.,
weighted) sampling if a depth search is used.

To generate output files that contain uniq 3D
data voxels, use $normdsampuniqvoxflag.  This
will only report the first surface vtx that has
"claimed" a 3D data voxel.  If, in addition,
$normdsampuniqvtxflag is ticked, the *vertex*
that "claims" a voxel will be the one closest to
the average of all vertices sampling the same
voxel.

If $normdsampallflag is also set,
$normdsampuniqvoxflag will be overriden.

The controllable parameters are:

 normdsampsearchflag -- do depth search along norm
 normdsampuniqvoxflag -- only report uniq 3D vox
 normdsampuniqvtxflag -- represent. vtx for uniq 3Dvox
 normdsamplallflag -- report at every search depth

 normdfracflag -- ON=depthfraction, OFF=mm
 bokflag -- experimental Bok sampledepth correction

 normdsamp -- single or minimum sample depth (mm)
 normdmax -- maximum sample depth (mm)

 normdfracsamp -- single or min sampledepth fraction
 normdfracmax -- maximum sampledepth fraction

 normddstep -- mm or fraction to move each new sample
 normdop -- operation on samples (0=max,1=avg,2=min)
   N.B.: only affect tksurfer "PAINT" button

 preclustfthr -- hard stat threshold before surfclust
 clustarea -- min cluster size for cluster filter mm^2

 sulfrac -- Bok parm
 gyrfrac -- Bok parm

For more details on each variable, R-click the
variable tickbox or entry on the popup.

####################
label
####################

-------------------------------------------
entry variable: $label -- absolute name labelfile
def: $SUBJECTS_DIR/$name/label/$hemi-MY_AREA.label
-------------------------------------------
entry variable: $anlabel -- abs name annotation file
def: $SUBJECTS_DIR/$name/label/$hemi.aparc.annot
[dropdown also loads: *.poi, *.obj]
-------------------------------------------

The "label:" entry shows the current label file,
which could be any one the the following:

  single-area freesurfer label   (*.label, ASCII)
  multi-label MGH annotation  (*.annot, MSB binary)
  multi-label GIFTI annotation  (*.gii, ASCII)
  BV patches-of-interest file    (*.poi, ASCII)
  Wavefront surf+col as annot (*.obj, ASCII)
  vertex color file                   (*.cols, ASCII)

No file is loaded at startup.  The dropdown will
contain files in the "label" subdirectory ending
in any of those suffixes.

Two pairs of useful annotation files for the RH
and LH fsaverage surfaces are included in this
distribution:

 {rh,lh}-CsurfMaps1.annot
 {rh,lh}.HCP-MMP1.annot

They are found here:

 $CSURF_DIR/subjects/fsaverage-ADDITIONS

and can be copied into the label subdirectory of
FreeSurfer subject, fsaverage.  Run the
annot2roi.tcl script to sample them to an
individual subject.

To load a label or MGH annotation (or other
format annotation: GIFTI *.gii, or BV *.poi, or
Wavefront *.obj), select one from the "label:"
dropdown.  To display the location of the label
or MGH annotation as a transparent overlay, use
"D".  Many other actions using a label or an
annotation file are possible.

The R-click help for each "label:" line button
make a second left popup containing verbosely
labeled buttons for all the alternate clicks on
each main button (an immediate <Return> will
close the help panel).

See also *shift*-R-click help for this entry for
a summary of actions using an MGH annotation
(the current file is plain R-click help :-} ).

Relative label name assumes same dir as above.
Home dir of subject can be abbreviated as tilde
(~) and session dir (usu. includes "image") as an
asterisk (*).  Absolute name OK, too.  When
making labels files, replace <id> with an
informative infix.  To distinguish csurf label
files from MGH label files (interchangeable
except that MGH label files cannot contain
complex values), a dash is used after $hemi
instead of a period.

The "label:" dropdown is loaded with any file
ending in *.label, *.annot, *.poi (or *.obj).

Label files (and multi-label annotation files)
can be used/read in (at least) 7 distinct ways:

(1) To color (mark) surface vertices of labeled
    region w/single transparent color.  Use "D"
    (display) button, or from script, use tcl
    function, read_label_to_annot_using_col $r $g
    $b.  Ignores vertex data in label.  The "D"
    button can also be used to display MGH
    annotation files (double-mid-click to pop up
    annot region name/color after display).

(2) To recut a label, a hole, or add to a cut
    label (clearing the .val(.val2) field(s)).
    Use "C" (cut) button, or from a script with
    function, read_label_cut_clearvals <0,1,2>

(3) To read the *data* in the label file into the
    .val(.val2) field(s).  Done with "R" button,
    or from script with function, read_label_to_val.
    If all vertices need to be cleared first, use
    CLR button on "val:" line, else any existing
    .val(.val2)'s will remain.  Not clearing can
    be useful for masking operations or assembling
    activations.

(4) To write the data from the .val(.val2)
    field(s) from a selected portion of the
    surface into a file ("W" button).

(5) To constrain the range of another operation
    such as sampling 3D data or timecourses using
    the label, constraining a searchlight or
    retinotopic border run (done with "T", "S",
    "X" buttons), or providing a border for
    a FILL or ROI operation

(6) To convert a label, annotation region, or all
    or annotations to a 3D AFNI ROI(s) (also "D"
    button)

(7) To assemble a group of labels, together
    with a FreeSurfer LUT file, into an MGH
    annotation file (also the "W" button)


FreeSurfer ASCII label file (*.label)

A standard single-label ASCII file can contain
any valid vertex number, but is typically made by
flood-filling a connected patch created using
AREA (closed contour cut) or ROI (fill to
threshold).  With more than one seed
(left-click), AREA and ROI will combine
disconnected patches into one label.

The label file is an ASCII file with the
following format:

  The first line is a comment, typically:
  #!ascii , from subject <somebody>

  The second line contains a single number, which
  is the number of labeled vertices in the file.

  The third and following lines will each have 5
  or 6 numbers: the vertex number, the x,y,z
  coordinates of the vertex (from the $origcoords
  surface, typically $hemi.orig), the value of
  vertex[i].val, and optionally vertex[i].val2,
  if the complex-valued data has being displayed.
  The data field(s) will be 0.0 if a label is
  written when no overlay data has been loaded.

  -------------------------------------------
  Fragment of a real-valued label file:
  -------------------------------------------
  #!ascii , from subject martys09
  317
  26595 42.500 -61.500 -11.500 0.254000
  27575 44.500 -60.500 -9.500 -0.456067
  27599 44.500 -60.500 -10.500 0.948998
  27600 43.500 -60.500 -10.500 1.239467
  27614 45.500 -60.500 -11.500 -1.392878
  27615 44.500 -60.500 -11.500 0.000000
  ... [311 more lines]
  -------------------------------------------

To assign an RGB color to the labeled vertices
(first usage (1) above -- ignores data in file),
set the values of the r,g,b fields to the right
of the MESH button before reading the label file.
The color setting only affects the rendered color
of a subsequently read label file.


SamSrf (pRF) data labels

Labels written by the SamSrf toolbox for pRF
mapping that is available at:

  http://figshare.com/articles/
    SamSrf_toolbox_for_pRF_mapping/1344765

are typically saved in a "prf" subdir of a
subject.  They have the same ASCII format as the
real-valued *.label files above.  These are
loaded as a group at the bottom of the "label:"
dropdown.  These have an underscore (e.g., 'rh_')
after the hemisphere (instead of a 'rh.' for an
MGH label, and a 'rh-' for a csurf label).  If
the label is part of a complex-valued pair such
as:

 ~/prf/rh_pRF_sf_pol_r.label
 ~/prf/rh_pRF_sf_pol_i.label
           or
 ~/prf/lh_pRF_sf_ecc_r.label
 ~/prf/lh_pRF_sf_ecc_i.label

reading the data from either one of these files
using "R" will automatically load the other file
from the complex-valued pair, and then auto-reset
the color scale setting appropriately as follows:

SamSrf (both ecc and pol):
  set complexvalflag 1
  set colscale 0
  set fthresh 0.0
  set fmid 0.025
  set fslope 100.0

SamSrf (ecc only):
  set angle_cycles 1.0
  set angle_offset 0.0

SamSrf (pol only):
  set angle_cycles 2.001
  set angle_offset 0.5   ;# N.B.: both hemi's same
  set revphaseflag 1

Note that csurf labels ('rh-' prefix), by
contrast, typically store real and imaginary
values in a single label file (6 entries per line
instead of 5).


MGH annotation file (*.annot, vtx cols + LUT)

Binary (MSB first) MGH .annot files contain a
color for every vertex followed by a look up
table that maps cortical area names to unique
colors.  The definition of the "new format"
annotation file follows:

  ------------ header 1 ---------------------
   4-byte int: surface vertex count
  ------------ vtx cols ---------------------
   4-byte int: vtxnum
   4-byte int: packed color (ABGR)
   ... [pairs for every surface vertex]
  ------------ header 2 ---------------------
   4-byte int: tag (=1)
   4-byte int: version (-2 = vers2)
   4-byte int: largest ID number of any area
   4-byte int: length of LUT filename
   [length] bytes ending with \0: orig LUT filename
   4-byte int: color LUT entries
  ------------ LUT entries ------------------
   4-byte int: area ID number
   4-byte int: length of region name
   [length] bytes ending with \0: region name
   4-byte int: red
   4-byte int: green
   4-byte int: blue
   4-byte int: transparency
   ... [7-tuples for every cortical area]
  -------------------------------------------

The slightly different "old format" is also
readable/auto-detected.

N.B.: mris_convert and freeview crash/can't read
annotation files containing:

  (1) 'holes' in the list of region ID numbers
  (2) actual largest ID number (must be +1)

so tksurfer write_mgh_annot re-numbers the output
and increments the max ID num field.

The MGH annot files can be displayed with the "D"
button (auto selects function read_mgh_annot if
input file suffix is .annot).  They can also be
used to extract current surface data as follows:

  1) load vertex data of interest to .val(.val2)
  2) load MGH annot with left-click "D"
  3) click one colored label to use (loads color)
  4) set name in "label:" entry for output file
  5) Shift-middle-click-"W" (see below)

When an MGH annot file is displayed, clicking a
vertex reports the current annotation color in
the r,g,b entries to the right of the MESH
button, and the corresponding brain structure
found in the embedded color LUT in the csurf log
(double-middle-click vertex to get a pop-up).

The data for every region in an MGH annot file
can be dumped to separate label files with a
shift-left-click on the "W" button.

A selected subset of annotation region labels can
be (1) displayed or, (2) used to mask overlay
data, using a shift-right-click on the "D"
button, which makes popups to pick a subset of
annotation regions by idnum (all other regions
(1) or overlay data (2) are masked).  In case
(2), the data can be dumped to individual label
files.

An MGH annot file can be constructed from a
FreeSurfer LUT file and a series of individual
labels with ctrl-middle-click on the "W" button.

An MGH .annot file from fsaverage can be
resampled to an individual subject to make a
subject-specific .annot file, and optionally
converted to 3D AFNI BRIK ROIs by using the
standard tcl script, annot2roi.tcl, which is
available from the "tcl:" dropdown.

The vertex-wise percent overlap between currently
loaded vertex values (.val) that are non-zero and
each region in an MGH .annot file can be
calculated (ctrl-shift-right-click on the "D"
button).

Finally, an MGH .annot file can be viewed as a
colored cortical ribbon on a 2D slice in tkmedit
bu using the SURFPAINT panel in the F4 interface
of tkmedit.


GIFTI annotation file (*.gii)

A GIFTI xml annotation file (as generated from an
MGH annotation file by FreeSurfer) contain a
FreeSurfer color table that maps region names
(and sequential, zero-based region id numbers) to
unique r,g,b colors, followed by a list of region
id numbers for each vertex.

The color table contains floating point r,g,b
colors in the range 0-1 (N.B.: can result in
overlapping unsigned char [0-255] colors if not
converted from them).

The subsequent list of region id numbers must
match the total number of vertices in the
surface.

The expected format looks like this:

  -------------------------------------------
  <?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE GIFTI SYSTEM "http://gifti.projects.nitrc.org/gifti.dtd">
  <GIFTI Version="1.0"  NumberOfDataArrays="1">
     <MetaData>
       ...
     </MetaData>
     <LabelTable>
        <Label Key="0" Red="0" Green="0" Blue="0" Alpha="0"><![CDATA[Unknown]]></Label>
        <Label Key="1" Red="0.392157" Green="0" Blue="0.745098" Alpha="1"><![CDATA[V1_lower]]></Label>
        <Label Key="2" Red="0.392157" Green="0" Blue="0.784314" Alpha="1"><![CDATA[V1_upper]]></Label>
        ...
        <Label Key="102" Red="0.294118" Green="0.666667" Blue="0.27451" Alpha="1"><![CDATA[SMA2]]></Label>
     </LabelTable>
     <DataArray Intent="NIFTI_INTENT_LABEL"
                DataType="NIFTI_TYPE_INT32"
                ArrayIndexingOrder="RowMajorOrder"
                Dimensionality="1"
                Dim0="163842"
                Encoding="GZipBase64Binary"
                Endian="LittleEndian"
                ExternalFileName=""
                ExternalFileOffset="">
        <MetaData>
           <MD>
              <Name><![CDATA[Name]]></Name>
              <Value><![CDATA[node label]]></Value>
           </MD>
        </MetaData>
        <Data>eJztnXm3FEXy93N ... </Data>
     </DataArray>
  </GIFTI>
  -------------------------------------------


BV patches-of-interest (*.poi) file (label group + LUT)

These Brain Voyager files are functionally
similar to MGH annotation files (label group +
LUT) and should be able to be used in similar
ways.  The expected file format looks like this:

  -------------------------------------------
   FileVersion:      2
   FromMeshFile:     "<none>"
   NrOfMeshVertices: 163842
   NrOfPOIs:         8

   NameOfPOI:        "Te10"
   InfoTextFile:     "<none>"
   ColorOfPOI:       227 26 28
   LabelVertex:      0
   NrOfVertices:     468
   52656
   52657
   ... [vtxnums for every vtx in this patch]

   NameOfPOI:        "Te11"
   InfoTextFile:     "<none>"
   ColorOfPOI:       253 191 111
   LabelVertex:      0
   NrOfVertices:     855
   43
   166
   ... [vtxnums for every vtx in this patch]

   ... [additional patches]
  -------------------------------------------


Wavefront ASCII OBJ surface+colors file

A Wavefront surface file containing vertexwise
colors can be read as if it was an annotation (a
set of patches-of-interest) by considering
vertices in each unique color to be a different
brain region (up to 5000 unique colors/regions
allowed, before bailing).  The expected format
looks like this (only reads r,g,b - surface
gemoetry ignored):

  -------------- header ---------------------
   # comment line (no req'd header)
   [vertex triples implicitly numbered]
   "v"  x  y  z  r  g  b
   "v"  x  y  z  r  g  b
   ... [x,y,z triples or sextuples up to vertex count]

   [normal triples implicitly num'd, norm maybe!=1]
   [N.B.: currently ignored here and recalc'd as usual]
   "vn"  x  y  z
   "vn"  x  y  z
   ... [x,y,z triples up to vertex count]

   [face triples implicitly num'd]
   [entries: vtx, vtx/tex, vtx//norm, vtx/tex/norm]
   [N.B.: vtx/tex/norm nums are 1-based!]
   [N.B.: ignores tex/norm nums]
   "f" vtx1 vtx2 vtx3
            *or*
   "f" vtx1/tex1 vtx2/tex2 vtx3/tex3
            *or*
   "f" vtx1//norm1 vtx2//norm2 vtx3//norm3
            *or*
   "f" vtx1/tex1/norm1 vtx2/tex2/norm2 vtx3/tex3/norm3
   ... [triples up to face count]
  -------------------------------------------


Vertex color file (*.cols)

A vertex color file contains RGB colors for some
or all vertices (before modifications of vertex
color by lighting calculations).

This is fixed "paint" which ignores all color
scale settings for data.  It also occludes any
currently displayed data.

This allows combining data that has been rendered
with *different* color scales on the *same*
surface (e.g., visual and auditory data).  The
expected format is:

  #!ascii
  <vertices-in-file>
  <vtx> <r:0-1> <g:0-1> <b:0-1> 
  ...

Here is a fragment of such a file:

  -------------------------------------------
  #!ascii , from subject fsaverage
  10287
  509     0.000   0.522   0.960
  510     0.072   0.000   1.000
  519     0.868   0.019   0.576
  520     0.996   0.001   0.504
  ...
  -------------------------------------------

Use the "label:" line "R" button (middle-click-R)
to read such a file and the "CLR" button
(middle-click-CLR) to clear all such colors.  Use
the "D" button (ctrl-right-click-D) to copy the
current vertex colors (data as rendered by color
scale settings) to vertex colors.  Use the "W"
button (ctrl-righl-click-W) to write them out to
a *.cols file (all visible vertex, so cut first
to get smaller patch).


Label Buttons (D, C, CLR, R, W, T, S, X)

A large number of different operations (now
almost 50) can be done with a label (or an MGH
annotation) using the buttons on the "label:"
line.  Here are the default (left-click)
functions of each of the buttons.

Each button has individual right-click help.
They can all be scripted (see tcl functs, or
click upper left "tcl:" to see tcl functs echoed
as they are executed).

 D -- display transparent label or MGH annotation
  (tclfunct: read_label_to_annot_using_col <r> <g> <b>)
  (tclfunct: read_mgh_annot => all regions MGH .annot file)
  (tclfunct: read_poi_annot => all regions BV .poi file)

 C -- recut label without restoring prev cuts
    (tcl funct: read_label_cut_clearvals 0)

 CLR -- clear all displayed labels (and MGH annot LUT)
    (tcl funct: clear_annot)

 R -- read vtx data in label onto surface (maybe recut)
    (tcl funct: read_label_to_val 0,1)

 W -- write current surface val data to label file
    (tcl funct: write_val_visible_vertices)

 T -- use label to sample rawdata 3D timecourses to file
    (tcl funct: write_label_timecourses_stats <0=rawtime>)

 S -- like T but also get 3D stats
  (tcl funct: write_label_timecourses_stats <2=stat+rawtime)

 X -- run surface-based searchlight cross-corr over label
    (tcl funct: corr_over_label <neitype> <crit> <cmptype>)

Middle-clicks and left and middle clicks with
shift and/or control keys access alternate
conceptually related functions for each of these
buttons (also documented at top of R-click help
for each button):

-------------------------------------------
 left-D -- [def: display label or annotation]

 middle-D -- use label to undo cut
    (tcl funct: read_label_to_undo_cut)

 shift-left-D -- convert one MGH annot region to 3D-ROI
    (tcl funct: write_annotcol_timecourses_stats

 shift-middle-D -- convert label to 3D ROI
    (tcl funct: write_label_timecourses_stats <3=ROI>)

 shift-right-D -- pick annot idnums to view/mask
    (tcl funct: set_idnums_visiblity <0,1>)
    (tcl funct: set_idnum_visiblity <idnum< <0,1>)

 ctrl-shift-left-D -- convert all MGH annots to 3D ROIs
    (tcl funct: write_annotcols_timecourses_stats <3=ROI>)

 ctrl-middle-D -- count neighbor annot areas -> stat, print
    (tcl funct: areaneigh2stat)

 ctrl-left-click-D: select vertices in label (as if clicked)
    (tcl funct: read_label_to_select)

 ctrl-right-click-D: annots overlap w/non-0 .val
    (tcl funct: calc_annots_nzval_overlap)

 ctrl-right-click-D: copy curr col to vtxcol
    (tcl funct: currcol_to_vtxcol)

-------------------------------------------
 left-C -- [def: re-cut label]

 middle-C -- cut a hole using label
    (tcl funct: read_label_cut_clearvals <1=hole>)

 shift-middle-C -- add label to existing cut label
    (tcl funct: read_label_cut_clearvals <2=add>)

 ctrl-left-C -- re-cut existing displayed labels
    (tcl functs: labeled_cut_clearvals <0=label>)

 ctrl-middle-C -- cut hole using existing labels
    (tcl functs: labeled_cut_clearvals <1=hole>)

 ctrl-shift-left-C -- re-cut w/uniq vtx's
    (tcl funct: read_uniqsamp_vertices)
    (tcl funct: read_label_cut_clearvals 0)

-------------------------------------------
 left-CLR -- [def: clear labels/annots]

 middle-CLR -- clear vertex col label "paint"
    (tcl funct: clear_vtxcol_labels)

 ctrl-left-CLR -- use label to clear labels/annot
    (tcl funct: read_label_to_clear_annot)

 ctrl-middle-CLR -- clear one color of annot
    (tcl funct: clear_annot_with_col <r> <g> <b>)

-------------------------------------------
 left-R -- [def: read vals in label to .val]

 middle-R -- read vertex col label onto surface
    (tcl funct: read_vtxcol_label)

 shift-middle-R -- real val and recut label
    (tcl funct: read_label_to_val <1=cutlabelflag>)

 ctrl-left-R -- read uniq samp vertices label
    (tcl funct: read_uniqsamp_vertices)

-------------------------------------------
 left-W -- [def: write vals at currently visible vtxs]

 middle-W -- conv label to vertex color label
    (tcl funct: label_to_vtxcol_label)

 shift-middle-W -- write val data from annotated vtxs
    (tcl funct: write_val_annoted_vertices)
      => use label to get current val data

 shift-left-W -- write val data from 1 MGH annot area
    (tcl funct: write_val_annotedcol_vertices <r> <g> <b>)
      => first click an annot area to load color
      => gets current val data for one MGH annot label

 shift-ctrl-left-W -- write val data from all MGH annots
    (tcl funct: write_val_annotedcols_vertices)

 ctrl-left-W -- write curr set clicked vtxs to label
    (tcl funct: write_val_selected_list_to_label)

 ctrl-middle-W -- assemble MGH annot using MGH LUT file
    (tcl funct: write_mgh_annot)

 shift-ctrl-middle-W -- write concat searchlights to ASCII
    (tcl funct: write_searchlights <fillneartype> <criterion>)

 shift-ctrl-right-W -- extract label from annotation (autoname)
    (tcl funct:  write_val_annotedcol_autoname <r> <g> <b>

 ctrl-right-click-W: curr vtxcols to vtxcol label 
    (tcl funct: write_vtxcol_label)

 shift-right-click-W: write adjusted phase
    (tcl funct: write_adjphase_vertices)

-------------------------------------------
 left-T -- [def: write rawdata at label]

 shift-left-T -- rawdata at label + percent (Fourier) resp
    (tcl funct: write_label_timecourses_stats <4=time+percnt>)

 middle-T -- rawdata from one MGH annotation region
    (tcl funct: write_annotcol_timecourses_stats
                               <r> <g> <b> <0=rawtime>)

 shift-middle-T -- rawdata from every MGH annot region
    (tclfunc: write_annotcols_timecourses_stats <0=rawtime>)

-------------------------------------------
 left-S -- [def: write 3D write stat+raw at label]

 middle-S -- write 3D stats+raw for MGH annot region
    (tcl funct: write_annotcol_timecourses_stats
                                <r> <g> <b> <2=stat+rawtime>)

 shift-middle-S -- get stats+rawdata all MGH annot regions
    (tcl funct:  write_annotcols_timecourses_stats
                            <2=stat+rawtime>

 ctrl-left-S -- get just stats for label
    (tcl funct: write_label_timecourses_stats <1=st>

 ctrl-middle-S -- get stats for MGH annot region
    (tcl funct: write_annotcol_timecourses_stats
                                   <r> <g> <b> <1=statonly>)

 shift-ctrl-middle-S -- get stats for all MGH annot regions
    (tcl funct: write_annotcols_timecourses_stats <1=statonly>)

-------------------------------------------
 left-X -- [def: searchlight cross-corr over label]

 middle-X -- searchlight cross-corr on 1 MGH annot region
    (tcl funct: corr_over_annotcol 
                       <neitype> <crit> <cmptype> <r> <g> <b>)

-------------------------------------------

Convert data label to vertex-color label

The rendered color of a the vertex data of a
label (as controlled by any color scale, any
panel settings) can be converted to a
vertex-color label (suffix: *.cols).  This kind
of label contains vertex colors rather than data,
but can be read onto a surface already displaying
other data.  Note that it ignores color scale
settings.

This allows combining data that has been rendered
with *different* color scales on the *same*
surface.  With ordinary *data* labels, if two
more more are read onto a surface, they all have
to use the same color scale (mapping between data
values and colors).

Here is a recipe for doing this:

  (1) define a label using cuts and/or ROIs
  (2) write label using "label:" "W"
        (default left-click)
  (3) adj color scale settings to desired
  (4) convert current rendering of label data
        to vertex-color label (auto output name)
        (middle-click on "label:" "W")
  (5) display or read data label for underlay
  (6) read vertex color label onto surface
        (middle-click on "label:" "R")
        (auto input name from data label name)

Fill Holes in Label or Label Data

The SMOOTH button can run two different
hole-filling functions if the following text is
typed into the entry (instead of a number):

   labelholes -> fill holes in D'd label
   valholes   -> fill holes in R'd label *data*

These hole filling operations only affect
unlabeled vertices.  Any vertex with data is
considered fixed.

Make a single-vertex-wide line label (traverse an area)

  (1) turn on MESH
  (2) zoom until individual vertices visible
  (3) right-click to clear all prev selections
  (4) left-click a line of vertices
  (5) ctrl-left-click "W" (write selected list to label)

Note that when single-vertex 'line labels' (or
line labels generated by geodesic traverses using
the "Dijk" button) are re-displayed, they will
appear to be 3 vertices thick even though they
are actually 1 vertex thick.  This is because a
label is displayed by coloring *faces*, and any
face that has a vertex in the label will be
colored.  Faces on the boundary of the label will
have one or two vertices assigned background gray
color (darker of two grays = concave), so these
faces will merge into dark gray.  For more
details, see R-click help for ROI button.

Tips for label editing

The label drawing facilities are powerful but not
extremely user friendly.  Here are some tips on
how to refine a label after an initial attempt:

  Erode (rm rim of single vertices):
    click in label
    left-click "er", FILL

  Dilate (add rim of single vertices):
    click in label
    middle-click "er", FILL

  Touch up edges:
    select points -> trim: left-click-PTS
    select points -> add: middle-click-PTS

  Trim label using another label
    load target label
    select trim label
    middle-click "C" (cut away)

  Eliminate dangling edges (see with MESH)
    FILL or left-click + PTS

  Eliminate stray single vtxs (see w/mid-clk MESH)
    FILL or left-click + PTS

  Make label adjoining another label:
    "D" first label
    cut line new label start/end in displayed
    FILL (respects displayed labels)

  Add chunk to a label:
    display orig label
    cut line around chunk to add
    FILL (just the chunk)
    select original label again from dropdown
    shift-middle-click "C" to add it back to chunk

  Dilate label to meet existing label(s)
    display labels you want to respect
    re-cut the label you want to grow (only it visible)
    middle-click "er" (=dilate)
    repeat FILL (grows to invis. prev disp'd labels

  Quick re-view of a current set of labels:
    make tcl script in scriptsdir starting with:
      set labelflag 1
      set labelalpha 255
      clear_annot
    followed by pairs of lines like:
      ...
      ...
      setfile label ~/label/$hemi-MT.label
      read_label_to_annot_using_col 250 0 0
      ...
      ...
    INIT (show everything)
    run script with GO on "tcl:" line

  Hint: it is very easy to accidentally
    type something like "rh-V2_upper.label" on
    saving a finely crafted label that is on the
    *superior* occipital pole that is actually
    *lower* field V2 :-}

  For adjoining labels, sketch before cutting!
    click along intended bounadaries
    save selected as tmp label (ctrl-L-clk "W" labelline)
    display tmp label with label line "D" to guide cut
    cut/CLR/FILL first label, save, INIT, load
    redisplay tmp label sketch
    cut/CLR/FILL second label up to first, save, INIT, load
    ... (CLR so FILL doesn't avoid tmp label)

  Adjust border between two completely surrounded labels
    clear to-be-shrunken label (ctrl-left-CLR)
    cut line across cleared label
    FILL up to the other label
    ADD (shift-middle-C) other label to filled

  Make colored border line around a set of areas
    make labels for set of areas
    make color LUT for those areas
    assemble annotation (write_mgh_annot), load it
    turn on eroding fill
    FILL up to areas to make surface mask w/holes
    FILL mask 3x to enlarge holes
    mid-clk-C cut hole in orig mask w/3x erode (largest-hole)
    save border label
    tcl cmd: read_label_to_setvalval2 <real=2.0> <imag=0.0>
    make val2rgblut: 2.0 <r> <g> <b>
    R label to display val, mid-clk "W" to conv to vtxcol label


####################
annot
####################

-------------------------------------------
USING MGH ANNOTATION FILES (*.annot)
-------------------------------------------
Summary of main operations that can be quickly
performed using an MGH annotation (multi-label)
file (e.g., $hemi-CsurfMaps1.annot or
$hemi-HCP-MMP1.annot) or a Brain Voyager
patches-of-interest file (*.poi).  This is the
*shift*-right click help :-}


-------------------------------------------
Display fsaverage or indiv-subject MGH annotation file
-------------------------------------------

  select *.annot from "label:" dropdown
  "D" (display)
  -----
  adjust label transparency with "tran"
  shift-middle-click tick left of "label:" => toggle borders
  ctrl-shift-middle-click tick => white dots as borders
  ctrl-shift-right-click tick => prune white dots
  double-middle-click region => col/idnum/name popup

-------------------------------------------
Display subset of areas in MGH annotation file
-------------------------------------------

  select *.annot from "label:" dropdown
  "D" (display)
  -----
  shift-R-click D    [pop-up: idnums/names/cols]
  type in space-separated list idnums to show
  READY
  type "all" to restore all

-------------------------------------------
Resample an fsaverage annot to an indiv subject
-------------------------------------------

This is for fsaverage annotations that have not
already been resampled by standard freesurfer
recon-all (e.g., Van Essen parcellation,
$hemi.HCP-MMP1.annot, in directory,
$CSURF_DIR/fsaverage-ADDITIONS/label):

  open indiv subject
  select "annot2roi.tcl" from "tcl:" dropdown
  GO
  select fsaverage .annot from "annot:" dropdown on popup
  RUN SCRIPT   (uses mri_surf2surf)

-------------------------------------------
Dump out surface data for single annotation area:
-------------------------------------------

  load some data into indiv subject or fsaverage
  load annotation file
  click in one area
  shift-middle-click-W on "label:" line

-------------------------------------------
Dump out surface data for *all* annotation areas:
-------------------------------------------

  load some data into subject
  load annotation file
  shift-left-click-W on "label:" line

-------------------------------------------
Construct fsaverage annotation file from set of labels:
-------------------------------------------

  make a bunch of labels in fsaverage named like this:
     $SUBJECTS_DIR/fsaverage/label/rh-V1_upper.label
  follow label-making hints bottom of R-click "label:" help
  make ASCII FreeSurfer LUT file referencing label infixes
    => N.B.: choose unique colors and id numbers
#----------- cut here -----------------------------------
#!ascii , CsurfColorLUT.txt (in $CSURF_DIR/lib/lut)
#--------------------------------------------------------
#id  region		R	G	B	A
#--------------------------------------------------------
0    Unknown		0	0	0	0
1    V1_lower		150	0	10	0
2    V1_upper		150	0	120	0
4    V3_lower		0	50	200	0
. . . [etc]
#----------- cut here -----------------------------------
  ctrl-middle-click-W on "label:" line
  enter name of your LUT file in pop-up

-------------------------------------------
Display all annotation region(s) on 2D slice
-------------------------------------------

  open fsaverage or indiv-sub in *tkmedit* (VOLUME)
  F4 to get big tkmedit panel
  select annot file from "annot:" dropdown
  click R (read)
    => "line:" entry controls thickness colored ribbon

-------------------------------------------
Display *one* annotation region(s) on 2D slice
-------------------------------------------

  also display annotation on surface (SURFACE)
  double-mid-click region for popup with region idnum
  ------------------
  open fsaverage or indiv-sub in tkmedit (VOLUME)
  F4 to get big tkmedit panel
  select annot file from "annot:" dropdown
  click R (read)
  type in idnum to tkmedit "an:" in SURFPAINT, <Return>
    => e.g., see where 3b (idnum=9) actually is in slices :-}
    => "line:" entry controls thickness colored ribbon

-------------------------------------------
Make indiv subj 3D AFNI ROIs from fsaverage annotation
-------------------------------------------

  open indiv subj functional in View Functional Data
  select "annot2roi.tcl" from  "tcl:" dropdown
  GO
  select fsaverage .annot from "annot:" dropdown on popup
  click to select tick: "Make_3D_AFNI_ROIs_flag"
  RUN SCRIPT (uses mri_surf2surf, tksurfer funct)
    => result is single-subject functional-resolution ROI for
            each surface region, plus, an all-in-one ROI file
    => can erode each region 1+ layers of vtxs before => 3D
    => can adjust normal search parameters before => 3D


####################
label_read
####################

#### display, uncut, conv=>3D a label/annot ####
-------------------------------------------
funct: "Display Label or Annot (left-click-D)"
  set label <infile>
  read_label_to_annot_using_col $r $g $b
  ------- or --------
  set anlabel <infile>
  read_mgh_annot
  read_poi_annot
  read_obj_to_annot
  read_gifti_to_annot
-------------------------------------------
funct: "Undo Cut with Label (mid-click-D)"
  set label <infile>
  read_label_to_undo_cut
-------------------------------------------
funct: "Convert Label to 3D ROI (shift-mid-click-D)"
  set label <outfile>
  write_label_timecourses_stats 3
-------------------------------------------
funct: "Convert One Annot ID to 3D ROI (shift-left-click-D)"
  [3D-ROI outfile is auto-named]
  write_annotcol_timecourses_stats $r $g $b 3
-------------------------------------------
funct: "Pick Annot Idnums to View/Mask (shift-right-click-D)"
  set_idnums_visibility <0,1>
  set_idnum_visibility <idnum> <0,1>
  set_idnum_visibility <idnum> <0,1>
    [etc for all visible]
  set annotmaskflag 1
  redraw
  [write_val_unmasked_vertices]
-------------------------------------------
funct: "All Annots to 3D ROIs (ctrl-shift-left-click-D)"
  [3D-ROI outfiles are auto-named]
  write_annotcols_timecourses_stats 3
-------------------------------------------
funct: "Count/Print annot neighbors (ctrl-mid-click-D)"
  areaneigh2stat
-------------------------------------------
funct: "Read Label to Select (ctrl-left-click-D)"
  set label <infile>
  read_label_to_select
-------------------------------------------
funct: "Calc Overlap Annots w/Non-0 (ctrl-shift-right-clk-D)"
  calc_annots_nzval_overlap
-------------------------------------------
funct: "Copy Current Cols to Vtxcols (ctrl-right-clk-D)"
  currcol_to_vtxcol
-------------------------------------------
funct:"Copy Curr Lab/Annot to Vtxcols (ctrl-shift-mid-clk-D)"
  labelcol_to_vtxcol
-------------------------------------------
funct: "Display Label on Nearest Vertices (no hotkey)"
  read_label_to_nearest_annot_using_col
-------------------------------------------


Display Layering

There are 5 layers in the cortical surface
display separated by increments of 0.02 mm along
the vertex normal.

  [most superficial]
  --------------------
  cyan cursor (0.10 mm up)
  vertex points (0.08 mm up)
  face edge mesh (0.06 mm up
  labels/annot (0.04 mm up)
  data/curv,vtxcols (0.00 mm up)
  --------------------
  [deepest]

For data in the same layer, later reads occlude
earlier reads (except vertex colors, which are
always drawn after data/curv colors).

Detailed Description of Label "D" Button Actions

-------------------------------------------
funct: "Display Label or Annot (left-click-D)"
  set label <infile>
  read_label_to_annot_using_col $r $g $b
  -------------------
  set anlabel <infile>
  read_mgh_annot
  read_poi_annot
  read_obj_to_annot
  read_gifti_to_annot
-------------------------------------------

A default left-click on the "D" button
auto-detects (by suffix) and reads five different
kind of files available in the "label:" dropdown
into the annotation color field (.annot) of each
vertex -- (1) standard ASCII single-label files
(*.label), (2) binary MGH annotation files
(*.annot), (3) ASCII BV 'patches of interest"
(*.poi) files, (4) Wavefront ASCII surface+colors
files, and (5) GIFTI annotation files.

(1) ASCII Label file (.label suffix)

Left-clicking "D" reads the current file in the
label entry (tcl var: $label) and displays the
label as a colored overlay (N.B.: this ignores
both val's and coord's in the label file).

The area of the label is reported on the popup
after reading.  The "curr area" is the label area
calculated using the current surface.  The "orig
area" is the label area calculated using the
lh/rh.area file, which is generated during
initial surface reconstruction using the
lh/rh.white surface.

If you have used the fsaverage update script,
$CSURF_DIR/bin/noarch/update-fsaverage (highly
recommended!), then (just) for the average
subject, fsaverage, the "orig area" will be
calculated using the inflated_avg surface, which
is much less shrunken than the smoothwm/white
surfaces.  This is because surface-averaging
coordinates of folded surfaces smooths
idiosyncratic 'crinkles', selectively reducing
sulcal area in the average; surface-averaging
coordinates of individually inflated surfaces
avoids this distortion).

The default is to only show the boundary of the
label (so it doesn't occlude activations).  To
fill in the label, R-click the tickbox to the
left of "label:" and untick "annotbordflag".

The r,g,b values that the "D" button passes to
this function are taken from the current values
of the r,g,b entries to the right of the MESH
button (default 120,120,255=blue/purple).  To
change the label color, reset those values and
re-left-click "D".

The opacity of all labels is controlled by the
far upper left "tran" entry ($labelalpha).  The
default is 128 for partially transparent (0 is
invisible and 255 is opaque).

To use the label to extract surface vertex data
in the .val(.val2) fields, see "W" button R-click
help.  For example, shift-middle-clk-W writes out
a new label containing currently displayed
.val(.val2) data just from labeled vertices
(uses tcl funct: write_val_annoted_vertices).

Use the "label:" line "CLR" button to clear any
displayed labels (or annotations).  This does not
affect data in the .val(.val2) fields.

For the ASCII format of freesurfer *.label files,
see the R-click help for the "label:" line entry,
(also describes special case of SamSrf toolbox
labels saved in non-standard "prf" subdir of
subject).

To make labels consisting of a line of single
vertices more visible, set r/g/b (to right of
MESH) to 255/255/255, tick "padlabelvtxsflag" (on
R-click label tickbox popup), set "tran"
(transparency) to 255.  This also labels
neighbors of each vertex in label.

(2) MGH Annotation file (.annot suffix)

The "D" button can also read a binary MGH
annotation file, which typically contains a set
of differently colored labels, as a transparent
overlay.  In this case the "D" button also reads
the color LUT embedded in the annotation file,
which maps unique colors to brain region names
and numbers.  This uses the C/tcl function,
read_mgh_annot.

This also pops up a window with the the full
color table listing all label regions with the
following format:

#from: /usr0/subjects/fsaverage/label/rh-CsurfMaps1.annot
#---------------------------------------------------------
#id  name                              r   g   b    a
#---------------------------------------------------------
  0  Unknown                           0   0   0    0
  1  V1_lower                        100   0 190    0
  2  V1_upper                        100   0 200    0
  3  V2_lower                         60  20 240    0
    [etc]
#---------------------------------------------------------

This table is generated when an annotation is
read, and is saved as an ASCII file with the same
prefix as the annotation file, either here if
you started tksurfer with the SURFACE button:

  $SUBJECTS_DIR/$subject/scripts/<prefix>.ctab

or here (if the annotation is loaded after
starting tksurfer from a functional session using
the SURFACE-STATS button):

  $FUNCTIONALS_DIR/$session/image/scripts/<prefix>.ctab

In addition, another file is saved in the same place
identical to the freesurfer *.ctab file, but with
the area (mm^2) of each region appended as a 7th
column:

  $SUBJECTS_DIR/$subject/scripts/<prefix>.ctab.area
  $FUNCTIONALS_DIR/$session/image/scripts/<prefix>.ctab.area

Double-middle-click a region on the brain surface
to get a temporary pop-up with this information,
for example:

  MT_lower

    idnum:  21
    rgb:  35  175  175
    neighcnt:  4
    vertexcnt:  232
    origarea:  135.0 mm^2

To avoid clogging up the display, this popup
automatically closes itself in 3.5 sec.

Alternatively, to display the names of *all* of
the annotation regions, tick "areanamesflag"
(default=OFF) on the LABEL CONTROLS popup. The
label names are centered on the vertex in each
annotation region that is closest to the 3D
average of the vertices in each region.  This 3D
average is calculated by read_mgh_annot on
whatever surface (folded, inflated, flattened)
that the annotation has been read onto (if
surface interactively changed, re-read annotation
to re-calc).  See R-click help for the "W" button
on the "label:" line to write out the center
vertex for each region.  Use tksurfer command
line option -fontfile <somefont.ttf> to use a
different font than the included luxisb.ttf (put
the alt .ttf file into $CSURF_DIR/lib/fonts).

Left-clicking (or double-middle-clicking) a
region also loads the annotation color of that
region into the r,g,b field to the right of the
MESH button.

To use the MGH annotation to extract surface
vertex data in the .val(.val2) fields under one
of the colored labels, see "W" button R-click
help (tcl funct: write_val_annotedcol_vertices).

To count the number of neighbors of each
annotation region, save the counts in stat, and
print each area's neighbors to the scripts dir
(file: AnnotRegionsNeighborCounts.txt), use
ctrl-mid-click-D (tcl function: areaneigh2stat,
see below).

To calculate vertex-wise percent overlap between
each region in the currently loaded MGH
annotation file and any vertices containing
non-zero .val data, use calc_annots_nzval_overlap
(see below).

The "label:" line "CLR" button clears all
displayed labels, and also, the embedded MGH
color LUT.

To resample an fsaverage annotation to current
single subject, use the standard tcl script:

  annot2roi.tcl

from "tcl:" dropdown (described in R-click help
for the "tcl:" entry).

For the binary format of the MGH annotation
files, see the R-click help for the "label:" line
entry.

(3) Brain Voyager POI Annotation file (.poi suffix)

The "D" button can also read an Brain Voyager
"Patches of Interest" (*.poi) annotation file
(ASCII, vers=2).  Any *.poi file in the current
subject's label directory will be loaded into the
"label:" line dropdown.  This uses the C/tcl
function, read_poi_annot.

The result of reading a *.poi file is the same as
the result of reading an MGH annotation file, and
the displayed labels/patches can be used in the
same way.

For the ASCII format of BV patches-of-interest
files, see the R-click help for the "label:" line
entry.

(4) Wavefront ASCII file w/vertexwise colors (.obj suffix)

The "D" button can also read an ASCII Wavefront
surface file containing vertexwise colors as if
it was an annotation (a set of patches of
interest).  That is, the vertices in each unique
color are assigned to different brain regions (up
to 5000 unique colors/regions allowed, before
bailing).  This uses the C/tcl function,
read_obj_to_annot.  Again see R-click help for
the "label:" entry for expected file format.

In this case, the vertex x,y,z coordinates and
faces geometry (and texture if there) is ignored.

(5) GIFTI xml annotation file (.gii suffix)

The "D" button can also read a GIFTI xml
annotation file (e.g., as generated by
mris_convert).  This contains a color lookup
table that maps region names and region id number
to floating point (0.0 to 1.0) r,g,b colors,
followed by a list of region id numbers for every
surface vertex.  This uses the C/tcl function,
read_gifti_to_annot.

-------------------------------------------
funct: "Undo Cut with Label (mid-click-D)"
  set label <infile>
  read_label_to_undo_cut
-------------------------------------------

If the "D" button is middle-clicked (instead of
default left-clicked), vertices in label are read
and used to uncut the surface (if cut).  If
vertex not cut, no effect.

To repair unintended surface cuts on a patch,
first make a label that covers the parts of the
cut(s) you want to undo.

There are two critical points:

(1) the cut-fixing label has to be *made* on an
  *uncut* surface (e.g., inflated).  This is so
  that the missing vertices can be labeled.  To
  transfer the location from the cut surface to
  the uncut surface, FILL an AREA cut around the
  unintended cut as a marker label, display that
  on the uncut surface, then make a new AREA cut.

(2) the cut-fixing label can only be *applied*
  to an already-cut but *still 3D* surface (e.g.,
  full.patch.3d).  This is because the missing
  (invisible) vertices on an already-flattened
  patch will no longer be located inside the cut
  (they will still be back in their original 3D
  locations!).

Re-read the cut surface, select the label on
the "label:" entry, and middle click the "D"
button to repair the cut.

Before applying, you can display the cut-fixing
label with a left click on the "D" button.

-------------------------------------------
funct: "Convert Label to 3D ROI (shift-mid-click-D)"
  set label <outfile>
  write_label_timecourses_stats 3
-------------------------------------------

If the "D" button is shift-middle-clicked
(instead of default left-clicked), the currently
selected label is converted to a 3D ROI mask
(0,1) AFNI BRIK at the resolution and orientation
of the raw data set (the rawdata set must be
present in the scandir for this to work).

The name of the function is a little confusing.
The "3" option changes its behavior from
extracting timecourses to dumping an ROI, but
using the exact same normal search code used
during time course extraction.

The sampling of the 3D data set is done according
to the current sample settings (right-click the
"label:" label for a popup), and uses the name of
the label as a BRIK prefix.  For example, a label
named:

  rh-MY_AREA.label

will be converted to an ROI BRIK named:

  rh-MY_AREA+orig.BRIK

-------------------------------------------
funct: "Convert One Annot ID to 3D ROI (shift-left-click-D)"
  [3D-ROI outfile is auto-named]
  write_annotcol_timecourses_stats $r $g $b 3
-------------------------------------------

A shift-left-click on the "D" button (instead of
default left-clicked), can be used to extract a
3D ROI mask AFNI BRIK for one of the brain
regions in a loaded MGH annotation file.

The name of the function is a little confusing.
The "3" option changes its behavior from
extracting timecourses to dumping an ROI, but
using the exact same normal search code used
during time course extraction.

As above, the ROI will be at the resolution and
orientation of the raw data set (so the rawdata
set must be present in the scandir for this to
work).  The steps are:

 (1) select MGH annotation from label dropdown
 (2) load it with left-click "D"
 (3) click one of the brain regions to load r,g,b color
 (4) shift-left-click "D" to extract 3D ROI

The sampling of the 3D data set is done according
to the current sample settings (right-click the
"label:" label for a popup).

The name of the ROI BRIK will be taken from the
MGH annotation file name for the current r,g,b
color.

For example, for annotation file:

  rh.aparc.a2009s.annot

clicking on the STS will set r,g,b (just to right
of MESH) to 223,220,60, which corresponds to
structure "S_temporal_sup" and the output mask
BRIK will be named:

  rh-region_S_temporal_sup+orig.BRIK

The selected voxels in the output mask BRIK
(datatype=short) will contain the IDnum for this
region ("S_temporal_sup" IDnum=74), else zero.

See also standard tcl script, annot2roi.tcl,
available from the "tcl:" dropdown, which dumps
out each of the annotations in an MGH annotation
file into individual volumes, and also into a
single, composite volume (with voxel value equal
to annotID).

-------------------------------------------
funct: "Pick Annot Idnums to View/Mask (shift-right-click-D)"
  set_idnums_visibility <0,1>
  set_idnum_visibility <idnum> <0,1>
  set_idnum_visibility <idnum> <0,1>
    [etc for all visible]
  set annotmaskflag 1
  redraw
  [write_val_unmasked_vertices]
-------------------------------------------

After an MGH surface annotation file has been
read with "D" on the "label:" line, you can use
this function either to:

  (1) display a subset of the annotation labels

or, if a vtxcol label (fixed "paint") has been
loaded:

  (2) display a subset of the vtxcol "paint"

or, if surface data overlay has been loaded (at
least the .val field):

  (3) mask real/complex data by annotation idnum's

A shift-right-click on the "D" button brings up
two popups.  The tcl function to do this is:

  annotmaskctrls

The first popup lists the idnum's and names of
all the annotation regions for reference.  In the
second popup (3 similar versions depending on
state), you enter a space-separated list of
idnum's to show (all not listed are masked).  To
quickly find a label, just enter one label number
and <Return>.

In case (1), the subset of annotation regions is
displayed over a grayed curvature (transparency
controlled by the upper right "tran" entry
($labelapha).

In case (2), the subset of vtxcol regions is
displayed over the curvature (no effect of
transparency).

In case (3), overlay data in the .val(.val2)
fields is only shown for selected annotation
regions.  This is useful, for example, to see
phase encoded data from annotation regions
(easier than with colored annotation borders).

Here is an example tcl script to reload a mask
containing somatomotor areas (3b, 4, etc) from
the HCP parcellation (assuming you have loaded
that annotation):

# tksurfer tcl script (N.B.: idnums vs. idnum)
set annotmaskflag 1
set labelflag 0
set_idnums_visibility 0    ;# mask all: idnums vs. idnum
set_idnum_visibility  8 1  ;# area 4
set_idnum_visibility  9 1  ;# area 3b
set_idnum_visibility 36 1  ;# area 5m
set_idnum_visibility 39 1  ;# area 5L
set_idnum_visibility 40 1  ;# area 24dd
set_idnum_visibility 41 1  ;# area 24dv
set_idnum_visibility 51 1  ;# area 1
set_idnum_visibility 52 1  ;# area 2
set_idnum_visibility 53 1  ;# area 3a
set_idnum_visibility 54 1  ;# area 6d
set_idnum_visibility 55 1  ;# area 6mp
set_idnum_visibility 56 1  ;# area 6v
redraw 

Once an annotation has been set up to mask data
(second case), the masked subset of data can be
optionally written out in two different forms.

To get a single label containing all currently
displayed (unmasked) data (uses C/tcl funct,
write_val_unmasked_vertices):

  tick "unmasked_to_label_flag"
  enter output file in "labelabbrev"
     [format: ~/label/$hemi-<infix>.label]
  READY

To instead write out currently visible data to
per-area label files (uses C/tcl funct,
write_val_idnum_vertices):

  tick "unmasked_to_labels_flag"
  enter output files *stem* in "labelabbrev"
     [format: ~/label/$hemi-<infix>]
  READY

This writes a label for each displayed region
into the subject's label directory with the name
formatted as follows:

  rh-<infix>_<areaname>.label

These operations are slightly out-of-place for
the label "D" button (display) as opposed to
being to being attached to the label "W" button
(write), but more convenient here grouped with
their display-only equivalents..

-------------------------------------------
funct: "All Annots to 3D ROIs (ctrl-shift-left-click-D)"
  [3D-ROI outfiles are auto-named]
  write_annotcols_timecourses_stats 3
-------------------------------------------

Same as previous, but automatically dumps *all*
of the brain regions in an MGH annotation files
to seperate AFNI ROI mask BRIK's.

This runs faster if the sampling surface (usu.
"orig") is first loaded.

This also constructs a single, all-ROIs-in-one
BRIK named:

  $hemi-ALL_ANNOT_ROIs-<sampledepth>+orig.BRIK

Each annotation region is added to the all-in-one
ROI BRIK sequentially, so if a voxel is claimed
by more than one region, the last one 'wins'.

Overlap between ROIs can be reduced by first
eroding the surface annotation regions by
entering "annoterode" for smoothing steps and
clicking the SMOOTH button.  Each click erodes
another single layer of vertices from each
annotation region.

-------------------------------------------
funct: "Count/Print annot neighbors (ctrl-mid-click-D)"
  areaneigh2stat
-------------------------------------------

Count the number of other areas bordering each
area in an annotation (first, have to load an MGH
annotation file -- see HOWTO above).  The integer
sum is stored (vertexwise) in the .stat field
(overwrite warning), and then the counts and all
the neighbors of each annotation area are written
to an ASCII table in the current subject's
scripts dir (no overwrite warning):

  AnnotRegionsNeighborCounts.txt

Here is what a portion of that output file looks
like for rh.HCP-MMP1.annot:

#IDnum  Neighs  Structure			NeighIDnums
#-------------------------------------------
...
21      5       R_LO2_ROI			20 22 156 6 138
22      5       R_PIT_ROI			21 6 7 18 138
23      4       R_MT_ROI			156 159 2 141
24      3       R_A1_ROI			173 104 174
25      6       R_PSL_ROI			28 149 105 175 148 104
...

The neighbors are indicated by area ID numbers.

-------------------------------------------
funct: "Read Label to Select (ctrl-left-click-D)"
  set label <infile>
  read_label_to_select
-------------------------------------------

Read label and select each vertex in it
(as if each vertex left-clicked).

The inverse is write_val_selected_list_to_label
(ctrl-left-click "W" on "label:" line).

-------------------------------------------
funct: "Calc Overlap Annots w/Non-0 (ctrl-shift-right-clk-D)"
  calc_annots_nzval_overlap
-------------------------------------------

Calculate vertex-wise percent overlap between
each region in the currently loaded MGH
annotation file and any vertices containing
non-zero .val data.  Annotation regions
overlapping only zero .val's are not reported.

To use this, if necessary, first clear any
existing .annot or .val data from the surface
using:

  "CLR" on the "label:" line
  "CLR" on the "val:" line

Then load the .val field, using either:

  select valfile (*.w or *.mgh) file "val:" dropdown
  click "R" (=read) on the "val:" line
     *or*
  select data-containing label from "label:" dropdown
  click "R" (=read) on the "label:" line

Also, load an MGH annotation using:

  select .annot file from "label:" dropdown
  click "D" (=display) on the "val:" line

Finally, ctrl-shift-right-click the "D" button on
the "val:" line.

The result is written to a pop-up, to the csurf
log, and to a text file ($hemi.overlap.txt) in
the subject's "scripts" directory with the
following format:

#calc_annots_nzval_overlap (non-zero .val's)
#annot=/usr0/subjects/fsaverage/label/lh.HCP-MMP1.annot
#val=/tmp/191101BC-ICA_mgh/ICA20_medial_sensorimotor_rh.mgh
#IDnum	Percent	(Overlap/Vtxs)		Structure
#-----------------------------------------------------------
8	27.7%	(1111/4015)        	L_4_ROI
9	29.9%	(852/2845)          	L_3b_ROI
10	5.2%	(43/832)              	L_FEF_ROI
11	6.1%	(23/375)              	L_PEF_ROI
12	39.8%	(261/656)		L_55b_ROI
...

The $hemi.overlap.txt file is overwritten each
time cal_annots_nzval_overlap is re-run, so first
copy the previous output aside if you want to
save it.

-------------------------------------------
funct:"Copy Current Cols to Vtxcols (ctrl-right-clk-D)"
  currcol_to_vtxcol
-------------------------------------------

Copy the current data-derived color at each
visible vertex (as controlled by current settings
of colscale, etc) to the fixed vertex color
"paint" fields (.vr/.vg/.vb).  This can be used
to assemble illustrations containing data that
uses different color scales.

N.B.: ignores labels/annotations!  Use
currlabel_to_vtxcol below to copy labels
instead.

N.B.: this is color before the lighting
calculations have been applied!

N.B.: does NOT turn on $vtxcolflag (view
vtxcol's).

To save the vertex colors as a file, use
ctrl-R-click W on the "label:" line (tcl/C
function: write_vtxcol_label).

Be sure to start with a clean vtxcol slate by
middle-click-CLR on the "label:" line, else any
previously copied vtxcols will be included in
final .cols file.

Also, if you want to assemble multiple vtxcol's,
be sure a label has been re-cut so the whole
surface won't be saved to the vtxcol file, which
would otherwise occlude other vtxcol labels if
loaded after them.

If you already have a data-containing label, this
can all be done in one step by converting a
standard label directly to a vertex color label
using middle-click W on "label:" line (tcl/C
function: label_to_vtxcol_label).

-------------------------------------------
funct: "Copy Curr Lab/Annot to Vtxcols (ctrl-shift-mid-clk-D)"
  labelcol_to_vtxcol
-------------------------------------------

Copy the currently displayed label/annotation
color at each visible vertex to the fixed vertex
color "paint" fields (.vr/.vg/.vb).

This can be used to save a snapshot of a label or
annotation, e.g., for blink comparison with
another annotation by ticking and unticking
"labelflag" (tickbox to left of "label:"), since
vtxcols are below labels/annotations.

N.B.: ignores any currently displayed data! (use
currcol_to_vtxcol above to copy labels instead)

N.B.: this is color before the lighting
calculations have been applied!

N.B.: does NOT turn on $vtxcolflag (view
vtxcol's).

To save the vertex colors as a file, use
ctrl-R-click W on the "label:" line (tcl/C
function: write_vtxcol_label).

Be sure to start with a clean vtxcol slate by
middle-click-CLR on the "label:" line, else any
previously copied vtxcols will be included in
final .cols file.

Also, if you want to assemble multiple vtxcol's,
be sure a label has been re-cut so the whole
surface won't be saved to the vtxcol file, which
would otherwise occlude other vtxcol labels if
loaded after them.

-------------------------------------------
funct: "Display Label on Nearest Vertices (no hotkey)"
  read_label_to_nearest_annot_using_col
-------------------------------------------

Import a label file (for the same subject), but
which has a different vertex numbering scheme
(e.g., a surface made from a previous edit).

This works like read_label_to_annot_using_col in
that the requested color is defined in the r,g,b
fields to the right of "MESH"),

However, instead of reading the label file vertex
indices (first entry on each label line) to
determine which surface vertices to color, each
label file line will be used to color the current
surface vertex that has its .orig x,y,z
coordinates closest to the x,y,z coordinates in
that label file line.  N.B.: the label file
coordinates are are assumed to be from the .orig
surface, which is the default for label-writing
(i.e., not from the new Talairach coordinate
option above, for from inflated surface
coordinates, etc).

This makes it possible to display a label file
written out from an earlier version of a surface,
which will have a different vertex numbering
scheme, and which would otherwise be incompatible
with the newer surface.

N.B.: this will give non-sensical results if the
label file comes from a different subject or if
the label file contains x.y,z vertex coordinates
that are not from the .orig surface.

N.B.: to save new label:

  (1) re-cut current labeled (ctrl-L-clk "C" on "label:" line
         or tcl funct:  labeled_cut_clearvals 0)
  (2) change name in "label:" line entry to avoid overwrite!
  (3) save label with \"W\" on \"label:\" line"

This works well when edits are localized and no
global refinements have been applied (e.g.,
slightly different target target image value
criterion).  If not, there will be aliasing
between the older label x,y,z vertex positions
and the newer surface x,y,z vertex positions,
resulting in many small linear-shaped holes in
the transferred label where a new surface vertex
just missed being assigned an annotation from a
label vertex.

To fix this, use the C/tcl function
fill_annot_holes_neigh, which can be accessed by
typing "fillannot-neigh" into the unlabeled
"steps" entry immediately to the right of the
"SMOOTH" button.  A <Ret> or clicking SMOOTH
brings up a popup to control the size of the
smoothing neighborhood, "neighord" (1-5, where 1
means just consider nearest vertex neighbors),
and "annotedfrac" (% of surrounding vertices
required to cause an annotation/label hole to be
filled with the surrounding color).  For more
details, see R-click help for the smooth steps
entry immediately right of the "SMOOTH" button.

However, even without hole-filling, the converted
label can be used as a template to re-cut a new
native surface label.

This function is quick on a standard sized
freesurfer brain (130K vertices), but it will be 
slow with a very large surface (e.g., over 30 min
for a 5M vertex cerebellum).  In that case, it 
can be sped up by cutting away irrelevant parts
of the surface (if these are known), for example,
using the "PLANE" button.


####################
label_readcut
####################

#### re-cut, make-hole-with, add a label ####
-------------------------------------------
funct: "Re-cut Label File (left-click-C)"
  set label <infile>
  read_label_cut_clearvals <0=label>
-------------------------------------------
funct: "Make Hole w/Label File (mid-click-C)"
  set label <infile>
  read_label_cut_clearvals <1=hole>
-------------------------------------------
funct: "Add Label File to Existing (shift-mid-clk-C)"
  set label <infile>
  read_label_cut_clearvals <2=add>
-------------------------------------------
funct: "Re-cut CurrLabeled (ctrl-left-click-C)"
  labeled_cut_clearvals <0=label>
-------------------------------------------
funct: "Make Hole w/CurrLabeled (ctrl-mid-click-C)"
  labeled_cut_clearvals <1=hole>
-------------------------------------------
funct: "Re-cut Label w/Uniq (ctrl-shift-left-clk-C)"
  clear_uniqvoxdata
  setfile label */$scandir/$hemi-UniqSampVtxs.label
  read_uniqsamp_vertices
  set label <infile>
  read_label_cut_clearvals 0
-------------------------------------------


Detailed Description of Label "C" Button Actions

-------------------------------------------
funct: "Re-cut Label File (left-click-C)"
  set label <infile>
  read_label_cut_clearvals <0=label>
-------------------------------------------

Re-cut a label (leave just label) and zero the
.val/.val2 fields from the cut-away parts.

This has multiple uses, for example, to touch up
a label (use PTS button after re-cutting), to set
up to append another label (see below), to write
out a wfile (subset or full-surface modes)
containiing only values in the label.

Ignores data values in label file itself.  Use
shift-middle-click-R (read and re-cut) instead if
you want to read the values in the label into the
.val field.

This operation does *not* restore any currently
invisible vertices.  Thus, it can be used to find
the overlap between two (or more) labels as
follows:

  1) clear all displayed labels with "CLR"

  2) select 1st label ("label:" dropdown)
      "C" => display, recut 1st label

  3) select 2nd overlapping label
      "C" => also recut 2nd label

  etc..

The final result is the overlap (AND) of two (or
more) labels.  To find the area of the label or
overlap, select a point in area, and use FILL.

N.B.: if the labels don't overlap, nothing will
be left!

Click lower right INIT to start over or recut a
different label.

If a wfile is loaded before doing this, a wfile
(as opposed to an ASCII *.label file) containing
surface values for only the label (or label
intersection) can be saved with "W" on the "val:"
line.

-------------------------------------------
funct: "Make Hole w/Label File (mid-click-C)"
  set label <infile>
  read_label_cut_clearvals <1=hole>
-------------------------------------------

Cut vertices in the label out of the currently
displayed surface (cut out a hole) and zero the
.val/.val2 fields from the cut-away parts.

Ignores values in label file itself.

This is useful for removing overlap between
labels as follows:

  1) tick "er" ($erodingfillflag) near FILL button

  2) start by recut oversized label (left-click-C)

  3) select label for cutting in "label:" dropdown

  4) cut hole (middle-click-C) to remove overlap

  5) type orig label name in "label:" dropdown!!

  6) save fixed label (left-click-W)

N.B.: If the "er" is unticked, this operation
will result in labels that share vertices at
their boundary (may be desired).

This is also useful for editing wfiles (as
opposed to labels) to remove artifacts as
follows:

  1) display a wfile (not label) with "R" on the
       "val:" line

  2) fill artifact in it with ROI and fthresh,
       possibly restricting fill w/tmp cuts

  3) save the resulting artifact label

  4) INIT, to restore surface cuts

  5) middle-click "C" on the "label:" line to
       cut out the artifact and zero .val/.val2

  6) save modified wfile with "W" on "val:" line

This can also be used to create complex labels by
subtracting (multiple) subregions.

When saving the final label after this operation
(with left-W on the "label:" line), be sure to
verify (there will be a warning popup) that the
"label:" entry has the intended output file name!

-------------------------------------------
funct: "Add Label File to Existing (shift-mid-clk-C)"
  set label <infile>
  read_label_cut_clearvals <2=add>
-------------------------------------------

Make all vertices in the label visible.  No
effect if those vertices are already visible.

If this operation restores part of the surface
that previously had data read onto it (with "R"),
that data will be restored.

N.B.: ignores values in label file itself.

This operation can be used to combine (merge)
labels as follows:

  1) clear all displayed labels with "CLR"

  2) select 1st label ("label:" dropdown)
      "leftclick-C" => display, recut 1st label

  3) select 2nd label to add
      "Shift-middleclick-C" => add 2nd label

  etc...

When saving the final label, be sure to verify
that the "label:" entry has the correct intended
output file name!

The composite cut label can be immediately saved
with "W", or after first reading data into it.
Later on, the label can be used to capture
surface data from any other data set from the
same subject as follows:

  1) load any surface data

  2) select label from dropdown and display
       it with "D" as a transparent label
       over the data

  3) change name of label in "label:" entry
       if you don't want to overwrite the
       data currently in the label

  4) use Shift-MiddleClick-"W" (tcl funct:
       write_val_annoted_vertices) to write label

-------------------------------------------
funct: "Re-cut CurrLabeled (ctrl-left-click-C)"
  labeled_cut_clearvals <0=label>
-------------------------------------------

Cut a label (leave just labeled) using currently
display label(s) and zero the .val/.val2 fields
from the cut-away parts.

Same as first option but uses currently displayed
label(s) instead of reading a file.

Can be used to combine labels or to mask
activations in preparation for making a vertex
color label.

-------------------------------------------
funct: "Make Hole w/CurrLabeled (ctrl-mid-click-C)"
  labeled_cut_clearvals <1=hole>
-------------------------------------------

Cut vertices in currently display label(s) out of
surface (cut out a hole) and zero the .val/.val2
fields from the cut-away parts.

Same as second option but uses currently
displayed label(s) instead of reading a file.

-------------------------------------------
funct: "Re-cut Label w/Uniq (ctrl-shift-left-clk-C)"
  clear_uniqvoxdata
  setfile label */$scandir/$hemi-UniqSampVtxs.label
  read_uniqsamp_vertices
  set label <infile>
  read_label_cut_clearvals 0
-------------------------------------------

Same as a default left-click but also auto-reads
$hemi-UniqSampVtxs.label (generated at PAINT time
if UniqVtx was ticked) so recut label will only
contain 'representative' vertices -- that is, a
single vertex for each sampled voxel nearest to
the average position of the vertices that sampled
that voxel.

At re-cut time, since the resulting sparse label
will typically contain only a single vertex from
any given face, it cannot be displayed as a
continuous surfacepatch, so $pointsflag will be
turned on to make the sparse label visible
(middle-click the MESH button to toggle
$pointsflag).

Once the sparse label has been written,
re-displaying it with the "D" button will pad the
single vertices with their surrounding faces so
it can be seen (see the R-click for the ROI
button for a full explanation of why it has to be
this way).


####################
label_clear
####################

#### clear displayed labels, vtx colors ####
-------------------------------------------
funct: "Clear All Annotation (left-click-CLR)"
  clear_annot
-------------------------------------------
funct: "Clear All VtxCol Paint (mid-clk-CLR)"
  clear_vtxcol_labels
-------------------------------------------
funct: "Clear Annot+VtxCol (shift-mid-clk-CLR)"
  clear_annot
  clear_vtxcol_labels
-------------------------------------------
funct: "Clear One Label (ctrl-left-click-CLR)"
  set label <infile>
  read_label_to_clear_annot
-------------------------------------------
funct: "Clear One Color (ctrl-mid-click-CLR)"
  clear_annot_with_col <r> <g> <b>
-------------------------------------------


Detailed Description of Label "CLR" Button Actions

-------------------------------------------
funct: "Clear All Annotation (left-click-CLR)"
  clear_annot -- clear labels
-------------------------------------------

Clear all displayed annotation labels (labels
read into .annot field) from brain.  Any vertex
data previously partially occluded by the
annotation label(s) will now be fully visible.

If an MGH annotation file has been loaded, this
also clear the color LUT that maps annotation
label color to brain structure.

Finally, the .annotbord field is also cleared,
which will clear dot borders (if any are
displayed).

Note that if vertex data associated with a label
has instead, or in addition, been read into the
val field (using the "R" button -- function:
read_label_to_val), *that* data will *not* be
cleared.  Use the "CLR" button on the "val:" line
to clear vertex data.

-------------------------------------------
funct: "Clear All VtxCol Paint (mid-clk-CLR)"
  clear_vtxcol_labels
-------------------------------------------

Clear all vertex-color labels from brain.  Any
vertex data previously occluded by the
vertex-color label will now be visible.  This
won't affect labels displayed using "D" or any
vertex data loaded with "R".


-------------------------------------------
funct: "Clear Annot+VtxCol (shift-mid-clk-CLR)"
  clear_annot
  clear_vtxcol_labels
-------------------------------------------

Clear both annotation labels and all vertex-color
labels, too.

-------------------------------------------
funct: "Clear One Label (ctrl-left-click-CLR)"
  set label <infile>
  read_label_to_clear_annot
-------------------------------------------

Clear displayed annotation only under label
currently in "label:" line entry.

-------------------------------------------
funct: "Clear One Color (ctrl-mid-click-CLR)"
  clear_annot_with_col <r> <g> <b>
-------------------------------------------

Clear displayed annotation with color specified
by r,g,b fields to right of MESH button.  Load
the color by first clicking an annotation region.


####################
label_read2val
####################

#### read label data, read vtxcols, read+cut ####
-------------------------------------------
funct: "Read Label -> Val (left-click-R)"
  set label <infile>
  read_label_to_val <cutlabelflag=0>
-------------------------------------------
funct: "Read VtxCol Paint (middle-click-R)"
  set vclabel <infile>
  read_vtxcol_label
-------------------------------------------
funct: "Read/Recut Label->Val (shift-mid-clk-R)"
  set label <infile>
  read_label_to_val <cutlabelflag=1>
-------------------------------------------
funct: "Read Uniqsamp Vtxs (ctrl-left-click-R)"
  setfile label */$scandir/$hemi-UniqSampVtxs.label
  read_uniqsamp_vertices
-------------------------------------------


Detailed Description of Label "R" Button Actions

-------------------------------------------
funct: "Read Label -> Val (left-click-R)"
  set label <infile>
  read_label_to_val <cutlabelflag=0>
-------------------------------------------

Read data (real or complex) for labeled vertices
from ASCII label file whose name is current value
of $label (entry at left) into the .val field
(and also .val2 field if complex).

If "cpx" is unticked ($complexvalflag equals 0),
then this expects a real-valued file with 5
numbers on each line after the 2-line header
(vtxnum x y z val).

If "cpx" is ticked ($complexvalflag equals 1),
then this expects a complex-valued file with 6
numbers on each line after the 2-line header
(vtxnum x y z r i).

See the R-click help for the label entry for more
details on file formats.

Vertices not in label file are not modified
(e.g., when masking or merging activations).  To
first clear the data from all vertices (.val and
.val2 fields) use CLR button two rows below to
right of "val:".

The data in the label file is rendered using the
current settings (colscale, fmid, etc.), which
can be adjusted to taste after reading the label.

The label is not re-cut (see shift-middle-click
below to read a label *and* recut it).

If the label filename has a pattern such as:

 ~/prf/rh_pRF_sf_pol_r.label
 ~/prf/rh_pRF_sf_pol_r.label

(or with 'rh' prefix, or 'ecc' infix) indicating
it is a complex-valued pair, reading either
member will auto-read the other, and also reset
the color scale parameters to appropriate values.

You can also directly call the (verbosely-named)
tcl wrapper function that correctly handles the
different cases:

  read_realcomplex_or_samcomplex_label_to_val

This requires a single valid label file in entry.

-------------------------------------------
funct: "Read VtxCol Paint (middle-click-R)"
  set vclabel <infile>
  read_vtxcol_label
-------------------------------------------

If the "R" button is middle-clicked (instead of
default left-clicked), an alternate read label
function is called: read_vtxcol_label.  This
function reads a previously-written "vertex-color
label".  This will have been previously created
from a label using middle-click-W (see
right-click help for the "W" button).

The filename of the vertex-color label ($vclabel)
is parallel to the label from which it was
created.  You can enter the name of the *.cols
file directly *or* the name of the corresponding
regular label file:

  ~/label/rh-V1.cols => label in entry
  ~/label/rh-V1.cols => vertex-color label that is read

or

  ~/label/rh-V1.label => label in entry
  ~/label/rh-V1.cols => vertex-color label that is read

A vertex-color label (suffix: .cols) contains the
actual colors of each rendered vertex in a label
given all the tksurfer panel settings at the time
the vertex-color label was created (e.g.,
colscale, fmid, anglecycles, etc).  Note that
these colors are *before* lighting calculations
have been applied, so the same *.cols file can be
correctly displayed on differently shaped
surfaces.

This differs from a regular label, which contains
a set of statistical values that don't themselves
change as the color scale display settings are
changed.

This function can be used to assemble the results
of multiple experiments on one brain surface in
cases where the separate experiments require
different color scales (since the current color
scale is otherwise applied to every vertex).  A
vertex-color label will opaquely occlude
activations already displayed on the surface in
the location of the label; and subsequently read
vertex-color labels occlude previously read
vertex-color labels.

A middle-click on the unlabeled checkbutton as
the far left of the "label;" lines toggles the
visibility of any vertex-color labels.

See R-click help for the "label:"  "W" button for
format of ASCII vertex-color label file.

-------------------------------------------
funct: "Read/Recut Label->Val (shift-mid-clk-R)"
  set label <infile>
  read_label_to_val <cutlabelflag=1>
-------------------------------------------

[was "RC", read-then-cut, button]

Exactly the same as default left click -- read
real or complex data from ASCII label file whose
name is current value of $label (entry at left)
into the .val field (and .val2 field if complex)
-- except that label is also re-cut.

This can be used to edit/trim an existing label,
or to incorporate different overlay data before
re-saving the label (usu. with a different
name!).

Note that the re-cutting operation will restore
to visibility any vertices in the label that are
currently invisible.  For find label overlap, use
the "C" button instead (recuts a label without
restoring invisible vertices or reading values).

-------------------------------------------
funct: "Read Uniqsamp Vtxs (ctrl-left-click-R)"
  setfile label */$scandir/$hemi-UniqSampVtxs.label
  read_uniqsamp_vertices
-------------------------------------------

Read label to mark uniqsamp vertices (output of
PAINT if Setup Functional "UniqVtx" ticked).
Currently, only accepts label with this name:

  ?h-UniqSampVtxs.label

(the "setfile" above is a csurf-specific globbing
"set").  This reads previously computed single
vertices that were closest to the average location
of each set of vertices that sampled one voxel
during the paint operation.  The value at each
vertex in the file is the number of vertices
intersected by this unique vertex, which is saved
in the .uniqvoxcnt field.  The .uniqvoxnum field
is set to a sequential numbering of the unique
vertices.  These fields affect the operation of:

  "T" button (write_label_timecourses_stats)
  "X" button (corr_over_label) searchlight-based xcorr
  tcl funct: find_FDR_from_pvals


####################
label_write
####################

#### write label data, vtxcols, MGHannot data ####
-------------------------------------------
funct: "All Visible To Label (left-click-W)"
  set label <outfile>    [must end in *.label]
  write_val_visible_vertices
-------------------------------------------
funct: "Labeled Vals to VtxCol (mid-click-W)"
  set label <label2convert>
  label_to_vtxcol_label
-------------------------------------------
funct: "Labeled Vals to Label (shift-mid-click-W)"
  set label <outfile>
  write_val_annoted_vertices
-------------------------------------------
funct: "AnnotCol Vals to Label (shift-left-click-W)"
  set label <outfile>
  write_val_annotedcol_vertices <r> <g> <b>
-------------------------------------------
funct: "AnnotCols Vals to Labels (shift-ctrl-left-clk-W)"
  set label <outfilepref>   [just: {lh,rh}-pref]
  write_val_annotedcols_vertices
-------------------------------------------
funct: "Selected Vertices/Vals to Label (ctrl-left-click-W)"
  set label <outfile>
  write_val_selected_list_to_label
-------------------------------------------
funct: "Assemble MGH Annot from LUT (ctrl-mid-clk-W)"
  set lulabel <CsurfColorLut.txt>
  set anlabel <outfile>
  write_mgh_annot
-------------------------------------------
funct: "Searchlights On Label (shift-ctrl-mid-click-W)"
  set label <outfile>
  write_searchlights <fillneartype> <criterion>
-------------------------------------------
funct: "AnnotCol Vals to Named (shift-ctrl-right-clk-W)"
  [output auto-named]
  write_val_annotedcol_autoname <r> <g> <b>
-------------------------------------------
funct: "Write Curr VtxCols to ColsFile (ctrl-right-clk-W)"
  set label <outfile>   [must end in *.cols]
  write_vtxcol_label
-------------------------------------------
funct: "Write Adjusted Phase to Label (shift-right-clk-W)"
  set label <outfile>
  write_adjphase_vertices
-------------------------------------------
funct: "Write StatIDs to RandCol MGH Annot (no hotkey)"
  set label <outfile>
  write_statids2randcolannot
-------------------------------------------
funct: "Sort Label By Dist Last Clicked Vtx (no hotkey)"
  set label <outfile>
  write_sorted_by_pathdist_label
-------------------------------------------
funct: "Write Region Centers to scriptsdir (no hotkey)"
  write_annot_region_centers
-------------------------------------------


Detailed Description of Label "W" Button Actions

-------------------------------------------
funct: "All Visible To Label (left-click-W)"
  set label <outfile>
  write_val_visible_vertices:
-------------------------------------------

Write out an ASCII label file using the name
$label (name in entry to left).  Any vertex
without its ripflag (invisible flag) set will be
written to the file -- that is, anything that is
currently visible in the surface window!
Typically, vertices-to-save are first selected by
doing a closed-line cut (AREA) followed by a FILL
*before* writing the label file.

N.B.: if you display a label with "D" and then
immediately write out a label file with "W", with
the whole surface visible, you won't make a copy
of the displayed label but will instead replace
the original (typically small) label file with
one that covers the whole surface (usu. not
intended!).

To edit an existing label, read in its data *and*
re-cut it with shift-middle-click "R" on the
"label:" line (N.B.: the "C" button also recuts
the label, but it clears the data fields).

Vertex number (field 1)

The first field in each label file line is
the vertex number.

Surface x,y,z Coordinates (fields 2,3,4)

The next three fields are the x,y,z coordinates
of each vertex.  There are five different
possibilities:

  (1) .orig surf coord
  (2) .orig surf coord incl. elevation along normal
  (3) .orig coord converted to MNI Talairach
  (4) .orig coord conv. to MNI Talairach w/elev. on normal
  (5) coord from current surface (e.g., .inflated)

In the first case, the x,y,z coordinates written
into the label file are come from the $origcoords
surface, which is typically $hemi.orig,
regardless of which surface is currently being
displayed.

For the second case (freesurfer surface
coordinates), turn ON $normdsampsearchflag (top
tickbox on popup from left-click on "label:"
label).  N.B.: this is now ON by default.  In
this case, the x,y,z coordinates will be elevated
along the normal to each vertex.  The elevation
distance can either be a fraction of the local
cortical thickness (if $normdfracflag is ON,
where the fraction is halfway between
$normdfracsamp and $normdfracmax) or a fixed
distance in mm (if $normdfracflag is OFF, where
the distance is halfway between $normdsamp and
$normdmax).  All those parameters are on the
popup.

For the third and fourth cases (Talairach
coordinates), turn on $usetalcoordsflag
(middle-click upper left "c2lab" tickbox), and
control elevation along the normal as above.

N.B.: the elevation along the normal should
usually be the same as that used when the 3D data
was sampled to the surface by the PAINT button.
The sampling parameters are save on the
SessionTools -> Setup Align/Funct Scans panel).

For the last case, left-click "c2lab" (no
elevation along normal possible in this case).

A different gray/white matter surface than .orig
can be used by resetting $origcoords with a tcl
script like this:

  setfile origcoords rh.orig2
  setfile origcoords /abs/path/to/surface

e.g., by using EDIT and RUN at middle upper left
of surfer tools panel (N.B.: this has no effect
if the current surface is a patch).

N.B.: if a patch has been displayed, the z coord
will be 0.0 for every vertex in this case.

Overlay Data (fields 5, optionally 6)

The data in the .val field that is written into
the label file comes from the currently visible
overlay data.  If no overlay data has been read,
the values will all be 0.0.  If the loaded data
is complex ($complexvalflag is set), then the
.val2 field is also written out (6 entries per
line instead of 5).

See help for the label entry field for more
information and examples of the label file
format.

-------------------------------------------
funct: "Labeled Vals to VtxCol (mid-click-W)"
  set label <label2convert>
  label_to_vtxcol_label
-------------------------------------------

If the "W" button is middle-clicked (instead of
default left-clicked), an alternate write label
function is called:

  label_to_vtxcol_label

This function reads the label file in the entry
to the left and then converts the data in it
using current color scale settings to a
"vertex-color label".

The filename of the vertex-color label ($vclabel)
is parallel to the label from which it was
created:

  ~/label/rh-V1.label => label in entry
  ~/label/rh-V1.cols => vertex-color label made

A vertex-color label (suffix: .cols) contains the
actual colors of each rendered vertex in a label
given all the tksurfer panel settings at the time
the vertex-color label is created (e.g.,
colscale, fmid, anglecycles, etc).  Note that
these colors are *before* lighting calculations
have been applied, so the same *.cols file can be
correctly displayed on differently shaped
surfaces.

Vertex-color labels can be used to assemble
results rendered with different color scales on a
single brain surface (see help for the label "R"
button).

The format of the vertex-color label file is a
single header line, followed by the number of
vertices followed by lines containing 4 entries
(vtxnum r g b). The rgb values are in the range
of 0.0 to 1.0, for example:

#!ascii , from subject claudia2
13617
26402   0.009   0.986   0.009
26403   0.016   0.975   0.016
26404   0.042   0.934   0.042
...

-------------------------------------------
funct: "Labeled Vals to Label (shift-mid-click-W)"
  set label <outfile>
  write_val_annoted_vertices
-------------------------------------------

If the "W" button is *shift*-middle-clicked
(instead of default left-clicked), yet another
alternate write label function is called:

  write_val_annoted_vertices

This function checks at each vertex whether an
annotation is being displayed (transparent label
location displayed with "D"), and then writes out
the values for those vertices (from vertex.val
field -- and vertex.val2 field if $complexvalflag
is set) to the label name in the entry.

N.B.: if an MGH annotation file is loaded, the
output label file will include all regions (see
next to write out one region from an annotation
file).

This is a short-cut way of using one or more
labels to save out a subset of the data currently
displayed on a surface that doesn't require
re-cutting the label.

N.B.: if $annotbordflag is ON (toggle with
shift-middle-click on leftmost tickbox on
"label:" line), only border vertices will be
included in each label.

-------------------------------------------
funct: "AnnotCol Vals to Label (shift-left-click-W)"
  set label <outfile>
  write_val_annotedcol_vertices <r> <g> <b>
-------------------------------------------

If the "W" button is *shift*-left-clicked
(instead of default left-clicked), yet another
alternate write label function is called:

  write_val_annotedcol_vertices <r> <g> <b>

This function is dumps vertex data for a single
color label from a displayed MGH annotation file.

The tksurfer interface takes the r,g,b values
from the current settings of r,g,b in the fields
to the right of the MESH button.  If an MGH
annotation has been displayed, those entries will
be automatically updated with the current
annotation color when any surface vertex is
clicked.

This function checks at each vertex whether an
annotation with the specified r,g,b values is
being displayed (transparent label location
displayed with "D") in the specified color, and
then writes out the values for those vertices
from the vertex.val field (and vertex.val2 field
if $complexvalflag is set) to the label name in
the entry.

HOWTO summary:

  1) load vertex data of interest to .val(.val2)
  2) display transparent MGH annot w/left-click "D"
  3) click one colored label to use (loads r,g,b color)
  4) set name in "label:" entry to desired output file
  5) Shift-left-click-"W"

N.B.: if $annotbordflag is ON (toggle with
shift-middle-click on leftmost tickbox on
"label:" line), only border vertices will be
included in each label.

N.B.: to display and dump data to label files
from a subset of labels, see the help for the "D"
button on the "label:" line (shift-R-click-D).

-------------------------------------------
funct: "AnnotCols Vals to Labels (shift-ctrl-left-clk-W)"
  set label <outfilepref>   [just: {lh,rh}-pref]
  write_val_annotedcols_vertices
-------------------------------------------

If the "W" button is *ctrl*-*shift*-left-clicked
(instead of default left-clicked), yet another
alternate write label function is called:

  write_val_annotedcols_vertices

This function is like the previous one, except
that it dumps vertex data for *every* color label
from the currently displayed MGH annotation file
into separate label files for each differently
colored region.

N.B.: instead of entering the name of a single
label file in the "label:" entry, you must enter
a prefix in the following form (for the last
component of the pathname):

  .../{rh,lh}-<infix>

That is:

  1) $hemi must match current
  2) third char must be '-' (dash)
  3) infix must be at least 1 character long

For infix "TEST" with the rh of HCP-MMP1, this
will generate a series of 180 label files
containing current vertex data that look like
this:

  .../rh-TEST_R_V1_ROI.label
  .../rh-TEST_R_MST_ROI.label
  .../rh-TEST_R_V6_ROI.label
  .../rh-TEST_R_V2_ROI.label
  [etc]

N.B.: if $annotbordflag is ON (toggle with
shift-middle-click on leftmost tickbox on
"label:" line), only border vertices will be
included in the labels.

N.B.: to display and dump data to label files
from a subset of labels, see the help for the "D"
button on the "label:" line (shift-R-click-D).

-------------------------------------------
funct: "Selected Vertices/Vals to Label (ctrl-left-click-W)"
  set label <outfile>
  write_val_selected_list_to_label
-------------------------------------------

If the "W" button is *ctrl*-left-clicked (instead
of default left-clicked), yet another alternate
write label function is called:

  write_val_selected_list_to_label

This dumps vertex data for all currently selected
vertices to a label file.

Like default write_val_visible_vertices, it loads
original surface coordinates (if not already
loaded), and can instead dump current surface
coordinates (if $usecurrcoordsflag is set to 1).

The inverse of this is read_label_to_select
(ctrl-left-click "D" on "label:" line).

N.B.: this function is sensitive to the state of
$bigcursorflag.  If $bigcursorflag is ON (see
R-click popup from REDRAW button) when this
function is executed, the the neighbors of
selected vertices will be included in the output
label.  This is useful when you want to outline
where a cut should be made using one surface,
convert those outlines to a label, and then
display that label on a different surface - for
example, to outline the cerebellar vermis on the
highly folded smoothwm surface where it is easier
to see, save that outline as a label, then
display it on the inflated surface, where the
cuts are much easier to make.

-------------------------------------------
funct: "Assemble MGH Annot from LUT (ctrl-mid-clk-W)"
  set lulabel <CsurfColorLut.txt>
  set anlabel <outfile>
  write_mgh_annot
-------------------------------------------

If the "W" button is *ctrl*-*middle*-clicked
(instead of default left-clicked), a popup is
made that runs yet an alternate write label
function:

  write_mgh_annot

This assembles multiple labels into a single MGH
annotation file using all of the region names and
colors from an MGH FreeSurfer LUT file.

(1) MGH FreeSurfer Color Lookup Table (LUT)
  [default name:]
  $CSURF_DIR/lib/lut/CsurfColorLUT.txt

(2) output .annot file
  [default name:]
  $SUBJECTS_DIR/$subject/label/$hemi-MY_ANNOT.annot

The dropdowns are loaded with all *.txt and
*.annot files in the default directories.

Change the "MY_ANNOT" infix to something more
useful (this is the default to avoid accidental
overwrites).  Here is an example of the format of
an MGH FreeSurfer LUT file (empty lines or lines
starting with '#' are ignored).  The numbers in
the "id" column cannot overlap, but they may
contain 'holes'.

#!ascii , CsurfColorLUT.txt (in $CSURF_DIR/lib/lut)
#------------------------------------------
#id	region(=labelinfix)		R      G      B      A
#------------------------------------------
 0	Unknown		0      0       0       0
 1	V1_lower		150   0      100    0
 2	V1_upper		150   0      120    0
14	V3_lower		0      50     200    0
15	VP_upper		0      50     220    0

To quickly comment-in or comment-out blocks of
regions from the output annotation, two
additional pseudo-comemnt directives are
recognized (the first of the three hash marks
must be the first character on the line, and and
the string must exactly match):

### include_following
### exclude_following

These toggle inclusion/exclusion of any following
region until the next (optional) directive.  You
can comment these directives out like this:

# ### include_following

N.B.: Though csurf tksurfer will accept and
display a FreeSurfer Color LUT containing
non-zero values for column A (alpha,
transparency), MGH tksurfer/freeview requires
that the color LUT value of alpha always be 0
(100% transparent, AKA invisible).  Therefore,
for compatibility, always use 0 as the last entry
in each FreeSurfer Color LUT line.  The
transparency of all labels can be adjusted
afterward with set_annot_alpha.

Each region or structure name (except "Unknown")
must have a corresponding csurf dash-style label
file in the current subject's label directory.
Using the example above for the right hemisphere
of the subject, fsaverage, the following label
files must exist:

  $SUBJECTS_DIR/fsaverage/label/rh-V1_lower.label
  $SUBJECTS_DIR/fsaverage/label/rh-V1_upper.label
  $SUBJECTS_DIR/fsaverage/label/rh-V3_lower.label
  $SUBJECTS_DIR/fsaverage/label/rh-VP_upper.label

If any are missing, they will be omitted from the
final combined annotation file.

Finally, click READY to assemble an MGH
annotation file containing these labels in these
colors.  The new assembled annotation file will
be displayed, followed by the number of hits per
vertex (this will be 2 on borders).  To
re-display the assembled annotation at another
time, select it, and use "D" on the "label:"
line.

The process will fail if there are any duplicate
region id numbers *or* duplicate colors in the
color LUT file (duplicates reported in popups).

Input labels may overlap.  The number of hits per
vertex (e.g., if labels overlap) is saved into
the .stat field and swapped to the surface at the
end to make it visible.  To save it, select a new
wfile name (e.g., <annotname>_nhits-$hemi.w) and
use "W" on the "val:" line.

Since the final annotation file will only contain
one region name and one color per vertex, the
last label file (as defined by the order of
regions in the LUT file) that contains a
particular vertex will control the structure name
and color for that vertex.

Vertices on the surface not included in any label
will be given structure name "Unknown" and will
always be displayed as completely transparent
(alpha=0).  The transparency of all other
structures is controlled by the "tran" entry at
the upper right.

Although csurf tksurfer read_mgh_annot can accept
*.annot files containing non-sequential region
idnums, these files will crash mris_convert and
are sometimes not read properly by freeview,
which uses similar utils/colortable.c functions.
Therefore, when tksurfer write_mgh_annot reads an
input FreeSurfer color LUT containing
non-sequential idnums, it will renumber them
sequentially in the .annot output file.

A second workaround needed to avoid mris_convert
crashes and freeview fail-to-reads is that the
header field in the output *.annot file for the
maximum idnum (which is a separate field from
idnum count) must be incremented by 1 over the
actual value (e.g., for sequentially renumbered
idnums 0,1,2,3, idmax must be set to 4, not 3).
Csurf tksurfer read_mgh_annot accepts either
incremented or incremented idmax.  The field that
has to be incremented is "maxstruc" here:

  https://surfer.nmr.mgh.harvard.edu/fswiki/LabelsClutsAnnotationFiles

How to do assemble an annotation with a tcl
script:

  ### set infile (default, but any source OK)
  set lulabel $CSURF_DIR/lib/lut/CsurfColorLUT.txt
  ### set outfile (setfile is csurf-specific glob)
  setfile anlabel ~/label/$hemi-MY_ANNOT.annot
  ### make annotation
  write_mgh_annot

-------------------------------------------
funct: "Searchlights On Label (shift-ctrl-mid-click-W)"
  set label <outfile>
  write_searchlights <fillneartype> <criterion>
-------------------------------------------

If the "W" button is *shift*-*ctrl*-middle-clicked
(instead of default left-clicked), yet another
alternate write label function is called:

  write_searchlights <fillneartype> <criterion>

This generates a single ASCII file of the
concatenated searchlights (vertex number lists)
for each vertex in the label, using distances
from the currently displayed surface.  Here is an
example format:

  #!ascii , 82934 searchlight centers, lab=/usr0/sessions/fsaverage/label/rh-MY_AREA.label, surf=rh.inflated,  fillneartype=1, criterion=250
  searchlight 0 vertex 3457
  3456
  3459
  ...
  searchlight 1 vertex 3878
  3874
  3881
  ...
  [to searchlight 82933]

When used interactively, the first function
argument, $fillneartype, is taken from the most
recent middle-click on the lower right buttons,
N, A, and R:

  middle-click N (number of vtxs: fillneartype=0)
  middle-click A (area in mm^2: fillneartype=1)
  middle-click R (radius in mm: fillneartype=2)

The second function argument, $criterion, is
taken from the entry between the N and A buttons.
Its meaning depends on the fillneartype (number
of vertices, area in mm^2, or radius in mm).

N.B.: for $fillneartype 1=area and 2=radius, the
number of vertices in each searchlight will vary
slightly.  To get a fixed number in each
searchlight, use $fillneartype=0.

For 250-vertex searchlights, this operation takes
roughly 1 min for every 2500 vertices in a label.

'Representative vertex' searchlights

To generate searchlights that only contain
'representative' unique vertices -- that is,
using only one vertex for each uniquely sampled
3D stat voxel -- load a 3D data set to specify
voxels, sample voxels to surface, and calculate
representative vertices before writing out
searchlights.

To find representative vertices interactively:

  left-click "val:" => changes to "val3d:"
  "val:" entry => select BRIK to define voxels
  left-click "R" => read BRIK
  left-click "label:" => set sampling parms in popup
  left-click "PAINT" => sample to surf, find uniqvox
  left-click-"UQ" => calc uniq vtxs

To find representative vertices in a tcl script:

  ### read 3D data BRIK to define voxels
  setfile statpatt */scandir1/some3Ddata+orig.BRIK
  read_native_stat 0          ;# 0 means real
  ### set sampling parms
  set normdsampsearchflag 1   ;# turn on norm search
  set normdfracsamp 0.5       ;# begin search
  set normdfracmax 0.5        ;# end search
  ### sample 3D data to surface, record uni vox IDs's
  paint_surface 0             ;# 0=justpaint
  ### calc/select/write uniq vtxs from uniq vox ID's
  find_uniqsamp_vertices
  select_uniqsamp_vertices
  write_uniqsamp_vertices

Finally, open the cross correlation panel with a
left-click on the "X" on the "label:" line and
tick:

  searchlightuniqflag

and optionally, if a fixed number of vertices per
searchlight are required (only works with the "N"
fillneartype=0 criterion):

  numafteruniqflag

The ASCII output file of searchlights is written
into the current subject's label directory:

  $SUBJECT_DIR/$subject/label/Spotlights.txt

-------------------------------------------
funct: "AnnotCol Vals to Named (shift-ctrl-right-clk-W)"
  [output auto-named]
  write_val_annotedcol_autoname <r> <g> <b>
-------------------------------------------

If the "W" button is *shift*-*ctrl*-right-clicked
(instead of default left-clicked), yet another
alternate write label function is called:

  write_val_annotedcol_autoname <r> <g> <b>

Once an MGH annotation has been loaded, this
function generates a single ASCII label file from
the currently clicked annotation region.  To pick
which region, first click it, which loads its r,g,b
values (into r,g,b fields right of "MESH" button).

This also saves any displayed data currently in
the .val(.val2) into the label (else zero if none
displayed).

The output label file is auto-named using the
current annotation region name, and is written
into the subject's label directory, for example:

  ~/label/rh-R_a9-46v_ROI.label

This allows extraction of annotation region, for
example, to edit it.  Except for output file
name, same as write_val_annotedcol_vertices.

-------------------------------------------
funct: "Write Curr VtxCols to ColsFile (ctrl-right-clk-W)"
  set label <outfile>   [must end in *.cols]
  write_vtxcol_label
-------------------------------------------

If the "W" button is *ctrl*-right-clicked
(instead of default left-clicked), yet another
alternate write label function is called:

  write_vtxcol_label

This writes any visible vertices that currently
have vtxcol "paint" to a new vtxcol file.  The
label file suffix entered in the "label:" line
entry must end in *.cols.  No file is written if
there are no currently visible vertices that have
been vtxcol'd.

Can used to combine vtxcol labels, or to save
vtxcol's generated by linrampphase2vtxcol.

-------------------------------------------
funct: "Write Adjusted Phase to Label (shift-right-clk-W)"
  set label <outfile>
  write_adjphase_vertices
-------------------------------------------

If the "W" button is *shift*-right-clicked
(instead of default left-clicked), yet another
alternate write label function is called:

  write_adjphase_vertices

During normal operation, the complex-valued phase
in Fourier analyzed data is processed on the fly
to generate a tweakable color map.  But the
underlying phase data - which contains offsets
due to hemodynamic delays as well as the starting
stimulus position, as well as phase reversals for
opposite hemispheres - is never modified.

This function provides a way to generate a
complex-valued label with estimated polar angle
that removes those offsets and reversals.

It requires that the original complex-valued
Fourier analyzed polar angle data has been
loaded, and that $angle_cycles is set to a
non-integral value (like 1.0001, to trigger a
polar angle color scale).  This function takes
account of the settings of $angle_cycles,
$angle_offset, $revphaseflag, and $invphaseflag
to write out an adjusted phase.

To obtain a label file containing polar angles
approximately between -pi/2 and pi/2 (positive
for the upper field, and negative for the lower
field, same for either hemisphere) given a
standard 64-sec cycle mapper stimulus starting at
zero degrees (right horizontal meridian) and
progressing in a counterclockwise direction,
adjust those parameters for each hemisphere
approximately as follows, before calling
write_adjphase_vertices:

  ### right hemisphere
  set angle_cycles 1.001
  set angle_offset 0.96
  set revphaseflag 1

  ### left hemisphere
  set angle_cycles 1.001
  set angle_offset 0.46
  set revphaseflag 0

The phases are written out as a 6-arg, ASCII
label file containing amplitude 1 complex
numbers.

Increasing $angle_cycles will linearly expand the
range of polar angles in the output file.  This
can be useful for data averaged across subjects,
where there will be a reduced range of polar
angles due to slight intersubject spatial
offsets, especially in the case of small visual
areas.  This causes a 'regression to the
horizontal meridian' in cross-subject average
data (too much blue).

To interactively check what the output will be,
click a vertex and check the value of "adja" in
the csurf log (final value on the first log line
output from a click on a vertex).  Ignore the
displayed colors (which will be reversed from the
'standard' polar angle scale, which is
lower/horiz/upper -> green/blue/red).

If the resulting adjusted phase label file is
read back in, to verify that the polar angles in
it are correct, click a vertex and look at the
val/val2 phase angle on the third log line output
from a click on a vertex, *not* the value of
"adja", which will now, confusingly, be
re-adjusted.

To see the standard colors for the adjusted data,
set parameters as follows (N.B.: same for both
hemispheres):

  set angle_cycles 1.6
  set angle_offset 0.5
  set revphaseflag 1

-------------------------------------------
funct: "Write StatIDs to RandCol MGH Annot (no hotkey)"
  set label <outfile>
  write_statids2randcolannot
-------------------------------------------

This reads the .stat field, assuming that there
are integers there and writes a random color
annotation file for each unique .stat integer.

Designed to save the results of running:

  neighop_val2stat <neiorder:1-6> <operation=3>
  grow_stat_idnums

The first function generates non-overlapping
patches of nearest vertex neighbor order size
(first- to sixth-order neighbors).  For
fsaverage, the neighbor counts for the different
order neighbors are:

  1-neighbors: 7
  2-neighbors: 19
  3-neighbors: 37
  4-neighbors: 61
  5-neighbors: 91
  6-neighbors: 127

The grow_stat_idnums function then fills in the
gaps as fairly as possible.

This was used to generate simulated cerebellar
granule cell patches.  For more details, see the
R-click help for the SMOOTH button under the
topic "paintballs".

-------------------------------------------
funct: "Sort Label By Dist Last Clicked Vtx (no hotkey)"
  set label <outfile>
  write_sorted_by_pathdist_label
-------------------------------------------

This reads the current label ("label:" entry) and
then sorts the lines in the file by the Euclidean
distance along a path from the last interactively
selected vertex (e.g., the beginning of a
single-vertex-wide label path).  It simply copies
any overlay data that may or may not be included
in the original label file.

The second vertex will be the closest to the
initially selected vertex, the third vertex will
be the closest to the second vertex, and so on
(so this is not equivalent to merely sorting
vertices by distance from the initial vertex).

Standard freesurfer/csurf labels are normally
written in vertex number order (but since the
csurf/freesurfer label-reading code ignores the
order of lines in the label file, the sorted file
will still be readable).  However, an external
program can now use the re-ordered lines in the
sorted output file to find the path order.

This function can successfuly sort a path label
containing a series of vertices along a line that
curves back on itself (as long as it doesn't
cross itself, since there is no linearity
constraint).

N.B.: this function overwrites the input label,
but first saves it aside with a tilde (~) suffix.

This is useful for sampling data (e.g., phase
data) along an arbitrary curved line of vertices.
First, save a standard label from a sequence of
selected vertices (write_val_selected_list_to_label,
or "Selected Vertices to Label" from R-click help
pop-up on "W" on "label:" line) that contains the
phase data you want, then path-sort that line
label using this function ("Sort Label By Dist
Last Clicked Vtx" on same popup).

This was first written to sort the geodesic path
output of mris_pmake.  It is also useful for sorting
a single vertex line label made by selecting
vertices along a line, but not necessarily in exact
path order (e.g., if missed vertices have been
filled in after roughing out the line).

-------------------------------------------
funct: "Write Region Centers to scriptsdir (no hotkey)"
  write_annot_region_centers
-------------------------------------------

This writes out the 3D average location (current
surface coordinates) of the vertices in each
region of an MGH annotation.  The vertex nearest
the average is found and its vertex number
appended.

This average calculation occurs when any label is
read with the "D" button on the "label:" line.

N.B.: the average is calculated from the surface
visible at the time the annotation file was read.
If the surface is subsequently interactively
changed, be sure to re-read the annotation file.

The ASCII file, AnnotRegionCenters.txt, is
written to the subject's scriptdir, e.g.,
$SUBJECTS_DIR/fsaverage/scripts, and looks
like this:

#IDnum  RegionName      Avgx    Avgy    Avgz    NearestVtxNum
#------------------------------------------------------------
#0      Unknown         [omit]
1       V1_lower        -29.51  -117.25 -20.54  9454
2       V1_upper        -27.02  -108.95 -34.63  90544
3       V2_lower        -25.82  -126.61 -14.81  156659
4       V2_upper        -22.74  -111.07 -45.03  62841
5       V3              -23.85  -129.02 -5.84   24153
6       VP              -14.54  -110.01 -49.08  62867
...


####################
label_write_annot
####################

-------------------------------------------
vars,functs (left-click): for assemble labels into annotation
  set lulabel <SomeColorLUT.txt> 
  set anlabel <$hemi-MY_ANNOT.annot>
  write_mgh_annot
-------------------------------------------

This assembles multiple labels into a single MGH
annotation file using the region names (i.e.,
labelfile prefixes) and matching colors from an
MGH FreeSurfer LUT file.

(1) MGH FreeSurfer Color Lookup Table (LUT)
  [default name:]
  $CSURF_DIR/lib/lut/CsurfColorLUT.txt

(2) output .annot file
  [default name:]
  $SUBJECTS_DIR/$subject/label/$hemi-MY_ANNOT.annot

The dropdowns are loaded with all *.txt and
*.annot files in the default directories.

Change the "MY_ANNOT" infix to something more
useful (this is the default to avoid accidental
overwrites).  Here is an example of the format of
an MGH FreeSurfer LUT file (empty lines or lines
starting with '#' are ignored).

#!ascii , CsurfColorLUT.txt (in $CSURF_DIR/lib/lut)
#------------------------------------------
#id	region(=labelinfix)		R      G      B      A
#------------------------------------------
 0	Unknown		0      0       0       0
 1	V1_lower		150   0      100    0
 2	V1_upper		150   0      120    0
14	V3_lower		0      50     200    0
15	VP_upper		0      50     220    0

N.B.: Though csurf tksurfer will accept and
display a FreeSurfer Color LUT containing
non-zero values for column A (alpha,
transparency), MGH tksurfer/freeview requires
that the color LUT value of alpha always be 0
(100% transparent, AKA invisible).  Therefore,
for compatibility, always use 0 as the last entry
in each FreeSurfer Color LUT line.  The
transparency of all labels can be adjusted
afterward with set_annot_alpha.

Each region or structure name (except "Unknown")
must have a corresponding csurf dash-style label
file in the current subject's label directory.
Using the example above for the right hemisphere
of the subject, fsaverage, the following label
files must exist:

  $SUBJECTS_DIR/fsaverage/label/rh-V1_lower.label
  $SUBJECTS_DIR/fsaverage/label/rh-V1_upper.label
  $SUBJECTS_DIR/fsaverage/label/rh-V3_lower.label
  $SUBJECTS_DIR/fsaverage/label/rh-VP_upper.label

If any are missing, they will be omitted from the
final combined annotation file.

Finally, click READY to assemble an MGH
annotation file containing these labels in these
colors.  The new assembled annotation file will
be displayed, followed by the number of hits per
vertex (this will be 2 on borders).  To
re-display the assembled annotation at another
time, select it, and use "D" on the "label:"
line.

The process will fail if there are any duplicate
region id numbers *or* duplicate colors in the
color LUT file (duplicates reported in popup).

The number of hits per vertex (e.g., if labels
overlap) is saved into the .stat field and
swapped to the surface at the end to make it
visible.  To save it, select a new wfile name
(e.g., <annotname>_nhits-$hemi.w) and use "W" on
the "val:" line.  The last label file that
contains a vertex sets the structure name and
color for that vertex in the annotation file.

Vertices on the surface not included in any label
will be given structure name "Unknown" and will
always be displayed as completely transparent
(alpha=0).  The transparency of all other
structures is controlled by the "tran" entry at
the upper right.

How to do this procedure with a tcl script:

  ### set infile (default, but any source OK)
  set lulabel $CSURF_DIR/lib/lut/CsurfColorLUT.txt
  ### set outfile (setfile is csurf-specific glob)
  setfile anlabel ~/label/$hemi-MY_ANNOT.annot
  write_mgh_annot

####################
label_timecourses
####################

#### extract 3D Timecourses ####
-------------------------------------------
funct: "Dump Time-Series from Label Vtxs (left-click-T)"
  set label <outfile>
  write_label_timecourses_stats 0            ;# rawdata
-------------------------------------------
funct: "Same As Above + Avg FT Percent (shift-left-clk-T)"
  set label <outfile>
  write_label_timecourses_stats 4            ;# rawdata + percent
-------------------------------------------
funct: "Dump Time-Series from Annot RGB (middle-click-T)"
  [single output auto-named w/region-name]
  write_annotcol_timecourses_stats r g b 0 ;# rawdata
-------------------------------------------
funct: "Dump Time-Series All Annots (shift-middle-click-T)"
  [multiple outputs auto-named w/region-names]
  write_annotcols_timecourses_stats 0      ;# rawdata
-------------------------------------------
N.B.: for single-voxel timecourse: ctrl-mid-click a vertex


Overview

The "T" button on the "label:" entry line reads a
label file or an MGH annotation file (which are
usually located in the "label" subdir of a
subject directory, but can be anywhere) using the
name in the "label:" entry to the left (variable:
$label, $anlabel).

Rawdata time series for the set of surface
vertices in the label or MGH annotation are
extracted using the current register.dat
transformation matrix in the current scandir.

The rawdata is sampled from the 3D file at one or
more points above the vertex along local surface
normal (see controls below).  Extracted
timecourses are then written to an ASCII file (or
files) in the current scan directory (see below).

Finally, the average timecourse for the entire
label is displayed at the top of the brain
surface window.

There are 4 different versions of this procedure:

 left-click-T:            all vertices in current label
 shift-left-click-T:     same + avg Fourier percent resp popup
 middle-click-T:       use annot vtxs from region w/curr color
 shift-middle-click-T:  all regions in current MGH annotation

See end below for details of file format,
documentation of the search-along-the-normal
parameters, and viewing average and single-vertex
time series.

-------------------------------------------
funct: "Dump Time-Series from Label Vtxs (left-click-T)"
  set label <outfile>
  write_label_timecourses_stats 0    ;# rawdata
-------------------------------------------

A default left-click on the "T" button dumps raw
data timecourses from current label in the
"label:" entry (see below for ASCII output
files -- listed on popup when proc finishes).

-------------------------------------------
funct: "Same As Above + Avg FT Percent (shift-left-clk-T)"
  set label <outfile>
  write_label_timecourses_stats 4    ;# rawdata/percent
-------------------------------------------

The second case (shift-left-click) is the same as
the first but also calculates precent response
across the label.  This only works with complex,
Fourier-analyzed data.  The average percent
peak-to-peak response amplitude returned in the
last pop-up (and the csurf log).

N.B.: this requires that complex raw fourier *3D
stats* (_x,_y) fourier have first been loaded
(i.e., not surface-sampled wfiles -- there will
be an error pop-up if 3D data not loaded).  Load
3D data as follows:

  (1) click "val:" to get "val3d:"
  (2) select _x or _y BRIK
  (3) click "R" (no visible effect)

The peak-to-peak stimulus frequency amplitude is
computed by dividing the raw discrete FT
amplitude at the stimulus frequence (hypot(_x,_y)
by the number of time points, comparing it to the
average voxel amplitude, then converting to
peak-to-peak percent:

               hypot(_x,_y)
 %resp  =  --------------   /   rawavg * 2 * 2 * 100
                timepoints

The first factor of 2 is for pos/neg freqs, and
the second is for peak-to-peak amplitude.

See R-click help for the "val:" line "W" button
for how to get percent response directly from
surface-painted _x,_y data without a timecourse
(requires entering timepoints and average rawdata
timecourse amplitude).

-------------------------------------------
funct: "Dump Time-Series from Annot RGB (middle-click-T)"
  [single output auto-named w/region-name]
  write_annotcol_timecourses_stats r g b 0    ;# rawdata
-------------------------------------------

For the third alternate case, first load an MGH
annotation file by selecting one from the
dropdown followed by "R" on the "label:" line.

Then load a single RGB color from a region in
that MGH annotation by clicking the region
(colors load to the entries to the right of the
"MESH" button; region names will be visible in
the csurf log).

The extracted timecourses will come from that
single region in the MGH annotation.

-------------------------------------------
funct: "Dump Time-Series All Annots (shift-middle-click-T)"
  [multiple outputs auto-named w/region-names]
  write_annotcols_timecourses_stats 0    ;# rawdata
-------------------------------------------

The final fourth case is like the third, except
that data from every one of the different regions
in the annotation will be dumped (takes a while).


ASCII Output files (3)

For a default left click of "T", three ASCII
output files will have names constructed from the
name of label file (same format for both MGH
'dot' style or UCSD/UCL 'dash' style label
files).  For example:

  rh.MT.label ->

     rh.MT.raw
     rh.MT.xyz
     rh.MT.avg

or:

  rh-MT.label ->

     rh.MT.raw
     rh.MT.xyz
     rh.MT.avg

For a middle-click or shift-middle click used to
extract MGH annotation file rawdata, the file
names will all contain an infix "region" followed
by the structure name in the annotation file.
For example:

  rh.region_S_central.raw
  rh.region_S_central.xyz
  rh.region_S_central.avg

The first output file is the timecourses file
(*.raw), which has a one-line header (format,
data size, sources) followed by a series of
lines, one for each vertex.  Each line contains
the vertex number, the original-surface floating
point surface coordinates used for sampling
(surfx, surfy, surfz), the integer indices of the
(non-unique) sampled rawdata (rawx, rawy, rawz)
voxel, the MNI Talairach coordinates (talx, taly,
talz) of the surface points, and finally the
rawdata voxel brightness values for each time
point.  For example:

#!ascii , fmt (justtime): vtx surfx surfy surfz \
  rawx rawy rawz talx taly talz t1 t2 ... t512 \
  (lab=lh-MY_AREA.label, raw=pol+orig.BRIK, \
   n=201, normdfracsamp=0.00, uniqvfl=0)
 21465 -9.50 -66.50 -9.50 14 26 19 602 615 601 ...
 21483 -11.50 -66.50 -11.50 15 23 9 562 556 554 ..
 ...
 [foreach vertex in label file]


Norm search parameters

The rawdata timecourse is extracted at one or
more points along the vertex normal.  This
operation is controlled by 7 settings at the
bottom of the SessionTools -> Setup Funct Scan
panel.  These setting also control the PAINT
operation:

  "NormSrch:" (units: "mm" or "frac" of thick)
  "mn/mx:" (limits along normal)
  "dx:" (step size along normal)
  [PAINT operation] "mx" or "av" or "nm"
  "NormSrch" (point or search)
  "Same" (freesurfer vs. same-vtx thickness)
  "UniqVox" (first vtx to sample a voxel gets it)
  "UniqVtx" (vtx nearest avg of set sampling vox wins)
  "Alldx" (write out tseries for each depth)
  "AllVtxs" (don't omit vtxs off edge of funct scan)

See Help -> Setup Align/Funct Scans for more
details.  The default is to sample a point midway
between min and max using the fractional distance
between the white and pial surfaces.

These parameters can also be adjusted
interactively in tksurfer by left-clicking
"label:", which brings up a pop-up panel.
Currently, normdop (0=max, 1=avg, 2=min) only
affects the tksurfer paint button, "PAINT"
(left-click "val:" to make the PAINT button
visible).

The surfx,surfy,surfz coordinates are from the
$origcoords surface, typically $hemi.orig or
$hemi.white (not the current surface).  Surface
coordinates read out of label file are ignored.

The rawx,rawy,rawz coordinates are in raw BRIK
order, ignoring any orientation information in
the HEAD (so the BRIK file can be read by
itself):

  for (t=0; t<rawdata_tdim; t++)
    for (z=0; z<rawdata_zdim; z++)
      for (y=0; y<rawdata_ydim; y++)
        for (x=0; x<rawdata_xdim; x++)
          rawdata[t][z][y][x] = one_time_point;

If the surface vertex location is off the edge of
the rawdata block, the integer rawx,rawy,rawz
indices are all set to -1, and the rawdata voxel
values are all set to 0.

By default the timecourses in the first output
file are not unique; for typical fMRI data, more
than one vertex will sample the same rawdata
timecourse voxel since surface vertices are
closer together than typical fMRI voxels (see
details in Help -> Setup Align/Funct Scans).

The second output file (*.xyz) contains unique
rawdata voxel indices intersected by label
vertices for indexing into the rawdata BRIK.

The third output file (*.avg) contains the
average timecourse.


Norm search args for tksurfer

  -regdat <registerdatfile>
  -rawdata <rawdata>+orig.BRIK
  -normdfracflag <0=mm,1=frac>
  -normdfracsamp <float:def=0.4>
  -normdfracmax <float> [used if search]
  -normdsamp <float:def=1.0(mm)>
  -normdmax <float> [used if search]
  -normdsampsearchflag <0,1>
  -normdsampuniqvoxflag <0,1>
  -normdsampuniqvtxflag <0,1>
  -normddstep <float:mm=0.25, frac=0.1>
  -samevtxthickflag <0,1>
  -stimcycles <int:def=8>
  -showavgcycflag <0,1:def=1>
  -rawdatarange <float:def=0.0=auto>

The procedure can also be performed from the
tksurfer tcl prompt (or a tcl script) where
$scandir is name of scan directory inside "image"
subdir inside the current session.  The current
scandir can be abbreviated with a '*' and the
current subject dir with a '~' using setfile (a
globbing 'set').  For example:

  setfile regdat */$scandir/register.dat
  read_regdat
  setfile rawdata */$scandir/<rawdata>+orig.BRIK
  read_rawdata
  setfile label ~/label/rh-MT.label
  ## use next for mm
  set normdsamp 1.0
  ## use next for fraction of thickness
  set normdfracsamp 0.4
  ## arg is: 0=timecourses,1=stats,2=both
  write_label_timecourses_stats 0

    => output files: */$scandir/rh.MT.raw
                     */$scandir/rh.MT.xyz

If the current hemisphere thickness file is
present (tksurfer will automatically read it if
it is found) and -normdfracflag is set, the
rawdata will be sampled at the requested fraction
of cortical thickness along normal above each
vertex (option: tksurfer ...  -normdfracsamp
<frac>, or tcl: set normdfracsamp <dfrac>).  If
no thickness file is present, absolute distance
above vertex in mm will be used instead (option:
tksurfer ... -normdsamp <mm>, or tcl: set
normdsamp <mm>).

A search along the normal will be performed if
-normdsampsearchflag is set with limits set by
normd{frac}samp and normd{frac}max.

The first time that timecourses are extracted for
a label file (or for ctrl-middle-clicking a
vertex -- see below), there will be a short delay
to read the entire raw data file into memory.  To
re-read a different rawdata file with the same
surface displayed, use tcl commands, or restart
tksurfer with new args (e.g., from csurf).  The
tiny register.dat file is re-read every time.


Average timecourse display across label/annotation

A simple average of the timecourses from the
label is computed and displayed (N.B.: for
phase-encoded data, label should approximately
follow an isopolar or isoeccentricity line
to keep phases from cancelling each other).

The average timecourse line will be colored
according to the current color scale after
averaging the .val (real data) or both
.val and .val2 (complex data) from the
data currently present on the surface (which is
normally derived from the avg raw data timecourse
being displayed).

If stats read in are complex, average cycle is
drawn under the timecourse by default, using a
thicker, slightly dimmer line (to turn off avg
cycle underlay: tcl: set showavgcycflag 0).

By default, the rawdata range is autoscaled for
each new timecourse plot (to see directly
comparable de-meaned data values: tcl: e.g., set
rawdatarange 100).


Display single vertex timecourse

To simply display the rawdata timecourse for a
single vertex in the tksurfer window, do
ctrl-middle-click on a vertex (no need to first
select it).  This will also write out (append)
that vertex to an ASCII file in the current
scandir:

    */$scandir/rh.selected.raw

This file has the same format as the timecourses
files above.  To clear timecourse(s) from the
tksurfer window, click "REDRAW" (or R-click,
which clears marked vertices and also does an
auto "REDRAW").

For Fourier-analyzed data, the timecourse will be
colored using the current (e.g., phase-sensitive)
color scale.  In addition, the number of
stimcycles will be used to collapse the time
course to a single cycle, which will then be
repeated stimcycles times in a thicker line
underneath the timecourse.  Finally, the precent
response for this voxel will be printed in the
csurf log.

By default, the previous single voxel timecourse
is cleared.  To cause prevent clearing in order
to overlay multiple single-voxel timecourses, set
the C/tcl variable multitimecourseflag to 1.

N.B.: If you "W" (write) an rgb file, the window
will be raised and redrawn first, which will
erase the graph(s).  If you want to save the
onscreen timecourse(s) and cyan cursors, use the
"WN" (write, no raise/redraw) button to the right
of "W" button instead (be sure no windows are
obscuring the tksurfer window before displaying
timecourses since the "WN" button does not raise
window).

####################
label_stat
####################

#### extract 3D Stats + Timecourses ####
-------------------------------------------
funct: "Dump Stat+TimeSeries at Label Vtxs (left-click-S)"
  set label <outfile>
  write_label_timecourses_stats 2                ;# stat+raw
-------------------------------------------
funct: "Dump Stat+TimeSer at Annot RGB (middle-click-S)"
  [single output auto-named w/region-name]
  write_annotcol_timecourses_stats r g b 2   ;# stat+raw
-------------------------------------------
funct: "Dump Stat+TimeSer All Annots (shift-middle-clk-S)"
  [multiple outputs auto-named w/region-names]
  write_annotcols_timecourses_stats 2         ;# stat+raw
-------------------------------------------

###### extract 3D Stats only ######
-------------------------------------------
funct: "Dump Just Stat at Label Vtxs (ctrl-left-click-S)"
  set label <outfile>
  write_label_timecourses_stats 1;               ;# stat only
-------------------------------------------
funct: "Dump Just Stat at Annot RGB (ctrl-middle-click-S)"
  [single output auto-named w/region-name]
  write_annotcol_timecourses_stats r g b 1   ;# stat only
-------------------------------------------
funct: "Dump Just Stat All Annots (shift-ctrl-middle-clk-S)"
funct (shift-ctrl-middle-click): write stat each annot region
  [multiple outputs auto-named w/region-names]
  write_annotcols_timecourses_stats 1         ;#stat only
-------------------------------------------


The "S" button on the "label:" entry line
performs the same operation as the "T" button
(dump ASCII 3D data for a set of surface
vertices) but also includes samples of 3D volume
stats file (possibly complex) in the ASCII output
file (immediately before the timecourse).  If
ctrl is pressed in addition, then *only* stats
are dumped (no timecourses).

As with the "T" button, the set (or sets) of
surface vertices whose timecourses are dumped is
determined by:

 left-click:               all vertices in current label file
 middle-click:          annotation vtxs from region w/curr col
 shift-middle-click:   all regions in current annotation

In the second case, first load a color by
clicking a region in the MGH annotation (colors
load to the entries to the right of the "MESH"
button; region names will be visible in the csurf
log).

See the R-click help for "T" for details.
Left-click "label:" to get a pop-up for
interactively controlling the norm search
parameters.

As with the "T" button, this requires that the
option, -rawdata, has been given to tksurfer to
specify the rawdata file.

In addition, the 3D volume stats file must be
loaded with -real3d (and optionally -imag3d and
-mask3d), or interactively loaded by first
clicking "val:" to change it to "val3d:", and
then clicking the "R" button to read the 3D
volume(s).

It is not necessary to click the paint button,
"PAINT" (though this can be done to view the 3D
stats volume on the surface).

Args for tksurfer:

  -regdat <registerdatfile>
  -rawdata <rawdata>+orig.BRIK
  -real3d <stem[_r]{+orig.BRIK,_%03d.bfloat}>
  -imag3d <stem_i{+orig.BRIK,_%03d.bfloat}>
  -mask3d <stem_s{+orig.BRIK,_%03d.bfloat}>

As with the timecourse button, "T", for label
files, the two extracted ASCII output files (for
MGH 'dot' style or UCSD/UCL 'dash' style label
files) are named as follows (first suffix has
comma; "stat,raw"):

  rh.MT.label  -> rh.MT.stat,raw, rh.MT.xyz
  rh-MT.label  -> rh.MT.stat,raw, rh.MT.xyz

and for extractions using an MGH annotation, the
file names will use the structure name in the
annotation file as an infix:

  rh.region_S_central.raw
  rh.region_S_central.xyz


####################
label_corr
####################

#### searchlight correlation in label ####
-------------------------------------------
funct: "SearchLight CrossCorr at Label Vtxs (left-click-X)"
  set label <infile>     [constraint region from label file]
  corr_over_label <neitype> <crit> <cmptype>
-------------------------------------------
funct: "Searchlight CrossCorr at Annot RGB (mid-click-X)"
  [constraint region from r,g,b of annotation]
  corr_over_annotcol <neitype> <crit> <cmptype> <r> <g> <b>
-------------------------------------------
funct: "Calculate RawData Covariance (shift-left-click-X)"
  rawdatasubbrik_to_paintable 0
  paint_surface 0
  find_uniqsamp_vertices
  calc_rawdata_covar
-------------------------------------------
funct: "Write RawData Covariance (shift-mid-click-X)"
  write_rawdata_covar
-------------------------------------------
funct: "Read RawData Covariance (shift-mid-click-X)"
  read_rawdata_covar
-------------------------------------------
funct: "Display Correlation for CurrVectex (shift-right-click-X)"
  [select vertex]
  copy_rowcovar_val
-------------------------------------------


The "X" button on the "label:" entry line
performs searchlight cross correlations within a
label or annotation region, and can also
calculate, write, and display covariance of raw
data time series.


Detailed Description of Label "X" Button Actions

-------------------------------------------
funct: "SearchLight CrossCorr at Label Vtxs (left-click-X)"
  set label <infile>     [constraint region from label file]
  corr_over_label <neitype> <crit> <cmptype>
-------------------------------------------
funct: "Searchlight CrossCorr at Annot RGB (mid-click-X)"
  [constraint region from r,g,b of annotation]
  corr_over_annotcol <neitype> <crit> <cmptype> <r> <g> <b>
-------------------------------------------

The first two functions are identical searchlight
cross correlations performed within a region
defined by either a tksurfer label or a single
colored region in an MGH annot file.  This is
done to constrain this potentially time-consuming
operation.  To cover the entire cortex, simply
FILL everything.

The tksurfer.tcl wrapper function used to run
corr_over_label and corr_over_annotcol is:
corrctrls (which calls do_corr).

Calculate Pearson Product-Moment Correlation:

                 Sum[(x - xav)*(y - yav)]
corr =   -----------------------------------
          sqrt[Sum(x - xav)^2 * Sum(y - yav)^2]

between two vertexwise data sets for a set of
searchlights that each include nearest neighbors
extending to a radius defined by simple vertex
count, surface area (mm^2), or radius (mm).  The
correlated values x and y at each vertex can each
be either real numbers or complex amplitudes (see
below).

If there are two complex-valued inputs and
comparison type ($cmptype) 4 is chosen, a
circular correlation is performed instead:

                 Sum[sin(x - xav)*sin(y - yav)]
corr =  ----------------------------------------
        sqrt[Sum[sin^2(x - xav)] * Sum[sin^2(y - yav)]]

where x and y are now angles at each vertex, and
xav and yav are now angular averages (computed by
normalizing complex input vectors before vector
averaging).

The set of searchlight centers is defined by a
label (left-click the "X") or by a single MGH
annotation region r,g,b color (middle-click the
"X" after picking a region with a left-click).

Loading Input Data Sets

In addition to a label specifying the searchlight
centers, this function requires that two data
sets (each can be either real or complex) to
correlate have been loaded into the visible
.val(.val2) data field(s) and the invisible
.valbak(.val2bak) data field(s).

This can be done by reading wfiles (*.w or
*.curv/area or 1D *.mgh, *.vtk, *.gii), or label
files (*.label).  It is OK to mix, but if you
read a label, don't forget to reload the label
specifying searchlight centers afterward.

To read the values in a wfile (or 1D .mgh file)
into the val field(s), use the "R" button on
"val:" line, which uses the tcl funct
read_binary_values.  This will auto-detect the
following formats:

  *.w -- freesurfer wfile, usu. vertex subset
  *.w/*.curv -- new curv/area, req's data all vtxs
  *.mgh -- 1D float real data (req's *.mgh suff)
  *.vtk -- 1D ASCII real (req's *.vtk suff)
  *.vtk-like -- 1D ASCII beginning w/POINT_DATA
  *.gii -- single-frame vertex-data GIFTI file

To read values in a *label* into the val field(s),
use use the "R" button on the "label:" line (which
uses the tcl funct read_label_to_val).

How to Load the Second Data Set

There is a stack of possible values at each
vertex.  Only the top (or top pair) is visible on
the displayed surface (the .val field for
real-valued data if complexvalflag is 0, or the
.val/.val2 fields for complex-valued data if
complexvalflag is 1).  The stack looks like this:

    val         (always visible)
    val2       (visible if complexvalflag is 1)

    stats       (invisible)
    pval       (invisible)

    valbak    (invisible)
    val2bak  (invisible)

To swap values between real and imaginary fields
on the top (visible) part of the stack, use a
middle-click on "S/V":

  swap_val_val2

To swap *pairs* of values between top (visible)
and bottom (invisible) parts of the stack, use
a shift-middle-click "S/V":

  swap_valval2_valbakval2bak

N.B.: also use this to swap just the top and
bottom real values (val and valbak).

Output Correlation Coefficient

The correlation is calculated and saved in the
.stat field.   If the operation is done by clicking
the "X" button in the interface, the result will
displayed when done.   In a tcl script, when the
functions corr_over_label or corr_over_annotcol
finish, do swap_stat_val and reset the colscale
(see example below).

To display a .stat, which is normally invisible
(only visible effect is optional stat masking),
the .stat has to be swapped to the visible .val
field.  A counterintuitive effect of this is when
clicking on a vertex, the swapped .stat value
will now be reported as "val" (the number
reported as "stat" will be whatever was
previously in the "val" field).

Output Correlation Coefficient

The vertexwise output correlation coefficient
will automatically be saved as a wfile with a
prefix taken from the "xcorr_outstem" entry on
the pop-up, and an "_s" infix ("_r" is in use for
real values).  The file will be saved in the
parent directory of the current "val:" file (asks
overwrite).

Alternate Output Z-Score

To save a z-score instead of the correlation
coefficient (z = atanh(r)), tick "r2zscoreflag".
In this case, the output file will have a "_z"
infix.

The correlation coefficient (or z-score) can also
be saved afterward to an ASCII label using the
"W" on the label line.  To save only the vertices
over which the correlation was performed, first
click "C" (recut current label) on the "label:"
line before saving (else the label will contain
all vertices).

Alternate Output -- Covariance

If the "xcorrcovarflag" in the Searchlight
Correlation popup is ticked, the numerator of the
Pearson (or circular) correlation equation is
instead divided by the number of vertices, and
the result is saved in .stat instead of the
correlation (or circular correlation).  The
p-value of the correlation is calculated as usual
(see next), but the then correlation (r) itself
is discarded.

The output wfile will have the same "_s" infix as
the correlation coefficient output.

N.B.: "xcorrcovarflag" is incompatible with
"r2zscoreflag".  You will have to untick one or
the other to procede.

Output p-Value for Circ Correlation Coefficient

This is calculated as follows:

  avgssx = 1/n * Sum[sin^2(x - xav)
  avgssy = 1/n * Sum[sin^2(y - yav)
  avgssxy = 1/n * Sum[sin^2(y - yav) * sin^2(y - yav)]
  t = sqrt((n*avgssx*avgssy) / avgssxy) * corr
  p = 2.0 * (1.0 - normcdf(fabs(t)))

N.B.: the equations for circular correlation as
well as the p-value calculations in Berens (2009)
(http://www.jstatsoft.org/v31/i10) contain
multiple errors, but the associated MATLAB code
is correct.  For the correct equations, go, for
example, here:

  http://ncss.wpengine.netdna-cdn.com/wp-content/themes/ncss/pdf/Procedures/NCSS/Circular_Data_Analysis.pdf

For convenience in using tksurfer color scales,
the output p-value is saved as the positive power
of ten (e.g., p<0.01 is saved as 2):

  vertex[i].pval = -log10(p)

The maximum positive p-value exponent is clamped
to 37.

To view (or save) the p-value, first swap it to
the visible position using the tcl function
swap_pval_val.  This can be done interactively
with a shift-left-click on the S/V button.

Searchlight Operation and Parameters

For a left-click on "X", the searchlight centers
are defined by every vertex in the file ($label)
that is currently in the "label:" field.  The
label doesn't have to be displayed.  the 2nd
through 5th (or 6th) entries on each label line
are ignored, so a 2-line label header (#!ascii,
vertexcount) followed by a single column of
vertex numbers is a sufficient label here.

For a middle-click on "X", the searchlight
centers are defined by every vertex in an
individual MGH annotation region with a certain
r,g,b color.  To select a region, load an
annotation (with "D") and click a vertex in one
of the regions to capture this region's color in
the r,g,b fields (to the right of the MESH
button) before middle-clicking the "X" button.

The vertices are first sorted by distance from
each center vertex by Euclidean distance.  To use
approximate geodesic distances (shortest
distances along the surface), use the inflated
surface.  Using a folded surface will instead
find the nearest vertices within a sphere around
each center vertex; this approximates a standard
searchlight in 3D, but one that is helpfully
restricted to the gray matter.

The number of vertices in the searchlight can be
specified directly (by number), or by however
many vertices are required to reach a specified
surface area (in mm^2), or a specified radius
(entered in mm).

To see the size of given searchlight, left-click
somewhere on the surface, and use the bottom
right "N", "A", and "R" buttons ("UNDO" to
restore surface).

When "X" is clicked, a popup first appears with 3
adjustable parameters that control the
searchlight, with the following definitions:

  $fillneartype (int: 0-2)

    0: corr over nearest n neighbors
    1: corr over nearest up to area
    2: corr over nearest up to radius

  $num_sqmm_mm (criterion, int or float)

    fillneartype=0: number of vertices
    fillneartype=1: area in mm^2
    fillneartype=2: radius in mm

  $cmptype (int: 0-4)

    0: real/real
    1: complex-amp/real
    2: real/complex-amp
    3: complex-amp/complex-amp
    4: complex-phase/complex-phase (circular corr)

The last parameter controls how the data loaded
into the val (val2) and valbak (val2bak) fields
at each vertex is treated.  There will be an
error if any of the required members for a
$cmptype have not been loaded.

    0: val <==> valbak
    1: amp(val,val2) <==> valbak
    2: val <==> amp(valbak,val2bak)
    3: hypot(val,val2) <==> hypot(valbak,val2bak)
    4: atan2(val,val2) <==> atan2(valbak,val2bak)

To illustrate the progess of the searchlight
without slowing it down, the center of one out of
every 200 searchlights computed are marked on the
surface.

Note that once the value fields have been loaded,
there is no check as to whether the fields are
stale relative to the current selection of
$cmptype.  For example, one could load two
complex-valued data sets, then perform a spurious
real-to-complex comparison.

To clear all fields before starting, do a
middle-click on the CLR button on the "val:" line
(*not* the CLR button on the "label:" line).
This clears:

  vertex[i].val
  vertex[i].val2
  vertex[i].valbak
  vertex[i].val2bak
  vertex[i].stat
  vertex[i].pval
  vertex[i].uniqvoxnum
  vertex[i].uniqvoxcnt

Use Representative Vertices (upsampling correction)

If "searchlightuniqflag" in the Searchlight
Correlation popup is ticked, each Pearson or
circular correlation searchlight is calculated
across 'representative' unique vertices -- that
is, using only one vertex for each uniquely
sampled 3D stat voxel.

This overcomes surface-based upsampling, the
result of a surface mesh that is typically finer
than standard 3D functional data sets (i.e., each
functional voxel is typically nearest-neighbor
sampled to more than one 2D surface vertex).

Unique vertices for each 3D functional voxel
(vertex in set sampling a single voxel nearest
the average location of all vertices in the set)
must first be calculated.  To do this, click
"val:" to get "val3d:" and do:

 1) select 3D stat BRIK from "val3d:" dropdown
 2) read 3D data with "val3d:" "R" button
 3) sample 3D data to surface with "PAINT"
 4) click UQ

The searchlight will still be calculated for
every vertex, but will only use 'representative'
vertices for calculating correlations.  This
resulting picture is less smooth and will require
a larger searchlight (still measured by
number/radius/area using all vertices) to obtain
the same number of data points to correlate.

To force the same number of vertices to be used
for each searchlight when "searchlightuniqflag"
is ticked, use fillneartype=0 (num of vertices)
and also tick "numafteruniqflag".  Note that this
expands the overall area of each searchlight in
order to make up for the skipped vertices.

---------------------------------
Example -- real-cplxamp by interface clicks
---------------------------------

## load 2nd data set (e.g., real)
select valfile from "val:" dropdown
read valfile ("R" on "val:" line)
           or
select labelfile from "label:" dropdown
read labelfile to val ("R" on "label:" line)

## swap pair (empty imaginary OK) to bottom of stack
shift-middle-click "S/V"

## load 1st data set (e.g., complex-valued)
select real (or imaginary) valfile from "val:" dropdown
read valfile ("R" on "val:" line)
=> auto-reads both real, imaginary
           or
select complex-valued labelfile from "label:" dropdown
read label file ("R" on "label:" line)

## select label for searchlight centers
select labelfile from "label:" dropdown

## set searchlight parms (7mm radius) and run corr's
click "X", and enter paramters in popup
  fillneartype -> 2          ;# use radius
  num_sqmm_mm -> 7.0  ;# 7 mm
  cmptype -> 1             ;# compare complex-amp to real
click "READY"
confirm choices and click "Searchlight Correlation"
=> takes a few minutes

## view result
when done, .stat field result swapped, colscale reset

---------------------------------
Same example -- by tcl script
---------------------------------

## load 1st data set (e.g., real), move to .valbak
setfile */scan1/scan+orig-lh_a.w
read_binary_values
swap_valval2_valbakval2bak
## load 2nd data set (e.g., complex-valued)
setfile */scan1/scan+orig-lh_i.w
read_binary_values
swap_val_val2
setfile */scan1/scan+orig-lh_r.w
read_binary_values
## set label of vtxs for searchlight centers
setfile */scan1/lh-searchregion.label
## searchlight
set fillneartype 2
set num_sqmm_mm 7.0
set cmptype 1
corr_over_label $fillneartype $num_sqmm_mm $cmptype
## view
swap_stat_val
set complexvalflag 0
set revphaseflag 0
set colscale 6
set fthresh 0.001
set fmid 0.6
set fslope 2.0
redraw

-------------------------------------------
funct: "Calculate RawData Covariance (shift-left-click-X)"
  rawdatasubbrik_to_paintable 0
  paint_surface 0
  find_uniqsamp_vertices
  calc_rawdata_covar
-------------------------------------------

This function calculates a covariance matrix for
a raw time-series data (AFNI BRIK containing
shorts) after sampling it to the surface, using
current parameters for distance along the local
surface normals.  To constrain the size of the
covariance matrix and avoid redundantly sampling
the data, 'representative vertices' are used.

A 'representative' (unique) vertex is the one
closest to average location of all the vertices
that have sampled one voxel.  The first three
functions generate the 'representative' vertex
subset.  For one hemisphere, this will be about
13K vertices (out of about 140K) for a 3.2 mm
width functional scan.

Each covariance matrix entry (for a pair of
vertices) is computed in the usual way as follows
(sum is across t):

           Sum[(v1 - v1_avg) * (v2 - v2_avg)]
corr =   -----------------------------------------
                               n - 1

which results in a symmetric matrix with
variances along the diagonal.  Before running
this function the policy for sampling the 3D
along the local surface normal should be set
(left-click the "label:" label to get a popup).
First tick or untick:

  normdsampsearchflag     # turn norm search on/off
  normdfracflag                # choose fraction of ctx thk vs. mm

then, depending on the state of the second flag,
set one of the following two pairs to the same
value (i.e., sample at a point):

  normdmax       # max sample dist in mm
  normdsamp     # min sample dist in mm

or:

  normdfracmax      # max sample dist in ctx thk fraction
  normdfracsamp    # min sample dist in ctx thk fraction

Then load a raw data time series (and
register.dat) as follows:

 1) click "val:" to toggle it to "val3d:" 
 2) click "RD" to get read rawdata popup 
 3) select rawdata BRIK from popup "val3d:" dropdown 
 4) click "READ RAWDATA and REGISTRATION"

Finally, R-click the "X" button on the "label:"
line to get a buttonbar popup and click
"Calculate RawData Covariance" (or
shift-left-click-X).  This takes about a minute.

The result can be written out, or a row of the
matrix can be displayed using the two functions
below.

N.B.: to see the 'representative' vertices, click
"UQ" on the "val3d:" line after "Calculate
RawData Covariance" has run.

-------------------------------------------
funct: "Write RawData Covariance (shift-mid-click-X)"
  write_rawdata_covar
-------------------------------------------

The covariance matrix can be written out as a
headerless binary file of floats, which will be
given a standard name in the current $scandir:

  $hemi-CovarianceMatrix.float

The indices of the rows and columns of this
covariance matrix are the sequentially numbered
'representative' vertex subset.  So in addition,
an ASCII file of the original full-surface vertex
numbers of these 'representative' vertices will
be written to:

  $hemi-CovarianceMatrixVnums.txt

The headerless binary file of floats is written
in standard freesurfer byte order (MSB).  Use
AFNI 4swap to convert to Intel (LSB) byte order
before reading the binary data into an external
program expecting LSB byte order.  For example:

  4swap rh-CovarianceMatrix.float

-------------------------------------------
funct: "Read RawData Covariance (shift-mid-click-X)"
  read_rawdata_covar
-------------------------------------------

This function reads the two files written above
(if they exist), so correlations can immediately
be displayed without re-calculating the
covariance matrix.

N.B.: this won't work right if the *.float file
has been 4swap'd to LSB :-}

-------------------------------------------
funct: "Display Correlation for CurrVectex (shift-right-click-X)"
  [select vertex]
  copy_rowcovar_val
-------------------------------------------

To display a row of the covariance matrix
(correlations for particular vertex), select a
vertex and click "Display Correlation for
CurrVertex".

First, the unique 'representative' vertex nearest
the selected vertex is found.

This index is then used to copy a row of the
covariance matrix to each other representative
vertex.  Before display, this data is first
sparse-smoothed (i.e., representative vertices
are fixed and only surrounding undefined vertices
are interpolated), for 20 steps. This uses the
C/tcl function, smooth_val_sparse, which can be
accessed directly from the SMOOTH button with the
"sp" option.

Finally, the first time a correlation is
displayed, the following sane colscale parameters
are set.  The tcl command used are:

  copy_rowcovar_val
  smooth_val_sparse 20
  set overlayflag 1
  set complexvalflag 0
  set statmaskampflag 0
  set truncphaseflag 0
  set colscale 11
  set fslope 0.1
  set fthresh 5.0
  set fmid 10.0


####################
val2rgb
####################

-------------------------------------------
entry variable: $val2rgblut -- abs name col LUT file
-------------------------------------------
default: */$scandir/val2rgb.lut

The "lut:" entry shows the current color lookup
table (LUT) file (usu. not loaded at initial
startup).  To load a color look up table, select
one from the "lut:" dropdown and click "R".

The color look-up table (LUT) file name is used
with colscale=12 (colorscale radio button "lt",
real-valued color scale), colscale=13 (complex
amplitude), and colscale=14 (complex phase).

Left-click the "Col:" label to get a pop-up with
all of the color scales (incl. 13 and 14).

This file can have any name and be saved to and
read from anywhere, but by default, and in order
to be automatically read on tksurfer startup, it
is inside the current scandir, e.g.:

 $FUNCTIONALS_DIR/110219MS/image/scan1/val2rgb.lut

Color LUT for Real-Valued Data

Here is an example of the ASCII file format for a
positive real-valued color scale ranging from
gray->red->blue->green:

## default val->color lookup table (req: ascending)
# val   red     green   blue
0.0     88      88      88
1.0     255     0       0
2.0     0       0       255
3.5     0       255     0

The val's are floating point data numbers,
possibly negative, that have to be in ascending
order (non-ascending entries skipped).  The table
entries do not have to be evenly spaced.

The r,g,b colors are each 0-255.  Empty lines and
comment lines (lines starting with '#') are
ignored.

Interpolated, Bottom-Edge, ZeroSymmetric Flags

Three flags ("intp", "bot", "sym", at the upper
right, above "lt" radiobutton) control the
interpretation of the value-to-RGBcolor entries
in the color table.  There are 8 different
possible combinations of these three flags.  The
last two flags only affect LUT's for real-valued
data or complex-valued amplitude (for
complex-valued phase data, see below).

Interpolated vs. Non-interpolated LUT

If $interpolatelutflag is 1 ("intp" ticked at
upper right), the r,g,b entries in the table are
linearly interpolated to the next table entry for
intermediate data val's.

If $interpolatelutflag is 0 ("intp" unticked),
the r,g,b color stays constant until the next,
possibly unevenly spaced, table entry.

Here is a tcl script that reads the real-valued
look-up table above and displays data with
interpolation first OFF, then ON:

   set val2rgblut /tmp/zz.lut
   read_val2rgblut
   set fthresh 0   ;# no trunc
   set colscale 12
   set interpolatelutflag 0
   redraw
   set interpolatelutflag 1
   redraw

Bottom-Edge-Defined vs. Center-Defined Colors (real)

If $botedgelutflag is 1 ("bot" ticked at upper
right), the r,g,b entries in the table specify
the data value for the bottom of the range of a
color.  In this case, the displayed color changes
(or is interpolated), as the data value hits (or
approaches) the value of the next entry.

If $botedgelutflag is 0 ("bot" unticked), the
r,g,b entries in the table specify the data value
for the center of a color.  In this case, the
displayed color changes (or is interpolated), as
the data value hits (or approaches) the midpoint
value to the next entry.

Center-defined colors are perhaps more intutive.
Bottom-edge defined colors are easier to use when
you want to define/mark specific contours.

Zero Symmetric vs. One-Sided (bottom) Threshold (real)

Finally, if $zerosymmfadeflag is 1 ("sym" ticked
at upper right), (s)fthresh and (s)fmid will cut
into the color scale symmetrically in both
directions from zero.

If $zerosymmfadeflag is 0 ("sym" unticked),
(s)fthresh and (s)fmid cut into the color scale
only from the bottom.

When this flag is set ("sym" is ticked), there is
a secondary effect when "bot" is also ticked
(bottom-edge defined colors).  The "bottom" range
of a color for *negative* values is flipped.
That is, the value for the bottom range of a
color is always nearest zero, from either above
zero or below zero.

Color LUT files complex-valued phase

If $colscale 12 ("lt" radio button) is first
selected, and then $complexvalflag is set to 1
("cpx" clicked), then a *phase* color LUT file is
expected instead ("lt" radio button is
unclicked), which is "ltw", $colscale 14.  This
can be selected directly by left-clicking the
"Col:" label to get the all-colorscales popup,
and then selecting the "ltw" button.

In this case, val's (first column) should begin
at 0.0 and end at 1.0, and the colors for 0.0 and
1.0 should typically be the same if you want the
phase colors to wrap around smoothly.  If
$interpolatelutflag is turned off, discrete
colors are used as if $botedgelutflag was ON.
There is no effect of changing $botedgelutflag or
$zerosymmfadeflag with this colscale.

You can write out an example file like this by
clicking the phase color wheel ("w1") and writing
out a LUT file ("W" to right of "lut:" entry).
Note that the *currently displayed* color scale
is written out -- i.e., it will incorporate any
effects of $revphaseflag, $angle_offset, and
$angle_cycles.

Here is an example of a LUT for complex phase
suitable for hand-editing (R->B->G):

## default val->color lookup table
# val   red     green   blue
0.0     255      0       0
0.3333  0        0     255
0.6667  0      255       0
1.0     255      0       0

N.B.: The *display* of phase color LUT's is
affected by $revphaseflag and $angle_offset (but
not by $angle_cycles, which is equivalent to
changing the look up table as opposed to just
rotating or reversing it).  Because of this, to
re-display a phase color LUT just written without
change, turn off $revphaseflag and set
$angle_offset to 0.0 after re-reading the LUT.

Color LUT files complex-valued *amplitude*

Finally, a color LUT can be used to display the
complex-valued *amplitude*.  This color is set
interactively by left-clicking the "Col:" label
to get the all-colorscales popup and selecting
the "lta" button.

Here is how to do this in a tcl script (similar
would work for other LUT colscales, too):

  setfile val2rgblut my-cplx-amp.lut
  read_val2rgblut
  set complexvalflag 1
  set colscale 13
  redraw

HOWTO write LUT for current color scale

See help for the "W" button for more details.
Note that the written-out color table potentially
takes into consideration the state of all of
these parameters (depending on whether data
is real or complex):

  $complexvalflag
  $angle_offset
  $angle_cycles
  $fthresh, $sfthresh
  $fmid, $sfmid
  $fslope, $sfslope
  $revphaseflag
  $invphaseflag
  $interpolatelutflag
  $botedgelutflag
  $zerosymmfadeflag

This means that if the just-written-out color
scale is immediately re-read, some of these
parameters will be recursively applied.  To avoid
this:

  set complexvalflag <same-as-writefile-time>
  set angle_offset 0.0
  set fthresh <below-any-data-value>
  set fmid <below-any-data-value>
  set sfmid <below-any-stat-value>
  set fslope <large>
  set sfslope <large>
  set revphaseflag 0
  set invphaseflag 0
  set interpolatelutflag 1
  set botedgelutflag 0
  set zerosymmfadeflag 0

####################
val2rgb_edit
####################

-------------------------------------------
tcl function: editfile $val2rgblut
-------------------------------------------
keyboard equivalent: none

The "ED" button on the "lut:" (color look up
table) entry line edits the lut file named in the
entry to the left using a basic editor (tries
TextEdit, gedit, nedit, xedit in that order).

If the file in the "lut:" field (by default,
*/$scandir/val2rgb.lut) doesn't exist when the
"ED" button is clicked, a default one will be
contructed when the editor opens.

To cause the editor to be vi inside a popped-up
gterm or xterm, set this environment variable:

  setenv CSURFEDITORVIGTERM
         *or*
  export CSURFEDITORVIGTERM=1

####################
val2rgb_read
####################

-------------------------------------------
var,funct (left-click): read col LUT
  set val2rgblut <infile>
  read_val2rgblut
-------------------------------------------

The "R" button on the "lut:" entry line reads the
color lookup table (LUT) from file whose name is
current value of $val2rgblut (entry to left).  If
$complexvalflag not set to 1 ("cpx" is
unclicked), the "R" button will reset the
colscale to 12 (real-valued LUT).

If $complexvalflag is set to 1 ("cpx" is clicked),
then the "R" button will reset the color scale to
14 (complex LUT for phase).  In this case, it
expects to read a color LUT file whose first
column ranges from 0.0 to 1.0 (and which usually
wraps -- i.e., color for 0.0 equals color for
1.0).  Complex phase LUT first column values
below 0.0 or above 1.0 are ignored.

The *display* of complex color LUT is affected by
$revphaseflag and $angle_offset (but not by
$angle_cycles).  Since the state of the variables
$revphaseflag, $angle_offset, and $angle_cycles
is incorporated into the phase color LUT at the
time the LUT file was written, to restore that
appearance, unset revphaseflag (unlick "rev") and
set $angle_offset to 0.0.

The setting of $angle_cycles will be ignored for
phase LUT display, except to determine whether
the colorscale disk is displayed as
"eccentricity" (integer angle_cycles) or "polar
angle" (floating point angle_cycles).

####################
val2rgb_write
####################

-------------------------------------------
var,funct (left-click): write col LUT
  set val2rgblut <infile>
  write_val2rgblut
-------------------------------------------

The "W" button on the "lut:" entry line writes a
color lookup table (LUT) for current colscale
containing $val2rgblutout (default=15) entries.

Write LUT for real-valued data

If $complexvalflag unset ("cpx" unticked), a
real-valued LUT will be written for the current
colscale settings including:

  $fthresh, $sfthresh
  $fmid, $sfmid
  $fslope, $sfslope
  $interpolatelutflag
  $botedgelutflag
  $zerosymmfadeflag

Amplitude limits will be taken from the current
values of the color bar limits (entries on either
side of "bar" ($minstatcolscale, and
$minstatcolscale).  An input stat of 25.0 will be
assumed while writing the file, so set $sfthresh
to 0.0 to avoid desaturating the color LUT.

Immediately re-reading the just-written-out color
scale will recursively apply some of these
parameters. To avoid this:

  set fthresh <below-any-data-value>
  set fmid <below-any-data-value>
  set sfmid <below-any-stat-value>
  set fslope <large>
  set sfslope <large>
  set interpolatelutflag 1
  set botedgelutflag 0
  set zerosymmfadeflag 0

Write LUT for complex-valued data

If $complexvalflag is set ("cpx" clicked), a
smoothly-wrapped complex *phase* LUT will be
written (color for 0.0 will equal color for 1.0).

Here, phase controls hue, while complex amplitude
controls color saturation.  To be sure you
generate a fully saturated LUT, set set $fthresh
and $sfthresh to 0.0 just before writing the file
(an input amplitude of 5.0 and an input stat of
25.0 is assumed when writing the file).

When *displaying* data with this LUT file, the
*amplitude* will be taken from the complex
amplitude of the data that is currently read in
(incl. statistical mask, if present).

This parallels the behavior of colscale=1 ("w1")
or colscale=8 ("w2") and controlled by $fthresh,
$fmid, and $fslope.

Note that the write-time values of $revphaseflag,
$angle_offset, and $angle_cycles are incorporated
into the phase LUT file when it is created.  The
LUT file maps the unmodified 0-1 phase angle
(calcuated by atan2() from real and imaginary
data at each vertex) to the *currently displayed*
vertex color (which is affected by the current
settings of $revphaseflag, $angle_offset, and
$angle_cycles, and also $fthresh, $fmid, and
$fslope).

The raw phase angle at a vertex can be listed by
clicking a vertex and looking in the log for
something like:

  tksurfer: val/val2:(-12.905,1.963)=>(13.054,171deg),...

Note that when *displaying* a read-in color LUT,
$revphaseflag and $angle_offset will still affect
the colors the same way they affect the built-in
phase colscale=1 ("w1").

Because of this, to *display* the same colors
visible at the time the phase LUT file was
written, unset $revphaseflag (unclick "rev") and
set $angle_offset to 0.0.

At display time, the $angle_cycles field is
ignored (except to decide whether to show an
"eccentricity" or "polar angle" inset).

####################
gradfsarrows
####################

#### FIELDSIGN, GRADIENT ARROWS CONTROLS ####
-------------------------------------------
toggle variable (left-click tickbox):
  $nonbinaryfsflag -- toggle fs approx=0 valley
-------------------------------------------
toggle variable (shift-middle-click tickbox):
  $gradvecflag -- toggle val/val2 arrows
-------------------------------------------
toggle variable (middle-click tickbox):
  $gradvecbakflag -- toggle valbak/val2bak arrs
-------------------------------------------
toggle variable (ctrl-middle-click tickbox):
  $gradvecbak3dflag -- toggle valbak/val2bak 3D arrows
-------------------------------------------
toggle variable (popup):
  $reggradvecbakflag -- per-region valbak/val2bak arrows
-------------------------------------------
toggle variable (popup):
  $reggradvecbak3dflag -- per-region val/val2bak 3D arrows
-------------------------------------------
toggle variable (popup):
  $arrownormflag -- toggle gradient arrow norm
-------------------------------------------
toggle variable (popup):
  $filledarrowsflag -- toggle filled vs. line arrows
-------------------------------------------
toggle variable (popup):
  $centerarrowsflag -- toggle cent on vertex vs. from vtx
-------------------------------------------
toggle variable (popup):
  $angoffrevarrflag -- toggle disp pol/ecc as screen-rel arr
-------------------------------------------
toggle variable (popup):
  $flipRHpolararrowsflag -- flip RH arrows to match colscale
-------------------------------------------
variable: $arrowscale (popup) -- arrow length
-------------------------------------------
variable: $arrowline (popup) -- arrow stem thickness
-------------------------------------------
variable: $arrowheadfracauto (popup) -- head frac stem len
-------------------------------------------
variable: $arrowheadmin (popup) -- minimum head length
-------------------------------------------
variable: $line_arrowbarbangle (popup) -- angle barbs/stem
-------------------------------------------
variable: $filled_arrowtipangle (popup) -- ang tip-edge/stem
-------------------------------------------
variable: $filled_arrowbarbangle (popup) -- ang barbs/stem
-------------------------------------------
variable: $gridsize (popup) -- requested downsamp interval
-------------------------------------------
variable: $sdoutlierfact (popup) -- crop lg arr g.t. this * stdev
-------------------------------------------
variable: $areaoutliermin (popup) -- min vtx area to disp arr
-------------------------------------------
toggle variable (popup):
  $rmgradoutliersflag -- toggle rm grad arrows outliers
-------------------------------------------
toggle variable (popup):
  $prunearrowsflag -- toggle arrow downsampling
-------------------------------------------
button: PRUNE ARROWS (popup button)
  function: prune_arrows <gridsize>
-------------------------------------------
button: DENSE ARROWS DEFAULTS (popup button)
  function: [reset multiple panel variables]
-------------------------------------------
button: SPARSE ARROWS DEFAULTS (popup button)
  function: [reset multiple panel variables]
-------------------------------------------

This unlabeled tickbox to left of fieldsign file
entry ("fs:") toggles a fieldsign display setting
(how to color ambiguous fieldsign) and has many
additional flags for controlling display of
gradient arrows and per-vertex vectors.

The best way to access these (and more above)
parameters is by a right-click on that tickbox to
pop up a control panel (along with this help
panel; also auto-pops up when R-clicking the
gradient button, GR).

A number of these parameters are duplicated on
the ARROWS/NORMALS/POINTS popup available from a
R-click on the unlabeled tickbox at the bottom of
the "phc" (phasecontours) panel at the middle
left of the tksurfer panel.

-------------------------------------------
Left-click tickbox (toggle $nonbinaryfsflag)
-------------------------------------------

The default left-click toggles $nonbinaryfsflag.
When it is set to 1 (ticked) near-zero fieldsign
values fade from yellow/blue coloring to gray.
This is in addition to main modulation by fsmask.
The width of the near zero valley is controlled
by $fsslope which is the unlabeled energy just to
the right of the tick.  No effect on oldstyle
$hemi.fs files, which were clamped to -1,0,1.

-------------------------------------------
Shift-Middle-click tickbox (toggle $gradvecflag)
-------------------------------------------

A non-default shift-middle-click on this tick box
toggles $gradvecflag, which controls whether the
val/val2 fields should be shown as overlay
arrows.

This can also be used to toggle visibility of one
of two gradients when fieldsign has been computed
with $fsdata2gradsflag set to 1, which causes the
data loaded into both val/val2 and valbak/valbak2
to be replaced with gradients.

-------------------------------------------
Middle-click tickbox (toggle $gradvecbakflag)
-------------------------------------------

A second non-default middle-click on this tick
box toggles $gradvecbakflag, which controls
whether or not gradients loaded into the
valbak/val2bak fields should be shown as overlay
arrows.

This sets arrowscale to 5.0 and unsets
$arrownormflag and $angoffrevarrflag (if
$gradvecflag is not set).

-------------------------------------------
Control-Middle-click tickbox (toggle $gradvecbak3dflag)
-------------------------------------------

A third non-default control-middle-click on this
tick box toggles $gradvecbak3dflag, which
controls whether the valbak/val2bak/val3bak
fields should be shown as 3D overlay arrows or
not.

In contrast to the previous two cases (2d arrows)
the 3d arrows follow the folded surface.


R-click Popup: tickboxes, entry variables, buttons

-------------------------------------------
tick: $reggradvecbakflag (popup) -- per-region valbak/val2bak arrows
-------------------------------------------

This flag, $reggradvecbakflag, toggles visibility
of per-region average gradient arrows on 2D/flat
surfaces.  No effect unless MGH annotation has
been read on top of real or complex-valued data,
and a gradient (curv, val, angle-of-complex) has
been calculated using the "GR" button on the
"fs:" line (R-click on "GR" to get 12-button
popup, use bottom buttons 7-9).

N.B.: this overrides $gradvecbakflag, so it must
be unticked to reveal full field of dense (or
dense-pruned) per-vertex gradient arrows.

-------------------------------------------
tick: $reggradvecbak3dflag (popup) -- per-region val/val2bak 3D arrows
-------------------------------------------

This flag, $reggradvecbak3dflag, toggles
visibility of per-region average gradient arrows
on 3D surfaces.  No effect unless MGH annotation
has been read on top of real or complex-valued
data, and a gradient (curv, val,
angle-of-complex) has been calculated using the
"GR" button on the "fs:" line (R-click on "GR" to
get 12-button popup, use bottom buttons 10-12).

N.B.: this overrides $gradvecbak3flag, so it must
be unticked to reveal full field of dense (or
dense-pruned) per-vertex gradient arrows.

-------------------------------------------
tick: $arrownormflag (popup) -- toggle gradient arrow norm
-------------------------------------------

This unlabeled tick at the bottom of the
phasecontour box ("phc") (or $arrownormflag on 
the popup) toggles whether gradient vector
lengths are normalized to the same length or are
proportional.  Gradient vectors are calculated
and displayed when the "F" (fieldsign) or "GR"
(calculate gradients) buttons on the "fs:" line
are used.  See the R-click help for "F" and "GR"
for details. 

If the gradients were calculated on phase-encoded
data (i.e., on the phase angles), they will be
appoximately perpendicular to the iso-phase
contours (hence placement of these controls
here).

The unmarked entry immediately to the right of
the tickbox scales the gradient vectors (whether
normalized or not).  When $arrownormflag
(constant length gradient arrows) is enabled,
that field will be autoset to a sane value of 0.5
mm (which can be adjusted afterward).

-------------------------------------------
tick: $filledarrowsflag (popup) -- toggle filled vs. line arrows
-------------------------------------------

This toggles between line arrows and filled
arrowheads.  The filled arrowheads are made of
four adjustable triangles: two for the arrow
barbs, and two forming a diamond for the point.

Depending on the data gradients, other arrow
parameters may need adjusting when this is
toggled.  There is a DEFAULT LINE/FILL ARROWS
button to set defaults for each type.

Currently filled arrows only working for 2D/flat
gradient arrows (no effect of ticking this on 3D
surface arrows).

-------------------------------------------
tick: $centerarrowsflag (popup) -- toggle center arrow on vertex
-------------------------------------------

The default state (ON) centers the stem of the
arrow on the vertex to which it belongs (else,
the arrow stem starts from the vertex).

The only time this is forced off is when two
arrows are drawn at each vertex to illustrate the
polar and and eccentricity gradients at the same
time.

-------------------------------------------
tick: $angoffrevarrflag (popup) -- toggle display polar arrows
-------------------------------------------

Toggles the value of $angoffrevarrflag, which
causes polar angle data in the val/val2 fields to
be displayed as arrows.  For more details see the
end of this R-click help.

-------------------------------------------
tick: $flipRHpolararrowsflag -- flip RH arrows to match colscale
-------------------------------------------

Because standard rotating wedge polar angle
mapping stimuli result in phases with opposite
signs in left and right hemispheres, by default,
$flipRHpolararrowsflag is ON, which causes a 180
deg flip of RH gradient arrows (to match the flip
in the standard polar angle color scales).
Gradient arrows are only flipped if:

  (1) complexvalflag is ON
  (2) hemi is "rh"
  (3) angle_cycles is *not* an integer (1.0, 2.0, ...)

Turning OFF $flipRHpolararrowsflag stops all
arrow flipping.

-------------------------------------------
variable: $arrowscale (popup) -- arrow length
-------------------------------------------

The displayed length of gradient arrows can be
globally adjusted with the entry variable,
$arrowscale (default=2.0), which is a fraction
applied to all arrows.  Alternatively, if arrow
length has been normalized (made all the same)
with $arrownormflag, $arrowscale will then be in
units of mm.

-------------------------------------------
variable: $arrowline (popup) -- arrow stem thickness
-------------------------------------------

The thickness of the line used to draw line
arrows (stem and arrowhead are lines) is
controlled with the entry variable, $arrowline.
When $filledarrowsflag is ticked, this entry
controls the thickness of the arrow stem.

-------------------------------------------
variable: $arrowheadfracauto (popup) -- head frac stem len
-------------------------------------------

This variable specifies the size of the arrowhead 
as a fraction of the arrow stem length; as the
arrow length declines, the arrow barbs do too 
(with a minimum cutoff, see next variable).  To
turn off this scaling, in order to get constant
size arrowheads, set this to 0.0.

-------------------------------------------
variable: $arrowheadmin (popup) -- minimum head length
-------------------------------------------

When $arrowheadfracauto (above) is non-zero, this
variable, $arrowheadmin, sets the minimum size of
the arrowhead (as a fraction of the arrow stem
length).  When arrow-length normalization is 
turned off by settings $arrowheadfracauto to
zero, this variable will set the fixed size for
all arrowheads.

-------------------------------------------
variable: $line_arrowbarbangle (popup) -- ang barbs/stem
-------------------------------------------

For line arrows, this variable sets the angle of
the arrow barbs relative to the arrow stem
(default 22.5 deg).  No effect on filled arrows.

-------------------------------------------
variable: $filled_arrowtipangle (popup) -- ang tip-edge/stem
-------------------------------------------

For filled arrows, this variable sets the angle
of the tip of the arrow relative to the arrow
stem (default 15 deg).  If this angle is small
(like the default), the sides of the arrow barbs
will be concave.  Increasing it will make sides
of the arrow barbs flat, and then eventually
convex.  Set to taste.  No effect on line arrows.

-------------------------------------------
variable: $filled_arrowbarbangle (popup) -- ang barbs/stem
-------------------------------------------

For filled arrows, this variable sets the angle
of the arrow barbs relative to the arrow stem
(default 60 deg).  Increasing it makes a fatter
arrowhead.  No effect on filled arrows.

-------------------------------------------
variable: $gridsize (popup) -- requested downsamp interval
-------------------------------------------

Sets the gridsize (in mm) for pruning arrows.
Only the single arrow closest to each grid cell
will be shown when $prunearrowsflag is on.

-------------------------------------------
variable: $sdoutlierfact (popup) -- crop lg arr if g.t. this x stdev
-------------------------------------------

This crops extra-large arrows if the arrow
amplitude is greater than this factor
($sdoutlierfact) times the standard deviation of
all the arrows amplitude (default: 2x stddev).

-------------------------------------------
variable: $areaoutliermin (popup) -- min vtx area to disp arr
-------------------------------------------

This crops extra tiny arrows if the vertex area
(vertex[i].area) is below this ($areaoutliermin)
(default: 0.02).

-------------------------------------------
toggle: $rmgradoutliersflag (popup) -- toggle rm grad outliers
-------------------------------------------

This toggles whether to remove of overly large
gradient arrow outliers (based on the standard
deviation of the other arrow amplitudes), as well
as overly tiny arrows (based on tiny vertex
area).

N.B.: since this flag is only consulted during
gradient calculation, re-calculate gradient to
see the effect of changing it.

-------------------------------------------
toggle: $prunearrowsflag (popup) -- toggle arrow downsampling
-------------------------------------------

This flag toggles arrow pruning.  The removed
arrows are still there, just hidden when
$prunearrowsflag is on.

-------------------------------------------
button: PRUNE ARROWS (popup)
  function: prune_arrows <gridsize>
-------------------------------------------

Gradient calculations result in a very large
number of gradient arrows (one per vertex), which
will look cluttered (unless the surface is
strongly zoomed).  A R-click on the unlabeled
tickbox to the left of "fs:" (middle left),
brings up a popup for controlling gradient (and
fieldsign) arrows.

There is a PRUNE ARROWS button at the bottom of
the popup.  The density of arrows is set by the
$gridsize parameter (in mm) on the popup.  The
"prunearrowsflag" toggles between pruning and no
pruning.  N.B.: click PRUNE ARROWS again to see
the effect of adjusting $gridsize.

The pruning works by only showing one arrow for
each specified-size grid cell.  Since the actual
vertex location of the winning arrow is used, the
grid will be slightly irregular. Try slight (+/-
0.1) adjustments for fine-tuning.

Also remember that *.val (or *.stat) thresholds
can be used to prune 'noise' arrows by setting
$fthresh (or $sfthresh if "mask" is ticked), and
then recalculating the gradient arrows.

-------------------------------------------
button: DENSE ARROWS DEFAULTS (popup button)
  function: [reset multiple panel variables]
-------------------------------------------

The line arrows and filled arrows need subtly
different settings to look good on the same data.
Also, different gradient data requires different
settings.

The DENSE ARROWS DEFAULTS button sets sane
defaults, depending on whether $filledarrowsflag
is on or off, for gradient of retinotopic mapping
phase data.

-------------------------------------------
button: SPARSE ARROWS DEFAULTS (popup button)
  function: [reset multiple panel variables]
-------------------------------------------

The SPARSE ARROWS DEFAULTS button has a similar
function to the above button, but for arrows that
have been pruned to a (default) 3 mm grid, so the
arrows are bigger and thicker.

-------------------------------------------
HOWTO load your own vertex-wise vector field
-------------------------------------------

To load a vector field overlay of your own making
(over any data set) on a flat patch:

 1) put x,y vectors into complex label (6 entries per line)
 2) read with "R" on "label:" line (goes to va/val2 fields)
 3) shift-middle-click "S/V" => swap to cmplx stack bottom
 4) load surface data over which arrows will be displayed
 5) tick popup gradvecflag (or shift-mid-clk mainpanel tick)

Note that arrows will rotate with the pose of the
flat patch (i.e., the arrows will be stuck to the
surface).  The z-rotation of the flat patch is
typically saved in Preferences -> Expert
Preferences -> Views.

Because of the way patches are flattened, if the
rotation of the patch view has been set to zero,
unfortunately the positive y direction is *down*
and the positive x direction is *left*.  Thus,
the vector (1,1) will point down and to the lower
left in the window (both reversed from normal
expectations).

-------------------------------------------
HOWTO View polar angle arrows (hack)
-------------------------------------------

If $gradvecbakflag is *not* set (i.e., you are
*not* displaying two sets of gradients), this
action also does an additional thing:

  set arrowscale 0.5       ;# mm
  set arrownormflag 1     ;# unit length vectors
  set angoffrevarrflag 1   ;# use angle_offset/revphaseflag

in order to view raw polar angle phase data as a
field of arrows relative to screen.

Note that in contrast to the display of gradient
arrows, the arrows here are drawn *relative to
the window frame* -- that is, upward arrows
indicate upper field polar angle data and left
arrows indicate left hemifield.  Unlike the
gradient arrows, rotating the flat patch will
have no effect on the orientation of these
arrows, and the settings of $angle_offset and
$revphaseflag will affect the arrows.

The $angoffrevarrflag can be directly toggled
with a middle-click on the unlabeled tick box at
the bottom of the phasecontours box to the left
of "fmid:" (a regular left-click here toggles
$arrownormflag).

Interface uglies

The overloaded "fs:" line tick box mark only
reflects the state of $nonbinarfsflag even tho
the other flags are being toggled.  Same for the
(unlabeled) $arrownorm/$angoffrevarrflag.

It is much easier to use the popup from R-click
help on the "fs:" line tickbox (same popup from a
R-click on the "GR" button), which explicitly shows
all the parameters.  A R-click on the unlabeled
tickbox at the bottom of the mid right "phc" panel
makes another popup with most of these parameters
(as well as paramters for controlling the display
of normals, edges, points, and the cursor).

Since the 'direct display' of phase data responds
to angle_offset and revphaseflag as well as
hemisphere (so arrows point into the correct
hemifield), the *raw phase* can only be displayed
in the right hemisphere with angle_offset = 0 and
revphaseflag off.


####################
fsslope
####################

-------------------------------------------
entry variable: $fsslope -- fieldsign near-0 valley
-------------------------------------------
default: 3000

The unlabeld entry to the left of "fs:" (variable
$fsslope), controls the steepness of additional
near-zero modulation of fieldsign saturation.

The fieldsign values (signed magnitude of cross
product of eccen and polar gradients) are small
(-0.02 to 0.02) so a steep slope is required.  To
get no truncation, set fsslope=100000.

####################
fieldsign
####################

-------------------------------------------
entry variable: $fs -- fieldsign (fsmask implied)
-------------------------------------------
def: */fs/$hemi.fs  (implies */fs/$hemi.fm)

The "fs:" entry shows the current fieldsign file
(and implied fieldsign mask file, both usu.
unloaded at initial startup).  Click "R" to load
fieldsign and fieldsign mask.

Session directory can be abbreviated as an
asterisk (*).  Absolute name OK, too.  Relative
name appended to session.

The fieldsign file (*.fs, variable: $fs) is the
dot product of the eccentricity and polar angle
gradients, which are estimated by fitting a plane
to the data around each vertex.  The color scale
usually effectively only uses the sign (but see
help for tickbox just to left for nonbinary
display).

The name of the fsmask (fieldsign mask) file
(*.fm, variable: $fm) is generated upon clicking
READ or WRITE by stripping the .fs suffix and
appending an .fm suffix.  It is the geometric
mean of the r,th power/significance.

Binary fieldsign file format:
  [no magic number]
  4-byte int patch vertex count (must be full)
  4-byte float fieldsign value
  ...
  [implicit vertex nums]

Binary fsmask (fieldsign mask) file format:
  [no magic number]
  4-byte int patch vertex count (must be full)
  4-byte float fsmask value
  ...
  [implicit vertex nums]

####################
fieldsign_read
####################

-------------------------------------------
functs,vars (left-click): to read computed fieldsign
  set fs <$hemi.fs>
  read_fieldsign
  set fm <$hemi.fm>
  read_fsmask
-------------------------------------------

The "R" button on the "fs:" entry line reads the
fieldsign from the file whose name is the current
value of $fs (entry at left).

The tcl interface then also reads the fieldsign
mask (statistical mask) from the file whose name
is the current value of $fs with the .fs suffix
replaced by an .fm suffix.

####################
fieldsign_write
####################

-------------------------------------------
functs,vars (left-click): to write computed fieldsign
  set fs <$hemi.fs>
  write_fieldsign
  set fm <$hemi.fm>
  write_fsmask
-------------------------------------------

The "W" button on the "fs:" entry line writes out
current fieldsign and fieldsign mask (generated
by function: compute_fieldsign, after reading
eccen and polar data -- see fs-make.tcl) as files
$fs and $fm.

The fieldsign name, $fs, is the current value of
the "fs:" entry at the left.  The tcl interface
auto-generates the fieldsign mask output file by
stripping the .fs suffix and replacing it with
an .fm suffix.

####################
comp_fs
####################

-------------------------------------------
tcl/C functions:
  compute_angles
  compute_fieldsign
tcl/C variables:
  $fsdata2gradsflag
  $gradvecflag
  $gradvecbakflag
  $arrownormflag
  $arrowscale
  $angoffrevarrflag
-------------------------------------------

The "F" button on the "fs:" entry line computes
the visual fieldsign and the fieldsign mask.  The
tksurfer.tcl function used to run compute_angles
and compute_fieldsign is: comp_fs

Visual fieldsign data sets are normally generated
using the SessionTools -> Calc Visual Field Sign
panel.

To interactively generate fieldsign data set with
an overlay of the gradient vectors used to
calculate fieldsign using the "F" button, first
do the following:

 (1) load a flat patch (for fieldsign computation)
 (2) load polar angle data ("R" on "val:" line)
 (3) smooth with SMOOTH (e.g., 30 steps)
 (4) Shift-Middle-S/V (swap_valval2_valbakval2bak)
 (5) load eccentricity data ("R" on "val:" line)
 (6) smooth with SMOOTH (e.g., 30 steps)

To access files in another scandir, manually type
the scandir name into the "val:" entry after "*/"
(star-slash), the abbreviation for the session
"image" directory).

Clicking "F" first does:

   compute_angles

to convert complex data in the two pairs of
fields, val/val2, and valbak/val2bak, from real
and imaginary to phase and amplitude (the phase
will end up in the first member of each pair, val
and valbak).

Then, fieldsign is computed with:

  compute_fieldsign

which calculates gradients in the phase of
eccentricity and polar angle and takes the sign
of their cross product.

This fieldsign result is written to $hemi.fs
(amplitude and sign of the cross product between
polar angle and eccen gradients), and $hemi.fm
(geometric mean of amplitude of polar and
eccentricity data) into the current scan
directory (the polar and eccen data may have been
read out of other scandirs):

  setfile fs */$scandir/$hemi.fs
  write_fieldsign
  setfile fm */$scandir/$hemi.fm
  write_fsmask

or, to follow the naming convention for wfiles,
and write files with the same format as curv:

  setfile fs */$scandir/fs-$hemi.w
  write_fieldsign_curvfmt
  setfile fm */$scandir/fm-$hemi.w
  write_fsmask_curvfmt

Finally, the results are auto-loaded as an
underlay (functions below will autodetect and
read either kind of output above):

  read_fieldsign
  read_fsmask
  set colscale 9

On running "F", a popup will ask to to show
gradients, which will set $fsdata2gradsflag to 1
before running compute_fieldsign.  This has the
effect of saving the gradients into the val/va2
and valbak/val2bak fields so they can be
displayed as arrows (replacing the phase and
amplitude information compute_angles put
there, by replacing the original real and
imaginary data).

The following flags are automatically set to
control the display of the gradient arrows:

 set gradvecflag 1       ;# show eccen gradient vector
 set gradvecbakflag 1  ;# show polar gradient vector
 set arrownormflag 1    ;# ignore gradient amplitude
 set arrowscale 0.5      ;# mm length of arrows
 set angoffrevarrflag 0  ;# don't do win-relative polar angle

The settings of $arrownormflag and $arrowscale
can be adjusted using the unlabeled tick box
(arrownormflag) and the unlabeld entry
(arrowscale) at the bottom of the phasecontour
box ("phc").

Arrow colors

The eccentricity gradient (last loaded) arrows
will be red-orange, while the polar angle
gradient (first loaded) arrows will be cyan (the
colors were chosen to be visible over both yellow
mirror image fieldsign and blue non-mirror image
fieldsign).  They can be toggled on and off with
shift-middle-clicking or middle-clicking the
unmarked checkbutton to the left of "fs:".

Gradient directions for default eccen/polar stims

The default eccentricity stimulus moves from
center to periphery.  This means that the
periphery will have later (=larger) phases, and
that the gradient of eccentricity phase will
point toward the periphery.  The eccentriticity
color scale is typically arranged to have the
center of gaze red, intermediate eccentricities
blue, and the periphery green,

The default polar angle stimulus starts at the
horizontal meridian of the right hemifield and
rotates in a counter-clockwise direction.  This
means that the stimulus sweeps lower-to-upper in
the right hemifield (left hemisphere) but sweeps
upper-to-lower in the left hemifield (right
hemisphere).

Thus, in the left hemisphere, the upper field
will have later (=larger) phases, and the
gradient of polar angle will point toward the
upper field.  By contrast, in the right
hemisphere, the *lower* field with have later
(=larger) phases, and the gradient of polar angle
there will point toward the *lower* field.

For the opposite stimuli (contracting
eccentricity stimulus or clockwise polar angle
stimulus) simply reverse everything in the
previous 3 paragraphs :-}

####################
comp_grad
####################

#### calc 2D and 3D gradients of curv/val/phase ####
-------------------------------------------
funct: "Calc 2D/Flat Gradient Curv (left-click-GR)"
  compute_gradient <0=curv>
-------------------------------------------
funct: "Calc 2D/Flat Gradient RealVal (mid-click-GR)"
  compute_gradient <1=val>
-------------------------------------------
funct: "Calc 2D/Flat Gradient Phase (shift-mid-clk-GR)"
  compute_angles_vals_to_baks
  compute_gradient <2=phase-of-val/val2>
-------------------------------------------
funct: "Calc Surf Gradient Curv (ctrl-left-click-GR)"
  compute_surfgrad <0=curv>
-------------------------------------------
funct: "Calc Surf Gradient RealVal (ctrl-mid-click-GR)"
  compute_surfgrad <1=val>
-------------------------------------------
funct: "Calc Surf Gradient Phase (ctrl-shift-mid-clk-GR)"
  compute_angles_vals_to_baks
  compute_surfgrad <2=phase-of-val/val2>
-------------------------------------------
[like first 6, but single grad vecs avg'd by annot region]
-------------------------------------------
funct: "Calc 2D/Flat BrainRegAvg Curv (no hotkey)"
  compute_gradient <0=curv>
  compute_brainregion_avggrads
-------------------------------------------
funct: "Calc 2D/Flat BrainRegAvg RealVal (no hotkey)"
  compute_gradient <1=val>
  compute_brainregion_avggrads
-------------------------------------------
funct: "Calc 2D/Flat BrainRegAvg Grad Phase (no hotkey)"
  compute_angles_vals_to_baks
  compute_gradient <2=phase-of-val/val2>
  compute_brainregion_avggrads
-------------------------------------------
funct: "Calc Surf BrainRegAvg Curv (no hotkey)"
  compute_surfgrad <0=curv>
  compute_brainregion_avggrads
-------------------------------------------
funct: "Calc Surf BrainRegAvg RealVal (no hotkey)"
  compute_surfgrad <1=val>
  compute_brainregion_avggrads
-------------------------------------------
funct: "Calc Surf BrainRegAvg Grad Phase (no hotkey)"
  compute_angles_vals_to_baks
  compute_surfgrad <2=phase-of-val/val2>
  compute_brainregion_avggrads
-------------------------------------------
funct: "Find Gradient Reversals (no hotkey)"
  find_grad_reversals
-------------------------------------------
[funct: compute_laplacian]
-------------------------------------------


The "GR" button on the "fs:" entry line computes
gradients on surface-loaded data.

N.B.: first 3 require first loading a 2D/flat patch
N.B.: second 3 require first loading 3D surface
N.B.: last 6 are like first, but avg'd by annot region
N.B.: R-click on "GR" to get convenient controls popup!
N.B.: 13th button req's 1st running one of the first 12

-------------------------------------------
Calculating the 2D gradient of 2D or 3D surface data
-------------------------------------------

A left-, middle-, or shift-middle-click on the
"GR" button uses "compute_gradient" to compute
the 2D gradient of the current data in curv, val,
or complex phase (val/val2), put the result in
the bottom of the stack (valbak,val2bak), and
then display it as a field of arrows.  This
doesn't disturb the data in the val/(val2)
fields.

By adding control (control-left, control-middle,
control-shift-middle), the local 2D gradient is
instead computed on an arbitrary 3D surface,
using "compute_surfgrad" (this function computes
gradients using unit vectors to neighboring
vertices).  N.B.: in sharply curved regions,
large gradient arrows on the 3D surface may be
truncated because they penetrate the surface.

An additional 6 options, available as buttons on
the popup available from a R-click on the "GR"
button, calculate the same 6 gradients but then
also vector-average them across each brain region
of the currently displayed annotation, resulting
in only one gradient vector per annotation
region.

For val, curv, and phase gradients, finite
differences are computed between the current and
neighboring vertices.  With phase, a circular
subtraction is used.

Because standard rotating wedge polar angle
mapping stimuli result in phases with opposite
signs in left and right hemispheres, by default,
$flipRHpolararrowsflag is ON, which causes a 180
deg flip of RH gradient arrows (to match the flip
in the standard polar angle color scales).
Gradient arrows are only flipped if:

  (1) complexvalflag is ON
  (2) hemi is "rh"
  (3) angle_cycles is *not* an integer (1.0, 2.0, ...)

Turning OFF $flipRHpolararrowsflag stops all
arrow flipping.

In both flat and 3D surface cases, gradients of
val or phase data are truncated to zero during
the calculation if:

  (1) $statmaskamp OFF:
      any data vertices used to calc gradients
      fall below $fthresh (complex amplitude in
      the case of phase data)

  (2) $statmaskamp ON:
      any vertices used to calc gradients have a
      .stat field that falls below $sfthresh

N.B.: To see the effect of changing $fthresh or
$sfthresh, you must re-run compute_gradient or
compute_surfgrad.

N.B.: The displayed gradient arrows may not refer
to the data currently displayed.  For example,
the gradient of *curvature* can be computed with
a val (or val/val2) overlay loaded.  Also, a
different val (or val/val2) overlay can be loaded
under the arrows computed for a previous val (or
val/val2) data set. Both of these scenarios could
be useful.

For real-valued data (curv or val) on a flat
surface, the tcl commands are:

  compute_gradient <0=curv,1=val>
  set gradvecbakflag 1
  redraw

or, for 2D gradients on a 3D surface:

  compute_surfgrad <0=curv,1=val>
  set gradvecbak3dflag 1
  redraw

For the gradient of the phase of complex-valued
data, the data must first be converted to
phase/amplitude with compute_angles_vals_to_baks.
The output of that function goes to the bottom of
complex stack (*.valbak,*.val2bak), and then
"compute_gradient 2" (2=phase) converts it to a
gradient in place.  For a flat surface, the tcl
commands are:

  compute_angles_vals_to_baks
  compute_gradient <2=phase>
  set gradvecbakflag 1
  redraw

or, for 2D gradients on a 3D surface:

  compute_angles_vals_to_baks
  compute_surfgrad <2=phase>
  set gradvecbak3dflag 1
  redraw

Finally, per-brainregion averages are computed
with:

   compute_brainregion_avggrads

and displayed for flat surfaces with:

  set reggradvecbakflag 1

and 3d surfaces with:

  set reggradvecbak3dflag 1

-------------------------------------------
Gradient vector display controls
-------------------------------------------

A R-click on the unlabeled tickbox to the left of
"fs:" (tksurfer middle left), brings up a
convienient popup for controlling and pruning
gradient (and fieldsign) arrows.

The displayed length of gradient arrows can be
scaled with $arrowscale, which is a fraction.
Alternatively, the length can be normalized with
$arrownormflag, in which case, $arrowscale will
be in units of mm.  These variables can be set on
the popup or by using the unlabeled tick box
($arrownormflag) and the unlabeld entry
($arrowscale) at the bottom of the phasecontour
box ("phc") (there since gradients are
perpendicular to isocontours).

To toggle visibility of gradient arrows on a flat
surface, use "gradvecbakflag" on the popup (or do
a middle-click on the checkbutton to the left of
"fs:", or set $gradvecbakflag to 0 or 1).

To toggle visibility of gradient arrows on a 3D
surface, use "gradvecbak3dflag" on the popup (or
do a control-middle-click on the same
checkbutton, or set $gradvecebak3dflag to 0 or
1).

The equivalent for per-brainregion average
gradients (displayed at the vertex closest to the
average 3D location for each region) are
"reggradvecbakflag" and "reggradvecbak3dflag"

To draw the arrowhead for the 3D gradient
vectors, the local tangent plane is approximated
by taking the cross product of the 3D gradient
vector and the local surface normal.

-------------------------------------------
Pruning gradient vectors
-------------------------------------------

Gradient calculations result in a very large
number of gradient arrows (one per vertex), which
will look cluttered (unless you strongly zoom in
on the surface).  A R-click on the unlabeled
tickbox to the left of "fs:" (middle left),
brings up a popup for controlling gradient (and
fieldsign) arrows.

There is a PRUNE ARROWS button at the bottom of
the popup.  The density of arrows is set by the
$gridsize parameter (in mm) on the popup.  The
"prunearrowsflag" toggles between pruning and no
pruning.  N.B.: click PRUNE ARROWS again after
$gridsize is adjusted to see effect.

The pruning works by only showing one arrow for
each specified-size grid cell (the one closest to
center of cell).  Since the actual vertex
location of the winning arrow is used, the grid
will be slightly irregular.  Try slight (+/-
0.1) adjustments for fine-tuning.

Also remember that *.val (or *.stat) thresholds
can be used to prune 'noise' arrows by setting
$fthresh (or $sfthresh if "mask" is ticked), and
then recalculating the gradient arrows.

N.B.: this process does not do any smoothing of
the gradient vectors (see next).

-------------------------------------------
Smoothing gradient vectors
-------------------------------------------

To smooth gradient vectors (e.g., before
pruning), use "Surface Smooth (gr)" on buttonbar
popup available from a R-click on the SMOOTH
button (or change to the larger F3 interface
(cmd/fn-F3) and use the extra "gr" option with
the SMOOTH button).

This can also be used to smooth any other
complex-valued data in the bottom of the data
stack (.valbak/.val2bak).

Note that if data (real or complex) itself has
been SMOOTH'd before calculating gradients, the
gradient arrows should already be smoothly
changing.

-------------------------------------------
Viewing gradient amplitude with standard color scales
-------------------------------------------

Since the 2D gradient is stored as x and y
components in the bottom of the stack (.valbak
and .val2bak), its amplitude can be displayed by
using the complex-valued heat scale ($colscale 1)
after first swapping the gradient to the top of
the complex stack with shift-middle-click "S/V".
The tcl commands are:

  swap_valval2_valbakval2bak
  set colscale 1
  redraw

N.B.: doesn't work with 3D gradient arrows on a
3D surface.

Alternatively, here is how to obtain a
real-valued overlay containing the gradient
amplitude (after the gradient has been computed):

  1) swap gradient to top of complex stack
  2) convert to phase/ampl (goes back to bottom)
  3) swap phase/ampl to the top
  4) swap val and valbak (ampl is second)
  5) unset display gradient vectors flag
  6) unset complexval flag
  7) adjust color scale

Here are example tcl commands:

  swap_valval2_valbakval2bak
  compute_angles_vals_to_baks   
  swap_valval2_valbakval2bak
  swap_val_val2
  set gradvecbakflag 0
  set gradvecbak3dflag 0
  set complexvalflag 0
  set colscale 6
  set overlayflag 1
  set fthresh 0.0
  set fmid 0.08
  set fslope 10.0
  redraw

This process can be done all at once by clicking
"GRAD ARROWS -> COLOR" button on the popup
available from a R-click on the unmarked tickbox
at the bottom of the phase contour panel (just to
right of "cpx" button), after a gradient has been
calculated.  Finally, to save the auto-calculated
gradient amplitude as a real valued-file:

  setfile val */scan1/gradamp-$hemi.w
  write_binary_values

-------------------------------------------
Gradients on re-cut patches
-------------------------------------------

Since the gradient is calculated using
neighboring vertex values, the gradient is
undefined for vertices on the boundary of a
re-cut label.

If you want to calculate gradient values for
vertices on the boundary, first dilate the patch
by one layer of vertices before calculating the
gradient:

  middle-click "er" tickbox (tickbox label -> "dl" for dilate)
  left-click a vertex inside the re-cut label
  click FILL

or simply recut the patch *after* the gradient
calculation.

-------------------------------------------
funct: "Find Gradient Reversals (no hotkey)"
  find_grad_reversals
-------------------------------------------

The 13th "Find Gradient Reversals" button makes a
popup, "FIND GRADIENT REVERSALS", which runs the
C/tcl function, find_gradient_reversals.  It
requires that a gradient (of curv, real-valued
.val, or complex-valued phase from .val and
.val2) has first been calculated and displayed
on a 2D or 3D surface using one of the first 12
buttons on the "GR" R-click popup.

For each vertex, the absolute angular difference
(lesser of CW and CCW angles) between the
gradient vector at the vertex and the gradient
vectors at each neighboring vertex are measured.
For each angular difference that exceeds
$mindiffphase, the .pval field for that vertex is
incremented by 1/n, where n is the number of
neighbors.  The permissive default value of
$mindiffphase is 0.1 (36deg) (0.5=180deg), which
can be increased to reduce noise in the reversal
detection.  Re-run FIND REVERSALS to see the
effect.

The calculated vertexwise .pval's are saved as a
wfile in the current scandir (or in the subject's
scripts dir for curv gradient reversals) as:

  gradrevprob_k-$hemi.w

The gradient reversals can be displayed in two
ways.  By default, $pvalborddotflag is ON
(ticked), which displays reversal vertices as
cyan dots (color adjustable in the the popup),
with a .pval threshold controlled by $dthresh
(default 0.3).  Turn this up to reduce the number
of dots displayed (i.e., require a higher pval).
This doesn't require re-running FIND REVERSALS
(use a <Return> in entry).

If real or complex-valued data is displayed,
reversal dots will be truncated if real .val or
complex amplitude of .val/.va2 are below
$fthresh.

If $pvalborddotflag is unticked, there will be a
popup offering to swap .pval into the .val field
and display it using colscale 11 (BRy).

-------------------------------------------
[funct: compute_laplacian]
-------------------------------------------

The buttons to run the compute_laplacian function
are currently hidden.  To expose, change the
tksurfer.tcl line:

  set includelaplacian 0

to the following:

  set includelaplacian 1

Or the function can be called from a tcl script.
The real-valued output is written to the .valbak
field.  To compute the laplacian of curv, val, or
phase angle, and view the output, do something
like this in a script:

  [load curv, real, or complex data]
  compute_laplacian <0=curv,1=val,2=phase>
  swap_valval2_valbakval2bak
  set overlayflag
  set complexvalflag 0
  set colscale 11
  set fslope 2.0
  set fmid 0.5     ;# curv: 0.002
  set fthresh 0.0
  redrawbutton


####################
val
####################

-------------------------------------------
entry variable: $val -- vtxlist file (real)
-------------------------------------------
default: */scandir1/scan1-$hemi.w

The "val:" entry shows the current vertex list
data file (usu. file with *.w suffix, orig
meaning 'weight'), which will be loaded if
tksurfer was started with data overlay.  To load
a different file, select one from the "val:"
dropdown and click "R" (auto-detects
complex-valued pairs).

The wfile (vertex list file, output of PAINT) is
read into the top of the stack (.val).  This is
also the stack position that can be written out
to a wfile (with "W").

Session directory can be abbreviated as an
asterisk (*).  Absolute name OK, too.  Relative
name appended to session.  The stack is normally
automatically loaded by standard scripts or by
using the complex-valued-data sensitive "R"
button.  The function push_val_val2 can be used
to copy the top of stack (.val) to (.val2) before
reading second data set into top.

Examples:

  pol1_r-rh.w   # real comp. Fourier stats
  pol1_i-rh.w   # imaginary comp. Fourier stats
  pol1_f-rh.mgh # real-valued stats file
  mp2rage_profiles.vtk  # surface + real-valued stats

Six different data formats can be read in here:

 (1) *.w -- wfile fmt (vtxnums plus float data, maybe subset)
 (2) *.w/.curv -- newcurv fmt (floatdata all vtxs, implicit num)
 (3) *.mgh -- pseudovol fmt (float data, all vtxs, implicit num)
 (4) *.vtk -- ASCII fmt (POINT_DATA) w/1+ columns per vtx
 (5) *.gii -- GIFTI overlay format (*.shape.gii, *.func.gii)
 (6) *_000.bfloat -- floatdata all vtxs, implicit num

Valfiles (wfile's) can contain data for a subset
of all vertices in the surface, while newcurv and
bfloat files contain data for all vertices
(ancient 'oldcurv' files *cannot* be read as a
valfile and will be recognized and rejected).
Finally, 1D pseudo-volume *.mgh files and ASCII
*.vtk files can be read.

-----------------------------------------------------
Binary valfile/wfile/*.w file format:
-----------------------------------------------------
  2-byte latency: 0 (was ms lat*10 for EEG/MEG)
  3-byte uint: num painted vertices (usu. subset)
  3-byte uint: painted vertex number
  4-byte float: data
  3-byte uint: painted vertex number
  4-byte float: data
   ...
  [vertices can be in any order]
  [unpainted *and* data=0 vertices not in file]

-----------------------------------------------------
Binary newcurv file format (=newarea):
-----------------------------------------------------
  3-byte magic number: 16777215
  4-byte int: vertex count
  4-byte int: face count
  4-byte int: values per vertex
  4-byte float: data [vtx0]
  4-byte float: data [vtx1]
  ...
  [implicit sequential vtx numbering req'd]
  [all vtxs req'd]

-----------------------------------------------------
Binary 1D .mgh format (now only accepts float)
-----------------------------------------------------
  4-byte int: version (1)
  4-byte int: width (usu. num vertices)
  4-byte int: height (usu. 1)
  4-byte int: depth (usu. 1)
  4-byte int: nframes (usu. 1)
  4-byte int: type (must be 3: 0=byte,1=int,3=float,4=short)
  [skip remaining hdr (bytes=0-283) to 1st img byte=284
  4-byte float: data [vtx0]
  4-byte float: data [vtx1]
  [begin first frame/brik]
  ...
  [maybe begin second frame/brik]
  ...
  [skip footer]
  [skip tags]

-----------------------------------------------------
ASCII 1D .vtk format (surface + overlay data)
-----------------------------------------------------
  ... [opt. surf spec -- see Help -> csurf]
----- anything above here ignored ----
  POINT_DATA <vertexcount>
  SCALARS EmbedVertex float <columncount>
  LOOKUP_TABLE default
  column1value column2value ... [columncount entries]
  column1value column2value ... [columncount entries]
  ... [implitictly num'd tuples to vertexcount]

-----------------------------------------------------
GIFTI 1D .gii format (overlay data)
-----------------------------------------------------
  <?xml version="1.0" encoding="UTF-8"?>
  <GIFTI ...
         NumberOfDataArrays="1">
  ...
    <DataArray Intent="NIFTI_INTENT_NORMAL"
               DataType="NIFTI_TYPE_FLOAT32"
               ArrayIndexingOrder="RowMajorOrder"
               Dimensionality="1"
               Dim0="32492"
               Encoding="GZipBase64Binary"
               Endian="LittleEndian"
               ExternalFileName=""
               ExternalFileOffset="0">
      ...
      <Data>
        [usu: base64 encoded gzipped binary data]
      </Data>
    </DataArray>
  </GIFTI>

For details, see: https://www.nitrc.org/projects/gifti/

-----------------------------------------------------
Binary/ASCII bfloat-plus-hdr file format:
-----------------------------------------------------
  <stem>_000.bfloat 
  <stem>_000.hdr
  <stem>_001.bfloat 
  <stem>_001.hdr
  . . .

The *.bfloat files are MSB floats with no header
and the *.hdr files are one-line ASCII files:

  <y> <x> <t> 0

where y=1, x=vertexcnt, and t=1.  The second
number must match the number of vertices in the
current surface.
-----------------------------------------------------

Multiple frames

If the .mgh file header says it contains more
than one frame, the "R" button will bring up a
popup to allow resetting the variable
$mghvalframe from its default (0=firstframe).

[TODO: implement above for multi-frame bfloat's]

One-frame files with height and/or depth not
equal to 1 (e.g., single-frame FSL .mgh output)
can be read if width*height*depth = numvertices
in current surface.

If the .vtk has a line as follows, whose 4th
argument is larger than 1:

  SCALARS EmbedVertex float 21

the "R" button will bring up a popup to allow
resetting the variable $vtkvalcolumn from its
default (0=firstcolumn).  A pseudo-vtk file that
begins with a POINT_DATA line will also be
accepted.

GIFTI files are expected to contain only one
frame.

Output format

Two flags, both currently unset (=0) by default,
modify format of an *output* val file:

  allverticesflag -> write full (3-byte style) wfile
     (vs. just non-zero vertices)

  val2newcurvflag -> write full newcurv wfile
     (ignores allverticesflag)

A middle-click on the "val:" label makes a popup
for interactively controlling these flags.


####################
val_lab
####################

-------------------------------------------
left-click: toggle val type: "val:" vs. "val3d:"
mid-click: if "val:", get valfile output type popup
-------------------------------------------

Left-click "val:" or "val3d:"

This label/entry has two different states, "val:"
(real or complex-valued surface vertex list
stats), and "val3d:" (real or complex-valued
native resolution 3D stat files).

On startup, the default state is "val:", which is
used to (re-)read ("R" button) vertex list wfiles
(usu. generated by PAINT) onto the surface.

Left-clicking on the label "val:" (bold to
indicate it is button-like) swaps in the "val3d:"
entry, which is used to load ("R" button) 3D stat
files (float BRIK's or *.bfloat sets).  These
files won't be visible until they have been
sampled to the surface with "PAINT" (only visible
when label is "val3d:").

Clicking on the "val3d:" label again toggles the
entry back to the original "val:" state.

Middle-click "val:"

A middle-click on the "val:" makes a popup for
controlling the valfile type written when "W" on
the "val:" line is clicked.

The $allverticesflag tick (default=OFF) controls
whether vertices only with non-zero vals are
written or all vertices are written.

The $val2newcurvflag tick (default=OFF) controls
whether oldstyle valfiles are written (3-byte
index, 4-byte value) or newcurv valfiles are
written (all vtxs, no indices, 4-byte value).
If ON, ignores $allverticesflag.


####################
val_read
####################

#### read vertexwise data to .val field, (also vectors) ####
-------------------------------------------
funct: "Read Valfile, Real Or Complex (left-click-R)"
  set val <infile>
  read_binary_values
  [tcl: read_real_or_complex_binary_values]
-------------------------------------------
funct: "Same As Above + Demean, VarNorm (mid-clk-R)"
  set val <infile>
  read_binary_values
  [tcl: read_real_or_complex_binary_values]
  demean_varnorm_val
-------------------------------------------
functs: "Read Valfile Real/Imag,Set Amp=1 (shift-mid-clk-R)"
  set val <infile>
  read_binary_values
  [tcl: read_real_or_complex_binary_values]
  meanamp2one_valval2
-------------------------------------------
funct: "Read 3-Frame *.mgh File as Vect (shift-right-clk-R)"
  set val <infile>   [must be 3-frame *.mgh]
  read_mgh_dipoles
-------------------------------------------


Detailed Description of Label "R" Button Actions

-------------------------------------------
funct: "Read Valfile, Real Or Complex (left-click-R)"
  set val <infile>
  read_binary_values
  [tcl: read_real_or_complex_binary_values]
-------------------------------------------

A default left-click the "R" button on the "val:"
entry line reads painted surface vertexwise data
from file whose name is current value of $val
(entry at left).  Re-read overwrites any data
currently in the vertex[i].val field.

The entire .val field is always zeroed before
reading, even with file formats containing vertex
subsets.

The read_binary_values function can auto-detect
and read the following formats, mostly using
magic numbers (first 3 bytes):

  *.w -- freesurfer wfile, usu. vertex subset
  *.w/*.curv -- new curv/area, req's data all vtxs
  *.mgh -- 1D float real data (req's *.mgh suff)
  *.vtk -- 1D ASCII real (req's *.vtk suff)
  *.vtk-like -- 1D ASCII beginning w/POINT_DATA
  *.gii -- single-frame vertex-data GIFTI file
  *_000.bfloat -- bfloat, req's data all vtxs

In order for *.w files to be loaded into the
dropdown, they should have the format:

  <stem>-?h.w

and similarly, for bfloat files:

  <stem>-?h_000.bfloat
  
See R-click help for val entry for details of
file formats.  The old curv format (truly
ancient) cannot be read by the "val:" field.

In the special case where:

  1) complexvalflag is set ("cpx" checked)
  2) the entry matches this pattern:  *_?-?h.w
  3) the infix is: _r or _i (or _x or _y)

such as:

  */image/pol1/pol1-vreg+orig_r-rh.w

the "R" button (tksurfer.tcl wrapper function:
read_real_or_complex_binary_values) will
auto-read complex valued data using these
commands:

  set infix $imag
  setfile val ${stem}${infix}-${hemi}.w
  read_binary_values
  push_val_val2
  set infix $real
  setfile val ${stem}${infix}-${hemi}.w
  read_binary_values

using $stem, $hemi, and $real and $imag infixes
extracted from the filename in the entry.  The
filename in the entry can contain either the real
(_r or _x) or imaginary (_i or _y) infix.

The same works for complex-valued bfloat file
pairs.

In cases where a *.mgh file contains more than
one frame, a pop-up allows a non-zero-index frame
to be chosen.

See read_mgh_dipoles below for how to read a
3-frame surface-vertex-list *.mgh file in order
to display it as surface ball-and-stick vectors.

Functions to Manipulate Read-In Data

Some of the tcl script functions that can copy or
move data out of the .val field, or manipulate it
in place include:

 swap_stat_val		swap stat/val (S/V)
 swap_val_val2		swap val/val2 (middle-S/V)
 swap_pval_val		swap pval/val (shift-left-S/V)
 swap_valval2_valbakval2bak
		swap 2 real or cplx (shift-middle-S/V)
 swap_curv_val
 swap_pval_val
 swap_val_val2		swap real/imag
 swap_val_valbak        
 copy_val_val2		copy val to val2 (script only)
 copy_val_dip <0=x,1=y,2=z>
 clear_values		both .val .val2
 scale_val <scalefact>
 subtr_valbak_from_val

The .val field is the 'top of the stack', usually
the first entry point for vertexwise data.  The
stack at each numbered vertex[i] looks like this:

  vertex[i].val		(always visible)
  vertex[i].val2		(visible if complexvalflag is 1)

  vertex[i].stat		(invisible, maybe modulates)
  vertex[i].pval		(invisible, maybe modulates)

  vertex[i].valbak		(invisible, maybe compute with)
  vertex[i].val2bak		(invisible, maybe compute with)

Conversions

The commandline program calcvert can covert
between a number of different formats.  For
example, the following converts an ASCII label
file to a wfile.  Note that the hemisphere
(lh,rh) must be placed first in a label filename,
but just before the *.w suffix in a wfile
filename:

  calcvert -convert -labelfilein -valfileout rh-MT.label MT-rh.w


-------------------------------------------
funct: "Same As Above + Demean, VarNorm (mid-clk-R)"
  set val <infile>
  read_binary_values
  [tcl: read_real_or_complex_binary_values]
  demean_varnorm_val
-------------------------------------------

Similar to read_binary_values above, but subtract
mean, divide by standard deviation after read.

N.B.: the de-mean and divide-by-standard
deviation operations are only computed using
currently visible/uncut vertices.


-------------------------------------------
functs: "Read Valfile Real/Imag,Set Amp=1 (shift-mid-clk-R)"
  set label <outfile>
  read_binary_values
  [tcl: read_real_or_complex_binary_values]
  meanamp2one_valval2
-------------------------------------------

Similar to above, but scale complex amplitude of
.val/.val2 to one, without changing phase.

N.B.: the average complex amplitude is only
computed across currently visible/uncut vertices.


-------------------------------------------
funct: "Read 3-Frame *.mgh File as Vect (shift-right-clk-R)"
  set val <infile>   [must be 3-frame *.mgh]
  read_mgh_dipoles
-------------------------------------------

[N.B.: this one doesn't touch .val field!]

Read a 3-frame vertexwise *.mgh file into the
.dip{x,y,z} fields and display it as a field of
magenta ball-and-stick vectors.

N.B.: any vectors pointing into the surface are
reversed (flipped outward).  A shift-right-click
on the unlabeld arrowscale tickbox (in the
middle-right "phc" box) toggles vector display.


####################
swapstatval
####################

#### swap values on the vertexwise data stack ####
-------------------------------------------
funct: "Swap Stat/Val (left-click-S/V)"
  swap_stat_val
-------------------------------------------
funct: "Swap Val/Val2 (mid-click-S/V)"
  swap_val_val2
-------------------------------------------
funct: "Swap Two Complex (shift-mid-clk-S/V)"
  swap_valval2_valbakval2bak
-------------------------------------------
funct: "Swap Pval/Val (shift-left-click-S/V)"
  swap_pval_val
-------------------------------------------
funct: "Swap Curv/Curvbak (shift-right-click-S/V)"
  swap_curv_curvbak
-------------------------------------------
funct: "Swap Curv/Val (ctrl-right-click-S/V)"
  swap_curv_val
-------------------------------------------
funct: "Swap OrigArea/Val (ctrl-mid-click-S/V)"
  swap_origarea_val
-------------------------------------------
funct: "Copy IDnum to Val (ctrl-left-click-S/V)"
  copy_idnum_val
-------------------------------------------


The "S/V" button on the "val:" entry line
manipulates the position of vertexwise data in
the stack of 6 values at each vertex using 4
different functions (an additional 3 functions
manipulate curvature and annotation idnums -- see
below).

Note that only the top one (or top pair) is
visible on the displayed surface (the
vertex[i].val field for real-valued data if
complexvalflag is 0, or the vertex[i].val and
vertex[i].val2 fields for complex-valued data if
complexvalflag is 1).

The stack at each numbered vertex[i] looks like
this:

  vertex[i].val		(always visible)
  vertex[i].val2		(visible if complexvalflag is 1)

  vertex[i].stat		(invisible)
  vertex[i].pval		(invisible)

  vertex[i].valbak		(invisible)
  vertex[i].val2bak		(invisible)


Data is typically only read into or written from
the top of the stack.  Even though the .stat
field is not directly visible, if "mask" is
clicked, it will be used to mask the visible part
of the stack.

The following current color scale settings are
swapped along with the data:

  colscale
  fthresh
  sfthresh
  fmid
  sfmid
  fslope
  sfslope
  angle_cycles
  angle_offset
  revphaseflag
  ipsiyellowfact

-------------------------------------------
funct: "Swap Stat/Val (left-click-S/V)"
  swap_stat_val
-------------------------------------------

Swap the stat and val data fields at each vertex
(vertex[i].stat and vertex[i].val).  A typical
usage is:

  "R" statfile
  left-click "S/V"
  "R" valfile

or equivalently:

  "R" valfile
  left-click "S/V"
  "R" statfile
  "S/V"

Here are tcl script commands to do the same thing:

  setfile val */scan1/statfile.w
  [or: set val /some/statfile.w]
  read_binary_values
  swap_stat_val
  setfile val */scan1/valfile.w
  [or: set val /some/valfile.w]
  set colscale <num-that-uses-stat-and-val>
  redraw

See also:

  push_val_val2               copy val to val2
  swap_val_val2               swap val and val2
  swap_valval2_valbakval2bak  swap 2 complex nums

Finally, it is also possible to read a stat file
directly into the stat field without using swap
function:

  setfile stat */scan1/statfile.w
  read_binary_stats

This function can also be used to directly view
the stat field on the surface (use a real-valued
color scale like "BR").

-------------------------------------------
funct: "Swap Val/Val2 (mid-click-S/V)"
  swap_val_val2
-------------------------------------------

If the "S/V" button is middle-clicked (instead of
default left-clicked), an alternate swap function
is called:

  swap_val_val2

Swap the .val and the .val2 data fields at each
vertex (vertex[i].val and vertex[i].val2).  A
typical usage is:

  "R" imaginary valfile
  middle-click "S/V" (swap_val_val2)
  "R" real valfile

-------------------------------------------
funct: "Swap Two Complex (shift-mid-clk-S/V)"
  swap_valval2_valbakval2bak
-------------------------------------------

If the "S/V" button is shift-middle-clicked
(instead of default left-clicked), another
alternate swap function is called:

  swap_valval2_valbakval2bak

This function swaps the position of a pair of
complex-valued data sets, A and B, on the
vertex-wise data stack.  If the starting
condition is as follows:

 vertex[i].val		-> real-A
 vertex[i].val2		-> imaginary-A

 vertex[i].stat		(not touched)
 vertex[i].pval		(not touched)

 vertex[i].valbak		-> real-B
 vertex[i].val2bak		-> imaginary-B

after executing the function, the ending
condition is:

 vertex[i].val		-> real-B
 vertex[i].val2		-> imaginary-B

 vertex[i].stat		(not touched)
 vertex[i].pval		(not touched)

 vertex[i].valbak		-> real-A
 vertex[i].val2bak		-> imaginary-A

This function is used to load a pair of
complex-valued data sets prior to calculating
visual field sign, finding retinotopic areas by
region growing, or performing correlations as
follows:

  ### read eccen imaginary, push
  setfile val */$eccendir/${eccenstem}_i-$hemi.w
  read_binary_values
  smooth_val $smoothsteps
  push_val_val2
  ### read ecc real
  setfile val */$eccendir/${eccenstem}_r-$hemi.w
  read_binary_values
  smooth_val $smoothsteps
  ### swap complex
  swap_valval2_valbakval2bak

  ### read polar imaginary, push
  setfile val */$polardir/${polarstem}_i-$hemi.w
  read_binary_values
  smooth_val $smoothsteps
  push_val_val2
  ### read polar real
  setfile val */$polardir/${polarstem}_r-$hemi.w
  read_binary_values
  smooth_val $smoothsteps
  ### swap complex (ecc on top)
  swap_valval2_valbakval2bak

-------------------------------------------
funct: "Swap Pval/Val (shift-left-click-S/V)"
  swap_pval_val
-------------------------------------------

Swap the pval and val data fields at each vertex
(vertex[i].pval and vertex[i].val).  This
function makes the pval visible and saveable.

Currently, the .pval field is only loaded when
corr_over_label is run ("X" button on "label:"
line).  In that case, the pval is saved as the
positive power of ten; for example, p<0.01 is
saved as 2.0

-------------------------------------------
funct: "Swap Curv/Curvbak (shift-right-click-S/V)"
  swap_curv_curvbak
-------------------------------------------

Swap the curv and curvbak data fields at each
vertex (vertex[i].curv and vertex[i].curvbak).

In addition to the overlay stack described above,
there also two curvatures at each vertex:

  vertex[i].curv	(visible [unless surfcolor=0])
  vertex[i].curvbak	(always invisible)

This can be used to toggle between two curvatures
(e.g., native curvature and target template
curvature):

  set template /Applications/freesurfer/average/..buckner40..
  set templateframe 6
  read_tif_template
  swap_curv_curvbak
  read_binary_curv
  ### compare
  swap_curv_curvbak
  swap_curv_curvbak
  swap_curv_curvbak
  ...

-------------------------------------------
funct: "Swap Curv/Val (ctrl-right-click-S/V)"
  swap_curv_val
-------------------------------------------

Swap the curv and val data fields at each vertex
(vertex[i].curv and vertex[i].val).

N.B.: if .val is part of a complex number
(val,val2), this can make the overlay colors
nonsensical (undo by re-apply).

This can be used to import a template variable
into the data overlay stack:

  set template /my/template/file
  set templateframe 3
  read_tif_template
  swap_curv_val

To import a complex-valued data overlay from two
frames of template data, do something like:

  set template /my/template/file
  set templateframe 6  ;# imaginary
  read_tif_template
  swap_curv_val
  swap_val_val2
  set templateframe 3  ;# real
  read_tif_template

-------------------------------------------
funct: "Swap OrigArea/Val (ctrl-mid-click-S/V)"
  swap_origarea_val
-------------------------------------------

Swap the origarea and val data fields at each
vertex (vertex[i].origarea and vertex[i].val).

N.B.: if .val is part of a complex number
(val,val2), this can make the overlay colors
nonsensical (undo by re-apply).

This can be used to import a valfile (e.g., an
*.mgh file) into the 'original area' field
(.origarea), which is typically loaded at startup
with the $hemi.area file.

-------------------------------------------
funct: "Copy IDnum to Val (ctrl-left-click-S/V)"
  copy_idnum_val
-------------------------------------------

Copy the integer idnum into the val data field at
each vertex (copy brainregion[i].idnum to
vertex[i].val).  An annotation must first be
loaded.

This is useful for writing out quick-and-dirty
annotation-like files in labelfile or valfile
format (using "W" on the "label:" line, or "W" on
the "val:" line).

The x,y,z coordinates written to the label file
will respect any currently set normal search
parameters (left-click "label:" to get popup to
adjust).  The will also respect the settings of
the upper left "|ta|cu|" select buttons (origsurf
vs. currsurf vs. MNI 305 Talairach vs. MNI 152
Talairach coordinates).

To display/verify the integer values, you can
make a random color lookup table with the
supplied $CSURF_DIR/bin/noarch program,
mkrandlut:

  mkrandlut <minval> <maxval> <step> [rseed]

For example, to make a random color LUT for the
CsurfMaps1 annotation file (117 regions) for
fsaverage, do the following in bash/tcsh to write
a val2rgb.lut file to the cwd:

  cd $SUBJECTS_DIR/fsaverage/script
  $CSURF_DIR/bin/noarch/mkrandlut 0 117 1

Then click "Col:" to get colscale popup, select
color scale 12 ("lt"), and read the val2rgb.lut
file with "R" on the "lut:" line.

####################
val_clust
####################

#### surfcluster or FDR: mult comparison correct ####
-------------------------------------------
funct: "Run SurfCluster (left-click-CS)"
  set preclustfthr <e.g.: 5.0>
  set clustarea <e.g., 300>
  run_surfclust
-------------------------------------------
functs: "FDR Controls Pop-Up (mid-clk-CS)"
  smooth <steps> val
  clear_uniqvoxdata
  setfile label */<scandir>/$hemi-UniqSampVtxs.label
  [optional: read_uniqsamp_vertices]
  set noisedf <noise-deg-freedom>
  pval_from_fourier_fstat
  find_FDR_from_pvals <desired_FDR>
-------------------------------------------


Detailed Description of "CS" Button Actions

-------------------------------------------
funct: "Run SurfCluster (left-click-CS)"
  set preclustfthr <e.g.: 5.0>
  set clustarea <e.g., 300>
  run_surfclust
-------------------------------------------

A default left-click on the "CS" button on the
"val:" entry line uses the commandline program
"surfclust" to apply a surface-based cluster size
exclusion filter to data currently loaded into
the vertex-wise .stat field.  The .stat field is
can be loaded in two ways from the "val3d:" line.

For complex-valued data with complex amplitude
replaced by the sqrt(F) (BRIK's w/infixes:
_r,_i), the .stat field will automatically be
loaded with F when "PAINT" is clicked.

For a real-valued stat data BRIK, first click PNT
(paint) to sample it to the surface, then click
S/V to swap it into the surface .stat field.

The clustering parameters are controlled by the
tksurfer commandline options:

  -preclustfthr <F>			hard thresh before filter
  -clustarea <mm^2>			min cluster area

or the corresponding tcl variables, $preclustfthr
and $clustarea in a script.  The initial values
are loaded from the Fourier panel, but can also
be controlled live from tksurfer using the pop-up
accessed by a R-click on "label:" (see bottom of
pop-up).

The sequence of actions done by run_surfclust is:

  1) swap stat and val (stat to writable 'val' position)
  2) write out stat to temp wfile
  3) run surfclust on temp wfile
  4) read output back into .val
  5) swap stat and val again (back to .stat)

Here is an example of the full surfclust
commandline run when "CS" is clicked:

  surfclust
     -instem ./TmpCplxFstatsVtxListFile_f
     -name martys
     -outstem ./TmpCplxClustFstatsVtxListFile_h
     -hemi lh
     -thresh 5.0
     -minarea 300
     -surf smoothwm

Here is the set of tcl commands required to load
a complex-valued pair of 3D volume phase-stat
files, paint them onto the surface and load the
.stat field with unclustered F (which is square
of _r,_i amplitude), and finally run the cluster
exclusion filter to modify the data in the .stat
field:

  setfile statpatt */scandir1/pol1_r+orig.BRIK
  read_native_stat 0   
  setfile statpatt */scandir1/pol1_i+orig.BRIK
  read_native_stat 1
  # "1" arg on next line means load F into .stat
  paint_surface 1
  set preclustfthr 5.0
  set clustarea 300
  run_surfclust

To save the resulting clustered F stats wfile
(N.B.: these are hemisphere-specific) in the
current scandir ("scandir1" below), use:

  swap_stat_val
  setfile */scandir1/pol1+orig_h-$hemi.w
  write_binary_values

The _h infix is the default for surface-based
clustered stats.


-------------------------------------------
functs: "FDR Controls Pop-Up (mid-clk-CS)"
  smooth <steps> val
  clear_uniqvoxdata
  setfile label */<scandir>/$hemi-UniqSampVtxs.label
  [optional: read_uniqsamp_vertices]
  set noisedf <noise-deg-freedom>
  pval_from_fourier_fstat
  find_FDR_from_pvals <desired_FDR>
-------------------------------------------

Calculate p-Value for Given False Discovery Rate

An middle-click on the "CS" button provides an
alternate non-parametric FDR method of correcting
for multiple comparisons.

The Benjamini/Hochberg (1995) method as
introduced to fMRI by Nichols estimates a
corrected p-value to use for a desired false
discovery rate (FDR) as follows:

  read F-stat onto surface
  calc p-val for each vertex (fcdf)
  sort p's in ascending order
  find highest p less than or equal to (i/N * q), where
      i = index of that p
      N = total num vertices
      q = desired probability

A middle-click on the "CS" button brings up a
popup with 6 adjustable parameters:

  smoothsteps
  val,weight
  desired_FDR
  noisedf
  uniqsampvtxflag
  arbitrFDRcovarflag

Optional "smoothsteps" are applied to the F-stats
before converting to p-values and sorting.  The
smoothing method ("val,weight") can be either
"val" (=standard nearest neighbor) or the gentler
"weight" (Gaussian distance-weighted, 0.8mm FWHM,
adjustable with $halfweightdist: def=0.4).

Now enter "desired_FDR" (as a p-value, e.g.,
0.05) and "noisedf", the noise degrees of
freedom.  Assuming that the F-stats were
calculated by csurf fourier methods, this will
typically be 256 or 512 frequencies minus 11
nuisance regressors (very low frequencies, 2nd
and 3rd harmonics, and -1/+1 neighbors of the
1st-3rd harmonics).

The "uniqsampvtxflag" tick controls whether all
vertices are used, or whether only a single
vertex is used for each sampled voxel, namely,
the vertex that is closest to average position of
the set of vertices that sampled that voxel (~10
vertices/voxel for 3mm^3 data).

The required file of unique vertices used by
"uniqsampvtxflag" will have been generated if
PAINT was run after ticking "UniqVtx" on the
Setup Functional panel.

Finally, the "arbitrFDRcovarflag" tick implements
the Benjamini/Yekutieli (2001) non-parametric
correction to q for arbitrary covariance by
dividing q by the sum of 1/i (approximately equal
to log(N) + 0.5772) instead of by 1.

N.B.: vertices with a value of 0.0 are excluded
from the calculation because these are off the
edge of the functional volume.

The corrected p-value is returned in a final
pop-up and written into the csurf log.

To use the corrected estimate, enter the
corresponding F into the "sfmid" field for the
mask (right-hand "fmid" entry).

Loading F-stat Data

The CS button only requires F-stats in the
invisible .stat field.  An easy way to do this
from the csurf "View Functional Data" panel:

  (1) select _r file from "Paintfile:" dropdown
  (2) click "sig+(clust)Fmask" =>auto-selects _h mask (clust)
  (3) select _f file instead from "StatMask Paintfile: dropdown
  (4) SURFACE-STATS

Alternatively, the .stat field can be loaded
interactively from tksurfer as follows:

  (1) click S/V to save/swap existing map data
  (2) select _f file from "val:" dropdown
  (3) read it into .val with "R"
  (4) click S/V to swap F-stat into .stat field
        (restores map data)

Regions of Interest

To further restrict the set of vertices over
which the desired_FDR is calculated, cut away
parts of the surface (cut-away vertices are
ignored for the FDR calculation).  An existing
label can be used for this purpose by selecting
it from the dropdown and left-clicking "C"
(re-cut) on the "label:" line.

FDR via Tcl Script for tksurfer

The FDR calculation (including using
unique vertex sampling) can be run
quickly (runtime less than 1sec) with a
commandline tcl script for tksurfer that
doesn't bring up any windows.

Save the following script into a file (e.g.,
zz.tcl in the scripts dir of a functional
session), after first replacing <scandir>,
<stem_up_to_+orig>, <session>, and <subject>
below with your values:

  set scandir <scandir>
  setfile val */$scandir/<stem_up_to_+orig>_f-$hemi.w
  read_binary_values
  smooth_val 0
  swap_stat_val
  set noisedf 245
  setfile label */$scandir/$hemi-UniqSampVtxs.label
  read_uniqsamp_vertices
  pval_from_fourier_fstat
  find_FDR_from_pvals 0.05
  exit

Then run the tcl script from a shell (bash or tcsh):

  cd $FUNCTIONALS_DIR/<session>/image/scripts
  tksurfer <subject> rh inflated -tcl zz.tcl

This will print some lines, ending with:

  ...
  % tksurfer: find_FDR_from_pvals(q=0.050000):
  % tksurfer:  use only uniqsamp vtxs
  % tksurfer:  for desired FDR=0.0500 use pval=0.0171 (n=12501)

####################
val_clear
####################

#### clear val, other data fields ####
-------------------------------------------
funct: "Clear Real/Imag DataVals (val,val2) (left-click-CLR)"
  clear_values
-------------------------------------------
funct: "Clear Stat Values (stat) (shift-left-clk-CLR)"
  clear_stat
-------------------------------------------
functs: "Clearall (val,val2,valbaks,stat,pval,uniq) (mid-clk-CLR)"
   clear_values
   clear_valbaks
   clear_stats
   clear_pvals
   clear_uniqvoxdata
-------------------------------------------


Detailed Description of val "CLR" Button Actions

-------------------------------------------
funct: "Clear Real/Imag DataVals (val,val2) (left-click-CLR)"
  clear_values
-------------------------------------------

Uses the tcl function clear_values to clear .val
and .val2 fields to zero.  This clears any
visible data off the surface (real or complex
data).

N.B.: this will leave the stat field (.stat) and
the invisible data on the stack bottom (.valbak,
.val2bak) intact.  Use middle-click (see below)
to clear those.

N.B. this will not clear vertex color labels
("paint" that ignores data and color scale
controls, fmid/fslope, etc).  Do a middle-click
on the *label* CLR button to clear vertex color
labels.

-------------------------------------------
funct: "Clear Stat Values (stat) (shift-left-clk-CLR)"
  clear_stat
-------------------------------------------

Uses the tcl function clear_stat to clear the
.stat field to zero.  The .stat field is
not directly visible, but usually used to mask
visible data in the .val/.val2 fields.

-------------------------------------------
functs: "Clearall (vals,valbaks,stat,pval,uniq) (mid-clk-CLR)"
   clear_values
   clear_valbaks
   clear_stats
   clear_pvals
   clear_uniqvoxdata
-------------------------------------------

If the "CLR" button is middle-clicked (instead of
default left-clicked), an alternate, full data
clear is done using these five clear functions:

   clear_values
   clear_valbaks
   clear_stats
   clear_pvals
   clear_uniqdata

This clears all of these 8 vertex data fields:

   vertex[i].val
   vertex[i].val2
   vertex[i].valbak
   vertex[i].val2bak
   vertex[i].stat
   vertex[i].pval
   vertex[i].uniqvoxnum
   vertex[i].uniqvoxcnt

N.B. this will *not* clear vertex color labels.
Use the "CLR" button on the "label:" line
(middle-click).


####################
val_write
####################

#### write (convert) vtx data ####
-------------------------------------------
funct: "Write Curr Val to *.w File (left-click-W)"
  set val <outfile>
  write_binary_values
-------------------------------------------
functs: "Conv FT Amp To Percent (mid-click-W)"
  compute_tseriesavg2stat
    [output to .stat field of vtxs, next uses as inp]
  compute_dftamp2pcnt2stat $avg_rawamp $time_points
    [output to .stat field of vtxs]
-------------------------------------------
funct: "Write MGH 1D *.mgh File (ctrl-left-click-W)"
  set val <outfile>    [should end in *.mgh]
  write_mgh_values
-------------------------------------------
funct: "Write VTK *.vtk ValOnly File (ctrl-mid-click-W)"
  set val <outfile>    [should end in *.vtk]
  write_vtk_values
-------------------------------------------
funct: "Write VTK Surf/Val File (shift-ctrl-mid-click-W)"
  set val <outfile>    [should end in *.vtk]
  write_vtk_surface_plus_values
-------------------------------------------
funct: "Write Curv to Sphim (shift-mid-click-W)"
  [output to internal 'reverse paint' sph vol]
  surf2sphim 0   [0=curvim]
-------------------------------------------
funct: "Write Stat to Sphim (shift-right-click-W)"
  [output to internal 'reverse paint' sph vol]
  surf2sphim 1   [1=statim]
-------------------------------------------
functs: "Write val/val2 to Sphim (shift-left-click-W)"
  [output to internal 'reverse paint' sph vol]
  surf2sphim 2   [2=realim]
  surf2sphim 3   [3=imagim]
-------------------------------------------
functs: "Write val/val2baks Sphim (shift-ctrl-left-clk-W)"
  [output to internal 'reverse paint' sph vol]
  surf2sphim 4   [4=realim2]
  surf2sphim 5   [5=imagim2]
-------------------------------------------
funct: "Debug/View SphimPanel (shift-ctrl-right-clk-W)"
  sphimctrls     [for debug]
-------------------------------------------


Detailed Description of "W" Button Actions

-------------------------------------------
funct: "Write Curr Val to *.w File (left-click-W)"
  set val <outfile>
  write_binary_values
-------------------------------------------

A default left-click on the "W" button writes out
current (possibly smoothed) value of the
per-vertex .val field to the file $val (filename
in entry to left, after expansion of any
abbreviation).  Must confirm overwrite (direct
use of C/tcl function write_binary_values doesn't
ask).

Default is to write valfile/wfile/*.w format,
which contains only non-zero vertices.

To write wfile containing all vertices, first
use:

  set allverticesflag 1

To instead write out a newcurv format file
(always contains all vertices, so ignores
allverticesflag), first use:

  set val2newcurvflag 1

A middle-click on the "val:" label makes a popup
for interactively controlling these 2 flags.

For details of different binary formats, see
R-click help for "val:" field.  Formats are
auto-detected on read.

-------------------------------------------
functs: "Conv FT Amp To Percent (mid-click-W)"
  compute_tseriesavg2stat
    [output to .stat field of vtxs, next uses as inp]
  compute_dftamp2pcnt2stat $avg_rawamp $time_points
    [output to .stat field of vtxs]
-------------------------------------------

An alternative middle-click on the "W" button
brings up a popup that converts raw Fourier
transform data to vertexwise percent responses,
displays the results, and also writes them to a
wfile (infix: _%).

To do this, we need the time series average
brightness.  This can either be calculated from
the raw time series BRIK if this is available, or
it can be entered directly, if it is not
available (e.g., phase average, or cross-subj
average).

(1) First, load the complex-valued raw Fourier
amplitude wfiles to the surface.  Pick the _x (or
_y) surface wfile from the "val:" dropdown and
click "R" (picking either loads both).

(2) Second, if raw data is present, load it.
This can be done quickly by ctrl-mid-clicking the
surface (to display a single vertex timecourse,
which auto-loads the rawdata), or more explicitly
as follows:

  click "val:" label to change it to "val3d:"
  click "RD" to get read rawdata popup
  select rawdata timeseries BRIK in dropdown
  click READ RAWDATA & REGISTRATION on popup

[now back to the RAW FOURIER TO PERCENT popup]

(3) Third, find average rawdata brightness.  If
rawdata has been loaded, click:

  COMPUTER AVG t-SERIES EACH VTX

on the popup.  Once this finishes, the
.stat field will contain the rawdata average
for each vertex, the $avg_rawamp entry will be
reset to "vtxwise", and the number of
$time_points will be set.

If no rawdata is available, manually enter the
average rawdata brightness (voxels in brain - or
brains), and the number of timecourse timepoints.

  avg_rawamp:  avg brain voxel timecourse brightness
  time_points:    TRs in timecourse (e.g., 512)

(4) Finally, compute percent response by
clicking:

  COMPUTE PERCENT RESP

on the FOURIER TO PERCENT RESPONSE popup.  The
.stat field at each vertex will now be replaced
with response percent, which will then be swapped
to the viewable .val field, the color scale
adjusted to display real values, and finally, the
average rawdata amplitude will be written to a
wfile with a "_%" infix.

To return to viewing the complex data, re-swap
stat and val, by left-clicking S/V.

Implementation details

The tcl/C function to calculate the vertexwise
raw data average is:

  compute_tseriesavg2stat

The tcl/C function to calculate percent resp is:

  compute_dftamp2pcnt2stat $avg_rawamp $time_points

In tksurfer.tcl, the proc writedftampctrls makes
the popup and the two popup buttons call the
following tcl proc's:

  do_computetseravgs
  do_writedftamp

which finally call the two C/tcl functs above.

N.B.: results are valid only if the
complex-valued raw Fourier transform of
timeseries has been read onto the surface (these
wfile typically have _x,_y infixes).

This *vertexwise* operation partly overlaps with
shift-left-click on the "T" button, which, by
contrast, displays the average response percent
across all the vertices in *label*.

The tcl/C functions run by do_writedftamp
include:

  compute_dftamp2pcnt2stat $avg_rawamp $time_points
  swap_stat_val
  set complexvalflag 0
  set colscale 6
  set fmid 0.6
  set fslope 2.0
  setfile val ${stem}_%-${hemi}.w
  write_binary_values

If -1.0 is entered for the $avg_rawamp argument
above, this is a flag meaning use average rawdata
amplitude currently saved in .stat field (vs. use
the argument value, which should be positive).

Here is the C-code for compute_dftamp2pcnt2stat:

  if (avgrawamp == -1.0) usestat = 1;
  for (k=0; k<vertexcnt; k++) {
    dftamp = hypot(vertex[k].val,vertex[k].val2);
    pcnt = dftamp;            /* assume _x,_y in val/val2 */
    pcnt /= (float)tcnt;      /* norm discrete FT */
    if (usestat)
      pcnt /= vertex[k].stat; /* resp frac (use .stat) */
    else
      pcnt /= avgrawamp;      /* resp frac (use func arg) */
    pcnt *= 2.0;              /* incl pos+neg freqs */
    pcnt *= 2.0;              /* report peak-to-peak */
    pcnt *= 100.0;            /* percent */
    vertex[k].stat = pcnt;    /* save to .stat */
  }

As always, to see exactly what's going on, click
the "tcl:" label to see tcl commands as they are
executed by interface clicks.

N.B.: ctrl-middle-clicking a vertex to display
the timecourse can also display the percent
response once the 3D _x,_y BRIKs have been loaded
as follows:

  click "val:" label to change it to "val3d:"
  click "RD" to get read rawdata popup
  select _x (or _y) 3D BRIK in dropdown
  click "R" on "val3d:" line (auto-reads both)

When a vertex is ctrl-middle-clicked, the 3D
rawdata is auto-loaded (if not already), and then
both the rawata and the 3D Fourier _x,_y data is
re-sampled to the surface in order to calculate
percent response.  To see the exact same percent
responses as the functions above (which use the
_x,_y wfiles that have already been sampled to
the surface), be sure the surface smoothing of
the _x,_y files (or lack of it) is the same in
both cases.


-------------------------------------------
funct: "Write MGH 1D *.mgh File (ctrl-left-click-W)"
  set val <outfile>    [should end in *.mgh]
  write_mgh_values
-------------------------------------------

An second alternative ctrl-left-click on the "W"
button writes out the currently displayed values
in the per-vertex .val field to a 1D, one-frame,
float .mgh file, using the current filename in
the "val:" entry (tcl variable: $val).  This file
contains all vertices.

This can be read back onto the surface in using
the "R" button on the "val:" line (format is
auto-detected).


-------------------------------------------
funct: "Write VTK *.vtk ValOnly File (ctrl-mid-click-W)"
  set val <outfile>    [should end in *.vtk]
  write_vtk_values
-------------------------------------------

A third alternative ctrl-middle-click on the "W"
button writes out the currently displayed values
in the per-vertex .val field to a 1D, one-column,
float ASCII .vtk file, using the current filename
in the "val:" entry (tcl variable: $val).  This
file contains all vertices.

The resulting output file begins like this:

POINT_DATA <numvertices>
SCALARS EmbedVertex float 1
LOOKUP_TABLE default
1.293870
5.293872
...
...

There should be <numvertices> lines of values
following the 3-line header.  This file can be
read back onto the surface using the "R" button
on the "val:" line.

It is *not* a valid *.vtk file by itself (tho
tksurfer can read it -- see below).  It is
designed to be contatenated onto the end of an
ASCII .vtk surface with the same number of
vertices.  For example:

  cat lh.surf.vtk lh.vals.vtk > lh.surf+vals.vtk

The end result of concatenation should look like
this:

# vtk DataFile Version 3.0
BB4T130527_S4_mp2rage_0_inf_profiles
ASCII
DATASET POLYDATA
POINTS 954296 float
43.35591 108.78648 122.05577
43.44609 108.62583 122.07568
...
...
19.28717 77.35710 24.23914
19.33012 77.21865 24.23220
POLYGONS 1908740 7634960
3 2 1 0
3 1 3 0
...
...
3 954295 954257 954255
3 954295 954252 954257
POINT_DATA 954296
SCALARS EmbedVertex float 1
LOOKUP_TABLE default
1.293870
5.293872
...
...

The "R" button on the "val:" line will accept
either the bare POINT_DATA file or a full, valid
surface-plus-data *.vtk file.


-------------------------------------------
funct: "Write VTK Surf/Val File (shift-ctrl-mid-click-W)"
  set val <outfile>    [should end in *.vtk]
  write_vtk_surface_plus_values
-------------------------------------------

The fourth alternative shift-ctrl-middle-click on
the "val:" line "W" button writes out the current
surface as an ASCII *.vtk file and auto-appends
the current real vertex-wise values in one
operation (as described in previous section).


-------------------------------------------
funct: "Write Curv to Sphim (shift-mid-click-W)"
  [output to internal 'reverse paint' sph vol]
  surf2sphim 0   [0=curvim]
-------------------------------------------
funct: "Write Stat to Sphim (shift-right-click-W)"
  [output to internal 'reverse paint' sph vol]
  surf2sphim 1   [1=statim]
-------------------------------------------
functs: "Write val/val2 to Sphim (shift-left-click-W)"
  [output to internal 'reverse paint' sph vol]
  surf2sphim 2   [2=realim]
  surf2sphim 3   [3=imagim]
-------------------------------------------
functs: "Write val/val2baks Sphim (shift-ctrl-left-clk-W)"
  [output to internal 'reverse paint' sph vol]
  surf2sphim 4   [4=realim2]
  surf2sphim 5   [5=imagim2]
-------------------------------------------
funct: "Debug/View SphimPanel (shift-ctrl-right-clk-W)"
  sphimctrls
-------------------------------------------

The fifth, sixth, seventh, and eight alternative
operations -- shift-middle-click and
shift-right-click and shift-left-click and
shift-ctrl-left-click on the "val:" line "W"
button -- perform a "reverse paint" of the vertex
data from the current spherical (or other)
surface into a 3D volume (a thin shell) for use
as one (or more) morph targets for sphere_morph
("REG" button on F3 interface).

See also, interactive pop-up available in large
F3 interface by clicking the bold "im:" label,
which can also allow converting any one spherical
shell to an *.mgz volume (~/mri/sphim.$hemi.mgz)
for debugging/display by tkmedit.  Pop-up also
available on standard F2 interface using
shift-ctrl-right-click-"W".

The source for the reverse paint operation are
the data values currently loaded into one of the
following fields on the surface (error/no-op if
not loaded):

   vertex[i].curv		[surf2sphim 0]
   vertex[i].stat		[surf2sphim 1]
   vertex[i].val		[surf2sphim 2]
   vertex[i].val2		[surf2sphim 3]
   vertex[i].valbak		[surf2sphim 4]
   vertex[i].val2bak		[surf2sphim 5]

To avoid holes/aliasing when sampling surface
vertex data (ico vertex spacing ~0.95 mm) to the
"reverse painted" 3D shells (1x1x1mm), the 3D
voxels are set at each point along a normal
search at each vertex starting at -2.0 mm inside
the sphere to 2.0 mm outside the sphere in steps
of 0.1 mm.  To remove the few remaining holes, a
nearest neighbor hole-filling operation is
performed after sampling.

N.B. current files in the "curv:" and/or "val:"
entries are NOT reloaded.

N.B.: to load the .stat field, first "R"
(read_binary_values) a *.w file to get it into
the .val field, then "S/V" (swap_stat_val).

N.B.: to load the .val2 field, first "R"
(read_binary_values) a *.w file containing the
imaginary component to get it into the .val
field, then middle-click-"S/V" (swap_val_val2) to
get it into the .val2 field.  Finally, load the
.val field with another "R" (read_binary_values)
using a *.w file containing the real-valued
component.

N.B.: to load the .valbak and .val2bak fields,
first load the imaginary and real components of a
second complex-valued data set into .val2 and
.val as above.  Then shift-mid-click "S/V"
(swap_valval2_valbakval2bak) to get this second
complex data set into .valbak and .val2bak.
Finally, load the first complex-valued data set
into .val and .val2 (again as above).

N.B.: a data shell can be generated for other
surfaces (e.g., inflated), but sphere_morph()
doesn't (yet) support morphing on them (the
original 'tractor beams' idea!).

Example

To load the curvature image target volume, first
read desired curvature target data onto surface,
then "reverse paint" it to a volume:

  select sulc file from dropdown
  [left-click "R" on "curv:" line]
  shift-middle-click "W" button on "val:" line

or as tcl commands:

  set curv ~/surf/$hemi.sulc
  read_binary_curv
  surf2sphim 0


####################
statpatt
####################

-------------------------------------------
entry variable: $statpatt -- 3D stats file (real)
-------------------------------------------
default: */scandir1/scan1+orig.BRIK

The "val3d:" entry shows the current 3D volume
stat file (usu. not loaded at startup).  To load
a 3D file (usu. AFNI BRIK), select one from the
"val3d:" dropdown and click "R" (auto-detects
complex-valued pairs).

Defines a 3D volume stats file (input to PAINT)
that can be read into a 3D stats buffer to that
it can be interactively 'painted' (sampled onto
the surface) in order to view the data.

The session directory (leading part of the full
path up to the "image" subdirectory) can be
abbreviated as an asterisk (*).  Absolute name is
OK, too.

Examples:

 */scandir1/pol1_r+orig.BRIK
 */scandir1/pol1_i+orig.BRIK

 */scandir1/pol1_r_%03d.bfloat
 */scandir1/pol1_i_%03d.bfloat

The two formats read are: (1) an AFNI float BRIK,
and, (2) a set of slice-by-slice .bfloat files.

In the first AFNI case, there should be a
correspondingly name .HEAD file present.  The
.HEAD file should have BRICK_TYPE => 3 (float
data) and ORIENT_SPECIFIC => 0 4 3 (standard
transverse EPI slice data order).

In the second bfloat case, the series of .bfloat
files should have correspondingly named .hdr
files, each of which should consist of one ASCII
line:

  y  x  t  0

A printf-style pattern is used to match a set of
files, but a single file can also be selected
from the dropdown -- for example, the third
zero-based bfloat file:

 */scandir1/pol1_r_002.bfloat

and the printf pattern will automatically be
substituted when the file set is read.

####################
val3d_read
####################

-------------------------------------------
function: read_native_stat <0=real,1=imag,2=mask>
-------------------------------------------
keyboard equivalent: none

The "R" button on the "val3d:" entry line reads
3D volume stat files into an internal buffer (no
display change).  From there, they can be sampled
onto the surface using the adjacent "PAINT"
button.

Files can be read into one of three buffers:

  read_native_stat 0   => real component buff
  read_native_stat 1   => imaginary component buff
  read_native_stat 2   => mask buff

The input file name is the current value of
$statpatt taken from the "val3d:" entry
immediately entry to the left.

A re-read overwrites previous data in one of
the buffers.

N.B.: subsequent reads must be from BRIK or
bfloat files that have the same dimensions as the
first-read file(s).

The "R" button (wrapper tcl function for button:
read_real_or_complex_native_stats) automatically
attempts to read the partner of a file if it has
a complex-valued infix:

  _r,_i		complex-valued significance files
  _x,_y		complex-valued raw Fourier amplitude

In a tcl script, reading a complex-valued pair
of 3D stat files could be done as follows:

  setfile statpatt */scandir1/pol1_r+orig.BRIK
  read_native_stat 0
  setfile statpatt */scandir1/pol1_i+orig.BRIK
  read_native_stat 1

The setfile command is used to expand the
abbreviation to the full path.

####################
val3d_paint
####################

#### sample 3D data to surface ####
-------------------------------------------
funct (left-click): paint
  paint_surface <fstatflag=0,1>
-------------------------------------------
funct (middle-click): also smooth
  paint_surface <fstatflag=0,1>
  smooth_{val,val_sparse} <steps>
-------------------------------------------


Detailed Description of "PAINT" Button Actions

-------------------------------------------
funct (left-click):
  paint_surface <fstatflag=0,1>
-------------------------------------------

A default left-click on the "PAINT" button on the
"val3d:" entry line samples the 3D volume stat
files previously read into internal buffers onto
the surface using the same code as paint.c (which
is what is called by the PAINT buttons in csurf
panels).  No effect if 3D buffers unloaded.

Sampling surface

PAINT always reloads the current "original"
surface (e.g., "white" or "orig" extension)
before sampling the 3D data.  The sample surface
can be changed on the "NormSamp (PAINT)" pop-up
(see below).  The current surface (e.g., inflated
or a flat patch) is reloaded after sampling.

The parameters that control the sampling
operation are set by tksurfer options:

  -wmgmext <orig,white>			surf to use for sampling
  -normdfracflag <0,1>			0=mm,1=frac along norm
  -normdsampsearchflag <0,1>			samp between limits
  -normdsampuniqvoxflag <0,1>		samp uniqvox
  -normdsampallflag <0,1>			samp every normddstep
  -normdfracsamp <float>			samp pnt or min frac wht->pial
  -normdfracmax <float>			max frac wht->pial
  -normdsamp <float>			samp pnt (or min) mm over wht
  -normdmax <float>			max mm above wht
  -normddstep <float>			searchstep mm/frac
  -normdop <0=max,1=avg,2=min>
  -samevtxthickflag <0,1>			dist to samenum vtx as "thick"

The initial values are loaded from current
settings in csurf for the current scandir.  The
PAINT button blocks some inconsistent settings
(e.g., norm search with non-zero range, min
larger than max).

These parameters can be modified directly from
tksurfer using a pop-up that is accessed by
left-clicking the bold "label:" (these are the
same parameters used for sampling raw timecourses
and stats using a label).

Finally, these parameters can also be controlled
as tcl variables in scripts like this:

  set normdfracmax 0.8
  [set others]
  paint_surface 0

The paint_surface argument, fstatflag, controls
whether the amplitude of a complex-valued stat is
squared and placed in the .stat field to use as a
statistical mask (shortcut to load vertexwise
.stat field when reading complex-valued data that
has amplitude replaced by sqrt(F)).  This is
automatically set to 1 w/complex data.

This can be passed through a cluster exclusion
filter (see help for the "CS" button on normal
surface-based "val:" line).

The paint_surface function forcibly zeros range
by setting max to min if norm search if off.

The "PAINT" button automatically tries to paint
the partner of a file if it has a complex-valued
infix:

  _r,_i		complex-valued significance files
  _x,_y		complex-valued raw Fourier amplitude

The wrapper tcl function for "PAINT" button is:

  paint_real_or_complex

-------------------------------------------
Alt funct (middle-click): also smooth
  paint_surface <fstatflag=0,1>
  smooth_{val,val_sparse} <steps>
-------------------------------------------

Like a default left click, except that the data
is surface-smoothed before redraw, using current
interface settings of smoothtype (e.g., val or
sparse) and steps (e.g., 10 -> ~3mm FWHM).

The wrapper tcl function accepts an option flag
to also smooth:

  paint_real_or_complex 1

####################
val3d_uniq
####################

#### find/write uniq sample vertices ####
-------------------------------------------
functs (left-click): find/show uniq vertices
  find_uniqsamp_vertices
  select_uniqsamp_vertices
-------------------------------------------
functs (middle-click): also write scandir label
  find_uniqsamp_vertices
  select_uniqsamp_vertices
  write_uniqsamp_vertices
-------------------------------------------


Detailed Description of "UQ" Button Actions

-------------------------------------------
functs (left-click):
  find_uniqsamp_vertices
  select_uniqsamp_vertices
-------------------------------------------

A default left-click on the "UQ" button on the
"val3d:" entry line marks 3D-voxel-unique
'representative' vertices.  To do this:

 0) [click "val:" to toggle to "val3d:"]
 1) select 3D stat BRIK from "val3d:" dropdown
 2) read 3D data with "val3d:" "R" button
 3) sample 3D data to surface with "PA" (paint) button
 4) click UQ

Note that this must be a directory with 3D data
and a register.dat in it (see below for
surface-averaged data).

Since 3D functional data usually has larger
voxels than the 1x1x1 (or better) structural
scans used to reconstruct the cortical surface,
each functional voxel will typically be
nearest-neighbor sampled to more than one 2D
surface vertex.

For each set of vertices that has sampled the
same 3D functional voxel (as determined when
paint_surface uniquely numbers the 3D voxels it
is sampling), the "UQ" button does the following:

 1) get avg 3D location of vertices in unique voxel set
 2) find vertex in set whose location is closest to avg
 3) vertex[win].uniqvoxcnt 'winner' set to num vtxs
 4) vertex[lose].uniqvoxcnt 'losers' all set to 0
 5) uniq vertices marked (can be saved, see below)

N.B.: this doesn't work if the normal search
operation ($normdop) is set to 1 (average), since
more than one voxel is sampled in that case.

The resulting set of vertices can be saved in a
label by typing a suitable label name (e.g.,
lh-UniqSampVtxs.label) and ctrl-left-clicking "D"
on the "label:" line, which calls the function,
write_val_selected_list_to_label.

The tcl/C functions used to perform the full
sequence of actions listed at the top (read 3D
data, paint and find unique vox sets, find
representative vertices, display representative
vertices) are:

  read_native_stat <0=real,1=imag>
  paint_surface <fstatflag=0,1>
  find_uniqsamp_vertices
  select_uniqsamp_vertices      ;# display

Sampling surface

The "UQ" button by default temporarily reloads
the coordinates of the current "original" surface
(e.g. "white") before finding uniq vertices for
each sampled voxel (like PA [=paint] does).  To
instead use the current surface for the uniq'ing
operation, tick "c2lab" (this sets
($usecurrcoordsflag to 1).

The difference is subtle.  When the function
find_uniqsamp_vertices is run on an inflated
surface, the nearest-to-average vertex will be in
the middle of the almost flat patch of vertices
labeled by the data from one 3D voxel.

When run on a folded surface, nearest-to-average
vertex is not guaranteed to lie in the middle of
the one-voxel patch AFTER the surface has been
inflated.

The sample surface can be changed on the
"NormSamp (paint/label) and ClusterFilter
Controls" pop-up accessed by clicking the bold
"label:" label (parameter: wmgmext).  The current
surface is reloaded when the operation finishes.

Command line operation (cmdline program: paint)

The program, paint, will directly generate the
uniq sample vertex label if the following
option is appended to its command line:

  -uniqsampvtxs

The result is written to a label in the same
scandir as the other paint output files.

  ?h-UniqSampVtxs.label

Surface-Averaged Data

In the case of data generated by cross-subject
spherical averaging, there will usually be no 3D
datasets or register.dat in the cross-session
average scandir.

One way to generate 'representative' vertices at
a given voxel resolution for surface-averaged
data is to manually register 3D data from one of
the single subjects to target fsaverage, using a
3D timeseries, to generate a register.dat file.
Then read in a 3D stats file from the same
scandir.  To do this:

 1) File -> New Functional
 2) choose fsaverage as the matching subject
 3) SessionTools -> Setup Align/Funct Scans
 4) READ HEADER, use tkregister to align to fsaverage 3D
 5) copy 3D statBRIK and register.dat to average scandir
 6) follow instructions 1-4 at top

How to copy single subj scandir files to surfavg
scandir for step 5 (csh commandline example):

 set onesubj $FUNCTIONALS_DIR/150801/image/pol
 set surfavg $FUNCTIONALS_DIR/150901polavg/image/avg
 cd $surfavg
 cp $onesubj/register.dat .
 cp $onesubj/pol-vreg+orig.HEAD .
 cp $onesubj/pol-vreg+orig.BRIK .

The registration only has to be good enough to
make sure that the fsaverage surface will sample
voxels everywhere as opposed to space outside of
the functional data block (voxel contents are
ignored when calculating 'representative'
vertices).

There will be a harmless "stale vertex list"
error on starting tksurfer with SURFACE-STATS if
you are using a local surface average (not
fsaverage), which should be ignored.

-------------------------------------------
Alt functs (middle-click): also write label
  find_uniqsamp_vertices
  select_uniqsamp_vertices
  write_uniqsamp_vertices
-------------------------------------------

Like a default left click, except that the
selected vertices are also written to a .label
file in the current scandir.  The name of the
label file is first reset to:

  ?h-UniqSampVtxs.label

The function, write_uniqsamp_vertices, always
reloads the orig/sample surface coordinates, even
if "c2lab" ($usecurrcoordsflag) has been ticked
(which WILL STILL affect the operation of
find_uniqsamp_vertices).  Asks overwrite.

####################
val3d_raw
####################

#### read rawdata timeseries (or DTi) & registration ####
-------------------------------------------
functs (left-click): read raw data
  read_regdat
  read_rawdata
  rawdatasubbrik_to_paintable <frame>
-------------------------------------------

A default left-click on the "RD" button on the
"val3d:" entry line opens a pop-up to allow
reading a raw data BRIK ($rawdata, can select
from the "val3d:" dropdown, which contains all
BRIKs in current scandir), and a local
register.dat ($regdat).

Clicking the first button at the bottom of the
popup, "READ RAWDATA and REGISTRATION", reads the
data and registration into memory buffers, so
other functions (e.g., "val3d:" line "V"
(vectors) or "label:" line "T" (time) and "S"
(stat) and "X" (covar)) can do something with the
data.

Some examples of rawdata BRIKs include:

 (1) fMRI time-course series (typically short data)
 (2) 21-volume output of AFNI 3dDWItoDT (float data)

The startup values of $regdat and $rawdata will
typically be initialized by csurf.

If tksurfer is started using the csurf SURFACE
button on the main csurf panel, first use the
"session:" and "scandir:" dropdowns at the right
to pick the desired scandir.  The isession entry
($FUNCTIONALS_DIR/$session/image) is readonly, so
restart tksurfer if it is wrong).

If tksurfer is started using the SURFACE-STATS
button from a SessionTools -> View Functional
Data panel, the initial $regdat and $rawdata will
come from the selected $scandir in the current
panel.

To (re-)set the startup values of $regdat and
$rawdata in a tcl script, use "set" or "setfile"
(a globbing set), before calling the read
functions, for example:

  setfile regdat */some_scandir/register.dat
  read_regdat
  setfile rawdata */some_scandir/some_rawdata+orig.BRIK
  read_rawdata

where "*" is an abbreviation for the "image"
subdir of the current functional session.

The second button, "MAKE FIRST VOL PAINTABLE (for
uniq)" reads the first frame of rawdata into the
paintable (float) buffer so that the data can be
sampled to the surface by the "PA" (PAINT) button
on the "val3d:" line.  After sampling to the
surface, the unique sample vertices (for each
voxel, a 'representative' vertex for all the
vertices that sampled that 3D voxel) can be
calculated with the "UQ" button on the "val3d:"
line.

The "make paintable" operation is automatically
done when a stats volume is read with the "R"
button on the "val3d:" line.  It is not done for
(typically short integer) rawdata, since you
usually do not want to display a rawdata frame on
the surface, and so is only needed for the find
unique vertex operation, cases where you might
not have already loaded a native resolution 3D
stat file (on which the unique-ing operation can
also be done).


####################
val3d_vecs
####################

#### read 3D volume vecs for surface display ####
-------------------------------------------
funct,var (left-click): read 3Dvecs, sample to surf
  read_vecs2surf 9 5
  set dipolesflag 1
-------------------------------------------

A default left-click on the "V" button on the
"val3d:" entry line makes a popup to control
sampling vectors from a volume data for display
on a surface.

This requires first having read a rawdata
float-valued BRIK volume containing at least 3
volumes representing the x,y,z coordinates of the
vector and optionally a 4th volume for a scale
factor at each voxel.  It also requires having
read a corresponding register.dat.

The BRIK may contain more than 4 volumes (can
choose subbrik for x vector and scale factor).

To do those two, first use the "RD" button on the
"val3d:" line.

An example input volume set is output of 3dDWItoDT:
-------------------------------------------
### Calculate diffusion tensor from HARDI dataset (AFNI)
### BRIK: req's 1 init b0, strip extra b0's w/selector
### gradvec.1D line: Gxi, Gyi, Gzi => N.B.: omit *all* b0's
3dDWItoDT -automask -eigs gradvecs.1D \
  'scan02+orig[0..16,18..33,35..50,52..67]'
### outbrik (def=DT+orig, 0-base sel, 6-19 like 3dDTeig 0-13):
#  0-5 -> tensor
#  6-8 -> lambda_1,lambda_2,lambda_3,
#  9-11 -> eigvec_1[1-3]
#  12-14 -> eigvec_2[1-3]
#  15-17 -> eigvec_3[1-3]
#  18 -> FA
#  19 -> MD
-------------------------------------------

Enter the desired AFNI subbrik number for the
x-component of the vector (xvect_subbrik) and the
optional length scale volume (scale_subbrik).
These indices are zero-based (i.e., the first
BRIK in bucket is 0).

Next set the sampling surface and the cortical
depth of the sample.  The default is to sample at
the position of each surface vertex.  To sample
above (or below) that point along the local
surface normal, tick $normdsampsearchflag.  Pick
the units for the sampling distance (mm if
$normdfracflag unticked, or fraction of cortical
thickness if $normdfracflag ticked).  Finally,
set the sampling point (if mm, use $normdsamp_pnt
if fraction of local cortical thickness, use
$normdfracsamp_pnt).

The volume data for each x,y,z coodinate of the
vector set is processed as follows:

 (1) read coord into float volume buffer
 (2) sample to surf (.val) using curr register.dat
       and current vertex normal sampling policy
 (3) copy result into corresponding .dip{x,y,z} field
 (4) optional scale by 4th vol data set (e.g., eigenvalue)
 (5) display vectors as magenta ball-and-sticks

Here is how to perform all the subactions done by
the C/tcl function read_vecs2surf, assuming we
sample the diffusion vector volume at a point
halfway between the gray/white and pial surfaces:

if {$rawdataloaded && $registerdatloaded} {
  ### rawdata -> vector (dipole) display
  set xvectbrik 9
  set scalebrik 5
  set normdsampsearchflag 1
  set normdfracflag 1
  set normdfracsamp 0.5
  set normdfracmax 0.5
  swap_val_valbak    ;# save curr overlay
  for {set i 0} {$i < 3} {incr i} {
    rawdatasubbrik_to_paintable [expr $xvectbrik + $i]
    paint_surface 0
    push_val_dip $i   ;# 0=dipx,1=dipy,2=dipz
  }
  set dipolesloaded 1
  calc_dipavglen      ;# saved in $dipavglen
  ### optional scale by 4th volume data set
  if {$scalebrik >= 0} {
    rawdatasubbrik_to_paintable $scalebrik
    paint_surface 0
    swap_stat_val
    scale_dipxyz_by_stat
  }
  rotate_dti
  swap_val_valbak  ;# restore curr ovelay
  set dipolesflag 1
  redrawbutton
}

This is exactly equivalent to calling the
combined function directly:

if {$rawdataloaded && $registerdatloaded} {
  ### rawdata -> vector (dipole) display
  set xvectbrik 9
  set scalebrik 5
  set normdsampsearchflag 1
  set normdfracflag 1
  set normdfracsamp 0.5
  set normdfracmax 0.5
  read_vecs2surf $xvectbrik $scalebrik  ;# all-in-one
  set dipolesflag 1
  redrawbutton
}


####################
rgb
####################

-------------------------------------------
entry variable: $rgb -- abs filename output bitmap
-------------------------------------------
default: */rgb/tksurfer.tiff (or set by script)

The "rgb:" entry shows the current bitmap image
file name.  To write out the current buffer to
this file, use "W".  To view a previously saved
bitmap, select one from the dropdown and use "R".

This variable is usually pre-set by a script to
the following name format:

  3D:	[scannum]-[scandir]-[hemi]-[surf]-[view].tiff
  flat:	[scannum]-[scandir]-[hemi]-[patch].tiff

Session directory can be abbreviated as an
asterisk (*).  Absolute name OK, too.  Relative
name is appended to $session/rgb/.  Must confirm
overwrite, or use tcl function save_rgb directly
(doesn't ask).  Alternatively, set target rgb
directory ($named_rgbdir) and write rgb file with
tcl function: save_rgb_named <relative_name>.

To quickly see the names of already-saved
bitmaps, do a R-click on the "rgb:" label itself

The default bitmap output format is tiff (3 bytes
per pixel, lossless LZW compression, no
transparency).  To obtain an SGI rgb file, unset
$tiffoutflag by unclicking the unlabled check at
end of the rgb entry, which will update output
file suffix), or restart tksurfer from csurf with
Preferences -> Save .tiff unselected.

If $black2transparentflag is set (Preferences ->
Surf:Black->Transpar ticked), the black
background will be converted to transparent and a
4 byte per pixel tiff will be written (N.B.: some
tiff viewers ignore or mishandle tiffs with
transparency).

Offscreen rendering

The bitmap saved with "WRITE" comes from the
current onscreen window.  To obtain a bitmap that
is larger than the screen size, use offscreen
rendering.  This currently requires a tcl script.
The tcl flag, $renderoffscreen, has to be set to
1 and the window size set with "resize_window"
*before* the GL window has been opened with
"open_window" (if a window is already open, first
close it with "close_window").

Here is an example of a complete tcl script to
read in a particular surface (inflated), a
curvature data set (sulc), a complex-valued
overlay data set (polar1{_r,_i}-$hemi.w), and
then render a high resolution medial view of it
and exit:

  close_window
  resize_window 2500
  set renderoffscreen 1
  open_window
  setfile insurf ~/surf/$hemi.inflated
  read_binary_surface
  setfile curv ~/surf/$hemi.sulc
  read_binary_curv
  make_lateral_view
  set overlayflag 1
  set complexvalflag 1
  setfile val */scandir1/polar1_i-$hemi.w
  smooth_val 10
  push_val_val2
  setfile val */scandir1/polar1_r-$hemi.w
  smooth_val 10
  make_lateral_view
  rotate_brain_y 180
  redraw
  setfile rgb ~/rgb/polar1-rh-inflated-med.tiff
  save_rgb
  exit

Put these commands into a file, test.tcl,
in a functional session scripts directory.
This script can be run, either from the
command line:

  cd $FUNCTIONALS_DIR/130625MS/image/scripts
  tksurfer marty rh smoothwm -tcl test.tcl

or using "GO" (any cmdline surf OK since script
reads a specific one).  The tiff will be written
into the "rgb" subdirectory of the functional
session, and tksurfer will exit.

To render onto a flat patch instead, replace
the script lines:

  make_lateral_view
  rotate_brain_y 180

with:

  set patchname occip.patch.flat  ;# for setdefpatchview
  setfile patch ~/surf/$hemi.$patchname
  read_binary_patch
  restore    ;# tksurfer.tcl func to setup patchview


####################
tiffout
####################

-------------------------------------------
variable: $tiffoutflag -- tiff vs. rgb
-------------------------------------------
default: 1 (TRUE)

The unlabeled tickbox on the "rgb:" entry line
controls bitmap output file format.

When tiffoutflag is 1 (ticked, the default), the
bitmap output file format is a 3 bytes per pixel,
LZW compressed, tiff file.  If tiffoutflag is 0
(unticked), the original SGI rgb bitmap format
(uncompressed) is used instead.

####################
rgb_read
####################

#### display saved bitmaps ####
-------------------------------------------
funct (left-click): display selected bitmap
  nmovie <selected-bitmap>
-------------------------------------------
funct (middle-click): display all tiffs in rgb dir
  nmovie *.tiff
-------------------------------------------


Detailed Description of Rgb "R" Button Actions

-------------------------------------------
funct (left-click): display selected bitmap
  nmovie <selected-bitmap>
-------------------------------------------

A default left-click the "R" button on the "rgb:"
entry line displays the current rgb/tiff file in
entry using the program, nmovie.

The default file name in this entry may not yet
exist.  Existing files will always be found in
the dropdown (or by R-click on "rgb:" to get a
persistent pop-up).

-------------------------------------------
Alt funct (left-click): display all tiffs
  nmovie *.tiff
-------------------------------------------

If the "R" button is middle-clicked, all the
tiffs in directory specified by the current file
in the "rgb:" entry are displayed in one window
by nmovie.

Scroll through them with the arrow keys.  The
filename is in the title bar.

####################
rgb_write
####################

#### write bitmap from current display ####
-------------------------------------------
funct (left-click): write 24bit TIFF/RGB file
  set rgb <outfile>
  save_rgb
-------------------------------------------
funct (middle-click): write transparent-bg TIFF/RGB
  set black2transparent 1
  set rgb <outfile>
  save_rgb
-------------------------------------------


Detailed Description of "rgb:" line "W" Button Actions

-------------------------------------------
funct (left-click): write 24bit TIFF/RGB file
  set rgb <outfile>
  save_rgb
-------------------------------------------

A default left-click on the "W" button on the
"rgb:" entry line writes out the current surface
view in GL window as a 3-byte/pixel TIFF file
(after name expansion if '~' or '*'-abbreviated).

Must confirm overwrite (tcl funct, save_rgb,
doesn't ask overwrite).  Ignores mouse cursor,
pops window to front, and redraws before saving.

Untick nearby checkbutton ($tiffoutflag) to write
SGI *.rgb file instead.

To save cursor and/or timecourse overlay (cleared
on redraw), use adjoining "WN" button instead.
In that case, be sure there are no overlapping
windows before saving.

-------------------------------------------
Alt funct (left-click): write transparent-background TIFF/RGB
  set black2transparent 1
  set rgb <outfile>
  save_rgb
-------------------------------------------

If the "W" button is middle-clicked, a
4-byte/pixel TIFF with the black background
converted to transparent is written.  This is
useful for making figures with overlapping
images.

####################
rgb_write2
####################

#### write bitmap from current display ####
-------------------------------------------
funct (left-click): write 24bit TIFF/RGB file
  [no redraw]
  set rgb <outfile>
  save_rgb
-------------------------------------------
funct (middle-click): write transparent-bg TIFF/RGB
  [no redraw]
  set black2transparent 1
  set rgb <outfile>
  save_rgb
-------------------------------------------


Detailed Description of "rgb:" line "WN" Button Actions

-------------------------------------------
funct (left-click): write 24bit TIFF/RGB file
  [no redraw]
  set rgb <outfile>
  save_rgb
-------------------------------------------

A default left-click on the "WN" button (write,
no redraw) is the same as left-clicking the "W"
button, except there is no pop/redraw, so tmp
overlays (e.g., cyan cursors, rawdata time
courses) will also be saved into bitmap.

N.B.: any overlapping window will be saved into
bitmap so first manually unoverlap the image
window.

-------------------------------------------
Alt funct (left-click): write transparent-background TIFF/RGB
  [no redraw]
  set black2transparent 1
  set rgb <outfile>
  save_rgb
-------------------------------------------

If the "WN" button is middle-clicked, a
4-byte/pixel tiff with the black background
converted to transparent is written.  This is
useful for making figures with overlapping
images.

####################
brainpose
####################

-------------------------------------------
Brain Pose (rotate, translate, scale)
-------------------------------------------

The quickest way to adjust the pose of the
displayed hemisphere is by direct manipulation
using Shift click-drag.  With Shift depressed:

  Rotate  =>  left-click-drag
  Translate  =>  middle-click-drag
  Scale  =>  right-click-drag (up/down)

One Button Mouse or Trackpad

  On Mac, to get a middle or right click out of a
  1-button mouse or a trackpad, open X11 ->
  Preferences -> Input (Tab), tick "Emulate 3
  button mouse", and use:

    opt-click    =>  gives middle-click
    cmd-click  =>  gives right-click

  Thus, for direct click-drag manipulation of a
  surface on a one-button Mac:

    rotate      =>  shift, then click-drag
    translate  =>  shift-opt, then click-drag
       [N.B.: req's order: 1=opt,2=click,3=shift]
    scale      =>  shift-cmd, then click-drag

For controlled rotations, translations, and
scaling, use the sliders and entries in the lower
left part of the tksurfer panel, or use keyboard
shortcuts (arrow keys, +/-)

  Rotate  =>  left/right/up/down arrows
  Rotate in plane  =>  Control-Shift-left/right
  Translate  =>  Shift-left/right/up/down arrows
  Scale  =>  plus/minus keys

If mouse focus is in the buttons window instead
of the display window, add cmd- (Mac) or alt-
(Linux) to avoid manipulating the current entry.

To get back to a lateral view, user RESTORE.

The "Save" and "Goto" buttons can be used to save
and restore any current view (arbitrary rotation,
translation, and scaling) of the current surface.


Really rotate/translate/scale

The ROTATE, TRANSLATE, and SCALE sliders merely
adjust the pose of the surface without changing
the saved coordinates of each vertex.  To
destructively change those coordinates for the
current surface so they can be saved as a new
surface, you can use the following C/tcl
functions from a tcl script:

  really_translate_brain <rh/lh> <ant/post> <sup/inf> [mm]
  really_scale_brain <rh/lh> <ant/post> <sup/inf> [frac,not%]
  really_rotate_brain_x <deg>    [N.B.: lh/rh axis]
  really_rotate_brain_y <deg>    [N.B.: ant/post axis]
  really_rotate_brain_z <deg>    [N.B.: sup/inf axis]
  really_center_brain

Any changes caused by these commands are
accumulated in an internal 4x4 transformation
matrix in tksurfer.  That matrix can be written
to or read from this file:

  $subject/tmp/really.mat

using the C/tcl functions:

  read_really_matrix     [also applies to surf vtxs!]
  write_really_matrix

N.B.: if the "really" functions are used, the
surface will no longer be aligned with the 3D
data from which it was reconstructed.

####################
yrot
####################

-------------------------------------------
variable: $yrot -- rotate brain around y-axis
-------------------------------------------
keyboard equivalent: [Cmd/Alt]-left/right arrow
direct manip. equiv.: Shift-left-click-drag-left/right

The "yrot:" entry (lower left) rotates brain
surface around a vertical axis (i.e., around the
y-axis) in degrees (positive rotates the right
side of the brain towards the viewer).

Clicking in the slider troughs rotates 1 degree.

In a tcl rendering script, this rotation can be
achieved with:

  rotate_brain_y <deg>
  redraw

If focus is on the brain surface window, the
left/right arrows rotate the brain -2/+2 degrees
(in the interface window, cmd-arrow is required
to avoid instead moving the cursor in an entry).

####################
xrot
####################

-------------------------------------------
variable: $xrot -- rotate brain around x-axis
-------------------------------------------
keyboard equivalent: [Cmd/Alt]-up/down arrow
direct manip. equiv.: Shift-left-click-drag-up/down

The "xrot:" entry (lower left) rotates brain
surface around a horizontal axis (i.e., around
the x-axis) in degrees (positive rotates the top
side of the brain towards the viewer).

Clicking in the slider troughs rotates 1 degree.

In a tcl rendering script, this rotation can be
achieved with:

  rotate_brain_x <deg>
  redraw

If focus is on the brain surface window, the
up/down arrows rotate the brain -2/+2 degrees (in
the interface window, cmd-arrow is required to
avoid instead moving the cursor in an entry).


####################
zrot
####################

-------------------------------------------
variable: $zrot -- rotate brain in window plane
-------------------------------------------
keyboard equivalent: [Ctrl]-L/R arrow keys
direct manip. equiv.: none

Rotates brain surface in the plane of the window
(i.e., around the z-axis) in degrees (positive is
counter-clockwise (convention on 2D Cartesian
axes).

In a tcl rendering script, this rotation can be
achieved with:

  rotate_brain_z <deg>
  redraw

####################
winxy
####################

-------------------------------------------
variable: $glwinxydim -- GL window size
-------------------------------------------
default: 600

The "winxy:" entry (lower left) resets the
(enforced square) window to a different specific
value in pixels.

The default window size is 600x600 pixels.

In a tcl rendering script, this can be achieved
with:

  open_window
  resize_window <pix>

####################
xtrans
####################

-------------------------------------------
variable: $xtrans -- translate brain in x-axis
-------------------------------------------
keyboard equivalent: [Cmd/Alt]-Shift-right/left arrow
direct manip. equiv.: Shift-middle-click-drag left/right

The "x:" entry (lower middle) translates brain
surface in the left/right direction in mm divided
by the current scale factor.

That is, translating +10 at the initial default
scale of 1.0 moves the brain 10 mm to the right,
while at a scale of 2.0 (200%), the brain is
moved 5 mm (same proportional distance relative
to the window).

Clicking in the slider troughs translates 1 unit.

In a tcl rendering script, this translation can
be achieved with:

  translate_brain_x <mm/scalefactor>
  redraw

If focus is on the brain surface window, then
Shift-right/left arrow translates the brain -2/+2
mm.  In the interface window, add a command key
(Mac=Cmd, Linux=Alt) to Shift-arrow (this avoids
instead moving the cursor in an entry).

####################
ytrans
####################

-------------------------------------------
variable: $ytrans -- translate brain in y-axis
-------------------------------------------
keyboard equivalent: [Cmd/Alt]-Shift-up/down arrow
direct manip. equiv.: Shift-middle-click-drag up/down

The "y:" entry (lower middle) translates brain
surface in the up/down direction in mm divided by
the current scale factor.

That is, translating +10 at the initial default
scale of 1.0 moves the brain 10 mm up, while at a
scale of 2.0 (200%), the brain is moved 5 mm
(same proportional distance relative to the
window).

Clicking in the slider troughs translates 1 unit.

In a tcl rendering script, this translation can
be achieved with:

  translate_brain_y <mm/scalefactor>
  redraw

If focus is on the brain surface window, then
Shift-up/down arrow translates the brain -2/+2
mm.  In the interface window, add a command key
(Mac=Cmd, Linux=Alt) to Shift-arrow (this avoids 
instead moving the cursor in an entry).

####################
scalepercent
####################

-------------------------------------------
entry variable: $scalepercent -- scale brain
-------------------------------------------
keyboard equivalent: [cmd/alt]-plus/minus
direct manip. equiv.: Shift-right-click-drag-up/down

The "%:" entry (bottom middle) scales the brain
brain around the center of the display window.

Clicking in the slider troughs scales 1 percent.

In a tcl rendering script, this scaling can be
achieved with:

  scale_brain <fraction>   ;# use 1.01 for 1% increase
  redraw

If focus is on the brain surface window, the +/-
keys (no need for Shift) scale the brain up and
down by 1% (in the interface window, cmd-minus or
cmd-plus is required to avoid typing characters
in the current entry).

####################
saveview
####################

#### save/restore surface view ####
-------------------------------------------
funct (left-click): save/goto view (surfer.mat)
  write_view_matrix
  read_view_matrix
-------------------------------------------
funct (middle-click): interactively add suffix
  set viewmatrix surfer.matSUFFIX
  [write or read]
  set viewmatrix surfer.mat
-------------------------------------------
[left click "View" to get current saved list]
-------------------------------------------


Detailed Description of Label "Save/Goto" Buttons

-------------------------------------------
funct (left-click): save/goto view (surfer.mat)
  write_view_matrix
  read_view_matrix
-------------------------------------------

The "Save" and "Goto" buttons (inside lower
middle left TRANSLATE subpanel) read and write
the current OpenGL viewing matrix.

The buttons can be used to save and restore any
current view (arbitrary rotation, translation,
and scaling) of the current surface.  If the same
subject is opened in a 2nd csurf/tksurfer, the
buttons can be used to align the two ("Save" in
one, "Goto" in both).

The C/tcl read_view_matrix and write_view_matrix
functions called by these buttons read and write
an ASCII file (also written to log on "Save"):

  surfer.mat

in the standard per-subject tmp dir:

  $SUBJECT_DIR/<subject>/tmp

This directory path is stored in the tcl
variable, $subjtmpdir, and can be reset to any
(writable) directory in a tcl script.

N.B.: since the SEND and GOTO vertex buttons
(C/tcl functions: find_orig_vertex_coordinates
and select_orig_vertex_coordinates) also read and
write a file (edit.dat) in $subjtmpdir (as does
tkmedit SEND/GOTO), if you change $subjtmpdir,
restore it to default when you are done using it.

-------------------------------------------
funct (middle-click): interactively add suffix
  set viewmatrix surfer.matSUFFIX
  [write or read]
  set viewmatrix surfer.mat
-------------------------------------------

A non-default middle-click on the "Save" and
"Goto" buttons brings up a pop-up to allow adding
an arbitrary suffix to the default view matrix
filename (surfer.mat) before writing or reading
it, for example:

  surfer.mat-GOODPOSE

To find the available view matrices already saved
for a subject, left-click the "View" label above
the buttons.

To restore this previously saved view in a
rendering tcl script, use:

  set viewmatrix surfer.mat-GOODPOSE
  read_view_matrix


####################
dist
####################

-------------------------------------------
funct (left-click):
  print_dist_last2_selected
-------------------------------------------
funct (mid-click):
  compute_avg_edgewidth
-------------------------------------------


Detailed Description of "DIST" Button Actions

-------------------------------------------
funct (left-click):
  print_dist_last2_selected
-------------------------------------------

A default left-click on the "DIST" button (lower
middle) prints Euclidean distance in mm between
last two selected surface vertices to the log.

-------------------------------------------
funct (mid-click):
  compute_avg_edgewidth
-------------------------------------------

An alternate middle-click on the "DIST" button
computes the average inter-vertex distance on the
current surface.

The length of each edge coming from a vertex is
measured and averaged.  To obtain the number of
edges (printed to the log), the total number of
measurements is divided by 2, because each edge
is measured twice (from the vertex at each end).

For a triangular mesh, the number of edges can
also be obtained from the number of faces as
follows:

  edges = faces * 3 / 2

We also have to divide by 2 in this case because
each of the 3 edges of a triangular face are
represented twice by the triangle on either side
of the edge.

The Euler equation relating vertices, edges, and
faces for a closed surface without defects is:

  vertices - edges + faces = 2


####################
dijk
####################

-------------------------------------------
funct (left-click):
  tksurfer tcl proc: getdijk2
-------------------------------------------

The "Dijk" button (lower middle) calculates the
approximate geodesic path between the last two
clicked points on the current surface (using
smoothwm, not the current surface).  The path is
found using a Dijkstra algorithm by the MGH
freesurfer binary, mris_pmake, by Rudolph
Pienaar, and a single-vertex-wide label line is
written to $hemi-dijk.label (context-dependent
location see below).

The path follows the edges of triangular faces
and is therefore very slightly longer than a
geodesic path.

When finished (about 5 sec for a standard
hemisphere), the path is displayed in yellow,
using the label generated by mris_pmake.

The displayed path label can be used to define
the edge of another label since FILL and ROI
respect displayed labels.

If the surface was opened by selecting a subject
from the csurf "subject:" dropdown and clicking
SURFACE, the single-vertex-wide geodesic path
label will be saved inside the subject's label
directory:

  ~/label/$hemi-dijk.label

If the surface was opened by selecting a session
from the csurf "session:" dropdown and clicking
SURFACE-STATS in the View Functional Data panel,
the path label will be saved inside the current
scandir:

  */$scandir/$hemi-dijk.label

Command line used:

 ### vtx0 next-to-last, vtx1 last-clicked
 mris_pmake \
   --subject $subject \
   --hemi $hemi \
   --mpmOverlay euclidean \
   --mpmProg pathFind \
   --mpmArgs startVertex:${vtx0},endVertex:${vtx1}

If the default curv file, $hemi.smoothwm.H.crv,
is not found, $hemi.curv is used instead by
also specifiying "--curv0 curv".

See: https://mail.nmr.mgh.harvard.edu/
  pipermail/freesurfer/2013-January/027543.html

N.B.: with a large surface (e.g., 5M vertex
cerebellum) this program needs a lot of RAM
(more than 16G).

####################
isocont
####################

-------------------------------------------
variable: $isocontourflag -- sphere.reg coords
-------------------------------------------
default: 0 (FALSE)

The "isocont" tickbox (lower middle) toggles
view of sphere-derived contour lines.

When $isocontourflag is 1 (ticked), x,y,z
coordinates from $hemi.sphere.reg are read
(causes small delay first time checkbutton
clicked).  Isocontours from these canonical
coordinates are then displayed on top of any
data.

The sphere has a radius of 100 mm (10 cm).  The
contours will appear as perfect circles on
sphere.reg, but on any other surface or patch,
they will be variously distorted.

Setting isocontourflag has no effect if the
registered sphere surface, sphere.reg, doesn't
(yet) exist.

The tcl parameters affecting the coordinate
isocontour display can be controlled on a popup
available from a R-click help on the "isocont"
tickbox.  They include:

  contourspacingRL    (deg/mm: def=10.0 -> deg/mm)
  contourspacingAP    (deg/mm: def=10.0 -> deg/mm)
  contourspacingSI    (deg/mm: def=10.0 -> deg/mm) 
  contourlinewidthRL  (pixels: def=2.0 -> pix)
  contourlinewidthAP  (pixels: def=2.0 -> pix)
  contourlinewidthSI  (pixels: def=2.0 -> pix)
  isoconttype         (0,1,2,3,4: def=4=latlong)

Setting a contourspacing to 0.0 turns off display
of that set of contours.

The default isocontour display (isoconttype=4) is
latitude and longitude with a superior/inferior
north/south pole, spaced at 10 degree intervals.
The isoconttype options 0-4 are:

  0 -- x,y,z isocontours at 10 mm spacing
  1 -- 3 orthogonal latitudes at 10 deg spacing
  2 -- latitude/longitude with right/left poles
  3 -- latitude/longitude with ant/post poles
  4 -- latitude/longitude with sup/inf poles

For x,y,z and latitudes display, it is less
confusing to look at if only two directions are
displayed, for example:

  set isoconttype 1    ;# latitudes
  set contourspacingRL 0.0
  redraw

In the GLX display window, the main contour lines
can be incrementally thickened with cmd-shift-L.

####################
selectdmax
####################

### select cursor extensions
-------------------------------------------
toggle variable (left-click):
  toggles value of $selectdmax: "click closeness" criterion
-------------------------------------------
toggle variable (middle-click):
  $selectinsideflag -- select inside surf instead, adj lighting
-------------------------------------------

The "clo" tickbox (lower middle) toggles between
the default permissive click-to-vertex criterion
($selectdmax = 2.0 mm) and a rigorous criterion
($selectdmax = 0.25 mm).

Normally, the first vertex within 2 mm of a
perpendicular line from the screen surface to the
cortical surface is selected.  This makes it hard
to 'miss' a vertex.  However, in special cases
(e.g., a 'deep canyon' in a highly folded
cerebellar surface), this can end up selecting a
vertex on one of the 'canyon walls'.  To decrease
the nearness criterion to 0.25 mm, click the
"clo" button at the bottom middle.  Other
criteria can be set by directly adjusting the
tcl/C variable, $selectdmax.

With "clo" ticked, some clicks may now miss
selecting any vertex, and you will have to click
more accurately.

The (tcl-only) variable of the tickbox is
$selectcloseflag.

-------------------------------------------
toggle variable (middle-click):
  $selectinsideflag -- select inside surface, adj lighting
-------------------------------------------

An alternate middle-click on the "clo" tickbox
(middle bottom) toggles $selectinsideflag.  When
this flag is ON, vertices can be selected from
the inside/back surface.

N.B.: this will disable the normal selecting of
vertices on the outside of the surface!
(middle=click again to go back to normal).

This rarely-used facility was written to help
with editing extermely convoluted surfaces such
as the anterior lobe vermis of the human
cerebellum.

To make the surface and the selected vertices
visible, two additional variables are adjusted:

  set lighttwosidedflag 1   ;# show inside surface
  set light1 1.0                ;# also light inside/back surface

Selections on the inside surface are also marked
when viewing the surface from the outside.

A shift-R-click on the "REDRAW" button makes a
popup with full control over the 4 lights
(brightness, x/y/z position, $insidesurffact
(brightness inside relative to outside), and
$lighttwosidedflag.

####################
redraw
####################

#### redraw, stereo, show inside, lights, bigcursor ####
-------------------------------------------
funct: "REDRAW (if stereo, bak to single) (left-click-REDRAW)"
keyboard equivlalent: <Cmd/Alt-r>
  set stereoflag 0
  set convergentflag 0
  redrawbutton
-------------------------------------------
funct: "Divergent Stereo REDRAW (mid-click-REDRAW)"
  set stereoflag 1
  set convergentflag 0
  redrawbutton
-------------------------------------------
funct: "Convergent Stereo REDRAW (shift-mid-clk-REDRAW)"
  set stereoflag 1
  set convergentflag 1
  redrawbutton
-------------------------------------------
funct: "Toggle Light Inside/Back Surf (ctrl-mid-clk-REDRAW)"
  set lighttwosidedflag [expr !$twosidedflag]
  redrawbutton
-------------------------------------------
funct: "Lights Bright/Position Popup (shift-R-clk-REDRAW)"
  lightsctrls
-------------------------------------------
funct: "Toggle Disp Mult Timecourses (ctrl-R-clk-REDRAW)"
  set multitimecourseflag [expr !$multitimecourseflag]
-------------------------------------------
funct: "Toggle BigCursor (shows neigh) (shift-L-clk-REDRAW)"
  set bigcursorflag [expr !$bigcursorflag]
-------------------------------------------
funct: "Select Vertex By Number Popup" (no hotkey)
  set selected $selected_vertex
  set selected_vertex $selected
  leftclick_vertex <vtxnum>
  read_rawdata
  read_regdat
  show_timecourse
  select_uniqsamp_vertices
-------------------------------------------


Detailed Description of "REDRAW" Button Actions

-------------------------------------------
funct: "REDRAW (if stereo, bak to single) (left-click-REDRAW)"
keyboard equivalent: <Cmd/Alt-r>
  set stereoflag 0
  set convergentflag 0
  redrawbutton
-------------------------------------------

The "REDRAW" button procedure (tksurfer.tcl) is
automatically called by most interface elements
that affect the rendered image and rarely has to
be explicitly clicked.

proc redrawbutton {  } {
  transform		;# apply transform
  resize_window 0		;# reshape window
  dolighting		;# reset lights
  redraw		;# C/tcl redraw function
  resettransform		;# reset transform
  after 100		;# stop feedback
}

The default left-click on REDRAW also turns off
stereo viewing if this has been enabled.

-------------------------------------------
funct: "Divergent Stereo REDRAW (mid-click-REDRAW)"
  set stereoflag 1
  set convergentflag 0
  redrawbutton
-------------------------------------------

An alternate middle-click on the REDRAW button
displays divergent stereo viewing.  The brain is
drawn twice, side-by-side, for stereo viewing by
divergent fixation (left copy viewed by left eye,
right copy viewed by right eye).

-------------------------------------------
funct: "Convergent Stereo REDRAW (shift-mid-clk-REDRAW)"
  set stereoflag 1
  set convergentflag 1
  redrawbutton
-------------------------------------------

A second alternate shift-middle-click on REDRAW
displays convergent ('cross-eye') stereo viewing.
The brain is draw twice (left copy viewed by
right eye, and vice versa).  Some people prefer
this to divergent viewing.

-------------------------------------------
Hints for stereo viewing
-------------------------------------------

It is easiest to achieve stereo fusion when there
is single high-contrast target -- e.g., brain at
near initial magnification -- but it is harder to
make out details that way.  If you zoom
(shift-R-click drag up/down) *after* fusing, you
won't break stereo fusion.  To do that, have your
left finger on the shift key *before* you fuse,
since you will break fusion if you have to look
away at the keyboard.  Another useful high
contrast target is the color scale disk or
vertical bar at the lower right.

Stereo viewing is particularly good for
appreciating the orientation of the surface
normal display, and the complex geometry of the
folded (smoothwm) surface.

A Google Daydream or equivalent set of closeup
stereo lenses can be taped to the screen to make
divergent fusion easier (N.B. won't work with
convergent display).

Use "winxy:" ($glwinxydim) to adjust the
intraocular distance.

-------------------------------------------
funct: "Toggle Light Inside/Back Surface (control-mid-clk-REDRAW)"
  set lighttwosidedflag [expr !$twosidedflag]
  redrawbutton
-------------------------------------------

An alternate ctrl-middle-click on the REDRAW
button toggles whether back/inside surfaces
should be lit.

The inside of the closed folded and inflated
surfaces are not normally visible.  Use this
option to visualize the inside of a cut 3D
surface (inside is dark gray).

The PLANE button sets this automatically.

The default is 0 (off).

The relative brightness of the inside surface is
set by $insidesurffact.  This variable (def=0.6)
appears in the larger F3 interface in an
unlabeled entry directly to the right of the
mid-lower right "offset:" entry.

N.B.: when looking at the inside of the brain
surface, there will be a strong 'hollow-face
illusion' (concave surface looks convex) and you
may have to interactively rotate the surface
(shift-left-click-drag) to overcome this.

-------------------------------------------
funct: "Lights Bright/Position Popup (shift-R-clk-REDRAW)"
  lightsctrls
-------------------------------------------

An alternate shift-right-click on the REDRAW
button makes a popup containing the brightnesses
and positions of the fix lights that illuminate
the brain.

The brightness parameters are:

  $light0
  $light1
  $light2
  $light3

and the position x,y,z parameters are:

  $light0x
  $light0y
  $light0z
  $light1x
  $light1y
  [etc]

See right-click help on the popup for details.

-------------------------------------------
funct: "Toggle Display Mult Timecourses (ctrl-R-clk-REDRAW)"
  set multitimecourseflag [expr !$multitimecourseflag]
-------------------------------------------

An alternate ctrl-right-click on the REDRAW
button toggles whether to not to overlay multiple
single-voxel timecourses (from each successive
ctrl-middle-click on a vertex in the surface
window).

The default is 0 (off).

-------------------------------------------
funct: "Toggle BigCursor (shows neigh) (shift-L-clk-REDRAW)"
  set bigcursorflag [expr !$bigcursorflag]
-------------------------------------------

For high resolution surfaces with large number of
vertices (e.g., post-mortem cerebellum scan), it
can be difficult to see which vertex is selected.
When $bigcursorflag is on, an additional ring of
mesh edges are highlighted (normally, only the
edges extending from the selected vertex are
highlighted).

N.B.: when $bigcursorflag is ON, only the central
vertex will still be selected by a left-click
(i.e., the same single-vertex selection as when
$bigcursorflag is OFF) - except in the following
special case:

If $bigcursorflag is ON when the C/tcl command
write_val_selected_list_to_label is executed, the
the neighbors of selected vertices will be
included in the output label.  This is useful
when you want to outline where a cut should be
made using one surface, convert those outlines to
a label, and then display that label on a
different surface - for example, to outline the
cerebellar vermis on the highly folded smoothwm
surface where it is easier to see, save that
outline as a label, then display it on the
inflated surface, where the cuts are much easier
to make.

-------------------------------------------
funct: "Select Vertex By Number Popup" (no hotkey)
  set selected $selected_vertex
  set selected_vertex $selected
  leftclick_vertex <vtxnum>
  read_rawdata
  read_regdat
  show_timecourse
-------------------------------------------

This popup allows manipulating the display with
vertex numebrs (mainly for debugging).

To find the vertex number of a selected vertex
(also available from the csurf log):

  click a vertex in display window
  click CURRENTLY SELECTED VTX on popup

To select a vertex by number:

  enter vertex number in "select_vertex" on popup
  click SELECT VERTEX BY NUMBER

To display the rawdata timecourse for a numbered
vertex:

  enter vertex number in "select_vertex" on popup
  click SHOW VERTEX TIMECOURSE

(last also available from ctrl-middle-click a
vertex in the display window).

The tcl variable $selected is the currently
selected vertex number.  A $selected value of -1
means no vertex is currently selected (e.g.,
after a R-click clear in display windwo).

N.B.: the "selected_vertex" entry on the popup is
*not* updated when you select a vertex in the
display window.  To grab that vertex number into
the "selecte_vertex" entry, use the CURRENTLY
SELECTED VTX button.

Finally, if 3D-voxel-uniq 'representative'
vertices have been computed, SHOW UNIQSAMP
VERTICES (re-)displays them by reselecting them
all.


####################
restore
####################

#### restore, zero position, recalc/move to center ####
-------------------------------------------
funct: "Restore original brain pose (left-click-RESTORE)"
  restore
  [keyboard equiv: <Cmd/Alt-Shift-R>]
-------------------------------------------
funct: "Restore zero pos before rot->lat (shift-L-clk-RESTORE)"
  restore_zero_position
-------------------------------------------
funct: "Recalc Disp Center, coords unchanged (mid-clk-RES.)"
  recalc_surface_center
  restore
-------------------------------------------
funct: "ReCent Coords (misaligns surf/3D) (shift-mid-clk-RES.)"
  really_center_brain
  restore
-------------------------------------------


Detailed Description of "RESTORE" Button Actions

-------------------------------------------
funct: "Restore original brain pose (left-click-RESTORE)"
  restore (tksurfer.tcl)
  [keyboard equiv: <Cmd/Alt-Shift-R>]
-------------------------------------------

Resets transformation matrix (rotation,
translation, scale) to a lateral view for a full
hemisphere and to a perpendicular view for a
flattened patch.

Tcl commands for a hemisphere surface:

  make_lateral_view
  redraw

The make_lateral_view function loads the identity
matrix (surface will be oriented so viewer is
looking at the frontal pole), translates the
brain to the average x,y,z coord to center it,
and then rotates the brain to the left or right
depending on which hemisphere for a lateral view.

Tcl commands for a flat patch:

  restore_zero_position
  rotate_brain_x -90
  redraw

If tcl vars $flatzrot, $flatxtrans, $flatytrans,
or $flatscale are defined, these will then be
applied to a flat patch in that order.

-------------------------------------------
funct: "Restore zero pos before rot->lat (shift-L-clk-RESTORE)"
  restore_zero_position
-------------------------------------------

This function resets viewing transformation
matrix (rotate, translation, scale) to the
identity matrix.

This will be equivalent to the CORONAL view of
the 3D data tkmedit (without the default
translation that puts the average vertex of the
hemisphere at the center of window).  For default
reconstructed smoothwm/inflated surfaces, the
surface will be oriented so viewer is looking at
the frontal pole.

For flat patches, this original view is rotated
(see above) so that the brain/patch is viewed
from the top (tkmedit HORIZONTAL view).  This was
an early decision; it would have been more
intuitive for this to have been a side view
(tkmedit SAGITTAL view).

-------------------------------------------
funct: "Recalc Disp Center, coords unchanged (mid-clk-RES.)"
  recalc_surface_center
  restore
-------------------------------------------

Same as RESTORE but first recalculate surface
center (tcl funct: recalc_surface_center).  This
is useful for re-centering a surface that has
been read in over a centered startup surface
(e.g., when changing between folded and inflated
with the "surf:" dropdown).

-------------------------------------------
funct: "ReCent Coords (misaligns surf/3D) (shift-mid-clk-RES.)"
  really_center_brain
  restore
-------------------------------------------

In contrast to the functions above, which only
affect the display of the surface, this function
actually moves all surface vertices after
recalculating the surface center (tcl funct:
really_center_brain).

Note that this will probably misalign the surface
with any 3D data sets.  Useful for already-cut,
inflated, or flattened surfaces.

Since a patch (surface subset) -- including a 3d
patch -- inherits from a full surface, the
initial centering will come from the full
surface.

####################
save_pnt
####################

-------------------------------------------
funct: find_orig_vertex_coordinates -- save vertex location
-------------------------------------------
keyboard equivalent: <Cmd/Alt-f>

The "SEND" button (upper right) writes the
freesurfer orig surface coordinates of the last
selected vertex location (last left-click) to the
file:

  edit.dat

in the standard per-subject tmp dir:

  $SUBJECTS_DIR/<subject>/tmp

This directory path is stored in the tcl 
variable, $subjtmpdir, and can be reset to any
(writable) directory in a tcl script.

The surface coordinates are found by looking them
up for the same-numbered vertex in the
$origcoords surface file, which by default is set
to:

  $SUBJECTS_DIR/<subject>/surf/$hemi.orig

If $normdsampsearchflag is ticked, the midpoint
of the current search range along the vertex
normal is first added to the coordinates from the
clicked vertex on the orig surface before writing
the edit.dat file.

Note that this uses the *currently* specified
search policy, which may differ from the policy
in effect when the currently displayed surface
vertex overlay data file was generated.  To see
or change the current policy, use popup from a
left click on the bold "label:" text at the upper
left.

The orig coords in the edit.dat file can be read
by tkregister and tkmedit to find and mark the
position of this surface vertex in a 3D data set
-- after adding the midpoint of the search range
along the surface normal.  It can also be read
back into tksurfer to (re)locate/select the same
vertex.

If a Talairach matrix has been loaded, the MNI
305 Talairach x,y,z's is be written as the second
line of the edit.dat file (or MNI 152 coordinates
if the upper left "ta" button is selected and 152
chosen from the popup).  The edit/dat Talairach
coordinates are currently ignored by tkmedit,
tkregister, and tksurfer.

N.B.: the Save/Goto Views buttons in the
TRANSLATE panel (tcl functions: write_view_matrix
and read_view_matrix) also use $subjtmpdir.

####################
goto_pnt
####################

#### GOTO surface point ####
-------------------------------------------
funct (left-click): goto saved vertex location
  select_orig_vertex_coordinates
  (keyboard equivalent: <Cmd/Alt-g>)
-------------------------------------------
funct (middle-click): goto same point other hemi
  select_opphemi_vertex_coordinates
-------------------------------------------


Detailed Description of "GOTO" Button Actions

-------------------------------------------
funct (left-click): goto saved vertex location
  select_orig_vertex_coordinates 
  (keyboard equivalent: <Cmd/Alt-g>)
-------------------------------------------

A default left-click on the upper right "GOTO"
button reads a point in the individual subject
surface coordinate system from the file:

  edit.dat

in the standard per-subject tmp dir:

  $SUBJECTS_DIR/<subject>/tmp

This full directory path is stored in $subjtmpdir
(and can be reset to any writable directory in a
tcl script).

GOTO then finds and marks (with a cyan cursor)
the vertex with the nearest (Euclidean distance)
"original surface" coordinates to the edit.dat
point on the current surface (N.B.: the currently
displayed surface might be a different surface
than orig such as inflated, etc, but "original
surface" coordinates are always used).

The "original surface" coordinates are defined by
the $origcoords file pathname, which by default
is set to:

  $SUBJECTS_DIR/<subject>/surf/$hemi.orig

If the edit.dat surface coordinate point was
written by tksurfer "SEND", then it is guaranteed
to correspond exactly to a vertex on the
$origcoords surface.

However, if the edit.dat surface coordinate
location was written by tkregister or tkmedit
"SEND PNT", it may not correspond exactly to an
$origcoords surface vertex, or may not even be on
the surface.  In that case, the nearest
$origcoords surface vertex is found and marked.

N.B.: if the saved point in edit.dat came from
clicking on a point in the opposite hemisphere in
tkmedit or tkregister, the find-nearest-point
algorithm may produce unanticipated results.  For
example, selecting a point in tkmedit in the
*right* hemisphere, and then using "GOTO" in a
tksurfer that is displaying the *left* hemisphere
of the same subject will usually find a surface
point on the left hemisphere midline.

N.B.: the Save/Goto Views buttons in the
TRANSLATE panel (tcl functions: write_view_matrix
and read_view_matrix) also use $subjtmpdir.

-------------------------------------------
Alt2 funct (middle-click): goto same point other hemi
  select_opphemi_vertex_coordinates
-------------------------------------------

If the "GOTO" button is middle-clicked, it will
instead go to the equivalent point in the
*opposite* hemisphere from the one in which the
point was originally selected/saved using "SEND".

This function is designed to be used on the
fsaverage surface, which provides a standardized
coordinate system with the x-axis perpendicular
to the plane of the midline.

It works by taking the negative of the
x-coordinate of the target point in edit.dat
before finding that surface point on the current
surface.

The easiest way to use this is to open the left
and right hemispheres of fsaverage in two
separate csurf's.

N.B.: using any other single-subject surface
instead of "fsaverage" or appended an version of
fsaverage like "fsaverage-ver17", generates a
warning popup, but then goes to the
(approximately) opposite point.


####################
fliphemi
####################

-------------------------------------------
functs (left-click): mirror-image surface
  really_flip_brain_x
  compute_normals_areas
  redraw
-------------------------------------------

The "FlipHemi" button at the upper far right of
the larger F3 interface mirror-images the
currently displayed surface by taking the
negative of the x-coordinate.

N.B.: this will misalign the surface with any 3D
image data that it was derived from.

N.B.: there is no permanent effect until the
surface is saved (see below).

This operation is occasionally needed for surface
coordinates read in from other software packages
that navtively use a left-handed coordinate
system.

For reference, FreeSurfer (and Talairach) use a
right-handed (RAS) coordinate system:

  +x -> R (right)
  +y -> A (anterior)
  +z -> S (superior)

There are a large number of possible Cartesian
coordinate systems for 3D space (48 possible),
half of which are are right-handed like RAS and
Talairach.  For a left-handed coordinate system
like the PIL system used in Brain Voyager (all
positive):

  +x -> P (posterior)
  +y -> I (inferior)
  +z -> L (left)

if the native x,y,z surface vertex coordinates
are read verbatim into the right-handed
FreeSurfer display system, a right hemisphere
will appear as a left hemisphere, and vice versa.

Reversing (taking the negative of) the
coordinates of any single axis will cause the
surface to be mirror-imaged (the original surface
data file is untouched).  The "FlipHemi" button
on the larger F3 interface does this operation on
the x-coordinate.

The C/tcl functions used by "FlipHemi" are:

  really_flip_brain_x
  compute_normals_areas
  redraw

After the x-coordinate has been flipped, the
order of the corner vertices in the entry for
each face is flipped so that lighting
calculations work correctly.  The y- and
z-coordinates can be flipped with
really_flip_brain_y and really_flip_brain_z.

The resulting flipped surface can be saved to a
native freesurfer surface by entering a name in
the upper-left "outsurf:" entry in the F3
interface and clicking "W".  To perform the same
action with a tcl script, do something like:

  setfile outsurf ~/surf/lh.my_flipped_RH
  write_binary_surface


####################
hbutt
####################

#### help, histograms ####
-------------------------------------------
funct (left-click): tksurfer general help
-------------------------------------------
funct (middle-click): surface region histogram
  print_hist <datatype:0-6> <bins> <smoothsteps>
-------------------------------------------
funct (right-click): [this help]
-------------------------------------------


Detailed Description "h" Button Actions

-------------------------------------------
funct (left-click): tksurfere general help
-------------------------------------------

A default left-click on the far upper right "h"
button on tksurfer pops up general application
help (same as csurf: Help -> tksurfer).

For detailed help, R-click any interface button,
entry, or tickbox.

-------------------------------------------
funct (middle-click):
  print_hist <datatype:0-6> <bins> <smoothsteps>
-------------------------------------------

An alternate middle-click on "h" pops up a panel
to generate a histogram of the current real or
complex surface data using gnuplot (if installed:
looks for gnuplot as /usr/local/gnuplot or
/opt/local/bin/gnuplot).

The pop-up options are:

  $histtype (int: 0-6)

    0:  curvature (.curv)
    1:  real/val (.val)
    2:  complex amplitude of (.val,.val2)
    3:  complex angle of (.val,.val2)
    4:  complex angle if complex amp > $fthresh
    5:  complex angle if .stat > $sfthresh
    6:  statistic (.stat)

  $histbins (def=256, max=1024)

  $histsmoothsteps (def=0)

Each click on READY generates a new gnuplot
window.

-------------------------------------------
funct (right-click);
  helpwin tksurfer
-------------------------------------------
This help.

####################
curv_bgcol
####################

-------------------------------------------
switch variable: $surfcolor -- background color
switch value: 0-4
switch variable: $colscale -- overlay color
switch value: 0-17
-------------------------------------------

Background Color (curvature, sulcus/gyrus)

The radio buttons to the right of "Col:" sets
whether or not to use the .curv data field (which
can be loaded with curvature or sulcus/gyrus) to
modulate the background surface color.

With data overlay off ("ovlay" is unticked,
$overlayflag is 0), the data in the .curv field
is displayed in red and green:

  red: locally concave (or sulcus) => .curv is pos
  green: locally convex (or gyrus) => .curv is neg

If data overlay is turned on ($overlayflag is 1)
and curvature (or sulcus) has been loaded,
curvature or sulcus/gyrus is displayed as two
shades of gray:

  dark gray: locally concave (or sulcus) => .curv is pos
  light gray: locally convex (or gyrus) => .curv is neg

The unlabeled entries further to the right set
the brightness (0-1, default=0.3) and contrast
(0-2, default=1.3) of the grays (numbers below
1.0 reverse contrast of light/dark gray
background color).

Data Overlay ColorScales (real- or complex-valued data)

If data overlay is on ("ovlay" is ticked,
$overlayflag is 1), then there are 17 different
data overlay color scales to choose from.  Seven
are visible on interface (w1, ht, bi, BRy, BR,
lt, fs).  For more colscales, see below.

-------------------------------------------
funct (left-click): make colscale popup
-------------------------------------------

A left-click on "Col:" makes a color scale popup
with more verbose descriptions almost all
available color scales.  R-click help works here,
too.

F3 panel

Displaying area ("ar") and shear ("sh")
distortion as a red/green background color only
works when cortex is being unfolded.

####################
curv_tick
####################

-------------------------------------------
toggle variable (left-click):
  $surfcolor -- toggles curv visibility
-------------------------------------------
toggle variable (middle-click):
  $nobicurvfadeoverfthresh -- toggle separate fade to sulc/gyr
-------------------------------------------

The upper middle right "curv" tickbox controls
two different variables controlling the display
of curvature.

-------------------------------------------
toggle variable (left-click):
  $surfcolor -- toggles curv visibility
-------------------------------------------
default: 1 (TRUE)

The "curv" tickbox under the REDRAW button
controls whether curvature is diplayed.

If ticked ($surfcolor is 1), curvature is shown
as the saturation of red and green, or as two
binary shades of gray (if overlay):

  no overlay: red (concave) vs. green (convex)
  overlay: dark-gray (concave) vs. light gray (convex)

If not ticked ($surfcolor is 0), the background
is uniform.  This is useful for overlay data that
has smooth, low amplitude variations.

The default curvature data set shown is
$hemi.curv -- local curvature measured to
vertices immediately neighboring each single
vertex.  Gyral crowns are convex and sulcal fundi
are concave.  But the banks of sulci typically
contain an even mix of convex and concave
regions.

To see a contrast that is closer to gyrus vs.
sulcus, load the $hemi.sulc data set using the
"curv:" dropdown.  This displays the magnitude of
surface-perpendicular movement that occurred
during unfolding (sulci move further than gyri),
normalized around the mean movement distance.

(The "curv" tickbox is a shortcut to the rarely
used full radiobutton set of none/curv/area/shear
on the big F3 interface).

-------------------------------------------
toggle variable (middle-click):
  $nobicurvfadeoverfthresh -- toggle separate fade to sulc/gyr
-------------------------------------------
default: 0 (FALSE)

By default, overlay colors fade smoothly into the
two different background grays (gyrus light,
sulcus dark) when overlay amplitude decreases
less than fmid.  Ths goal is to see near 
threshold data without the distracting sharp
edges of a hard truncation (by fthresh).  The
differential fading is not normally visible for
overlay amplitudes greater than fmid unless
fslope is extremely shallow (less than 0.5).

To block this behavior, middle-click the "curv"
tick.  This will prevent any modulation of the
overlay color by the underlying sulcus vs. gyrus
color.  It does this by re-setting the underlay
color to sulcus dark, as long as the overlay
amplitude is larger than $fthresh, else both
sulcus dark and gyrus light will be displayed.

N.B.: if $fthresh is less than $fmid, this will
disturb the sulc/gyrus pattern (creating more
dark gray) in regions where overlay amplitude is
above $fthresh (which will cause the background
to be set to sulcus dark), but where a higher
fmid will have already rolled off the color to
background.


####################
curv_none
####################

-------------------------------------------
switch variable: $surfcolor -- background color
-------------------------------------------
default value: 0 => no background surface color

Turns off background surface color leaving
surface gray in places where there is no
functional overlay.

####################
curv_curv
####################

-------------------------------------------
switch variable: $surfcolor -- background color
-------------------------------------------
default switch value: 1 => display curvature

Display curvature (if it has been read in
with function read_binary_curv).

 curv only:  convex = red      concave = green
   overlay:  convex = litegray concave = darkgray


-------------------------------------------
toggle variable (middle-click):
  $nobicurvfadeoverfthresh -- toggle separate fade to sulc/gyr
-------------------------------------------
default: 0 (FALSE)

An alternate (rarely used) middle-click on the
"cv" radio button toggles $nobicurvfadeoverfthresh,
which controls how overlay colors fade into the
two background grays:

  0: (default) fade seperately to two grays
  1: no differential fade if overlay above $fthresh

By default, overlay colors fade smoothly into the
two different background grays (gyrus light,
sulcus dark) when overlay amplitude decreases
less than fmid.  Ths goal is to see near
threshold data without the distracting sharp
edges of a hard truncation (by fthresh).  The
differential fading is not normally visible for
overlay amplitudes greater than fmid unless
fslope is extremely shallow (less than 0.5).

To block this behavior, middle-click the "curv"
tick.  This will prevent any modulation of the
overlay color by the underlying sulcus vs. gyrus
color.  It does this by re-setting the underlay
color to sulcus dark, as long as the overlay
amplitude is larger than $fthresh, else both
sulcus dark and gyrus light will be displayed.

N.B.: if $fthresh is less than $fmid, this will
disturb the sulc/gyrus pattern (creating more
dark gray) in regions where overlay amplitude is
above $fthresh (which will cause the background
to be set to sulcus dark), but where a higher
fmid will have already rolled off the color to
background.


####################
offset
####################

-------------------------------------------
variable: $offset -- brightness background gray
-------------------------------------------
default: 0.30

The first unlabeled entry under the RESTORE
button (just right of "curv" tickbox) sets the
intrinsic brightness of the darker (concave or
sulcus) background gray (1.0 is white).

The lighter gray is set by $offset * $cvfact.
The actual rendered brightness if affected by the
settings of $light0, $light1, $light2, and
$light3.  See also $blufact on large interface
([fn]-F3) to give the brain a bluish or yellowish
tint.

####################
insidesurffact
####################

-------------------------------------------
variable: $insidesurffact -- rel brightness inside
-------------------------------------------
default: 0.60

The second unlabeled entry for "offset", which is
only visible on the larger F3 panel, controls the
relative brightness of the inside surface
(relative to the front surface).

No visible effect unless $lighttwosidedflag is
set (toggle with ctrl-middle-click on REDRAW)
*and* some part of inside surface is visible.


####################
cvfact
####################

-------------------------------------------
variable: $cvfact -- background gray contrast
-------------------------------------------
default: 1.3

The second unlabeled entry under the RESTORE
button (just to left of "intp" tickbox) sets the
contrast of the background light/dark gray
curvature underlay (def=1.3).

Darker gray is set by entry to left ($offset,
def=0.3).  Lighter gray is set by $offset *
$cvfact.  Using a $cvfact less than 1 reverses
contrast.

For ease of blink comparison between conditions,
it is best to keep this constant.

####################
intplut
####################

-------------------------------------------
tickbox var: $interpolatelutflag -- for color LUT's
-------------------------------------------
default: 1 (TRUE)

If the "intp" tickbox (near upper right) is
ticked, r,g,b's for val's in between color lookup
table entries (in e.g., $iscandir/scripts/*.lut)
are interpolated.

If not ticked, colors are constant until val
reaches next highest entry.

For real-valued LUT's, see "bot" tick to control
whether the color LUT val entry sets bottom edge
or center of color, and "sym" tick to determine
whether (s)fthresh and (s)fmid cut into color
scale from symmetrically in both directions from
zero, or just from the bottom.

See help for "lut:" entry for more details.

####################
botedge
####################

-------------------------------------------
tickbox variable: $botedgelutflag -- for real color LUT
-------------------------------------------
default: 0 (FALSE)

If the "bot" tickbox (upper right) is ticked, the
r,g,b entries in the user-defined color lookup
table (e.g., in $iscandir/scripts/*.lut) specify
the bottom of the color range for each given val.

If not ticked, each color in the color LUT define
the center of the color range.


See "intp" tick to control whether colors in
between val table entries are interpolated or
constant, and "sym" tick to determine whether
(s)fthresh and (s)fmid cut into color scale from
the bottom or symmetrically in both directions
from zero.

See help for "lut:" entry for more details.

N.B.: no effect of tick on phase LUT (always ON,
i.e., always interpolated).

####################
zerosymm
####################

-------------------------------------------
tickbox variable: $zerosymmfadeflag -- for color LUT
-------------------------------------------
default: 0 (FALSE)

If the "sym" tickbox (upper right) is ticked,
(s)fthresh and (s)fmid cut into the color scale
symmetrically in both directions from zero.

If not ticked, thresholds only cut in from the
bottom.

See "intp" tick to control whether colors in
between table entries are interpolated or
constant, and "bot" tick to control whether entry
sets bottom edge or center of color,

See help for "lut:" entry for more details.

N.B.: no effect on phase LUT (assumed OFF).

####################
val_w1
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 0 => RBG wheel1 (complex data)

The "w1" (wheel1) color scale is designed for
phase-encoded data (e.g., retinotopic mapping).

Eccentricity maps

With $angle_cycles=1.0, the scale is
red->blu->grn wrapping back through dark yellow
to red (each phase will have a unique color).
Higher integer numbers result in multiple passes
through the color wheel for one cycle of phase.

Polar angle maps (hemifield)

With non-integral $angle_cycles there is only one
red->blu->grn cycle.  Phase values below full red
are clamped to red and phase values above full
green clamped to green.  Higher non-integer
values of $angle cycles (e.g., 3.9) compress
range between full red and full green (i.e., less
blue).  The clamped red and green fade to gray
for ipsiliateral phases (180 deg away from blue)
as controlled by $fadef (1.0=no fade,
0.7=default, smaller for more fade).

Ipsilateral phases can be colored yellow instead
of gray by setting "iy:" ($ipsiyellowfact) to a
non-zero value (from 0.0001 to 1.0).

-------------------------------------------
Alt (mid-click): shortcut to get "w2" w/o fn-F3
-------------------------------------------

Middle-clicking the "w1" button switches to the
"w2" RYGB wheel (colscale=8) without having to
use the extended (fn-F3) panel.  See the
right-click help for "w2" on the fn-F3 panel for
details of that color scale.


####################
val_w2
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 8 => RYGB wheel (complex data)

The "w2" (wheel2) color scale designed for
phase-encoded data (e.g., retinotopic mapping
data).  The scale is:

  Red -> Yellow -> Green -> Blue -> Red

Setting angle_cycles > 1.0 results in multiple
cycles through the scale.  Fractional numbers do
not wrap gracefully.


####################
val_w3
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 16 => MBCGYR wheel (complex data)

The "w3" (wheel3) color scale is designed for
phase-encoded data.  The scale is:

  Magenta->Blue->Cyan->Green->Yellow->Red

followed by a mirror image of that sequence:

  Red->Yellow->Green->Cyan->Blue->Magenta

This color scale is specific to polar angle data.
A quarter cycle offset is included so that zero
phase corresponds to the horizontal meridian.

The scale can be rotated by using $angle_offset.
Using $truncphaseflag works, but $angle_cycles
and $invphaseflag have no effect.

####################
val_w4
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 18 => ORBGY wheel (complex data)

The "w4" (wheel4) color scale was designed by
Fred Dick for auditory cortical maps (complex
data).  It has more colors than the standard
green-blue-red wheel, and a built-in gray region
at the phase wrap-around point.

The scale is:

 Gray -> Orange -> Red -> Blue -> Green -> Yellow -> Gray

The scale can be rotated with $angle_offset,
reversed with $revphaseflag, and 180-deg flipped
with $invphaseflag.  There is no effect of
$angle_cycles, $fadef, or $ipsiyellowfact.

####################
val_bi
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 4 => two-cond red-grn (complex data)

The "bi" (bicolor) color scale designed for
two-condition, phase-analyzed data (standard
ON/OFF design).

The first half of the phases (correlated with the
ON stim in an ON/OFF design) are, by default,
colored red.  The the second half (correlated
with the OFF stim) are colored green.

A *positive* angle_offset cancels a delay in the
functional signal.

The phase value limits applied when truncphase is
selected are in units of 0-1, *after* the phase
has been (optionally) adjusted by:

  "rev" tickbox:
     -> reverse time with $revphaseflag

  "invph" tickbox:
     -> add half a cycle with $invphaseflag (=mult by -1)

  "angleoffset" entry:
     -> subtract $angle_offset

Adjustable/Arbitrary ON and OFF colors

Arbitrary ON and OFF colors can be entered in the
[fn-]F3 panel in the three r,g,b "col1" and the
three r,g,b "col2" entries (a little below the
REDRAW button).

The first time the "bi" color scale is selected,
these r,g,b entries will be set to pure red (255
0 0) and pure green (0 255 0), but can be reset
arbitrarily (update on REDRAW or carriage return
in an entry).

Implementation

The phaseangle is first converted from 0-1 to
0-2Pi.  This is then turned into a color
saturation as follows:

 sat = tanh(phaseangle*(fslope -   0)) *
        -tanh(phaseangle*(fslope -  Pi)) *
        -tanh(phaseangle*(fslope - 2Pi));

The result is an adjustable, clipped sine-like
curve.  At fslope=1.0, the color saturation of
each phase is approximately the sine of the phase
angle.  Phases near the boundary between red and
green will fade to gray, and full saturation will
only be reached at a phase of Pi/2 and 3Pi/2.
With fslope > 10, all the colors in each half of
the phase wheel will be fully saturated, and the
red/green transition will be abrupt.

####################
val_ht
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 1 => pos heat scale (complex data)

The "ht" (heat) color scale requires
complex-valued data.  It runs from dark brown to
white.  If "trunphase" it unticked
($truncphaseflag is 0), it displays any brain
region significantly activated in a periodic
fashion (i.e., it ignores phases).

Ticking "truncphase" causes half of the phases to
be truncated.  The "angleoffset" entry
($angle_offset) controls exact half that are
truncated.

The $angle_offset for two condition expt with 20s
ON and 20s OFF should be approximately 0.1 (this
is in units of one cycle: 0.1 * 40 sec = 4 sec
delay).

####################
val_BRy
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 11 => blue/red to yellow/cyan (real data)

The "BRy" (blue/red -> cyan/yellow) color scale
is for real-valued, possibly signed statistics.

Red is positive and blue is negative, which can
be reversed by ticking "invph" (set $invphaseflag
to 1).

As significance increases, the scale changes from
red->yellow and blue->cyan.

Not affected by $angle_offset, $angle_cycles,
and $revphaseflag.

Unlike other scales, the units of $fmid and
$fthresh are *not* equivalent -- $fmid should
always be higher than fthresh.  If fmid is set
less than $fthresh, there is a warning, and you
get green colors.

The setting of $fthresh sets the roll off to
background grays, while the setting of $fmid sets
the red->yellow and blue->cyan transition
points.

-------------------------------------------
Alt (mid-click): shortcut to get "jet" w/o fn-F3
-------------------------------------------

Middle-clicking the "BRy" button switches to the
"jet" MATLAB wheel (colscale=15) without having
to use the the "Col:" popup or the extended
(fn-F3) panel.

####################
val_BRw
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 6 => blu/red to white (real data)

The "BR" (blue/red -> cyan/orange -> white) color
scale is for real-valued, possibly signed
statistics.

Red is positive and blue is negative, which can
be reversed by ticking "rev" (set $revphaseflag
to 1).

As significance increases, scale goes from
blue/red to cyan/orange to white/white.

Not affected by $angle_offset, $angle_cycles, or
$invphaseflag.

-------------------------------------------
Alt (mid-click): shortcut to get "vd" w/o fn-F3
-------------------------------------------

Middle-clicking the "BR" button switches to the
"vd" CARET videen-style wheel (colscale=17)
without having to use the the "Col:" popup or the
extended (fn-F3) panel.

####################
val_lt
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 12 => color lookup table (real data)

The "lt" (color lookup table) color scale is
designed for user-entered real-valued custom
val->rgb color lookup table.

See right-click help for the "lut:" entry and
buttons to the left (below label line) for more
details on LUT file formats and LUT file flags.

Fade-out Options

By default, this color scale is truncated to
background when the real-valued data is below
$fthresh.  For a smooth fade out, use $fmid,
which sets 50% saturation point.

If a stat has also been loaded (and "mask"
ticked), LUT colors are also truncated to
background when the *stat* is below $sfthresh (or
get faded out using $sfmid, which sets 50%
saturation point).

To make the fade out symmetric around zero
instead of bottom-only (default), set
$zerosymmfadeflag.  To toggle this flag on and
off interactively, click "sym".

To toggle defining colors by their bottom edge
instead of their center (default), click "bot".

To block any truncation or fading of positive
data, toggle $zerosymmfadeflag to 0, unclick
"mask", and set fthresh and fmid to 0.  If the
data and LUT go negative, use a suitably negative
fthresh and fmid.

Complex Phase or Amplitude (vs. def real-valued)

To use a custom color scale to display complex
phase use colorscale "ltw".  To display complex
amplitude, use colorscale "lta".  Click "Col:" to
get a popup with these (and other) color scales.
See right-click help for "ltw" and "lta" buttons
there for details.

####################
val_lta
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 13 => color lookup table (complex ampl)

The "lta" (color lookup table, complex amplitude)
color scale is designed for user-entered
real-valued custom color look-up table for the
*amplitude* of a complex-valued signal.

Left-click the "Col:" label to get a popup to set
this scale, and R-click on the "lta" radio button
there for details on how to use this color scale.

####################
val_ltw
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 14 => color lookup table (complex phase)

The "ltw" (color lookup table, complex phase) is
designed for user-entered complex-valued custom
complex *phase* -> rgb color look up table.

Left-click the "Col:" label to get a popup to set
this scale, and R-click on the "ltw" radio button
there for details on how to use this color scale.

Rarely used

On the fn-F3 large interface, a middle-click
(instead of a left click) on the "ltw" button
instead selects $colscale=13, which is for a
custom complex *amplitude* -> rgb color look up
table.

####################
val_GR
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 7 => green/red (real data)

The rarely used "GR" (green-red) colorscale is
for signed, real-valued statistics.

Red is positive and green is negative (reversible
with revphaseflag).  Remains green and red as
significance increases.

Not affected by angle_offset, angle_cycles, and
invphase.

####################
val_fs
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 9 => blu/yel fieldsign (real data)

The "fs" (fieldsign) color scale designed for
field sign data only.  Yellow is mirror-image
field sign (e.g., V1) and blue is
non-mirror-image fieldsign (e.g., V2).

####################
val_jt
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 15 => MATLAB Jet (blu/cyan/yel/red)

The "jt" (MATLAB Jet) colorscale is for real data
(signed or all-positive), or for complex
amplitude.

N.B.: unlike other colscales, to control this
color scale, enter bottom and top data values
into the unmarked entries under the truncphase
button enter data values.  Any data values
smaller than the left entry or larger than the
right entry are clamped to the limiting colors
(dark red, dark blue).  Negative numbers in
entries are OK as long as left entry smaller than
right.

Also in contrast to other color scales, extreme
values are dark, so well adapted to data with a
central tendency (light yellowish-green near
center of scale).

Fade-out Options

Color is truncated to background when the
real-valued data below $fthresh (and/or fades out
below $fmid, which sets 50% saturation point).

If a stat has also been loaded (and "mask"
ticked), colors are also truncated to background
when the *stat* is below $sfthresh (and/or fades
below $sfmid, which sets 50% saturation point).

The setting of $zerosymmfadeflag (see next)
determines whether fthresh/fmid and
sfthresh/sfmid threshold data from the bottom, or
whether they cut into data symmetrically around
zero.

For full color saturation, set fthresh and fmid
to 0.0.

Initial Scale End Settings

When this color scale is interactively selected,
if only real data has previously been read onto
the surface, fmid and fthresh are set to 0.0 and
an initial estimate of the clamped ends of the
color scale (-5.0, 5.0) are set in the entries
under truncphase.  These can be subsequently
reset.

If data is real, $zerosymmfadeflag is set to 1
(fthresh/fmid and sfthresh/sfmid fade out data
symmetrically around zero).  If data is complex
(see next), $zerosymmfadeflag is set to 0 (to
display positive-only complex amplitude).

To toggle this flag on and off interactively,
click "Col:" to get the all-color-scales popup 
and do a *middle* click on "MATLAB Jet Signed".

Complex Data (amplitude)

If complex-valued data has previously been read
onto the surface, then the complex amplitude will
be colored.  This will instead initially clamp
the ends of the color scale to ($fthresh,
$fmid*4) and set $zerosymmfadeflag to 0.

To desaturate the colors, use small fslope (0.1)
with a negative fmid (-1.0).  This allows
background grays (or just gray if Col: "none" is
clicked) to begin to show through.

Flip Colorscale Ends

To flip ends of color scale use the "invphase"
tickbox ($invphaseflag is 1).  This flips around
zero, so you will have to adjust the color scale
ends if they are not symmetric around zero.

####################
val_vd
####################

-------------------------------------------
switch variable: $colscale -- funct color scale
-------------------------------------------
switch value: 17 => CARET "videen-style" (spectral)

The "vd" (CARET "videen-style" spectral) color
scale is for real data (signed or all positive),
or for complex data amplitude.

N.B.: unlike other colscales, to control this
color scale, enter bottom and top data values
into the unmarked entries under the truncphase
button enter data values.  Any data values
smaller than the left entry or larger than the
right entry are clamped to the limiting colors
(black, red).  Negative numbers in entries are OK
as long as left entry smaller than right.

Fade-out Options

Color is truncated to background when the
real-valued data below $fthresh (and/or fades out
below $fmid, which sets 50% saturation point).

If a stat has also been loaded (and "mask"
ticked), colors are also truncated to background
when the *stat* is below $sfthresh (and/or fades
below $sfmid, which sets 50% saturation point).

The setting of $zerosymmfadeflag (see next)
determines whether fthresh/fmid and 
sfthresh/sfmid threshold data from the bottom, or
whether they cut into data symmetrically around
zero.

For full color saturation, set fthresh and fmid
to 0.0.

Initial Scale Settings

When this color scale is interactively selected,
$zerosymmfadeflag is set to 0.  To toggle this
flag on and off interactively, click "Col:" to
get the all-color-scales popup and do a *middle*
click on "CARET Videen-Style".  If set,
fthresh/fmid and sfthresh/sfmid fade out data
symmetrically around zero.

Complex Data (amplitude)

If complex-valued data has previously been read
onto the surface, then the complex amplitude will
be colored.  This will instead initially auto-set
$fthresh to 0, and clamp ends of the color scale
to (0.0, $fmid*4).

Flip Colorscale

To flip ends of color scale use the "invph"
tickbox ($invphaseflag is 1).  This flips around
zero, so you will have to adjust the color scale
ends if they are not symmetric around zero.

####################
mesh
####################

#### toggle mesh view, points view ####
-------------------------------------------
toggle variable (left-click):
  $edgesflag -- toggle surface mesh
-------------------------------------------
toggle variable (middle-click):
  $pointsflag -- toggle surface vertex points
-------------------------------------------


The upper middle MESH button (under REDRAW) has
two different functions.

-------------------------------------------
Left-click (toggle $edgesflag)
-------------------------------------------

A default left-click on the "MESH" button toggles
drawing of edges of surface polygons in addition
to the polygon, just above filled polygon.
Standard surface have so many polygons they won't
generally be individually visible without
zooming.

Control color of mesh with entries to right of
button ($meshr, $meshg, $meshb), which are also
used to color labels, and report and choose MGH
annotations,

Control the width of the mesh line in pixels
(default=1.1) with $meshline, which is accessible
(along with edgesflag) from a popup made on a
R-click (help) on the unlabeled tickbox at the
bottom of the middle right "phc" (phase contours)
box.

-------------------------------------------
Middle-click (toggle $pointsflag)
-------------------------------------------

An alternate middle-click on the "MESH" button
toggles the drawing of a point just above each
non-cut-away vertex.  This is mainly useful for
displaying sparse labels that don't have enough
vertices to be displayed as faces (at re-cut
time).  An example is when a uniq vtx label is
re-cut by a ctrl-left-click "C" on the "label:"
line.

Control color of vertex points with entries to
right of button ($meshr, $meshg, $meshb), which
are also used to color the mesh, labels, and
report and choose MGH annotations,

You can control points display and size (with
$pointsize) from a popup made on a R-click (help)
on the unlabeled tickbox at the bottom of the
middle right "phc" (phase contours).

Finally, a shift-middle click on the lower right
PTS button will turn on $pointsflag and increase
$pointsize to 2 for the purpose of finding stray
vertices when editing a label.

####################
meshr
####################

-------------------------------------------
variable: $meshr -- mesh/label/annot red (0-255)
-------------------------------------------
default: 120

The "r" (red) entry next to the "MESH" button
has seven uses:

 1) sets red component (0-255) of polygon mesh
    color (display/hide with MESH).

 2) sets red component (0-255) of next label
    that is displayed using the "D" button on the
    "label:" line.  Changes do not affect color
    of already-displayed labels.

 3) sets red component (0-255) of the next
    display of vertex points (toggle point
    visibility with middle-click MESH butt).

 4) sets red component (0-255) of the next
    display of annotation border dots
    ($annotborddotflag on LABEL CONTROLS popup).

 5) sets red component (0-255) of the next
    display of coordinate isocontours (lower 
    middle "isocont" tickbox).

 6) reports red component of MGH annotation
    label color at currently clicked vertex
    (if MGH annotation loaded)

 7) sets red component of MGH annotation
    label color used to extract underlying
    .val(.val2) vertex data


####################
meshg
####################

-------------------------------------------
variable: $meshg -- mesh/label/annot green (0-255)
-------------------------------------------
default: 120

The "g" (green) entry next to the "MESH" button
has seven uses:

 1) sets green component (0-255) of polygon mesh
    color (display/hide with MESH).

 2) sets green component (0-255) of next label
    that is displayed using the "D" button on the
    "label:" line.  Changes do not affect color
    of already-displayed labels.

 3) sets green component (0-255) of the next
    display of vertex points (toggle point
    visibility with middle-click MESH butt).

 4) sets green component (0-255) of the next
    display of annotation border dots
    ($annotborddotflag on LABEL CONTROLS popup).

 5) sets green component (0-255) of the next
    display of coordinate isocontours (lower 
    middle "isocont" tickbox).

 6) reports green component of MGH annotation
    label color at currently clicked vertex
    (if MGH annotation loaded)

 7) sets green component of MGH annotation
    label color used to extract underlying
    .val(.val2) vertex data


####################
meshb
####################

-------------------------------------------
variable: $meshb -- mesh/label/annot blue (0-255)
-------------------------------------------
default: 255

The "b" (blue) entry next to the "MESH" button
has seven uses:

 1) sets blue component (0-255) of polygon mesh
    color (display/hide with MESH).

 2) sets blue component (0-255) of next label
    that is displayed using the "D" button on the
    "label:" line.  Changes do not affect color
    of already-displayed labels.

 3) sets blue component (0-255) of the next
    display of vertex points (toggle point
    visibility with middle-click MESH butt).

 4) sets blue component (0-255) of the next
    display of annotation border dots
    ($annotborddotflag on LABEL CONTROLS popup).

 5) sets blue component (0-255) of the next
    display of coordinate isocontours (lower
    middle "isocont" tickbox).

 6) reports blue component of MGH annotation
    label color at currently clicked vertex
    (if MGH annotation loaded)

 7) sets blue component of MGH annotation
    label color used to extract underlying
    .val(.val2) vertex data

####################
rect
####################

-------------------------------------------
variable: $colscalerectflag -- toggle rect/disk
-------------------------------------------
default: 0 (off)

The "bar" or "rect" or "off" button (upper right)
toggles the state of the lower right display
window color scale inset between 3 states:

 (1) disk color scale (phase is angle if
     non-integral angle_cycles and radius if
     intergral angle_cycles).

 (2) rectangular phase color scale inset
     (x-axis is phase, y-axis is significance)

 (3) off

Use $fullpolrectflag ("ful" in [fn]-F3 interface)
to toggle half/full phase range of rect with
non-integral $angle_cycles.

In state (1), the disk represents the the color
saturation for complex amplitude input of
2.0*fmid (i.e., fully saturated).  To see a range
of saturations, use state (2).

In state (2), the bottom of the rectangular phase
color scale represents the color saturation for a
complex amplitude input of zero.  The top of the
rectangle starts out representing a complex
amplitude input of 2.0*fmid.  The top limit can
be reset with the entry to the right of "bar"
(just above "fthresh").

N.B.: the effects of the stat mask are not
represented in the rect/disk insets (with the
rectangle, a 3D volume would be required to
represent colors for all different combinations
of phase, amplitude, and stat).

####################
cm2
####################

-------------------------------------------
variables: $scalebarflag, $colscalebarflag
-------------------------------------------
default: both 1 (on)

The "cm" button (upper right) toggles the
visibility in the display window of both the
horizontal 10 mm (1 cm) scalebar as well as the
color scale inset.

####################
col1col2
####################

-------------------------------------------
variables: set explicit colors for "bi" colscale
  --------- r,g,b for OFF phases
  $colr1
  $colg1
  $colb1
  --------- r.g,b for ON phases
  $colr2
  $colg2
  $colb2
-------------------------------------------

The "bi" colscale by default uses green for OFF
phases and red for ON phases.

Arbitrary colors for OFF and ON in the "bi"
colscale can be specified by setting these 6
variables before redraw.

####################
truncphase
####################

-------------------------------------------
tickbox var: $truncphaseflag -- for complex data
-------------------------------------------
default: 0 (FALSE)

The upper middle "truncph" tickbox (just under
the "MESH" button) toggles truncation of
complex-valued data by phase limits.

When $truncphaseflag is 1 ("truncph" is ticked),
only the phases within the interval specified in
the unlabeled entries on the next line are shown,
while phases outside the limits truncated to
background surface color.

The truncphase limits wrap.  For example:

  trunphasemin=0.3 truncphase=0.9
    => show phases between 0.3 and 0.9

  trunphasemin=0.9 truncphase=0.3
    => show phases between 0.9 and 1.0
    => show phases between 0.0 and 0.3

N.B.: the truncphase limits are applied *after*
the phase has been (optionally) adjusted by "rev"
(reverse time), "invph" (add half a cycle, which
equals multiply by -1), and "angleoffset"
(subtract arbitrary phase).

The tickbox immediately to the left labeled "sft"
controls $softtruncphaseflag, which linearly
ramps the cutoff edges to zero (see its R-click
help for details).

####################
truncphasesoft
####################

-------------------------------------------
tickbox var: $softtruncphaseflag -- for complex data
-------------------------------------------
default: 0 (FALSE)

The upper middle "sft" tickbox (just to the right
of "truncph", under the "MESH" button) toggles
truncation of a complex-valued data by soft phase
limits.  Ticking the "sft" unticks "truncph" and
vice versa.

This uses same phase limits as $truncphaseflag
(unlabeled entries immediately below tickboxes),
and wraps in the same way, but instead of
truncating to zero (background color) beyond the
phase limits, linearly rolls off to zero over an
additional angular width ($softtruncwidth:
def=0.05) beyond each truncation endpoint.

Ramping to zero reduces the contrast and therfore
the distracting prominence of the (irrelevant)
ragged shape of the color edge at the truncation
endpoint.

-------------------------------------------
entry var: $softtruncwidth -- ramp-to-zero width (0-1)
-------------------------------------------
default: 0.05

The ramp width is controlled by the unlabeled
entry below the truncphase endpoints entries
(immediately right of "invph").  The ramp width
is constrained to be half of the truncated range.


####################
softtruncwidth
####################

-------------------------------------------
entry var: $softtruncwidth -- ramp-to-zero width (0-1)
-------------------------------------------
default: 0.05

The ramp width is controlled by the unlabeled
entry below the truncphase endpoints entries
(immediately right of "invph").  The ramp width
is constrained to be half of the truncated range.


####################
truncphasemin
####################

-------------------------------------------
entry variable: $truncphasemin -- truncate phase min
-------------------------------------------
default: 0.25

The left unlabeled entry below the "truncphase"
tickbox is $truncphasemin.

This is only used for complex-valued data if
"truncphase" is ticked ($truncphaseflag is 1).
It adjusts the min phase angle below which color
scale is hard truncated to background grays.
Applied *after* $revphaseflag, $invphaseflag, and
$angle_offset.  Effects are also shown in phase
wheel inset at lower right of display window.
For gradual fade out, use fadef instead (or in
addition).

The truncphase limits wrap.  For example: 

  trunphasemin=0.3 truncphase=0.9
    => show phases between 0.3 and 0.9

  trunphasemin=0.9 truncphase=0.3
    => show phases between 0.9 and 1.0
    => show phases between 0.0 and 0.3


Truncphase{min,max) overloaded to control real-valued

The $trunphasemin and $trunphasemax fields are
also used to control the data-value endpoints of
the real-valued MATLAB JET colorscale ("jet") and
the CARET 'videen-style' colorscale ("vd"),
accessible from the popup available by R-clicking
the "Col:" label.

####################
truncphasemax
####################

-------------------------------------------
entry variable: $truncphasemax -- truncate phase max
-------------------------------------------
default: 0.75

The right unlabeled entry below the "truncphase"
tickbox is $truncphasemax.

This is only used for complex-valued data if
"truncphase" is ticked ($truncphaseflag is 1).
It adjusts the max phase angle below which color
scale is hard truncated to background grays.
Applied *after* $revphaseflag, $invphaseflag, and
$angle_offset.  Effects are also shown in phase
wheel inset at lower right of display window.
For gradual fade out, use fadef instead (or in
addition).

The truncphase limits wrap.  For example: 

  trunphasemin=0.3 truncphase=0.9
    => show phases between 0.3 and 0.9

  trunphasemin=0.9 truncphase=0.3
    => show phases between 0.9 and 1.0
    => show phases between 0.0 and 0.3


Truncphase{min,max) overloaded to control real-valued

The $trunphasemin and $trunphasemax fields are
also used to control the data-value endpoints of
the real-valued MATLAB JET colorscale ("jet") and
the CARET 'videen-style' colorscale ("vd"),
accessible from the popup available by R-clicking
the "Col:" label.

####################
invphase
####################

-------------------------------------------
tickbox variable: $invphaseflag -- add phase of pi
-------------------------------------------
default: 0 (FALSE)

The "invph" tickbox (center-left) inverts phase
of complex color scales, but is also used to
invert the ends of some real-valued colscales.

For Fourier-analyzed data, when $invphaseflag is
1 ("invph" is ticked), Pi phase is effectively
added to the time course, that is, f(t) ->
f(t+Pi).

This is equivalent to multiplying phase by -1.

####################
overlay
####################

-------------------------------------------
tickbox variable: $overlayflag -- toggle funct overlay
-------------------------------------------
default: 0 (FALSE)

The "ovlag" tickbox (just right of center)
toggles visibility of a data overlay.

When "ovlay" is ticked ($overlayflag is 1), the
background surface colors are changed to grays,
and functional data (from the .val[.val2] fields)
is overlaid in color on the surface.

If curvature has been loaded, and radio button to
right of "Col:" is set to "curv", the curv scale
changes from red/green to light/dark gray.  If
the "none" radio button is selected, there is a
single shade of gray.

The brightness ratio of the grays is adjustable
by $cvfact (def=1.3) and the single or darker
gray color is set by $offset (def=0.3) (unmarked
entries just to right).

####################
complexval
####################

-------------------------------------------
tickbox variable: $complexvalflag -- toggle complex data
-------------------------------------------
default: 0 (FALSE)

The "cpx" tickbox (just right of center) toggles
whether data is displayed as real-valued or
complex-valued.

When "cpx" is ticked ($complexvalflag is 1), the
functional data value is assumed to have two
components (real, imaginary).  A phase angle is
calculated and used to generate the color scale.
The colorscale radio buttons reset this flag
appropriately.

N.B.: if a complex-valued colscale (0,1,4,8,18)
is currently set and "cpx" is unticked, the
colscale is changed to real-valued
(colscale=6=BR) to avoid showing a blank surface.

N.B.: If a real-valued colscale (6,11) is
currently set and "cpx" is ticked, the colscale
is changed to complex-valued (colscale=0=w1) to
avoid showing a blank surface.

N.B.: complex data displayed using a real-valued
color scale or real data displayed using a
complex-valued color scale can be confusing to
interpret.

N.B.: colscales 15 and 17 can display real-valued
data or the amplitude of complex-valued data.


####################
statmaskamp
####################

#### toggle statmask, statANDhypot mask ####
-------------------------------------------
toggle variable (left-click):
  $statmaskampflag -- toggle use of stat mask
-------------------------------------------
toggle variable (middle-click):
  $statANDhypotflag -- ROI uses stat AND complex amp
-------------------------------------------
toggle variable (ctrl-middle-click):
  $statANDrealflag -- ROI uses stat AND real amp
-------------------------------------------


The "mask" tickbox (just right of center) toggles
the application of a statistic mask to real- or
complex-valued amplitude data.

N.B.: the two overloads only control how and ROI
fill is done.

-------------------------------------------
Left-click (toggle $statANDhypotflag)
-------------------------------------------

When ticked ($statmaskampflag is 1), the fthresh,
fmid, and fslope entries are each doubled (and
the labels are abbreviated to "fthr:", "fmid",
and "fslo:").

The first entry in each pair controls the
threshold and contrast of the real or complex
amplitude itself.  For example, if a value (or
complex amplitude) is below current $fthresh, it
will not be visible in the overlay.

The second set of entries in each pair controls
whether the amplitude values are masked further
based on what is found in the currently loaded
stat mask.  For example, if the value of of the
invisible .stat field for this pixel is below the
current $sfthresh, the *value* will be masked.

If unticked, the interface goes back to one set
of "fthresh", "fmid", and "fslope" entries for
controlling the amplitude overlay threshold and
contrast.

HOWTO Load Stat Mask

The stat mask is loaded with:

  setfile val <statwfile>
  read_binary_values
  swap_stat_val

Note that this overwrites the .val field, so
.stat should be loaded before val.  Before
loading, stat is initialized to 0.

There is also a direct load function:

  setfile stat <statwfile>
  read_binary_stats

-------------------------------------------
Middle-click (toggle $statANDhypotflag)
-------------------------------------------

A non-default middle-click on this checkbutton
toggles $statANDhypotflag.  This only affects the
lower middle right ROI button "FILL" operation.
This will only fill connected vertices that have
.stat greater than $sfthresh AND complex
amplitude (hypot(.val,val2) greater than
$fthresh.

Setting this turns incompatible $statANDrealflag
OFF.

-------------------------------------------
Control-Middle-click (toggle $statANDrealflag)
-------------------------------------------

A non-default control-middle-click on this
checkbutton toggles $statANDrealflag.  This only
affects the lower middle right ROI button "FILL"
operation.  This will only fill connected
vertices that have .stat greater than $sfthresh
AND real amplitude (.val) greater than $fthresh.

Setting this turns incompatible $statANDhypotflag
OFF.


####################
statmultamp
####################

-------------------------------------------
tickbox variable: $statmultampflag -- toggle multiply by stat
-------------------------------------------
default: 0 (FALSE)

When statmultampflag is TRUE (mul selected), the
amplitude of complex-valued data is *multiplied*
by the value of the stat field.  The stat field
is loaded with:

  setfile val <somefile>
  read_binary_values
  swap_stat_val

Note that this overwrites the val field, so stat
should be loaded before val.  Before loading, the
stat field will be 0.

####################
statreplamp
####################

-------------------------------------------
tickbox variable: $statreplampflag -- toggle stat replace
-------------------------------------------
default: 0 (FALSE)

When statreplampflag is TRUE (stat selected), the
amplitude of complex-valued data is *replaced* by
the value of the stat field.  The stat field is
loaded with:

  setfile val <somefile>
  read_binary_values
  swap_stat_val

Note that this overwrites the val field, so stat
should be loaded before val.  Before loading, the
stat field will be 0.

####################
minstat
####################

-------------------------------------------
variable: $minstatcolscale -- color bar min
-------------------------------------------
default: [autoscale]

Entry to the left of "bar" (above "fthresh:")
controls overlay statistic value for the bottom
of the vertical scale bar (lower right, in the
surface display window).

This also controls the min vertical limit of the
rectangular phase color inset (x-axis is phase,
y-axis is significance), available on clicking
the upper right "rect" button (just to left of
"cm").

Initially autoscaled but can be manually reset.
To redo autoscale, set both max and min to 0.

####################
maxstat
####################

-------------------------------------------
variable: $maxstatcolscale -- color bar max
-------------------------------------------
default: [autoscale]

Entry to the right of "bar" (above "fthresh:")
controls overlay statistic value for the top of
the vertical scale bar (lower right, in the
surface display window).

This also controls the max vertical limit of the
rectangular phase color inset (x-axis is phase,
y-axis is significance), available on clicking
the upper right "rect" button (just to left of
"cm").

Initially autoscaled but can be manually reset.
To redo autoscale, set both max and min to 0.

####################
fthresh
####################

-------------------------------------------
entry variable: $fthresh -- statistical hard threshold
-------------------------------------------
default: 0.3

The "fthresh:" entry sets the vertex-wise overlay
value (or complex amplitude value) below which
the background gray surface color is displayed.
Use an equivalent fmid to achieve a smoother
roll-off into the background color.

For most color scales, the units of fthresh are
the same as those of fmid.

When "mask" is checked, the data is subject to
two different thresholds -- the amplitude data
(in .val[.val2]) compared to $fthresh, but also
the stat data (in .stat) compared to $sfthresh.

For complex-valued data, the stat field and the
real and imaginary data fields can be manually
loaded from the tksurfer tools interface as follows
(this is usu. done by csurf):

  1) type name stat wfile in "val:" field
  2) "R" button (on "val:" line)
  3) optional SMOOTH (w/val ticked)
  4) "S/V" (swap .stat and .val)
  5) type name real-valued wfile in "val:" field
  6) "R" (auto-reads matching imaginary pair of real wfile)
  7) opt. SMOOTH (auto-detects complex-val'd, does both)
   
or from a tcl script as follows:

  ### read/smooth/load stat
  set val /some/stat/wfile
  read_binary_values
  smooth_val <steps>
  swap_stat_val
  ### read/smooth/push imaginary
  set val /some/imaginary/wfile
  read_binary_values
  smooth_val <steps>
  push_val_val2
  ### read/smooth real
  set val /some/real/wfile
  read_binary_values
  smooth_val <steps>
  ### show
  redraw

####################
sfthresh
####################

-------------------------------------------
entry variable: $sfthresh -- statmask hard threshold
-------------------------------------------
default: 0.3

This unmarked entry (second entry after "fthr:")
is only visible if "mask" ($statmaskampflag) is
ticked.

If the stat mask for a pixel is below this
number, the displayed *value* (e.g., complex
amplitude or HDR response amplitude estimate) is
masked to background.

The units of this mask threshold ($sfthresh) will
*not* in general be the same as the units of the
amplitude thresh ($fthresh).

See $fthresh and $fmid help for more details.

Note that the color scale bar and the color scale
bar limits are in amplitude units, not stat mask
units.

The color scale bar in the surface display window
is *not* statmasked, and so only affected by
$fthresh, $fmid, and $fslope.

####################
phcont
####################

-------------------------------------------
tickbox variable: $phasecontoursflag -- show
-------------------------------------------
default: 0 (FALSE)

When the "phc" tickbox (middle right) is ticked
($phasecontoursflag is 1), white polygon-wise
isophase contours are shown (no effect if not
complex-valued data).

Number and width of phase contours are controlled
by "n" and "w" entries below.

The sharp edge of each phasecontour points in
direction of phase gradient (steepest uphill
direction).  The opposite edge fades into the
current phase color (downhill direction).

####################
phcont_num
####################

-------------------------------------------
variable: $phasecontours -- num phasecontours
-------------------------------------------
default: 40

The "n" entry below the "phc" tickbox sets the
number of white, signed phase contours across 360
degrees of response phase (see color wheel
inset).  Note that only approximately half this
many contours will be seen for a stimulus that
only activates one hemifield.

####################
phcont_width
####################

-------------------------------------------
variable: $phasecontoursfrac -- phasecontour width
-------------------------------------------
default: 0.4

The "w" entry below the "phc" tickbox sets the
fraction of distance between each phase contour
that is shaded white.  The high end of each phase
contour (positive gradient direction) is white.
The low end fades back into the local phase
color.

####################
arrownorm
####################

#### ARROWS/NORMALS/POINTS CONTROLS ####
-------------------------------------------
variable: $arrowscale (popup) -- arrow length
-------------------------------------------
variable: $arrowline (popup) -- arrow stem thickness
-------------------------------------------
variable: $arrowheadfracauto (popup) -- head frac stem len
-------------------------------------------
variable: $arrowheadmin (popup) -- minimum head length
-------------------------------------------
variable: $line_arrowbarbangle (popup) -- angle barbs/stem
-------------------------------------------
variable: $filled_arrowtipangle (popup) -- ang tip-edge/stem
-------------------------------------------
variable: $filled_arrowbarbangle (popup) -- ang barbs/stem
-------------------------------------------
toggle popup variable (left-click tickbox):
  $arrownormflag -- toggle gradient arrow norm
-------------------------------------------
toggle variable (popup):
  $filledarrowsflag -- toggle filled vs. line arrows
-------------------------------------------
toggle variable (popup):
  $centerarrowsflag -- toggle center arrow on vertex
-------------------------------------------
toggle variable (popup):
  $angoffrevarrflag -- toggle display polar arrows
-------------------------------------------
toggle variable (popup):
  $rmgradoutliersflag -- toggle rm grad arrows outliers
-------------------------------------------
toggle variable (ctrl-middle-click tickbox):
  $normalsflag -- toggle display vertex normals
-------------------------------------------
toggle variable (shift-right-click tickbox):
  $dipolesflag -- toggle display vertex vectors from .dipole
------------------------------------------
toggle variable (left-click MESH button):
  $edgesflag -- toggle display vertex vectors
-------------------------------------------
toggle variable (middle-click MESH button):
  $pointsflag -- toggle display vertex points
-------------------------------------------
toggle variable (shortcut: [fn]-k)
  $bigcursorflag -- toggle display bigger select cursor
-------------------------------------------
variable: $meshline -- for left-click MESH button
-------------------------------------------
variable: $pointsize -- for middle-click MESH button
-------------------------------------------
button: GRAD ARROWS -> COLOR (popup button)
  (also: shift-middle click tickbox)
  tcl funct: display gradient amplitude as color
-------------------------------------------

The unlabeled tickbox and entry at the bottom of
the middle right "phc" (phasecontours) panel
toggles the normalization of gradient arrows and
has an aditional 6 overloaded functions related
to gradient arrows and other per-vertex vectors
and points.

The best way to access these (and more above)
parameters is by a right-click on that tickbox to
pop up a control panel (along with the help
window).

Many of these parameters are duplicated on the
FIELDSIGN and GRADIENTS ARROWS popup available
from a R-click on the unlabeled tickbox to the
left of "fs:".


-------------------------------------------
variable: $arrowscale (popup) -- arrow length
-------------------------------------------

The displayed length of gradient arrows can be
globally adjusted with the entry variable,
$arrowscale (default=2.0), which is a fraction
applied to all arrows.  Alternatively, if arrow
length has been normalized (made all the same)
with $arrownormflag, $arrowscale will then be in
units of mm.

-------------------------------------------
variable: $arrowline (popup) -- arrow stem thickness
-------------------------------------------

The thickness of the line used to draw line
arrows (stem and arrowhead are lines) is
controlled with the entry variable, $arrowline.
When $filledarrowsflag is ticked, this entry
controls the thickness of the arrow stem.

-------------------------------------------
variable: $arrowheadfracauto (popup) -- head frac stem len
-------------------------------------------

This variable specifies the size of the arrowhead
as a fraction of the arrow stem length; as the
arrow length declines, the arrow barbs do too
(with a minimum cutoff, see next variable).  To
turn off this scaling, in order to get constant
size arrowheads, set this to 0.0.

-------------------------------------------
variable: $arrowheadmin (popup) -- minimum head length
-------------------------------------------

When $arrowheadfracauto (above) is non-zero, this
variable, $arrowheadmin, sets the minimum size of
the arrowhead (as a fraction of the arrow stem
length).  When arrow-length normalization is
turned off by settings $arrowheadfracauto to
zero, this variable will set the fixed size for
all arrowheads.

-------------------------------------------
variable: $line_arrowbarbangle (popup) -- ang barbs/stem
-------------------------------------------

For line arrows, this variable sets the angle of
the arrow barbs relative to the arrow stem
(default 22.5 deg).  No effect on filled arrows.

-------------------------------------------
variable: $filled_arrowtipangle (popup) -- ang tip-edge/stem
-------------------------------------------

For filled arrows, this variable sets the angle
of the tip of the arrow relative to the arrow
stem (default 15 deg).  If this angle is small
(like the default), the sides of the arrow barbs
will be concave.  Increasing it will make sides
of the arrow barbs flat, and then eventually
convex.  Set to taste.  No effect on line arrows.

-------------------------------------------
variable: $filled_arrowbarbangle (popup) -- ang barbs/stem
-------------------------------------------

For filled arrows, this variable sets the angle 
of the arrow barbs relative to the arrow stem
(default 60 deg).  Increasing it makes a fatter  
arrowhead.  No effect on filled arrows.

-------------------------------------------
toggle variable (left-click bottom "phc" tickbox):
  $arrownormflag -- toggle gradient arrow norm
-------------------------------------------

This unlabeled tick at the bottom of the
phasecontour box ("phc") (or $arrownormflag on
the popup) toggles whether gradient vector
lengths are normalized to the same length or are
proportional.  Gradient vectors are calculated
and displayed when the "F" (fieldsign) or "GR"
(calculate gradients) buttons on the "fs:" line
are used.  See the R-click help for "F" and "GR"
for details.

If the gradients were calculated on phase-encoded
data (i.e., on the phase angles), they will be
appoximately perpendicular to the iso-phase
contours (hence placement of these controls
here).

The unmarked entry immediately to the right of
the tickbox scales the gradient vectors (whether
normalized or not).  When $arrownormflag
(constant length gradient arrows) is enabled,
that field will be autoset to a sane value of 0.5
mm (which can be adjusted afterward).

-------------------------------------------
$filledarrowsflag (popup) -- toggle filled vs. line arrows
-------------------------------------------

This toggles between line arrows and filled
arrowheads.  The filled arrowheads are made of
four adjustable triangles: two for the arrow
barbs, and two forming a diamond for the point.

Depending on the data gradients, other arrow
parameters may need adjusting when this is
toggled.  There is a DEFAULT LINE/FILL ARROWS
button to set defaults for each type.

Currently filled arrows only working for 2D/flat
gradient arrows (no effect of ticking this on 3D
surface arrows).

-------------------------------------------
$centerarrowsflag (popup) -- toggle center arrow on vertex
-------------------------------------------

The default state (ON) centers the stem of the
arrow on the vertex to which it belongs (else,
the arrow stem starts from the vertex).

The only time this is forced off is when two
arrows are drawn at each vertex to illustrate the
polar and and eccentricity gradients at the same
time.

-------------------------------------------
toggle variable (middle-click tickbox):
  $angoffrevarrflag -- toggle display polar arrows
-------------------------------------------

A non-default middle-click toggles the value of
$angoffrevarrflag, which causes polar angle data
in the val/val2 fields to be displayed as arrows.
For more details see the end of the R-click help
for the check box just to the left of "fs:".

-------------------------------------------
toggle variable (popup):
  $rmgradoutliersflag -- toggle rm grad arrows outliers
-------------------------------------------

This toggles whether to remove of overly large
gradient arrow outliers (based on the standard
deviation of the other arrow amplitudes), as well
as overly tiny arrows (based on tiny vertex
area).  The limits themselves can be adjusted on
the popup available from a R-click on the
unmarked tickbox just to the left of "fs:" or on
the "GR" button.

-------------------------------------------
toggle variable (ctrl-middle-click tickbox):
  $normalsflag -- toggle display vertex normals
-------------------------------------------

A third non-default control-middle-click toggles
display of vertex normals as yellow lines with a
ball end.  The length of the lines can be
controlled by the adjoining entry ($arrowscale,
default=2.0) and the line thickness can be
controlled from a tcl script ($arrowline,
default=1.0).

A Shift-Return (instead of a default Return) in
the adjoining entry sets both $arrowscale and
$arrowline to the current entry value.

-------------------------------------------
toggle variable (shift-right-click tickbox):
  $dipolesflag -- toggle display vertex vectors
-------------------------------------------

A fourth non-default shift-right-click toggles
display of vertex vectors (e.g., DTi
eigenvectors) as cyan lines with a ball end.  The
length of the lines can be controlled by the
adjoining entry ($arrowscale, default=2.0) and
the line thickness can be controlled from a tcl
script ($arrowline, default=1.0).

A Shift-Return (instead of a default Return) in
the adjoining arrowscale entry sets both
$arrowscale and $arrowline to the current entry
value.

------------------------------------------
toggle variable (left-click MESH button):
  $edgesflag -- toggle display vertex vectors
-------------------------------------------

This toggles the display of the surface mesh on
and off (equivalent to left-clicking on the MESH
button).

-------------------------------------------
toggle variable (middle-click MESH button):
  $pointsflag -- toggle display vertex points
-------------------------------------------

This toggles the display of the vertex points on
and off (equivalent to middle-clicking on the
MESH button).

-------------------------------------------
toggle variable (shortcut: cmd/alt-k)
  $bigcursorflag -- toggle display bigger select cursor
-------------------------------------------

For high resolution surfaces with large number of
vertices (e.g., post-mortem cerebellum scan), it
can be difficult to see which vertex is selected.
When $bigcursorflag is on, an additional ring of
mesh edges are highlighted (normally, only the
edges extending from the selected vertex are
highlighted).

When $bigcursorflag is ON, only the central
vertex will be selected by a left-click (i.e.,
the same single-vertex selection as when
$bigcursorflag is OFF) - except in the following
special case:

If $bigcursorflag is ON when the C/tcl command
write_val_selected_list_to_label is executed, the
the neighbors of selected vertices will be
included in the output label.  This is useful
when you want to outline where a cut should be
made using one surface, convert those outlines to
a label, and then display that label on a
different surface - for example, to outline the
cerebellar vermis on the highly folded smoothwm
surface where it is easier to see, save that
outline as a label, then display it on the
inflated surface, where the cuts are much easier
to make.

-------------------------------------------
variable: $meshline -- for left-click MESH button
-------------------------------------------

Sets the width of the lines in the surface mesh
toggles by the MESH button.  The default is 1.0
pixel (fractional pixels accepted).

-------------------------------------------
variable: $pointsize -- for middle-click MESH button
-------------------------------------------

Sets the point size of vertex points (toggle on
with a middle-click on MESH).  This is mainly
useful for displaying sparse labels that don't
have enough vertices to be displayed as faces (at
re-cut time).  An example is when a uniq vtx
label is re-cut by a ctrl-left-click "C" on the
"label:" line.

-------------------------------------------
button: GRAD ARROWS -> COLOR (popup button)
  (also: shift-middle click tickbox)
  tcl funct: display gradient amplitude as color
-------------------------------------------

Clicking GRAD ARROWS -> COLOR button on the popup
(or a non-default shift-middle-click on the
unlabeled tickbox at the bottom of the "phc"
subpanel) converts a displayed-as-arrows gradient
data set to a real-valued color gradient
amplitude overlay.  This can only be done once
after calculating a gradient.  To redo, first
reload data, and recalc the gradient on it.  Here
are the tcl commands executed on
shift-middle-click:

  swap_valval2_valbakval2bak
  compute_angles_vals_to_baks
  swap_valval2_valbakval2bak
  swap_val_val2
  set gradvecbakflag 0
  set complexvalflag 0
  set overlayflag 1
  set colscale 6
  set fthresh 0.0
  set fmid 0.08
  set fslope 10.0
  redraw

For more explanatory details, see the R-click
help for the "GR" (gradient) button.


####################
arrowscale
####################

-------------------------------------------
variable: $arrowscale -- gradient arrow scaling
default: 0 (FALSE)
-------------------------------------------
Return -- set $arrowscale
Shift-Return -- set both $arrowscale and $arrowline
-------------------------------------------

This unlabeled entry (at the bottom of the
phasecontour box, "phc") scales the length of
gradient arrows displayed when the "F"
(fieldsign) or "GR" (calculate gradients) buttons
on the "fs:" line are used.  See "F" and "GR"
help for details.  This entry also scales the
length of vertex normal vectors when they are displayed.

The unmarked checkbox immediately to the left of
the entry toggles the normalization gradient
vectors.  If ticked, the units of the value typed
into the entry will be mm.  If not ticked, the
value is multiplied by gradient length to scale
it.  That checkbox can also be used to toggle the
display of vertex normal vectors.

If gradients have been calculated using
phase-encoded data, the gradient arrows (fastest
changing direction of scalar data) will be
appoximately perpendicular to the phase contours
(direction of no change in scalar data).  This is
why these controls have been placed near the
phase contour controls.

Shift-Return -- also set $arrowline

A Shift-Return instead of a default Return in
this entry also sets $arrowline to the current
entry value.  The default is 1.0

####################
fslope
####################

-------------------------------------------
entry variable: $fslope -- statistical contrast
-------------------------------------------
default: 1.5
keyboard shortcut:
  Cmd-s,S  =>  adjust fslope 0.5 up/down

The "fslope:" entry controls steepness of the
saturation sigmoid (or double sigmoids with
two-ended/signed color scales), whose midpoint is
set by $fmid.

Small values of $fslope result in a nearly linear
relation between statistic and color saturation
while large values result in a step function
cutoff at the value of $fmid (i.e., same as a
hard threshold).

N.B.: The meaning of "small" and "large" above
depends on the range of the data.

For Fourier-analyzed, complex-valued data such as
the sqrt(F) found in the {_r,_i} files, the data
will range from 0-10.  In this case, an $fslope
of 1.5 will provide a smooth roll-off, while an
$fslope of 10 will result in a hard threshold.

For Fourier-analyzed, complex-valued data such as
the raw Fourier amplitude found in the {_x,_y}
files, the data will typically range from 0-1000.
In this case, an $fslope of 0.01 will provide a
smooth roll-off, while an $fslope of 0.1 will
result in a hard threshold.

The equation mapping data (0-whatever)to color
saturation (0-1) is:

  saturation = (1 + tanh(fslope*(data - fmid)))/2;

Thus, in general, $fslope should be inversely
related to the data range to obtain the same
visual effect.

####################
sfslope
####################

-------------------------------------------
entry variable: $sfslope -- statmask contrast
-------------------------------------------
default: 1.5

This unmarked entry (second entry after "fslo:")
is only visible if "mask" ($statmaskampflag) is
ticked.

This entry controls steepness of the *stat mask*
color saturation sigmoid (or double sigmoids with
two-ended/signed color scales).

Smaller values give a more linear relation
between statistic and color saturation.  Larger
values approach a hard threshold.

See $fmid and $sfmid R-click help for more
details.

####################
fmid
####################

-------------------------------------------
entry variable: $fmid -- statistical sigmoid threshold
-------------------------------------------
default: 1.1
keyboard shortcuts:
  Cmd-i,I  =>  fmid 0.1 up/down [e.g., sqrtF]
  Cmd-u,U  =>  fmid 10.0 up/down [e.g., raw fourieramp]

The "fmid:" entry is the primary way to set an
activation threshold.  It adjusts the position in
amplitude units (e.g., sqrt F-ratio) where the
overlay color contrast display color reaches 50%
saturation.  See "fslope:" to adjust contrast
(slope of the sigmoid).

Fmid effectively sets a soft threshold.  To set a
hard threshold, use $fthresh.  Setting $fthresh
equal to $fmid truncates lower half of the
sigmoid (for all color scales *except* BRy).

Typical Settings for Complex-valued Data

For Fourier-analyzed complex-valued data, the
{_r,_i} files will have amplitude replaced by
sqrt(F), so an fmid around 2.5 is a good starting
point.  The {_x,_y} files contain the raw fourier
amplitude, so an fmid around 350.0 is a good
starting point (both for unsmoothed data).

PerVertex ColorScale Pipeline Outline

  1)  get background sulc/gyrus color (to fade into)
  2a) if real data: get amplitude, f
  2b) if complex data: get complex amplitude, f
  2c) if stat mask: get optional real stat
  3)  hard threshold f to zero if f below $fthresh
  4)  if mask, hard thresh f to zero if *stat* below $sfthresh
  5)  sigmoid (tanh) transform f into 0-1 ($fmid,$fslope)
  6)  opt 2nd sigmoid transform f to 0-1 ($sfmid,$sfslope)
  7a) if real, translate f to color
  7b) if complex, trans. phase ang to col, f to col saturation
  8)  as f goes to 0, color fades to 1 of 2 background grays

In double-ended scales, there are two sigmoids
both controlled by fmid/fslope at equal distances
either side of zero.

How The Sigmoid Squashing Functions Work

The bare function y = tanh(x) is a sigmoid.  The
output, y, is about -1 for x less than -2.  The
output passes through 0 at x equals 0, and is
about 1 for x greater than 2.

The tanh function is used as follows.  The
fslope/sfslope variables control the steepness of
the transitions.  A small fslope (0.01) is
approximately linear while a large fslope (10) is
basically a step from background color to fully
saturated color at the point where input
amplitude equals fmid.  The fmid/sfmid variables
control where the transition occurs.  Here is
the outline C code:

first amplitude squash:

    f = (1 + tanh(fslope*(f - fmid)))/2;

second stat squash:

    f = f * (1 + tanh(sfslope*(fabs(stat) - sfmid)))/2;

N.B.: the appropriate fslope for the squashing
function depends on the range of the data.  In
general, fslope (steepness of sigmoid ramp)
should be inversely related to fmid (data value
at middle of ramp) and the data range, in order
to get a similar visual effect.

The discussion above assumed display of an
F-ratio or a z-score (0-10).  For data with a
larger range such as the raw fourier amplitude
(0-1000), a visually similar effect requires a
much smaller fslope (e.g., 0.01), since the
transition from noise to signal is spread out
over a larger range of values.

Relation Between (s)fmid and (s)fthresh

The (s)fthresh variables do a sharp cutoff using
the value entered.  This can generate visually
distracting sharp edges to activations.  The
(s)fmid variables set the 50% saturation point
using the value entered.  With a medium fslope
(e.g., 1.5 with F data in the range of 1-10),
colors will fade rapidly into the background
below the value entered, but without distracting
edges.  Set (s)fmid to the same as (s)fthresh to
truncate the 'fade'.

To see these effects in the color scale bar,
click on "RECT" at the upper right to get an x-y
scale bar (phase left-right, significance
up-down) and play around with the values of
fthresh and fmid.

####################
sfmid
####################

-------------------------------------------
entry variable: $sfmid -- statmask sigmoid threshold
-------------------------------------------
default: 0.0

This unmarked entry (second entry after "fmid"
entry) is only visible if middle-right "mask"
($statmaskampflag) is ticked.

The $sfmid entry defines the soft threshold for
masking the displayed "data" using a number in a
second "stat" file.  For example, the complex
amplitude or HDR response amplitude estimate
("data") can be masked with an estimated F-ratio
("stat").

This has the same usits as $sfthresh, but
performs a soft/fading threshold.

See the $fmid help for a lot more details.

N.B.: the units of this stat mask threshold
($sfmid) will *not* in general be the same as the
units of the data amplitude thresh ($fmid).

N.B.: the color scale bar and the color scale bar
limits are in amplitude units, not stat mask
units.

N.B. the color scale bar in the surface display
window is *not* stat-masked and so is only
affected by $fthresh, $fmid, and $fslope.

####################
cslope
####################

-------------------------------------------
variable: $cslope -- red/green curvature contrast
-------------------------------------------
default: 3.0

Controls steepness of contrast sigmoid for
red/green curvature display.  Large values result
in pure red vs. pure green.  No effect on color
of light/dark gray underlay (use two grayed-out
entries at far right above color scale buttons to
adjust underlay gray brightness and contrast).

####################
cmid
####################

-------------------------------------------
variable: $cmid -- red/green curvature midpoint
-------------------------------------------
default: 0.0

Adjust position (in curvature units) where where
color changes from red to green (gray point in
curvature display), or from lightgray to darkgray
(overlay display).  Settings above 0.0 emphasize
convex (green/lightgray, negative curvature)
while settings below 0.0 emphasize concave
(red/darkgray) positive curvature).

The second unlabeled entry is $dimredcurvfact,
which dims red (sulcus) in curvature display.
This provides (e.g., at 0.8) better contrast for
full color illustrations, better conversion to
B/W, and better visibility for red-green
colorblind (N.B.: no effect on contrast of
light/dark gray curvature with data overlay; use
$cvfact to adjust that).

####################
dimredcurvfact
####################

-------------------------------------------
variable: $dimredcurvfact -- dim red for better contrast
-------------------------------------------
default: 1.0

Dims red (sulcus) in curvature display.  This
provides (e.g., at 0.8) better contrast for full
color illustrations, better conversion to B/W,
and better visibility for red-green colorblind.

This has no effect on contrast of light/dark gray
curvature with data overlay; use $cvfact to
adjust that.

####################
fadef
####################

-------------------------------------------
variable: $fadef -- ipsilateral fade out
-------------------------------------------
default: 0.7

The "fad:" entry controls the fraction of the
colorscale that is *not* grayed-out (or
yellowed-out if ipsiyellowfact>0.0).

Changing $fadef has no effect if $angle_cycles is
set to an integer (1, 2, ...)

With $fadef set to 0.99, ipsilateral graying-out
is disabled.  Lower fadef's result in a larger
percentage of phases being grayed-out.  At
fadef=0.0, 2/3 of the color wheel is grayed out.

####################
ipsiyellowfact
####################

-------------------------------------------
variable: $ipsiyellowfact -- ipsi yellowing
-------------------------------------------
default: 0.0

The "iy:" entry (middle right) changes the
ipsilateral fade out from gray to various amounts
of yellow.

Setting $ipsiyellowfact to 0.0 gives pure gray
while setting it to 1.0 gives pure yellow.

The range of phase angles or both gray and yellow
is controlled with $fadef ("fad:" entry).

####################
angle_cycles
####################

-------------------------------------------
entry variable: $angle_cycles -- adjust phase colscale
-------------------------------------------
default: 2.2

The "anglecycles:" entry (lower right) controls
the spacing of colors around phase color wheels.

Integral values of $angle_cycles (1,2,3) result
in one or more red-green-blue/magenta wraps of
across 360 deg of phase.

Non-integral values of $angle_cycles result in a
single green-blue-red cycle.  For example,
$angle_cycles 2.2 results in a slightly more
rapid change between green-blue-red then with
2.01 cycles per 360 degrees.  By contrast,
$angle_cycles 1.4 results in a more spread-out
green-blue-red cycle.

Larger, non-integral $angle_cycles (e.g.,
$angle_cycles 3.1) squeeze the green-blue-red
transition even tighter, which can be useful for
cross-subject average data where the range of
phases is compressed as a result of slight
spatial misalignments of averaged maps.

Phases just beyond either end of the single pass
through green-blue-red are initially clamped to
the end colors (red or green), and then at
greater angular distances eventually fade to gray
at phases opposite to the center color (blue).

The effects of different $angle_cycles are best
seen by clicking "disk" at the upper right to get
a color wheel inset.

-------------------------------------------
Cortex-position-dep adjustments for average data
-------------------------------------------

As visual areas get smaller, which is generally
correlated with being more anterior in the brain,
there is a tendency to 'regress to the horizontal
meridian' because of slight between-subject
offets in the location and orientation of smaller
areas.

More anterior maps are also more likely to
demonstrate eye position-dependent maps (e.g.,
VIP) which can systematically displace the polar
angle of receptive fields.

These effects can be compensated in a tcl script
using the C/tcl function (not currently exposed
in the interface):

  linrampphase2vtxcol <aoff1> <acyc1> <aoff2> <acyc2>

First click twice on a folded, inflated, or
flattened surface.  The first click defines the
beginning of the ramp and the second click, the
end.  A linear ramp in angle_offset and
angle_cycles is applied along the line between
the two clicks, with modification isocontours
perpendicular to that line.  The value of
angle_offset and angle_cycles beyond the ends of
two-click line segment are flat, clamped to the
values specified above.

This sets the vertex color (vtxcol) fields for
the entire brain.  Use middle-click "CLR" on the
"label:" line to clear the vertex colors (which
will reveal the standard color scale colors
underneath.  Or to toggle between the original
and the vtxcol "paint", toggle vtxcolflag
(available in R-click help popup from far left
tickbox on "label:" line).

The result can be saved to .tiff or .rgb like any
other rendering.

To save the vtxcol "paint", use ctrl-right-W on
the "label:" line (tclfunct: write_vtxcol_label).

Currently, this command does not accept phase
wraps in angle_offset, so if you want to make a
ramp between an angle_offset of 0.98 and 0.03,
use 0.98 and 1.03 instead.


####################
revphase
####################

-------------------------------------------
variable: $revphaseflag -- reverse time axis
-------------------------------------------
default: 0 (FALSE)

The "rev" tickbox (lower right) reverses the
phase of complex-valued color scales (it also
reverses the sign of the "BW" color scale).

This happens *before* adjustment by angle_offset.

For Fourier-analyzed data, when $revphaseflag is
1 ("rev" is ticked), the time axis is effectively
reversed, that is, f(t) -> f(-t).

In general, this is not equivalent to multiplying
by -1 ($invphaseflag).

####################
angle_offset
####################

-------------------------------------------
variable: $angle_offset -- rotate phase colscale
-------------------------------------------
default: 0.0
keyboard shortcuts:
  Cmd-o,O  =>  adjust angle_offset 0.01 up/down
  Cmd-y,Y  =>  adjust angle_cycles 0.1 up/down

The "angleoffset" entry (lower right) controls
the rotation of phase color wheels.

This operation happens *after* adjustment by
revphaseflag.

Values from 0.0 to 1.0 rotate the color scale in
a clockwise direction from 0 to 360 degrees.  For
a default polar angle stimulus slowly rotating in
the clockwise direction, slightly increasing the
value above 0.0 will compensate for a longer
hemodynamic delay.

Values larger than 1.0 or smaller than 0.0 are
acceptable (they will wrap).

-------------------------------------------
Cortex-position-dep adjustments for average data
-------------------------------------------

See R-click help for anglecycles.

####################
cuts
####################

-------------------------------------------
 Cuts and Fills HOWTO
-------------------------------------------
Surface cuts followed by region growing fills are
done for two primary reasons: (1) selecting
region to flatten, and (2) defining a label for
marking the surface or extracting overlaid
data.

Linear cuts are made between selected vertices in
the order in which the vertices have been
selected.  To clear any previously selected
vertices, do a right-click anywhere in the
surface display window.

Generating Patches for Flattening

For example, to flatten the entire cortex, here
is a typical sequence of operations:

  -- MGHTools -> Make Occip Surf Cuts (init outname)
  -- relaxation cuts -- LEFT-CLICK sequence, LINE
  -- remove midline -- LEFT-CLICK sequence, AREA
  -- fill region to keep -- one LEFT-CLICK, FILL
  -- save patch file -- WRITE (?h.full.patch.3d)
  -- select 3d patch in csurf ("patch:" combobox)
  -- SubjectTools or MGHTools -> Flatten Surface

To flatten just the occipital lobe:

  -- MGHTools -> Make Full Surface Cuts (init outname)
  -- rotate to medial view
  -- calcarine cut -- LEFT-CLICK sequence, LINE
  -- cut off occip -- 3 clicks to define plane,
            and 4th to pick side to save, PLANE
  -- save patch file -- WRITE (?h.occip.patch.3d)
  -- select 3d patch in csurf ("patch:" combobox)
  -- SubjectTools or MGHTools -> Flatten Surface

To make new cuts guided by previous set, define
label (see next) by FILL'ing previous "viewcuts"
surface, then read label into uncut inflated
(easier to see cuts with curvature off).

Defining Labels ("label:" line)

There are three main ways of selecting a region
that can be used as a label to mark a set of
vertices, or to extract data currently overlaid
on the surface to an ASCII file:

  (1) make LINE (open), AREA (closed) cuts, FILL
  (2) fill to statistical criterion with ROI
  (3) fill vertices nearest a point with N, A, or R

Region-growing operations done by FILL or ROI
respect any label that has been displayed as a
transparent overlay (that is, using the "D"
button).  ROI respects cuts like FILL does.  Note
that labels whose *data* has been read onto the
surface with the "R" button are treated like any
other overlay data, and will be included in a
FILL or ROI operation.

The FILL and ROI operations can generate
disconnected regions if two or more vertices are
first selected.  It you don't want this, use
right-click to clear all vertices before
starting.

The third method of selecting a region is based
on the 3D Euclidean distance from the
last-selected point.  The size of the region can
controlled by entering either a vertex count (N),
an area in sq mm (A), or a radius in mm (R).

On a folded surface, this will select vertices
that lie within a spherical volumes around the
selected point (this may select disconnected
surface patches).  To select a spherical region
around a point in a sulcus, select the point on
the inflated surface, then change to a folded
surface before clicking N, A, or R.

By contrast, using Euclidian distance selection
method on an inflated surface give a close
approximation to geodesic (shortest path)
distances from the selected point on the folded
surface.

Saving and Using Labels ("label:" line)

To save a label generated by any method, use
label "W" button (tcl: write_val_visible_vertices).
All visible vertices are saved as an ASCII file.
To restore invisible vertices after a cut/FILL,
ROI, or nearest vertices N/A/R operation, use
"UNDO" (last) or "INIT" (back to initially
read-in state).  To clear displayed labels, use
the "CLR".

To use a previously defined label to extract data
from a different surface overlay data set, read
in the surface overlay, use shift-middle-click
"R" (read label data and re-cut label, was "RC"
button) to re-cut the previously defined label,
and then "W" (after choosing a new label name) to
write out the new overlay data for that label.

A short-cut to do the above is: display data to
be extracted, "D" a label, type in new output
label name, then shift-middle-click on the the
"W" button (tcl: write_val_annoted_vertices).

See R-click help for "label:" entry, and R-click
help for each label button for details.

####################
cutregion
####################

-------------------------------------------
funct: cut_line <1=closed> -- cut closed contour w/list
-------------------------------------------
keyboard equivalent: none

The "AREA" button (lower middle) performs a
closed-line cut of the surface using the current
ordered list of surface marks.

This can be used to generate an ROI label.

N.B.: First, be sure to clear all current marks
on the surface with a R-click in the surface
display window.

N.B.: if you want to make a large, elaborate AREA
cut, it is better to divide it into a series of
LINE cuts, so you can UNDO if you click a stray
vertex (also good to save snapshot patches as you
go along).

Then, select a series of surface vertices by
left-clicking each in turn.  A middle-click on
any already-selected vertex will remove it from
the ordered list before the cut.  Clicking "AREA"
then disconnects edges intersecting the closed
polygon defined by the identified vertices
(implied last-to-first cut).

Use "UNDO" button to undo previous cut (tcl
funct: restore_ripflags 1).

Use "INIT" button to go back to the initial
read-in state of the surface, which may have
already had some hidden vertices (tcl funct:
restore_ripflags 2).

Use "ALL" button to show all vertices (tcl funct:
clear_ripflags).

If only one vertex is selected, "AREA" removes a
single vertex.

See "PTS" to more generally edit (cut/restore)
lists of single vertices.

####################
erode
####################

#### control policy at edge of FILL ####
-------------------------------------------
toggle variable (left-click):
  $erodingfillflag -- toggle erode vs. standard
-------------------------------------------
toggle variable (middle-click):
  $dilatingfillflag -- toggle dilate vs. standard
-------------------------------------------


The "er" (erode) tickbox (next to "AREA" button)
controls the operation of "FILL".  By default,
this is unticked -- that is, clicking FILL does
standard fill (neither erode nor dilate).

There are 3 possible states of this tickbox via
left and middle clicks:

  1) unticked, label is "er" => standard FILL
  2) ticked, label is "er" => eroding FILL
  3) unticked, label is "dl" => dilating FILL

-------------------------------------------
Left-click (toggle $erodingfillflag)
-------------------------------------------

If $erodingfillflag is 1 ("er" is ticked), FILL
will only save vertices *inside* the border of a
cut (i.e., it will discard border vertices).
Thus, each repeated application of FILL
successively erodes one layer of vertices from a
patch.

This can be used to gradually shrink a patch.

This can also be used to construct completely
non-overlapping adjoining labels:

 (1) left-click "er"
 (2) display existing label (FILL will respect it)
 (3) "U"-shaped cut w/both ends in displayed label
 (4) left-click inside cut
 (5) FILL to create non-overlapping label

If "er" is unclicked (the default at startup), by
contrast, the two adjoining labels created by this
process will share vertices at their boundary
(this may be desired).

N.B.: this flag is *always* set to 1 when the ROI
button is used since the ROI operation strictly
uses vertexwise data.

See help for ROI for exact details on how flood
filling is implemented (esp. distinction between
vertices and faces during FILL).

-------------------------------------------
Middle-click (toggle $dilatingfillflag)
-------------------------------------------

If the "er" is middle-clicked (vs. left-clicked)
then $dilatingfillflag will be set to 1 (the "er"
tick label will change to a bold "dl"), and FILL
will add a rim of single vertices around the
fill.  The tickbox will remain unticked.

Repeated applications of FILL with this flag set
will thus successively dilate a patch, one layer
of vertices at a time.

The dilation operation respects any label that
has been displayed with "D", even though the
label might be on part of the surface that has
already been cut away (use CLR on the "label:"
line to clear all displayed labels if this
behavior is not desired).

N.B.: a middle-click will only change to dilating
FILL if the eroding fill tickbox is first
unticked.  Also, if dilating FILL is set (label
is bold "dl") ticking the unticked tickbox will
cancel dilating FILL it and change to eroding
FILL.

####################
fill
####################

-------------------------------------------
funct (left-click): nearest-neighbor-FILL region
  floodfill_marked_patch <0,1,2,3,4,5>
-------------------------------------------

The "FILL" button (lower right) performs a
region-growing operation on the surface starting
from any current marked seed(s).

"FILL" is used to select a connected subset(s) of
vertices to be written out as a patch or a label.
After this operation finished, any unselected
vertices are made invisible (after the report of
the filled area in sq mm).  Undo this with "UNDO"
or use "INIT" to restore initial read-in state of
surface.

Start by clearing all previously marked vertices
with a right-click in the surface display window.

Then specify one or more closed regions using
open- or closed-line cuts:

  closed line:
    left click sequence
    AREA (tcl/C function: cut_line 1)

  open line:
    left click sequence
    LINE (tcl/C function: cut_line 0)

Then specify seed(s) for fill(s) with one (or
more) left-clicks in region(s) to save (N.B.:
left-clicking two disconnected regions will fill
them both, which you may want to do).

Finally, click FILL.  This flood fills the marked
region(s).  The progress of the flood fill is
shown by white coloring.  When done, the white
coloring is removed and only the filled region(s)
are visible.

For surfaces with a very large number of vertices
(e.g., cerebellum), an ongoing FILL operation can
be killed with cmd-F (i.e., cmd-shift-f)

FILL and ROI will not fill any region containing
a displayed ("D") label or annotation.  Clear
labels or annotations first ("label:" line CLR)
to remove this contraint.  On the other hand,
leaving labels displayed is a way to generate
adjoining labels.

At this point, the result can be saved as a patch
(e.g., for flattening) or as a label (or both).
The patch is a binary file that will contain the
current surface vertex x,y,z positions but no
data.  The label is an ASCII file that will
contain the vertex numbers, any data that was on
the surface at write time, and typically the
vertex x,y,z positions in the original folded
surface (N.B.: not the current surface).

The tcl wrapper function for the FILL button,
which runs floodfill_marked_patch and generates
the sum filled area popup, is:

  fillbutton

The meaning of the number arguments to the
underlying function, floodfill_marked_patch, are:

  floodfill_marked_patch <0-5>:

    0: fill to cuts and labels
    1: fill to stat=sfthresh (and cuts/labels)
    2: fill to val=fthresh (and cuts/labels)
    3: fill to complexamp=fthresh (and cuts/labels)
    4: fill to truncphase limits (and cuts/labels)
    5: fill to stat=sfthresh and complexamp=fthresh

A vertex can be marked from a script using:

  click_vertex <xpix> <ypix>

Find out x and y from "pix=<x>,<y>" in the log
after an interactive click.  The argument units
are window pixels.  For the standard 600x600
window the upper left corner is 0 0 and the lower
right is 599 599, so the near the center of the
default 600x600 window is: click_vertex 300 300.

Label Boundaries

The first time a patch is FILL'd, its outer
boundary vertices will be set to 'border'.  Doing
a second FILL operation on this already-FILL'd
patch will thus remove one layer of vertices.

Therefore, by default, FILL pads the set of
filled vertices with all the vertices of visible
faces on the edge of the label.  This prevents
that layer of 'border' vertices from being
stripped when FILL is repeated on the same patch
(no effect of this padding the first time filling
a cut region since the cut vertices are already
hidden).

Since a non-eroding fill pads vertices from
currently visible faces on the label boundary,
this means that FILL'ing up to a displayed label,
will generate adjoining labels that share the
vertices at their boundary (sometimes desired).

To create completely non-overlapping adjoining
labels, click "er" (for "eroding", next to FILL)
before clicking FILL, which restores the original
eroding behavior of FILL (sets $erodingfillflag
to 1).  Since a layer of vertices is lost, draw
cuts taking this into consideration.

Touch up a cut label (or a cut region before a
FILL) with the PTS button: left-click PTS after
selecting a series of vertices to remove them,
middle-click PTS to add nearest neighbors to a
series of selected vertices.  Use MESH to show
dangling edges.  R-click unlabeled tixbox at
bottom of left "phc" panel to get popup to turn
on $pointsflag to see stray solitary vertices.

An alternate use of an eroding fill is to shrink
a label: with "er" ticked, a second click and
FILL of an already filled region will erode one
layer of vertices.

The ROI button *always* does an eroding fill so
that only vertices above the number in "fthresh:"
will be included in the label.

See help for ROI for exact details on how flood
filling is implemented.

Surface Area Measurments/Report

The "area" of each vertex is the sum of 1/3 of
the area of each of the triangles surrounding
that vertex.

When the FILL, ROI, or N/A/R buttons are clicked,
a popup reports the summed vertexwise area of the
result.  Two sums are reported.  The first, the
"curr surf" area, comes from measuring area on
the currently displayed surface (the .area
field).  The second, the "orig surf" area, comes
from summing areas for the same vertices from the
areafile.  The areafile ($hemi.area) is read into
the .origarea field at startup (it can be updated
interactively by clicking "R" on the "area:"
line).

The two summed area numbers from the most recent
FILL, ROI, or N/A/R operation are saved as in the
tcl variables:

  $filled_origarea
  $filled_currarea

These can be retrieved any time before the next
FILL, ROI. or N/A/R operation by clicking FILL
with no vertex selected.

MGH freesurfer currently uses $hemi.white to
write the original areafiles.  This file can be
interactively overwritten (after a warning) with
current surface areas by clicking "W" on the
"area:" line.

The "curr surf" area of the vertices on the
boundaries of a flat patch would be reduced
relative to patch-internal vertices, since
contributions from the cut-away faces that used
to adjoin those border vertices won't be defined
after flattening and can't be included (this only
applies to flattened, not to inflated surfaces).
Therefore, the "curr surf" area of patch-edge
vertices are estimated by replacing them with the
values in the areafile.  (not required for "orig
surf" patch areas, which use the areafile for all
vertices).

####################
cutplane
####################

-------------------------------------------
function: cut_plane -- cut surface using a plane
-------------------------------------------
keyboard equivalent: none

The "PLANE" button (lower right) cuts through the
surface using a plane and then saves only those
vertices on one side of the plane.

First, clear all marks with a R-click in the
surface display window.

Then select 4 surface vertices.  The first 3
define a plane to use for cutting, and the last
marked vertex indicates which part of the surface
(which side of the plane) should be saved.  If
more than 4 vertices have been selected, last 4
are used.

This automatically turns on $lighttwosidedflag so
the inside surface is visible.  The second
unlabeled entry for "offset", visible on the
larger F3 panel, controls the relative brightness
of the inside surface (relative to front surface)
using the tcl variable $insidesurffact.

For reasons obscure, the change in the lighting
model requires calling do_lighting_model twice to
make the inside surface appear gray (otherwise
it will appear cyan):

  do_lighting_model
  do_lighting_model
  redraw

This is automatically done by the PLANE button.


####################
cutline
####################

-------------------------------------------
funct: cut_line <0=open> -- cut open contour w/list
-------------------------------------------
keyboard equivalent: none

The "LINE" button (lower right), performs a
connected line segment cut of the surface using
the current ordered list of surface marks.

This can be used to make relaxation cuts when
flattening hemispheres or surface fragments, or
can be used to touch up an already cut label.

N.B.: First, be sure to clear any surface marks
with a R-click in the surface display window.

N.B.: if you are making a large, elaborate cut,
do it in stages so you can use (one-step) UNDO,
in case you make a stray click..

Then mark a series of surface vertices by
left-clicking each in turn.  A middle-click on
any already-selected vertex will remove it from
the ordered list before the cut.  Clicking "LINE"
then disconnects edges intersecting the line
segments identified by successive pairs of
vertices.

Use "UNDO" button to undo previous cut (tcl
funct: restore_ripflags 1).

Use "INIT" button to go back to the initial
read-in state of the surface, which may have
already had some hidden vertices (tcl funct:
restore_ripflags 2).

Use "ALL" button to show all vertices (tcl funct:
clear_ripflags).

If only one vertex is selected, "LINE" removes a
single vertex.

See "PTS" to more generally edit (cut/restore)
lists of single vertices.


####################
cutpts
####################

#### cut vertices in list, restore neighbors of list ####
-------------------------------------------
funct (left-click): cut selected list of single vertices
  cut_vertices
-------------------------------------------
funct (middle-click): restore neighbors of selected list
  uncut_connected_vertices
-------------------------------------------
funct (shift-middle-click): setup catch stray points
  set pointsflag 1
  set pointsize 2
  arrownormctrls
-------------------------------------------


Detailed Description of "PTS" Button Actions

-------------------------------------------
funct (left-click):
  cut_vertices -- cut list of single selected vertices
-------------------------------------------

Remove single vertices in currently selected list
(this is also used by LINE and AREA if only one
vertex is selected).

Useful for quickly trimming ragged edges of a
label.

  1) recut label with "C" on "label:" line

  2) select one or more edge vertices to trim

  3) left-click PTS

This can also make hole(s) in the middle of a
label.

After patching using PTS, it's a good idea to
zoom in, and turn on MESH in order to see and
clean up stray remaining single edges (these
won't be visible as surface triangles).

-------------------------------------------
Alt funct (middle-click):
  uncut_connected_vertices -- restore neighbors selected list
-------------------------------------------

Restore any invisible neighbors of each vertex in
the current list.

This can be used to locally extend the edge of a
label as follows:

  1) recut label with "C" on "label:" line

  2) select one or more edge vertices to extend

  3) middle-click PTS

This can also be used to patch a hole in the
middle of a label.

-------------------------------------------
Alt funct (shfit-middle-click):
  set pointsflag 1
  set pointsize 2
  arrownormctrls
-------------------------------------------

After manipulating a label with FILL, PTS, and
functions that cut or add label parts, stray
vertices may remain.  These are invisible with
normal window settings.  This function makes them
visible, and a popup to set back to the default
condition, which is pointsflag=0 and pointsize=1.


####################
roi
####################

-------------------------------------------
function: floodfill_marked_patch <0,1,2,3,4,5>
-------------------------------------------
keyboard equivalent: none

The "ROI" button floodfills a connected surface
region starting from one or more seed vertices
that has stat, complex phase, complex amplitude,
or val above a requested threshold value.  If
multiple starting vertices are selected, this
may result in disconnected patches.

The precendence of operations is:

 (a) if statANDhypot: STAT>$sfthresh && CPLXAMP>$fthresh
 (a) if statANDreal:    STAT>$sfthresh && REALAMP>$fthresh
 (b) if mask on, use:          STAT > $sfthresh 
 (c) if truncphase, use:      COMPLEX PHASE within limits 
 (d) if complex data, use:   COMPLEX AMP > $fthresh 
 (e) if real data, use:         REAL AMP > $fthresh 

Which operation is done thus depends on the state
of the following tickboxes:

  mid-click "mask" -> toggles $statANDhypotflag
  ctrl-mid-click "mask" -> toggles $statANDrealflag
  left-click "mask" -> toggles $maskflag
  left-click "truncph" -> toggle $truncphaseflag
  left-click "cpx" -> toggle $complexvalflag

N.B.: the first matching conditions win and the
other criteria are ignored.  For example, to fill
a region in an overlay containing real data, the
"mask", "truncphase", and "cpx" ticks must all be
unticked.  The operations in more detail are:

N.B.: statANDhypotflag and statANDrealflag are
incompatible (autofixed based on state of
complexvalflag).

Here again are the ROI fill criteria in order of
precedence (first wins):

 (a) compare hypot(.val,.val2) to $fthresh
         AND compare .stat to $sfthresh
 (b) compare .val to $fthresh AND .stat to $sfthresh
 (c) compare .stat to $sfthresh
 (d) compare atan2(.val2,.val)/2Pi to $truncphasemin,max
 (e) compare hypot(.val,.val2) to $fthresh
 (f) compare .val to $fthresh

The "AND" in the first two cases means, only show
areas with .stat over $sfthresh AND real or
complex amplitude over $fthresh.  If "mask" is
ticked with real or complex data, popups will
force explicit choice between: use stat AND
real/hypot thresholds vs. just use stat
threshold.

In truncphase case, the phase angle is modifed by
$revphaseflag, $invphaseflag, and $angle_offset
before truncation is applied (like "truncphase").

In all cases, this fill procedure also respects
(doesn't go past) cuts, as well as any currently
displayed labels ("label:" ine CLR them if
desired).

Disconnected regions can be filled by marking
vertices by left-clicking them in more than one
region before clicking ROI.

For scripts, the function arguments to
floodfill_marked_patch are (N.B.: arg numbers
have different order than precedence above,
sorry):

 0 - fill visible, connected (this is FILL button)
 1 - compare .stat to $sfthresh
 2 - compare .val to $fthresh
 3 - compare complexamp to $fthresh: hypot(val,val2)
 4 - compare complexpha to $truncphasemin,$truncphasemax
 5 - compare .stat to $sfthresh AND complexamp to $fthresh
 6 - compare .stat to $sfthresh AND real to $fthresh

In contrast to the FILL button, the ROI button
forces an eroding fill (regardless of the setting
of "erode").  This is so that the initially
selected patch will only contain vertices equal
or above "fthresh" (or sfthresh, or within
complex-valued criteria, or stat AND complexamp).

Note that this means that re-doing ROI on an
already-cut-out ROI to the same "fthresh" will
successively erode it (because boundary [=cut]
vertices will be treated the same as vertices
below "fthresh").

See below for the gory details of why this is
this way.

=============================================
Arcane details of flood filling
=============================================

The surface specification consists of a list of
vertices who know their neighbors, and a list of
faces who know their vertices.  During flood
filling, all vertices are first "ripped" (made
invisible), then starting from the seed(s)
vertices, *neighboring vertices* are added to the
growing patch if (as described above):

 (1) not already added
 (2) not set to "border"
 (3) not currently displaying any label
 (3a) .stat>sfthresh AND cplxamp(val,val2)>fthresh (optional)
 (3b) .stat>sfthresh AND val>fthresh (optional)
 (3c) .stat field equal/above sfthresh (optional)
 (3d) cplxphase (val,val2) in trunphase limits (optional)
 (3e) cplxamp (val,val2) eq/above fthresh (optional)
 (3f) .val field equal/above fthresh (optional)

Two things are done when adding the vertex to the
patch:

 (1) vertex is unripped (made visible)
 (2) vertex is labeled "marked" (white)

When done (no more nearest-neighbor filling
possible after up and down passes of the vertex
list), the non-filled *faces* (as opposed to
vertices) are 'ripped' (made invisible).  This is
done by:

 (1) removing faces with 1+ non-filled vertices
 (2) setting vertices of all ripped faces to 'border'

Thus, invisible vertices are 'ripped' plus
'border', border vertices are 'not ripped' plus
'border', and internal vertices are 'not ripped'
plus 'not border'.

The last step also results in a filled vertex on
the border being not being filled the next time
around because it has now become a border.

To prevent this erosion (e.g., during repeated
FILL's up to a cut), the edge is padded by:

  if any vertex of a face is "marked",
  unrip (make visible) all of its vertices

Then, when faces are ripped, the edge won't be
eroded (if even one vertex of a face is filled,
the face gets drawn).

However, for a floodfill of *vertices* above a
thresh, we typically *don't* want to do this,
since this would add another layer of vertices
that were just below the threshold.  So, the ROI
button always forces an eroding fill.

####################
fill2num
####################

#### make ROI, or just set $fillneartype ####
-------------------------------------------
funct (left-click):
  fill_nearest_vertices 0 <n>
-------------------------------------------
set (middle-click):
  set fillneartype 0
-------------------------------------------

Fill Closest N Vertices

The "N" button (lower right) selects n vertices
that are the closest in Euclidean distance to the
most recently selected vertex on the currently
displayed surface.

On an inflated surface, this approximates
geodesic distances along the folded surface.

On a folded surface, it will select cortical
surface vertices that intersect a spherical
volume centered at the selected vertex.  In this
case, the selected vertices may not form a single
connected patch on the cortical surface.

The radius of the most distant vertex is reported
in log.  For a standard surface, each vertex
accounts for approximately 1 sq mm.

To undo this, use UNDO, INIT, or ALL.

Use a middle click on "N" to just set the value
of $fillneartype (e.g., for write_searchlights)
to 0 (number of vertices).

Use 'Representative Vertices'

Open the Searchlight Correlation popup ("X"
button on label line) or the Searchlight
Operation popup (middle-click SMOOTH) to access
two options that affect the operation of the "N"
button:

  searchlightuniqflag (req's load/samp/uniq 3D BRIK)
  numafteruniqflag

See "Use Representative Vertices" in the R-click
help for the "X" button on the "label:" line for
more details.

####################
fillcrit
####################

-------------------------------------------
tcl var: $criterion passed to fill_nearest_vertices
-------------------------------------------
keyboard equivalent: none

The unlabeled entry between the "N" and "A"
buttons (lower right) specifies the number to be
passed to the fill_nearest_vertices function as
the criterion argument:

  fill_nearest_vertices <type> <criterion>

Its meaning depends on which type is selected:

  N (fillneartype=0: number) -- fill to vertex count (n)
  A (fillneartype=1: area) -- fill to orig area (mm^2)
  R (fillneartype=2: radius) -- fill to radius (mm)

The default value (250) makes sense for either
number or area, since each vertex accounts for
approximately 1 mm^2.

N.B.: the radius of an equivalently-sized region
is approximately 10 mm.

####################
fill2area
####################

#### make ROI, or just set $fillneartype ####
-------------------------------------------
funct (left-click):
  fill_nearest_vertices 1 <sqmm>
-------------------------------------------
set (middle-click):
  set fillneartype 1
-------------------------------------------

Fill Closest Vertices up to Area (sq mm)

The "A" button (lower right) selects vertices
nearest in Euclidean distance to the most
recently selected vertex on the currently
displayed surface until the requested total area
is reached.

On an inflated surface, this approximates
geodesic distances along the folded surface.

On a folded surface, it will select cortical
surface vertices that intersect a spherical
volume centered at the selected vertex.  In this
case, the selected vertices may not form a single
connected patch.

The radius of the most distant vertex is reported
in log.

To undo this, use UNDO, INIT, or ALL.

Use a middle click to just set $fillneartype
(e.g., for write_searchlights).

Use a middle click on "A" to just set the value 
of $fillneartype (e.g., for write_searchlights) 
to 1 (area in mm^2).


####################
fill2rad
####################

#### make ROI, or just set fill type ####
-------------------------------------------
funct (left-click):
  fill_nearest_vertices 2 <mm>
-------------------------------------------
set (middle-click):
  set fillneartype 2
-------------------------------------------

Fill Closest Vertices up to Radius (mm)

The "R" button (lower right) selects vertices
nearest in Euclidean distance to the most
recently selected vertex on the currently
displayed surface until the requested radius (in
mm) is reached.

On an inflated surface, this approximates
geodesic distances along the folded surface.

On a folded surface, it will select cortical
surface vertices that intersect a spherical
volume centered at the selected vertex.  In this
case, the selected vertices may not form a single
connected patch.

The total original area is reported in log.

To undo this, use UNDO, INIT, or ALL.

Use a middle click on "N" to just set the value 
of $fillneartype (e.g., for write_searchlights) 
to 2 (radius in mm).


####################
undo
####################

-------------------------------------------
function: restore_ripflags <1> -- undo cut
-------------------------------------------
keyboard equivalent: cmd/alt-z (w/focus on tools window!)

The "UNDO" button (lower right) swaps old and
current cuts (ripflags).  This toggles back and
forth between last two states of surface cuts.

Thus, this is a one-step-only undo/redo.

"UNDO" also unmarks all vertices.

To just unmark all vertices, do a R-click in the
surface display window.

See "INIT" and "ALL" for restoring initial cuts
or undoing all cuts.

N.B.: when mouse focus is on OpenGL window with
brain surface, the undo shortcut, cmd/alt-z,
instead restores a previously (e.g.,
accidentally) cleared set of vertex selections.


####################
init
####################

-------------------------------------------
function: restore_ripflags <2> -- init
-------------------------------------------
keyboard equivalent: none

The "INIT" button (lower right) saves current
cuts (ripflags, recoverable with UNDO), and then
restores cuts to original state read in from 3D
surface or flat patch.

This leaves any displayed vertex data intact.

All vertices are unmarked.

See "ALL" to undo all cuts, even initially
read-in.

####################
nocut
####################

-------------------------------------------
function: clear_ripflags -- undo all cuts
-------------------------------------------
keyboard equivalent: none

The "ALL" button (lower right) first clears all
cuts (ripflags) including those that might have
been read in at tksurfer startup.

It also clears any patch (surface subset) that
was read in ($flag2d is set to 0).

Finally, it re-reads the surface and curvature,
and restores lateral pose.

"ALL" leaves current vertex data (if any) intact.

Command to do this in tcl script:

  clear_ripflags
  read_binary_surface
  read_binary_curv
  set flag2d 0
  restore
  redrawbutton

####################
smooth
####################

#### various smooth types, searchlight operations ####
-------------------------------------------
left-click SMOOTH button w/diff interface settings
      *or use*
explicit-name buttonbar buttons (same, uses steps setting)
-------------------------------------------
  "Surface Smooth (cv) - .curv (curv/sulc/area)"
    smooth_curv <steps>
  -------------------------
  "Surface Smooth (val) - .val(.val2), and .stat if there"
  [real]
    smooth_val <steps>
    smooth_stat <steps>
  [complex]
    swap_val_val2
    smooth_val <steps>
    swap_val_val2
    smooth_val <steps>
    smooth_stat <steps>
  -------------------------
  "Surface Smooth (s) - .stat field only"
    smooth_stat <steps>
  -------------------------
  "Surface Smooth  (w) - .val(.val2), distance-weighted"
  [real]
    smooth_val_weighted <steps>
    smooth_stat <steps>
  [complex]
    swap_val_val2
    smooth_val_weighted <steps>
    swap_val_val2
    smooth_val_weighted <steps>
    smooth_stat <steps>
  -------------------------
  "Surface Smooth (sp) - .val(.val2), sparse, fixed-val interp"
  [real]
    smooth_val_sparse <steps>
    smooth_stat <steps>
  [complex]
    swap_val_val2
    smooth_val_sparse <steps>
    swap_val_val2
    smooth_val_sparse <steps>
    smooth_stat <steps>
  -------------------------
  "Surface Smooth (cr) - .val(.val2), cmplex ang w/realamp"
    smooth_complexang_realamp <steps>
  -------------------------
  "Surface Smooth (gr) - .valbak(.val2bak) gradient arrows"
    swap_valval2_valbakval2bak
    swap_val_val2
    smooth_val <steps>
    swap_val_val2
    smooth_val <steps>
    swap_valval2_valbakval2bak
  -------------------------
  "Fill Annot/Label Holes, 1-Neigh (steps = annotholes)"
    fill_annot_holes
  -------------------------
  "Fill .val Field Holes, 1-Neigh Avg (steps = valholes)"
    fill_val_holes
  -------------------------
  "Fill Annot/Label Holes, AdjNeigh (=annotholes-neigh)"
    fill_annot_holes_neigh <neighord> <annotedfrac>
  -------------------------
  "Erode Edges of Annot/Label (steps = annoterode)"
    erode_annot
-------------------------------------------
"Searchlight Ops Control Popup (mid-click-SMOOTH)"
  searchlightop_val2stat <filltype> <criterion> <op>
-------------------------------------------
"No-overlap .stat Paintballs Popup (shift-mid-clk-SMOOTH)"
  neighop_val2stat <neighord> <criterion=3>
-------------------------------------------


Detailed Description of "SMOOTH" Button Actions

-------------------------------------------
funct (left-click):
  [various, depending on interface settings]
-------------------------------------------

The SMOOTH button runs requested number of steps
of surface-based smoothing (number of steps in
entry).

Select smoothing type using radio buttons at
right (radio button labels in quotes in left
column of table below).  If the data is complex,
both components are smoothed.

  "cv"  (curvature)     -- vertex[i].curv
  "val" (nearest nei)   -- vertex[i].val,{vertex[i].val2}
                                   and vertex[i].stat, if there
  "w"   (dist weight)    -- vertex[i].val,{vertex[i].val2}
  "sp"  (sparse)         -- vertex[i].val,{vertex[i].val2}

See the right click help of each radio button for
more details on each operation.  There are
additional SMOOTH radio buttons on the large F3
tksurfer interface:

  "vo" (valonly)        -- vertex[i].val,{vertex[i].val2}, not .stat
  "cr"  (complex/real) -- vertex[i].val,{vertex[i].val2}
  "s"  (stat)               -- vertex[i].stat only
  "gr"  (gradient)       -- vertex[i].valbak,{vertex[i].val2bak}

The convenient SMOOTH button tcl wrapper proc,
"smooth", can also be called from a user tcl
script.  It can call all the different types of
smooth functions and is a one-liner for smoothing
complex data:

  smooth <steps> <type>

where <steps> is one of:

  1) number of steps (e.g., "5")
  2) "valholes" (or "valueholes")
  3) "annotholes" (or "labelholes")
  4) "annoterode"

and <type> is one of:

  1) curv       (or sulc/area)
  2) val         (auto-detect real/complex, also stat if there)
  3) stat         (smooth just stat)
  4) weight    (auto-detect real/cmplx, dist- & num-weighted)
  5) sparse    (detect real/cmplx, only interp nodata vtxs)
  6) valonly   (auto-detect real/cmplx, don't smooth stat)
  7) cpxreal   (smooth complex angle and real amplitude)
  8) grad       (valbak/val2bak arrows gradient calc)

Omit <type> arg to tcl "smooth" function if
"<steps>" is set to "valholes", etc.

A R-click (help) on the SMOOTH button brings up a
button bar with a button for each of these 12
different types of smoothing.  There are two
additional bottom buttons on the button bar for
'searchlight' and 'paintball' operations (see
below).


Real vs. Complex-Valued Smoothing

The SMOOTH button does the following with
complex-valued data and the default smoothing
function for it, smooth_val (assumes real in
already in .val and imaginary already in .val2):

  swap_val_val2
  smooth_val <steps>
  swap_val_val2
  smooth_val <steps>

Note that complex-valued smoothing (averaging 2D
vectors) will generally reduce the amplitude of
the resulting vector more than real-valued
smoothing of the amplitude by itself.  This is
because complex valued smoothing (vector
averaging) is affected by local phase
differences, which are often substantial with
retinotopic mapping data.

Thus, smoothing complex-valued mapping data and
thresholding it at a given amplitude will reveal
somewhat *less* activation than smoothing the
amplitude -- e.g., sqrt(F) -- as a real value,
and then using it to mask the smoothed but
unthresholded complex-valued data at the same
amplitude.

There is an alternate smoothing method for
complex-valued data on the larger F3 panel (or
via middle-click on the "val" button on the
standard F2 panel):

  "cr"  (complex/real)		-- vertex[i].val,vertex[i].val2

This uses the funct, smooth_complexang_realamp,
which averages the complex angle, but then
replaces the resulting amplitude with a
real-valued average of the complex amplitudes,
thus ignoring local phase differences.  On the
csurf View Functional Data panel, there is an
unmarked tickbox (default unticked) immediately
to the left of the smoothsteps entry that toggles
using this function (for complex data) instead of
smooth_val.

To use this function in a tcl script, simply load
real to .val, imaginary to .val2, and call the
function.

The SMOOTH button can also be used to smooth
arrows generated by calculating gradients (of
curv, val, or phase).  First change to the large
F3 panel, and then use the extra "gr" radio
button next to the SMOOTH button (near bottom of
long vertical panel):

  "gr"  (gradient)          -- vertex[i].valbak,vertex[i].val2bak


Alternate hole-filling and eroding operations

The SMOOTH button can instead run four different
hole-filling and eroding functions if the
following text is typed into the entry next to
SMOOTH (instead of a number):

  annotholes -> fill holes in D'd label/annot
  valholes   -> fill holes in R'd label *data*
  annotholes-neigh -> fill holes w/adj neighbors & criterion
  annoterode -> erode 1 vtx from D'd label/annot

The first three operations do *not* smooth or
change the .annotation or .val field of vertices
that were part of the original label.  In that
respect, they behave like SMOOTH with "sp"
(sparse).

The fourth operation erodes the current
annotation (that is, sets it to zero) of any
vertex that has a neighbor with a different
annotation value.  Note that this does not do a
FILL operation, so repeated applications may not
leave a connected label.

In tcl scripts, the following C/tcl functions can
be used:

  smooth_curv <steps>
  smooth_val <steps>
  smooth_stat <steps>
  smooth_val_sparse <steps>
  smooth_val_weighted <steps>
  smooth_complexang_realamp <steps>
  fill_annot_holes
  fill_val_holes
  fill_annot_holes_neigh
  erode_annot

See R-click help for the smooth steps entry for
more details.


Lock a subset of vertices to locally prevent smoothing

The "locklabel" tickbox (F3 panel, lower middle)
toggles whether smoothing is disabled at vertices
under a label (displayed using "D").

If the tickbox variable, $locklabelflag, is TRUE
(=1), any vertex data (curv, val, val2) at locked
vertices will not be touched by the following
functions:

  smooth_curv
  smooth_val
  smooth_complexang_realamp


-------------------------------------------
"Searchlight Ops Control Popup (mid-click-SMOOTH)"
  searchlightop_val2stat <filltype> <criterion> <op>
-------------------------------------------

When the SMOOTH button is middle-clicked, a popup
appears with two adjustable parameters to control
the searchlight ROI size, and a third parameter to
select one of three operations to compute using
the C/tcl function:

  searchlightop_val2stat <filltype:0-2> <criterion> <op:0-4>

The searchlight size is controlled by:

  fillneartype:
    0: nearest n neighbors
    1: nearest up to area
    2: nearest up to radius

  criterion:
    if fillneartype=0: number of vertices
    if fillneartype=1: area in mm^2
    if fillneartype=2: radius in mm

There are five currently available searchlight
operations:

    op=0: average .val in each ROI => .stat
    op=1: count int IDs in each ROI => ,stat
    op=2: get variance after subtr currID from neighID's
    op=3: [not available: use neighop_val2stat]
    op=4: sum .val in each ROI => .stat

There are two additional options for controlling
whether 'representative vertices' are used in
each spotlight:

  searchlightuniqflag (req's load/samp/uniq 3D BRIK)
  numafteruniqflag

See "Use Representative Vertices" in the R-click
help for the "X" button on the "label:" line for
more details on how to use these two bottom
ticks.

N.B.: op=3 (non-overlapping patches to int ids in
.stat) is currently only available when using
the alternate function, neighop_val2stat (as
opposed to searchlightop_val2stat) in a tcl
script.  The neighop_val2stat function constructs
ROIs around each vertex by neighbor order (1-6).

Input Data

The input is the full-brain vertexwise data
currently loaded into the .val field.  The .val
field can be loaded using "R" on either the
"val:" or "label:" lines.

Output

The result, computed for searchlight ROIs across
the entire hemisphere, is put into the (invisible)
.stat field of each vertex.  To make the result
visible, use "S/V" to swap the .stat and .val
fields, and adjust the $colscale, $fslope, and
$fmid.

Searchlight operations

The first operation (optype=0) is a boxcar
average (N.B.: useful for very large kernels but
much slower than nearest neighbor smoothing for
small kernels).

The second and third operations are currently
designed for positive, ordered, integer cluster
IDs (negative vertex data is ignored).

The second operation (optype=1) counts the number
of different cluster IDs in each searchlight.

The third operation (optype=2) calculates the
variance of cluster IDs after first subtracting
off the cluster ID of the searchlight center.

The fourth operation (optype=3) paint
non-overlapping IDs (used for cerebellar patches
simulation).  N.B.: this currently only works
with the parallel function, neighop_val2stat, not
searchlightop_val2stat.

The fifth operation (optype=4) simply sums
.val for each searchlight ROI.

This function is multi-threaded (8 threads) and
takes about 9 min to finish on a standard
cortical hemiphere surface on a 4-core i7 (the
processor fans will increase their speed).

Example script

An example tcl script for loading data, running
the function, displaying and saving the results,
and subtracting the results from two different
data sets (using the C/tcl function,
subtr_valbak_from_val), is here:

  $CSURF_DIR/lib/tcl/zz-examples/searchlightdiff.tcl

That script expects two full-brain labels
containing positive integer cluster IDs ordered
by similarity, and displays differences in
cluster counts or cluster variance between
two different clusterings.


-------------------------------------------
"NonOverlap .stat Paintballs Popup (shift-mid-clk SMOOTH)"
  neighop_val2stat <neighorder:1-5> <operation=3>
-------------------------------------------

[not exactly smoothing but a local operation!]

A shift-middle click on the SMOOTH button brings
up a popup to provide interface support to run
the C/tcl function, neighop_val2stat (with
operation=3), for generating generating
'paintball' label/annots.  This function
generates a set of non-overlapping
label/annotation regions, whose size is specified
by vertex neighbor order (1=justneighbors,
2=neighbors-of-neighbors, etc).

The special operation=3 here is the only one that
ignores the .val field while writing to the .stat
field (the other operations for neighop_val2stat
are parallel to the operations in
searchlightop_val2stat).

Here are the neighbor counts for the fsaverage
surfaces:

    1-neighbors: 7
    2-neighbors: 19
    3-neighbors: 37
    4-neighbors: 61
    5-neighbors: 91
    6-neighbors: 127

When neighop_val2stat is run with operation=3, it
generates the non-overlapping regions as
sequentially-numbered, integer values in the
.stat field.

There will be small unlabeled regions in between
each non-overlapping, approximately circular
patch.  To fill these in, click the GROW STAT
IDNUMS button (C/tcl function grow_stat_idnums).
This selects a shuffled vertex and then, if it is
empty, adds it to an existing region if any of
its neighbors already have an idnum in the .stat
field.

The .stat idnum regions can then be turned into
an MGH annotation in order to use these regions
for further analysis.  This was originally
written to display the size of hypothetical
granule cell patches in the cerebellar cortex :-}
The regions are given random (non-overlapping)
colors in the output MGH annot file.

To see or use the result:

(1) save the .stat regions to a randcol annot file:
     --R-click "label:" line "W" to get popup
     --choose output file name in "label:" entry
     --"Write StatIds to RandCol MGH Annot" button

(2) display/use resulting annot file:
     --use "label:" line "D" button


####################
smooth_steps
####################

-------------------------------------------
variable: $smoothsteps -- surface-smooth steps
-------------------------------------------
default: 5

The entry immediately right of the "SMOOTH"
button specified smooth steps.  It also accepts
the following 7 words (see below):

  "annotholes" (or "labelholes")
  "valholes" (or "valueholes")
  "annotholes-neigh" (or "labelholes-niegh")
  "annoterode"

An empirically derived correspondence between the
number of smoothing steps with the standard
nearest-neighbor functions (smooth_curv,
smooth_val, smooth_stat) and the average
full-width-at-half-max filter result starting
with a single non-zero vertex on a standard
resolution surface is:

  steps   FWHM (mm)
 --------------------
    5      2.22
   10      3.20
   20      4.49
   30      5.36
   50      6.99
   70      8.31
  100     10.15
  230     ~1.5 cm
  400     ~2 cm
  900     ~3 cm
 --------------------

A power function fit to this empirical map
(r^2 = 0.9987) is:

  fwhm = 0.9921 * steps^0.5018

Three alternate smoothing functions behave
differently:

  smooth_val_sparse <steps>
  smooth_val_weighted <steps>
  smooth_complexang_realamp <steps>

Sparse smoothing only interpolates non defined
vertices at the 'speed of light' (one additional
ring of vertices for each step).  Gaussian
weighted smoothing is still a nearest neighbor
operation, but has adjustable strength.
Smoothing using complex angle and real amplitude
smooths less than standard smoothing because
phase angle differences are ignored for the
purposes of determining amplitude.

Alternate hole-filling and eroding operations

If "annotholes"/"labelholes" or
"annotholes-neigh"/"labelholes-neigh" or
"valholes"/valueholes" or "annoterode" is entered
as the 'number' of smoothing steps (no quotes),
the SMOOTH button will instead run the following
tcl/C functions:

  1) annotholes -> fill_annot_holes
     [or labelholes -> synonym for above]

  2) valholes -> fill_val_holes
     [or valueholes -> synonym for above]

  3) annotholes-neigh -> fill_annot_holes_neigh
     [or labelholes-neigh -> syn for above]

  4) annoterode -> annot_erode

This R-click help also brings up a buttonbar to
conveniently access all of these options.

(1) smooth steps = "annotholes"

The first option calls the C/tcl function
fill_annot_holes, which fills holes in a label
previously read in as a binary annotation or a
single label using the "D" button (label vs.
non-labeled).  The annotation/color used to fill
is the annotation of the last non-zero neighbor.

(2) smooth steps = "valholes"

The second option calls the C/tcl function
fill_val_holes, fills in holes in label values
read into the .val field with the "R" button
(floating point values).  Filled values are the
average of non-zero neighbor val's.

In both cases a fill-able hole is defined as a
vertex in which all but 2 of its neighbors are
annotated (annotholes/labelholes) or non-zero
(valholes/valueholes).

This conservative definition of a hole will only
fill an outright single-vertex hole, or the end
of a linear defect.  Therefore, it may have to be
run several times to reach asymptote.  It will
not expand the convex edges of a label (like
SMOOTH with "sp" -> sparse will), but it will
fill in one-vertex-thick cracks in otherwise
linear edges.

(3) smooth steps = "annotholes-neigh"

The third option calls a more general and
controllable annotation/label C/tcl hole-filler
function, fill_annot_holes_neigh, which has an
adjustable neighborhood ($neighord: 1-5 rings of
nearest neighbors), and an adjustable criterion
($annotfrac: fill if some % of total neighbors
filled).  This is run and controlled from a popup
brought up when "annotholes-neigh" is entered for
'smooth steps' followed by a <Ret> or clicking
"SMOOTH".

Larger neighborhoods (3-5) are successively
slower with a large surface (e.g., 5M vertex
cerebellum), but can be sped up by cutting away
irrelevant parts of the surface, for example, by
using the "PLANE" button.

A final touch-up method to remove pesky remaining
holes is to FILL the region around the label,
save that everything-but-label as a new label,
then read it in to the full surface and FILL up
to the everything-but-label label.

(4) smooth steps = "annoterode"

Finally, the fourth/last option calls the C/tcl
function, erode_annot, which erodes a single
layer of vertices from each color in an
annotation (e.g., the HCP parcellation displayed
with "D") by setting the annotation of a vertex
to zero if any of its neighbors have a different
annotation value.  This will also work on a
single "D"-displayed label.  Note that this does
not do a FILL, so repeated applications of
annot_erode may result in disconnected patches
for a single color (probably what you want - see
next).

One use for eroded regions is to generate a label
that selects vertices that are more likely to
actually be in the region (away from the
boundaries with other regions).

Save a hole-filled annotation (when .val's don't matter)

Sometime, you just want to patch holes in a label
without concern for values - for example, to use
the label to make a multi-area annotation, or to
clean up holes in a 'foreign' label that was read
in from a previous surface edit using
read_label_to_nearest_annot_using_col.

In this case, to save the patched label:

 (1) re-cut label (ctrl-L-clk "C" on "label:" line)
 (2) maybe change "label:" entry (to avoid overwrite!)
 (3) save label with "W" on "label:" line"

Saving hole-filled values in a label

Once a read-in label has had its value holes
filled (or has been eroded), there are several
ways to save the new label.  Note that the "W"
button on the "label:" line (default left-click:
function: write_val_visible_vertices) saves all
visible vertices (and their currently displayed
values).  You probably don't want the entire
brain, so first re-cut the label by selecting a
vertex inside it and using the ROI button with
fthresh set to a value below any in the displayed
label's values (e.g., 0.001).  Also, type in a
new name on the "label:" line entry unless you
want to overwrite the original label.

For example, to patch value holes in a
single-subject MGH BA label (values are
probabiities):

 (1) set colscale to "BR" (real values)
 (2) read BA label (probabilities) to surf with "R"
 (3) enter "valholes" in smoothsteps entry
 (4) click SMOOTH several times until holes filled
 (5) click vertex inside label, click ROI to re-cut
 (6) type new filename for label
 (7) left-click "W"

Save data under label(s) in one step

It is possible to save the vertices and values of
a displayed label (transparent display from using
the "D" button; N.B.: the values being saved may
not be visible if "overlay" is unclicked),
without re-cutting the label by using an
alternate shift-middle-click "W" (function:
write_val_annoted_vertices <r> <g> <b>).

If a multi-area annotation is loaded, the
currently displayed value data for each
annotation region can be saved out as a separate
label file all at once with an alternate
shift-ctrl-left-click "W" (function:
write_val_annotedcols_vertices).

See the help for the "label:" "W" button for more
details.

####################
smooth_curv
####################

-------------------------------------------
function: smooth_curv $steps
-------------------------------------------
keyboard equivalent: none

The "cv" radio button (lower right) causes the
"SMOOTH" button to operate on curvature.

The data in the curvature vertex field
(vertex[i].curv) is surface-smoothed by
nearest neighbor smoothing.

####################
smooth_val
####################

-------------------------------------------
function: smooth_val $steps
-------------------------------------------
keyboard equivalent: none

The "val" radio button (lower right) causes the
"SMOOTH" button to operate on overlaid data
values (.val and possibly .stat).

Left-click

If real-valued data, a nearest neighbor smoothing
is performed on the .val field (vertex[i].val).

If complex-valued data ($complexvalflag is 1),
nearest neighbor smoothing is performed on both
.val and .val2 fields (vertex[i].val and
vertex[i].val2).

If stat mask field is loaded (and "mask"
checked), the stat field (vertex[i].stat)
is also smoothed.

Here are tcl script commands for 10 steps (~3 mm
FWHM) of surface-smoothing of already-read-in
complex data and stat mask:

  swap_val_val2
  smooth_val 10
  swap_val_val2
  smooth_val 10
  swap_stat_val
  smooth_val 10
  swap_stat_val

Here is the equivalent operation for real-valued
data:

  smooth_val 10
  swap_stat_val
  smooth_val 10
  swap_stat_val

Both of the above can also be done more simply
using the tcl wrapper function, smooth, as
follows:

  smooth <steps> <type>
  smooth 10 val


Middle-click (alternate)

A middle-click on the "val" button is a shortcut
to the "cr" smoothing function available on the
larger F3 panel:

  smooth_complexang_realamp 10

This does nearest neighbor complex-valued
smoothing to generate angles, but then inserts
real-valued smoothing of complex amplitude for
amplitudes.  There is less reduction in amplitude
for a given number of smoothing steps because
local phase angle differences are ignored, and do
not reduce amplitude.

####################
smooth_stat
####################

-------------------------------------------
function: smooth_stat $steps
-------------------------------------------
keyboard equivalent: none

The "s" radio button (lower right on larger F3
panel) causes the "SMOOTH" button to operate on
the stat field.

The data in the curvature vertex field
(vertex[i].stat) is surface-smoothed by
nearest neighbor smoothing.

####################
smooth_cpxreal
####################

-------------------------------------------
function: smooth_complexang_realamp $steps
-------------------------------------------
keyboard equivalent: none

The "cr" radio button (lower right on the larger
F3 panel) causes the "SMOOTH" button to operate
on overlaid complex-valued date.

The real and imaginary components are smoothed as
with "val" smoothing, but then the amplitude is
replaced with a real-valued smoothing of the
complex amplitude.

This results in less reduction in amplitude for a
given number of smoothing steps because local
differences in phase angle are ignored, and
therefore do not reduce amplitude.

It is appropriate for complex-valued data where
the complex amplitude has been replaced by a
statistic, such as the _r,_i datasets -- where
the complex amplitude is sqrt(F).

This smoothing option is not visible in the
standard F2 panel but is accessible there with a
middle-click on the "val" button.

####################
smooth_valonly
####################

-------------------------------------------
function: smooth_val $steps
-------------------------------------------
keyboard equivalent: none

The "vo" (val-only) radio button (lower right on
the larger F3 panel) causes the "SMOOTH" button
to smooth real (or complex) data without
smoothing the stat mask field.

If real-valued data, surface-smooth the val field
(vertex[i].val).

If complex-valued data (complexvalflag=1),
surface-smooth both val and val2 fields
(vertex[i].val and vertex[i].val2).

The stat mask field will *not* be smoothed, even
if it is loaded (use the "val" radio button to
also smooth the stat field if loaded).

Here are tcl script commands for 10 steps (~3 mm
FWHM) of surface-smoothing of already-read-in
complex data (what SMOOTH button does with
complex data):

  swap_val_val2
  smooth_val 10
  swap_val_val2
  smooth_val 10

Here is the equivalent command executed for
real-valued data:

  smooth_val 10

####################
smooth_weight
####################

-------------------------------------------
function: smooth_val_weighted <steps>
-------------------------------------------
keyboard equivalent: none

The "w" radio button (lower right) causes the
"SMOOTH" button to perform a distance- and
number-weighted smoothing (as opposed to nearest
neighbor smoothing) on overlaid data

By selecting "w", smooth_val_weighted is used to
smooth current vertex data (if real data,
vertex[i].val, else if complexvalflag=1,
vertex[i].val and vertex[i].val2).

This function produces similar results to
smooth_val ("val") but can be adjusted to smooth
less agressively using $halfweightdist
(default=0.4).  This is useful for high
resolution data that approaches the resolution of
the surface mesh.

To control, R-click the "w" radio button to get a
popup.

This iterative nearest-neighbor smoothing is like
smooth_val except that it is distance- and
density-weighted.  The distance-weighting uses
neighboring vertex distances from the $origcoords
surface (usu. ?h.orig) and is controlled by the
tcl var $halfweightdist (default=0.4), which
indicates the distance in mm where the Gaussian
weight drops to 0.5 (before density weighting).

This is still an operation that only involves
neighboring vertices.

The density-weighting controls varying number of
neighboring vertices (~6 for a triangular
surface).

Here is schematic C-code:

  fwhm = 2.0*halfweightdist;
  sigma = fwhm/(2.0*sqrt(2.0*log(2.0)));
  foreach vertex {
    foreach neighbor {
      weight = exp(-(d*d)/(2.0*(sigma*sigma)));
      weight *= avgneigbors/currneighbors;
      sumweight += weight;
      sumvertexdata += weight*vertexdata;
    }
    newvertexdata = sumvertexdata/sumweight;
  }

As $halfweightdist is increased, the behavior of
smooth_val_weighted approaches the behavior of
smooth_val (R-click smooth steps entry for
empirical estimates of nearest-neighbor kernel
size -- e.g., 10 steps ~3.2mm FWMM).

The first time this function is used, it may have
to read in the $origcoords surface to find
original intervertex distances.

Here are tcl script commands for 10 steps (~3 mm
FWHM) of surface-smoothing of already-read-in
complex data (what SMOOTH button does with
complex data):

  swap_val_val2
  smooth_val_weighted 10
  swap_val_val2
  smooth_val_weighted 10

Here are tcl script commands for 1 step
of Gaussian smoothing with a FWHM of 1 mm:

  set halfweightdist 0.5
  swap_val_val2
  smooth_val_weighted 1
  swap_val_val2
  smooth_val_weighted 1

####################
smooth_sparse
####################

-------------------------------------------
function: smooth_val_sparse $steps
-------------------------------------------
keyboard equivalent: none

The "sp" radio button (lower left) causes the
"SMOOTH" button to perform a fixed-value
interpolation (sparse smoothing).

This operates on real or complex data
(vertex[i].val and maybe vertex[i].val2).

In contrast to "val" (nearset neighbor) or "w"
(weighted) smoothing, vertices with data are not
changed, but vertices that are initially
undefined are interpolated (at the 'speed of
light' -- one vertex per smoothstep) to fill in
between defined vertices.

N.B.: this will have no effect on full rank data
where all vertices have defined values.

####################
smooth_grad
####################

-------------------------------------------
functions: smooth_val $steps
              swap_valval2_valbakval2bak
              swap_val_val2
-------------------------------------------


Smooths gradient vectors currently residing in
the valbak/val2bak fields (vertex[i].valbak,
vertex[i].val2bak).

Here are tcl script commands used for 10 steps
(~3 mm FWHM) of surface-smoothing:

  swap_valval2_valbakval2bak 
  swap_val_val2
  smooth_val 10
  swap_val_val2
  smooth_val 10
  swap_valval2_valbakval2bak

This can be used on any complex-valued data in
valbak/val2bak.

This can also be done using the tcl wrapper
function, smooth, as follows:

  smooth <steps> <type>
  smooth 10 grad 


####################
home
####################

-------------------------------------------
variable: $home/$subject -- subject home dir
-------------------------------------------

Normally, this directory gets set to:

  $SUBJECTS_DIR/subjname

where SUBJECTS_DIR is the home directory of the
subjects database (setenv SUBJECTS_DIR in .cshrc)
Subject's name taken from tksurfer command line.
Can't reset home and name here.

####################
insurf_read
####################

-------------------------------------------
var,funct: load surface (topology must match startup)
  set insurf <surface>
  read_binary_surface
-------------------------------------------

Large Panel Only: [fn-]F3

The "insurf:" entry at the upper left (large
fn-F3 panel only) contains editable name used for
reading/reloading a surface using the "R" button
to the right.  The entry shows the full filename
of the current surface (not just suffix like the
"surf:" entry on the F2 panel).

To load a different surface for the current
subject and hemisphere, type its name in the
entry and click "R".  An invalid entry will
reload the initial surface.

The standard location for surfaces is:

  $SUBJECTS_DIR/<subjname>/surf/$hemi.$surfext

This entry accepts the following variations in
the pathname for a left hemisphere orig surface:

  lh.orig               ;# in $SUBJECTS_DIR/$subject/surf
  ~/surf/lh.orig        ;# '~' globs to current subject
  /full/path/to/lh.orig ;# absolute path

The new surface must have the same number of
vertices and faces as the surface tksurfer was
started up with.  The current surface pose,
magnification, and statistical overlay data (if
any) are preserved.

This entry uses the C/tcl function:

  read_binary_surface

to read the current surface filename in the tcl/C
variable, $insurf.  The function can read native
freesurfer triangular or quadrangular surfaces in
binary or ASCII format.  A number of other
surface formats are also auto-detected and
readable by this function:

  native FreeSurfer tri or quad: (binary)
  native FreeSurfer tri or quad: (ASCII)
  ICO tri: FreeSurfer icosahedral (ASCII)
  VTK tri: visualization toolkit format (ASCII)
  OFF tri: object file format (ASCII)
  GIFTI tri: NIFTI surface format (base64 ASCII)
  OBJ tri: Alias Wavefront (ASCII)
  SRF tri: Brain Voyager (binary)

If the tksurfer start-up surface is a triangular
surface, it can't be updated/changed to a
same-vertex-count quadrangular surface (can't
know which edges to remove) using this entry.
The reverse, however works (startup with quad
surface, update with same-vertex tri surface).

Since *.srf surfaces have left-handed coordinates
(PIL vs. freesurfer RAS coordinates), they will
appear mirror-imaged in tksurfer (a right hemi
will look like a left hemi, and vice versa, and
you will get a warning panel the first two times
you open the surface).  The surface coordinates
can be mirror-imaged (e.g., in order to save the
surface as a native freesurfer surface) with
"FlipHemi" at the middle-upper right of the
larger F3 interface (this flips the sign of the
x-coordinate).

See R-click help for the upper-left "surf:" entry
for details of readable surface file formats.

####################
readenv
####################

-------------------------------------------
tcl function: source readenv.tcl -- read lowercase env to tcl
-------------------------------------------
keyboard equivalent: none

Read lower case shell environment variables (set
in sh/bash by "export", or in csh/tcsh by
"setenv") into the tcl interpreter to
override/create default tcl script parms.

Any environment var starting with a lower case
letter will be global to all scripts:

  sh/bash:   export parm=value
  csh/tcsh:  setenv parm value

To restrict a parameter (e.g., a rendering
parameter) to one scandir, prefix it with the
appropriate $rgbname, e.g., "curv" (which
saveviews.tcl will expand to something like
"/full/path/to/curv-rh-pial-lat.tiff").

  sh/bash:   export $rgbname.parm=value
  csh/tcsh:  setenv $rgbname.parm value


####################
ls
####################

-------------------------------------------
function: ls -- list tcl scripts
-------------------------------------------
keyboard equivalent: none

List all the standard scripts in the csurf tcl
script dir:

  $CSURF_DIR/lib/tcl

####################
outsurf
####################

-------------------------------------------
entry variable: $outsurf -- absolute name output surf
-------------------------------------------
default: $SUBJECTS_DIR/name/surf/$hemi.surftmp

Large Panel Only: [fn-]F3

The "outsurf:" entry on the large fn-F3 panel
contains the editable name that will be used for
writing out the current state of the surface to a
file, using one of the six buttons to the right.

The default name is:

  ~/surf/$hemi.surftmp

where the tilde (~) expands to the 'home
directory' of the current subject:

  $SUBJECTS_DIR/<subject>

A relative name assumes the same directory as
above.  An absolute name (starting with '/') is
also accepted.

Surface File Formats

Six different surface file formats can be written
using the following buttons:

  W	native freesurfer format (binary)
  ASC	freesurfer format (ASCII)
  VTK	vtk 3.0 format (ASCII)
  OFF	object file format: OFF,COFF (ASCII)
  STL	stereolithography format: 3D printer (ASCII)
  GLB	glTF 2.0: GL transmission format (binary)
  OBJ	Alias/Wavefront (ASCII)

Use the native freesurfer format ("W") for normal
operations.  The other options are for exporting
a finished surface to a 3D printer, or to use it
in another software package.

The corresponding tcl/C functions for writing
each of these six file types are:

  write_binary_surface
  write_ascii_surface
  write_vtk_surface
  write_off_surface
  write_stl_surface
  write_glb_surface
  write_obj_surface

The output file written by these functions is the
current value of the $outsurf variable, so a
minimal tcl script usage is:

  set outsurf /tmp/zz.vtk
  write_vtk_surface

If you want csurf-specific globbing (e.g., ~ to
mean the current subject), use "setfile" instead
of "set":

  setfile outsurf ~/surf/zz.vtk
  write_vtk_surface

Unlike the interface buttons, the functions don't
ask if it is OK to overwrite.

In all cases except the first, type-specific
suffixes:

  *.ascii
  *.vtk
  *.off
  *.stl
  *.glb
  *.obj
 
will be appended to the name in the "outsurf:"
entry (tcl variable $outsurf) if not already
there.  The tcl/C functions do this as well.

See R-click help for each output button for full
details of the different binary and ASCII
formats.

The original binary freesurfer surface file
format (quadrangular) was designed in 1990 on an
SGI machine with a 300 MB disk.  It was optimized
to save space and defined as native big-endian
(SGI/Sun/Motorola):

    [header]
  3bytes: 16777215
  3bytes: number of vertices
  3bytes: number of faces
    [vertex list--implicit vertex numbering]
  2bytes: x[vertex0]*100
  2bytes: y[vertex0]*100
  2bytes: z[vertex0]*100
  ...
    [face list--vertex numbers of corners]
  3bytes: face1: vertex number 1st corner
  3bytes: face1: vertex number 2nd corner
  3bytes: face1: vertex number 3rd corner
  3bytes: face1: vertex number 4th corner
  ...

See R-click help for the upper left "surf:"
dropdown on the F2 interface for full details.


####################
outsurf_write
####################

-------------------------------------------
var,funct: write FreeSurfer binary surface
  set outsurf <surface>
  write_binary_surface
-------------------------------------------

Large Panel Only: [fn-]F3

The "W" button on the "outsurf:" line in the
large fn-F3 panel writes out the current surface
as file whose name is current value of $outsurf
(entry at left), in native freesurfer format.

Overwrite with button must be confirmed, or use
tcl/C functtion, write_binary_surface which
doesn't ask.

The type of binary file written depends on the
settings of several flags, shown here in pseudo
code:

  if (vertices_per_face == 4) {
    if (newquadoutputflag) {
      write float vertices
    }
    else {
      write 2byte vertices
    }
    write quadface corners w/3byte vertex nums
  }
  if (vertices_per_face == 3) {
    if (dividequadsdoneflag && undividequadsflag) {
      if (newquadoutputflag)
        write quads with float vertices
      else
        write quads with 2byte vertices
      write quadface corners w/3byte vertex nums
    }
    else {  /* default */
      write float vertices
      write triface corners w/4byte ints
    }
  }

These flags can be passed to tksurfer as options,
set in a tcl script, or controlled by the csurf
Preferences menu:

  Preferences -> Expert Preferences -> Surf tab

####################
outsurfasc_write
####################

-------------------------------------------
var,funct: write FreeSurfer ASCII surface
  set outsurf <surface>
  write_ascii_surface
-------------------------------------------

Large Panel Only: [fn-]F3

The "ASC" button on the "outsurf:" line on the
large fn-F3 panel writes out current surface as a
FreeSurfer ASCII file whose name is current value
of $outsurf (entry at left) after auto-appending
".asc" if it isn't already there.

The button checks overwrite but the equivalent
tclfunct, write_ascii_surface, doesn't.

Writes either a triangle or quandrangle file
depending on input surface and flags.  For a
triangle input file, a triangle output file is
written.  For a quadrangle input file, it may
have been subdivided into triangles upon read (if
$dividequadsflag is set to 1).  If so, it can
still be written out as quadrangles if
$undividequadsflag is set to 1.  Those two flags
can be set per-subject in csurf -> Expert
Preferences -> Surf Tab:

  "divide each quad into 2 trianagles" => dividequdsflag
  "write div'd->tri quads as quads" => undividequadsflag

Here is the same thing in pseudo code:

  if (vertices_per_face == 4) {
    write vertices coords list
    write quadface corners list
  }
  if (vertices_per_face == 3) {
    if (dividequadsdoneflag && undividequadsflag) {
      write vertices coords list
      write quadface corners list
    }
    else {   /* default tri input */
      write vertices coords list
      write triface corners list
    }
  }

Those flags can be set in Expert Preferences.

The format of the file is:

  --line 1 begins with "#!ascii"
  --line 2 contains vertex and face counts
  --list x,y,z coords each vertex (implicit num'd)
  --list vertex numbers of each face (implicitly num'd)

For example, a triangle surface file looks like:

  #!ascii version of surface -- FreeSurfer triangles ...
  153827 307650 
  8.523451 -92.493668 11.540395
  8.326207 -92.494865 11.582228
  ...
  ...
  0.804889 22.503111 18.786871
  0.761208 22.427162 18.935295
  0 1 3
  4 3 1
  ...
  ...
  122012 122938 121995
  121116 121982 122919

A fourth entry (e.g., 0) on each vertex
or face line is ignored.

A quad file is similar except that each face in
the face list has 4 entries instead of 3, and the
header line must include at least the string
"quadrang", for example:

  #!ascii version of surface -- FreeSurfer quadrangles ...

####################
outsurfvtk_write
####################

-------------------------------------------
var,funct: write VTK (Visualization Toolkit) surface
  set outsurf <surface>
  write_vtk_surface
-------------------------------------------

Large Panel Only: [fn-]F3

The "VTK" button on the "outsurf:" line on the
large fn-F3 panel writes out current surface as a
VTK ASCII file whose name is current value of
$outsurf (entry at left) after auto-appending
".vtk" if it isn't already there.

The button checks overwrite but the equivalent
tclfunct, write_vtk_surface, doesn't.

The vertex coordinates are not transformed in any
way -- they are written in the native freesurfer
coordinate system (which may not display as a
lateral view of a hemisphere in a vtk file
viewer).

Currently, only writes a triangle file.  The
format of the file is:

  --line 1: magic line
  --line 2: header line up to 256 chars
  --line 3: ASCII (vs. BINARY)
  --line 4: DATASET <type>
  --line 5: POINTS <numvertices>
  --line 6: first vertex (implicitly num'd)
  --line 7: second vertex (implicitly num'd)
  ...
  ... [to num_vertices POINTS lines]
  --line n: POLYGONS <numpolygons> <numpolytokens>
  --line n+1: corner_count, first face vertex numbers
  --line n+2: corner_count, first face vertex numbers
  ...
  ... [to num_polygons POLYGONS lines]

For example, a vtk file looks like this (indented
below, but natively left justified):

  # vtk DataFile Version 3.0
  BB4T130527_S4_mp2rage_0_inf_profiles
  ASCII
  DATASET POLYDATA
  POINTS 954296 float
  43.35591 108.78648 122.05577
  43.44609 108.62583 122.07568
  ...
  ...
  19.28717 77.35710 24.23914
  19.33012 77.21865 24.23220
  POLYGONS 1908740 7634960
  3 2 1 0
  3 1 3 0
  ...
  ...
  3 954295 954257 954255
  3 954295 954252 954257

####################
outsurfoff_write
####################

-------------------------------------------
var,funct: write OFF (object file format) surface (ASCII)
  set outsurf <surface>
  write_off_surface
-------------------------------------------

Large Panel Only: [fn-]F3

The "OFF" button on the "outsurf:" line on the
large fn-F3 panel writes out current surface as a
OFF (object file format) ASCII file whose name is
current value of $outsurf (entry at left) after
auto-appending ".off" if it isn't already there.

The button checks overwrite but the equivalent
tclfunct, write_off_surface, doesn't.

Here is an example of how to import and display
an *.off file in Mathematica (tested on vers=9):

  Show[Import["/tmp/lh.inflated.off"], ViewPoint -> Left]

The colored surface can them be manipulated in 3D
within Mathematica.

The vertex coordinates are not transformed in any
way -- they are written in the native freesurfer
coordinate system (which may not display as a
lateral view of a hemisphere in an .off file
viewer).  The units are millimeters.

Currently, only writes a triangle file.  The
format of the file is:

  --line 1: OFF (or COFF)
  --line 2: # comment line ...
  --line 3: <vertex-count> <face-count> <edge-count>
  --line 4: <x> <y> <z>
  --line 5: <x> <y> <z>
  ...
  ... [to vertex-count lines]
  --line n+1: 3 <n1> <n2> <n3>    => 1st face vtx nums
  --line n+2: 3 <n1> <n2> <n3>    => 2nd face vtx nums
  ...
  ... [to face-count lines]

Colored surfaces

If this button is middle-clicked instead of
default left-clicked, the vertex colors of the 3
corners of each face are averaged and appended to
each face line (RGBA in 0.0-1.0 units).

If this button is shift-middle-clicked instead of
default left-clicked, vertex colors are instead
appended to each vertex line, and the first line
of the file is changed to COFF from OFF.

Currently, any displayed transparent labels are
ignored when saving face/vertex colors.

Example output

For example, an .off file with vertex colors
looks like this (indented below, but natively
left justified):

  COFF
  # created by sereno (subj=john,vtxs=148993,faces=...
  148993 297982 446973
  -19.720390 -17.439209 -56.901649 0.108 0.832 0.108 1
  -19.841877 -17.408539 -57.191742 0.108 0.832 0.108 1
  ...
  ...
  -39.697487 97.215988 -12.510045 0.390 0.390 0.390 1
  -39.618374 98.124832 -12.841537 0.390 0.390 0.390 1
  3 0 1 8
  3 9 8 1
  ...
  ...
  3 133758 133078 133757
  3 134353 134916 134907


####################
outsurfstl_write
####################

-------------------------------------------
var,funct: write stereolithography/3D printer surface
  set outsurf <surface>
  write_stl_surface
-------------------------------------------

Large Panel Only: [fn-]F3

The "STL" button on the "outsurf:" line on the
large fn-F3 panel writes out current surface as a
STL (stereolithography for 3D printer) ASCII file
whose name is current value of $outsurf (entry at
left) after auto-appending ".stl" if it isn't
already there.

The button checks overwrite but the equivalent
tclfunct, write_stl_surface, doesn't.

The vertex coordinates are translated into the
all-positive octant, but are otherwise native
freesurfer coordinates.  The units are
millimeters.

The format of the file is written as:

  --line 1: solid <object-name>
  --line 2: facet normal <xn> <yn> <zn>
  --line 3:  outer loop
  --line 4:   vertex <x> <y> <z>
  --line 5:   vertex <x> <y> <z>
  --line 6:   vertex <x> <y> <z>
  --line 7:  endloop
  --line 8: endfacet
  ...
  ... [to vertex-count groups each like line2-8]

For example, a .stl file looks like this
(indented below, but natively left justified):

  solid marser-qT1
  facet normal 0.058335 -0.992071 -0.096673
   outer loop
    vertex 26.366608 0.001556 22.375313
    vertex 26.245121 0.032227 22.085220
    vertex 26.731939 0.047028 22.294407
   endloop
  endfacet
  ...
  ...
  facet normal -0.994432 0.085947 0.060131
   outer loop
    vertex 6.264633 235.800507 63.428627
    vertex 6.239880 234.987000 64.281990
    vertex 6.389610 236.444626 64.618721
   endloop
  endfacet
  endsolid marser-qT1

####################
outsurfglb_write
####################

-------------------------------------------
var,funct: write glTF/GLB (GL Transmission Format) surface
  set outsurf <surface>
  write_glb_surface
-------------------------------------------

Large Panel Only: [fn-]F3

The "GLB" button on the "outsurf:" line on the
large fn-F3 panel writes out current surface
including current surface color, as a binary glTF
2.0 file (*.glb, little-endian) whose name is
current value of $outsurf (entry at left) after
auto-appending ".glb" if it isn't already there.

The GLB button checks overwrite but the
equivalent C/tcl funct, write_glb_surface,
doesn't.

Media Types (formerly known as MIME type)

The media type for a *.glb file was registered
in Nov 2017 as:

  model/gltf-binary
  https://www.iana.org/assignments/media-types/model/gltf-binary

A *.glb file can also be linked as:

  <a href="brain.glb" download>Get Brain Model</a>

Without these, a brower may attempt to (and fail
to) load it as html.

Binary glTF file format

The output file is an all-in-one, little-endian
binary (*.glb) glTF 2.0 file with the following
format:

  Header (12 bytes)

   4byte UInt magic ("glTF", 0x46546C67)
   4byte UInt version (2)
   4byte UInt length (bytes)

  Chunk0 (JSON, variable length)

   4byte UInt chunkLength (bytes)
   4byte UInt chunkType ("JSON", 0x4E4F534A)
   1byte UChar chunkData (ASCII, space pad to 4byte bound)
 
  Chunk1 (BIN, variable length)
 
   4byte UInt chunkLength (bytes)
   4byte UInt chunkType ("BIN", 0x004E4942)
   1byte UChar chunkData (binary, zero-pad to 4byte bound)

JSON (Chunk0) details

Here is an example of the ASCII data in the JSON
chunk for a typical FreeSurfer human hemisphere:

{
  "asset":{"generator":"CSURF2GLTF","version":"2.0"},
  "scene":0,
  "scenes":[
    {"nodes":[0]}
  ],
  "nodes":[
    {"children":[1],"matrix":
        [1.0, 0.0, 0.0, 0.0,
         0.0, 0.0,-1.0, 0.0,
         0.0, 1.0, 0.0, 0.0,
         0.0, 0.0, 0.0, 1.0]},
    {"mesh":0}
  ],
  "meshes":[
    {
      "primitives":[
        {
          "attributes":{
            "NORMAL":1,
            "POSITION":2,
            "COLOR_0":3
          },
          "indices":0,
          "mode":4
        },
      ],
      "name":"Mesh"
    }
  ],
  "accessors":[
    {
      "bufferView":0,
      "byteOffset":0,
      "componentType":5125,
      "count":893946,
      "max":[148992], 
      "min":[0],
      "type":"SCALAR"
    },
    {
      "bufferView":1,
      "byteOffset":0,
      "componentType":5126,
      "count":148993,
      "max":[1.0,1.0,1.0],
      "min":[-1.0,-1.0,-1.0],
      "type":"VEC3"
    },
    {
      "bufferView":1,
      "byteOffset":1787916,
      "componentType":5126,
      "count":148993,
      "max":[101.0,150.0,101.0],
      "min":[-101.0,-150.0,-101.0],
      "type":"VEC3"
    },
    {
      "bufferView":1,
      "byteOffset":3575832,
      "componentType":5126,
      "count":148993,
      "max":[1.0,1.0,1.0],
      "min":[0.0,0.0,0.0],
      "type":"VEC3"
    }
  ],
  "bufferViews":[
    {
      "buffer":0,
      "byteOffset":5363748,
      "byteLength":3575784,
      "target":34963
    },
    {
      "buffer":0,
      "byteOffset":0,
      "byteLength":5363748,
      "byteStride":12,
      "target":34962
    }
  ],
  "buffers":[
    {"byteLength":8939532}
  ]
}

BIN (Chunk0) details

Here is the format and order of the binary data
in the BIN chunk:

 ---------- vertex normals ---------------
   [normal triples are implicitly numbered]
   4-byte float vertex normal x comp (normlength=1)
   4-byte float vertex normal y comp (normlength=1)
   4-byte float vertex normal z comp (normlength=1)
   ... [x,y,z triples up to vertex count]
 ---------- vertex positions ---------------
   [vertex triples are implicitly numbered]
   4-byte float vertex x-position (mm)
   4-byte float vertex y-position (mm)
   4-byte float vertex z-position (mm)
   ... [x,y,z triples up to vertex count]
 ---------- vertex colors ---------------
   [color triples are implicitly numbered]
   4-byte float red (0-1), vertex0
   4-byte float green (0-1), vertex0
   4-byte float blue (0-1), vertex0
   ... [r,g,b, triples up to vertex count]
 ---- vertex numbers around each face ------
   [faces are implicitly numbered]
   [vtx nums here are implicit vtx nums above]
   [num each face ordered CCW from outside]
   4-byte unsigned int corner1, face0
   4-byte unsigned int corner2, face0
   4-byte unsigned int corner3, face0
   4-byte unsigned int corner1, face1
   4-byte unsigned int corner2, face1
   4-byte unsigned int corner3, face1
   ... [triples up to face count]
 -------------------------------------------

Full format documentation

The current full specification of the glTF 2.0
format can be found here:

  https://github.com/KhronosGroup/glTF/tree/master/specification/2.0


####################
outsurfobj_write
####################

-------------------------------------------
var,funct: write Wavefront/Alias object surface (ASCII)
  set outsurf <surface>
  write_obj_surface
-------------------------------------------

Large Panel Only: [fn-]F3

The "OBJ" button on the "outsurf:" line on the
large fn-F3 panel writes out current surface as a
OBJ (Wavefront/Alias object format) ASCII file
whose name is current value of $outsurf (entry at
left) after auto-appending ".obj" if it isn't
already there.

The button checks overwrite but the equivalent
tclfunct, write_obj_surface, doesn't.

An *.obj file can be imported and displayed in
PhotoShop (tested on version 12.0, CS5).

  File -> Open -> exported *.obj file

The surface can them be manipulated in 3D within
PhotoShop.  Vertex colors are not imported in
Photoshop CS5, but are imported in 2018 and more
recent Photoshop.

The vertex coordinates are not transformed in any
way -- they are written in the native freesurfer
coordinate system (which may not display as a
lateral view of a hemisphere in an .obj file
viewer).  The units are millimeters.

Currently, only writes a triangle file.  The
format of the file is:

  --line 1: # comment line
   [begin vertices, v]
  --line 2: v <x> <y> <z> [<r> <g> <b>]
  --line 3: v <x> <y> <z> [<r> <g> <b>]
  ...
  ... [to vertex-count lines]
   [begin optional normals, vn]
  --line n+1: [vn <x> <y> <z>]
  --line n+2: [vn <x> <y> <z>]
  ...
  ... [to vertex-count lines]
   [begin faces, f]
  --line m+1: f <n1> <n2> <n3>   => 1st face vtx nums
  --line m+2: f <n1> <n2> <n3>   => 2nd face vtx nums
  ...
  ... [to face-count lines]

If normals are included, the vtx numbers in
the face lines will look like this:

   [begin faces, f]
  --line m+1: f <n1>//<n1> <n2>//<n2> <n3>//<n3>
  --line m+2: f <n1>//<n1> <n2>//<n2> <n3>//<n3>
  ...
  ... [to face-count lines]

N.B.: vtx numbers on faces lines are always
one-based! (not zero-based as in native
freesurfer formats).

Colored surfaces, optional include vertex normals

If this button is middle-clicked instead of
default left-clicked, the vertex colors of the 3
corners of each face are averaged and appended to
each face line (RGB in 0-1 units).

If this button is shift-middle-clicked instead of
default left-clicked, the x,y,z coordinates of
vertex normals are also included in the file.

Currently, any displayed transparent labels are
ignored when saving face/vertex colors.

Example output

An example .obj file with vertex colors (but no
normals) looks like this (indented below, but
natively left justified):

  # created by sereno (subj=seamol,vtxs=147326,faces=...
  v -10.977 -137.216 -23.560 0.162 0.605 0.162
  v -11.088 -137.341 -23.928 0.147 0.638 0.147
  v -11.166 -137.467 -24.370 0.135 0.666 0.135
  ...
  ...

  v -35.129 116.356 -33.792 0.089 0.768 0.089
  v -34.610 116.343 -33.769 0.066 0.818 0.066
  f 1 2 6
  f 7 6 2
  ...
  ...
  f 147326 144180 143327
  f 143327 144180 143753


####################
dip_spacing
####################

-------------------------------------------
variable: $dip_spacing -- dipole subsample spacing
-------------------------------------------
default: 1

  subsample_dist <$dip_spacing:(int)mm>
       or
  subsample_orient <$dip_spacing:1-adjdotprod>
  write_binary_decimation

If dip_spacing>0.99, dist subsample, else orient.
$dip_spacing updates decimation filename $dec.

####################
full
####################

-------------------------------------------
variable: $fullpolrectflag
-------------------------------------------
default: 0 (off)

Toggles the display of 180 deg (default) or 360
deg of polar angle color scale on a rectangular
color scale inset mapping significance (y-axis)
and polar angle (x-axis).

####################
cm
####################

-------------------------------------------
variable: $scalebarflag -- toggle mm scale
-------------------------------------------
default: 1 (on)

The scalebar is 10 mm (1 cm) long.

####################
colbar
####################

-------------------------------------------
variable: $colscalebarflag -- scalebar switch
-------------------------------------------
default: 0 (off)

The scalebar is linear plot of statistic color
that extends from {-maxval,maxval} where:

      maxval = fmid + (1.0/fslope)

For example, for fmid=0.5 and fslope=5.0,
scalebar is -0.7 to 0.7.

####################
lights
####################

-------------------------------------------
variables: $light0, $light1, $light2, $light3
-------------------------------------------
defaults: 0.4, 0.0, 0.8, 0.2

The four "light{0,1,2,3}:" entries (F3 panel,
middle right) control the brightness of the 4
fixed lights that illuminate the brain.

On both F2 and F3 panels, shift-R-click REDRAW to
get a popup with all of the lighting parameters.

The lights don't change position as the pose of
the brain is changed.  The default brightnesses
and positions are:

  $light0 (0.4) -- straight from viewer into screen
  $light1 (0.0) -- from behind brain (i.e., turned off)
  $light2 (0.8) -- from upper right
  $light3 (0.2) -- from direct left

The x,y,z position variables look like this:

  $light0x
  $light0y
  $light0z
  $light1x
  $light1y
  [etc]

All 16 parameters can be interactively controlled
from the shift-R-click REDRAW popup.  A <Return>
in any parameter field will redraw the brain.

Non-default brightnesses and positions can be
saved on a per-subject basis in csurf -> Expert
Preferences -> Lights.

Brightness values over 1.0 work, but are
increasingly clipped to white.

The behind-the-brain light (brightness off, and
w/negative z-coord, so no effect as is) can be
re-positioned (with a positive z-coord so it's on
the same side of the brain as the viewer!) as
desired.  Positive x is to the right and positive
y is up.

In a script, use:

  set light0 <0-1>
  set light0x <-1.0 to 1.0>
  [etc]
  . . .
  do_lighting_model
  redraw

The redrawbutton proc includes the last two
commands (do_lighting_model, redraw).

Finally, the last parameter, $insidesurffact
(default: 0.6), controls the brightness of the
inside surface relative to the front surface
(over 1.0 OK).

No visible effect of $insidesurffact unless
$lighttwosidedflag is set (toggle with
ctrl-middle-click on REDRAW) *and* some part of
inside surface is visible.

####################
blufact
####################

-------------------------------------------
variable: $blufact -- background blue tint
-------------------------------------------
default: 1.0 (neutral/gray)

The "blufact:" entry (F3 panel, middle right) has
a default value of 1.0.  Setting $blufact above
1.0 give the background gray brain surface a
bluish tint.  Setting it below 1.0 gives the
surface a yellowish (brownish) tint.

This is only visible with the curvature coloring
off (or in the narrow range of colors with it on
where the surface is gray when the curvature is
zero).

Use <Return> in the entry, or the REDRAW button
to see effects of a change.  In a script, use:

  do_lighting_model
  redraw

or, more simply:

  redrawbutton


####################
shrink
####################

-------------------------------------------
function: shrink <steps>
tcl wrapper funct: startstopshrink <steps> <cyc> [normflag]
-------------------------------------------

Runs requested number of steps of surface
deformation, possibly paying attention to one or
more loaded 3D data sets.

The sum of the vectors to neighboring vertices is
first computed.  Each vertex is then moved
according to a scaled tangential force and a
scaled normal force.

The tangential force is the component of the
vector sum perpendicular to the local surface
normal (tangential to the surface).  The normal
force is the component of the vector sum in the
direction of the local surface normal.

SHRINK can also use one or more 3D data sets to
modify the normal force (if areaflag=0).

Middle-click SHRINK also runs normalize_area
after every cycle of n steps (useful for
inflate).

To save the result of a shrink in standard
FreeSurfer surface format, enter a surface suffix
in the "outsurf:" entry (default: surftmp) and
click "W" (or ASC, VTK, OFF, STL, GLB for other
formats).  Checks overwrite.


Shrink Parameters (defs, not relevant all modes/types)

 ## shrink() -- areaflag=0, flag2d=0, shrinkfillflag=0
 # dx = sx*ws + nx*nforce;
 ws (0.5) -- {area_}shrink: tangent weight (restore geom)
 wn (0.5) -- {area_}shrink: normal weight (curv reduce)
 forcemode (0)
   0: force = mstrength* tanh((val - mmid)*mslope);
   1: force = mstrength* tanh((inval - mmid)*mslope);
   2: force = mstrength*(tanh((inval - mmid)*mslope)
        - ptanh((outval - mmid)*mslope));
   3: force = 0.5*(mstrength*tanh((inval-whitemid)*mslope)
        + mstrength*tanh((val - graymid)*mslope));
 sulcflag (0) -- enable add up movement in normal dir
 locklabelflag (0) -- vertices under label won't move
 MRIflag (0) -- check T1 image ($inim)
 mstrength (0.125) -- mri image outward force factor
 mslope (0.05) -- normal force sigmoid steepness
 mmid (45.0) -- main mri value target
 whitemid (45.0) -- (force=3) inner
 graymid (30.0) -- (force=3) outer
 cthk (1.0) -- shrink est. cort thick
 chkselfintflag (0) -- self intersect: normforce=OFF,req MRI
 selfstilt (-1.0) --  slight in/neg unsticks out-moving surf
 chkfilledflag (0) -- filled ($inim2) not 0 turns off normforce
 chkthirdflag (0) -- T2 ($inim3) bright turns off normforce
 chkthird_lolim (60) -- bot lim im3 turnoff normforce
 chkthird_hilim (120) -- top lim im3 turnoff normforce
 chkgradampflag (0) -- check 3D gradient amp image
 gradampfac (5.0) -- scale 1-either-side grad amp to byte
 expandflag (0) -- normal expand no matter what
 explodeflag (0) --  if stress too high, rupture

 ### area_shrink() -- areaflag=1, flag2d=0, shrinkfillflag=0
 # dx = tx*wt + ax*wa + sx*ws + nx*nc*wn + nx*nforce*wc;
 areaflag (0) --  replace shrink() with area_shrink()
 ncthreshflag (0) -- no-op if norm component below
 ws (0.5) -- {area_}shrink: tangent weight (restore geom)
 wn (0.5) -- {area_}shrink: normal weight (curv reduce)
 wa (0.5) -- area_shrink: orig area preserving
 wt (0.5) -- area_shrink: radial border-only force
 wc (0.0) -- area_shrink: neg arat -> norm force (def=OFF!)
 wsh (0.5) -- shrink2d: shear force
 wbn (0.5) -- shrink2d: boundary normal force
 bordneiflag (1) -- area_shrink: mv bord w/non-bord nei

 ### shrink2d() -- flag2d=1, shrinkfillflag=0
 # dx = tx*wt + ax*wa + sx*ws + shx*wsh + tnx*wbn;
 flag2d (0) -- replace shrink() with shrink2d() 

 ### shrink_to_fill() -- shrinkfillflag=1
 shrinkfillflag (0) -- replace shrink() with shrink_to_fill()

 ### curv_shrink_to_fill(), ellipsoid_morph()
 icstrength (1.0) -- original ellipsoid sulc morph

 ### sphere_morph() -- spherical curv/stat/cmplx register
 # dx += (xn - x)*w;  /* nei basis, w from curv/sta/cpx */
 ws (0.5) -- tangent weight (restore geom)
 wcrv (0.5) -- curv targ img error weight
 wsta (0.0) -- stat targ img error weight
 wcpx (0.0) -- complex targ img error weight
 [for details, see R-click help to "REG" button]

 ### common parms
 momentumflag (1) -- dr = decay*lastr + update*dr;
 update (0.9) -- frac new to use
 decay (0.9) -- frac old to use

The tcl wrapper function, startstopshrink:

  startstopshrink <steps> <cyc> [normflag]

can be used to run the shrink function after the
interface is up (it make the button
purple/killable).  The <cyc> argument controls
how many rounds of <steps> updates to do before
the display is refreshed.  To see every refresh,
set <steps> to 1.

####################
shrink_steps
####################

-------------------------------------------
entry variable: $shrinksteps -- steps per redraw
-------------------------------------------
default: 2

The "steps:" entry (F3 panel, middle bottom)
controls the number of execution steps
(iterations) passed to the C/tcl function,
shrink, for each cycle.

The surface is redrawn once each cycle (function
call), so to see results of every pass through
the inner loop of shrink(), set this to 1.

####################
shrink_cyc
####################

-------------------------------------------
entry variable: $shrinkcycles -- cycles of redraws
-------------------------------------------
default: 10

The "cyc" entry (F3 panel, middle bottom)
controls the number of times the C/tcl function,
shrink(), is called.  Each call passes
$shrink_steps to the function, so the total
number of passes thru the inner loop of the
function will be:

  $shrinkcycles * $shrinksteps

The surface will be redrawn once after each cycle
(once per shrink() function call).

Here is an example of how to run shrink from a
tcl script, and write a numbered tiff of each
shrink cycle output into the subject's rgb dir:

set steps 10
set cycles 100
for {set cyc 0} {$cyc < $cycles} {incr cyc} {
  shrink $steps
  normalize_area  ;# optional
  redraw
  setfile rgb ~/rgb/frame-[format "%05d" $cyc].tiff
  save_rgb
}

####################
shrink_ckMRI
####################

-------------------------------------------
tickbox var: $MRIflag -- make shrink consider "im:" data
-------------------------------------------
default: 0 (FALSE)

The "ckMRI" tickbox (F3 panel, lower right) toggles
whether 3D MRI data is considered during a SHRINK.
 
If ticked, *and* a 3D data set has been loaded
using the "im:" entry (upper left of the F3
panel), then the value of 3D image data near each
vertex is considered during deformation of the
surface by the C/tcl function shrink (SHRINK
button).

There are 4 different ways of calculating the
'force' generated from the local image data (see
R-click help for $forcemode).

If no MRI data is loaded, shrink procedes anyway,
ignoring the image data term.

####################
shrink_adj
####################

-------------------------------------------
tcl funct: mriforce <up,down> -- adj img data targ
-------------------------------------------
keyboard equivalent: none

The "FAT" button is a convenient way to subtract
1.0 from the current value of $mmid, which
defines the "im:" 3D data value for which there
is no normal 'force' on a moveable surface
vertex.

For a standard 'T1-weighted' scan image (shorter
T1 is brighter), lowering the value of $mmid will
cause a moveable surface near the pial surface
seek a position closer to dark CSF (hence causing
the cortex to get more "FAT").

The "THIN" button adds 1.0 to $mmid, which makes
the moveable surface vertex seek a position
nearer the white matter.

####################
shrink_forcemode
####################

-------------------------------------------
entry variable: $forcemode -- normal img force eq. in shrink()
-------------------------------------------
default: 0: force = mstrength*tanh((val - mmid)*mslope);

This integer parameter (F3 panel, lower right) controls
the equation used to calculate the surface-normal image
force in shrink().  The current options are:

 0:  force = mstrength* tanh((val - mmid)*mslope);

 1:  force = mstrength* tanh((inval - mmid)*mslope);

 2:  force = mstrength*(tanh((inval - mmid)*mslope)
      - ptanh((outval - mmid)*mslope));

 3:  force = 0.5*(mstrength*tanh((inval - whitemid)*mslope)
      + mstrength*tanh((val - graymid)*mslope));

The 0-255 brightness of the image voxel (val) is
nearest-neighbor sampled at the vertex location
(val), at a distance $cthk inward along the
normal (inval), and/or at a distance $ostilt
outward along the normal (outval).

The other adjustable C/tcl parameters are:

  $mstrength -- strength of normal force
  $mslope -- steepness of ramp part of tanh sigmoid
  $mmid -- zero point of normal force
  $whitemid -- (forcemode=3) zero point inward sample
  $graymid -- (forcemode=3) zero point vertex sample

The tksurfer.c function, ptanh(), truncates
negative outputs of tanh() to 0.0

####################
shrink_mmid
####################

-------------------------------------------
entry variable: $mmid -- MRI force zeropoint
-------------------------------------------
default: 45.0

This C/tcl variable (F3 panel, lower right), sets
the value of a loaded 3D image data ("im:" entry)
at which no normal force will be applied to the
moveable surface vertex during shrink().

The default value (45.0) causes the moveable
surface to move toward a point near the pial
surface, where a standard 'T1-weighted' image
transitions to the nearly zero (black) CSF.

This variable is consulted in forcemode=0/1/2

For example, in forcemode=0, the normal force
is calculated as:

   force = mstrength* tanh((val - mmid)*mslope);

See R-click help for $forcemode for more details.

####################
shrink_ws
####################

-------------------------------------------
variable: $ws -- tangential force shrink,sphere_morph,etc
-------------------------------------------
default: 0.5

The floating point parameter, $ws ("weight of
surface"), (F3 panel, lower left) controls the
strength of the tangential neighbor
redistribution 'force' in shrink() and
sphere_morph().

The tangential force is the resultant vector from
summing the vectors from the current vertex to
each of its neighors (and then subtracting out
the component parallel to the vertex normal).
This tangentially redistributes vertices so that
they are more evenly spaced.

Turning up $ws increases the 'stiffness' of the
surface and tends to make it preserve original
geometry better.

This alters the importance of original surface
geometry relative to the other 'forces' on the
vertex, which can include:

 shrink(), area_shrink(), shrink2d(), sphere_morph()
    $wn -- normal force
 area_shrink() and shrink_2d() only
    $wa -- perserve area
 sphere_morph() only
    $wcrv (0.5) -- curv targ img error weight
    $wsta (0.0) -- stat targ img error weight
    $wcpx (0.0) -- complex targ img error weight
 shrink_2d() only
    $wbn (0.5) -- boundary normal force
    $wsh (0.5) -- anti-shear force (quads only)

Of course, turning up geometry-preservation
implies that the errors minimized by the other
forces will be minimized less.  Registration
implies deformation :-}

####################
shrink_wn
####################

-------------------------------------------
variable: $wn -- normal force shrink,sphere_morph,etc
-------------------------------------------
default: 0.5

The floating point parameter, $wn ("weight of
normal"), (F3 panel, lower left) controls the
strength of the vertex-normal 'force' in
shrink(), area_shrink(), and sphere_morph().

The first effect of the normal force is to reduce
curvature.  Since the surface is typically
smoothly convex, this will also gradually reduce
its area.

If $MRIflag is set to 1 (and a 3D data set is
loaded), the normal force will also vary as a
function of local image brightness ($forcemode
provides several different functions).

####################
shrink_wa
####################

-------------------------------------------
variable: $wa -- area force: area_shrink, shrink_2d()
-------------------------------------------
default: 0.5

The floating point parameter, $wa ("weight of
area"), (F3 panel, lower left) controls the
strength of the tangential 'force' that tries to
restore original area associated with this vertex
(sum of 1/3 of the area of each surrounding
face).

Only relevant to:

 area_shrink() -- SHRINK with "ar" ticked
 shrink_2d() -- SHRINK with "2d" ticked

####################
shrink_wbn
####################

-------------------------------------------
variable: $wbn -- boundary normal force: shrink_2d()
-------------------------------------------
default: 0.5

The floating point parameter, $wbn ("weight of
boundary normal"), (was F3 panel, lower left, now
only available by tcl script) controls the
strength of the 'force' that moves vertices at a
cut edge of a flattened patch outward to prevent
them from curling under (compensates unbalanced
distribution of neighboring vertices at a cut
edge).

This is only relevant to shrink_2d() (SHRINK with
"2d" ticked).

####################
shrink_ckself
####################

-------------------------------------------
tickbox var: $chkselfintflag -- consider self-intersect
-------------------------------------------
default: 0 (FALSE)

The "ckself" tickbox (F3 panel, lower middle)
toggles whether a self interect volume is
consulted during shrink operations.

If ticked, the shrink() function updates the
self-intersect volume at the top of the loop over
vertices.  The normal force is then zeroed if the
vertex is inside the self-intersect volume.

The update of the self-intersect volume can be
refined by adjusting the value in the "selfd:"
entry, controls the how far to move along the
surface normal from a vertex before marking the
self-intersection volume.

####################
shrink_ckfill
####################

-------------------------------------------
tickbox var: $chkfilledflag -- consider filled volume
-------------------------------------------
default: 0 (FALSE)

The "ckfill" tickbox (F3 panel, lower middle)
toggles whether a volume loaded using the "im2:"
entry (and corresponding "R" button) is consulted
during shrink operations.  This volume is
typically a standard "filled" volume.

If loaded+ticked, if a vertex is positioned
inside a non-zero (filled) voxel, the normal
force at this vertex is zeroed.

No effect of tick if "im2:" volume not loaded.

####################
shrink_ckgr
####################

-------------------------------------------
tickbox var: $chkgradampflag -- consider gradient amp
-------------------------------------------
default: 0 (FALSE)

The "ckgr" tickbox (F3 panel, lower middle)
toggles whether a gradient amplitude volume is
checked during shrink() operations.

The gradient amplitude is calculated/loaded using
the currently loaded main image volume ("im:") by
the calc_gradamp() function.  This is typically a
T1-weighted image, so the gradient amplitude will
be increase at the gray/white border and the
pial/CSF border.

The calc_gradamp() function also writes out
gradient amplitude to:

  $SUBJECTS_DIR/$subject/mri/gradamp.mgz

####################
shrink_ck3rd
####################

-------------------------------------------
tickbox var: $chkthirdflag -- consider im3 data
entry var: $chkthird_lolim
entry var: $chkthird_hilim
-------------------------------------------


The "ck3rd" tickbox (F3 panel, lower middle)
toggles whether a loaded "im3:" volume (e.g., T2
image) is checked during shrink operations.

One use is ignoring T1 voxels that are detected
to be blood vessels in a corresponding T2 image.

This will zero the shrink normal force according
to a comparison between the current "im3:" voxel
value and the current settings of $chkthird_lolim
and $chkthird_hilim ("ck3:lo" and "ck3:hi"
entries on next line).

If the current vertex finds itself within an
"im3:" voxel that is above $chkthird_hilim, the
normal force is zeroed ("vessel").  The normal
force is also zeroed if the "im3:" voxel is
*below* $chkthird_lolim ("CSF" for "T2" with
T1-weighting).

####################
shrink_clearself
####################

-------------------------------------------
tcl funct: clear_selfintersect -- clear curr img
-------------------------------------------
keyboard equivalent: none

The "CLR" button (F3 panel lower middle) clears
the current 3D self intersect buffer (if loaded).

This is an internal 3D buffer updated from the
current state of the surface at the top of each
inner loop in shrink() if $chkselfintflag is set
to 1.

After the next proposed vertex movement has been
calculated (later in the shrink() loop), if the
movement would result in self-intersection
(penetration of the current self-intersect
volume), the normal force for that vertex is
zeroed.

####################
shrink_writeself
####################

-------------------------------------------
funct: write_self_images -- write curr self-intersect
-------------------------------------------
keyboard equivalent: none

The "W" button (F3 panel, middle bottom) writes
out current contents of the self-intersect 3d
buffer to the file, $selfintersectim.

This requires that at least one mgz file has
already been read (e.g., using "im:") to load the
header fields.

####################
shrink_selfd
####################

-------------------------------------------
entry variable: $selfstilt -- selfintersect stilt
-------------------------------------------
default: -1.0

The "selfd:" entry (F3 panel, middle bottom)
controls the how far to move along the surface
normal from a vertex before nearest-neighbor
marking the self-intersection volume.

A negative $selfstilt is inward, and a positive
$selfstilt is outward.

Slightly negative (inward) unsticks an
outward-moving surface (and vice versa).

No effect unless $chkselfintflag is TRUE (=1).

####################
shrink_areaflag
####################

-------------------------------------------
tickbox variable (left-click):
  $areaflag -- toggle shrink() vs. area_shrink()
-------------------------------------------
tickbox variable (middle-click):
  $bordneiflag -- toggle special treat bord vtx
-------------------------------------------


The "ar" tickbox (F3 panel, lower middle) has two
different functions that affect the operation of
SHRINK.

-------------------------------------------
Left-click (toggle $areaflag)
-------------------------------------------

When $areaflag is 1 (ticked, default is unticked)
SHRINK uses alternate C/tcl 'shrink' function,
area_shrink().

The area_shrink() function was originally
designed for deforming quadrangular surfaces,
which can preserve edge distances without
preserving face area (by distorting each face
into a narrow diamond).

With triangular surfaces, area is directly tied
to edge lengths.

Here is code for a proposed update vector for one
vertex, from area_shrink():

  dx = tx*wt + ax*wa + sx*ws + nx*nc*wn + nx*nforce*wc;
  dy = ty*wt + ay*wa + sy*ws + ny*nc*wn + ny*nforce*wc;
  dz = tz*wt + az*wa + sz*ws + nz*nc*wn + nz*nforce*wc;

The amplitude of final movement is clamped to 1.

-------------------------------------------
Middle-click (toggle $bordneiflag)
-------------------------------------------

When $bordneiflag is 1 (middle-click the tickbox,
default state is 0), border vertices are moved
according to the average movement of their
non-border neighbors.  N.B.: a middle-click tick
toggles $bordneiflag but does not change the "ar"
tickbox, which only indicates state of $areaflag.

This is designed for running area_shrink() on a
surface that has holes cut in it, which would
otherwise have a bias to move border vertices
away from a hole, in a direction perpendicular to
the edge of the hole (because of unbalanced
neighbors).

No affect if $areaflag not 1 ("ar" tick).

####################
shrink_2dflag
####################

-------------------------------------------
tickbox variable: $flag2d -- shrink() -> shrink2d()
-------------------------------------------
default: 0 (FALSE)

The "2d" tickbox (F3 panel, lower middle) toggles
whether or not to use an alternate C/tcl 'shrink'
function, shrink2d().

The shrink2d() function is designed for
flattening cut surfaces, so it includes an
additional force that is normal to the boundary
of a cut edge.

The strength of this force is controlled by $wbn
("weight of the boundary normal").  This force
prevents inward compression and curling of the
unbalanced edge vertices.

####################
shrink_locklabel
####################

-------------------------------------------
tickbox var: $locklabelflag -- immobilize labeled
-------------------------------------------
default: 0 (FALSE)

The "locklabel" tickbox (F3 panel, lower middle)
toggles whether vertices under a label (displayed
using "D") are immobilized during shrink and
morph operations.

This flag also disables smoothing of vertex data
(curv, val, val2) at locked vertices otherwise
performed by the functions:

  smooth_curv
  smooth_val
  smooth_complexang_realamp

Usage example -- repair fsaverage inflated_avg

Immobilize all vertices in the fsaverage
$hemi.inflated_avg surfaces except for a few
giant triangles at the north and south poles.

Usage example -- only adjust not masked

Immobilize vertices without significant auditory
mapping data.

####################
shrink_ncthr
####################

-------------------------------------------
entry variable: $ncthresh -- norm comp thresh
-------------------------------------------
default: 0.02

The entry to the right of "nc" (F3 panel, middle
bottom) sets the threshold movement below which
the normal component (of total resultant neighbor
force) is zeroed.

No effect unless "nc" ($ncthreshflag) is ticked.

Used to dampen oscillating ripples in unfolded
surface (orig for quadrangular surface).

####################
shrink_ncthr_ck
####################

-------------------------------------------
tickbox var: $ncthreshflag -- toggle norm comp thresh
-------------------------------------------
default: 0 (FALSE)

The "nc" tickbox (F3 panel, lower middle) toggles
whether normal force is zeroed when proposed
normal component movement is below $ncthresh
(entry immediately to right).

####################
shrink_update
####################

-------------------------------------------
entry variable: $update -- frac proposed update
-------------------------------------------
default: 0.9

If "mo" ($momentumflag) is ticked, the "upd:"
entry (F3 panel, bottom) sets the fraction of the
CURRENT proposed movement to include in the
current update vector (tcl var: $update).

This affects the following functions:

  shrink
  area_shrink
  shrink2d
  curv_shrink_to_fill
  sphere_shrink
  ellipsoid_shrink
  ellipsoid_morph
  sphere_morph

Here is example code from area_shrink():

  /* final proposed movement this vertex */
  dx = tx*wt + ax*wa + sx*ws + nx*nc*wn + nx*nforce*wc;
  dy = ty*wt + ay*wa + sy*ws + ny*nc*wn + ny*nforce*wc;
  dz = tz*wt + az*wa + sz*ws + nz*nc*wn + nz*nforce*wc;

  if (momentumflag) {
    dx = decay*v->mx + update*dx;
    dy = decay*v->my + update*dy;
    dz = decay*v->mz + update*dz;
  }

  /* clamp move to 1 mm */
  d = sqrt(dx*dx + dy*dy + dz*dz);
  if (d>1.0) {nclip++; dx/=d; dy/=d; dz/=d;}

####################
shrink_decay
####################

-------------------------------------------
entry variable: $decay -- frac prev movement
-------------------------------------------
default: 0.9

If "mo" ($momentumflag) is ticked, the "dec:"
entry (F3 panel, bottom) sets the fraction of the
PREVIOUS actual movement to include in the
current update vector (tcl var: $decay).

This affects the following functions:

  shrink
  area_shrink
  shrink2d
  curv_shrink_to_fill
  sphere_shrink
  ellipsoid_shrink
  ellipsoid_morph
  sphere_morph

Here is example code from area_shrink():

  /* final proposed movement this vertex */
  dx = tx*wt + ax*wa + sx*ws + nx*nc*wn + nx*nforce*wc;  
  dy = ty*wt + ay*wa + sy*ws + ny*nc*wn + ny*nforce*wc;
  dz = tz*wt + az*wa + sz*ws + nz*nc*wn + nz*nforce*wc;

  if (momentumflag) {
    dx = decay*v->mx + update*dx;
    dy = decay*v->my + update*dy;
    dz = decay*v->mz + update*dz;
  }

  /* clamp move to 1 mm */
  d = sqrt(dx*dx + dy*dy + dz*dz);
  if (d>1.0) {nclip++; dx/=d; dy/=d; dz/=d;}


####################
shrink_momentum
####################

-------------------------------------------
tickbox var: $momentumflag -- toggle momentum
-------------------------------------------
default: 0 (FALSE)

The "mo" tickbox (F3 panel, bottom) toggles
whether vertices move with 'momentum' -- that is,
whether a portion of the last update is included
in the current update.

See R-click help for "upd:" or "dec:" for
more details.

####################
shrink_expand
####################

-------------------------------------------
tickbox var: $expandflag -- add expansion force
-------------------------------------------
default: 0 (FALSE)

The "expand" tickbox (F3 panel, bottom) toggles
whether to include an unconditional outward force
(in the direction of the local surface normal).

The strength is set by $mstrength.

Can be used with $explodeflag.  Only affects
shrink().

####################
shrink_explode
####################

-------------------------------------------
tickbox var: $explodeflag -- rip edge above $stressthresh
-------------------------------------------
default: 0 (FALSE)

The "explode" tickbox (F3 panel, bottom) toggles
whether to rip an edge between vertices if the
stress exceeds $stressthresh.

Adjust $stressthresh by 10% using the "FAT" and
"THIN" buttons (F3 panel, bottom right).

Stress is typically generated by ticking "expand"
($expandflag).  One an edge has ripped, a
stress-concentrating fracture will propagate to
neighboring edges.

Only affects shrink().  For a usage example, see
$CSURF_DIR/lib/tcl/explodemovie.tcl

####################
shrink_mstrength
####################

-------------------------------------------
variable: $mstrength -- strength normal img force in shrink()
-------------------------------------------
default: 0.125

This floating point parameter (F3 panel, lower
right) controls the strength of the normal image
force in shrink() and shrink_to_fill().

For the default forcemode (0), the normal image
force is calculated as:

  force = mstrength*tanh((val - mmid)*mslope);

See R-click help for $forcemode for more details.

####################
shrink_mslope
####################

-------------------------------------------
variable: $mslope -- steepness normal img force sigmoid
-------------------------------------------
default: 0.05

This floating point parameter (F3 panel, lower
right) controls the steepness of the the normal
image force tanh sigmoid in shrink() and
shrink_to_fill().

For the default forcemode (0), the normal image
force is calculated as:

  force = mstrength*tanh((val - mmid)*mslope);

See R-click help for $forcemode for more details.

####################
shrink_cthk
####################

-------------------------------------------
variable: $cthk -- inward normal sample position
-------------------------------------------
default: 1.0

This floating point parameter (F3 panel, lower
right) controls the inward distance to move along
the vertex normal before sampling the 'inval' 
from the "im:" dataset in shrink().

This is relevant for forcemode=1-3 (ignored in
forcemode=0).

For example, in forcemode=1, the normal image
force is calculated as:

  force = mstrength* tanh((inval - mmid)*mslope);

Another C/tcl variable, not currently exposed in
the interface (so script-only usage), is $ostilt
(default=1.0).

This is the 'outward along the normal' equivalent
of $cthk.  It is used to find 'outval', which is
only used in forcemode=2 as follows:

  force = mstrength*(tanh((inval - mmid)*mslope)
      - ptanh((outval - mmid)*mslope));

See R-click help for $forcemode for more details.

####################
shrink_whitemid
####################

-------------------------------------------
entry variable: $whitemid -- MRI force zeropnt, inward sample
-------------------------------------------
default: 45.0

Only relevant for forcemode=3 (ignored by other
forcemode's).

This C/tcl variable (F3 panel, lower right), sets
the value of a loaded 3D image data ("im:"
entry), sampled at a distance of $cthk inward
along the local normal, at which no normal force
will be applied to the moveable surface vertex
during shrink().

This behaves like $mmid except for the sample point.

In forcemode=3, the normal force is calculated as
follows:

 force = 0.5*(mstrength*tanh((inval - whitemid)*mslope)
      + mstrength*tanh((val - graymid)*mslope));

See R-click help for $forcemode for more details.

####################
shrink_graymid
####################

-------------------------------------------
entry variable: $graymid -- MRI force zeropoint
-------------------------------------------
default: 30.0

Only relevant for forcemode=3 (ignored by other
forcemode's).

This C/tcl variable (F3 panel, lower right), sets
the value of a loaded 3D image data ("im:" entry)
at which no normal force will be applied to the
moveable surface vertex during shrink().

The default value (30.0) causes the moveable
surface to move toward a point near the pial
surface, where a standard 'T1-weighted' image
transitions to the nearly zero (black) CSF.

In forcemode=3, this force is calculated as
follows:

 force = 0.5*(mstrength*tanh((inval - whitemid)*mslope)
      + mstrength*tanh((val - graymid)*mslope));

Thus, this is a forcemode=3 synonym for
forcemode=0 $mmid.

####################
morph
####################

-------------------------------------------
vars,function: for spherical morph
  [load data - see below]]
  set ws <geometry_weight>
  set wcrv <curv_weight>
  set wsta <stat_weight>
  set wcpx <complex_angle_weight>
  set wcpx <complex_angle2_weight>
  sphere_morph <steps>
-------------------------------------------
keyboard equivalent: none

The REG button runs the requested number of
cycles, each consisting of n steps (the surface
is refreshed once per cycle) of spherical surface
deformation (C/tcl function: sphere_morph).

The sphere_morph function simultaneously
minimizes error between up to four loaded 3D
target data sets -- curv, stat, complex-valued1,
complex-valued2 -- and their corresponding data
sets loaded onto the moveable/morphable surface,
all while trying to preserve local gemoetry.

The overall procedure is:

  (1) open a sphere.reg surface

  (2) load target curvature, and/or real-valued
  target data, and/or complex-valued data, and
  possibly a second complex-valued data set to
  surface.

  (3) sample target surface data to target
  volumes ("reverse paint", using alternate
  clicks on the "val:" line "W" button)

  (4) load corresponding moveable surface data
  (data to be morphed) onto the surface (N.B.:
  displaces target data)

  (5) run sphere_morph

The parameters (weights) controlling the morph
are found at the bottom left of the large F3
interface.  They are:

  ws: geometry restoration (neighboring vertices
    vector sum)

  wcrv: curvature (.curv) error times gradient
    component of target curvature, in neighboring
    vertex direction

  wsta: real-valued statistic (.stat) error times
    gradient compononent of target stat, in
    neighboring vertex direction

  wcpx: angle error -- atan2(.val2,.val) -- times
    gradient component of target angle times
    complex amplitude -- hypot(.val,.val2) -- in
    neighboring vertex direction

  wcpx2: angle error -- atan2(.val2bak,.valbak) -- times
    gradient component of target angle times
    complex amplitude -- hypot(.valbak,.val2bak) -- in
    neighboring vertex direction

Setting any of these parameters to 0.0 causes
this kind of data to be ignored in during error
minimization.

The vectors to neighboring vertices are first
obtained.  For each step, each center vertex is
then moved to reduce error in original geometry,
curvature, real-valued statistic, and
complex-valued angle (weighted by complex
amplitude)

The errors are computed by comparing the curv
(optional), stat (optional), complex (optional),
and complex2 (optional) values at the current
vertex to their corresponding values from the
target surface data that has been "reverse
painted" into a 3D volume (thin shells) by the
C/tcl function, surf2sphim (see R-click help for
"val:" line "W" button).

The gradients in the target images of curv, stat,
and/or angle of complex data are estimated by
sampling the respective target volumes using the
neighbors to the current vertex (neighbor vertex
basis).

The surface is forced back to the sphere every
update step by projecting the movement onto the
surface normal, after first clamping the maximum
per-step vertex movement to 1 mm ("nclips" in the
log reports number of vertices clamped each
step).

There are potentially 10 sets of vertexwise data
that need to be loaded:

CURV
  curv im target (in reverse paint voxel)
  curv at vertex of moveable surface
STAT
  stat im target (in reverse paint voxel) => e.g., qT1
  stat at vertex of moveable surface
COMPLEX
  real target (in reverse paint voxel) => e.g., _r
  real at vertex of moveable (.val)
  imag target (in reverse paint voxel) => e.g., _i
  imag at vertex of moveable (.val2)
COMPLEX2
  real2 target (in reverse paint voxel) => e.g., _r
  real2 at vertex of moveable (.valbak)
  imag2 target (in reverse paint voxel) => e.g., _i
  imag2 at vertex of moveable (.val2bak)

The first time sphere_morph is run, it will
convert the real and imaginary values in the
complex target images as well as the real and
imaginary values on the moveable surface data to
angle and amplitude (the converted surface data
is stored in in place, in .val and .val2 for the
first complex data set and .val2 and .val2bak for
the second).  This speeds up the morph (avoids
expensive per-vertex atan2's and hypot's).

Note that this will disrupt display of the
complex-valued surface data.


Example

Here is how to use 8 data sets (sulc, stat, real,
imaginary for both moveable and target) via the
interface:

  ### load surface
  must be sphere.reg
  ### load target data to surface
  select TARGET sulc file from "curv:" dropdown
  left-click "R" on "curv:" line to read to surface
  select TARGET real-val'd stat "val:" dropdown (e.g. qT1)
  left-click "R" on "val:" line to read to surface
  left-click "S/V" on "val:" line to move it to .stat
  select TARGET complex data dropdown (e.g., pol _r,_i)
  left-click "R" on "val:" line to read to surface
  ### "reverse paint" target data to volume
  shift-middle-click "W" on "val:" line (rev paint curv)
  shift-right-click "W" on "val:" line (rev paint stat)
  shift-left-click "W" on "val:" line (rev paint complex)
  ### load moveable data (data to be morphed)
  select MOVEABLE sulc file from "curv:" dropdown
  left-click "R" on "curv:" line to read to surface
  select MOVEABLE real-val'd stat "val:" dropdown (e.g. qT1)
  left-click "R" on "val:" line to read to surface
  left-click "S/V" on "val:" line to move it to .stat
  select MOVEABLE cmplx data dropdown (e.g., pol _r,_i)
  left-click "R" on "val:" line to read to surface
  ### morph (F3 interface)
  set parms: ws, wcrv, wsta, wcpx (start small)
  set steps/cycles
  click REG

or as tcl script commands:

  ### load surface
  must be sphere.reg
  ### load target to surface
  setfile curv ~/surf/targ-$hemi.sulc
  read_binary_curv
  setfile val ~/surf/targ-qT1-$hemi.w (or .curv/.mgh/.vtk)
  read_binary_values
  swap_stat_val
  setfile val ~/surf/targ-polarangle_i-$hemi.w
  read_binary_values
  swap_val_val2
  setfile val ~/surf/targ-polarangle_r-$hemi.w
  read_binary_values
  ### "reverse paint" target data to volume
  surf2sphim 0
  surf2sphim 1
  surf2sphim 2
  surf2sphim 3
  ### load data to be morphed
  setfile curv ~/surf/moveable-$hemi.sulc
  read_binary_curv
  setfile val ~/surf/moveable-qT1-$hemi.w (or .curv/.mgh/.vtk)
  read_binary_values
  swap_stat_val
  setfile val ~/surf/moveable-polarangle_i-$hemi.w
  read_binary_values
  swap_val_val2
  setfile val ~/surf/moveable-polarangle_r-$hemi.w
  read_binary_values
  ### morph
  set wc 0.5
  set wcrv 0.5
  set wsta 0.001   ;# inv proportional to real values
  set wcpx 0.1
  sphere_morph 20

N.B.: to load two complex-valued data sets for
moveable and target, load the second set first.

Morph Parameters

 ### sphere_morph()
 ws (0.5) -- tangent weight (restore geom)
 wcrv (0.5) -- curv targ img error weight
 wsta (0.0) -- stat targ img error weight
 wcpx (0.0) -- complex targ img error weight
 wcpx2 (0.0) -- 2nd complex targ img error weight
 momentumflag (1) -- dr = decay*lastr + update*dr;
 update (0.9) -- frac new to use
 decay (0.9) -- frac old to use


Actual C-code

Here is the core C-code for the two main
morph-related functions, sphere_morph() and
surf2sphim().

/*---------------------------------------*/
   morph function
/*---------------------------------------*/

#define REVPNT_PIX  1.0   /* reverse paint img pix */
#define REVPNT_SZ   256   /* reverse paint img size */
#define SPH_RAD     100.0 /* std sphere, sphere.reg */

void sphere_morph(int niter)
{
  int    k, iter, imnr, i, j, m, n, nclip, revpnt_sz=REVPNT_SZ;
  float  x, y, z, nx, ny, nz, xn, yn, zn, dx, dy, dz;
  float  dr, d, w;
  float  c=0.0, targc=0.0, targcn;
  float  s=0.0, targs=0.0, targsn;
  float  t=0.0, targt=0.0, targtn;  /* ang after conv2polar */
  float  a=0.0, targa=0.0, targan;  /* amp after conv2polar */
  float  t2=0.0, targt2=0.0;  /* ang2 after conv2polar (re-use targtn=tmpnei)*/
  float  a2=0.0, targa2=0.0;  /* amp2 after conv2polar (re-use targan=tmpnei)*/
  float  revpnt_st=REVPNT_PIX, revpnt_ps=REVPNT_PIX;
  vertex_type  *v;

  /* write r,i -> th,r in place (was: save r,i on top for disp, th,r -> bot)*/
  if (wcpx!=0.0 && !valims_cart2polarflag) {
    if (vals_cart2polarflag) {
      printf("tksurfer: ### sphere_morph: val,val2 r,i=>th,r: but not ims!\n");
      printf("tksurfer: ###   reload val,val2 and try again\n");PR return;}
    for (k=0; k<vertexcnt; k++) {
      t = atan2(vertex[k].val2,vertex[k].val);
      a = hypot(vertex[k].val,vertex[k].val2);
      vertex[k].val = t;    /* write converted in place (was to baks) */
      vertex[k].val2 = a;
    }
    vals_cart2polarflag = 1;
    for (k=0; k<revpnt_sz; k++)
    for (i=0; i<revpnt_sz; i++)
    for (j=0; j<revpnt_sz; j++) {
      t = atan2(revpnt_imag[k][i][j],revpnt_real[k][i][j]);
      a = hypot(revpnt_real[k][i][j],revpnt_imag[k][i][j]);
      revpnt_real[k][i][j] = t;
      revpnt_imag[k][i][j] = a;
    }
    valims_cart2polarflag = 1;
    printf("tksurfer: sphere_morph: onetime conv surf/ims r,i -> th,r done");PR
  }
  if (wcpx2!=0.0 && !valbakims_cart2polarflag) {
    if (valbaks_cart2polarflag) {
      printf("tksurfer: ### sphere_morph:valbak,valbak2 r,i=>th,r: not ims!\n");
      printf("tksurfer: ###   reload valbak,valbak2, try again\n");PR return;}
    for (k=0; k<vertexcnt; k++) {
      t = atan2(vertex[k].val2bak,vertex[k].valbak);
      a = hypot(vertex[k].valbak,vertex[k].val2bak);
      vertex[k].valbak = t;   /* write converted in place */
      vertex[k].val2bak = a;
    }
    valbaks_cart2polarflag = 1;
    for (k=0; k<revpnt_sz; k++)
    for (i=0; i<revpnt_sz; i++)
    for (j=0; j<revpnt_sz; j++) {
      t = atan2(revpnt_imag2[k][i][j],revpnt_real2[k][i][j]);
      a = hypot(revpnt_real2[k][i][j],revpnt_imag2[k][i][j]);
      revpnt_real2[k][i][j] = t;
      revpnt_imag2[k][i][j] = a;
    }
    valbakims_cart2polarflag = 1;
    printf("tksurfer: sphere_morph: onetime conv surf/ims r,i -> th,r done");PR
  }

  for (iter=0; iter<niter; iter++) {
    nclip = 0;
    for (k=0; k<vertexcnt; k++) {
      v = &vertex[k];
      v->ox = v->x;  v->oy = v->y;  v->oz = v->z;
    }
    for (k=0; k<vertexcnt; k++) {  /* TODO: multiscale */
      if (locklabelflag && v->annot) continue;  /* skip all: speedup */
      v = &vertex[k];
      x  = v->ox;  y  = v->oy;  z  = v->oz;  /* samp cent (vtx and targ) */
      nx = v->nx;  ny = v->ny;  nz = v->nz;
      imnr = (int)((y - yy0)/revpnt_st + 0.5);
      i =    (int)((zz1 - z)/revpnt_ps + 0.5);
      j =    (int)((xx1 - x)/revpnt_ps + 0.5);
      if (wcrv!=0.0) { c = v->curv;    targc = revpnt_curv[imnr][i][j]; }
      if (wsta!=0.0) { s = v->stat;    targs = revpnt_stat[imnr][i][j]; }
      if (wcpx!=0.0) { t = v->valbak;  targt = revpnt_real[imnr][i][j];
                       a = v->val2bak; targa = revpnt_imag[imnr][i][j]; }
      if (wcpx2!=0.0){ t2 = v->val; targt2 = revpnt_real2[imnr][i][j];
                       a2 = v->val2;targa2 = revpnt_imag2[imnr][i][j]; }
      /*if (wcpx!=0.0) targt -= 1.57;*/  /*debug: 90deg,rawFamp,wcpx=0.0002*/
      n = 0;
      dx = dy = dz = 0.0;
      for (m=0; m<v->vnum; m++) {  /* samp one nei (targ) */
        xn = vertex[v->v[m]].ox;
        yn = vertex[v->v[m]].oy;
        zn = vertex[v->v[m]].oz;
        imnr = (int)((yn - yy0)/revpnt_st + 0.5);
        i =    (int)((zz1 - zn)/revpnt_ps + 0.5);
        j =    (int)((xx1 - xn)/revpnt_ps + 0.5);
        w = ws;  /* ws=tang=0.5 */
        if (wcrv!=0.0) {  /*** err times grad comp */
          targcn = revpnt_curv[imnr][i][j];
          w += wcrv*(c - targc)*(targcn - targc);
        }
        if (wsta!=0.0) {  /*** same */
          targsn = revpnt_stat[imnr][i][j];
          w += wsta*(s - targs)*(targsn - targs);
        }
        if (wcpx!=0.0) {  /*** err times grad comp times targ amp */
          targtn = revpnt_real[imnr][i][j];  /* neighbor phase */
          targan = revpnt_imag[imnr][i][j];  /* neighbor amp (not used) */
          w += wcpx*circsubtract(t,targt)*circsubtract(targtn,targt)*targa;
        }  /* xxxxxxxxxxx -- curr:*targa, tried: *a, *(0.5*a*targa), *1.0 */
        if (wcpx2!=0.0) {  /*** err times grad comp times targ amp */
          targtn = revpnt_real2[imnr][i][j];  /* neighbor phase (OK to reuse) */
          targan = revpnt_imag2[imnr][i][j];  /* neighbor amp (not used) */
          w += wcpx2*circsubtract(t2,targt2)*circsubtract(targtn,targt)*targa2;
        }
        dx += (xn - x)*w;  /* neighbor basis */
        dy += (yn - y)*w;
        dz += (zn - z)*w;
        n++;
      }
      if (n>0) {dx = dx/n;  dy = dy/n;  dz = dz/n;}
      d = sqrt(dx*dx + dy*dy + dz*dz);  /* proposed mv dist */
      if (d>1.0) {nclip++; dx/=d; dy/=d; dz/=d;}  /* clip to 1mm */
      dr = SPH_RAD - sqrt((x+dx)*(x+dx) + (y+dy)*(y+dy) + (z+dz)*(z+dz));
      dx += dr*v->nx;  dy += dr*v->ny;  dz += dr*v->nz; /*bak2sph: proj2norm*/
      if (momentumflag) {
        dx = decay*v->mx + update*dx;
        dy = decay*v->my + update*dy;
        dz = decay*v->mz + update*dz;
        v->mx = dx;  v->my = dy;  v->mz = dz;
      }
      v->x += dx;  v->y += dy;  v->z += dz;  /*mv vtx; next: recalc sphnorm*/
      v->nx = v->x/SPH_RAD;  v->ny = v->y/SPH_RAD;  v->nz = v->z/SPH_RAD;
    }
    printf("tksurfer: step=%d: nclip=%d\n",iter,nclip);PR
  }
}

/*---------------------------------------*/
   reverse paint function
/*---------------------------------------*/

#define SPH_CURV  0
#define SPH_STAT  1
#define SPH_REAL  2
#define SPH_IMAG  3
#define SPH_REAL2 4
#define SPH_IMAG2 5

void surf2sphim(int sphvoltype) /* nearest-neigh reverse paint w/min downsamp*/
{
  int    k, imnr, i, j;
  int    revpnt_sz=REVPNT_SZ;
  float  ***revpnt=NULL, revpnt_st=REVPNT_PIX, revpnt_ps=REVPNT_PIX;
  float  x, y, z, d, maxd, dd;
  vertex_type  *v;

  if (sphvoltype==SPH_CURV)  revpnt = revpnt_curv;
  if (sphvoltype==SPH_STAT)  revpnt = revpnt_stat;
  if (sphvoltype==SPH_REAL)  revpnt = revpnt_real;
  if (sphvoltype==SPH_IMAG)  revpnt = revpnt_imag;
  if (sphvoltype==SPH_REAL2) revpnt = revpnt_real2;
  if (sphvoltype==SPH_IMAG2) revpnt = revpnt_imag2;
  if (revpnt!=NULL) freefloat3D(revpnt);
  revpnt = makefloat3D(revpnt_sz,revpnt_sz,revpnt_sz);
  if (sphvoltype==SPH_CURV)  revpnt_curv = revpnt;
  if (sphvoltype==SPH_STAT)  revpnt_stat = revpnt;
  if (sphvoltype==SPH_REAL)  revpnt_real = revpnt;
  if (sphvoltype==SPH_IMAG)  revpnt_imag = revpnt;
  if (sphvoltype==SPH_REAL2) revpnt_real2 = revpnt;
  if (sphvoltype==SPH_IMAG2) revpnt_imag2 = revpnt;

  /* avg ico vtx spacing ~0.95, samp 1mm^3 (N.B.: point upsamp -> holes) */
  for (k=0; k<revpnt_sz; k++)
  for (i=0; i<revpnt_sz; i++)
  for (j=0; j<revpnt_sz; j++)
    revpnt[k][i][j] = 0.0;
  dd = 0.2*revpnt_ps;  /* don't miss/alias (localized zeros w/1.0*revpnt_ps) */
  maxd = 1.2*revpnt_ps;
  for (k=0; k<vertexcnt; k++) {
    v = &vertex[k];
    for (d=-maxd; d<=maxd; d+=dd) {  /* reverse paint 1+ vox in/out on norm */
      x = v->x + d*v->nx;
      y = v->y + d*v->ny;
      z = v->z + d*v->nz;
      imnr = (int)((y - yy0)/revpnt_st + 0.5); /*skip clamp: req's std sphere*/
      i =    (int)((zz1 - z)/revpnt_ps + 0.5);
      j =    (int)((xx1 - x)/revpnt_ps + 0.5);
      if (sphvoltype==SPH_CURV) revpnt[imnr][i][j] = v->curv;
      if (sphvoltype==SPH_STAT) revpnt[imnr][i][j] = v->stat;
      if (sphvoltype==SPH_REAL) revpnt[imnr][i][j] = v->val;
      if (sphvoltype==SPH_IMAG) revpnt[imnr][i][j] = v->val2;
    }
  }
  if (sphvoltype==SPH_CURV)  curvimloadedflag = 1;
  if (sphvoltype==SPH_STAT)  statimloadedflag = 1;
  if (sphvoltype==SPH_REAL)  realimloadedflag = 1;
  if (sphvoltype==SPH_IMAG)  imagimloadedflag = 1;
  if (sphvoltype==SPH_REAL2) realim2loadedflag = 1;
  if (sphvoltype==SPH_IMAG2) imagim2loadedflag = 1;
}


####################
morph_wcrv
####################

-------------------------------------------
variable: $wcrv -- sulc error force sphere_morph()
-------------------------------------------
default: 0.5

The floating point parameter, $wcrv ("weight of
curv error"), (F3 panel, lower left) controls the
strength of the tangential 'force' in
sphere_morph() that tries to reduce curvature
error between moveable surface and target
(curvature data is typically "sulc" data set,
which indicates sulcal depth).

Turning this up produces better alignment at the
cost of more distorted surfaces.

See R-click help for "REG" for more details.

####################
morph_wsta
####################

-------------------------------------------
variable: $wsta -- stat error force sphere_morph()
-------------------------------------------
default: 0.0

The floating point parameter, $wsta ("weight of
stat error"), (F3 panel, lower left) controls the
strength of the tangential 'force' in
sphere_morph() that tries to reduce error between
a real-valued statistic on the moveable and
target surfaces.

Turning this up produces better alignment at the
cost of more distorted surfaces.

See R-click help for "REG" for more details.

####################
morph_wcpx
####################

-------------------------------------------
variable: $wcpx -- cmplx ang err force sphere_morph()
-------------------------------------------
default: 0.0

The floating point parameter, $wcpx ("weight of
complex angle error"), (F3 panel, lower left)
controls the strength of the tangential 'force'
in sphere_morph() that tries to reduce error
between the complex angle on the moveable and
target surfaces.

Turning this up produces better alignment at the
cost of more distorted surfaces.

See R-click help for "REG" for more details.

####################
morph_wcpx2
####################

-------------------------------------------
variable: $wcpx2 -- cmplx ang err force sphere_morph()
-------------------------------------------
default: 0.0

The floating point parameter, $wcpx2 ("weight of
complex angle error 2"), (F3 panel, lower left)
controls the strength of the tangential 'force'
in sphere_morph() that tries to reduce error
between the second complex angle on the moveable
and target surfaces.

Turning this up produces better alignment at the
cost of more distorted surfaces.

See R-click help for "REG" for more details.

####################
flatten
####################

-------------------------------------------
function: flatten -- flatten 3-D surface to plane
-------------------------------------------
keyboard equivalent: none

Flattens a 3-D surface to a plane by orthographic
projection along the average surface normal.  Use
prior to performing an area- and shear-minimizing
unfolding (shrink2d).

####################
shrink_normarea
####################

-------------------------------------------
funct: normalize_area -- restore original area
-------------------------------------------
keyboard equivalent: none

The "NormArea" button (F3 panel, far bottom left)
restores the original surface area after a SHRINK
operation.

Given a convex closed surface, the
curvature-reducing normal force in shrink() etc
will otherwise gradually cause the surface to
shrink (hence the name).

####################
clear_curv
####################

-------------------------------------------
funct: clear_curvature -- zero curvature field
-------------------------------------------
keyboard equivalent: none

The "CLR CURV" button (F3 panel, bottom left)
clears the .curv field of each vertex to 0.

####################
comp_curv
####################

-------------------------------------------
funct: compute_curvature -- recompute curvature
-------------------------------------------
keyboard equivalent: none

The "CMP CURV" button (F3 panel, bottom middle)
recomputes the curvature as the sum of the
projection of each neighboring vertex vector onto
the vertex normal.

####################
sum_sulc
####################

-------------------------------------------
tickbox var: $sulcflag -- toggle sum normal movement
-------------------------------------------
default: 0 (FALSE)

The "SumSulc" tickbox (F3 panel, bottom right)
toggles whether or not to sum the movements of
each vertex along its normal.

When this sum is computed during area-preserving
inflation of a surface, it provides a measure of
local sulcal depth, since vertices at the fundus
of a sulcus will move further outward than
vertices on the crown of a gyrus.

This sum is saved as the "sulc" dataset during a
standard surface reconstruction.

####################
swapcplx
####################

-------------------------------------------
funct: swap_valval2_valbakval2bak -- swap 2 complex
-------------------------------------------
keyboard equivalent: none

The "swapcplx" button (F3 panel, bottom right)
swaps two complex numbers at each vertex in
.val/.val2 and .valbak/.val2bak at each vertex,
which is useful during calculation of visual
field sign.

This function can also by accessed from the
standard F2 panel by using buttonbar from a
R-click on the "S/V" button on the "val:" line
(=shift-mid-click S/V).

See R-click help for "S/V" button for details.

####################
fill3d_mm
####################

-------------------------------------------
variable: $norm_move_mm_or_frac -- dist along normal
-------------------------------------------
default: -0.5

Set distance to move each vertex along vertex
normal for a single click of the "N" button.
Positive is outward, negative inward.

This can be used to make subvoxel adjustments to
the extent of the 3D fill_surface operation.

A middle-click on the "N" button uses fraction of
cortical thickness at each vertex instead of the
default mm.

####################
fill3d_normmove
####################

-------------------------------------------
funct (left-click): mv vtxs along normal, mm
  norm_move_vertices <mm>
-------------------------------------------
funct (mid-click): mv vtxs along normal, fraction
  norm_move_vertices_fracthick <frac>
-------------------------------------------


Detailed Description of "N" Button Actions

-------------------------------------------
funct (left-click): mv vtxs along normal, mm
  norm_move_vertices <mm>
-------------------------------------------

Moves each vertex along the vertex normal a given
distance in mm using the value in the adjoining
entry (pos=outward, neg=inward).

There is no surface self-intersection constraint,
so large moves may fold the surface.


-------------------------------------------
funct (mid-click): mv vtxs along normal, fraction
  norm_move_vertices_fracthick <frac>
-------------------------------------------

Moves each vertex along the vertex normal a given
fraction of cortical thickness at that vertex
(pos=outward, neg=inward).

No self-intersection contraint.

####################
fill3d_pix
####################

-------------------------------------------
variable: $fillpix -- 3d fill pixel size
-------------------------------------------
default: 1.0

If this is set to the current pixel size (1.0 or
0.5), a 3D fill (FILL3d button, to right) will be
performed with native-sized pixels resulting in a
volume similar (but not pixelwise identical) to
that produced by fill.

If fillpix is set larger than native, this will
result in a smaller number of total voxels in the
fill.  The effect is equivalent to scaling down
the surface by 1.0/(fillpix/nativepix) (e.g.,
with the function really_scale_brain) and filling
with native-sized voxels.

Setting fillpix larger than native this way can
be used to downsample a surface.  The resulting
fill.$hemi.mgz can be directly used as an input
to make a surface, which will have fewer vertices
than the original surface but be the same shape.
It will be smaller in linear dimensions by the
fraction: fillpix/nativepix.

The effect is reversed if fillpix is set smaller
than native (larger filled volume surface).

####################
fill3d_col
####################

-------------------------------------------
variable: $fillcolor3d -- 3d fill color
-------------------------------------------
default: 128

Grayscale color (0-255) to use for 3d fill.

If the volume will be used to make a surface
(e.g., using the program, surf), the fill colors
for the left and right hemispheres should match
the settings in the Expert Preferences -> Fill WM
panel (also used in the Surf panel).

The default colors are RH=127, LH=255.

####################
fill3d_fat
####################

-------------------------------------------
variable: $includeintersectingflag
-------------------------------------------
default: 0 (FALSE)

When set, voxels that intersect surface triangles
will be included in the fill (hence "fat"), else
they will be excluded.

####################
fill3d_op
####################

-------------------------------------------
function: fill_surface -- 3d fill current surface
-------------------------------------------
keyboard equiv: none

Performs a 3d fill on the current surface and
saved the result in an internal buffer.  It may
be saved with write_fill_images.

The fill begins by zeroing the 3D volume.

Then, any voxel that intersects a triangular or
quadrangular face of the surface is marked.

The volume is then filled up to the marked
surface-intersecting voxels.

The final step is to color the unfilled voxels
with $fillcolor3d and possibly also color the
surface-intersecting voxels, too, if the
$includeintersectingflag is set.

To use this volume to make a surface, name it (or
rename it) to filled.mgz and use SubjectTools ->
Create Orig Surface.

####################
fill3d_fillim
####################

-------------------------------------------
variable: $fillim -- absolute name fill3d output vol
-------------------------------------------
def: $SUBJECTS_DIR/$name/mri/fill.$hemi.mgz

Relative name assumes same dir as above.  Home
dir of subject can be abbreviated as tilde (~).
Absolute name OK, too.

####################
fill3d_saveim
####################

-------------------------------------------
function: write_fill_images
-------------------------------------------
keyboard equivalent: none

Write out current contents of the fill 3d buffer
to the file, $fillim.

This requires that at least one mgz file has
already been read (e.g., using "im:") to load the
header fields.

####################
nsamp_search
####################

-------------------------------------------
variable: $normdsampsearchflag -- toggle norm search
-------------------------------------------
default: 0

"NormSamp, Clust Controls" parameter.  To adjust,
access pop-up by L-click on "label:" (bold).

This flag affects the operation of the following
functions:

  write_label_timecourses_stats
  ("label:" line "T" and "S" buttons)

  paint_surface
  ("val3d:" line "PAINT" button)

  find_orig_vertex_coordinates
  (upper right SEND button)

  write_val_visible_vertices
  (left-clk "W" button on "label:" line)

If not ticked, data is sampled at vertex.  All
following tickboxes and entries for adjusting the
search along the normal will have no effect.

If ticked, a search along the vertex normal is
performed.  If $normdsamp and $normdmax (or
$normdfracsamp and $normdfracmax) are both 0.0,
this is equivalent to no norm search.

####################
nsamp_uniqvox
####################

-------------------------------------------
variable: $normdsampuniqvoxflag -- toggle uniq
-------------------------------------------
default: 0

"NormSamp, Clust Controls" parameter.  To adjust,
access pop-up by L-click on "label:" (bold).

This flag only affects the operation of:

  write_label_timecourses_stats
  ("label:" line "T" and "S" buttons)

It has no effect on:

  paint_surface
  ("val3d:" line "PAINT" button)

If ticked, timecourses (and/or stats) are only
written out once for each uniq voxel sampled by
the vertices in the input label.

The vertex that 'owns' the unique voxel is the
first one to hit it.

####################
nsamp_all
####################

-------------------------------------------
variable: $normdsampallflag -- toggle save all
-------------------------------------------
default: 0

"NormSamp, Clust Controls" parameter.  To adjust,
access pop-up by L-click on "label:" (bold).

This flag only affects the operation of:

  write_label_timecourses_stats
  ("label:" line "T" and "S" buttons)

It has no effect on:

  paint_surface
  ("val3d:" line "PAINT" button)

If ticked, timecourses (and/or stats) are written
out redundantly for every vertex in the input
label, even if they sample the same voxel.

####################
nsamp_dfrac
####################

-------------------------------------------
variable: $normdfracflag -- frac vs. mm
-------------------------------------------
default: 1

"NormSamp, Clust Controls" parameter.  To adjust,
access pop-up by L-click on "label:" (bold).

This flag affects the operation of the following
functions:

  write_label_timecourses_stats
  ("label:" line "T" and "S" buttons)

  paint_surface
  ("val3d:" line "PAINT" button)

  find_orig_vertex_coordinates
  (upper right SEND button)

  write_val_visible_vertices
  (left-clk "W" button on "label:" line)

If not ticked, search limits in first pair of
entries are used (in mm).

If ticked, search limits in next pair of entries
are used, and are entered as 0-1 fractions of the
distance between the sample surface and the pial
surface.

The white-matter-to-pial surface distance can
either come from the MGH freesurfer thickness
file ($samevtxthickflag = 0), or from the
distance to the equivalently numbered pial
surface vertex ($samevtxthickflag = 1).


####################
nsamp_samevtx
####################

-------------------------------------------
variable: $samevtxthickflag -- samevtx vs. norm
-------------------------------------------
default: 0

"NormSamp, Clust Controls" parameter.  To adjust,
access pop-up by L-click on "label:" (bold).

This flag affects the operation of both of the
following functions:

  write_label_timecourses_stats
  ("label:" line "T" and "S" buttons)

  paint_surface
  ("val3d:" line "PAINT" button)

If not ticked, search takes place along the local
surface normal (in mm, or as fraction of
thickness).

If ticked, search takes place along the vector to
the same-numbered vertex on the pial surface
instead of the surface normal.  If search is done
as fraction ($normdfracflag ticked), the
thickness is redefined as the distance to the
same-numbered vertex.

####################
nsamp_bok
####################

-------------------------------------------
variable: $bokflag -- curv-based mod sample depth
-------------------------------------------
default: 0

"NormSamp, Clust Controls" parameter.  To adjust,
access pop-up by L-click on "label:" (bold).

This flag affects the operation of both of the
following functions:

  write_label_timecourses_stats
  ("label:" line "T" and "S" buttons)

  paint_surface
  ("val3d:" line "PAINT" button)

If not ticked, sample distances (either mm or
fractional) are used as entered.

If ticked, the sample distance along the vertex
normal, dist, is replaced by dist2, using the
following equations.  The variables $sulfrac and
$gyrfrac control the strength of a Bok-like
cortical layer position correction, which falls
to zero at the gray/white matter and pial
surface:

 sulmm = sulfrac*thickness;
 gyrmm = gyrfrac*thickness;
 if (curv>0.0)
   dist2 += curv/curvmax*sulmm* -cos(Pi*dist/thick+0.5*Pi);
 else
   dist2 += curv/curvmin*gyrmm* -cos(Pi*dist/thick+0.5*Pi);

This only works if $normdfracflag is set to 1
(i.e., use fractional thickness distances):

####################
nsamp_wmgmext
####################

-------------------------------------------
variable: $wmgmext -- WM/GM boundary surf extension
-------------------------------------------
default: orig (or white)

"NormSamp, Clust Controls" parameter.  To adjust,
access pop-up by L-click on "label:" (bold).

This variable affects the operation of both of
the following functions:

  write_label_timecourses_stats
  ("label:" line "T" and "S" buttons)

  paint_surface
  ("val3d:" line "PAINT" button)

This sets the surface to use when searching along
the surface normal (or along the vector to the
equivalent pial vertex).  Extensions like:

  orig
  white

will be expanded to:

  $SUBJECTS_DIR/$subject/surf/$hemi.orig
  $SUBJECTS_DIR/$subject/surf/$hemi.white

####################
nsamp_min
####################

-------------------------------------------
variable: $normdsamp -- min dist (mm) along normal
-------------------------------------------
default: 0.0

"NormSamp, Clust Controls" parameter.  To adjust,
access pop-up by L-click on "label:" (bold).

This variable affects the operation of both of
the following functions:

  write_label_timecourses_stats
  ("label:" line "T" and "S" buttons)

  paint_surface
  ("val3d:" line "PAINT" button)

  find_orig_vertex_coordinates
  (upper right SEND button)

  write_val_visible_vertices
  (left-clk "W" button on "label:" line)

This sets the beginning position of the search
along the vertex normal in millimeters.

Negative numbers are accepted.

####################
nsamp_max
####################

-------------------------------------------
variable: $normdmax -- max dist (mm) along normal
-------------------------------------------
defaults: 0.0 or 2.0

"NormSamp, Clust Controls" parameter.  To adjust,
access pop-up by L-click on "label:" (bold).

This variable affects the operation of both of
the following functions:

  write_label_timecourses_stats
  ("label:" line "T" and "S" buttons)

  paint_surface
  ("val3d:" line "PAINT" button)

  find_orig_vertex_coordinates
  (upper right SEND button)

  write_val_visible_vertices
  (left-clk "W" button on "label:" line)

This sets the ending position of the search
along the vertex normal in millimeters.

Negative numbers or number beyond the
pial surface are accepted.

####################
nsamp_fracmin
####################

-------------------------------------------
variable: $normdfracsamp -- min dist (fraction) on norm
-------------------------------------------
default: 0.0

"NormSamp, Clust Controls" parameter.  To adjust,
access pop-up by L-click on "label:" (bold).

This variable affects the operation of both of
the following functions:

  write_label_timecourses_stats
  ("label:" line "T" and "S" buttons)

  paint_surface
  ("val3d:" line "PAINT" button)

  find_orig_vertex_coordinates
  (upper right SEND button)

  write_val_visible_vertices
  (left-clk "W" button on "label:" line)

This sets the beginning position of the search
along the vertex normal in a 0.0 to 1.0 fraction
of the cortical thickness at this vertex.

Negative numbers are accepted.

####################
nsamp_fracmax
####################

-------------------------------------------
variable: $normdfracmax -- max dist (fraction) on norm
-------------------------------------------
default: 0.0 or 0.8

"NormSamp, Clust Controls" parameter.  To adjust,
access pop-up by L-click on "label:" (bold).

This variable affects the operation of both of
the following functions:

  write_label_timecourses_stats
  ("label:" line "T" and "S" buttons)

  paint_surface
  ("val3d:" line "PAINT" button)

  find_orig_vertex_coordinates
  (upper right SEND button)

  write_val_visible_vertices
  (left-clk "W" button on "label:" line)

This sets the ending position of the search
along the vertex normal as a 0.0 to 1.0 fraction
of the cortical thickness at this vertex.

Negative numbers or numbers beyond the pial
surface are accepted.

####################
nsamp_step
####################

-------------------------------------------
variable: $normddstep -- sample step (mm or frac)
-------------------------------------------
default: 0.25 (mm) or 0.1 (frac)

"NormSamp, Clust Controls" parameter.  To adjust,
access pop-up by L-click on "label:" (bold).

This variable affects the operation of both of
the following functions:

  write_label_timecourses_stats
  ("label:" line "T" and "S" buttons)

  paint_surface
  ("val3d:" line "PAINT" button)

This variable sets the step size along the vertex
normal in either millimeters or fraction of
cortical thickness.

####################
nsamp_op
####################

-------------------------------------------
variable: $normdop -- operation along normal
-------------------------------------------
default: 0 (max)

"NormSamp, Clust Controls" parameter.  To adjust,
access pop-up by L-click on "label:" (bold).

This variable only affects the operation of:

  paint_surface
  ("val3d:" line "PAINT" button)

It currently has no effect on:

  write_label_timecourses_stats
  ("label:" line "T" and "S" buttons)

This controls the operation used when doing a
normal search:

  0 -- find max of all samples
  1 -- find avg of all samples
  2 -- find min of all samples

N.B. $normdop = 1 (avg) is incompatible with
finding uniq voxel vertices, since more than one
3D voxel will be sampled.

####################
nsamp_pre
####################

-------------------------------------------
variable: $preclustfthr -- hard thresh before cluster filter
-------------------------------------------
default: 5.0

"NormSamp, Clust Controls" parameter.  To adjust,
access pop-up by L-click on "label:" (bold).

This variable controls the hard threshold for
minimum-cluster-size-filtered statistics produced
by surfclust (run by "CS" button on "val:" line).

This is passed directly to surfclust as
follows:

  surfclust ... -thresh $preclustfthr ...

For more details on the operation of surfclust,
see:

  Help -> Cross Session Spherical Average

####################
nsamp_area
####################

-------------------------------------------
variable: $clustarea -- minimum cluster size mm^2
-------------------------------------------
default: 300.0

"NormSamp, Clust Controls" parameter.  To adjust,
access pop-up by L-click on "label:" (bold).

This variable controls the minimum cluster size
(in mm^2) for a cluster to pass the cluster size
filter in surfclust (run by "CS" button on "val:"
line).

This is passed directly to surfclust as follows:

  surfclust ... -minarea $clustarea ...

Use the command line utility, randsurfclust, to
determine the correct area here.  See

  Help -> Cross Session Spherical Average

for more detail on how to do this.

####################
nsamp_sul
####################

-------------------------------------------
variable: $sulfrac -- Bok-like correction in sulci
-------------------------------------------
default: -0.12

"NormSamp, Clust Controls" parameter.  To adjust,
access pop-up by L-click on "label:" (bold).

This variable displaces sample distance along the
vertex normal toward the gray/white matter
surface in sulci.  See help for $bokflag for
equation.

####################
nsamp_gyr
####################

-------------------------------------------
variable: $gyrfrac -- Bok-like correction on gyri
-------------------------------------------
default: 0.16

"NormSamp, Clust Controls" parameter.  To adjust,
access pop-up by L-click on "label:" (bold).

This variable displaces sample distances along
the vertex normal toward the pial surface on
gyri.  See help for $bokflag for equation.

####################
nsamp_uniqvtx
####################

-------------------------------------------
variable: $normdsampuniqvtxflag -- toggle uniq
-------------------------------------------
default: 0

"NormSamp, Clust Controls" parameter.  To adjust,
access pop-up by L-click on "label:" (bold).

This flag only affects the operation of:

  write_label_timecourses_stats
  ("label:" line "T" and "S" buttons)

It has no effect on:

  paint_surface
  ("val3d:" line "PAINT" button)

If ticked, timecourses (and/or stats) are only
written out once for each uniq voxel sampled by
the vertices in the input label, as when
$normdsampuniqvoxflag is set.

But in addition, the vertex that 'owns' the voxel
is the one closest to the average location of all
of the vertices that sampled the voxel (as
opposed to the first vertex to sample the voxel).

This requires doing the three operations on the
"val3d:" line (if not visible, click "val:" to
toggle to it):

 (1) one 3D native stats file is loaded with R
 (2) it is sampled to the surface with PAINT
 (3) UQ is run to find uniqsamp vertices

####################
direct_paint
####################

-------------------------------------------
funct (left-click): paint "im:" data to .val on surf
  direct_paint
-------------------------------------------

A left-click on the "P" button on the "im:" entry
line (large F3 interface) does a "direct paint"
(C/tcl funct: direct_paint) of the current "im:"
data into the .val field of the current surface.

This requires first loading a 3D data set using
"R" button on the "im:" line.

No transformation matrix is used, so this assumes
that the 3D data loaded is aligned with the
the samping surface ($wmgmext).

This function uses the following parameters to
sample the 3D data to the current surface:

  normdfracflag		0=mm, 1=fraction (def=0)
  normdsamp		dist along normal in mm (def=1.0)
  normdfracsamp		fraction cortical thickness (def=0.4)
  wmgmext		sampling surface (def=orig)

To adjust these parameters interactively, click
"label:" to get a popup.  All other parameters on
that pop-up besides the four above are ignored.

To sample inward (e.g., from the pial surface),
use a negative number for normdsamp (mm) or
normdfracsamp (fraction).

The .val data field can be scaled in place with
the C/tcl function:

  scale_val <scalefact>

To load complex-valued data, use the same
strategy as with read_binary_values -- "R" to
load imaginary 3D data first, "P" to paint it to
.val, middle-click "S/V", to swap it out of the
way to .val2, "R" to load real 3D data, "P" to
paint to it .val.

In a tcl script this would look like:

  setfile inim ~/mri/real.mgz
  read_images
  direct_paint
  swap_val_val2
  setfile inim ~/mri/imag.mgz
  read_images
  direct_paint

####################
nonintecc
####################

-------------------------------------------
variable: $noninteccendiskflag -- polar-like eccen disk
-------------------------------------------
default: 0 (off)

The "ecp" tick at the mid-upper right edge of the
F3 interface toggles display of non-integer
angle_cycles as a concentric eccentricity-like
color disk (usually only integer angle_cycles
appear as a concentric color disk).

####################
read_im_label
####################

-------------------------------------------
tcl function: sphimctrls
-------------------------------------------
keyboard equivalent: none

A default left-click on this text label ("im:")
(or a R-click on the "REG" button) in the larger
F3 interface produces a popup for sampling
surface data to a spherical shell and then
optionally saving the result as a *.mgz file in
SUBJECTS_DIR (for debugging):

  ~/mri/sphim.$hemi.mgz

The multiple spherical shells (one for each data
type) are used as possibly simultaneous morph
targets.  They and can contain the following data
types:

  .curv
  .stat
  .val
  .val2
  .valbak
  .val2bak

An optional tick "write_mgh_for_debug_flag"
enables writing out the currently sampled shell
to an *.mgz volume for debugging purposes.  This
can be displayed in tkmedit by selecting it from
the "im:" dropdown and clicking "R".

Since internal sphim data shells are in float
format, and since the optional mgz output is a
byte volume, use the $minsphdata and $maxsphdata
entries to control the floating point numbers
that will be mapped to 0 and 255 (sphim data
values beyond are clamped to these limits).

For example, to view standard curvature data
($sphvoltype=0), use -0.5 and 0.5

On the smaller F2 tksurfer interface panel, a
R-click on "W" on the "val:" line makes a
buttonbar with all the functions on the popup
(including a button to get this popup for
debugging write to .mgz).

####################
read_im
####################

-------------------------------------------
var,funct (left-click): read 3D volume into "im"
  set inim <infile>
  read_images
-------------------------------------------

The "im:" entry (not visible on fn-F2 smaller
interface), shows the name of the first volume
data set.  This data set can be used for surface
operations such as SHRINK (when "ckMRI" is
ticked) or direct_paint (adjacent "P" button).

A default startup of tksurfer from csurf (far
right "load2surf" not ticked) will *not* load
this data set.

The initial part of the path will be abbreviated
using a tidle (~) to represent the current
$SUBJECTS_DIR.

To read (or re-read) that data set, click the "R"
to the right of the entry.

To read in a different data set, enter either:

(1) a COR dir (containing 256 256x256x1byte
    or 512 512x512x1byte COR-??? images in
    coronal orientation, and COR-.info file)

       *or*

(2) an .mgh/.mgh format file (with similar
    orientation, datasize, and imagesize)

and click the "R" to the right of the entry.

The file name can be entered as a relative,
abbreviated, or absolute path.  Assuming
SUBJECTS_DIR equals /usr0/subjects, the following
3 names refer to the same COR dir data set:

  orig
  ~/mri/orig
  /usr0/subjects/martys/mri/orig

and the following 3 names refer to the same .mgz
data set:

  orig.mgz
  ~/mri/orig.mgz
  /usr0/subjects/martys/mri/orig.mgz

A <Return> is same as "R".

To write out the initial dataset, use SAVEIMG or
"W".  Change the name in the entry before
clicking "W" to write out edited data set with a
different name.

Tcl script operation

Here is an example of how to perform these
operations in a tcl script:

  setfile inim ~/mri/orig.mgz
  read_images

The "setfile" command expands the abbreviation
before setting the variable.  Alternatively, the
absolute path can be set directly:

  setfile inim /full/path/to/marty/mri/orig.mgz
  read_images


####################
read_im2
####################

-------------------------------------------
var,funct (left-click): read 3D volume into "im2"
  set inim2 <infile>
  read_images2
-------------------------------------------

The "im2:" entry (not visible on fn-F2 smaller
interface), shows the name of a secondary volume
data set.  This data set can be used for surface
operations such as SHRINK (when "ckfill" is
ticked).  This is typically a "filled" volume.

A default startup of tksurfer from csurf (far
right "load2surf filled/T2" not ticked) will
*not* load the "im:" or "im2:" data sets.  Note
that the primary image data ("im:" entry") must
be read before the secondary image can be read.

To read (or re-read) that data set, click the "R"
to the right of the entry.  See R-click help for
"im:" for image format details.

####################
read_im3
####################

-------------------------------------------
var,funct (left-click): read 3D volume into "im3"
  set inim3 <infile>
  read_images3
-------------------------------------------

The "im3:" entry (not visible on fn-F2 smaller
interface), shows the name of a tertiary volume
data set.  This data set can be used for surface
operations such as SHRINK (when "ck3rd" is
ticked).

A default startup of tksurfer from csurf (far
right "load2surf filled/T2" not ticked) will
*not* load the "im:" or "im3:" data sets.  Note
that the primary image data ("im:" entry") must 
be read before the secondary image can be read.

This can be used, for example to ignore T1 voxels
that are presumed to be blood vessels in a
corresponding T2 image, by zeroing the shrink
normal force according to a comparison between
the current "im3:" voxel value and the current
settings of $chkthird_lolim and $chkthird_hilim
("ck3:lo" and "ck3:hi" entries on next line).

To read (or re-read) that data set, click the "R"
to the right of the entry.  See R-click help for
"im:" for image format details.

####################
exptrans
####################

-------------------------------------------
variable: $logtransflag -- scale disk/rect switch
-------------------------------------------
default: 1 (on)

The "exp" tick at the mid-upper right edge of the
F3 interface toggles whether an exponential
transformation is applied to the concentric
eccentricity color disk (or rectangle for
illustrative purposes).

