1#!/bin/tcsh
2
3# ===================================================================
4# This program calculates where to put the focal point in a montaged
5# image so that the slice-viewing planes are evenly spread out across
6# the volume (well, approximately so).
7#
8# auth: PA Taylor (NIMH, NIH, USA)
9# ===================================================================
10#
11#set set version = "2.0";  set rev_dat = "Dec 19, 2018"
12#   + [PT] fix the focal point conditions.
13#
14#set set version = "2.1";  set rev_dat = "Dec 21, 2018"
15#   + [PT] re-fix the focal point conditions.
16#
17set set version = "2.2";  set rev_dat = "Jan 25, 2019"
18#   + [PT] bux fig: deal with subbrick selectors on inset;
19#          thanks again, C. Cunningham for continued patience in
20#          bug squashing!
21#
22# ===================================================================
23
24@global_parse `basename $0` "$*" ; if ($status) exit 0
25
26#set version   = "0.0";  set rev_dat   = "Nov 20, 2018"
27#   + this used to be part of @chauffeur_afni, but now is separated
28#     into its own separate @djunct_* program
29#
30# ================================================================
31
32set ulay = ""     # dset in question
33set mx   = ""     # mont dims, x
34set my   = ""     # mont dims, y
35set OUT_TYPE = "" # do we output ijk or xyz
36
37set coors = ( 0 0 0 )
38
39# ------------------- process options, a la rr ----------------------
40
41if ( $#argv == 0 ) goto SHOW_HELP
42
43set ac = 1
44while ( $ac <= $#argv )
45    # terminal options
46    if ( ("$argv[$ac]" == "-h" ) || ("$argv[$ac]" == "-help" )) then
47        goto SHOW_HELP
48    endif
49    if ( "$argv[$ac]" == "-ver" ) then
50        goto SHOW_VERSION
51    endif
52
53    #  ---------- inputs: required ---------------
54
55    if ( "$argv[$ac]" == "-inset" ) then
56        if ( $ac >= $#argv ) goto FAIL_MISSING_ARG
57        @ ac += 1
58        set ulay = "$argv[$ac]"
59
60    else if ( "$argv[$ac]" == "-montx" ) then
61        if ( $ac >= $#argv ) goto FAIL_MISSING_ARG
62        @ ac += 1
63        @ mx = "$argv[$ac]"
64
65    else if ( "$argv[$ac]" == "-monty" ) then
66        if ( $ac >= $#argv ) goto FAIL_MISSING_ARG
67        @ ac += 1
68        @ my = "$argv[$ac]"
69
70    # set type of output: ijk or xyz
71    else if ( "$argv[$ac]" == "-out_ijk" ) then
72        set OUT_TYPE = "IJK"
73    else if ( "$argv[$ac]" == "-out_xyz" ) then
74        set OUT_TYPE = "XYZ"
75
76    else
77        echo "\n\n** ERROR: unexpected option #$ac = '$argv[$ac]'\n\n"
78        goto BAD_EXIT
79
80    endif
81    @ ac += 1
82end
83
84# --------------------------- inputs -------------------------------
85
86if ( "$ulay" == "" ) then
87    echo "** ERROR: missing input dset! Use '-inset ..'"
88    goto BAD_EXIT
89endif
90
91if ( $mx == "" ) then
92    echo "** ERROR: missing montage dimension!"
93    echo "          Use '-montx ..'"
94    goto BAD_EXIT
95endif
96
97if ( $my == "" ) then
98    echo "** ERROR: missing montage dimension!"
99    echo "          Use '-monty ..'"
100    goto BAD_EXIT
101endif
102
103if ( $OUT_TYPE == "" ) then
104    echo "** ERROR: missing output type!"
105    echo "          Use '-out_ijk' or '-out_xyz'"
106    goto BAD_EXIT
107endif
108
109# ----------------------------- ugh ---------------------------------
110
111# needed to deal with orientation permutability : AIL, LAI, PSR, etc.
112
113set listori = ( 'R' 'L' 'A' 'P' 'I' 'S' )
114set listind = (  1   1   2   2   3   3  )
115
116# just the initializing value
117#set gapord = ( 0 0 0 )
118
119# ---------------------------- calcs --------------------------------
120
121# always determine dim from ulay, because that's how montaging works!
122set Dim  = `3dinfo -n4 "$ulay"`
123
124# silly stuff to deal with orientation
125set ori  = `3dinfo -orient "$ulay"`
126set ori0 = `echo $ori | awk '{print substr($0,1,1)}'`
127set ori1 = `echo $ori | awk '{print substr($0,2,1)}'`
128set ori2 = `echo $ori | awk '{print substr($0,3,1)}'`
129set all_ori = ( $ori0 $ori1 $ori2 )
130set order  = ()
131foreach oo ( $all_ori )
132    foreach i ( `seq 1 1 ${#listori}` )
133        if ( $oo == "$listori[${i}]" ) then
134            set order  = ( $order ${listind[$i]} )
135            break
136        endif
137    end
138end
139
140# ----------------- quantities related to mont dims ------------------
141
142# get ceilings of 'montage number + 1', in each direction
143#set xo2 = `echo "scale=2; ( $mx + 1 ) / 2." | bc`
144#set cmx = `echo $xo2 | perl -nl -MPOSIX -e 'print ceil($_);'`
145#set yo2 = `echo "scale=2; ( $my + 1 ) / 2." | bc`
146#set cmy = `echo $yo2 | perl -nl -MPOSIX -e 'print ceil($_);'`
147
148# ------- 1) find zero-based index of montage slices to focus on
149
150# It isn't always just the "middle" one, because in a matrix-like
151# montage, the choice is a bit more complicated.  Basically, it is a
152# central slice, in each dimension rounded up.
153#
154# This is also complicated by going back and forth between 0-based and
155# 1-based index numbers.
156
157## [PT: Dec 19, 2018] fix these values, and how they get used just
158## below to find the focal coors in terms of ijk values, which is a
159## little odd, to be honest.
160# zero-based numbers representing the row or col to jump to for the
161# focal slice in the montage.
162if ( `echo "( $mx % 2 )" | bc` == 1 ) then
163    set cmx = `echo "( ( $mx - 1) / 2 )" | bc`
164else
165    set cmx = `echo "( $mx / 2 )" | bc`
166endif
167
168if ( `echo "( $my % 2 )" | bc` == 1 ) then
169    set cmy = `echo "( ( $my - 1) / 2 )" | bc`
170else
171    set cmy = `echo "( $my / 2 )" | bc`
172endif
173
174# total number of panels
175@ tot     = $mx * $my
176# which panel is the "focal" one in the montage: 0-based counting for tcsh
177@ hpan    = ( ( $cmy ) * $mx ) + $cmx
178#echo "$mx $my $tot"
179#echo "$cmx $cmy  $hpan"
180
181# where we go just depends on this
182set gapord = `@djunct_slice_space -nwin $tot -inset "$ulay"`
183
184#set pfrac = `echo "scale=5; ( ( $hpan + 1 ) / ( $tot + 1 ) ) " | bc` # ????
185#echo "++ pfrac = $pfrac"
186
187# ## [PT: Dec 19, 2018] admittedly, this is an *odd* set of conditions
188# to reposition the centerpoint for the montage.  This depends very
189# much on how hpan is defined, above
190foreach i ( `seq 1 1 3` )
191    set offset = `echo "scale=5; ( $Dim[$i] - ( ( $tot - 1 ) * $gapord[$i] ) ) / 2" | bc`
192    set ccc0   = `echo "scale=5; $offset + ( $hpan * $gapord[$i] ) " | bc`
193    set ccc1   = `echo $ccc0 | perl -nl -MPOSIX -e 'print floor($_);'`
194    #echo OCC $offset $ccc0  $ccc1 $hpan
195
196    # somehow, R&L are just a little bit different
197    if ( ( $all_ori[$i] == 'R' ) ) then
198        set ccc2 = `echo "scale=0; $Dim[$i] - $ccc1 " | bc`
199    else if ( ( $all_ori[$i] == 'L' ) ) then
200        set ccc2 = `echo "scale=0; $ccc1 - 1 " | bc`
201    else if ( ( $all_ori[$i] == 'P' ) || ( $all_ori[$i] == 'S' ) ) then
202        set ccc2 = `echo "scale=0; $Dim[$i] - 1 - $ccc1 " | bc`
203    else
204        set ccc2 = `echo "scale=0; $ccc1 " | bc`
205    endif
206
207    set coors[$i] = `echo $ccc2 | perl -nl -MPOSIX -e 'print floor($_);'`
208end
209
210# ----------------- convert IJK to XYZ -----------------------------
211
212### Convert ijk -> xyz: the first three elements of $mdumpout are xyz
213# [PT: Jan 29, 2020] Now use a 3dcalc expr in case the ${ulay} dset
214# has RGB type, which would make 3dmaskdump whine (and the value
215# doesn't matter here---we just want ijk->xyz conversion for coords).
216set mdumpout = `3dmaskdump -ibox $coors -noijk -xyz \
217                "3dcalc -a ${ulay}[0] -expr a -byte"`
218
219if ( "$OUT_TYPE" == "IJK" ) then
220    echo $coors
221else if ( "$OUT_TYPE" == "XYZ" )  then
222    echo $mdumpout[1] $mdumpout[2] $mdumpout[3]
223else
224    echo "** ERROR: bad output type!"
225    echo "          This is not an option: '$OUT_TYPE'"
226    goto BAD_EXIT
227endif
228
229goto GOOD_EXIT
230
231# ========================================================================
232# ========================================================================
233
234SHOW_HELP:
235cat << EOF
236-------------------------------------------------------------------------
237
238OVERVIEW ~1~
239
240Just a tiny adjunct program for @chauffeur_afni.
241
242Small program to calculate how to evenly space a certain number of
243slices within each view plane of a dset.  Returns three numbers: the
244'delta slices' in the three view planes (in the order of the input
245dset's orientation).
246
247++ constructed by PA Taylor (NIMH, NIH, USA).
248
249# =========================================================================
250
251RUNNING ~1~
252
253Inputs ~2~
254
255  + a volume dset (to have a grid/dimensions)
256  + the montage's x- and y-dimensions
257  + the choice of either IJK or XYZ coordinates to be output
258
259Outputs ~2~
260
261  + three numbers: either 'i j k' or 'x y z' values.  These numbers
262    represent where to tell AFNI to set its crosshairs for a montage.
263    These can be redirected to a file, if so desired for scripting 
264    (likely!).
265
266# =========================================================================
267
268COMMAND OPTIONS ~1~
269
270-help, -h          :see helpfile (here!)
271-ver               :see version number
272
273-inset   UUU       :(req) name of input dset.
274
275-montx   MX        :(req) montage dimension: number of panels along x-axis 
276                    (i.e., number of cols)
277
278-monty   MY        :(req) montage dimension: number of panels along y-axis 
279                    (i.e., number of rows)
280
281-out_ijk           :make program output 'I J K' values.
282-out_xyz           :make program output 'X Y Z' values.
283
284EOF
285
286# ----------------------------------------------------------------------
287
288    goto GOOD_EXIT
289
290SHOW_VERSION:
291   echo "version  $version (${rev_dat})"
292   goto GOOD_EXIT
293
294FAIL_MISSING_ARG:
295    echo "** ERROR! Missing an argument after option flag: '$argv[$ac]'"
296    goto BAD_EXIT
297
298BAD_EXIT:
299    exit 1
300
301GOOD_EXIT:
302    exit 0
303