## Automatically adapted for numpy.oldnumeric Jul 23, 2007 by 

#
#$Header: /opt/cvs/Volume/Pvv/getimageCommands.py,v 1.2 2007/07/24 17:30:45 vareille Exp $
#
#$Id: getimageCommands.py,v 1.2 2007/07/24 17:30:45 vareille Exp $
#

# Demo command. Connects to the Parallel Volume Rendering Server.
# Loads one of  two datasets ("vh_bone256.cnf", "iso_toga_hb.cnf")
# depending on data loaded in the viewer (brain.data, ct.data).

from ViewerFramework.VFCommand import Command, CommandGUI
from mglutil.gui.InputForm.Tk.gui import InputFormDescr
import numpy.oldnumeric as Numeric, thread
import Image, array, time
#from omniVolServ import CCV
import Tkinter,  Pmw
import sys, os
path = sys.exec_prefix
path1 = 'lib/python2.0/site-packages/omni/lib/sun4_sosV_5.7'
sys.path.insert(0, os.path.join(path, path1))
path2 = 'lib/python2.0/site-packages/omni/lib/python'
sys.path.insert(0, os.path.join(path, path2))
#sys.path.insert(0, '/tsri/python/sun4SunOS5/lib/python2.0/site-packages/omni/lib/sun4_sosV_5.7')
#sys.path.insert(0, '/tsri/python/sun4SunOS5/lib/python2.0/site-packages/omni/lib/python')
import CCV
from omniORB import CORBA

