; $Id: davedat2d__cut.pro,v 1.8 2005/02/08 17:17:34 azuah Exp $
;###############################################################################
;
; CLASS NAME:
;   DaveDat2D
;
; PURPOSE:
;   This class encapsulates a DAVE formated dataset containing 2D
;   data.
;
; CATEGORY:
;   Data Browser
;
; SUPERCLASSES:
;   DaveDat
;
; PUBLIC METHODS:
;   Clone
;   Get
;   Print
;   Rebin
;   ResetData
;   Restore
;   Set
;   Transpose
;   XSpec
;
; AUTHOR:
;   Richard Tumanjong Azuah
;   NIST Center for Neutron Research
;   100 Bureau Drive, Gaithersburg, MD 20899
;   United States
;   azuah@nist.gov; (301) 9755604
;   Oct, 2002
;
; LICENSE:
;  The software in this file is written by an employee of 
;  National Institute of Standards and Technology 
;  as part of the DAVE software project.
;
;  The DAVE software package is not subject to copyright protection
;  and is in the public domain. It should be considered as an
;  experimental neutron scattering data reduction, visualization, and
;  analysis system. As such, the authors assume no responsibility
;  whatsoever for its use, and make no guarantees, expressed or
;  implied, about its quality, reliability, or any other
;  characteristic. The use of certain trade names or commercial
;  products does not imply any endorsement of a particular product,
;  nor does it imply that the named product is necessarily the best
;  product for the stated purpose. We would appreciate acknowledgment
;  if the DAVE software is used or if the code in this file is
;  included in another product.
;
;###############################################################################



;===============================================================================
; DaveDat2D::cut
;
; PURPOSE:
;   Take a cut/slice of the current object's data along the specified
;   axis.
;
; PARAMETERS:
;   axis [in] - (string) Is the axis (either 'x' or 'y') on which the
;               cut should be performed.
;
;   lolim [in] - (float) the lower limit (on the cut axis) of the cut
;                region.
;
;   uplim [in] - (float) the upper limit (on the cut axis) of the cut
;                region.
;
; KEYWORDS:
;
; RETURN VALUE
;   A NULL object, if unsuccessful
;   A new DaveDat1D object, if successful
;
function DaveDat2D::cut, axis, lolim, uplim

; reset !error_state structure, ie clear all errors
message,/reset

retFail = obj_new()


; ensure (required) number of parameters are present
if (n_params() ne 3) then begin
    !error_state.code = -1
    !error_state.msg = "DaveDat2D::cut: Inappropriate number of parameters"
    return, retFail
endif

; ensure axis is a string and set to 'x' or 'y'
if (vartype(axis) eq 'STRING') then begin
    if ((strupcase(axis) ne 'X') and (strupcase(axis) ne 'Y')) then begin
        !error_state.code = -1
        !error_state.msg = "DaveDat2D::cut: first parameter should be either 'X' or 'Y'"
        return, retFail
    endif
endif else begin
    !error_state.code = -1
    !error_state.msg = "DaveDat2D::cut: first parameter (cut axis) should be a string ('X' or 'Y')"
    return, retFail
endelse

; ensure lolim, hilim and binw have numeric type
if ((vartype(lolim) ne 'FLOAT') and $
    (vartype(lolim) ne 'DOUBLE') and $
    (vartype(lolim) ne 'INT') and $
    (vartype(lolim) ne 'LONG') ) then begin
    !error_state.code = -1
    !error_state.msg = "DaveDat2D::cut: second parameter (lolim) should be a number"
    return, retFail
endif
if ((vartype(uplim) ne 'FLOAT') and $
    (vartype(uplim) ne 'DOUBLE') and $
    (vartype(uplim) ne 'INT') and $
    (vartype(uplim) ne 'LONG') ) then begin
    !error_state.code = -1
    !error_state.msg = "DaveDat2D::cut: third parameter (uplim) should be a number"
    return, retFail
endif

; lolim and uplim should be scaler
lolim = float(lolim)
uplim = float(uplim)
if ((n_elements(lolim) ne 1) or (n_elements(uplim) ne 1)) then begin
    !error_state.code = -1
    !error_state.msg = "DaveDat2D::cut: second and third parameters should be (float) scalers"
    return, retFail
endif

; uplim must be greater than lolim
if (uplim le lolim) then begin
    !error_state.code = -1
    !error_state.msg = "DaveDat2D::cut: third (uplim) parameter must be > the second (lolim)"
    return, retFail
endif


