Location: Stomach Annotator for SPARC @ 9ea33dda840d / gui / annotator.py

Author:
rjag008 <rjag008@auckland.ac.nz>
Date:
2018-08-18 17:01:42+12:00
Desc:
Final Release
Permanent Source URI:
https://models.cellml.org/workspace/51d/rawfile/9ea33dda840d259caf68e26d21300bece4eeff3f/gui/annotator.py

'''
Created on 14/06/2018

@author: rjag008
'''
import numpy as np
from os import path
import os,sys,shutil,json
from opencmiss.zinc.context import Context
from opencmiss.zinc.glyph import Glyph
from opencmiss.zinc._graphics import Graphicslineattributes_SHAPE_TYPE_CIRCLE_EXTRUSION
from digitiser.qtdigitiser import PainterWidget
from digitiser.zincwidgets import SceneViewerWidget, ZincPainterWidget
from digitiser.mapping import MeshMapper

dir_path = path.dirname(path.realpath(sys.argv[0]))
if not hasattr(sys, 'frozen'): #For py2exe
    dir_path = path.join(dir_path,"..")
    
uiFile = path.join(dir_path,"./gui/stomachannotator.ui")

projectDetailsUi = path.join(dir_path,"./gui/projectdetails.ui")

projectDetailsEditUi = path.join(dir_path,"./gui/projectdetailsEdit.ui")

try:
    from PySide import  QtGui
    from PySide.QtGui import QApplication
    from PySide import QtCore, QtOpenGL
    from pysideuiutils.uic import loadUi
    from PySide import QtGui, QtWebKit
    
    signalHandle = QtCore.Signal
    
    class ProjectDetailsWindowBase(QtGui.QDialog):
        def __init__(self, parent=None):
            super(ProjectDetailsWindowBase, self).__init__(parent)
            loadUi(projectDetailsUi, self)            
    
    class ProjectDetailsEditWindowBase(QtGui.QDialog):
        def __init__(self, parent=None):
            super(ProjectDetailsEditWindowBase, self).__init__(parent)
            loadUi(projectDetailsEditUi, self)            

    class ApplicationWindowBase(QtGui.QMainWindow):
        def __init__(self, parent=None):
            super(ApplicationWindowBase, self).__init__(parent)
            loadUi(uiFile, self)
            self.projectOpened = False
            
        def closeEvent(self,event):
            if self.projectOpened:
                reply = QtGui.QMessageBox.question(self,"Unsaved new project"," The new project has not been saved! Do you wish to exit anyway?", QtGui.QMessageBox.Yes|QtGui.QMessageBox.No)
                if reply == QtGui.QMessageBox.No:
                    event.ignore()
                    return
            return QtGui.QMainWindow.closeEvent(self, event)
    
    
except ImportError:
    #from PyQt4 import QtGui, QtCore, uic
    #from PyQt4.QtGui import QApplication
    #from PyQt4 import  QtGui, QtWebKit
    #signalHandle = QtCore.pyqtSignal

    '''
    form,base = uic.loadUiType(uiFile)
    class ApplicationWindowBase(base,form):
        def __init__(self,parent=None):
            super(base,self).__init__(parent)
            self.setupUi(self)
    '''
    pass