class GetImage(Command):
    def __init__(self, volGeom):
        Command.__init__(self)
        self.volGeom = volGeom
        self.vec = Numeric.array([0,0,1,0], 'f')
        self.up = Numeric.array([0,1,0,0], 'f')
        self.dist = 800.
        self.proj = 0 #0 - orthogonal, 1 - perspective
        self.mode = 4
        # 4:pvolserver.idl - render with transfer function
        # 3: ----- with material shapes + isocontouring
        # 2: ----- with material shapes
        self.isDisplayed=0
        self.imSizeX = Tkinter.StringVar()
        self.imSizeX.set('512')
        self.imSizeY = Tkinter.StringVar()
        self.imSizeY.set('512')
        self.winSizeX = Tkinter.StringVar()
        self.winSizeX.set('600')
        self.winSizeY = Tkinter.StringVar()
        self.winSizeY.set('600')
        
        self.idf = None
        self.sc = 16
        self.volserv = None

        self.ro_scale = None
        self.ro_rot = None
        self.ro_trans = None
        #congiguration files used by the server
        self.cnf_file = "vh_bone256.cnf"
        self.files = ["vh_bone256.cnf", "iso_toga_hb.cnf"]
        #self.files = ["vh_bone256.cnf", "test.cnf"]
        self.isSubvol = 1

        
    def __call__(self, **kw):
        pass

    def guiCallback(self):
        if not self.volGeom.volume: return
        if self.isDisplayed: return
        self.isDisplayed=1
        idf = self.idf = InputFormDescr(title="VolServer Image")
        ew = 6
        idf.append({'widgetType':Pmw.EntryField,
                    'name':'winsizex',
                    'wcfg':{'labelpos':'w',
                            'label_text':'Window size:',
                            'entry_width': ew,
                            'validate':'integer',
                            'entry_textvariable':self.winSizeX},
                    'gridcfg':{'column':0, 'sticky':'w'}})
        idf.append({'widgetType':Pmw.EntryField,
                    'name':'winsizey',
                    'wcfg':{'entry_width': ew,
                            'validate':'integer',
                            'entry_textvariable':self.winSizeY},
                    'gridcfg':{'column':1,'row':-1,'sticky':'w'}})
        idf.append({'widgetType':Pmw.EntryField,
                    'name':'imsizex',
                    'wcfg':{'labelpos':'w',
                            'label_text':'Image size:   ',
                            'entry_width': ew,
                            'validate':'integer',
                            'entry_textvariable':self.imSizeX},
                    'gridcfg':{'column':0,'sticky':'w'}})
        idf.append({'widgetType':Pmw.EntryField,
                    'name':'imsizey',
                    'wcfg':{'entry_width': ew,
                            'validate':'integer',
                            'entry_textvariable':self.imSizeY},
                    'gridcfg':{'column':1,'row':-1,'sticky':'w'}})

        idf.append({'widgetType':Tkinter.Button,
                    'wcfg':{'text': 'Restore transformation',
                            'relief' : Tkinter.RAISED,
                            'borderwidth' : 3,
                            'command':self.setTransformation},
                    'gridcfg':{'column':0,'columnspan': 2 },
                    })
        idf.append({'widgetType':Tkinter.Button,
                    'wcfg':{'text': 'Get Image',
                            'relief' : Tkinter.RAISED,
                            'borderwidth' : 3,
                            'command':self.getImage_cb},
                    'gridcfg':{'column':0,'columnspan': 2 },
                    })
        idf.append({'widgetType':Tkinter.Button,
                    'wcfg':{'text': 'Dismiss',
                            'relief' : Tkinter.RAISED,
                            'borderwidth' : 3,
                            'command':self.dismiss_cb},
                    'gridcfg':{'column':0, 'columnspan': 2},
                    })
        self.form = self.vf.getUserInput(idf, modal = 0, blocking=0)
        
        #self.doitWrapper()

    def onAddCmdToViewer(self):
        pass


    def dismiss_cb(self):
        self.idf.form.destroy()
        self.isDisplayed=0
        self.idf = None

    def getImage_cb(self):
        if self.vf.commands.has_key('vliTransfer'):
            if not self.vf.vliTransfer.tm:
                print "Need to specify transfer function"
                return
        else: return
        if self.volGeom.dataSource == 'dataptr':
            if self.vf.commands.has_key('vliZoom'):
                file = self.vf.vliZoom.datafile
                if file:
                    file = file.split('/')[-1]
                    if file == "brain.data":
                        # text file containing paths and data info to
                        # toga brain data set
                        #self.cnf_file = self.files[1]
                        cnf_file = self.files[1]
                        #both data used by the viewer and the server
                        # is 8 bit
                        self.sc = 1 
                    elif file == "ct.data":
                        # text file containing data info of the
                        # visible human data
                        # the data used by the server is 16 bit integers,
                        #the data used by the viewer is 8 bit.
                        #self.cnf_file = self.files[0]
                        cnf_file = self.files[0]
                        self.sc = 16
        else:
            cnf_file = "vh_bone256.cnf"
            self.sc = 16
        print "data file:", cnf_file
        self.doitWrapper(cnf_file)
        
    def doit(self, cnf_file):
        if not self.volGeom.volume:
            print "Volume is not loaded"
            return
        
        viewParam= self.getViewingParam()
        self.saveCurrentTransformation()
        light = self.getLightInfo()
        iso_val = self.getIsoVals()
        tf = self.getTransferFunction()
        if self.isSubvol:
            subvol = self.getSubvolume()
        else:
            subvol = None
        self.getImageFromServer(cnf_file, viewParam, light,tf,iso_val,subvol) 
##          thread.start_new_thread( self.getImageFromServer,
##                           (cnf_file, viewParam, light,tf,iso_val, subvol) )
        
    def getImageFromServer(self, cnf_file, viewParam, light, tf,
                           iso_val, subvol):
