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

#############################################################################
#
# Author: Anna Omelchenko
#
# Copyright: M. Sanner TSRI
#
#############################################################################

#
#$Header: /opt/cvs/Volume/Pvv/ZoomBox.py,v 1.4 2007/07/24 17:30:45 vareille Exp $
#
#$Id: ZoomBox.py,v 1.4 2007/07/24 17:30:45 vareille Exp $
#
from DejaVu.Box import Box
from DejaVu import viewerConst
from math import log
import numpy.oldnumeric as Numeric

from opengltk.OpenGL import GL
from opengltk.OpenGL.GLU import gluErrorString

coords=((1,1,-1),(-1,1,-1),(-1,-1,-1),(1,-1,-1),(1,1,1),(-1,1,1),(-1,-1,1),(1,-1,1))
materials=((0,0,1),(0,1,0),(0,0,1),(0,1,0),(1,0,0),(1,0,0),)


class ZoomBox:

    def __init__(self, viewer, volGeom):
        self.viewer = viewer
        self.box=Box('zoombox', materials=materials, vertices=coords,
                     inheritMaterial=0, listed=0)
        #self.box.RenderMode(GL.GL_LINE, face=GL.GL_FRONT)
        self.box.Set(visible=0, frontPolyMode='line')
        self.volGeom = volGeom
        size = volGeom.volumeSize
        self.xmin = 0 #bounds of zoom box
        self.xmax = size[0]
        self.ymin = 0
        self.ymax = size[1]
        self.zmin = 0
        self.zmax = size[2]
        self.dx = 0
        self.dy = 0
        self.dz = 0
        self.setVolSize(size)
        self.checkHasBox()
        self.callbackFunc = []
        self.setScale()
        c=self.viewer.currentCamera
        c.actions['Object']['boxScaleX'] = self.ScaleX
        c.actions['Object']['boxScaleY'] = self.ScaleY
        c.actions['Object']['boxScaleZ'] = self.ScaleZ
        c.actions['Object']['boxTransX'] = self.TranslationX
        c.actions['Object']['boxTransY'] = self.TranslationY
        c.actions['Object']['boxTransZ'] = self.TranslationZ
        c.actions['Object']['boxScaleAll'] = self.ScaleAll
        c.actions['Object']['boxTransAll'] = self.translateAll
        self.visible = 0
        self.cornerPoints = ()
        

    def checkHasBox(self):
        #check whether the box is  in root.children
        if self.box not in self.viewer.rootObject.children:
##              p1 = (self.xmin-self.xCen, self.ymin-self.yCen,
##                    self.zmin-self.zCen)
##              p2 = (self.xmax-self.xCen, self.ymax-self.yCen,
##                    self.zmax-self.zCen)
##              self.box.Set(cornerPoints = (p1, p2))
            self.viewer.AddObject(self.box, redo=0)


    def __repr__(self):
        return "<ZoomBox> (%d,%d,%d)  x(%d,%d) y(%d,%d) z(%d,%d)" % \
               (self.dx, self.dy, self.dz, self.xmin, self.xmax,
                self.ymin, self.ymax, self.zmin, self.zmax)


    def setVolSize(self, size):
        if len(size) == 3:
            self.volCorners = [-size[0]/2., -size[1]/2., -size[2]/2.,
                               size[0]/2., size[1]/2., size[2]/2.]
            self.volSize = size
        elif len(size) == 6:
            self.volCorners = size
            self.volSize = [int(size[3]-size[0]), int(size[4]-size[1]),
                            int(size[5]-size[2])]
##          self.xCen = size[0]/2.
##          self.yCen = size[1]/2.
##          self.zCen = size[2]/2.

    def setScale(self):
        vliscale = self.volGeom.vliScalemat
        boxscale = self.box.scale
        if vliscale:
            if vliscale[0][0] != boxscale[0] or \
               vliscale[1][1] != boxscale[1] or \
               vliscale[2][2] != boxscale[2]:
                self.box.SetScale((vliscale[0][0],vliscale[1][1],vliscale[2][2]))

    def update(self):
        self.dx = self.xmax - self.xmin
        self.dy = self.ymax - self.ymin
        self.dz = self.zmax - self.zmin