class MainModelController(object):
    
    def __init__(self,appwidget):
        self.appWidget = appwidget
        self.context = appwidget.zincContext
        self.rootRegion = self.context.getDefaultRegion()
        self.pointTypeGraphics = dict()
        self.appWidget.mainModelInitialized.connect(self.linkToSceneViewer)
        self.appWidget.textureChanged.connect(self.setTexture)
        
    def loadMesh(self,meshString):
        region = self.rootRegion.findChildByName('stomach')
        if region.isValid():
            self.rootRegion.removeChild(region)
        region = self.rootRegion.createChild('stomach')
        sir  = region.createStreaminformationRegion()
        sir.createStreamresourceMemoryBuffer(str(meshString)) 
        region.read(sir)
        self.mesh = meshString
        self.region = region
        #Create a dict of elements
        self.elements = dict()
        fieldModule = self.region.getFieldmodule()
        mesh = fieldModule.findMeshByDimension(3)
        ei   = mesh.createElementiterator()
        elem = ei.next()
        while elem.isValid():
            self.elements[int(elem.getIdentifier())] = elem
            elem = ei.next()
        if len(self.elements) == 0: #A 2d mesh
            mesh = fieldModule.findMeshByDimension(2)
            ei   = mesh.createElementiterator()
            elem = ei.next()
            while elem.isValid():
                self.elements[int(elem.getIdentifier())] = elem
                elem = ei.next()
        
        #Create the texture coordinates
        self.createTextureCoordinates()
        #Create the scene filter and set the app's sceneview to use it
        sceneFilterModule = self.context.getScenefiltermodule()        
        self.sceneFilter = sceneFilterModule.createScenefilterRegion(region)
        
    def linkToSceneViewer(self):
        if hasattr(self, 'sceneFilter') and self.sceneFilter.isValid():
            self.appWidget.getMainModelSceneViewer().setScenefilter(self.sceneFilter)
        
        
    def createTextureCoordinates(self,circumferentialElements=8,lengthElements=11,wallElements=3):
        fieldModule = self.region.getFieldmodule()
        coordinates = fieldModule.findFieldByName('coordinates')
        cylindericalCoordinates = fieldModule.findFieldByName('cylindericalCoordinates')
        
        #Theta does not change monotonically, ensure this
        xiCoordinates = fieldModule.createFieldCoordinateTransformation (cylindericalCoordinates)
        xiCoordinates.setCoordinateSystemType(coordinates.COORDINATE_SYSTEM_TYPE_CYLINDRICAL_POLAR)

        
        r = fieldModule.createFieldComponent(xiCoordinates, 1)
        theta = fieldModule.createFieldComponent(xiCoordinates, 2)
        wi = fieldModule.createFieldComponent(xiCoordinates, 3)
        zero = fieldModule.createFieldConstant(0.0)
        one  = fieldModule.createFieldConstant(1.0)
        theta_lt_zero = fieldModule.createFieldLessThan(theta, zero)
        twopi = fieldModule.createFieldConstant(np.pi*2)
        mod_theta = fieldModule.createFieldIf(theta_lt_zero, fieldModule.createFieldAdd(theta, twopi), theta)
        vi = fieldModule.createFieldDivide(mod_theta, twopi)
        w = fieldModule.createFieldSubtract(one,wi)
        #Ensure node 1 is at 0.0
        one25  = fieldModule.createFieldConstant(0.125)
        vx = fieldModule.createFieldSubtract(vi,one25)
        v = fieldModule.createFieldSubtract(one,vx)
        self.xiCoordinates = fieldModule.createFieldConcatenate([v, w, r])
        '''
        nodeset = fieldModule.findNodesetByFieldDomainType(coordinates.DOMAIN_TYPE_NODES)
        nodeIterator = nodeset.createNodeiterator ()
        nodes = dict()
        node = nodeIterator.next()
        while node.isValid():
            nodes[int(node.getIdentifier())] = node
            node = nodeIterator.next()
        fieldCache = fieldModule.createFieldcache()
        for nd,node in nodes.items():
            fieldCache.setNode(node)
            _,coord = coordinates.evaluateReal(fieldCache,3)
            _,th = self.xiCoordinates.evaluateReal(fieldCache,3)
            print nd,' '.join(map(str,coord)),' '.join(map(str,th))
        '''    
        

    def setTexture(self,imageFile):
        fieldModule = self.region.getFieldmodule()
        image_field = fieldModule.createFieldImage()
        image_field.setFilterMode(image_field.FILTER_MODE_LINEAR)
        image_field.setWrapMode(image_field.WRAP_MODE_EDGE_CLAMP)
        coordinates = fieldModule.findFieldByName('coordinates')
        image_field.setDomainField(coordinates)
        image_field.setTextureCoordinateSizes([1, 1])
        # Create a stream information object that we can use to read the
        # image file from disk
        stream_information = image_field.createStreaminformationImage()
        stream_information.createStreamresourceFile(imageFile)
        image_field.read(stream_information)
        scene = self.region.getScene()
        textureMaterial = scene.getMaterialmodule().createMaterial()
        textureMaterial.setManaged(True)
        textureMaterial.setName("regionMap")
        textureMaterial.setTextureField(1, image_field)
        #textureMaterial.setAttributeReal(Material.ATTRIBUTE_ALPHA, 0.2)
        
        if hasattr(self, 'textureMaterial'):
            del self.textureMaterial
        self.textureMaterial = textureMaterial
        if hasattr(self, 'surfaceGraphics'):
            self.surfaceGraphics.setMaterial(self.textureMaterial)

    
    def showGraphics(self):
        scene = self.region.getScene()
        #Show nodes
        # We use the beginChange and endChange to wrap any immediate changes and will
        # streamline the rendering of the scene.
        scene.beginChange()
        # createSurfaceGraphic graphic start
        fieldModule = self.region.getFieldmodule()
        coordinateField = fieldModule.findFieldByName('coordinates')
        #Create necessary fields
        nodeAnnotationField = fieldModule.findFieldByName('nodeAnnotation')
        if not nodeAnnotationField.isValid():
            nodeAnnotationField = fieldModule.createFieldStoredString()
            nodeAnnotationField.setName('nodeAnnotation')
        self.nodeAnnotationField = nodeAnnotationField

        nodeVisibilityFlagField = fieldModule.findFieldByName('nodeVisibilityFlag')
        if not nodeVisibilityFlagField.isValid():
            nodeVisibilityFlagField = fieldModule.createFieldFiniteElement(1)
            nodeVisibilityFlagField.setName('nodeVisibilityFlag')           
        self.nodeVisibilityFlagField = nodeVisibilityFlagField
        
        nodeSizeField = fieldModule.findFieldByName('nodeSizeField')
        if not nodeSizeField.isValid():
            nodeSizeField = fieldModule.createFieldFiniteElement(9)
            nodeSizeField.setName('nodeSizeField')           
        self.nodeSizeField = nodeSizeField
        
        nodeColorField = fieldModule.findFieldByName('nodeColor')
        if not nodeColorField.isValid():
            nodeColorField = fieldModule.createFieldFiniteElement(3)
            nodeColorField.setName('nodeColor')
        self.nodeColorField = nodeColorField        
        
        self.datanodeset = fieldModule.findNodesetByFieldDomainType(self.xiCoordinates.DOMAIN_TYPE_DATAPOINTS)
        self.fieldCache = fieldModule.createFieldcache()
        self.coordinatesField = fieldModule.findFieldByName('coordinates').castFiniteElement()
        self.nodetemplate = self.datanodeset.createNodetemplate()
        self.nodetemplate.defineField(self.coordinatesField)
        self.nodetemplate.defineField(self.nodeAnnotationField)
        self.nodetemplate.defineField(self.nodeVisibilityFlagField)
        self.nodetemplate.defineField(self.nodeSizeField)
        self.nodetemplate.defineField(self.nodeColorField)

        glyphModule = scene.getGlyphmodule()
        glyphModule.defineStandardGlyphs() 
        glyphModule.beginChange()
        axisGlyph = glyphModule.findGlyphByGlyphShapeType(Glyph.SHAPE_TYPE_AXES_SOLID_XYZ) 
        glyphModule.endChange()
        
        '''
        graphics1 = scene.createGraphicsPoints()
        graphics1.setFieldDomainType(self.coordinatesField.DOMAIN_TYPE_MESH_HIGHEST_DIMENSION)
        graphics1.setCoordinateField(coordinateField)
        gpa1 = graphics1.getGraphicspointattributes()
        cmiss_number = fieldModule.findFieldByName('cmiss_number')
        gpa1.setLabelField(cmiss_number)
        gpa1.setGlyphShapeType(Glyph.SHAPE_TYPE_NONE)
        '''
        
        '''
        graphics = scene.findGraphicsByName("axis")
        if graphics.isValid():
            scene.removeGraphics(graphics)
        graphics = scene.createGraphicsPoints()
        graphics.setName("axis")
        graphics.setScenecoordinatesystem(SCENECOORDINATESYSTEM_NORMALISED_WINDOW_FIT_BOTTOM)
        pointattributes = graphics.getGraphicspointattributes()
        pointattributes.setGlyph(axisGlyph)
        pointattributes.setBaseSize([0.1,0.1,0.1])
        #pointattributes.setGlyphOffset([-0.9,0.0,0.0])
        '''
        materialModule = scene.getMaterialmodule ()
        materialModule.defineStandardMaterials ()
        surfaceMaterial = materialModule.findMaterialByName('gold')
        lineMaterial = materialModule.findMaterialByName('silver')
        # Create Surface
        
        self.surfaceGraphics = scene.createGraphicsSurfaces()
        self.surfaceGraphics.setCoordinateField(coordinateField)
        self.surfaceGraphics.setTextureCoordinateField(self.xiCoordinates)
        self.surfaceGraphics.setMaterial(surfaceMaterial)
        
        #Create lines
        self.surfaceLines = scene.createGraphicsLines()
        self.surfaceLines.setCoordinateField(coordinateField)
        lineattributes = self.surfaceLines.getGraphicslineattributes()
        lineattributes.setShapeType(Graphicslineattributes_SHAPE_TYPE_CIRCLE_EXTRUSION)
        lineattributes.setBaseSize([0.01,0.01,0.01])
        self.surfaceLines.setMaterial(lineMaterial)
        
        #Create spectrum to pick up rgb from nodeColor Field
        spectrumModule = scene.getSpectrummodule()
        spectrum = spectrumModule.createSpectrum()
        spectrum.setMaterialOverwrite(True) #This will ensure that the transparency of the material is used
        spectrum.setName("RGB")
        spectrumR = spectrum.createSpectrumcomponent()
        spectrumR.setColourMappingType(spectrumR.COLOUR_MAPPING_TYPE_RED)
        spectrumR.setFieldComponent(1)
        spectrumG = spectrum.createSpectrumcomponent()
        spectrumG.setColourMappingType(spectrumR.COLOUR_MAPPING_TYPE_GREEN)
        spectrumG.setFieldComponent(2)
        spectrumB = spectrum.createSpectrumcomponent()
        spectrumB.setColourMappingType(spectrumR.COLOUR_MAPPING_TYPE_BLUE)
        spectrumB.setFieldComponent(3)
        for spec in [spectrumR,spectrumG,spectrumB]:
            spec.setRangeMinimum(0.0)
            spec.setRangeMaximum(1.0)        
            spec.setColourMinimum(0.0)
            spec.setColourMaximum(1.0)
            spec.setExtendBelow(True)
            spec.setExtendAbove(True)
        self.spectrumR = spectrumR
        self.spectrumB = spectrumB
        self.spectrumG = spectrumG
        self.spectrum = spectrum
        #Code for rendering datapoints
        graphics = scene.createGraphicsPoints()
        graphics.setFieldDomainType(self.coordinatesField.DOMAIN_TYPE_DATAPOINTS)
        graphics.setCoordinateField(coordinateField)
        graphics.setSubgroupField(self.nodeVisibilityFlagField)
        graphics.setDataField(self.nodeColorField)
        
        gpa = graphics.getGraphicspointattributes()
        gpa.setGlyphShapeType(Glyph.SHAPE_TYPE_SPHERE)
        gpa.setOrientationScaleField(self.nodeSizeField)
        graphics.setSpectrum(spectrum)
        
        
        scene.endChange()
        
    def showDataPoints(self,listofpoints):
        fieldModule = self.region.getFieldmodule()
        fieldModule.beginChange()
        self.datanodeset.destroyAllNodes()
        self.dataNodeGroups = dict()
        for nd,v in listofpoints.items():
            mloc = [1.0-v[1][0],1.0-v[1][1]] #Xi needs to be inverted to match
            self.fieldCache.setMeshLocation(self.elements[v[0]],mloc)
            _,c = self.coordinatesField.evaluateReal(self.fieldCache,3)
            node = self.datanodeset.createNode(nd, self.nodetemplate)
            self.fieldCache.setNode(node)
            self.nodeAnnotationField.assignString(self.fieldCache,v[2])
            self.nodeVisibilityFlagField.assignReal(self.fieldCache,v[3])
            self.nodeSizeField.assignReal(self.fieldCache,v[4])
            self.nodeColorField.assignReal(self.fieldCache,v[5])
            self.coordinatesField.assignReal(self.fieldCache,c)
            if v[2] in self.dataNodeGroups:
                self.dataNodeGroups[v[2]].append(node)
            else:
                self.dataNodeGroups[v[2]] = [node]
        fieldModule.endChange()


