def __init__(self, viewport, viewportMngr, vpType, prototypeMngr, parent=None): """ Initialization of the CompositionView class Parameters: viewportMngr - the manager of the viewports where the composition view can reside in prototypeMngr - the manager of the prototypes is used to obtain the results of the solver """ QtWidgets.QDialog.__init__(self, parent) self.prototypeManager = prototypeMngr self.viewport = viewport self.viewportManager = viewportMngr self.settings = Settings() self.setWindowFlags(QtCore.Qt.Window) self.timer = QtCore.QObject() # QtCore.qsrand(QtCore.QTime(0,0,0).secsTo(QtCore.QTime.currentTime())) self.tree = Tree(None) self.infoOverlay = CVInfoOverlay(self) self.connections = [] self.ui = Ui_compositionView() self.ui.setupUi(self) self.ui.graphicsView.setupViewport( QtOpenGL.QGLWidget( QtOpenGL.QGLFormat(QtOpenGL.QGL.SampleBuffers | QtOpenGL.QGL.DoubleBuffer))) # self.ui.graphicsView.setViewport(QtGui.QWidget()) self.ui.graphicsView.setRenderHints( QtGui.QPainter.Antialiasing | QtGui.QPainter.SmoothPixmapTransform) self.collapsed = False self.currentTool = None self.viewportType = vpType self.first = False self.nodeId = 0 self.overConstrainedColor = QtGui.QColor(0, 0, 255) self.underConstrainedColor = QtGui.QColor(255, 0, 0) self.wellConstrainedColor = QtGui.QColor(0, 255, 0) self.unsolvedColor = QtGui.QColor(125, 124, 255) self.setScene() self.createTriggers()
def __init__(self, viewport, viewportMngr, vpType, prototypeMngr, parent=None): """ Initialization of the CompositionView class Parameters: viewportMngr - the manager of the viewports where the composition view can reside in prototypeMngr - the manager of the prototypes is used to obtain the results of the solver """ QtGui.QDialog.__init__(self, parent) self.prototypeManager = prototypeMngr self.viewport = viewport self.viewportManager = viewportMngr self.settings = Settings() self.setWindowFlags(QtCore.Qt.Window) self.timer = QtCore.QObject() #QtCore.qsrand(QtCore.QTime(0,0,0).secsTo(QtCore.QTime.currentTime())) self.tree = Tree(None) self.infoOverlay = CVInfoOverlay(self) self.connections = [] self.ui = Ui_compositionView() self.ui.setupUi(self) self.ui.graphicsView.setupViewport(QtOpenGL.QGLWidget(QtOpenGL.QGLFormat(QtOpenGL.QGL.SampleBuffers|QtOpenGL.QGL.DoubleBuffer))) #self.ui.graphicsView.setViewport(QtGui.QWidget()) self.ui.graphicsView.setRenderHints(QtGui.QPainter.Antialiasing | QtGui.QPainter.SmoothPixmapTransform) self.collapsed = False self.currentTool = None self.viewportType = vpType self.first = False self.nodeId = 0 self.overConstrainedColor = QtGui.QColor(0,0,255) self.underConstrainedColor = QtGui.QColor(255,0,0) self.wellConstrainedColor = QtGui.QColor(0,255,0) self.unsolvedColor = QtGui.QColor(125,124,255) self.setScene() self.createTriggers()
class CompositionView(QtGui.QDialog): """ A view where the decomposition of the system of constraints is visualised as a tree """ def __init__(self, viewport, viewportMngr, vpType, prototypeMngr, parent=None): """ Initialization of the CompositionView class Parameters: viewportMngr - the manager of the viewports where the composition view can reside in prototypeMngr - the manager of the prototypes is used to obtain the results of the solver """ QtGui.QDialog.__init__(self, parent) self.prototypeManager = prototypeMngr self.viewport = viewport self.viewportManager = viewportMngr self.settings = Settings() self.setWindowFlags(QtCore.Qt.Window) self.timer = QtCore.QObject() #QtCore.qsrand(QtCore.QTime(0,0,0).secsTo(QtCore.QTime.currentTime())) self.tree = Tree(None) self.infoOverlay = CVInfoOverlay(self) self.connections = [] self.ui = Ui_compositionView() self.ui.setupUi(self) self.ui.graphicsView.setupViewport(QtOpenGL.QGLWidget(QtOpenGL.QGLFormat(QtOpenGL.QGL.SampleBuffers|QtOpenGL.QGL.DoubleBuffer))) #self.ui.graphicsView.setViewport(QtGui.QWidget()) self.ui.graphicsView.setRenderHints(QtGui.QPainter.Antialiasing | QtGui.QPainter.SmoothPixmapTransform) self.collapsed = False self.currentTool = None self.viewportType = vpType self.first = False self.nodeId = 0 self.overConstrainedColor = QtGui.QColor(0,0,255) self.underConstrainedColor = QtGui.QColor(255,0,0) self.wellConstrainedColor = QtGui.QColor(0,255,0) self.unsolvedColor = QtGui.QColor(125,124,255) self.setScene() self.createTriggers() def createTriggers(self): """ Create the triggers for the components in the graphical window """ QtCore.QObject.connect(self.ui.zoomInButton,QtCore.SIGNAL("clicked()"),self.zoomIn) QtCore.QObject.connect(self.ui.zoomOutButton,QtCore.SIGNAL("clicked()"),self.zoomOut) QtCore.QObject.connect(self.ui.fitButton, QtCore.SIGNAL("clicked()"), self.fit) QtCore.QObject.connect(self.ui.collapseButton, QtCore.SIGNAL("clicked()"), self.collapse) QtCore.QObject.connect(self.ui.graphicsScene, QtCore.SIGNAL("changed(const QList<QRectF> & )"), self.updateSceneRect) QtCore.QObject.connect(self.ui.verticalSlider,QtCore.SIGNAL("valueChanged(int)"),self.setupMatrix) QtCore.QObject.connect(self.settings.dvData,QtCore.SIGNAL("treeOrientationChanged()"), self.updateTreeOrientation) def setScene(self): """ The scene where the tree is visualised in, will be created and set """ self.initView() def getViewportType(self): return self.viewportType def updateGL(self): self.update() def createDecomposition(self): """ Create a new decomposition. If an older one exists it will be removed. """ if self.ui.graphicsScene != None: for item in self.ui.graphicsView.items(): item.hide() if item.parentItem() == None: self.ui.graphicsScene.removeItem(item) if self.tree.root != None: self.tree.clear(self.tree.root) del self.connections[:] del self.settings.dvData.fixedClusterIds[:] self.initView() def initView(self): """ Updating the view with new data and nodes for the visualisation of the tree """ if self.prototypeManager.result != None: self.nodeId = 0 self.tree.root = self.populateTree(self.prototypeManager.result.subs, None, self.prototypeManager.result) self.drawTree(self.ui.graphicsScene, self.tree.root, self.tree.root.children) self.drawConnections(self.ui.graphicsScene) self.determineCollapse(self.tree.root) self.showConnections() self.tree.root.showChildren() self.updateTree() self.addInfoOverlay() self.initFixStates() def updateViewports(self): self.viewportManager.updateViewports() def updateTree(self): """ Update the tree, where the node positions and connections between the nodes are updated """ self.tree.clear(self.tree.root) self.tree.updateTree() self.updateNodePositions(self.tree.root) self.showConnections() def populateTree(self, nodes, rootNode, currentNode, id=0): """ Recursive function to populate a tree, from the results of the solver to finally display it in the Decomposition View. The population is depth first. Parameters: nodes - the childnodes rootNode - root node of the (partial) tree currentNode - the current node of the result obtained from the constraints solver """ if len(currentNode.variables) == 1: self.createLeafPoint(rootNode, currentNode.variables[0], self.nodeId) else: newNode = CVCluster(self, rootNode, self.nodeId) newNode.flag = currentNode.flag newNode.variables = currentNode.variables needCollapse = False """ Add children to the rootNode to create the full tree """ if rootNode != None: #self.setCollapse(newNode) rootNode.children += [newNode] """ Create a connection between the nodes if the current node has a rootnode""" newConnection = CVConnection(self, rootNode, newNode) self.connections += [newConnection] """ get the leaf nodes """ if len(nodes) == 0: for variable in newNode.variables: self.createLeafPoint(newNode, variable, self.nodeId) # Rick 20091116 - skip this for debug # for node in nodes: # self.nodeId += 1 # self.populateTree(node.subs, newNode, node, self.nodeId) """ To return the whole tree, a check will be performed for the rootnode """ if rootNode == None: return newNode def initFixStates(self): """ Initialize the fix states from another view if available """ for fixedId in self.settings.dvData.fixedClusterIds: self.updateState(fixedId, True, self.tree.root) def stateChange(self, id, fixed): """ Change the state of the cluster which might be fixed and report it to the other decomposition views. Paramaters: id - unique id of the cluster fixed - should the clusters be fixed or not """ self.viewportManager.updateDecompositionFixed(id, fixed) if fixed: self.settings.dvData.fixedClusterIds += [id] elif not fixed: self.settings.dvData.fixedClusterIds = filter(lambda x:x!=id, self.settings.dvData.fixedClusterIds) def updateState(self, id, fixed, rootNode): """ Update the fixed cluster, with the visuals. Parameters: id - unique id of the cluster fixed - should the cluster be fixed or not rootNode - recursive funcion to walk the tree """ if rootNode.identifier == id: if fixed and rootNode.isVisible(): rootNode.fixGraphic.show() rootNode.clusterActive = True elif fixed and not rootNode.isVisible(): rootNode.fixGraphic.hide() rootNode.clusterActive = True else: rootNode.fixGraphic.hide() rootNode.clusterActive = False self.prototypeManager.removeClusterObjects([rootNode.permCluster], True, True) rootNode.permCluster = None return True for node in rootNode.children: found = self.updateState(id, fixed, node) if found: break return False def createLeafPoint(self, node, variable, id): cvPoint = CVPoint(self, node, id) cvPoint.setWidthAndHeight(20, 20) cvPoint.prtRef = self.prototypeManager.getObjectByKey(variable) cvPoint.isCollapsed = False cvPoint.canCollapse = False #cvPoint.setInfoOverlay() node.children += [cvPoint] newConnection = CVConnection(self, node, cvPoint) self.connections += [newConnection] def setCollapse(self, node): node.isCollapsed = False if not isinstance(node, CVPoint): if not node.collapseFromResult(): node.updateCluster() def determineCollapse(self, node): self.setCollapse(node) for child in node.children: self.determineCollapse(child) def addInfoOverlay(self): self.ui.graphicsScene.addItem(self.infoOverlay) self.infoOverlay.hide() def drawTree(self, scene, root, childNodes): """ The different nodes are added to the scene and will automatically be drawn Parameters: scene - the scene where the rootnode has to be drawn in root - the rootnode of the (sub-) tree childNode - the children of this root node """ root.setPos(root.position) scene.addItem(root) #print "#nodes: ", len(childNodes), " position: ",root.position.x(), " " , root.position.y() for node in childNodes: self.drawTree(scene, node, node.children) def drawConnections(self, scene): """ The connections between the nodes are added to the scene and will automatically be drawn Parameters: scene - the scene where the connections has to be drawn in """ for connection in self.connections: #connection.setPos() scene.addItem(connection) def showConnections(self): """ Show/hide the connections between the nodes, this depends if the node is collapsed """ for connection in self.connections: connection.setPos(connection.nodeTo.position) if connection.nodeFrom.isCollapsed or (connection.nodeTo.isVisible() == False): connection.hide() else: connection.show() def updateConnections(self): for connection in self.connections: connection.update() def nrVisibleConnections(self): number = 0 #for connection in self.connections: #print "x, y: " , connection.x(), connection.y() #print "nr of visible connections: " , number def updateNodePositions(self, node): """ Map the position of the nodes in the tree on the graphical view Parameters: node - a node in the tree for which the position is set """ node.setPos(node.position) for childNode in node.children: self.updateNodePositions(childNode) def updateSceneRect(self, rectList=None): self.ui.graphicsScene.setSceneRect(self.ui.graphicsScene.itemsBoundingRect()) def updateTreeOrientation(self): self.tree.orientation = self.settings.dvData.treeAlignment def zoomIn(self): """ Zoom in the graphics view, by updating the vertical slider """ self.ui.verticalSlider.setValue(self.ui.verticalSlider.value() + 1) def zoomOut(self): """ Zoom out the graphics view, by updating the vertical slider """ self.ui.verticalSlider.setValue(self.ui.verticalSlider.value() - 1) def fit(self): """ Fits the tree exactly in the graphics view """ self.ui.graphicsView.fitInView(0.0, 0.0, self.ui.graphicsScene.width(), self.ui.graphicsScene.height(), QtCore.Qt.KeepAspectRatio) """ Update the slider """ value = (math.log(self.ui.graphicsView.matrix().m11(),2)*50) + 250.0 self.ui.verticalSlider.setValue(value) def collapseAll(self, node): if node.canCollapse: node.collapse() for childNode in node.children: self.collapseAll(childNode) def expandAll(self, node): node.expand() for childNode in node.children: self.expandAll(childNode) def collapse(self): if self.collapsed: self.collapsed = False self.collapseAll(self.tree.root) else: self.collapsed = True self.expandAll(self.tree.root) self.updateTree() self.update() def setupMatrix(self, value): """ Zoom in/out the graphics view, depending on the value of the slider Parameters value - value of the updated slider """ scale = math.pow(2.0, (self.ui.verticalSlider.value()-250.0)/50.0) matrix = QtGui.QMatrix() matrix.scale(scale,scale) self.ui.graphicsView.setMatrix(matrix)
class CompositionView(QtGui.QDialog): """ A view where the decomposition of the system of constraints is visualised as a tree """ def __init__(self, viewport, viewportMngr, vpType, prototypeMngr, parent=None): """ Initialization of the CompositionView class Parameters: viewportMngr - the manager of the viewports where the composition view can reside in prototypeMngr - the manager of the prototypes is used to obtain the results of the solver """ QtGui.QDialog.__init__(self, parent) self.prototypeManager = prototypeMngr self.viewport = viewport self.viewportManager = viewportMngr self.settings = Settings() self.setWindowFlags(QtCore.Qt.Window) self.timer = QtCore.QObject() #QtCore.qsrand(QtCore.QTime(0,0,0).secsTo(QtCore.QTime.currentTime())) self.tree = Tree(None) self.infoOverlay = CVInfoOverlay(self) self.connections = [] self.ui = Ui_compositionView() self.ui.setupUi(self) self.ui.graphicsView.setupViewport( QtOpenGL.QGLWidget( QtOpenGL.QGLFormat(QtOpenGL.QGL.SampleBuffers | QtOpenGL.QGL.DoubleBuffer))) #self.ui.graphicsView.setViewport(QtGui.QWidget()) self.ui.graphicsView.setRenderHints( QtGui.QPainter.Antialiasing | QtGui.QPainter.SmoothPixmapTransform) self.collapsed = False self.currentTool = None self.viewportType = vpType self.first = False self.nodeId = 0 self.overConstrainedColor = QtGui.QColor(0, 0, 255) self.underConstrainedColor = QtGui.QColor(255, 0, 0) self.wellConstrainedColor = QtGui.QColor(0, 255, 0) self.unsolvedColor = QtGui.QColor(125, 124, 255) self.setScene() self.createTriggers() def createTriggers(self): """ Create the triggers for the components in the graphical window """ QtCore.QObject.connect(self.ui.zoomInButton, QtCore.SIGNAL("clicked()"), self.zoomIn) QtCore.QObject.connect(self.ui.zoomOutButton, QtCore.SIGNAL("clicked()"), self.zoomOut) QtCore.QObject.connect(self.ui.fitButton, QtCore.SIGNAL("clicked()"), self.fit) QtCore.QObject.connect(self.ui.collapseButton, QtCore.SIGNAL("clicked()"), self.collapse) QtCore.QObject.connect( self.ui.graphicsScene, QtCore.SIGNAL("changed(const QList<QRectF> & )"), self.updateSceneRect) QtCore.QObject.connect(self.ui.verticalSlider, QtCore.SIGNAL("valueChanged(int)"), self.setupMatrix) QtCore.QObject.connect(self.settings.dvData, QtCore.SIGNAL("treeOrientationChanged()"), self.updateTreeOrientation) def setScene(self): """ The scene where the tree is visualised in, will be created and set """ self.initView() def getViewportType(self): return self.viewportType def updateGL(self): self.update() def createDecomposition(self): """ Create a new decomposition. If an older one exists it will be removed. """ if self.ui.graphicsScene != None: for item in self.ui.graphicsView.items(): item.hide() if item.parentItem() == None: self.ui.graphicsScene.removeItem(item) if self.tree.root != None: self.tree.clear(self.tree.root) del self.connections[:] del self.settings.dvData.fixedClusterIds[:] self.initView() def initView(self): """ Updating the view with new data and nodes for the visualisation of the tree """ if self.prototypeManager.result != None: self.nodeId = 0 self.tree.root = self.populateTree( self.prototypeManager.result.subs, None, self.prototypeManager.result) # return # Rick 20090522 debug self.drawTree(self.ui.graphicsScene, self.tree.root, self.tree.root.children) self.drawConnections(self.ui.graphicsScene) self.determineCollapse(self.tree.root) self.showConnections() self.tree.root.showChildren() self.updateTree() self.addInfoOverlay() self.initFixStates() def updateViewports(self): self.viewportManager.updateViewports() def updateTree(self): """ Update the tree, where the node positions and connections between the nodes are updated """ self.tree.clear(self.tree.root) self.tree.updateTree() self.updateNodePositions(self.tree.root) self.showConnections() def populateTree(self, nodes, rootNode, currentNode, id=0): """ Recursive function to populate a tree, from the results of the solver to finally display it in the Decomposition View. The population is depth first. Parameters: nodes - the childnodes rootNode - root node of the (partial) tree currentNode - the current node of the result obtained from the constraints solver """ if len(currentNode.variables) == 1: self.createLeafPoint(rootNode, currentNode.variables[0], self.nodeId) else: newNode = CVCluster(self, rootNode, self.nodeId) newNode.flag = currentNode.flag newNode.variables = currentNode.variables needCollapse = False """ Add children to the rootNode to create the full tree """ if rootNode != None: #self.setCollapse(newNode) rootNode.children += [newNode] """ Create a connection between the nodes if the current node has a rootnode""" newConnection = CVConnection(self, rootNode, newNode) self.connections += [newConnection] """ get the leaf nodes """ if len(nodes) == 0: for variable in newNode.variables: self.createLeafPoint(newNode, variable, self.nodeId) for node in nodes: self.nodeId += 1 self.populateTree(node.subs, newNode, node, self.nodeId) """ To return the whole tree, a check will be performed for the rootnode """ if rootNode == None: return newNode def initFixStates(self): """ Initialize the fix states from another view if available """ for fixedId in self.settings.dvData.fixedClusterIds: self.updateState(fixedId, True, self.tree.root) def stateChange(self, id, fixed): """ Change the state of the cluster which might be fixed and report it to the other decomposition views. Paramaters: id - unique id of the cluster fixed - should the clusters be fixed or not """ self.viewportManager.updateDecompositionFixed(id, fixed) if fixed: self.settings.dvData.fixedClusterIds += [id] elif not fixed: self.settings.dvData.fixedClusterIds = filter( lambda x: x != id, self.settings.dvData.fixedClusterIds) def updateState(self, id, fixed, rootNode): """ Update the fixed cluster, with the visuals. Parameters: id - unique id of the cluster fixed - should the cluster be fixed or not rootNode - recursive funcion to walk the tree """ if rootNode.identifier == id: if fixed and rootNode.isVisible(): rootNode.fixGraphic.show() rootNode.clusterActive = True elif fixed and not rootNode.isVisible(): rootNode.fixGraphic.hide() rootNode.clusterActive = True else: rootNode.fixGraphic.hide() rootNode.clusterActive = False self.prototypeManager.removeClusterObjects( [rootNode.permCluster], True, True) rootNode.permCluster = None return True for node in rootNode.children: found = self.updateState(id, fixed, node) if found: break return False def createLeafPoint(self, node, variable, id): cvPoint = CVPoint(self, node, id) cvPoint.setWidthAndHeight(20, 20) cvPoint.prtRef = self.prototypeManager.getObjectByKey(variable) cvPoint.isCollapsed = False cvPoint.canCollapse = False #cvPoint.setInfoOverlay() node.children += [cvPoint] newConnection = CVConnection(self, node, cvPoint) self.connections += [newConnection] def setCollapse(self, node): node.isCollapsed = False if not isinstance(node, CVPoint): if not node.collapseFromResult(): node.updateCluster() def determineCollapse(self, node): self.setCollapse(node) for child in node.children: self.determineCollapse(child) def addInfoOverlay(self): self.ui.graphicsScene.addItem(self.infoOverlay) self.infoOverlay.hide() def drawTree(self, scene, root, childNodes): """ The different nodes are added to the scene and will automatically be drawn Parameters: scene - the scene where the rootnode has to be drawn in root - the rootnode of the (sub-) tree childNode - the children of this root node """ root.setPos(root.position) scene.addItem(root) #print "#nodes: ", len(childNodes), " position: ",root.position.x(), " " , root.position.y() for node in childNodes: self.drawTree(scene, node, node.children) def drawConnections(self, scene): """ The connections between the nodes are added to the scene and will automatically be drawn Parameters: scene - the scene where the connections has to be drawn in """ for connection in self.connections: #connection.setPos() scene.addItem(connection) def showConnections(self): """ Show/hide the connections between the nodes, this depends if the node is collapsed """ for connection in self.connections: connection.setPos(connection.nodeTo.position) if connection.nodeFrom.isCollapsed or ( connection.nodeTo.isVisible() == False): connection.hide() else: connection.show() def updateConnections(self): for connection in self.connections: connection.update() def nrVisibleConnections(self): number = 0 #for connection in self.connections: #print "x, y: " , connection.x(), connection.y() #print "nr of visible connections: " , number def updateNodePositions(self, node): """ Map the position of the nodes in the tree on the graphical view Parameters: node - a node in the tree for which the position is set """ node.setPos(node.position) for childNode in node.children: self.updateNodePositions(childNode) def updateSceneRect(self, rectList=None): self.ui.graphicsScene.setSceneRect( self.ui.graphicsScene.itemsBoundingRect()) def updateTreeOrientation(self): self.tree.orientation = self.settings.dvData.treeAlignment def zoomIn(self): """ Zoom in the graphics view, by updating the vertical slider """ self.ui.verticalSlider.setValue(self.ui.verticalSlider.value() + 1) def zoomOut(self): """ Zoom out the graphics view, by updating the vertical slider """ self.ui.verticalSlider.setValue(self.ui.verticalSlider.value() - 1) def fit(self): """ Fits the tree exactly in the graphics view """ self.ui.graphicsView.fitInView(0.0, 0.0, self.ui.graphicsScene.width(), self.ui.graphicsScene.height(), QtCore.Qt.KeepAspectRatio) """ Update the slider """ value = (math.log(self.ui.graphicsView.matrix().m11(), 2) * 50) + 250.0 self.ui.verticalSlider.setValue(value) def collapseAll(self, node): if node.canCollapse: node.collapse() for childNode in node.children: self.collapseAll(childNode) def expandAll(self, node): node.expand() for childNode in node.children: self.expandAll(childNode) def collapse(self): if self.collapsed: self.collapsed = False self.collapseAll(self.tree.root) else: self.collapsed = True self.expandAll(self.tree.root) self.updateTree() self.update() def setupMatrix(self, value): """ Zoom in/out the graphics view, depending on the value of the slider Parameters value - value of the updated slider """ scale = math.pow(2.0, (self.ui.verticalSlider.value() - 250.0) / 50.0) matrix = QtGui.QMatrix() matrix.scale(scale, scale) self.ui.graphicsView.setMatrix(matrix)