diff --git a/geosolver/clsolver3D.py b/geosolver/clsolver3D.py index 6d46553..b38a438 100644 --- a/geosolver/clsolver3D.py +++ b/geosolver/clsolver3D.py @@ -149,7 +149,8 @@ class ClusterSolver3D(ClusterSolver): # end for match # end for method return False - + + def _add_method_complete(self, merge): # diag_print("add_method_complete "+str(merge), "clsolver3D") # check that method has one output diff --git a/geosolver/geometric.py b/geosolver/geometric.py index 9c85c51..59a9610 100644 --- a/geosolver/geometric.py +++ b/geosolver/geometric.py @@ -311,16 +311,26 @@ class GeometricSolver (Listener): def get_cluster(self): """Returns a GeometricCluster (the root of a tree of clusters), describing the solutions and the decomposition of the problem.""" + # several drcluster can maps to a single geoclusters map = {} + geoclusters = [] # map dr clusters for drcluster in self.dr.rigids(): - # create geo cluster and map to drcluster (and vice versa) - geocluster = GeometricCluster() - map[drcluster] = geocluster - map[geocluster] = drcluster - # determine variables - for var in drcluster.vars: - geocluster.variables.append(var) + # create geocluster and map to drcluster (and vice versa) + geocluster = GeometricCluster(drcluster.vars) + if geocluster not in map: + map[drcluster] = geocluster + map[geocluster] = [drcluster] + geoclusters.append(geocluster) + else: + geocluster = map[map[geocluster][0]] + map[drcluster] = geocluster + map[geocluster].append(drcluster) + + for geocluster in geoclusters: + # pick drcluster with fewest solutions + drclusters = map[geocluster] + drcluster = min(drclusters, key=lambda c: len(self.dr.get(drcluster))) # determine solutions solutions = self.dr.get(drcluster) underconstrained = False @@ -332,44 +342,33 @@ class GeometricSolver (Listener): # determine flag if drcluster.overconstrained: geocluster.flag = GeometricCluster.S_OVER + elif geocluster.solutions == None: + geocluster.flag = GeometricCluster.UNSOLVED elif len(geocluster.solutions) == 0: geocluster.flag = GeometricCluster.I_OVER elif underconstrained: geocluster.flag = GeometricCluster.I_UNDER else: geocluster.flag = GeometricCluster.OK - + + # determine subclusters for method in self.dr.methods(): + if not isinstance(method, PrototypeMethod) and not isinstance(method, SelectionMethod): for out in method.outputs(): if isinstance(out, Rigid): parent = map[out] for inp in method.inputs(): if isinstance(inp, Rigid): - parent.subs.append(map[inp]) + sub = map[inp] + if sub != parent: + parent.subs.append(sub) - # combine clusters due to selection - if True: - for method in self.dr.methods(): - if isinstance(method, PrototypeMethod): - incluster = method.inputs()[0] - outcluster = method.outputs()[0] - geoin = map[incluster] - geoout = map[outcluster] - geoout.subs = list(geoin.subs) - for method in self.dr.methods(): - if isinstance(method, SelectionMethod): - incluster = method.inputs()[0] - outcluster = method.outputs()[0] - geoin = map[incluster] - geoout = map[outcluster] - geoout.subs = list(geoin.subs) - # determine top-level result rigids = filter(lambda c: isinstance(c, Rigid), self.dr.top_level()) if len(rigids) == 0: # no variables in problem? - result = GeometricCluster() + result = GeometricCluster(self.problem.cg.variables()) result.variables = [] result.subs = [] result.solutions = [] @@ -379,12 +378,13 @@ class GeometricSolver (Listener): result = map[rigids[0]] else: # structurally underconstrained cluster - result = GeometricCluster() + result = GeometricCluster(self.problem.cg.variables()) result.flag = GeometricCluster.S_UNDER for rigid in rigids: result.subs.append(map[rigid]) return result + def get_solutions(self): """Returns a list of Configurations, which will be empty if the problem has no solutions. Note: this method is @@ -647,13 +647,22 @@ class GeometricCluster: UNSOLVED = "unsolved" EMPTY = "empty" - def __init__(self): + def __init__(self, variables): """initialise an empty new cluster""" - self.variables = [] + self.variables = frozenset(variables) self.solutions = [] self.subs = [] self.flag = GeometricCluster.OK + def __eq__(self, other): + if isinstance(other, GeometricCluster): + return self.variables == other.variables + else: + return False + + def __hash__(self): + return hash(self.variables) + def __str__(self): return self._str_recursive() @@ -679,7 +688,7 @@ class GeometricCluster: s = s + spaces + "|...\n" # pritn cluster - s = spaces + "cluster " + str(result.variables) + " " + str(result.flag) + " " + str(len(result.solutions)) + " solutions\n" + s + s = spaces + "cluster " + str(list(result.variables)) + " " + str(result.flag) + " " + str(len(result.solutions)) + " solutions\n" + s return s # def diff --git a/workbench/compositionView.py b/workbench/compositionView.py index da4f088..c9ad3b0 100644 --- a/workbench/compositionView.py +++ b/workbench/compositionView.py @@ -5,324 +5,324 @@ from cvitems import CVCluster, CVPoint, CVInfoOverlay, CVConnection from parameters import Settings 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 + """ 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 & )"), 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() + 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 & )"), 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 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) + 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) + 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) + self.ui.graphicsView.setMatrix(matrix) diff --git a/workbench/cvitems.py b/workbench/cvitems.py index c23b17f..c60c282 100644 --- a/workbench/cvitems.py +++ b/workbench/cvitems.py @@ -1,601 +1,77 @@ from includes import * -from tree import Node from geosolver import GeometricCluster from parameters import Settings -class CVCluster(QtGui.QGraphicsItem, Node): - """ Visualisation of the clusters (nodes) in the decompositionView """ - def __init__(self, compView, parentNode, id, parent=None): - QtGui.QGraphicsItem.__init__(self, parent) - Node.__init__(self, parentNode) - - self.compositionView = compView - self.setFlags(QtGui.QGraphicsItem.ItemIsSelectable) - self.setAcceptsHoverEvents(True) - self.startAngle = 0 - self.spanAngle = 0 - self.paintRect = QtCore.QRectF(0, 0, self.width, self.height) - self.boundary = QtCore.QRectF(0.0, 0.0, 0.0, 0.0) - self.fixGraphic = QtGui.QGraphicsSimpleTextItem("F", self) - - self.identifier = id - - self.bezierCurve = None - self.initAngles() - self.bound = QtCore.QRectF() - self.updateBound() - self.flag = None - self.clusterHighlight = None - self.permCluster = None - self.clusterActive = False - self.fixGraphic.hide() - - def initAngles(self): - """ Initialize the angles for the visual representation of the nodes, these are dependent on the orientation of the tree """ - self.startAngle = 60 * 16 - self.spanAngle = 60 * 16 - - if self.compositionView.tree.orientation == TreeOrientation.BOTTOM: - self.startAngle = -self.startAngle - self.spanAngle = -self.spanAngle - elif self.compositionView.tree.orientation == TreeOrientation.LEFT: - self.startAngle = self.startAngle + 90 * 16 - elif self.compositionView.tree.orientation == TreeOrientation.RIGHT: - self.startAngle = self.startAngle - 90 * 16 - - def updateBound(self): - """ The bound where the user can click in to do a certain action, is set here. This bound is tightly set around the object """ - pointBegin = QtCore.QPointF(0.0, 0.0) - pointBegin.setX((self.paintRect.width()/2.0) * math.cos(math.radians(self.startAngle/16.0))) - pointBegin.setY((self.paintRect.height()/2.0) * math.sin(math.radians(self.startAngle/16.0))) - - pointEnd = QtCore.QPointF(0.0, 0.0) - pointEnd.setX((self.paintRect.width()/2.0) * math.cos(math.radians((self.startAngle+self.spanAngle)/16.0))) - pointEnd.setY((self.paintRect.height()/2.0) * math.sin(math.radians((self.startAngle+self.spanAngle)/16.0))) - - pointMiddle = QtCore.QPointF(0.0, 0.0) - halfDegree = (self.startAngle+(self.spanAngle/2.0))/16.0 - pointMiddle.setX((self.paintRect.width()/2.0) * math.cos(math.radians(halfDegree))) - pointMiddle.setY((self.paintRect.height()/2.0) * math.sin(math.radians(halfDegree))) - - if pointBegin.x() < pointMiddle.x() and pointBegin.x() < pointEnd.x(): - self.boundary.setLeft(pointBegin.x()) - elif pointMiddle.x() < pointEnd.x(): - self.boundary.setLeft(pointMiddle.x()) - else: - self.boundary.setLeft(pointEnd.x()) - - if self.boundary.left() > 0.0: - self.boundary.setLeft(0.0) - - if pointBegin.x() > pointMiddle.x() and pointBegin.x() > pointEnd.x(): - self.boundary.setRight(pointBegin.x()) - elif pointMiddle.x() > pointEnd.x(): - self.boundary.setRight(pointMiddle.x()) - else: - self.boundary.setRight(pointEnd.x()) - - if self.boundary.right() < 0.0: - self.boundary.setRight(0.0) - - if pointBegin.y() < pointMiddle.y() and pointBegin.y() < pointEnd.y(): - self.boundary.setBottom(pointBegin.y()) - elif pointMiddle.y() < pointEnd.y(): - self.boundary.setBottom(pointMiddle.y()) - else: - self.boundary.setBottom(pointEnd.y()) - - if self.boundary.bottom() > 0.0: - self.boundary.setBottom(0.0) - - if pointBegin.y() > pointMiddle.y() and pointBegin.y() > pointEnd.y(): - self.boundary.setTop(pointBegin.y()) - elif pointMiddle.y() > pointEnd.y(): - self.boundary.setTop(pointMiddle.y()) - else: - self.boundary.setTop(pointEnd.y()) - - if self.boundary.top() < 0.0: - self.boundary.setTop(0.0) - - self.__translateBound() +class CVCluster(QtGui.QGraphicsItem): + """ Visualisation of the clusters (nodes) in the decompositionView """ + def __init__(self, compView, cluster, x,y): + QtGui.QGraphicsItem.__init__(self) + + self.compositionView = compView + self.cluster = cluster + self.position = QtCore.QPointF(x, y) - - def __translateBound(self): - """ Translation of the boundary, so that it fits exactly around the figure""" - self.boundary.setLeft(self.boundary.left()+self.paintRect.center().x()) - self.boundary.setRight(self.boundary.right()+self.paintRect.center().x()) - self.boundary.setTop(-self.boundary.top()+self.paintRect.center().y()) - self.boundary.setBottom(-self.boundary.bottom()+self.paintRect.center().y()) - - def shape(self): - """ Overridden function to set the boundary wherein the user can perform an action """ - path = QtGui.QPainterPath() - path.addRect(self.boundary) - return path - - def boundingRect(self): - """ Overridden function where a update area is determined for painting and returned """ - return self.paintRect - - def paint(self, painter, option, widget): - """ Visualisation of a clusteritem """ - painter.setPen(QtGui.QColor(0,155,50)) + self.textGraphic = QtGui.QGraphicsSimpleTextItem(str(list(self.cluster.variables)), self) + #self.textGraphic.translate(x,y) + self.paintRect = self.textGraphic.boundingRect() + #self.paintRect.translate(x,y) + self.translate(x,y) + + def boundingRect(self): + """ Overridden function where a update area is determined for painting and returned """ + return self.paintRect + + def paint(self, painter, option, widget): + """ Visualisation of a clusteritem """ + painter.setPen(QtGui.QColor(0,155,50)) - if self.flag != None: - if self.flag == GeometricCluster.OK: - painter.setBrush(QtGui.QBrush(self.compositionView.wellConstrainedColor)) - elif self.flag == GeometricCluster.I_UNDER or self.flag == GeometricCluster.S_UNDER: - painter.setBrush(QtGui.QBrush(self.compositionView.underConstrainedColor)) - elif self.flag == GeometricCluster.I_OVER or self.flag == GeometricCluster.S_OVER: - painter.setBrush(QtGui.QBrush(self.compositionView.overConstrainedColor)) - elif self.flag == GeometricCluster.UNSOLVED: - painter.setBrush(QtGui.QBrush(self.compositionView.unsolvedColor)) - painter.drawPie(self.paintRect, self.startAngle, self.spanAngle) - - def setInfoOverlay(self): - constrInfo = QtCore.QString("") - if self.flag == GeometricCluster.OK: - constrInfo = QtCore.QString("Well-Constrained\n") - elif self.flag == GeometricCluster.I_UNDER: - constrInfo = QtCore.QString("Inc. Underconstrained\n") - elif self.flag == GeometricCluster.S_UNDER: - constrInfo = QtCore.QString("Struct. Underconstrained\n") - elif self.flag == GeometricCluster.I_OVER: - constrInfo = QtCore.QString("Inc. Overconstrained\n") - elif self.flag == GeometricCluster.S_OVER: - constrInfo = QtCore.QString("Struct. Overconstrained\n") - elif self.flag == GeometricCluster.UNSOLVED: - constrInfo = QtCore.QString("Unsolved\n") - constrInfo.append("Points: ") - - for point in self.variables: - pointObject = self.compositionView.prototypeManager.getObjectByKey(point) - if pointObject != None: - constrInfo.append(pointObject.name) - if point != self.variables[-1]: - constrInfo.append(", ") - - self.compositionView.infoOverlay.infoText = constrInfo - - #painter.setBrush(QtCore.Qt.NoBrush) - #painter.drawRect(self.bound) - - def mousePressEvent(self, event): - """ Handling the mouse press, where the cluster (visualisation) and tree can be updated - - Parameters: - event - pressed mousebutton - """ - if event.button() == QtCore.Qt.LeftButton: - self.updateCluster() - self.updateBound() - self.compositionView.updateTree() - elif event.button() == QtCore.Qt.RightButton: - if not self.clusterActive: - self.permanentCluster() - self.clusterActive = True - self.fixGraphic.show() - self.compositionView.stateChange(self.identifier, True) - else: - self.compositionView.prototypeManager.removeClusterObjects([self.permCluster], True, True) - self.clusterActive = False - self.fixGraphic.hide() - self.compositionView.stateChange(self.identifier, False) - self.permCluster = None - self.compositionView.prototypeManager.setObjectVisibilityByClusters() - self.compositionView.updateViewports() - - def hoverEnterEvent(self, event): - self.setZValue(2) - self.setInfoOverlay() - self.compositionView.infoOverlay.setPosition(event.scenePos()) - self.compositionView.infoOverlay.show() - if not self.clusterActive: - self.compositionView.prototypeManager.selectObjectsByKeys(self.variables) - self.highlightCluster() - self.compositionView.update() - self.compositionView.updateViewports() - - def hoverMoveEvent(self, event): - self.overlayPosition = self.compositionView.ui.graphicsView.mapFromScene(event.scenePos()) - self.compositionView.infoOverlay.setPosition(event.scenePos()) - - self.compositionView.updateConnections() - self.compositionView.update() - - def hoverLeaveEvent(self, event): - self.setZValue(0) - self.compositionView.infoOverlay.infoText = "" - self.compositionView.infoOverlay.hide() - self.compositionView.infoOverlay.update() - if not self.clusterActive: - self.compositionView.prototypeManager.deselectAllObjects() - self.compositionView.prototypeManager.removeClusterObjects([self.clusterHighlight], True, False) - self.compositionView.updateViewports() - - def updateCluster(self): - """ Cluster update, where the cluster is (un-)collapsed depending on the state of the cluster, to visualise a certain part of the tree """ - if self.canCollapse: - if self.isCollapsed: - self.isCollapsed = False - self.showChildren() - height = self.paintRect.height()*0.5 - width = self.paintRect.width()*0.5 - height2 = self.paintRect.height() - if self.compositionView.tree.orientation == TreeOrientation.TOP: - self.paintRect.setTop(self.paintRect.top() + height ) - self.paintRect.setBottom(self.paintRect.bottom() + height) - elif self.compositionView.tree.orientation == TreeOrientation.BOTTOM: - self.paintRect.setTop(self.paintRect.top()- height ) - self.paintRect.setBottom(self.paintRect.bottom() - height) - elif self.compositionView.tree.orientation == TreeOrientation.LEFT: - self.paintRect.setLeft(self.paintRect.left() + width) - self.paintRect.setRight(self.paintRect.right() + width) - elif self.compositionView.tree.orientation == TreeOrientation.RIGHT: - self.paintRect.setLeft(self.paintRect.left() - width) - self.paintRect.setRight(self.paintRect.right() - width) - else: - self.isCollapsed = True - self.showChildren() - height = self.paintRect.height()*0.5 - width = self.paintRect.width()*0.5 - height2 = self.paintRect.height() - if self.compositionView.tree.orientation == TreeOrientation.TOP: - self.paintRect.setTop(self.paintRect.top() - height) - self.paintRect.setBottom(self.paintRect.bottom() - height) - elif self.compositionView.tree.orientation == TreeOrientation.BOTTOM: - self.paintRect.setTop(self.paintRect.top() + height) - self.paintRect.setBottom(self.paintRect.bottom() + height) - elif self.compositionView.tree.orientation == TreeOrientation.LEFT: - self.paintRect.setLeft(self.paintRect.left() - width) - self.paintRect.setRight(self.paintRect.right() - width) - elif self.compositionView.tree.orientation == TreeOrientation.RIGHT: - self.paintRect.setLeft(self.paintRect.left() + width) - self.paintRect.setRight(self.paintRect.right() + width) - - if self.compositionView.tree.orientation == TreeOrientation.LEFT or self.compositionView.tree.orientation == TreeOrientation.RIGHT: - self.startAngle = self.startAngle + 180 * 16 - else: - self.startAngle = -self.startAngle - self.spanAngle = -self.spanAngle - - def highlightCluster(self): - if self.clusterHighlight != None: - if self.clusterHighlight.temporary: - self.compositionView.prototypeManager.addClusterObject(self.clusterHighlight) - self.clusterHighlight.selected = True - else: - self.clusterHighlight = self.compositionView.prototypeManager.selectClusterObjectByKeys(self.variables) - if self.clusterHighlight == None: - self.clusterHighlight = self.compositionView.prototypeManager.createCluster(self.variables) - if self.clusterHighlight != None: - self.clusterHighlight.temporary = True - if self.clusterHighlight != None: - self.clusterHighlight.selected = True - - def permanentCluster(self): - if self.permCluster == None: - self.permCluster = self.compositionView.prototypeManager.createCluster(self.variables, self.flag) - self.permCluster.temporary = True - self.permCluster.fixed = True - self.compositionView.prototypeManager.setObjectVisibilityByClusters() - else: - self.compositionView.prototypeManager.addClusterObject(self.permCluster) - self.permCluster.selected = False - - def showChildren(self): - """ Show the children of this node """ - if self.isCollapsed or (self.isVisible()==False): - for child in self.children: - child.hide() - child.showChildren() - if child.clusterActive: - child.fixGraphic.hide() - else: - for child in self.children: - child.show() - child.showChildren() - if child.clusterActive: - child.fixGraphic.show() - else: - child.fixGraphic.hide() - - def collapseFromResult(self): - if self.flag == GeometricCluster.I_UNDER or self.flag == GeometricCluster.S_UNDER or self.flag == GeometricCluster.I_OVER or self.flag == GeometricCluster.S_OVER or self.flag == GeometricCluster.UNSOLVED: - return True - else: - return False - - def collapse(self): - if not self.isCollapsed: - self.updateCluster() - self.updateBound() - - def expand(self): - if self.isCollapsed: - self.updateCluster() - self.updateBound() - -class CVPoint(QtGui.QGraphicsItem, Node): - """ Visualisation of the leaves of the 'leaf' clusters in the tree """ - def __init__(self, compView, parentNode, id, parent=None): - QtGui.QGraphicsItem.__init__(self, parent) - Node.__init__(self, parentNode) - - self.compositionView = compView - self.setFlags(QtGui.QGraphicsItem.ItemIsSelectable) - self.setAcceptsHoverEvents(True) - self.startAngle = 0 - self.spanAngle = 0 - self.paintRect = QtCore.QRectF(0, 0, self.width/2, self.height/2) - self.fixGraphic = QtGui.QGraphicsSimpleTextItem("F", self) - self.fixGraphic.hide() - self.bezierCurve = None - self.flag = None - self.prtRef = None - self.boundary = self.paintRect - self.clusterHighlight = None - self.permCluster = None - self.clusterActive = False - self.identifier = id - - def paint(self, painter, option, widget): - painter.setPen(QtGui.QColor(0,155,50)) - painter.setBrush(QtGui.QBrush(QtGui.QColor(0,155,50))) - painter.drawEllipse(self.paintRect) - - def setInfoOverlay(self): - constrInfo = QtCore.QString("Points \n") - if self.prtRef != None: - constrInfo += "Name: " + self.prtRef.name + "\n" - constrInfo += "Position: (" + str(round(self.prtRef.position[0],2)) + " , " + str(round(self.prtRef.position[1])) + " , " + str(round(self.prtRef.position[2])) + ")" - self.compositionView.infoOverlay.infoText = constrInfo - - def mousePressEvent(self, event): - """ Handling the mouse press, where the cluster (visualisation) is handled - - Parameters: - event - pressed mousebutton - """ - if event.button() == QtCore.Qt.RightButton: - if not self.clusterActive: - self.permanentCluster() - self.clusterActive = True - self.fixGraphic.show() - self.compositionView.stateChange(self.identifier, True) - else: - self.compositionView.prototypeManager.removeClusterObjects([self.permCluster], True, True) - self.clusterActive = False - self.permCluster = None - self.fixGraphic.hide() - self.compositionView.stateChange(self.identifier, False) - self.compositionView.prototypeManager.setObjectVisibilityByClusters() - self.compositionView.updateViewports() - - def hoverEnterEvent(self, event): - self.setZValue(2) - self.setInfoOverlay() - self.compositionView.infoOverlay.setPosition(event.scenePos()) - self.compositionView.infoOverlay.show() - - if not self.clusterActive: - self.compositionView.prototypeManager.selectObject(self.prtRef) - self.highlightCluster() - self.compositionView.update() - self.compositionView.updateViewports() - - def hoverMoveEvent(self, event): - self.compositionView.infoOverlay.setPosition(event.scenePos()) - self.compositionView.update() - - def hoverLeaveEvent(self, event): - self.setZValue(0) - self.compositionView.infoOverlay.infoText = "" - self.compositionView.infoOverlay.hide() - self.compositionView.infoOverlay.update() - if not self.clusterActive: - self.compositionView.prototypeManager.deselectAllObjects() - self.compositionView.prototypeManager.removeClusterObjects([self.clusterHighlight], True) - self.compositionView.updateViewports() - - def highlightCluster(self): - if self.clusterHighlight != None: - if self.clusterHighlight.temporary: - self.compositionView.prototypeManager.addClusterObject(self.clusterHighlight) - self.clusterHighlight.selected = True - else: - self.clusterHighlight = self.compositionView.prototypeManager.selectClusterObjectByKeys([self.prtRef.key]) - if self.clusterHighlight == None: - self.clusterHighlight = self.compositionView.prototypeManager.createCluster([self.prtRef.key]) - if self.clusterHighlight != None: - self.clusterHighlight.temporary = True - if self.clusterHighlight != None: - self.clusterHighlight.selected = True - - def permanentCluster(self): - if self.permCluster == None: - self.permCluster = self.compositionView.prototypeManager.createCluster([self.prtRef.key]) - self.permCluster.temporary = True - self.permCluster.fixed = True - self.compositionView.prototypeManager.setObjectVisibilityByClusters() - else: - self.compositionView.prototypeManager.addClusterObject(self.permCluster) - self.permCluster.selected = False - - def boundingRect(self): - return self.paintRect - - def setWidthAndHeight(self, width, height): - self.width = width - self.height = height - self.paintRect.setWidth(width) - self.paintRect.setHeight(height) - - def showChildren(self): - """ Show the children of this node """ - if self.isCollapsed or (self.isVisible()==False): - for child in self.children: - child.hide() - child.showChildren() - else: - for child in self.children: - child.show() - child.showChildren() - - def collapse(self): - self.isCollapsed = True - - def expand(self): - self.isCollapsed = False - -class CVInfoOverlay(QtGui.QGraphicsItem): - def __init__(self, compView, parent=None): - QtGui.QGraphicsItem.__init__(self, parent) - self.node = None - self.compositionView = compView - self.infoText = QtCore.QString("") - self.setZValue(3) - self.infoOverlay = QtCore.QRectF(0, 0, 140, 50) - self.overlayPosition = QtCore.QPointF() - self.scenePosition = QtCore.QPointF() - - self.overlayBGColor = QtGui.QColor(204, 251, 255, 200) - self.overlayLineColor = QtGui.QColor(33, 116, 154) - self.overlayTextColor = QtGui.QColor(0, 0, 0) - - def paint(self, painter, option, widget): - painter.save() - painter.resetMatrix() - painter.translate(self.overlayPosition) - painter.translate(10.0, 10.0) - painter.setPen(self.overlayLineColor) - painter.setBrush(self.overlayBGColor) - painter.drawRect(self.infoOverlay) - - infoFont = QtGui.QFont("Arial", 7) - infoFont.setStyleStrategy(QtGui.QFont.ForceOutline) - painter.setFont(infoFont) - painter.setRenderHint(QtGui.QPainter.TextAntialiasing, False) - painter.setPen(self.overlayTextColor) - textRect = QtCore.QRect(self.infoOverlay.left()+4, self.infoOverlay.top(), self.infoOverlay.width()-3, self.infoOverlay.height()-3) - - painter.drawText(textRect, QtCore.Qt.AlignLeft|QtCore.Qt.TextWordWrap, self.infoText) - painter.restore() - - def setPosition(self, position): - self.scenePosition = position - self.overlayPosition = self.compositionView.ui.graphicsView.mapFromScene(position) - - def boundingRect(self): - check = QtCore.QRectF(self.infoOverlay) - return check - + if self.cluster.flag != None: + if self.cluster.flag == GeometricCluster.OK: + painter.setBrush(QtGui.QBrush(self.compositionView.wellConstrainedColor)) + elif self.cluster.flag == GeometricCluster.I_UNDER or self.cluster.flag == GeometricCluster.S_UNDER: + painter.setBrush(QtGui.QBrush(self.compositionView.underConstrainedColor)) + elif self.cluster.flag == GeometricCluster.I_OVER or self.cluster.flag == GeometricCluster.S_OVER: + painter.setBrush(QtGui.QBrush(self.compositionView.overConstrainedColor)) + elif self.cluster.flag == GeometricCluster.UNSOLVED: + painter.setBrush(QtGui.QBrush(self.compositionView.unsolvedColor)) + painter.drawRect(self.paintRect) + + + class CVConnection(QtGui.QGraphicsItem): - """ Visualisation of the connections between the clusters, where two types of visualisation can be chosen: Bezier(default) and Lines """ - def __init__(self, compView, nodeFrom , nodeTo, parent=None): - QtGui.QGraphicsItem.__init__(self, parent) - self.settings = Settings() - self.compositionView = compView - self.nodeFrom = nodeFrom - self.nodeTo = nodeTo - self.connectType = self.settings.dvData.treeConnection - #self.boundRect = QtCore.QRectF(0.0, 0.0, 0.0, 0.0) - self.beziercurve = None - self.paintRect = QtCore.QRectF(0, 0, 0, 0) - self.setZValue(1) - - def paint(self, painter, option, widget): - """ Visualisation of the connection between two nodes """ - if self.nodeFrom != None and self.nodeTo != None: - painter.setPen(QtGui.QColor(0,0,0)) - - diffPosExt = self.paintRect - endPoint = self.determineEndpoint(diffPosExt) + """ Visualisation of the connections between the clusters, where two types of visualisation can be chosen: Bezier(default) and Lines """ + def __init__(self, compView, nodeFrom , nodeTo): + QtGui.QGraphicsItem.__init__(self) + self.settings = Settings() + self.compositionView = compView + self.nodeFrom = nodeFrom + self.nodeTo = nodeTo + self.beziercurve = None + self.paintRect = None + self.setZValue(1) + + self.determinePath() - if self.connectType == ConnectionType.BEZIER: - """ display a bezier curve as connection """ - self.beziercurve = QtGui.QPainterPath() - - if self.compositionView.tree.orientation == TreeOrientation.TOP: - self.beziercurve.moveTo(diffPosExt.x(), diffPosExt.y()) - firstPoint = QtCore.QPointF(diffPosExt.x(), diffPosExt.height()*0.5) - elif self.compositionView.tree.orientation == TreeOrientation.BOTTOM: - self.beziercurve.moveTo(diffPosExt.x(), diffPosExt.bottom()) - firstPoint = QtCore.QPointF(diffPosExt.x(), -diffPosExt.height()*0.5 + self.nodeTo.paintRect.height()) - elif self.compositionView.tree.orientation == TreeOrientation.LEFT: - self.beziercurve.moveTo(diffPosExt.x(), diffPosExt.y()) - firstPoint = QtCore.QPointF(diffPosExt.width()*0.5, diffPosExt.y()) - elif self.compositionView.tree.orientation == TreeOrientation.RIGHT: - self.beziercurve.moveTo(diffPosExt.x(), diffPosExt.y()) - firstPoint = QtCore.QPointF(self.nodeTo.paintRect.width() + diffPosExt.width()*0.5,diffPosExt.y()) - - if self.compositionView.tree.orientation == TreeOrientation.TOP: - secondPoint = QtCore.QPointF(diffPosExt.right(),diffPosExt.height()*0.5) - elif self.compositionView.tree.orientation == TreeOrientation.BOTTOM: - secondPoint = QtCore.QPointF(diffPosExt.right(), self.nodeTo.paintRect.height() - diffPosExt.height()*0.5) - elif self.compositionView.tree.orientation == TreeOrientation.LEFT: - secondPoint = QtCore.QPointF(diffPosExt.width()*0.5, diffPosExt.bottom()) - elif self.compositionView.tree.orientation == TreeOrientation.RIGHT: - secondPoint = QtCore.QPointF(self.nodeTo.paintRect.width() + diffPosExt.width()*0.5, diffPosExt.bottom()) - - self.beziercurve.cubicTo(firstPoint, secondPoint, endPoint) - painter.drawPath(self.beziercurve) - - elif self.connectType == ConnectionType.LINES: - """ draw a straight line """ - if self.compositionView.tree.orientation == TreeOrientation.TOP: - painter.drawLine(QtCore.QPointF(self.nodeTo.paintRect.width()*0.5, 0.0), QtCore.QPointF(endPoint.x(), endPoint.y())) - elif self.compositionView.tree.orientation == TreeOrientation.BOTTOM: - painter.drawLine(QtCore.QPointF(self.nodeTo.paintRect.width()*0.5, self.nodeTo.paintRect.height()), QtCore.QPointF(endPoint.x(), endPoint.y())) - elif self.compositionView.tree.orientation == TreeOrientation.LEFT: - painter.drawLine(QtCore.QPointF(0.0, self.nodeTo.paintRect.height()*0.5), QtCore.QPointF(endPoint.x(), endPoint.y())) - elif self.compositionView.tree.orientation == TreeOrientation.RIGHT: - painter.drawLine(QtCore.QPointF(self.nodeTo.paintRect.width(), self.nodeTo.paintRect.height()*0.5), QtCore.QPointF(endPoint.x(), endPoint.y())) - - def areaBetweenNodes(self): - diffPos = self.nodeTo.position - self.nodeFrom.position - area = QtCore.QRectF(0.0, 0.0, 0.0 , 0.0) - if self.compositionView.tree.orientation == TreeOrientation.TOP: - area.setX(self.nodeTo.paintRect.width()*0.5) - area.setY(0.0) - area.setRight(self.nodeFrom.paintRect.width()*0.5 - diffPos.x()) - area.setBottom(self.nodeTo.boundary.height()-diffPos.y()) - elif self.compositionView.tree.orientation == TreeOrientation.BOTTOM: - area.setX(self.nodeTo.paintRect.width()*0.5) - area.setY(-diffPos.y()+self.nodeFrom.boundary.height()) - area.setRight(-diffPos.x()+self.nodeFrom.paintRect.width()*0.5) - area.setBottom(self.nodeTo.paintRect.height()) - elif self.compositionView.tree.orientation == TreeOrientation.LEFT: - area.setX(0.0) - area.setY(self.nodeTo.paintRect.height()*0.5) - area.setRight(-diffPos.x()+self.nodeFrom.boundary.width()) - area.setBottom(-diffPos.y() + self.nodeFrom.paintRect.height()*0.5) - elif self.compositionView.tree.orientation == TreeOrientation.RIGHT: - area.setX(self.nodeTo.paintRect.width()) - area.setY(self.nodeTo.paintRect.height()*0.5) - area.setRight(-diffPos.x() + self.nodeFrom.paintRect.width()*0.5) - area.setBottom(-diffPos.y() + self.nodeFrom.paintRect.height()*0.5) - return area - - def determineEndpoint(self, area): - endPoint = QtCore.QPointF(0.0, 0.0) - - if self.compositionView.tree.orientation == TreeOrientation.TOP: - endPoint.setX(area.right()) - endPoint.setY(area.height()) - elif self.compositionView.tree.orientation == TreeOrientation.BOTTOM: - endPoint.setX(area.right()) - endPoint.setY(area.y()) - elif self.compositionView.tree.orientation == TreeOrientation.LEFT: - endPoint.setX(area.right()) - endPoint.setY(area.bottom()) - elif self.compositionView.tree.orientation == TreeOrientation.RIGHT: - endPoint.setX(area.right()) - endPoint.setY(area.bottom()) - return endPoint - - def boundingRect(self): - """ Overridden function where a update area is determined for painting and returned """ - self.paintRect = self.areaBetweenNodes() - return self.paintRect + def determinePath(self): + if self.nodeFrom != None and self.nodeTo != None: + self.beziercurve = QtGui.QPainterPath() + x1 = self.nodeFrom.position.x() + self.nodeFrom.paintRect.width()/2 + x2 = self.nodeTo.position.x() + self.nodeTo.paintRect.width()/2 + y1 = self.nodeFrom.position.y() + y2 = self.nodeTo.position.y() + self.nodeFrom.paintRect.height() + p1 = QtCore.QPointF(x1,y1) + p2 = QtCore.QPointF(x1,y1+(y2-y1)/2) + p3 = QtCore.QPointF(x2,y1+(y2-y1)/2) + p4 = QtCore.QPointF(x2,y2) + self.beziercurve.moveTo(p1) + self.beziercurve.cubicTo(p2,p3,p4) + + def paint(self, painter, option, widget): + """ Visualisation of the connection between two nodes """ + if self.beziercurve: + painter.drawPath(self.beziercurve) + + def boundingRect(self): + """ Overridden function where a update area is determined for painting and returned """ + return self.beziercurve.boundingRect() + diff --git a/workbench/main.py b/workbench/main.py index f9fd223..91dd1b8 100644 --- a/workbench/main.py +++ b/workbench/main.py @@ -1,4 +1,4 @@ -import preferencesDlg, compositionView +import preferencesDlg, decompositionView from includes import * from viewportManager import * from prototypeObjects import PrototypeManager @@ -191,7 +191,7 @@ class Ui_MainWindow(QtGui.QMainWindow): self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.dock) def createDecompositionView(self): - self.compositionView = CompositionView(None, self.viewportManager, ViewportType.DECOMPOSITION ,PrototypeManager()) + self.compositionView = DecompositionView(None, self.viewportManager, ViewportType.DECOMPOSITION ,PrototypeManager()) def createSolutionView(self): self.solutionView = SolutionView(self, self.viewportManager, ViewportType.SOLUTION ,PrototypeManager()) diff --git a/workbench/solutionView.py b/workbench/solutionView.py index 364bf58..ea1cc2a 100644 --- a/workbench/solutionView.py +++ b/workbench/solutionView.py @@ -6,7 +6,7 @@ from parameters import Settings class SolutionView(QtGui.QDialog): """ Visualises the solution from the constraint solver. """ def __init__(self, mainWindow, viewportMngr, vpType, prototypeMngr, isViewport=False, parent=None): - """ Initialization of the CompositionView class + """ Initialization of the SolutionView class Parameters: mainWindow - main window of the application, necessary for updating diff --git a/workbench/viewport.py b/workbench/viewport.py index 0c502af..90d6c1f 100644 --- a/workbench/viewport.py +++ b/workbench/viewport.py @@ -1,5 +1,5 @@ from includes import * -from compositionView import CompositionView +from decompositionView import DecompositionView from solutionView import SolutionView from prototypeObjects import PrototypeManager from glViewer import * @@ -153,7 +153,7 @@ class Viewport(QtGui.QScrollArea): elif viewportName == "Perspective": self.glViewport = GLViewport(self, ViewportType.PERSPECTIVE, None, QtOpenGL.QGLFormat(QtOpenGL.QGL.SampleBuffers)) elif viewportName == "Decomposition": - self.glViewport = CompositionView(self, self.viewportManager, ViewportType.DECOMPOSITION, PrototypeManager()) #self.getMainWindow().compositionView # + self.glViewport = DecompositionView(self, self.viewportManager, ViewportType.DECOMPOSITION, PrototypeManager()) #self.getMainWindow().compositionView # elif viewportName == "Solution": self.solutionView = SolutionView(self.getMainWindow(), self.viewportManager, ViewportType.SOLUTION, PrototypeManager(), True) self.glViewport = self.solutionView.solutionWidget