class ProjectDetailsWindow(ProjectDetailsWindowBase):
    
    datacollected = signalHandle(object)
    userCancelled = signalHandle()
    
    def __init__(self,parent=None,title="New Project"):
        super(ProjectDetailsWindow,self).__init__(parent)
        self.searchProjectFolder.clicked.connect(self.searchForAProjectFolder)
        #self.searchMeshFile.clicked.connect(self.searchForMeshFile)
        #self.choose.toggled.connect(self.enableUserMesh)
        self.Ok.clicked.connect(self.okclicked)
        self.cancel.clicked.connect(self.cancelclicked)
        self.setModal(True)
        self.setWindowTitle(title)
        self.screenCenterDialog()

    def screenCenterDialog(self):
        frameGm = self.frameGeometry()
        screen = QtGui.QApplication.desktop().screenNumber(QtGui.QApplication.desktop().cursor().pos())
        centerPoint = QtGui.QApplication.desktop().screenGeometry(screen).center()
        frameGm.moveCenter(centerPoint)
        self.move(frameGm.topLeft())
        
    def searchForAProjectFolder(self):
        filename = QtGui.QFileDialog.getExistingDirectory(self,'Project folder', '')
        
        if isinstance(filename,tuple): #Handle pyside
            filename = str(filename[0])        
        if filename is not None and not str(filename) == "":
            self.projectFolder.setText(filename)
        
    def searchForMeshFile(self):
        filename = QtGui.QFileDialog.getOpenFileName(self,'Mesh or pickled mesh file', '',"Zinc exregion files (*.ex2);; Project Pickles (*.pkl *.pickle)")
        if isinstance(filename,tuple): #Handle pyside
            filename = str(filename[0])        
        if filename is not None and not str(filename) == "":
            self.symmetric.setChecked(False)
            self.human.setChecked(False)            
            self.sourceMesh.setText(filename)
    
    def okclicked(self):
        result = dict()
        result['name'] = str(self.projectName.text())
        if len(result['name'])==0:
            QtGui.QMessageBox.critical(self,'Missing value','Project name is required!')
            return
        result['author'] = str(self.author.text())
        if len(result['author'])==0:
            QtGui.QMessageBox.critical(self,'Missing value','Author name is required!')
            return
        result['comments'] = str(self.projectComments.toPlainText())
        result['projectFolder'] = str(self.projectFolder.text())           
        if len(result['projectFolder'])==0:
            QtGui.QMessageBox.critical(self,'Missing value','A Project folder is required!')
            return
        if not path.exists(result['projectFolder']):
            QtGui.QMessageBox.critical(self,'Missing value','A Valid project folder is required!')
            return        
        if self.symmetric.isChecked():
            result['meshtype'] = 'symmetric'
        elif self.human.isChecked():
            result['meshtype'] = 'human'
        else:
            result['meshtype'] = 'user'
            result['mesh'] = str(self.sourceMesh.text())
            if len(result['mesh'])==0:
                QtGui.QMessageBox.critical(self,'Missing value','A Mesh file should be specified!')
                return
            result['circumferentialelements'] = str(self.circumferentialElements.text())
            if len(result['circumferentialelements'])==0:
                QtGui.QMessageBox.critical(self,'Missing value','Number of circumferential elements should be specified!')
                return
            try:
                result['circumferentialelements'] = int(str(self.circumferentialElements.text()))
            except:
                QtGui.QMessageBox.critical(self,'Missing value','Integer number of circumferential elements should be specified!')
                return
            result['axialelements'] = str(self.circumferentialElements.text())
            if len(result['axialelements'])==0:
                QtGui.QMessageBox.critical(self,'Missing value','Number of Axial elements should be specified!')
                return
            try:
                result['axialelements'] = int(str(self.axialElements.text()))
            except:
                QtGui.QMessageBox.critical(self,'Missing value','Integer number of Axial elements should be specified!')
                return
            
        self.datacollected.emit(result)
        self.close()
    
    def cancelclicked(self):
        self.userCancelled.emit()
        self.close()
        
    def enableUserMesh(self):
        state = self.choose.isChecked() 
        self.sourceMesh.setEnabled(state)
        self.searchMeshFile.setEnabled(state)
        self.circumferentialElements.setEnabled(state)
        self.axialElements.setEnabled(state)


