; $Id: vert_t3d.pro,v 1.13 2004/01/21 15:55:04 scottm Exp $
;
; Copyright (c) 1994-2004, Research Systems, Inc.  All rights reserved.
;       Unauthorized reproduction prohibited.
;+
; NAME:
;       VERT_T3D
;
; PURPOSE:
;       This function tranforms 3-D points by a 4x4 transformation matrix.
;       The 3-D points are typically an array of polygon vertices that were
;       generated by SHADE_VOLUME or MESH_OBJ.
;
; CATEGORY:
;       Graphics.
;
; CALLING SEQUENCE:
;       result = VERT_T3D(vertex_list)
;
; INPUTS:
;       Vertex_List:
;               A 3 x n array of 3D coordinates to transform.
;
; KEYWORD PARAMETERS:
;
;	Double:
;		Set this keyword to a nonzero value to indicate that the
;		returned coordinates should be double precision.  If this
;		keyword is not set, the default is to return single
;		precision coordinates (unless double precision coordinates
;		are input, in which case the DOUBLE keyword is implied to
;		be non-zero).
;
;       Matrix:
;               The 4x4 transformation matrix to use. The default is to use
;               the system viewing matrix (!P.T). (See the "T3D" procedure). 
;
;       No_Copy:
;               Normally, a COPY of Vertex_List is transformed and the
;               original vertex_list is preserved. If No_Copy is set, however,
;               then the original Vertex_List will be undefined AFTER the call
;               to VERT_T3D. Using the No_Copy mode will require less memory.
;
;       No_Divide:
;               Normally, when a [x, y, z, 1] vector is transformed by a 4x4
;               matrix, the final homogeneous coordinates are obtained by
;               dividing the x, y, and z components of the result vector by
;               the fourth element in the result vector. Setting the No_Divide
;               keyword will prevent VERT_T3D from performing this division.
;               In some cases (usually when a perspective transformation is
;               involved) the fourth element in the result vector can be very
;               close to (or equal to) zero.
;
;       Save_Divide:
;               Set this keyword to a named variable to receive the fourth
;               element of the transformed vector(s). If Vertex_List is a
;               vector then Save_Divide is a scalar. If Vertex_List is a
;               [3, n] array then Save_Divide is an array of n elements.
;               This keyword only has effect when the No_Divide keyword is set.
;
; OUTPUTS:
;       This function returns the transformed coordinate(s). The returned
;       array has the same size and dimensions as Vertex_List.
;
; PROCEDURE:
;       Before performing the transformation, the [3, n] Vertex_List is padded
;       to produce a [4, n] array with 1's in the last column. After the
;       transformation, the first three columns of the array are divided by
;       the fourth column (unless the No_Divide keyword is set). The fourth
;       column is then stripped off (or saved in the Save_Divide keyword)
;       before returning.
;
; EXAMPLE:
;       Transform four points representing a square in the x-y plane by first
;       translating +2.0 in the positive X direction, and then rotating 60.0
;       degrees about the Y axis.
;
;               points = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], $
;                         [1.0, 1.0, 0.0], [0.0, 1.0, 0.0]]
;               T3d, /Reset
;               T3d, Translate=[2.0, 0.0, 0.0]
;               T3d, Rotate=[0.0, 60.0, 0.0]
;               points = VERT_T3D(points)
;
; MODIFICATION HISTORY:
;       Written by:     Daniel Carr, Thu Mar 31 15:58:07 MST 1994
;	DLD, April, 2000.  Update for double precision; add DOUBLE keyword.
;-

FUNCTION VERT_T3D, vertex_list, Double=do_double, $
                   Matrix=in_matrix, No_Copy=no_copy, $
                   No_Divide=no_divide, Save_Divide=save_divide

sz_vertex = Size(vertex_list)
n_verts = sz_vertex[2]

bDouble = KEYWORD_SET(do_double)
if (Size(vertex_list,/type) eq 5) then bDouble = 1

IF (N_Elements(in_matrix) LE 0L) THEN $
   matrix = !P.T $
ELSE $
   matrix=DOUBLE(in_matrix) 

IF (Keyword_Set(no_copy)) THEN BEGIN
   ret_list = Transpose( $
      Transpose([Temporary(vertex_list), Replicate(1.0, 1L, n_verts)]) # matrix)
ENDIF ELSE BEGIN
   ret_list = $
      Transpose(Transpose([vertex_list, Replicate(1.0, 1L, n_verts)]) # matrix)
ENDELSE

IF (Keyword_Set(no_divide)) THEN BEGIN
   save_divide = ret_list[3, *]
   IF (bDouble eq 0) THEN $
       RETURN, FLOAT([ret_list[0, *], ret_list[1, *], ret_list[2, *]]) $
   ELSE $
       RETURN, [ret_list[0, *], ret_list[1, *], ret_list[2, *]]
ENDIF ELSE BEGIN
   IF (bDouble eq 0) THEN $
       RETURN, FLOAT([(ret_list[0, *] / ret_list[3, *]), $
                      (ret_list[1, *] / ret_list[3, *]), $
                      (ret_list[2, *] / ret_list[3, *])])    $
   ELSE $
       RETURN, [(ret_list[0, *] / ret_list[3, *]), $
                (ret_list[1, *] / ret_list[3, *]), $
                (ret_list[2, *] / ret_list[3, *])]
ENDELSE

END
