home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / image144.sit / Projection.p < prev    next >
Encoding:
Text File  |  1992-02-28  |  46.2 KB  |  1,019 lines

  1. unit Projection;
  2. {************************************************************************}
  3. {*     Projection.p                                                                                                                                          *}
  4. {*     by Michael Castle (Pascal) and Janice Keller (assembly code)                                                          *}
  5. {*     University of Michigan Mental Health Research Institute (MHRI)                                                     *}
  6. {*     e-mail address: mike_castle@um.cc.umich.edu                                                                                   *}
  7. {* ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * }
  8.  
  9. interface
  10.  
  11.     uses
  12.         QuickDraw, PrintTraps, Palettes, Globals, Utilities, File2, File1, Graphics, Camera, Functions, Stacks;
  13.  
  14.  
  15.     procedure Project;
  16.  
  17.  
  18. implementation
  19.  
  20.     const
  21.         bigpowerof2 = 8192;                               {used for integer trigonometric arithmetic}
  22.  
  23.     type
  24.         MHRIRealArray = array[1..MaxPics] of real;
  25.         RealPoint = record
  26.                 x: real;
  27.                 y: real;
  28.             end;     {record}
  29.         IntPtr = ^integer;
  30.         LongPtr = ^LongInt;
  31.  
  32.     var
  33.         SliceInterval: real;                                 {distance, in pixels, between original slices}
  34.         BoundRect: rect;                                      {boundary rectangle for a rectangular selection}
  35.         cancelled: boolean;
  36.         lower, upper: integer;
  37.         ProjSize: LongInt;
  38.  
  39.  
  40.  
  41. {******************************************************************************}
  42. {*     This procedure frees memory allocated for buffers used in projection calculations.                                       *}
  43. {******************************************************************************}
  44.     procedure DisposeProjectionPtrs (projptr, opaptr, brightcueptr: ptr; zbufptr, countbufptr, cuezbufptr: IntPtr; sumbufptr: LongPtr);
  45.     begin
  46.         if zbufptr <> nil then
  47.             DisposPtr(Ptr(zbufptr));
  48.         if opaptr <> nil then
  49.             DisposPtr(opaptr);
  50.         if sumbufptr <> nil then
  51.             DisposPtr(Ptr(sumbufptr));
  52.         if countbufptr <> nil then
  53.             DisposPtr(Ptr(countbufptr));
  54.         if cuezbufptr <> nil then
  55.             DisposPtr(Ptr(cuezbufptr));
  56.         if brightcueptr <> nil then
  57.             DisposPtr(brightcueptr);
  58.         if projptr <> nil then
  59.             DisposPtr(projptr);
  60.     end;
  61.  
  62.  
  63. {******************************************************************************}
  64. {*     This procedure projects each pixel of a volume (stack of slices) onto a plane as the volume rotates about    *}
  65. {*  the x-axis.  Integer arithmetic, precomputation of values, and iterative addition rather than multiplication  *}
  66. {*  inside a loop are used extensively to make the code run efficiently.  Projection parameters stored in global   *}
  67. {*  variables determine how the projection will be performed.  This procedure returns various buffers which   *}
  68. {*  are actually used by DoProject to find the final projected image for the volume of slices at the current angle.*}
  69. {******************************************************************************}
  70.     procedure DoOneProjectionX (nSlices, ycenter, zcenter, projwidth, projheight: integer; costheta, sintheta: longint; projptr, opaptr, brightcueptr: ptr; zbufptr, cuezbufptr, countbufptr: IntPtr; sumbufptr: LongPtr; str: string);
  71.         var
  72.             i, j, k,                                                 {loop indices}
  73.             thispixel: integer;                              {the current pixel to be projected}
  74.             offset, offsetinit: longint;                   {precomputed offsets into an image buffer}
  75.             projaddr,                                            {buffer address for final projected image}
  76.             opaaddr,                                              {buffer address for opacity surface projection component}
  77.             brightcueaddr,                                   {buffer address for brightest-point projection with interior depth cues}
  78.             zbufaddr,                                            {z-buffer address for surface projections (nearest-point/opacity)}
  79.             cuezbufaddr,                                       {z-buffer address for brightest-point projection with interior depth cues}
  80.             countbufaddr,                                     {buffer addr for counting pixels in mean-value projection}
  81.             sumbufaddr: longint;                         {buffer addr for summing pixels in mean-value projection}
  82.             z,                                                        {z-coordinate of points in current slice before rotation}
  83.             ynew, znew,                                       {y- and z-coordinates of current point after rotation}
  84.             zmax, zmin,                                       {z-coordinates of first and last slices before rotation}
  85.             zmaxminuszmintimes100: longint;  {precomputed values to save time in loops}
  86.             c100minusDepthCueInt, c100minusDepthCueSurf: integer;
  87.             DepthCueIntlessthan100, DepthCueSurflessthan100: boolean;
  88.             OpacityOrNearestPt, OpacityAndNotNearestPt: boolean;
  89.             MeanVal, BrightestPt: boolean;
  90.             ysintheta, ycostheta,                          {values used in rotational calculations before projection}
  91.             zsintheta, zcostheta, ysinthetainit, ycosthetainit: longint;
  92.             p,                                                        {pointer to final projected image buffer}
  93.             op,                                                      {pointer to opacity surface projection buffer}
  94.             bp: ptr;                                              {pointer to brightest-point projection buffer with interior depth cues}
  95.             zp,                                                      {pointer to surface projection (nearest-point/opacity) z-buffer}
  96.             qp,                                                      {pointer to z-buffer for brightest-point projection with interior depth cues}
  97.             cp: IntPtr;                                          {pointer to buffer for counting pixels for mean-value projection}
  98.             sp: LongPtr;                                       {pointer to mean-value summing buffer}
  99.             width: integer;
  100.             theLine: LineType;
  101.     begin
  102.         with BoundRect do begin                    {precompute values to avoid computations in loop}
  103.                 width := right - left;
  104.                 zmax := zcenter + projheight div 2; {find z-coordinates of first and last slices}
  105.                 zmin := zcenter - projheight div 2;
  106.                 zmaxminuszmintimes100 := 100 * (zmax - zmin);
  107.                 c100minusDepthCueInt := 100 - DepthCueInt;
  108.                 c100minusDepthCueSurf := 100 - DepthCueSurf;
  109.                 DepthCueIntlessthan100 := DepthCueInt < 100;
  110.                 DepthCueSurflessthan100 := DepthCueSurf < 100;
  111.                 OpacityOrNearestPt := (ProjectionMethod = NearestPoint) or (Opacity > 0);
  112.                 OpacityAndNotNearestPt := (Opacity > 0) and (ProjectionMethod <> NearestPoint);
  113.                 MeanVal := ProjectionMethod = MeanValue;
  114.                 BrightestPt := ProjectionMethod = BrightestPoint;
  115.                 projaddr := ord4(projptr);
  116.                 opaaddr := ord4(opaptr);
  117.                 brightcueaddr := ord4(brightcueptr);
  118.                 zbufaddr := ord4(zbufptr);
  119.                 cuezbufaddr := ord4(cuezbufptr);
  120.                 countbufaddr := ord4(countbufptr);
  121.                 sumbufaddr := ord4(sumbufptr);
  122.                 ycosthetainit := (top - ycenter - 1) * costheta;
  123.                 ysinthetainit := (top - ycenter - 1) * sintheta;
  124.                 offsetinit := ((projheight - bottom + top) div 2) * projwidth + (projwidth - right + left) div 2 - 1;
  125.                 for k := 1 to nSlices do begin
  126.                         SelectSlice(k);
  127.                         z := round((k - 1) * SliceInterval) - zcenter;
  128.                         zcostheta := z * costheta;
  129.                         zsintheta := z * sintheta;
  130.                         ycostheta := ycosthetainit;
  131.                         ysintheta := ysinthetainit;
  132.                         for j := top to bottom - 1 do begin               {read each row in the current slice}
  133.                                 ycostheta := ycostheta + costheta;               {rotate about x-axis and find new y,z}
  134.                                 ysintheta := ysintheta + sintheta;               {x-coordinates will not change}
  135.                                 ynew := (ycostheta - zsintheta) div bigpowerof2 + ycenter - top;
  136.                                 znew := (ysintheta + zcostheta) div bigpowerof2 + zcenter;
  137.                                 offset := offsetinit + ynew * projwidth;
  138.                                 GetLine(left, j, width, theLine);
  139.                                 for i := 0 to width - 1 do begin             {read each pixel in current row and project it}
  140.                                         thispixel := theLine[i];
  141.                                         offset := offset + 1;
  142.                                         if (offset >= ProjSize) or (offset < 0) then
  143.                                             offset := 0;
  144.                                         if (thispixel <= Upper) and (thispixel >= Lower) then begin
  145.                                                 if OpacityOrNearestPt then begin
  146.                                                         zp := IntPtr(zbufaddr + offset + offset);
  147.                                                         if (znew < zp^) then begin
  148.                                                                 zp^ := znew;
  149.                                                                 if OpacityAndNotNearestPt then begin
  150.                                                                         op := ptr(opaaddr + offset);
  151.                                                                         if (DepthCueSurflessthan100) then
  152.                                                                             op^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100)
  153.                                                                         else
  154.                                                                             op^ := thispixel;
  155.                                                                     end
  156.                                                                 else begin
  157.                                                                         p := ptr(projaddr + offset);
  158.                                                                         if DepthCueSurflessthan100 then
  159.                                                                             p^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100)
  160.                                                                         else
  161.                                                                             p^ := thispixel;
  162.                                                                     end;
  163.                                                             end;
  164.                                                     end;     {NearestPoint case}
  165.                                                 if MeanVal then begin
  166.                                                         sp := LongPtr(sumbufaddr + offset + offset + offset + offset);
  167.                                                         sp^ := sp^ + thispixel;
  168.                                                         cp := IntPtr(countbufaddr + offset + offset);
  169.                                                         cp^ := cp^ + 1;
  170.                                                     end     {MeanValue case}
  171.                                                 else if BrightestPt then begin
  172.                                                         if (DepthCueIntlessthan100) then begin
  173.                                                                 p := ptr(projaddr + offset);
  174.                                                                 bp := ptr(brightcueaddr + offset);
  175.                                                                 qp := IntPtr(cuezbufaddr + offset + offset);
  176.                                                                 if (thispixel < BAND(bp^, 255)) or ((thispixel = BAND(bp^, 255)) and (znew < qp^)) then begin
  177.                                                                         bp^ := thispixel;                     {use z-buffer to ensure that if depth-cueing is on,  }
  178.                                                                         qp^ := znew;                            {the closer of two equally-bright points is displayed}
  179.                                                                         p^ := 255 - (DepthCueInt * (255 - thispixel) div 100 + (c100minusDepthCueInt) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100);
  180.                                                                     end;     {then}
  181.                                                             end
  182.                                                         else begin
  183.                                                                 p := ptr(projaddr + offset);
  184.                                                                 if (thispixel < BAND(p^, 255)) then
  185.                                                                     p^ := thispixel;
  186.                                                             end;     {else}
  187.                                                     end;     {BrightestPoint case}
  188.                                             end;
  189.                                     end;     {for j}
  190.                             end;     {for i}
  191.                         UpdateMeter(10 + (k * 90) div nSlices, str);
  192.                         if CommandPeriod then begin
  193.                                 cancelled := true;
  194.                                 beep;
  195.                                 leave;
  196.                             end;
  197.                     end;     {for k}
  198.             end;     {with}
  199.     end;     {procedure DoOneProjectionX}
  200.  
  201.  
  202.  
  203. {******************************************************************************}
  204. {*     This procedure projects each pixel of a volume (stack of slices) onto a plane as the volume rotates about    *}
  205. {*  the y-axis.  Integer arithmetic, precomputation of values, and iterative addition rather than multiplication  *}
  206. {*  inside a loop are used extensively to make the code run efficiently.  Projection parameters stored in global   *}
  207. {*  variables determine how the projection will be performed.  This procedure returns various buffers which   *}
  208. {*  are actually used by DoProject to find the final projected image for the volume of slices at the current angle.*}
  209. {******************************************************************************}
  210.     procedure DoOneProjectionY (nSlices, xcenter, zcenter, projwidth, projheight: integer; costheta, sintheta: longint; projptr, opaptr, brightcueptr: ptr; zbufptr, cuezbufptr, countbufptr: IntPtr; sumbufptr: LongPtr; str: string);
  211.         var
  212.             i, j, k, thispixel: integer;
  213.             offset, offsetinit: longint;
  214.             projaddr, opaaddr, brightcueaddr, zbufaddr, cuezbufaddr, countbufaddr, sumbufaddr: longint;
  215.             z, xnew, znew, zmax, zmin, zmaxminuszmintimes100: longint;
  216.             c100minusDepthCueInt, c100minusDepthCueSurf: integer;
  217.             DepthCueIntlessthan100, DepthCueSurflessthan100: boolean;
  218.             OpacityOrNearestPt, OpacityAndNotNearestPt: boolean;
  219.             MeanVal, BrightestPt: boolean;
  220.             xsintheta, xcostheta, zsintheta, zcostheta, xsinthetainit, xcosthetainit: longint;
  221.             p, op, bp: ptr;
  222.             zp, qp, cp: IntPtr;
  223.             sp: LongPtr;
  224.             width: integer;
  225.             aLine: LineType;
  226.     begin
  227.         with BoundRect do begin
  228.                 width := right - left;
  229.                 zmax := zcenter + projwidth div 2;
  230.                 zmin := zcenter - projwidth div 2;
  231.                 zmaxminuszmintimes100 := 100 * (zmax - zmin);
  232.                 c100minusDepthCueInt := 100 - DepthCueInt;
  233.                 c100minusDepthCueSurf := 100 - DepthCueSurf;
  234.                 DepthCueIntlessthan100 := DepthCueInt < 100;
  235.                 DepthCueSurflessthan100 := DepthCueSurf < 100;
  236.                 OpacityOrNearestPt := (ProjectionMethod = NearestPoint) or (Opacity > 0);
  237.                 OpacityAndNotNearestPt := (Opacity > 0) and (ProjectionMethod <> NearestPoint);
  238.                 MeanVal := ProjectionMethod = MeanValue;
  239.                 BrightestPt := ProjectionMethod = BrightestPoint;
  240.                 projaddr := ord4(projptr);
  241.                 opaaddr := ord4(opaptr);
  242.                 brightcueaddr := ord4(brightcueptr);
  243.                 zbufaddr := ord4(zbufptr);
  244.                 cuezbufaddr := ord4(cuezbufptr);
  245.                 countbufaddr := ord4(countbufptr);
  246.                 sumbufaddr := ord4(sumbufptr);
  247.                 xcosthetainit := (left - xcenter - 1) * costheta;
  248.                 xsinthetainit := (left - xcenter - 1) * sintheta;
  249.                 for k := 1 to nSlices do begin
  250.                         SelectSlice(k);
  251.                         z := round((k - 1) * SliceInterval) - zcenter;
  252.                         zcostheta := z * costheta;
  253.                         zsintheta := z * sintheta;
  254.                         offsetinit := ((projheight - bottom + top) div 2) * projwidth + (projwidth - right + left) div 2 - projwidth;
  255.                         for j := top to bottom - 1 do begin
  256.                                 xcostheta := xcosthetainit;
  257.                                 xsintheta := xsinthetainit;
  258.                                 offsetinit := offsetinit + projwidth;
  259.                                 GetLine(left, j, width, aLine);
  260.                                 for i := 0 to width - 1 do begin
  261.                                         thispixel := aLine[i];
  262.                                         xcostheta := xcostheta + costheta;
  263.                                         xsintheta := xsintheta + sintheta;
  264.                                         if (thispixel <= Upper) and (thispixel >= Lower) then begin
  265.                                                 xnew := (xcostheta + zsintheta) div bigpowerof2 + xcenter - left;
  266.                                                 znew := (zcostheta - xsintheta) div bigpowerof2 + zcenter;
  267.                                                 offset := offsetinit + xnew;
  268.                                                 if (offset >= ProjSize) or (offset < 0) then
  269.                                                     offset := 0;
  270.                                                 if OpacityOrNearestPt then begin
  271.                                                         zp := IntPtr(zbufaddr + offset + offset);
  272.                                                         if (znew < zp^) then begin
  273.                                                                 zp^ := znew;
  274.                                                                 if OpacityAndNotNearestPt then begin
  275.                                                                         op := ptr(opaaddr + offset);
  276.                                                                         if (DepthCueSurflessthan100) then
  277.                                                                             op^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100)
  278.                                                                         else
  279.                                                                             op^ := thispixel;
  280.                                                                     end
  281.                                                                 else begin
  282.                                                                         p := ptr(projaddr + offset);
  283.                                                                         if DepthCueSurflessthan100 then
  284.                                                                             p^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100)
  285.                                                                         else
  286.                                                                             p^ := thispixel;
  287.                                                                     end;
  288.                                                             end;
  289.                                                     end;     {NearestPoint case}
  290.                                                 if MeanVal then begin
  291.                                                         sp := LongPtr(sumbufaddr + offset + offset + offset + offset);
  292.                                                         sp^ := sp^ + thispixel;
  293.                                                         cp := IntPtr(countbufaddr + offset + offset);
  294.                                                         cp^ := cp^ + 1;
  295.                                                     end     {MeanValue case}
  296.                                                 else if BrightestPt then begin
  297.                                                         if (DepthCueIntlessthan100) then begin
  298.                                                                 p := ptr(projaddr + offset);
  299.                                                                 bp := ptr(brightcueaddr + offset);
  300.                                                                 qp := IntPtr(cuezbufaddr + offset + offset);
  301.                                                                 if (thispixel < BAND(bp^, 255)) or ((thispixel = BAND(bp^, 255)) and (znew < qp^)) then begin
  302.                                                                         bp^ := thispixel;
  303.                                                                         qp^ := znew;
  304.                                                                         p^ := 255 - (DepthCueInt * (255 - thispixel) div 100 + (c100minusDepthCueInt) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100);
  305.                                                                     end;     {then}
  306.                                                             end
  307.                                                         else begin
  308.                                                                 p := ptr(projaddr + offset);
  309.                                                                 if (thispixel < BAND(p^, 255)) then
  310.                                                                     p^ := thispixel;
  311.                                                             end;     {else}
  312.                                                     end;     {BrightestPoint case}
  313.                                             end;
  314.                                     end;     {for j}
  315.                             end;     {for i}
  316.                         UpdateMeter(10 + (k * 90) div nSlices, str);
  317.                         if CommandPeriod then begin
  318.                                 cancelled := true;
  319.                                 beep;
  320.                                 leave;
  321.                             end;
  322.                     end;     {for k}
  323.             end;     {with}
  324.     end;     {procedure DoOneProjectionY}
  325.  
  326.  
  327.  
  328. {******************************************************************************}
  329. {*     This procedure projects each pixel of a volume (stack of slices) onto a plane as the volume rotates about    *}
  330. {*  the z-axis.  Integer arithmetic, precomputation of values, and iterative addition rather than multiplication  *}
  331. {*  inside a loop are used extensively to make the code run efficiently.  Projection parameters stored in global   *}
  332. {*  variables determine how the projection will be performed.  This procedure returns various buffers which   *}
  333. {*  are actually used by DoProject to find the final projected image for the volume of slices at the current angle.*}
  334. {******************************************************************************}
  335.     procedure DoOneProjectionZ (nSlices, xcenter, ycenter, zcenter, projwidth, projheight: integer; costheta, sintheta: longint; projptr, opaptr, brightcueptr: ptr; zbufptr, cuezbufptr, countbufptr: IntPtr; sumbufptr: LongPtr; str: string);
  336.         var
  337.             i, j, k, thispixel: integer;
  338.             offset, offsetinit: longint;
  339.             projaddr, opaaddr, brightcueaddr, zbufaddr, cuezbufaddr, countbufaddr, sumbufaddr: longint;
  340.             z, xnew, ynew, zmax, zmin, zmaxminuszmintimes100: longint;
  341.             c100minusDepthCueInt, c100minusDepthCueSurf: integer;
  342.             DepthCueIntlessthan100, DepthCueSurflessthan100: boolean;
  343.             OpacityOrNearestPt, OpacityAndNotNearestPt: boolean;
  344.             MeanVal, BrightestPt: boolean;
  345.             xsintheta, xcostheta, ysintheta, ycostheta: longint;
  346.             xsinthetainit, xcosthetainit, ysinthetainit, ycosthetainit: longint;
  347.             p, op, bp: ptr;
  348.             zp, qp, cp: IntPtr;
  349.             sp: LongPtr;
  350.             width: integer;
  351.             theLine: LineType;
  352.     begin
  353.         with BoundRect do begin
  354.                 width := right - left;
  355.                 zmax := zcenter + projwidth div 2;
  356.                 zmin := zcenter - projwidth div 2;
  357.                 zmaxminuszmintimes100 := 100 * (zmax - zmin);
  358.                 c100minusDepthCueInt := 100 - DepthCueInt;
  359.                 c100minusDepthCueSurf := 100 - DepthCueSurf;
  360.                 DepthCueIntlessthan100 := DepthCueInt < 100;
  361.                 DepthCueSurflessthan100 := DepthCueSurf < 100;
  362.                 OpacityOrNearestPt := (ProjectionMethod = NearestPoint) or (Opacity > 0);
  363.                 OpacityAndNotNearestPt := (Opacity > 0) and (ProjectionMethod <> NearestPoint);
  364.                 MeanVal := ProjectionMethod = MeanValue;
  365.                 BrightestPt := ProjectionMethod = BrightestPoint;
  366.                 projaddr := ord4(projptr);
  367.                 opaaddr := ord4(opaptr);
  368.                 brightcueaddr := ord4(brightcueptr);
  369.                 zbufaddr := ord4(zbufptr);
  370.                 cuezbufaddr := ord4(cuezbufptr);
  371.                 countbufaddr := ord4(countbufptr);
  372.                 sumbufaddr := ord4(sumbufptr);
  373.                 xcosthetainit := (left - xcenter - 1) * costheta;
  374.                 xsinthetainit := (left - xcenter - 1) * sintheta;
  375.                 ycosthetainit := (top - ycenter - 1) * costheta;
  376.                 ysinthetainit := (top - ycenter - 1) * sintheta;
  377.                 offsetinit := ((projheight - bottom + top) div 2) * projwidth + (projwidth - right + left) div 2 + left - 1;
  378.                 for k := 1 to nSlices do begin
  379.                         SelectSlice(k);
  380.                         z := round((k - 1) * SliceInterval) - zcenter;
  381.                         ycostheta := ycosthetainit;
  382.                         ysintheta := ysinthetainit;
  383.                         for j := top to bottom - 1 do begin
  384.                                 ycostheta := ycostheta + costheta;
  385.                                 ysintheta := ysintheta + sintheta;
  386.                                 xcostheta := xcosthetainit;
  387.                                 xsintheta := xsinthetainit;
  388.                                 GetLine(left, j, width, theLine);
  389.                                 for i := 0 to width - 1 do begin
  390.                                         thisPixel := theLine[i];
  391.                                         xcostheta := xcostheta + costheta;
  392.                                         xsintheta := xsintheta + sintheta;
  393.                                         if (thispixel <= Upper) and (thispixel >= Lower) then begin
  394.                                                 xnew := (xcostheta - ysintheta) div bigpowerof2 + xcenter - left;
  395.                                                 ynew := (xsintheta + ycostheta) div bigpowerof2 + ycenter - top;
  396.                                                 offset := offsetinit + ynew * projwidth + xnew;
  397.                                                 if (offset >= ProjSize) or (offset < 0) then
  398.                                                     offset := 0;
  399.                                                 if OpacityOrNearestPt then begin
  400.                                                         zp := IntPtr(zbufaddr + offset + offset);
  401.                                                         if (z < zp^) then begin
  402.                                                                 zp^ := z;
  403.                                                                 if OpacityAndNotNearestPt then begin
  404.                                                                         op := ptr(opaaddr + offset);
  405.                                                                         if (DepthCueSurflessthan100) then
  406.                                                                             op^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - z) div zmaxminuszmintimes100)
  407.                                                                         else
  408.                                                                             op^ := thispixel;
  409.                                                                     end
  410.                                                                 else begin
  411.                                                                         p := ptr(projaddr + offset);
  412.                                                                         if DepthCueSurflessthan100 then
  413.                                                                             p^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - z) div zmaxminuszmintimes100)
  414.                                                                         else
  415.                                                                             p^ := thispixel;
  416.                                                                     end;
  417.                                                             end;
  418.                                                     end;     {NearestPoint case}
  419.                                                 if MeanVal then begin
  420.                                                         sp := LongPtr(sumbufaddr + offset + offset + offset + offset);
  421.                                                         sp^ := sp^ + thispixel;
  422.                                                         cp := IntPtr(countbufaddr + offset + offset);
  423.                                                         cp^ := cp^ + 1;
  424.                                                     end     {MeanValue case}
  425.                                                 else if BrightestPt then begin
  426.                                                         if (DepthCueIntlessthan100) then begin
  427.                                                                 p := ptr(projaddr + offset);
  428.                                                                 bp := ptr(brightcueaddr + offset);
  429.                                                                 qp := IntPtr(cuezbufaddr + offset + offset);
  430.                                                                 if (thispixel < BAND(bp^, 255)) or ((thispixel = BAND(bp^, 255)) and (z < qp^)) then begin
  431.                                                                         bp^ := thispixel;
  432.                                                                         qp^ := z;
  433.                                                                         p^ := 255 - (DepthCueInt * (255 - thispixel) div 100 + (c100minusDepthCueInt) * (255 - thispixel) * (zmax - z) div zmaxminuszmintimes100);
  434.                                                                     end;     {then}
  435.                                                             end
  436.                                                         else begin
  437.                                                                 p := ptr(projaddr + offset);
  438.                                                                 if (thispixel < BAND(p^, 255)) then
  439.                                                                     p^ := thispixel;
  440.                                                             end;     {else}
  441.                                                     end;     {BrightestPoint case}
  442.                                             end;
  443.                                     end;     {for j}
  444.                             end;     {for i}
  445.                         UpdateMeter(10 + (k * 90) div nSlices, str);
  446.                         if CommandPeriod then begin
  447.                                 cancelled := true;
  448.                                 beep;
  449.                                 leave;
  450.                             end;
  451.                     end;     {for k}
  452.             end;     {with}
  453.     end;     {procedure DoOneProjectionZ}
  454.  
  455.  
  456.  
  457. {******************************************************************************}
  458. {*     This code initializes buffers by filling them with uniform values.  The buffers may be filled with               *}
  459. {*  one-byte, two-byte, or four-byte values (maybe others, too!).  Since multiple, huge buffers are                  *}
  460. {*  allocated for projection calculations, we have decided to write this procedure in assembly language.               *}
  461. {*  Assembly code written by Janice Keller.                                                                                                              *}
  462. {******************************************************************************}
  463.     procedure InitializeBuffer (p: ptr; size: longint; value, step: integer);
  464.     inline
  465.         $4E56, $0000,                    {link  A6,#0}
  466.         $48E7, $F880,          {movem.l  a0/d0-d4, -(sp)}
  467.         $342E, $0004,         {move.w   4(a6),d2               step}
  468.         $7000,                     {clr.l  d0                               set high word}
  469.         $302E, $0006,         {move.w   6(a6),d0               value to set}
  470.         $222E, $0008,         {move.l   8(a6),d1               projsize}
  471.         $206E, $000C,         {movea.l  12(a6),a0             start address}
  472.         $7600,                     {Test1 clr.l   d3                   set remainder to 0}
  473.         $0881, $0000,        {bclr.l       #0,d1                  test for 1 and zero}
  474.         $6702,                    {beq.b       Test2                    if 1, save it, else continue}
  475.         $7601,                     {moveq.l     #1,d3                remainder is 1}
  476.         $0881, $0001,        {Test2  bclr.l  #1,d1             test for 2 or 3}
  477.         $6702,                    {beq.b  SetValues                   if found 1, set remainder}
  478.         $5403,                    {addq.b     #2,d3                   remainder + 2}
  479.         $7801,                    {SetValues moveq.l    #1,d4  decrement projsize by 1 for step 4}
  480.         $0C02, $0004,        {cmp.b   #4,d2     if step is 4...}
  481.         $6716,                    {beq.b     SetInit                    start initting}
  482.         $7802,                    {moveq.l  #2,d4                   decr projsize by 2 for step 2}
  483.         $0C02, $0002,        {cmp.b     #2,d2                   if step is 2...}
  484.         $6708,                   {beq.b   DoubleIt                    just have to double}
  485.         $7804,                    {moveq.l   #4,d4                  decre projsize by 4 for step 1}
  486.         $1400,                    {move.b   d0,d2                    else we have a 1-er}
  487.         $E148,                    {lsl.w   #8,d0                       lo to hi}
  488.         $1002,                    {move.b  d2,d0                     reset lo}
  489.         $3400,                   {DoubleIt  move.w d0,d2        save the lo word}
  490.         $4840,                   {swap  d0                              move lo to hi}
  491.         $3002,                   {move.w  d2,d0                     reset lo}
  492.         $20C0,                   {SetInit   move.l   d0,(a0)+    set this address}
  493.         $9284,                   {sub.l  d4,d1                         decr projsize}
  494.         $0C81, $0000, $0000,  {cmp.l   #0,d1               are we done yet}
  495.         $6EF4,                   {bgt.b  SetInit                                                no}
  496.         $0C03, $0000,      {Remainder  cmp.b  #0,d3     is there anything left}
  497.         $672C,                  {beq.b   Exit                           no, all done}
  498.         $5383,                  {subq.l  #1,d3                              0-2, not 1-3}
  499.         $302E, $0006,      {move.w  6(a6),d0                 get the value}
  500.         $342E, $0004,      {move.w 4(a6),d2                  get the step}
  501.         $0C02, $0004,        {cmp.b  #4,d2                        is this a step 4}
  502.         $6608,                     {bne.b   Teststep2                  no}
  503.         $20C0,                   {Loop4   move.l  d0,(a0)+      yes, set long}
  504.         $51CB, $FFFC,       {dbra   d3,Loop4                    next one}
  505.         $6014,                  {bra.b  Exit}
  506.         $0C02, $0002,      {TestStep2   cmp.b  #2,d2     is this a step 2}
  507.         $6608,                 {bne.b   Loop1                       no, must be a 1}
  508.         $30C0,                 {Loop2  move.w  d0,(a0)+     yes, set word}
  509.         $51CB, $FFFC,       {dbra   d3,Loop2                    next one}
  510.         $6006,                 {bra.b  Exit}
  511.         $10C0,                 {Loop1  move.b   d0,(a0)+      set bytes}
  512.         $51CB, $FFFC,      {dbra  d3,Loop1                     next one}
  513.         $4CDF, $011F,       {Exit  movem.l    (sp)+,a0/d0-d4}
  514.         $4E5E,                   {unlk    a6}
  515.         $DEFC, $000C;      {add.w   #12,sp}
  516. {this Pascal code works except for the fact that the pointer must change type with step}
  517. {so if you want to use the Pascal, you'll need a case statement for each allowable size}
  518. {$IFC false}
  519.     var
  520.         offset: longint;
  521. begin
  522.     for offset := 0 to size - 1 do begin
  523.             p^ := value;
  524.             p := Ptr(ord4(p) + step);
  525.         end;     {for}
  526. end;     {procedure InitializeBuffer}
  527. {$ENDC}
  528.  
  529. {******************************************************************************}
  530. {*     This function writes a message on the screen in an alert box, giving the user the option to either accept      *}
  531. {*  the consequences of the message by clicking OK or reject them by clicking CANCEL.  Based on PutMessage.     *}
  532. {******************************************************************************}
  533. function PutMessageWithCancel (str: str255): integer;
  534. begin
  535.     InitCursor;
  536.     ParamText(str, '', '', '');
  537.     PutMessageWithCancel := Alert(800, nil);
  538. end;
  539.  
  540.  
  541. {******************************************************************************}
  542. {*     This procedure creates a sequence of projections of a rotating volume (stack of slices) onto a plane using   *}
  543. {*  nearest-point (surface), brightest-point, or mean-value projection or a weighted combination of nearest- *}
  544. {*  point projection with either of the other two methods (partial opacity).  The user may choose to rotate the   *}
  545. {*  volume about any of the three orthogonal axes (x,y, or z), make portions of the volume transparent, or add  *}
  546. {*  a greater degree of visual realism by employing depth cues.                                                                               *}
  547. {******************************************************************************}
  548. procedure DoProjection;
  549.     var
  550.         tport: Grafptr;
  551.         nSlices: integer;                                      {number of slices in volume}
  552.         projwidth, projheight: integer;              {dimensions of projection image}
  553.         xcenter, ycenter, zcenter: integer;         {coordinates of center of volume of rotation}
  554.         theta: integer;                                          {current angle of rotation in degrees}
  555.         thetarad: real;                                          {current angle of rotation in radians}
  556.         sintheta, costheta: longint;                      {sine and cosine of current angle}
  557.         xsinthetainit, xcosthetainit: longint;      {precomputed products to avoid mult in loops}
  558.         offset, MemoryRequired: longint;
  559.         p, op, bp, projptr, opaptr, brightcueptr: ptr;
  560.         zp, zbufptr, qp, cuezbufptr, countbufptr, cp: IntPtr;
  561.         sp, sumbufptr: LongPtr;
  562.         curval, prevval, nextval, aboveval, belowval: integer;
  563.         ignore: integer;                                        {irrelevant return value from a function}
  564.         ticksinit, tickstogo, TicksForOneProjection: longint;
  565.         str, TimeStr, seconds: string;
  566.         SaveProjectionsTemp, AutoSelectAll, AllocatingBuffers: boolean;
  567.         n, nProjections, angle: integer;
  568.         SourceInfo, DestInfo: InfoPtr;
  569.  
  570.     procedure Abort;
  571.     begin
  572.         DisposeProjectionPtrs(projptr, opaptr, brightcueptr, zbufptr, countbufptr, cuezbufptr, sumbufptr);
  573.         if AllocatingBuffers and (MaxBlock > 20000) then
  574.             PutMessage('Insufficient Memory.');
  575.         exit(DoProjection);
  576.     end;
  577.  
  578. begin
  579.     ShowWatch;
  580.     AutoSelectAll := not Info^.RoiShowing;
  581.     if AutoSelectAll then
  582.         SelectAll(false);
  583.     if NotInBounds then
  584.         exit(DoProjection);
  585.     cancelled := false;
  586.     SourceInfo := Info;
  587.     GetPort(tPort);
  588.     with Info^ do begin
  589.             SetPort(GrafPtr(osPort));
  590.             BoundRect := Roirect;
  591.         end;
  592.     if (AngleInc = 0) and (TotalAngle <> 0) then
  593.         AngleInc := 5;
  594.     angle := 0;
  595.     nProjections := 0;
  596.     if AngleInc = 0 then
  597.         nProjections := 1
  598.     else
  599.         while angle <= TotalAngle do begin
  600.                 nProjections := nProjections + 1;
  601.                 angle := angle + AngleInc;
  602.             end;
  603.     if angle > 360 then
  604.         nProjections := nProjections - 1;
  605.     if nProjections <= 0 then
  606.         nProjections := 1;
  607.     nSlices := Info^.StackInfo^.nSlices;         {get number of slices in volume}
  608.     with BoundRect do begin
  609.             xcenter := (left + right) div 2;          {find center of volume of rotation}
  610.             ycenter := (top + bottom) div 2;
  611.             zcenter := round(nSlices * SliceInterval / 2.0);
  612.             if MinProjSize and (AxisOfRotation <> ZAxis) then begin
  613.                     case AxisOfRotation of                    {find dimensions of projection image}
  614.                         XAxis:  begin
  615.                                 projheight := round(sqrt(sqr(nSlices * SliceInterval) + longint(bottom - top) * (bottom - top)));
  616.                                 projwidth := right - left;
  617.                             end;     {XAxis}
  618.                         YAxis:  begin
  619.                                 projwidth := round(sqrt(sqr(nSlices * SliceInterval) + longint(right - left) * (right - left)));
  620.                                 projheight := bottom - top;
  621.                             end;     {YAxis}
  622.                     end;     {case}
  623.                 end     {then}
  624.             else begin
  625.                     projwidth := round(sqrt(sqr(nSlices * SliceInterval) + longint(right - left) * (right - left)));
  626.                     projheight := round(sqrt(sqr(nSlices * SliceInterval) + longint(bottom - top) * (bottom - top)));
  627.                 end;     {else make all windows the same size regardless of rotation axis}
  628.         end;     {with BoundRect}
  629.     if odd(projwidth) then
  630.         projwidth := projwidth + 1;
  631.     projptr := nil;
  632.     zbufptr := nil;
  633.     opaptr := nil;
  634.     brightcueptr := nil;
  635.     cuezbufptr := nil;
  636.     sumbufptr := nil;
  637.     countbufptr := nil;
  638.     AllocatingBuffers := true;
  639.     projsize := longint(projwidth) * longint(projheight);
  640.     projptr := NewPtr(projsize);
  641.     if projptr = nil then
  642.         Abort;
  643.     if (ProjectionMethod = NearestPoint) or (Opacity > 0) then begin    {get other required buffers}
  644.             zbufptr := IntPtr(NewPtr(projsize * 2));
  645.             if zbufptr = nil then
  646.                 Abort;
  647.         end;
  648.     if (Opacity > 0) and (ProjectionMethod <> NearestPoint) then begin
  649.             opaptr := NewPtr(projsize);
  650.             if opaptr = nil then
  651.                 Abort;
  652.         end;
  653.     if (ProjectionMethod = BrightestPoint) and (DepthCueInt < 100) then begin
  654.             brightcueptr := NewPtr(projsize);
  655.             cuezbufptr := IntPtr(NewPtr(projsize * 2));
  656.             if (brightcueptr = nil) or (cuezbufptr = nil) then
  657.                 abort;
  658.         end;
  659.     if (ProjectionMethod = MeanValue) then begin
  660.             sumbufptr := LongPtr(NewPtr(projsize * 4));
  661.             countbufptr := IntPtr(NewPtr(projsize * 2));
  662.             if (sumbufptr = nil) or (countbufptr = nil) then
  663.                 abort;
  664.         end;
  665.     AllocatingBuffers := false;
  666.     SaveProjectionsTemp := FALSE;              {check whether we have enough memory to open}
  667.     MemoryRequired := nProjections * projsize + SizeOf(PicInfo) + MinFree;
  668.     if (MemoryRequired > FreeMem) and not (SaveProjections) then begin
  669.             str := 'Insufficient memory to create entire stack of projections.  Projection images will be saved to disk.';
  670.             if (PutMessageWithCancel(str) = cancel) then
  671.                 Abort;
  672.             SaveProjections := TRUE;
  673.             SaveProjectionsTemp := TRUE;
  674.         end;
  675.     if (SaveProjections) then begin           {prepare to save projections as created if desired}
  676.             SaveAsWhat := AsTiff;
  677.             SaveAllState := SaveAllStage1;
  678.         end;
  679.     TimeStr := '?';
  680.     theta := InitAngle;                                     {begin rotation with user-specified angle}
  681.     ticksinit := TickCount;
  682.     for n := 1 to nProjections do begin
  683.             if (SaveProjections) or (n = 1) then begin    {open new window or stack slice}
  684.                     if SaveProjections then
  685.                         case AxisOfRotation of
  686.                             XAxis: 
  687.                                 str := StringOf('Projection X', theta : 4);
  688.                             YAxis: 
  689.                                 str := StringOf('Projection Y', theta : 4);
  690.                             ZAxis: 
  691.                                 str := StringOf('Projection Z', theta : 4);
  692.                         end
  693.                     else
  694.                         str := 'Projections';
  695.                     if not NewPicWindow(str, projwidth, projheight) then
  696.                         Abort;
  697.                 end
  698.             else if not (AddSlice(false)) then
  699.                 Abort;
  700.             str := StringOf('Projecting: ', n : 1, '/', nProjections : 1, ' (', Theta : 1, 'í', ', ', TimeStr, ')');
  701.             ShowMeter;
  702.             UpdateMeter(0, str);
  703.             thetarad := theta * pi / 180;
  704.             costheta := round(bigpowerof2 * cos(thetarad));
  705.             sintheta := round(bigpowerof2 * sin(thetarad));
  706.             p := projptr;                                          {initialize required projection buffers}
  707.             InitializeBuffer(p, projsize, 255, 1);
  708.             if (ProjectionMethod = NearestPoint) or (Opacity > 0) then begin
  709.                     zp := zbufptr;
  710.                     InitializeBuffer(Ptr(zp), projsize, 32767, 2);
  711.                 end;     {then}
  712.             if (Opacity > 0) and (ProjectionMethod <> NearestPoint) then begin
  713.                     op := opaptr;
  714.                     InitializeBuffer(op, projsize, 255, 1);
  715.                 end;     {then}
  716.             if (ProjectionMethod = MeanValue) then begin
  717.                     sp := sumbufptr;
  718.                     cp := countbufptr;
  719.                     InitializeBuffer(Ptr(sp), projsize, 0, 4);
  720.                     InitializeBuffer(Ptr(cp), projsize, 0, 2);
  721.                 end;
  722.             if (ProjectionMethod = BrightestPoint) and (DepthCueInt < 100) then begin
  723.                     bp := brightcueptr;
  724.                     InitializeBuffer(bp, projsize, 255, 1);
  725.                     qp := cuezbufptr;
  726.                     InitializeBuffer(Ptr(qp), projsize, 255, 2);
  727.                 end;     {then}
  728.             UpdateMeter(10, str);
  729.             DestInfo := Info;
  730.             Info := SourceInfo;
  731.             case AxisOfRotation of
  732.                 XAxis: 
  733.                     DoOneProjectionX(nSlices, ycenter, zcenter, projwidth, projheight, costheta, sintheta, projptr, opaptr, brightcueptr, zbufptr, cuezbufptr, countbufptr, sumbufptr, str);
  734.                 YAxis: 
  735.                     DoOneProjectionY(nSlices, xcenter, zcenter, projwidth, projheight, costheta, sintheta, projptr, opaptr, brightcueptr, zbufptr, cuezbufptr, countbufptr, sumbufptr, str);
  736.                 ZAxis: 
  737.                     DoOneProjectionZ(nSlices, xcenter, ycenter, zcenter, projwidth, projheight, costheta, sintheta, projptr, opaptr, brightcueptr, zbufptr, cuezbufptr, countbufptr, sumbufptr, str);
  738.             end;
  739.             Info := DestInfo;
  740.             if n = 1 then
  741.                 TicksForOneProjection := TickCount - TicksInit;
  742.             TicksToGo := round((nProjections - n) * TicksForOneProjection);
  743.             seconds := StringOf((TicksToGo div 60) mod 60 : 2);
  744.             if seconds[1] = ' ' then
  745.                 seconds[1] := '0';
  746.             timestr := StringOf(TicksToGo div 3600 : 1, ':', seconds);
  747.             if (ProjectionMethod = MeanValue) then begin
  748.                     p := projptr;                                    {calculate the mean-value image from returned info}
  749.                     sp := sumbufptr;
  750.                     cp := countbufptr;
  751.                     for offset := 0 to projsize - 1 do begin
  752.                             if (cp^ > 0) then
  753.                                 p^ := sp^ div cp^;
  754.                             p := ptr(ord4(p) + 1);
  755.                             sp := LongPtr(ord4(sp) + 4);
  756.                             cp := IntPtr(ord4(cp) + 2);
  757.                         end;     {for}
  758.                 end;     {then}
  759.             if (Opacity > 0) and (ProjectionMethod <> NearestPoint) then begin
  760.                     p := projptr;                                    {calculate surface proj component (opacity on)}
  761.                     op := opaptr;                                     {and combine with another proj component}
  762.                     for offset := 0 to projsize - 1 do begin
  763.                             p^ := (Opacity * BAND(op^, 255) + (100 - Opacity) * BAND(p^, 255)) div 100;
  764.                             p := ptr(ord4(p) + 1);
  765.                             op := ptr(ord4(op) + 1);
  766.                         end;     {for}
  767.                 end;     {then}
  768.             if (AxisOfRotation = ZAxis) then begin  {interpolate for z-axis rotation}
  769.                     p := ptr(ord4(projptr) + projwidth);
  770.                     for offset := projwidth to projsize - 1 - projwidth do begin
  771.                             curval := BAND(p^, 255);
  772.                             prevval := BAND(ptr(ord4(p) - 1)^, 255);
  773.                             nextval := BAND(ptr(ord4(p) + 1)^, 255);
  774.                             aboveval := BAND(ptr(ord4(p) - projwidth)^, 255);
  775.                             belowval := BAND(ptr(ord4(p) + projwidth)^, 255);
  776.                             if (curval = 255) and (prevval <> 255) and (nextval <> 255) and (aboveval <> 255) and (belowval <> 255) then
  777.                                 p^ := (prevval + nextval + aboveval + belowval) div 4;
  778.                             p := ptr(ord4(p) + 1);
  779.                         end;
  780.                 end;
  781.             if (SaveProjections) or (n = 1) then
  782.                 BlockMove(projptr, Info^.PicBaseAddr, projsize)         {whole ROI write to projection image}
  783.             else
  784.                 BlockMove(projptr, Info^.StackInfo^.PicBaseH[n]^, projsize);
  785.             UpdateMeter(-1, '');        {dispose of meter}
  786.             if cancelled then begin
  787.                     if n > 1 then
  788.                         DeleteSlice;
  789.                     leave;
  790.                 end;
  791.             if (SaveProjections) then begin
  792.                     SaveAs('', 0);                                    {just save and put away current image after creating it}
  793.                     ignore := CloseAWindow(info^.wptr);
  794.                 end
  795.             else if n = 1 then begin  {create new stack for first projection if not saving projections}
  796.                     if not MakeStackFromWindow then
  797.                         Abort
  798.                 end;
  799.             theta := (theta + AngleInc) mod 360;
  800.             UpdatePicWindow;
  801.         end;     {for}
  802.     SaveAllState := NoSaveAll;
  803.     if SaveProjectionsTemp then                 {turn this back off if we turned it on due to lack of memory}
  804.         SaveProjections := FALSE;
  805.     DisposeProjectionPtrs(projptr, opaptr, brightcueptr, zbufptr, countbufptr, cuezbufptr, sumbufptr);
  806.     SetPort(tPort);
  807.     DestInfo := info;
  808.     info := SourceInfo;
  809.     SelectSlice(info^.StackInfo^.CurrentSlice);
  810.     if AutoSelectAll then
  811.         KillRoi;
  812.     info := DestInfo;
  813. end;     {procedure DoProjection}
  814.  
  815.  
  816. {******************************************************************************}
  817. {*     This procedure allows the user to set parameters for projection in a large dialog box.                                  *}
  818. {******************************************************************************}
  819. procedure Project;
  820.     const
  821.         ProjectOptionsID = 128;
  822.         SliceIntervalID = 3;
  823.         InitAngleID = 4;
  824.         TotalAngleID = 5;
  825.         AngleIncID = 6;
  826.         TransparencyLowerID = 7;
  827.         TransparencyUpperID = 8;
  828.         OpacityID = 9;
  829.         DepthCueSurfID = 10;
  830.         DepthCueIntID = 11;
  831.         RotationAboutXID = 12;
  832.         RotationAboutYID = 13;
  833.         RotationAboutZID = 14;
  834.         SaveProjectionsID = 15;
  835.         MinProjSizeID = 16;
  836.         NearestID = 28;
  837.         BrightestID = 29;
  838.         MeanID = 30;
  839.     var
  840.         mylog: Dialogptr;                                           {pointer to dialog box}
  841.         i, item, alldone: integer;
  842.         SaveInitAngle, SaveTotalAngle, SaveAngleInc: integer;
  843.         SaveOpacity: integer;
  844.         SaveAxisOfRotation: AxisType;
  845.         SaveSaveProjections, SaveCloseSlices, SaveMinProjSize: Boolean;
  846.         PercentSurf, PercentInt: integer;
  847. begin
  848.     InitCursor;
  849.     SliceInterval := info^.StackInfo^.SliceSpacing;
  850.     if SliceInterval <= 0.0 then
  851.         SliceInterval := 1.0;
  852.     SaveInitAngle := InitAngle;
  853.     SaveTotalAngle := TotalAngle;
  854.     SaveAngleInc := AngleInc;
  855.     SaveOpacity := Opacity;
  856.     SaveAxisOfRotation := AxisOfRotation;
  857.     SaveSaveProjections := SaveProjections;
  858.     SaveMinProjSize := MinProjSize;
  859.     PercentSurf := 100 - DepthCueSurf;
  860.     PercentInt := 100 - DepthCueInt;
  861.     if DensitySlicing then
  862.         with info^ do begin
  863.                 lower := SliceStart;
  864.                 upper := SliceEnd;
  865.             end
  866.     else begin
  867.             lower := TransparencyLower;
  868.             upper := TransparencyUpper;
  869.         end;
  870.     mylog := GetNewDialog(ProjectOptionsID, nil, pointer(-1));
  871.     SetDReal(MyLog, SliceIntervalID, SliceInterval, 1);
  872.     SelIText(MyLog, SliceIntervalID, 0, 32767);
  873.     SetDNum(MyLog, InitAngleID, InitAngle);
  874.     SetDNum(MyLog, TotalAngleID, TotalAngle);
  875.     SetDNum(MyLog, AngleIncID, AngleInc);
  876.     SetDNum(MyLog, TransparencyLowerID, lower);
  877.     SetDNum(MyLog, TransparencyUpperID, upper);
  878.     SetDNum(MyLog, OpacityID, Opacity);
  879.     SetDNum(MyLog, DepthCueSurfID, PercentSurf);
  880.     SetDNum(MyLog, DepthCueIntID, PercentInt);
  881.     OutlineButton(MyLog, ok, 16);
  882.     SetDialogItem(MyLog, RotationAboutXID, ord(AxisOfRotation = XAxis));
  883.     SetDialogItem(MyLog, RotationAboutYID, ord(AxisOfRotation = YAxis));
  884.     SetDialogItem(MyLog, RotationAboutZID, ord(AxisOfRotation = ZAxis));
  885.     SetDialogItem(MyLog, NearestID, ord(ProjectionMethod = NearestPoint));
  886.     SetDialogItem(MyLog, BrightestID, ord(ProjectionMethod = BrightestPoint));
  887.     SetDialogItem(MyLog, MeanID, ord(ProjectionMethod = MeanValue));
  888.     SetDialogItem(MyLog, SaveProjectionsID, ord(SaveProjections));
  889.     SetDialogItem(MyLog, MinProjSizeID, ord(MinProjSize));
  890.     alldone := 0;
  891.     repeat  {if we don't do it this way, ModalDialog throws us into code checking after each keystroke}
  892.         repeat   {meaning you can't type in a 2 digit number}
  893.             ModalDialog(nil, item);
  894.             if item = SaveProjectionsID then begin
  895.                     SaveProjections := not SaveProjections;
  896.                     SetDialogItem(MyLog, SaveProjectionsID, ord(SaveProjections));
  897.                 end;
  898.             if item = MinProjSizeID then begin
  899.                     MinProjSize := not MinProjSize;
  900.                     SetDialogItem(MyLog, MinProjSizeID, ord(MinProjSize));
  901.                 end;
  902.             if (item = RotationAboutXID) or (item = RotationAboutYID) or (item = RotationAboutZID) then begin
  903.                     case item of
  904.                         RotationAboutXID: 
  905.                             AxisOfRotation := XAxis;
  906.                         RotationAboutYID: 
  907.                             AxisOfRotation := YAxis;
  908.                         RotationAboutZID: 
  909.                             AxisOfRotation := ZAxis;
  910.                     end;     {case}
  911.                     SetDialogItem(MyLog, RotationAboutXID, ord(AxisOfRotation = XAxis));
  912.                     SetDialogItem(MyLog, RotationAboutYID, ord(AxisOfRotation = YAxis));
  913.                     SetDialogItem(MyLog, RotationAboutZID, ord(AxisOfRotation = ZAxis));
  914.                 end;
  915.             if (item >= nearestID) and (item <= MeanID) then begin
  916.                     case item of
  917.                         NearestID: 
  918.                             ProjectionMethod := NearestPoint;
  919.                         BrightestID: 
  920.                             ProjectionMethod := BrightestPoint;
  921.                         MeanID: 
  922.                             ProjectionMethod := MeanValue;
  923.                     end;
  924.                     SetDialogItem(MyLog, NearestID, ord(projectionMethod = NearestPoint));
  925.                     SetDialogItem(MyLog, BrightestID, ord(projectionMethod = BrightestPoint));
  926.                     SetDialogItem(MyLog, MeanID, ord(projectionMethod = MeanValue));
  927.                 end;
  928.         until (item = ok) or (item = cancel);
  929.         alldone := 1;
  930.         if (item = ok) then begin  {check all the values that could have been entered, don't know which were changed}
  931.                 SliceInterval := GetDReal(MyLog, SliceIntervalID);
  932.                 if (SliceInterval <= 0.0) or (SliceInterval > 1023.0) then begin
  933.                         SliceInterval := info^.StackInfo^.SliceSpacing;
  934.                         SetDReal(MyLog, SliceIntervalID, SliceInterval, 1);
  935.                         beep;
  936.                         alldone := 0;
  937.                     end;  {if SliceInterval}
  938.                 InitAngle := GetDNum(MyLog, InitAngleID);
  939.                 if (InitAngle < 0) or (InitAngle > 360) then begin
  940.                         InitAngle := SaveInitAngle;
  941.                         SetDNum(MyLog, InitAngleID, InitAngle);
  942.                         beep;
  943.                         alldone := 0;
  944.                     end;  {if InitAngle}
  945.                 TotalAngle := GetDNum(MyLog, TotalAngleID);
  946.                 if (TotalAngle < 0) or (TotalAngle > 360) then begin
  947.                         TotalAngle := SaveTotalAngle;
  948.                         SetDNum(MyLog, TotalAngleID, TotalAngle);
  949.                         beep;
  950.                         alldone := 0;
  951.                     end;  {if TotalAngle}
  952.                 AngleInc := GetDNum(MyLog, AngleIncID);
  953.                 if (AngleInc < 0) or (AngleInc > 360) then begin
  954.                         AngleInc := SaveAngleInc;
  955.                         SetDNum(MyLog, AngleIncID, AngleInc);
  956.                         beep;
  957.                         alldone := 0;
  958.                     end;  {if AngleInc}
  959.                 lower := GetDNum(MyLog, TransparencyLowerID);
  960.                 if (lower < 0) or (lower > 255) then begin
  961.                         lower := TransparencyLower;
  962.                         SetDNum(MyLog, TransparencyLowerID, lower);
  963.                         beep;
  964.                         alldone := 0;
  965.                     end;  {if TransparencyLower}
  966.                 upper := GetDNum(MyLog, TransparencyUpperID);
  967.                 if (upper < 0) or (upper > 255) then begin
  968.                         upper := TransparencyUpper;
  969.                         SetDNum(MyLog, TransparencyUpperID, upper);
  970.                         beep;
  971.                         alldone := 0;
  972.                     end;  {if TransparencyUpper}
  973.                 Opacity := GetDNum(MyLog, OpacityID);
  974.                 if (Opacity < 0) or (Opacity > 100) then begin
  975.                         Opacity := SaveOpacity;
  976.                         SetDNum(MyLog, OpacityID, Opacity);
  977.                         beep;
  978.                         alldone := 0;
  979.                     end;  {if Opacity}
  980.                 PercentSurf := GetDNum(MyLog, DepthCueSurfID);
  981.                 if (PercentSurf < 0) or (PercentSurf > 100) then begin
  982.                         PercentSurf := 100 - DepthCueSurf;
  983.                         SetDNum(MyLog, DepthCueSurfID, PercentSurf);
  984.                         beep;
  985.                         alldone := 0;
  986.                     end;  {if DepthCueSurf}
  987.                 PercentInt := GetDNum(MyLog, DepthCueIntID);
  988.                 if (PercentInt < 0) or (PercentInt > 100) then begin
  989.                         PercentInt := 100 - DepthCueInt;
  990.                         SetDNum(MyLog, DepthCueIntID, PercentInt);
  991.                         beep;
  992.                         alldone := 0;
  993.                     end;  {if DepthCueInt}
  994.                 info^.StackInfo^.SliceSpacing := SliceInterval;
  995.             end;
  996.     until (alldone = 1);
  997.     DisposDialog(mylog);
  998.     if item = cancel then begin                       {if Cancel, keep the saved values}
  999.             InitAngle := SaveInitAngle;
  1000.             TotalAngle := SaveTotalAngle;
  1001.             AngleInc := SaveAngleInc;
  1002.             Opacity := SaveOpacity;
  1003.             AxisOfRotation := SaveAxisOfRotation;
  1004.             SaveProjections := SaveSaveProjections;
  1005.             MinProjSize := SaveMinProjSize;
  1006.         end
  1007.     else begin
  1008.             if not DensitySlicing then begin
  1009.                     TransparencyLower := lower;
  1010.                     TransparencyUpper := upper;
  1011.                 end;
  1012.             DepthCueSurf := 100 - PercentSurf;
  1013.             DepthCueInt := 100 - PercentInt;
  1014.             DoProjection;
  1015.         end;
  1016. end;
  1017.  
  1018.  
  1019. end.