class ProjectDetailsEditWindow(ProjectDetailsEditWindowBase):
    changed = signalHandle(object)    
    def __init__(self,projectRecord,parent=None,title="Current Project Details"):
        super(ProjectDetailsEditWindow,self).__init__(parent)
        self.projectRecord = projectRecord
        self.projectName.setText(projectRecord['name'])
        self.author.setText(projectRecord['author'])
        self.projectComments.clear()
        self.projectComments.appendPlainText(projectRecord['comments'])
        self.projectFolder.setText(projectRecord['projectFolder'])
        if projectRecord['meshtype']=='symmetric':
            self.meshType.setText('Symmetric')
        else:
            self.meshType.setText('Human')
        if 'texture' in projectRecord:
            self.textureFile.setText(projectRecord['texture'])        
        if 'regionMarkers' in projectRecord:
            self.regionsFile.setText(projectRecord['regionMarkers'])            
        if 'cellMarkers' in projectRecord:
            self.annotationFile.setText(projectRecord['cellMarkers'])
        
        self.Ok.clicked.connect(self.okclicked)
        self.cancel.clicked.connect(self.cancelclicked)
        self.setModal(True)
        self.setWindowTitle(title)
        self.screenCenterDialog()

    def screenCenterDialog(self):
        frameGm = self.frameGeometry()
        screen = QtGui.QApplication.desktop().screenNumber(QtGui.QApplication.desktop().cursor().pos())
        centerPoint = QtGui.QApplication.desktop().screenGeometry(screen).center()
        frameGm.moveCenter(centerPoint)
        self.move(frameGm.topLeft())
        
    def cancelclicked(self):
        self.close()
    
    def okclicked(self):
        projectFolder = self.projectRecord['projectFolder']
        name = self.projectRecord['name']
        self.projectRecord['author'] = str(self.author.text())
        self.projectRecord['comments'] = str(self.projectComments.toPlainText()) 
        with open(path.join(projectFolder,'%s.ann'%name),'wb') as ser:
            json.dump(self.projectRecord,ser,2)
        self.changed.emit(self.projectRecord)
        self.close()