##          print "viewParam:", viewParam
##          print "light:", light
##          print "args:", args
##          print "Initialising the ORB"
        if not self.volserv or cnf_file != self.cnf_file:
            orb = CORBA.ORB_init([" "], CORBA.ORB_ID)

            # get initial reference from a file
            str_ior = open("volren.ref", "r").read()
            obj = orb.string_to_object(str_ior)
            self.volserv = obj._narrow(CCV.PVolServer)
            if self.volserv is None:
                print "Object reference is not an CCV::PVolserver"
                sys.exit(1)
            # load dataset
            print "loading data:", cnf_file
            self.volserv.loadData(cnf_file)
            self.cnf_file = cnf_file
            self.orb = orb

        light_info = self.volserv.getLight(0)
        i = 0
        for l in light:
            light_info.vx = l[0]
            light_info.vy = l[1]
            light_info.vz = l[2]
            if i == 0:
                self.volserv.setLight(light_info, 0)
            elif i>0:
                self.volserv.addLight(light_info)
            i = i+1
            print "Light n %d: color: %d, %d, %d; direct: %f, %f, %f\n" % \
                  (i, light_info.red, light_info.green, light_info.blue,
                   light_info.vx, light_info.vy, light_info.vz)

        # set parameters
        persp = self.proj
        fov = 45.0

        #ws = [600, 600]
        #ims = [512, 512]
        ws = [int(self.winSizeX.get()), int(self.winSizeY.get())]
        ims = [int(self.imSizeX.get()), int(self.imSizeY.get())]
    
        filename = "serv_image.jpg"
    
        myparam = CCV.ViewParam(persp, fov, viewParam[0], viewParam[1],
                                viewParam[2])
        self.volserv.setViewParam(myparam)
        #self.volserv.setViewField(viewField)
        mode = self.mode
        #mode = 1
        if iso_val:
           mode = 3
           isocon = self.volserv.getContourInfo(0)
           i = 0
           for iv in iso_val:
               isocon.val = iv[0]
               isocon.opacity = iv[1]
               isocon.dr = iv[2]
               isocon.dg = iv[3]
               isocon.db = iv[4]
               isocon.sr = iv[2]/2
               isocon.sg = iv[3]/2
               isocon.sb = iv[4]/2
               isocon.cflag = 0
               print "isocon_info: val: %d, a: %.2f"%\
                     (isocon.val, isocon.opacity)
               print "ar: %d, ag: %d, ab: %d"% \
                     (isocon.ar, isocon.ag, isocon.ab)
               print "dr: %d, dg: %d, db: %d"% \
                     (isocon.dr, isocon.dg, isocon.db)
               print "sr: %d, sg: %d, sb: %d"% \
                     (isocon.sr, isocon.sg, isocon.sb)
               if i == 0:
                   self.volserv.setContourInfo(isocon, 0)
               elif i > 0:
                   self.volserv.addContour(isocon)
               i = i+1
               
        print "rendering mode:", mode , "(1-RAYT, 3-RAYT+ISOC)"
        self.volserv.setRenderingMode(mode)
        
        print "setting tf..."
        if tf:
            TF = []
            for e in tf:
                v,r,g,b,a = e    
                TF.append(CCV.DenMaterial(v,r,g,b,a))
            self.volserv.setDenTransfer(TF)

        self.volserv.setWindowSize(ws)
        self.volserv.setImageSize(ims)
    
        #get window size
        win = self.volserv.getWindowSize()
        print "window size: %d %d" % (win[0], win[1])
        
        if subvol:
            ox,oy,oz,dx,dy,dz = subvol
            sv = CCV.SubVolume(ox,oy,oz,dx,dy,dz)
            self.volserv.setSubVolume(sv)
    
        # get the image of volume rendering
        print "rendering ..."
        t1=time.time()
        image = self.volserv.render()
        t2 = time.time()
        print "render time: ", t2-t1
    
        # output the image to a file
        dx = image.dx
        dy = image.dy
        res = image.res
        image_len = len(image.img)
        image_size = dx*dy*res
        print "image size : %d, %d" % (image_len, image_size)
        print "dx: %d, dy: %d, res: %d" % (dx, dy, res)
    
        im = Image.fromstring("RGB", (dx,dy), image.img)
        im.save(filename)
        master = self.vf.GUI.ROOT
        text = "Image is created. (%s)" % filename
        dialog = Pmw.MessageDialog(master, title="Image",
                                   buttons=('OK', 'Show image'),
                                   defaultbutton='OK',
                                   message_text=text)
        res = dialog.activate()
        print res
        print " "
        if res == 'Show image':
            im.show()
        return 0

    def saveCurrentTransformation(self):
        ro = self.vf.GUI.VIEWER.rootObject
        self.ro_scale = ro.scale
        self.ro_rot = ro.rotation
        self.ro_trans = ro.translation

    def setTransformation(self):
        vi = self.vf.GUI.VIEWER
        ro = vi.rootObject
        if self.ro_scale == None or self.ro_rot ==None or self.ro_trans==None:
            return
        ro.SetScale(self.ro_scale)
        ro.SetRotation(self.ro_rot)
        ro.SetTranslation(self.ro_trans)
        vi.Redraw()
        
    def getViewingParam(self):
        vi = self.vf.GUI.VIEWER
        root = vi.rootObject
        rotmat = Numeric.reshape(root.rotation, (4,4))
        newvec = Numeric.dot(rotmat, self.vec)[:3]
        newpos = (newvec*self.dist).tolist()
        newvec = newvec.tolist()
        newup = Numeric.dot(rotmat, self.up)[:3].tolist()
        print "pos = ", newpos
        print "vec = ", newvec
        print "up = ", newup
        return  (newpos, newvec, newup)

    def getTransferFunction(self):
        
        if self.vf.commands.has_key('vliTransfer'):
            vals, alphas, rgb = self.vf.vliTransfer.tm.getTransferFunc()
            if len(vals) == 0:
                return None
            tf= []
            k = 255/4095.
            sc = self.sc
            if self.vf.Transfer.tm.xmaxval > 255:
                sc = 1
            for i in range(len(vals)):
            #for i in range( min(10,len(vals)) ):
                v = vals[i]*sc
                a = int(round(alphas[i]*k))
                r = int(rgb[i][0]*255)
                g = int(rgb[i][1]*255)
                b = int(rgb[i][2]*255)
                #tf.append(CCV.DenMaterial(v,r,g,b,a))
                tf.append([v,r,g,b,a])
                print "tf_vrgba:", v, r,g,b,a 
            return tf
        else:
            return None

    def getIsoVals(self):
        if self.vf.commands.has_key('vliTransfer'):
            iso_vals= self.vf.vliTransfer.tm.getIsoVals()
            if len(iso_vals) == 0: return None
            iv = []
            sc = self.sc
            if self.vf.Transfer.tm.xmaxval > 255:
                sc = 1
            for val in iso_vals:
                v = val['val']*sc
                a = val['alpha']/4095.
                r = int(val['rgb'][0]*255)
                g = int(val['rgb'][1]*255)
                b = int(val['rgb'][2]*255)
                print "iso_vargb:", v,a,r,g,b
                iv.append((v,a,r,g,b))
            
            return iv
        else: return None
            

    def getLightInfo(self):
        vi = self.vf.GUI.VIEWER
        dirs = []
        for l in vi.lights:
            if l.enabled:
                dirs.append((l.direction*(-1))[:3])
        return dirs
        
    def getSubvolume(self):
        if self.volGeom.dataSource == 'dataptr':
            if self.vf.commands.has_key('vliZoom'):
                if not self.vf.vliZoom.datafile: return None
                resol = self.vf.vliZoom.resol
                bounds = self.vf.vliZoom.bounds_dict[resol]
                if self.cnf_file == self.files[1]: # Toga Brain
                    resol = resol/4.
                cropBox = self.volGeom.cropBox
                xmin = cropBox.xmin
                ymin = cropBox.ymin
                zmin = cropBox.zmin
                dx = cropBox.dx
                dy = cropBox.dy
                dz = cropBox.dz
                subvol = ((bounds[0]+xmin)*resol,
                          (bounds[2]+ymin)*resol,
                          (bounds[4]+zmin)*resol,
                          dx*resol, dy*resol, dz*resol)
                print "subvolume:" , subvol
                return subvol
        else:
            return None
        
           


commandGUI = CommandGUI()
menuName = 'Get Image'
menuIndex = 15
commandNames = {'vli': 'GetImage', 'utvolren': None}

commandList = [{'name':'', 'cmd': None, 'gui': None}]


def initModule(viewer):
    for dict in commandList:
        if dict['name']:
            viewer.addCommand(dict['cmd'], dict['name'], dict['gui'])