##          size = self.volSize
##          xCen = size[0]/2.
##          yCen = size[1]/2.
##          zCen = size[2]/2.
##          p1 = (self.xmin-xCen, self.ymin-yCen, self.zmin-zCen)
##          p2 = (self.xmax-xCen, self.ymax-yCen, self.zmax-zCen)
        vc = self.volCorners
        p1 = (vc[0]+self.xmin, vc[1]+self.ymin, vc[2]+self.zmin)
        p2 = (vc[0]+self.xmax, vc[1]+self.ymax, vc[2]+self.zmax)
        self.cornerPoints = (p1,p2)
        redo = 1
        self.box.Set(redo = redo, cornerPoints = (p1, p2))
        self.GLError()
        self.viewer.Redraw() 
        if self.visible:
            for f in self.callbackFunc:
                f(self)

    def GLError(self):
        err_count = 0
        while 1:
            errCode = GL.glGetError()
            if not errCode: return None
            errString = gluErrorString(errCode)
            print 'GL ERROR in zoombox update: %d %s' % (errCode, errString)
            if err_count > 10: break
            err_count = err_count+1
            #raise RuntimeError, 'in zoom box update'
        
    def ScaleX(self, event, matrix, transXY, transZ):
        if transZ<0: delta = 1
        else: delta = -1
        xmin = self.xmin+delta
        xmax = self.xmax-delta
        if xmin == xmax:
            xmax = xmin+1
        if xmin < 0 : xmin = 0
        if xmax > self.volSize[0]: xmax = self.volSize[0]
        if xmin > xmax : return
        self.xmin = xmin
        self.xmax = xmax
        self.update()


    def ScaleY(self, event, matrix, transXY, transZ):
        if transZ<0: delta = 1
        else: delta = -1
        ymin = self.ymin+delta
        ymax = self.ymax-delta
        if ymin == ymax:
            ymax = ymin+1
        if ymin < 0: ymin = 0
        if ymax > self.volSize[1]: ymax = self.volSize[1]
        if ymin > ymax : return
        self.ymin = ymin
        self.ymax = ymax
        self.update()


    def ScaleZ(self, event, matrix, transXY, transZ):
        if transZ<0: delta = 1
        else: delta = -1
        zmin = self.zmin+delta
        zmax = self.zmax-delta
        if zmin == zmax:
            zmax = zmin+1
        if zmin < 0: zmin = 0
        if zmax > self.volSize[2]: zmax = self.volSize[2]
        if zmin > zmax : return
        self.zmin = zmin
        self.zmax = zmax
        self.update()

       
    def ScaleAll(self, event, matrix, transXY, transZ):
        if transZ<0: delta = 1
        else: delta = -1
        xmin = self.xmin+delta
        xmax = self.xmax-delta
        if xmin == xmax:
            xmax = xmin+1
        if xmin < 0 : xmin = 0
        if xmax > self.volSize[0]: xmax =self.volSize[0]
        if xmin > xmax : return
        self.xmin = xmin
        self.xmax = xmax
        
        ymin = self.ymin+delta
        ymax = self.ymax-delta
        if ymin == ymax:
            ymax = ymin+1
        if ymin < 0: ymin = 0
        if ymax > self.volSize[1]: ymax = self.volSize[1]
        if ymin > ymax : return
        self.ymin = ymin
        self.ymax = ymax
        
        zmin = self.zmin+delta
        zmax = self.zmax-delta
        if zmin == zmax:
            zmax = zmin+1
        if zmin < 0: zmin = 0
        if zmax > self.volSize[2]: zmax = self.volSize[2]
        if zmin > zmax : return
        self.zmin = zmin
        self.zmax = zmax
        self.update()



    def TranslationX(self, event, matrix, transXY, transZ):
        if transZ>0: delta = 2
        else: delta = -2
        self.xmin = self.xmin+delta
        self.xmax = self.xmax+delta
        if self.xmin == self.xmax:
            self.xmax = self.xmin+1
        if self.xmin < 0 :
            self.xmax = self.xmax-self.xmin
            self.xmin = 0
        if self.xmax > self.volSize[0]:
            self.xmin = self.xmin - (self.xmax-self.volSize[0])
            self.xmax = self.volSize[0]
        self.update()

        
    def TranslationY(self, event, matrix, transXY, transZ):
        if transZ>0: delta = 2
        else: delta = -2
        self.ymin = self.ymin+delta
        self.ymax = self.ymax+delta
        if self.ymin == self.ymax:
            self.ymax = self.ymin+1
        if self.ymin < 0 :
            self.ymax = self.ymax-self.ymin
            self.ymin = 0
        if self.ymax > self.volSize[1]:
            self.ymin = self.ymin - (self.ymax-self.volSize[1])
            self.ymax = self.volSize[1]
        self.update()

    def TranslationZ(self, event, matrix, transXY, transZ):
        if transZ>0: delta = 2
        else: delta = -2
        self.zmin = self.zmin+delta
        self.zmax = self.zmax+delta
        if self.zmin == self.zmax:
            self.zmax = self.zmin+1
        if self.zmin < 0 :
            self.zmax = self.zmax-self.zmin
            self.zmin = 0
        if self.zmax > self.volSize[2]:
            self.zmin = self.zmin - (self.zmax-self.volSize[2])
            self.zmax = self.volSize[2]
        self.update()

    def translateAll(self,event, matrix, transXY, transZ):
        m = self.viewer.rootObject.GetMatrixInverse()
        for i in range(3):
            m[i][3] = 0
        v = [transXY[0],transXY[1],0,1]
        v = Numeric.reshape(Numeric.array(v),(4,1))
        t = Numeric.dot(m,v)
        t = [t[0][0], t[1][0], t[2][0]]
        scl = 0.25
        #print "t:"
        t1 = int(t[0]*scl)
        t2 = int(t[1]*scl)
        t3 = int(t[2]*scl)
        self.xmin = self.xmin + t1
        self.xmax = self.xmax + t1
        if self.xmin < 0 :
            self.xmax = self.xmax-self.xmin
            self.xmin = 0
        if self.xmax > self.volSize[0]:
            self.xmin = self.xmin - (self.xmax-self.volSize[0])
            self.xmax = self.volSize[0]
        self.ymin = self.ymin + t2
        self.ymax = self.ymax + t2
        if self.ymin < 0 :
            self.ymax = self.ymax-self.ymin
            self.ymin = 0
        if self.ymax > self.volSize[1]:
            self.ymin = self.ymin - (self.ymax-self.volSize[1])
            self.ymax = self.volSize[1]
        self.zmin = self.zmin + t3
        self.zmax = self.zmax + t3
        if self.zmin < 0 :
            self.zmax = self.zmax-self.zmin
            self.zmin = 0
        if self.zmax > self.volSize[2]:
            self.zmin = self.zmin - (self.zmax-self.volSize[2])
            self.zmax = self.volSize[2]
        
        self.update()

    def BindMouseToBoxScale(self):
        """Bind the trackball to the box"""
        c = self.viewer.currentCamera
        c.bindActionToMouseButton('boxScaleX', 1, 'Control')
        c.bindActionToMouseButton('boxScaleY', 2, 'Control')
        c.bindActionToMouseButton('boxScaleZ', 3, 'Control')
        c.bindActionToMouseButton('boxScaleAll', 3, 'Meta')

    def BindMouseToBoxTranslate(self):
        c = self.viewer.currentCamera
        c.bindActionToMouseButton('boxTransX', 1, 'Meta')
        c.bindActionToMouseButton('boxTransY', 2, 'Meta')
        c.bindActionToMouseButton('boxTransZ', 3, 'Meta')

    def BindMouseToBoxTransAll(self):
        c = self.viewer.currentCamera
        c.bindActionToMouseButton('boxTransAll', 1, 'Meta')
        c.bindActionToMouseButton('None', 2, 'Meta')
        c.bindActionToMouseButton('boxScaleAll', 3, 'Meta') 




    def setLineWidth(self, val):
        self.box.Set(lineWidth = val)
        self.box.RedoDisplayList()
        self.viewer.Redraw()


    def showBox(self, flag):
        if flag:
            self.box.Set(visible=1)
            self.visible = 1
        else:
            self.box.Set(visible=0)
            self.visible = 0
        self.viewer.Redraw()

    def resetBox(self):
        self.xmin = 0
        self.xmax = self.volSize[0]
        self.ymin = 0
        self.ymax = self.volSize[1]
        self.zmin = 0
        self.zmax = self.volSize[2]
        self.update()