class ApplicationWindow(ApplicationWindowBase):
    
    mainModelInitialized = signalHandle()
    zincDigitizerInitialized = signalHandle()
    textureChanged = signalHandle(object)
    
    def __init__(self,parent=None):
        super(ApplicationWindow,self).__init__(parent)

        #Equally distribute the splitter contents
        self.splitter.setSizes([16777215,16777215])
        self.zincContext = Context("MainContext")
        
        self.mkLayout = QtGui.QVBoxLayout(self.markerWidget)
        self.mkLayout.setSpacing(0)
        self.mkLayout.setContentsMargins(0,0,0,0)
        self.mkLayout.setObjectName("mkLayout")     
        self.regionMarkerWidget = PainterWidget(0)
        self.mkLayout.addWidget(self.regionMarkerWidget)
        
        #Setup zinc widgets
        self.mvLayout = QtGui.QVBoxLayout(self.mainModel)
        self.mvLayout.setSpacing(0)
        self.mvLayout.setContentsMargins(0,0,0,0)
        self.mvLayout.setObjectName("mvLayout")
        self.mainModelqgl = QtOpenGL.QGLWidget(self.mainModel)
        self.mainModelView = SceneViewerWidget(self.mainModelqgl)
        self.mainModelView.setContext(self.zincContext)
        self.mvLayout.addWidget(self.mainModelView)
        
        self.dvLayout = QtGui.QVBoxLayout(self.zincDigitiser)
        self.dvLayout.setSpacing(0)
        self.dvLayout.setContentsMargins(0,0,0,0)
        self.dvLayout.setObjectName("dvLayout")
        self.digitiserqgl = QtOpenGL.QGLWidget(self.zincDigitiser)
        self.digitiserView = ZincPainterWidget(self.zincContext,self.digitiserqgl,self.mainModelView)
        self.dvLayout.addWidget(self.digitiserView)
        
        self._setConnections()
        self.mainModelView.graphicsInitialized.connect(self.setupMainModelGraphics)
        self.digitiserView.graphicsInitialized.connect(self.setupDigitiserGraphics)
        self.mainModelView.doubleClicked.connect(self.mainModelViewViewAll)
        
        self.currentProject = dict()
        
    
    def setupDigitizationMeshBackground(self,pkl,circumferentialElements=8,axialElements=11):
        self.backgroundMesh = MeshMapper()
        
        self.backgroundMesh.setupByPickle(pkl)
    
        class MeshGen(object):
            def __init__(self,mesh):
                self.meshgen = mesh
    
            def generateMesh(self,region):
                self.meshgen.generateFlatMesh(region, circumferentialElements,axialElements)
    
        self.digitiserView.setupMeshBackground(MeshGen(self.backgroundMesh))   
    
    def _setConnections(self):
        self.actionLoad_mesh.triggered.connect(self.loadMesh)
        self.actionOpen_Project.triggered.connect(self.openProject)
        self.actionSave_Project.triggered.connect(self.saveExisting)
        self.actionSave_As.triggered.connect(self.saveProject)
        self.actionExport_Ex2.triggered.connect(self.saveInEx2Format)
        self.actionProject_Details.triggered.connect(self.showProjectDetails)
        self.actionUser_documentation.triggered.connect(self.showUserDocumentation)
        self.actionExit.triggered.connect(self.exitApp)
        
        self.applyRegion.clicked.connect(self.createAndApplyTexture)
        self.updateMarkers.clicked.connect(self.updateSourceMarkers)
    
    def createAndApplyTexture(self):
        markers,colors = self.regionMarkerWidget.getMarkersAndColors()
        self.backgroundMesh.assignRegions(markers,colors)
        self.backgroundMesh.createImage(self.textureFile)
        self.digitiserView.setTexture(self.textureFile)
        self.textureChanged.emit(self.textureFile)
   
   
    def updateSourceMarkers(self):
        self.mainModelController.showDataPoints(self.digitiserView.getUsedNodesWithXiAndData())
   
    def mainModelViewViewAll(self):
        #self.mainModelView.viewAll()
        self.mainModelView.setViewParameters([0.006591612769376118, -0.28280922217064075, 2.5081264404696726], [0.08671705424785614, 0.029457375407218933, -0.07984980940818787], [0.15726460806804382, 0.9798543449214825, 0.12309876436305625], 0.6981317007977258)
    
    def digitiserViewViewAll(self):
        self.digitiserView.viewAll()    
    
    def getMainModelSceneViewer(self):
        return self.mainModelView

    def getDigitizerSceneViewer(self):
        return self.digitiserView
    
    def loadRegionMarker(self):
        self.regionMarkerWidget.setupMeshBackground(self.backgroundMesh,11)
        
    def loadMesh(self):
        '''
        Present a dialog to get details regarding the project
        '''
        def loadUserInput(result):
            #Just to ensure that the sceneviewer is setup, as it is lazy loaded and if it is not visible, then it is not ready 
            self.annotationWidgetsTab.setCurrentIndex(1)
            if hasattr(self, 'mainModelController'):
                del self.mainModelController
                
            self.mainModelController = MainModelController(self)
            del self.currentProject
            self.currentProject = result
            self.textureFile = path.join(result['projectFolder'],'Texture%s.png'%result['name'])
            ctr = 0
            while path.exists(self.textureFile):
                self.textureFile = path.join(result['projectFolder'],'Texture%s_%d.png'%(result['name'],ctr))
                ctr +=1
                
            if result['meshtype']=='symmetric':
                pklp = path.join(dir_path,"./gui/symmetricstomachsurface.pkl")
                self.setupDigitizationMeshBackground(pklp,8,11)
                self.mainModelController.loadMesh(self.backgroundMesh.mesh)
                self.mainModelController.linkToSceneViewer()
                self.currentProject['circumferentialelements'] = 8
                self.currentProject['axialelements'] = 11
            elif result['meshtype']=='human':
                pklp = path.join(dir_path,"./gui/stomachsurface.pkl")
                self.setupDigitizationMeshBackground(pklp,8,11)
                self.mainModelController.loadMesh(self.backgroundMesh.mesh)
                self.mainModelController.linkToSceneViewer()
                self.currentProject['circumferentialelements'] = 8
                self.currentProject['axialelements'] = 11
            else:
                pass
            self.annotationWidgetsTab.setCurrentIndex(0)
            self.mainModelController.showGraphics()
            self.loadRegionMarker()
            self.projectOpened = True
            
        data = ProjectDetailsWindow(self)
        data.datacollected.connect(loadUserInput)
        data.show()
        #result = {'projectFolder': r'D:\Jagir_Hussan\Research\SPARC\workspace\StomachAnnotation\pwork', 'name': 'testing', 'meshtype': 'human', 'axialelements': 2, 'author': 'sdf', 'comments': 'temporary','mesh': 'no mesh', 'circumferentialelements': 1}
        #loadUserInput(result)
        
    
    def openProject(self):
        filename = QtGui.QFileDialog.getOpenFileName(self,'Pickled project file', '',"Annotator (*.ann);; All Files (*.*)")
        if isinstance(filename,tuple): #Handle pyside
            filename = str(filename[0])        
        if filename is not None and not str(filename) == "":
            with open(filename,'rb') as ser:
                project = json.load(ser)
                projectFolder = project['projectFolder']
                if projectFolder != path.dirname(filename): #File has been moved
                    projectFolder = path.dirname(filename)
                    project['projectFolder'] = projectFolder
                
                backgroudMesh = project['backgroundMesh']
                
                texture = ''
                if 'texture' in project:
                    texture = project['texture']
                regionMarker = ''
                if 'regionMarkers' in project:
                    regionMarker = project['regionMarkers']
                cellMarker = ''
                if 'cellMarkers' in project:
                    cellMarker = project['cellMarkers']
                
                if path.isdir(projectFolder):
                    backgroudMesh = path.join(projectFolder,backgroudMesh)
                    if path.isfile(backgroudMesh):
                        texture = path.join(projectFolder,texture)
                        if not path.isfile(texture):
                            texture = None
                        regionMarker  = path.join(projectFolder,regionMarker)
                        if not path.isfile(regionMarker):
                            regionMarker = None
                        cellMarker  = path.join(projectFolder,cellMarker)
                        if not path.isfile(cellMarker):
                            cellMarker = None
                        
                    else:
                        QtGui.QMessageBox.critical('Missing file','Project mesh %s is missing!!'%backgroudMesh)
                        return
                else:
                    QtGui.QMessageBox.critical('Missing folder','Project folder %s is missing!!'%projectFolder)
                    return
                
                self.currentProject = dict()
                pkeys = ['projectFolder','name','meshtype', 'axialelements', 'author', 'comments','mesh', 'circumferentialelements']
                for k in pkeys:
                    if k in project:
                        self.currentProject[k] = project[k]
                
                self.currentProject['backgroundMesh'] = path.basename(backgroudMesh)
                if not regionMarker is None:
                    self.currentProject['regionMarkers']=path.basename(regionMarker)
                if not cellMarker is None:
                    self.currentProject['cellMarkers']=path.basename(cellMarker)
                
                
            self.annotationWidgetsTab.setCurrentIndex(1)
            if hasattr(self, 'mainModelController'):
                del self.mainModelController
                
            self.mainModelController = MainModelController(self)
            self.setupDigitizationMeshBackground(backgroudMesh,project['circumferentialelements'],project['axialelements'])
            self.mainModelController.loadMesh(self.backgroundMesh.mesh)
            self.loadRegionMarker()
            self.mainModelController.linkToSceneViewer()
            self.annotationWidgetsTab.setCurrentIndex(0)
            self.mainModelController.showGraphics()
            
            if not texture is None:
                self.textureFile = texture
                self.mainModelController.setTexture(texture)
                self.digitiserView.setTexture(texture)
            else:
                self.textureFile = path.join(project['projectFolder'],'Texture%s.png'%project['name'])
                ctr = 0
                while path.exists(self.textureFile):
                    self.textureFile = path.join(project['projectFolder'],'Texture%s_%d.png'%(project['name'],ctr))
                    ctr +=1
            if not regionMarker is None:
                self.regionMarkerWidget.loadRegions(regionMarker)
            if not cellMarker is None:
                self.digitiserView.loadRegions(cellMarker)
                self.updateSourceMarkers()
                
    def saveInEx2Format(self):
        if self.currentProject is None or len(self.currentProject)==0:
            return
        project = self.currentProject
        if 'regionMarkers' in project:
            if 'cellMarkers' in project:
                filename = QtGui.QFileDialog.getSaveFileName(self,'Ex2 file', '',"OpenCMISS Zinc (*.ex2);; All Files (*.*)")
                if isinstance(filename,tuple): #Handle pyside
                    filename = str(filename[0])        
                if filename is not None and not str(filename) == "":
                    self.mainModelController.rootRegion.writeFile(filename)
            else:
                QtGui.QMessageBox.information(self,'','No cell markers attached! Save project to associate them and retry')
        else:
            QtGui.QMessageBox.information(self,'','Annotation free mesh cannot be saved!')
    def saveExisting(self):
        self.projectOpened = False
        if self.currentProject is None or len(self.currentProject)==0:
            return
        project = self.currentProject
        projectFolder = project['projectFolder']
        name = project['name']
        if 'backgroundMesh' in project:
            backgroundMesh = project['backgroundMesh']
        else:
            backgroundMesh = 'BackgroundMesh%s.pkl' % name
            ctr = 0
            while path.exists(path.join(projectFolder,backgroundMesh)):
                backgroundMesh = 'BackgroundMesh%s_%d.pkl' % (name,ctr)
                ctr +=1
            project['backgroundMesh'] = backgroundMesh
            
        if 'regionMarkers' in project:
            regionMarker = project['regionMarkers']
        else:
            regionMarker = 'Regions%s.dat' %name
            ctr = 0
            while path.exists(path.join(projectFolder,regionMarker)):
                regionMarker = 'Regions%s_%d.dat' % (name,ctr)
                ctr +=1
            project['regionMarkers'] = regionMarker
            
        if 'cellMarkers' in project:
            cellMarker = project['cellMarkers']
        else:
            cellMarker = 'Markers%s.dat' %name
            ctr = 0
            while path.exists(path.join(projectFolder,cellMarker)):
                cellMarker = 'Markers%s_%d.dat' % (name,ctr)
                ctr +=1
            project['cellMarkers'] = cellMarker
        project['texture'] =path.basename(self.textureFile)
        
        self.backgroundMesh.serialize(path.join(projectFolder,backgroundMesh))
        if not self.regionMarkerWidget.saveRegions(path.join(projectFolder,regionMarker)):
            try:
                os.remove(path.join(projectFolder,regionMarker))
            except:
                pass
            del project['regionMarkers']
        if not self.digitiserView.saveRegions(path.join(projectFolder,cellMarker)):
            try:
                os.remove(path.join(projectFolder,cellMarker))
            except:
                pass
            
            del project['cellMarkers']
            
        with open(path.join(projectFolder,'%s.ann'%name),'wb') as ser:
                json.dump(project,ser,2)
            
    def saveProject(self):
        self.projectOpened = False        
        if self.currentProject is None or len(self.currentProject)==0:
            return
        filename = QtGui.QFileDialog.getExistingDirectory(self,'Project directory', '')
        if isinstance(filename,tuple): #Handle pyside
            filename = str(filename[0])        
        if filename is not None and not str(filename) == "":
            project = dict(self.currentProject)
            project['projectFolder'] = filename
            projectFolder = project['projectFolder']
            name = project['name']
            backgroundMesh = 'BackgroundMesh%s.pkl' % name
            ctr = 0
            while path.exists(path.join(projectFolder,backgroundMesh)):
                backgroundMesh = 'BackgroundMesh%s_%d.pkl' % (name,ctr)
                ctr +=1
            self.backgroundMesh.serialize(path.join(projectFolder,backgroundMesh))
            project['backgroundMesh'] = backgroundMesh
            if path.exists(self.textureFile):
                project['texture'] = path.basename(self.textureFile)
                shutil.copyfile(self.textureFile, path.join(projectFolder,project['texture']))
            regionMarker = 'Regions%s.dat' %name
            ctr = 0
            while path.exists(path.join(projectFolder,regionMarker)):
                regionMarker = 'Regions%s_%d.dat' % (name,ctr)
                ctr +=1
            if self.regionMarkerWidget.saveRegions(path.join(projectFolder,regionMarker)):
                project['regionMarkers']=regionMarker
    
            cellMarker = 'Markers%s.dat' %name
            ctr = 0
            while path.exists(path.join(projectFolder,cellMarker)):
                cellMarker = 'Markers%s_%d.dat' % (name,ctr)
                ctr +=1
            if self.digitiserView.saveRegions(path.join(projectFolder,cellMarker)):
                project['cellMarkers']=cellMarker

            with open(path.join(projectFolder,'%s.ann'%name),'wb') as ser:
                json.dump(project,ser,2)
            QtGui.QMessageBox.information(self,"Success","Successfully saved project!")
    
    def exitApp(self):
        self.close()
    
    def setupMainModelGraphics(self):
        self.mainModelView.setViewParameters([0.006591612769376118, -0.28280922217064075, 2.5081264404696726], [0.08671705424785614, 0.029457375407218933, -0.07984980940818787], [0.15726460806804382, 0.9798543449214825, 0.12309876436305625], 0.6981317007977258)        
        self.mainModelInitialized.emit()
    
    def setupDigitiserGraphics(self):
        self.zincDigitizerInitialized.emit()
        
    def showProjectDetails(self):
        if not self.currentProject is None and len(self.currentProject)>0:
            def changeCurrentProjectRecord(rec):
                self.currentProject = dict(rec)
            self.currentProject['texture'] = path.basename(self.textureFile)    
            pdialog = ProjectDetailsEditWindow(self.currentProject)
            pdialog.changed.connect(changeCurrentProjectRecord)
            pdialog.show()

    def showUserDocumentation(self):
        if hasattr(self, 'helpview'):
            del self.helpview
        self.helpview = QtWebKit.QWebView()
        self.helpview.setWindowTitle("User documentation")
        url = QtCore.QUrl.fromLocalFile(path.abspath(path.join(dir_path,'./help/help.html')))
        self.helpview.load(url)
        self.helpview.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ams = ApplicationWindow()     
    
    ams.show()
    #data = ProjectDetailsWindow()
    #data.show()
    sys.exit(app.exec_())