; Get the data to be rebinned - depends on the axis 
switch strupcase(axis) of 
    'X': begin
        if (not self->get(xtype=type,xval=vin,zval=zin,zerr=zein)) then return, 0
        break
    end
    
    'Y': begin
        if (not self->get(ytype=type,yval=vin,zval=zin,zerr=zein)) then return, 0
        zin = transpose(zin)    ; transpose data so that y-axis data become the rows to be rebinned
        zein = transpose(zein)  ;
        break
    end
endswitch


;; determine output bins
;; output range must be within input range
nin = n_elements(vin)
lolim = lolim > vin[0]
uplim = uplim < vin[nin-1]
gap = uplim - lolim
;; do the rebinning
type_upcase = strupcase(strmid(type,0,4))

switch type_upcase of
    'HIST': begin
        vout = findgen(2)*gap + lolim 
        drebin,vin,zin,zein,vout,zout,zeout,/hist,/to_hist,err=err,emsg=emsg
        break
    end
    
    'POIN':
    else: begin                 ; default is points
        vout = findgen(3)*gap + lolim - 0.5*gap
        drebin,vin,zin,zein,vout,zout,zeout,/points,/to_points,err=err,emsg=emsg
        zout = zout[1,*]
        zeout = zeout[1,*]
        break
    end
endswitch
if (err ne 0) then begin
    !error_state.code = err
    !error_state.msg = emsg
    return, retFail
endif
;; reform the output to 1D since it is currently 2D ie 1 x N
zout = reform(zout)
zeout = reform(zeout)


;if (type_upcase ne 'HIST') then begin
;    ;; fake histogram mode data
;    vlast = 0.5*(3*vin[nin-1] - vin[nin-2])
;    for i=0,nin-2 do begin
;        vin[i] = 0.5*(3*vin[i] - vin[i+1])
;    endfor
;    vin = [vin,vlast]
;endif 
;drebin,vin,zin,zein,vout,zout,zeout,/hist,/to_hist,err=err,emsg=emsg
;if (err ne 0) then begin
;    !error_state.code = err
;    !error_state.msg = emsg
;    return, retFail
;endif;
;
;if (type_upcase ne 'HIST') then begin
;    ;; have to scale the output by the bin width
;    zout = zout*(vout[1] - vout[0])
;    zeout = zeout*(vout[1] - vout[0])
;endif







;; Grab additional information required to create the new 1D object
;; from the cut data
switch strupcase(axis) of 
    'X': begin
        if (not self->get(yval=xout,ytype=xtype,ylabel=xlabel,yunits=xunits, $
                          zlabel=zlabel,zunits=zunits,treatment=trmt,yDir=xDir $
                          ,scalefactor=sfactor,descriptr=dscPtr,daveptr=dPtr)) then return, 0
        break
    end
    
    'Y': begin
        if (not self->get(xval=xout,xtype=xtype,xlabel=xlabel,xunits=xunits, $
                          zlabel=zlabel,zunits=zunits,treatment=trmt,xDir=xDir $
                          ,scalefactor=sfactor,descriptr=dscPtr,daveptr=dPtr)) then return, 0
        break
    end
endswitch

;; add additional entry in treatment
line = '=================================================='
trmt = [trmt, $
        line, $
        'Perform a cut of the '+axis+'-axis',$
        'Integrating from '+axis+' = '+ $
        strtrim(string(lolim),2)+' to '+strtrim(string(uplim),2)]

;; modify the davePtr because some things should/might change in going
;; from the current object to the new 1D object

;(*(*dPtr).descriPtr) = (*dscPtr)
(*(*(*dPtr).dataStrPtr).commonStr.treatmentPtr) = trmt
(*(*(*dPtr).dataStrPtr).commonStr.histPtr) = {qty:zout, $
                                              err:zeout, $
                                              x:xout, $
                                              y:0.0}

(*(*dPtr).dataStrPtr).commonStr.xlabel = xlabel
(*(*dPtr).dataStrPtr).commonStr.xtype = xtype
(*(*dPtr).dataStrPtr).commonStr.xunits = xunits
(*(*dPtr).dataStrPtr).commonStr.histlabel = zlabel
(*(*dPtr).dataStrPtr).commonStr.histunits = zunits

;; create the 1D object from the davePtr
newObj = obj_new('davedat1d',davePtr=dPtr,scalefactor=sfactor)
if (not obj_valid(newObj)) then begin
    heap_free, dPtr
    ptr_free, dscPtr
    return, retFail
endif
if (not newObj->set(descriPtr=dscPtr,xDir=xDir)) then begin ; assign descriPtr to new object
    heap_free, dPtr
    ptr_free, dscPtr
    obj_destroy, newObj
    return, retFail
endif

;; cleanup 
heap_free, dPtr
ptr_free, dscPtr

return, newObj
end
;_______________________________________________________________________________
