diff --git a/Canvas.py b/Canvas.py index 9c177f08dfba47809fc2c689d18933ee282719f3..5a92710f6c53327bc3529ed66ef937a6d64daa01 100644 --- a/Canvas.py +++ b/Canvas.py @@ -54,13 +54,13 @@ class Canvas(QLabel): self.first_point = None self.second_point = None self.third_point = None - self.showing_spine = False + self.showing_layer = False self.last_graphs = [] self.next_graphs = [] self.graph = Path(Nodes = []) - self.spines = [] + self.layers = [] self.bad_node = [] self.bad_edge = [] @@ -142,7 +142,7 @@ class Canvas(QLabel): if (self.main_mode_ == MainMode.EDIT_MODE): self.last_graphs.append(deepcopy(self.graph)) self.next_graphs.clear() - self.spines.clear() + self.layers.clear() pen.setColor(Qt.black) painter.setPen(pen) painter.drawEllipse(QPoint(point[0],point[1]),7,7) @@ -160,7 +160,7 @@ class Canvas(QLabel): if (not self.graph.crosses() and self.graph.is_spanning_path()): self.last_graphs.append(deepcopy(self.graph)) self.next_graphs.clear() - self.spines.clear() + self.layers.clear() pen.setColor(Qt.black) painter.setPen(pen) painter.drawEllipse(QPoint(point[0],point[1]),7,7) @@ -281,7 +281,7 @@ class Canvas(QLabel): assert(node in self.graph.getNodes()) self.last_graphs.append(deepcopy(self.graph)) self.next_graphs.clear() - self.spines.clear() + self.layers.clear() pen.setColor(Qt.white) painter.setPen(pen) nodelist = self.graph.getNodes() @@ -358,11 +358,41 @@ class Canvas(QLabel): painter.drawEllipse(QPoint(self.second_point.get_coord()[0], self.second_point.get_coord()[1]),7,7) self.first_point, self.second_point, self.third_point = None,None,None + + def compute_ch(self): + self.layers.clear() + nodelist = deepcopy(self.graph.getNodes()) + while (nodelist): + graph_copy = Graph(Nodes=nodelist,Lines=[]) + if (len(nodelist) == 1): + convex_hull = Graph(Nodes=graph_copy.getNodes()) + self.layers.append(convex_hull) + nodelist = [node for node in nodelist if not node in convex_hull.getNodes()] + elif (len(nodelist) == 2): + convex_hull = Graph(Nodes=graph_copy.getNodes()) + first = convex_hull.getNodes()[0] + second = convex_hull.getNodes()[1] + convex_hull.connect(first,second) + self.layers.append(convex_hull) + nodelist = [node for node in nodelist if not node in convex_hull.getNodes()] + else: + convex_hull = Graph(graph_copy.compute_ch()) + n = len(convex_hull.getNodes()) + for i in range(n-1): + first = convex_hull.getNodes()[i] + second = convex_hull.getNodes()[i+1] + convex_hull.connect(first,second) + first = convex_hull.getNodes()[0] + second = convex_hull.getNodes()[n-1] + convex_hull.connect(first,second) + self.layers.append(convex_hull) + nodelist = [node for node in nodelist if not node in convex_hull.getNodes()] + """ - Display the spine of the Node list on the screen. + Display the layer of the Node list on the screen. """ def show_ch(self): - self.spines.clear() + self.layers.clear() pen = QPen(Qt.darkGreen,Qt.DashLine) painter = QPainter(self.pixmap()) painter.setPen(pen) @@ -371,7 +401,7 @@ class Canvas(QLabel): graph_copy = Graph(Nodes=nodelist,Lines=[]) if (len(nodelist) == 1): convex_hull = Graph(Nodes=graph_copy.getNodes()) - self.spines.append(convex_hull) + self.layers.append(convex_hull) nodelist = [node for node in nodelist if not node in convex_hull.getNodes()] elif (len(nodelist) == 2): convex_hull = Graph(Nodes=graph_copy.getNodes()) @@ -379,7 +409,7 @@ class Canvas(QLabel): second = convex_hull.getNodes()[1] painter.drawLine(first.get_coord()[0],first.get_coord()[1],second.get_coord()[0],second.get_coord()[1]) convex_hull.connect(first,second) - self.spines.append(convex_hull) + self.layers.append(convex_hull) nodelist = [node for node in nodelist if not node in convex_hull.getNodes()] else: convex_hull = Graph(graph_copy.compute_ch()) @@ -393,12 +423,12 @@ class Canvas(QLabel): second = convex_hull.getNodes()[n-1] convex_hull.connect(first,second) painter.drawLine(first.get_coord()[0],first.get_coord()[1],second.get_coord()[0],second.get_coord()[1]) - self.spines.append(convex_hull) + self.layers.append(convex_hull) nodelist = [node for node in nodelist if not node in convex_hull.getNodes()] self.update() painter.end() - self.showing_spine = True - self.message.emit("Showing spine. Click anywhere to disable.") + self.showing_layer = True + self.message.emit("Showing layer. Click anywhere to disable.") """ Reset the whole Canvas and all member variables. @@ -413,7 +443,7 @@ class Canvas(QLabel): self.setPixmap(whiteboard) del self.graph self.graph = Path(Nodes=[],start=None, end=None, Lines=[]) - self.spines.clear() + self.layers.clear() self.i_ = 0 self.edge_diff = 0 self.message.emit("Cleared.") @@ -565,7 +595,7 @@ class Canvas(QLabel): fileName = QFileDialog.getSaveFileName(self,"Save Graph","./.grph","Graph Files (*.grph)") try: with open(fileName[0],"wb") as file: - pickle.dump((self.graph,self.main_mode_,self.sub_mode_), file, -1) + pickle.dump((self.graph,self.main_mode_,self.sub_mode_, self.size()), file, -1) except: self.message.emit("Save failed") @@ -576,14 +606,30 @@ class Canvas(QLabel): try: fileName = QFileDialog.getOpenFileName(self,"Load Graph", ".", "Graph Files (*.grph)") new_list = pickle.load(open(fileName[0],"rb")) - new_graph, new_main, new_sub = new_list[0], new_list[1], new_list[2] + new_graph, new_main, new_sub, new_size = new_list[0], new_list[1], new_list[2], new_list[3] if (new_main != self.main_mode_): self.main_mode_change.emit() self.sub_mode_change.emit(new_sub) self.graph = new_graph - self.spines.clear() + self.layers.clear() + if (new_size != self.size()): + r_w = self.size().width() / new_size.width() + r_h = self.size().height() / new_size.height() + graph = self.graph + for p in graph._Nodes: + p.set_coord(int(r_w * p._coord[0]), int(r_h * p._coord[1])) + for l in graph._Lines: + ps = l.getPoints() + p1, p2 = ps[0], ps[1] + new_p1 = (int(r_w * p1[0]), int(r_h * p1[1])) + new_p2 = (int(r_w * p2[0]), int(r_h * p2[1])) + l.setPoints(new_p1, new_p2) + whiteboard = QPixmap(self.size().width(), self.size().height()) + whiteboard.fill(Qt.white) + self.setPixmap(whiteboard) self.drawGraph() self.message.emit("Welcome again.") + except: self.message.emit("Load failed") @@ -680,6 +726,26 @@ class Canvas(QLabel): self.edge_diff = len(self.graph._Lines) + 1 - len(self.graph._Nodes) self.identify_problems() self.message.emit("Back to end") + + def resizeEvent(self,e): + r_w = e.size().width() / e.oldSize().width() + r_h = e.size().height() / e.oldSize().height() + graphs = [self.graph] + self.last_graphs + self.next_graphs + for graph in graphs: + for p in graph._Nodes: + p.set_coord(int(r_w * p._coord[0]), int(r_h * p._coord[1])) + for l in graph._Lines: + ps = l.getPoints() + p1, p2 = ps[0], ps[1] + new_p1 = (int(r_w * p1[0]), int(r_h * p1[1])) + new_p2 = (int(r_w * p2[0]), int(r_h * p2[1])) + l.setPoints(new_p1, new_p2) + self.width_ = e.size().width() + self.height_ = e.size().height() + whiteboard = QPixmap(e.size().width(), e.size().height()) + whiteboard.fill(Qt.white) + self.setPixmap(whiteboard) + self.drawGraph() """ Perform an action when a mouse button is released. @@ -692,7 +758,7 @@ class Canvas(QLabel): e: QtGui.QMouseEvent """ def mouseReleaseEvent(self, e): - if (self.showing_spine): + if (self.showing_layer): whiteboard = QPixmap(self.width_, self.height_) whiteboard.fill(Qt.white) self.setPixmap(whiteboard) @@ -709,7 +775,7 @@ class Canvas(QLabel): self.edge_diff = len(self.graph._Lines) + 1 - len(self.graph._Nodes) self.update() painter.end() - self.showing_spine = False + self.showing_layer = False self.message.emit(" ") else: if e.button() == Qt.LeftButton: @@ -807,34 +873,8 @@ class Canvas(QLabel): if (self.first_point == None): self.identify_problems() - # configure spines - self.spines.clear() - nodelist = deepcopy(self.graph.getNodes()) - while (nodelist): - graph_copy = Graph(Nodes=nodelist,Lines=[]) - if (len(nodelist) == 1): - convex_hull = Graph(Nodes=graph_copy.getNodes()) - self.spines.append(convex_hull) - nodelist = [node for node in nodelist if not node in convex_hull.getNodes()] - elif (len(nodelist) == 2): - convex_hull = Graph(Nodes=graph_copy.getNodes()) - first = convex_hull.getNodes()[0] - second = convex_hull.getNodes()[1] - convex_hull.connect(first,second) - self.spines.append(convex_hull) - nodelist = [node for node in nodelist if not node in convex_hull.getNodes()] - else: - convex_hull = Graph(graph_copy.compute_ch()) - n = len(convex_hull.getNodes()) - for i in range(n-1): - first = convex_hull.getNodes()[i] - second = convex_hull.getNodes()[i+1] - convex_hull.connect(first,second) - first = convex_hull.getNodes()[0] - second = convex_hull.getNodes()[n-1] - convex_hull.connect(first,second) - self.spines.append(convex_hull) - nodelist = [node for node in nodelist if not node in convex_hull.getNodes()] + # configure layers + self.compute_ch() def __hash__(self): return hash(self.canvas.graph, self.main_mode_, self.sub_mode_) \ No newline at end of file diff --git a/GraphClass.py b/GraphClass.py index 0ac93acf46841ee10c6fda050b1a09af8daa4841..17b3697b1446329c27776a4d8b949234a7c61fb9 100644 --- a/GraphClass.py +++ b/GraphClass.py @@ -32,6 +32,9 @@ class Node: def get_coord(self): return self._coord + def set_coord(self, x, y): + self._coord = (x,y) + """ Getter of coord member. @@ -116,6 +119,10 @@ class Line: def getPoints(self): return (self._point1, self._point2) + def setPoints(self, point1, point2): + self._point1 = point1 + self._point2 = point2 + """ Check if two Lines are equal. @@ -129,6 +136,7 @@ class Line: bool whether two Lines are the same. """ + def __eq__(self, line): return (self._point1 == line._point1 and self._point2 == line._point2) or (self._point1 == line._point2 and self._point2 == line._point1) @@ -445,7 +453,7 @@ class Graph: stack.append(nodelist[i]) return stack except: - print("Graph invalid") + pass """ Find all the Lines that intersect in the Path diff --git a/README.md b/README.md index aa88adb24268d8b3130ed8d19c7e7e9e97e2e21b..2590082c89ee5bdca65bec3678210c5849f9346c 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ spanning paths of general point set" ## General Information - + This software supports: - Planar path drawing @@ -17,23 +17,35 @@ This software supports: ## User Guide -### Button usage (From left to right) +## Button usage (From left to right, from up to down) + +### First Row + +**FLIP**: Switch between EDIT and FLIP mode. \ +(Modes can only be switched if the graph is a non crossing spanning path) + **NODE**: Adds a node and/or extend the path from an endpoint **EDGE**: Click on one node and then another, and an edge will be added. \ (Click on two already connected nodes does not work) -**DEL_NODE**: Deletes a node.\ -(THIS ALSO TRIGGERS AUTOMATIC PLANARITY DETECTION, USE AT YOUR OWN RISK) +**DEL_NODE**: Deletes a node. **DEL_EDGE**: Click on one node and then another, and an edge will be deleted (if exists). -**FLIP**: Click on three nodes A,B,C, then edge {A,B} will be deleted and edge {A,C} will be added. +**RANDOM**: Generate a random planar path on the same node set. + +**SOLVE**: Reconfigure the existing path to a canonical path (as defined in the thesis). + +**WRAP**: Reconfigure the existing canonical path to a wrapping path (as defined in th thesis). + +**Note:** Buttons in the first row is separated in EDIT and FLIP mode. \ +Available in **EDIT** mode: NODE, EDGE, DEL_EDGE, DEL_EDGE \ +Available in **FLIP** mode: RANDOM, SOLVE, WRAP -**CLEAR**: Clear the entire whiteboard. +### Second Row -**SPINES**: Draw the spines (layers of convex hulls). \ -(To stop it from showing, simply click elsewhere) +**CLEAR**: Clear the entire screen. **UNDO**: Undo the last change. @@ -43,25 +55,25 @@ This software supports: **TO_END**: Redo all changes. -**RANDOM**: Generate a random planar path on the same node set. - -**SOLVE**: Reconfigure the existing path to a canonical path (as defined in the thesis). \ -(Configure the **SPINES** before solving) - -**WRAP**: Reconfigure the existing canonical path to a wrapping path (as defined in th thesis). \ -(Make sure the path is **SOLVE**d and the **SPINES** are configured before wrapping) +**LAYERS**: Show the layers of convex hulls. \ +(To stop it from showing, simply click on the screen once) **SAVE**: Save the current graph (in a .grph file). **LOAD**: Load a graph from a .grph file. -### Additional functionalities: +### Third Row + +**ABOUT**: Load the about page. + +**HELP**: Load the help page that briefly explains the buttons' usage. + +## Additional functionalities: **Automatic planarity detection**: \ -If a graph is not a planar path, the program will check how the path can be fixed based on edge difference and suggest all solutions possible. +If a graph is not a planar path (i.e. non crossing and spanning), the program will check how the path can be fixed based on edge difference and suggest all solutions possible. **Simple edge operation**: \ -An edge can be deleted simply by right-clicking on an edge. Any edges (that can be added) suggested by the planarity detection can be added by simply left-clicking on the dotted line (as shown in the above image). \ -Note that the simple edge addition is only activated in **EDGE** mode to avoid unexpected edge addition. +An edge can be deleted simply by right-clicking on an edge. Any edge (that can be added) suggested by the planarity detection can be added by simply left-clicking on the dotted line (as shown in the above image). (only available in FLIP mode) ## Running the program @@ -81,7 +93,7 @@ python main.py ## Troubleshooting **Frozen whiteboard**: \ -In this case, **SAVE** the graph, relaunch the program and **LOAD** the saved graph again will work. +In this case, SAVE the graph, relaunch the program and LOAD the saved graph again will work. diff --git a/Screenshot_Program.png b/Screenshot_Program.png new file mode 100755 index 0000000000000000000000000000000000000000..657676c7915f1731096b5068981fc34aa56fa3cb Binary files /dev/null and b/Screenshot_Program.png differ diff --git a/Solver.py b/Solver.py index f91f716e651a63f564997444ca5dd9a99bba1005..fe9bdff7b90a1f0907299e1bd82a5f956a69a145 100644 --- a/Solver.py +++ b/Solver.py @@ -20,47 +20,47 @@ class Solver(QObject): self.previous_steps = [deepcopy(self._canvas.graph)] """ - Determine the spine, where the node lies. + Determine the layer, where the node lies. Parameters ---------- - spines: list[Graph] - The spine set. + layers: list[Graph] + The layer set. node: Node The node to be checked Returns ------- - spine: Graph - the spine, where the node lies. + layer: Graph + the layer, where the node lies. """ - def NodeWhichSpine(self,spines,node): - for spine in spines: - if (node in spine.getNodes()): - return spine + def NodeWhichlayer(self,layers,node): + for layer in layers: + if (node in layer.getNodes()): + return layer return None """ - Determine the spine, where the line lies. + Determine the layer, where the line lies. Parameters ---------- - spines: list[Graph] - The spine set. + layers: list[Graph] + The layer set. line: Line The line to be checked Returns ------- - spine: Graph - the spine, where the line lies. + layer: Graph + the layer, where the line lies. """ - def LineWhichSpine(self,spines,line): - for spine in spines: - if (line in spine.getLines()): - return spine + def LineWhichlayer(self,layers,line): + for layer in layers: + if (line in layer.getLines()): + return layer return None """ @@ -74,24 +74,24 @@ class Solver(QObject): path: Path The path - spines: list[Graph] - The spine set. + layers: list[Graph] + The layer set. node: Node The node to be checked """ - def boundary_alg(self,path: Path,spines,node: Node): + def boundary_alg(self,path: Path,layers,node: Node): assert (node in path.getNodes()) self.stopped = False painter = QPainter(self._canvas.pixmap()) pen = QPen() node_in_order = [] - # find which spine the point is in - spine = self.NodeWhichSpine(spines,node) - if (not len(spine.getNodes()) in [1,2]): - node_i_spine = spine.getNodes().index(node) - neighbor_node = [spine.getNodes()[node_i_spine - 1], - spine.getNodes()[(node_i_spine + 1) % len(spine.getNodes())]] + # find which layer the point is in + layer = self.NodeWhichlayer(layers,node) + if (not len(layer.getNodes()) in [1,2]): + node_i_layer = layer.getNodes().index(node) + neighbor_node = [layer.getNodes()[node_i_layer - 1], + layer.getNodes()[(node_i_layer + 1) % len(layer.getNodes())]] neighbor_node = [node0 for node0 in neighbor_node if not Line(node.get_coord(),node0.get_coord()) in path.getLines()] print("Scanned node:", str(neighbor_node)) @@ -114,9 +114,9 @@ class Solver(QObject): continue else: break - elif (len(spine.getNodes()) == 2): - first = spine.getNodes()[0] - second = spine.getNodes()[1] + elif (len(layer.getNodes()) == 2): + first = layer.getNodes()[0] + second = layer.getNodes()[1] if (not path.is_connected(first,second)): self._canvas.draw_edge(painter,pen,first,second) bad_edge = self._canvas.problem_edge() @@ -175,25 +175,25 @@ class Solver(QObject): path: Path The path - spines: list[Graph] - The spine set. + layers: list[Graph] + The layer set. node: Node The node to be checked """ - def boundary_alg_alt(self,path: Path, spines, node: Node): + def boundary_alg_alt(self,path: Path, layers, node: Node): assert (node in path.getNodes()) self.stopped = False painter = QPainter(self._canvas.pixmap()) pen = QPen() node_in_order = [] - # find which spine the point is in - spine = self.NodeWhichSpine(spines,node) - if (not len(spine.getNodes()) in [1,2]): - # detect neighboring nodes in this spine - node_i_spine = spine.getNodes().index(node) - neighbor_node = [spine.getNodes()[node_i_spine - 1], - spine.getNodes()[(node_i_spine + 1) % len(spine.getNodes())]] + # find which layer the point is in + layer = self.NodeWhichlayer(layers,node) + if (not len(layer.getNodes()) in [1,2]): + # detect neighboring nodes in this layer + node_i_layer = layer.getNodes().index(node) + neighbor_node = [layer.getNodes()[node_i_layer - 1], + layer.getNodes()[(node_i_layer + 1) % len(layer.getNodes())]] neighbor_node = [node0 for node0 in neighbor_node if not Line(node.get_coord(),node0.get_coord()) in path.getLines()] print("Scanned node:", str(neighbor_node)) @@ -222,9 +222,9 @@ class Solver(QObject): self._canvas.delete_edge(painter,pen,node,other_node) else: break - elif (len(spine.getNodes()) == 2): - first = spine.getNodes()[0] - second = spine.getNodes()[1] + elif (len(layer.getNodes()) == 2): + first = layer.getNodes()[0] + second = layer.getNodes()[1] if (not path.is_connected(first,second)): self._canvas.draw_edge(painter,pen,first,second) bad_edge = self._canvas.problem_edge() @@ -243,8 +243,8 @@ class Solver(QObject): """ Delete an layer crossing edge, choose a (missing) edge to add. - The newly added edge is determined by the spine edge vector - and added to where the spine edge vector value is less than desired. + The newly added edge is determined by the layer edge vector + and added to where the layer edge vector value is less than desired. If multiple possibilities exist, then choose randomly between them. @@ -254,22 +254,22 @@ class Solver(QObject): path: Path The path - spines: list[Graph] - The spine set + layers: list[Graph] + The layer set mode: int choose if the choice of new edge is random or not (0 if no, 1 if yes) """ - def allocate_non_spine(self,path: Path,spines,mode=0): + def allocate_non_layer(self,path: Path,layers,mode=0): painter = QPainter(self._canvas.pixmap()) pen = QPen() - linelist = [line for line in path.getLines() if self.LineWhichSpine(spines,line) == None] + linelist = [line for line in path.getLines() if self.LineWhichlayer(layers,line) == None] if (mode == 1): shuffle(linelist) line = linelist[0] else: - arr = self.check_layercross(path, spines) + arr = self.check_layercross(path, layers) diag = arr.diagonal(1) filter_arr = diag > 1 if (np.any(filter_arr)): @@ -279,8 +279,8 @@ class Solver(QObject): possible_line = [] for line in linelist: nodes = path.whichNodes(line) - node_i = spines.index(self.NodeWhichSpine(spines,nodes[0])) - node_j = spines.index(self.NodeWhichSpine(spines,nodes[1])) + node_i = layers.index(self.NodeWhichlayer(layers,nodes[0])) + node_j = layers.index(self.NodeWhichlayer(layers,nodes[1])) if ((node_i, node_j) in [(i,j),(j,i)]): possible_line.append(line) line = possible_line[0] @@ -294,101 +294,101 @@ class Solver(QObject): self.previous_steps.append(deepcopy(path)) """ - Get the spine edge vector of the path. + Get the layer edge vector of the path. Parameters ---------- path: Path The path - spines: list[Graph] + layers: list[Graph] Returns ---------- list[int] - list of integers representing the number of edges on a spine + list of integers representing the number of edges on a layer """ - def check_bound(self,path: Path,spines): - num_path_spines = [0] * len(spines) + def check_bound(self,path: Path,layers): + num_path_layers = [0] * len(layers) for line in path.getLines(): - if (self.LineWhichSpine(spines,line) != None): - line_i = spines.index(self.LineWhichSpine(spines,line)) - num_path_spines[line_i] += 1 - return num_path_spines + if (self.LineWhichlayer(layers,line) != None): + line_i = layers.index(self.LineWhichlayer(layers,line)) + num_path_layers[line_i] += 1 + return num_path_layers """ - Check if the spine edge vector fulfills the condition of a canonical path. + Check if the layer edge vector fulfills the condition of a canonical path. Parameters ---------- path: Path The path - spines: list[Graph] - The spine set. + layers: list[Graph] + The layer set. Returns --------- bool """ - def check_if_bound(self,path: Path,spines): - num_in_spines = [] - for spine in spines: - num_in_spines.append(len(spine.getLines())) - num_path_spines = self.check_bound(path,spines) - if (len(spines[-1].getNodes()) in [1,2]): - return all([x-y==1 for x,y in zip(num_in_spines[:-1],num_path_spines[:-1])] - + [num_in_spines[-1] == num_path_spines[-1]]) + def check_if_bound(self,path: Path,layers): + num_in_layers = [] + for layer in layers: + num_in_layers.append(len(layer.getLines())) + num_path_layers = self.check_bound(path,layers) + if (len(layers[-1].getNodes()) in [1,2]): + return all([x-y==1 for x,y in zip(num_in_layers[:-1],num_path_layers[:-1])] + + [num_in_layers[-1] == num_path_layers[-1]]) else: - return all([x-y==1 for x,y in zip(num_in_spines,num_path_spines)]) + return all([x-y==1 for x,y in zip(num_in_layers,num_path_layers)]) """ - Get the spine connectivity matrix of the path. + Get the layer connectivity matrix of the path. Parameters ---------- path: Path The path - spines: list[Graph] - The spine set + layers: list[Graph] + The layer set Returns ---------- numpy.ndarray(int) A matrix of integers representing the number of edges - that are between two spines + that are between two layers """ - def check_layercross(self,path: Path,spines): - n = len(spines) + def check_layercross(self,path: Path,layers): + n = len(layers) arr = np.zeros((n,n),dtype=int) - linelist = [line for line in path.getLines() if self.LineWhichSpine(spines,line) == None] + linelist = [line for line in path.getLines() if self.LineWhichlayer(layers,line) == None] for line in linelist: nodes = path.whichNodes(line) - node_i = spines.index(self.NodeWhichSpine(spines,nodes[0])) - node_j = spines.index(self.NodeWhichSpine(spines,nodes[1])) + node_i = layers.index(self.NodeWhichlayer(layers,nodes[0])) + node_j = layers.index(self.NodeWhichlayer(layers,nodes[1])) arr[node_i][node_j] += 1 arr[node_j][node_i] += 1 return arr """ - Check if the spine connectivity matrix fulfills the condition of a canonical path. + Check if the layer connectivity matrix fulfills the condition of a canonical path. Parameters ---------- path: Path The path - spines: list[Graph] - The spine set + layers: list[Graph] + The layer set Returns ---------- bool """ - def check_if_layercross(self, path: Path, spines): - n = len(spines) - arr = self.check_layercross(path,spines) + def check_if_layercross(self, path: Path, layers): + n = len(layers) + arr = self.check_layercross(path,layers) sample_arr = np.eye(n,k=1,dtype=int) + np.eye(n,k=-1,dtype=int) return np.all(arr == sample_arr) @@ -400,15 +400,15 @@ class Solver(QObject): path: Path The path - spines: list[Graph] - The spine set + layers: list[Graph] + The layer set Returns ---------- bool """ - def valid_canonical(self,path: Path,spines): - return self.check_if_bound(path, spines) and self.check_if_layercross(path,spines) and (path.is_spanning_path() and not path.crosses()) + def valid_canonical(self,path: Path,layers): + return self.check_if_bound(path, layers) and self.check_if_layercross(path,layers) and (path.is_spanning_path() and not path.crosses()) """ @@ -416,54 +416,55 @@ class Solver(QObject): """ @pyqtSlot() def solve_to_canonical(self): - if (not self._canvas.spines): - self.message.emit("Configure the SPINES first.") + self._canvas.compute_ch() + if (not self._canvas.layers): + self.message.emit("Configure the layerS first.") else: path = self._canvas.graph - spines = self._canvas.spines + layers = self._canvas.layers self.stopped = False rand = 3 steps = 0 layercross = [] - layercross.append(self.check_layercross(path,spines)) - while (not self.valid_canonical(path,spines)): + layercross.append(self.check_layercross(path,layers)) + while (not self.valid_canonical(path,layers)): if (self.stopped): break steps += 1 print("\nSolve step:", str(steps)) candidates = [path.getStart(), path.getEnd()] for anchor_node in candidates: - if (self.valid_canonical(path,spines)): break + if (self.valid_canonical(path,layers)): break if (self.stopped): break if (steps % 5 == 0): try: print("Trying:",str(anchor_node)) - self.boundary_alg_alt(path,spines,anchor_node) + self.boundary_alg_alt(path,layers,anchor_node) except AssertionError as e: print(e) continue else: try: print("Trying:",str(anchor_node)) - self.boundary_alg(path,spines,anchor_node) + self.boundary_alg(path,layers,anchor_node) except AssertionError as e: print(e) continue if (steps % 5 == rand): if (steps < 50 and steps > 5): - self.allocate_non_spine(path,spines) + self.allocate_non_layer(path,layers) rand = randint(2,3) elif (steps > 50 and steps < 800): - self.allocate_non_spine(path,spines,1) + self.allocate_non_layer(path,layers,1) rand = randint(2,3) else: - self.allocate_non_spine(path,spines,1) + self.allocate_non_layer(path,layers,1) rand = 1 if (steps > 1000): self._canvas.message.emit("Forced stop: Too many steps") self.forced_stop.emit() break - layercross.append(self.check_layercross(path,spines)) - if (self.valid_canonical(path,spines)): + layercross.append(self.check_layercross(path,layers)) + if (self.valid_canonical(path,layers)): self._canvas.message.emit("Solved") self.solved.emit() elif (self.stopped): @@ -555,7 +556,7 @@ class SolverWaitBox(QMessageBox): def solve(self): self._solverThread.start() self._solverThread.quit() - if (self._solverThread._solver._canvas.spines): + if (self._solverThread._solver._canvas.layers): self.show() self.exec() sleep(1) \ No newline at end of file diff --git a/Wrapper.py b/Wrapper.py index de8ca225d12931bd15eab0e769da08fcbd448186..602f89770d4bcec0729d38d5865bdcc3fe80c7ca 100644 --- a/Wrapper.py +++ b/Wrapper.py @@ -20,25 +20,25 @@ class Wrapper(QObject): self.stopped = True """ - Determine the spine, where the node lies. + Determine the layer, where the node lies. Parameters ---------- - spines: list[Graph] - The spine set. + layers: list[Graph] + The layer set. node: Node The node to be checked Returns ------- - spine: Graph - the spine, where the node lies. + layer: Graph + the layer, where the node lies. """ - def NodeWhichSpine(self,spines,node): - for spine in spines: - if (node in spine.getNodes()): - return spine + def NodeWhichlayer(self,layers,node): + for layer in layers: + if (node in layer.getNodes()): + return layer return None """ @@ -49,8 +49,8 @@ class Wrapper(QObject): path: Path The path - spines: list[Graph] - The spine set. + layers: list[Graph] + The layer set. start: Node The start of the path @@ -60,15 +60,15 @@ class Wrapper(QObject): list[Node] the list of nodes ordered in the way of a wrapping path. """ - def get_wrapping(self,path,spines,start): + def get_wrapping(self,path,layers,start): nodes_in_order = path.path_node_order() assert(start == nodes_in_order[0] or start == nodes_in_order[-1]) if (start == nodes_in_order[-1]): nodes_in_order.reverse() - assert(spines.index(self.NodeWhichSpine(spines,nodes_in_order[0])) == 0) + assert(layers.index(self.NodeWhichlayer(layers,nodes_in_order[0])) == 0) wrapping_path_order = [nodes_in_order[0]] other_nodes = nodes_in_order[1:] - second = next(node for node in other_nodes if spines.index(self.NodeWhichSpine(spines,nodes_in_order[0])) == 0) + second = next(node for node in other_nodes if layers.index(self.NodeWhichlayer(layers,nodes_in_order[0])) == 0) wrapping_path_order.append(second) other_nodes = [node for node in other_nodes if node != second] while (other_nodes): @@ -108,14 +108,14 @@ class Wrapper(QObject): 1 if a change is made 0 otherwise """ - def try_edge(self,painter: QPainter, pen: QPen, path: Path,spine,node1: Node,node2: Node): + def try_edge(self,painter: QPainter, pen: QPen, path: Path,layer,node1: Node,node2: Node): print("Trying Edge...") print("Connecting:", node1,node2) if (not Line(node1.get_coord(),node2.get_coord()) in path.getLines()): self._canvas.draw_edge(painter,pen,node1,node2) bad_edges = self._canvas.problem_edge() bad_edges = [line for line in bad_edges if line != Line(node1.get_coord(),node2.get_coord())] - comp = lambda line: spine.index(self.NodeWhichSpine(spine,path.whichNodes(line)[0])) + spine.index(self.NodeWhichSpine(spine,path.whichNodes(line)[1])) + comp = lambda line: layer.index(self.NodeWhichlayer(layer,path.whichNodes(line)[0])) + layer.index(self.NodeWhichlayer(layer,path.whichNodes(line)[1])) print("Can delete:", bad_edges) if (bad_edges): bad_edges.sort(key = comp,reverse=True) @@ -169,14 +169,14 @@ class Wrapper(QObject): 1 if a change is made 0 otherwise """ - def try_del_edge(self,painter:QPainter, pen:QPen, path:Path,spine,node1:Node,node2:Node): + def try_del_edge(self,painter:QPainter, pen:QPen, path:Path,layer,node1:Node,node2:Node): print("Trying to delete Edge...") print("Disconnecting:",node1, node2) if (Line(node1.get_coord(),node2.get_coord()) in path.getLines()): self._canvas.delete_edge(painter,pen,node1,node2) bad_edges = self._canvas.problem_edge() bad_edges = [line for line in bad_edges if line != Line(node1.get_coord(),node2.get_coord())] - comp = lambda line: spine.index(self.NodeWhichSpine(spine,path.whichNodes(line)[0])) + spine.index(self.NodeWhichSpine(spine,path.whichNodes(line)[1])) + comp = lambda line: layer.index(self.NodeWhichlayer(layer,path.whichNodes(line)[0])) + layer.index(self.NodeWhichlayer(layer,path.whichNodes(line)[1])) print("Can add:", bad_edges) if (bad_edges): bad_edges.sort(key = comp,reverse=True) @@ -231,12 +231,12 @@ class Wrapper(QObject): 1 if a change is made 0 otherwise """ - def try_all(self,painter:QPainter, pen:QPen, path:Path, spine, current:Node, nodelist, ordered=True): + def try_all(self,painter:QPainter, pen:QPen, path:Path, layer, current:Node, nodelist, ordered=True): errcode = 0 if (not ordered): shuffle(nodelist) for node in nodelist: - errcode = self.try_edge(painter,pen,path,spine,current, node) + errcode = self.try_edge(painter,pen,path,layer,current, node) if (errcode == 1): break return errcode @@ -270,12 +270,12 @@ class Wrapper(QObject): 1 if a change is made 0 otherwise """ - def try_del_all(self,painter:QPainter, pen:QPen, path:Path, spine, current:Node, nodelist, ordered=True): + def try_del_all(self,painter:QPainter, pen:QPen, path:Path, layer, current:Node, nodelist, ordered=True): errcode = 0 if (not ordered): shuffle(nodelist) for node in nodelist: - errcode = self.try_del_edge(painter,pen,path,spine,current, node) + errcode = self.try_del_edge(painter,pen,path,layer,current, node) if (errcode == 1): break return errcode @@ -309,7 +309,7 @@ class Wrapper(QObject): 1 if a change is made 0 otherwise """ - def try_node(self,painter:QPainter, pen:QPen, path:Path,spine, current:Node, node:Node, nodelist, path_start): + def try_node(self,painter:QPainter, pen:QPen, path:Path,layer, current:Node, node:Node, nodelist, path_start): print("Trying node:",node) adj_list = path.adj(node) shuffle(adj_list) @@ -324,7 +324,7 @@ class Wrapper(QObject): bad_edges = [line for line in bad_edges if not path_start in path.whichNodes(line)] ''' print("Can add:", bad_edges) - comp = lambda line: spine.index(self.NodeWhichSpine(spine,path.whichNodes(line)[0])) + spine.index(self.NodeWhichSpine(spine,path.whichNodes(line)[1])) + comp = lambda line: layer.index(self.NodeWhichlayer(layer,path.whichNodes(line)[0])) + layer.index(self.NodeWhichlayer(layer,path.whichNodes(line)[1])) if (bad_edges): bad_edges.sort(key = comp,reverse=True) val = comp(bad_edges[0]) @@ -339,13 +339,13 @@ class Wrapper(QObject): print("Connecting:",toadd_points[0], toadd_points[1]) self._canvas.draw_edge(painter,pen, toadd_points[0], toadd_points[1]) self._canvas.update() - errcode = self.try_all(painter,pen,path,spine,current,nodelist) + errcode = self.try_all(painter,pen,path,layer,current,nodelist) if (errcode == 1): path_nodes = path.path_node_order() if (path.deg(path_start) > 1): start_adj = path.adj(path_start) others = [node for node in start_adj if node != path_nodes[1]] - self.try_del_all(painter,pen,path,spine,path_start,others) + self.try_del_all(painter,pen,path,layer,path_start,others) return 1 else: print("Reverting change.") @@ -354,14 +354,14 @@ class Wrapper(QObject): return 0 """ - Partition the ordered nodes in the path as in spine set. + Partition the ordered nodes in the path as in layer set. Parameters ---------- path: Path The path - spine: list[Graph] + layer: list[Graph] The Returns @@ -369,13 +369,13 @@ class Wrapper(QObject): list[list[Node]] The node partition """ - def node_partition(self,path:Path, spine): + def node_partition(self,path:Path, layer): node_order = path.path_node_order() - if (spine.index(self.NodeWhichSpine(spine,node_order[0])) != 0): + if (layer.index(self.NodeWhichlayer(layer,node_order[0])) != 0): node_order.reverse() partition = [] - for i in range(len(spine)): - temp_list = [node for node in node_order if spine.index(self.NodeWhichSpine(spine,node)) == i] + for i in range(len(layer)): + temp_list = [node for node in node_order if layer.index(self.NodeWhichlayer(layer,node)) == i] partition.append(temp_list) return partition @@ -388,8 +388,8 @@ class Wrapper(QObject): path: Path The current path - spine: list[Graph] - The spine set + layer: list[Graph] + The layer set old_path_order: list[Node] The node order of the current path @@ -400,7 +400,7 @@ class Wrapper(QObject): i: int Order of the node in the current path """ - def wrap_path_step(self,path,spine,old_path_order,new_path_order,i): + def wrap_path_step(self,path,layer,old_path_order,new_path_order,i): current = new_path_order[i-1] to_be_connected = new_path_order[i] old_next = old_path_order[i] @@ -413,11 +413,11 @@ class Wrapper(QObject): >= min(path.angle(node,current,to_be_connected), path.angle(to_be_connected, current, node))] """ nodes_to_be_checked = [node for node in nodes_to_be_checked if node != old_next] - nodes_to_be_checked.sort(key = lambda node: spine.index(self.NodeWhichSpine(spine,node))) + nodes_to_be_checked.sort(key = lambda node: layer.index(self.NodeWhichlayer(layer,node))) new_nodes = [] - for x in range(len(spine)): + for x in range(len(layer)): temp_nodelist = [node for node in nodes_to_be_checked - if spine.index(self.NodeWhichSpine(spine,node)) == x] + if layer.index(self.NodeWhichlayer(layer,node)) == x] temp_nodelist.sort(key = lambda node: min(path.angle(node, current, to_be_connected), path.angle(to_be_connected, current, node))) @@ -436,19 +436,19 @@ class Wrapper(QObject): pen = QPen() start = old_path_order[0] for possible in nodes_to_be_checked: - errcode = self.try_node(painter,pen,path,spine,current, possible,nodes_to_be_checked,start) + errcode = self.try_node(painter,pen,path,layer,current, possible,nodes_to_be_checked,start) if (errcode == 1): break else: - errcode = self.try_all(painter,pen,path,spine,current, nodes_to_be_checked) + errcode = self.try_all(painter,pen,path,layer,current, nodes_to_be_checked) if (errcode != 1): - self.try_del_all(painter,pen,path,spine,possible, path.adj(possible)) + self.try_del_all(painter,pen,path,layer,possible, path.adj(possible)) else: break if (path.deg(start) > 1): start_adj = path.adj(start) others = [node for node in start_adj if node != old_path_order[1]] - self.try_del_all(painter,pen,path,spine,start,others) + self.try_del_all(painter,pen,path,layer,start,others) self._canvas.update() painter.end() @@ -460,8 +460,8 @@ class Wrapper(QObject): path: Path The current path - spine: list[Graph] - The spine set + layer: list[Graph] + The layer set old_path_order: list[Node] The node order of the current path @@ -472,7 +472,7 @@ class Wrapper(QObject): i: int Order of the node in the current path """ - def wrap_path_step_alt(self,path,spine,old_path_order,new_path_order,i): + def wrap_path_step_alt(self,path,layer,old_path_order,new_path_order,i): current = new_path_order[i-1] to_be_connected = new_path_order[i] old_next = old_path_order[i] @@ -485,11 +485,11 @@ class Wrapper(QObject): >= min(path.angle(node,current,to_be_connected), path.angle(to_be_connected, current, node))] """ nodes_to_be_checked = [node for node in nodes_to_be_checked if node != old_next] - nodes_to_be_checked.sort(key = lambda node: spine.index(self.NodeWhichSpine(spine,node))) + nodes_to_be_checked.sort(key = lambda node: layer.index(self.NodeWhichlayer(layer,node))) new_nodes = [] - for x in range(len(spine)): + for x in range(len(layer)): temp_nodelist = [node for node in nodes_to_be_checked - if spine.index(self.NodeWhichSpine(spine,node)) == x] + if layer.index(self.NodeWhichlayer(layer,node)) == x] temp_nodelist.sort(key = lambda node: min(path.angle(node, current, to_be_connected), path.angle(to_be_connected, current, node))) @@ -507,22 +507,22 @@ class Wrapper(QObject): painter = QPainter(self._canvas.pixmap()) pen = QPen() start = old_path_order[0] - errcode = self.try_all(painter,pen,path,spine,current,nodes_to_be_checked) + errcode = self.try_all(painter,pen,path,layer,current,nodes_to_be_checked) if (errcode != 1): for possible in nodes_to_be_checked: - errcode = self.try_node(painter,pen,path,spine,current, possible,nodes_to_be_checked, start) + errcode = self.try_node(painter,pen,path,layer,current, possible,nodes_to_be_checked, start) if (errcode == 1): break else: - errcode = self.try_del_all(painter,pen,path,spine,current, nodes_to_be_checked) + errcode = self.try_del_all(painter,pen,path,layer,current, nodes_to_be_checked) if (errcode != 1): - self.try_all(painter,pen,path,spine,possible, path.adj(possible)) + self.try_all(painter,pen,path,layer,possible, path.adj(possible)) else: break if (path.deg(start) > 1): start_adj = path.adj(start) others = [node for node in start_adj if node != old_path_order[1]] - self.try_del_all(painter,pen,path,spine,start,others) + self.try_del_all(painter,pen,path,layer,start,others) self._canvas.update() painter.end() @@ -537,8 +537,8 @@ class Wrapper(QObject): path: Path The current path - spine: list[Graph] - The spine set + layer: list[Graph] + The layer set start: Node The start of the node @@ -549,11 +549,11 @@ class Wrapper(QObject): 1 if a change is made 0 otherwise """ - def wrap_path_correction(self,path,spine,start:Node): + def wrap_path_correction(self,path,layer,start:Node): nodelist = path.adj(start) painter = QPainter(self._canvas.pixmap()) pen = QPen() - self.try_del_all(painter,pen,path,spine,start,nodelist) + self.try_del_all(painter,pen,path,layer,start,nodelist) if (path.deg(start) == 1): return 1 else: @@ -561,30 +561,30 @@ class Wrapper(QObject): """ Initialize this step of wrapping, if the node to be corrected is - at the end of first spine. + at the end of first layer. Parameters ---------- path: Path The current path - spine: list[Graph] - The spine set + layer: list[Graph] + The layer set """ - def wrap_path_step_first(self,path:Path,spine): - partition = self.node_partition(path,spine) - outer_spine = partition[0] - next_spine = partition[1] + def wrap_path_step_first(self,path:Path,layer): + partition = self.node_partition(path,layer) + outer_layer = partition[0] + next_layer = partition[1] painter = QPainter(self._canvas.pixmap()) pen = QPen() - if (len(next_spine) > 2): + if (len(next_layer) > 2): is_clockwise = lambda A,B,C : (C[1]-A[1])*(B[0]-A[0]) > (B[1]-A[1])*(C[0]-A[0]) - if (is_clockwise(outer_spine[0].get_coord(),outer_spine[1].get_coord(),outer_spine[2].get_coord()) != - is_clockwise(outer_spine[-2].get_coord(),outer_spine[-1].get_coord(),next_spine[0].get_coord())): - self.try_edge(painter,pen,path,spine,outer_spine[-1],next_spine[0]) - if (is_clockwise(outer_spine[0].get_coord(),outer_spine[1].get_coord(),outer_spine[2].get_coord()) != - is_clockwise(next_spine[0].get_coord(),next_spine[1].get_coord(),next_spine[2].get_coord())): - self.try_del_edge(painter,pen,path,spine,outer_spine[-1],outer_spine[-2]) + if (is_clockwise(outer_layer[0].get_coord(),outer_layer[1].get_coord(),outer_layer[2].get_coord()) != + is_clockwise(outer_layer[-2].get_coord(),outer_layer[-1].get_coord(),next_layer[0].get_coord())): + self.try_edge(painter,pen,path,layer,outer_layer[-1],next_layer[0]) + if (is_clockwise(outer_layer[0].get_coord(),outer_layer[1].get_coord(),outer_layer[2].get_coord()) != + is_clockwise(next_layer[0].get_coord(),next_layer[1].get_coord(),next_layer[2].get_coord())): + self.try_del_edge(painter,pen,path,layer,outer_layer[-1],outer_layer[-2]) """ Try to delete all edges that is after the node specified @@ -595,8 +595,8 @@ class Wrapper(QObject): path: Path The current path - spine: list[Graph] - The spine set + layer: list[Graph] + The layer set i: int Index of the node @@ -607,12 +607,12 @@ class Wrapper(QObject): 1 if a change is made 0 otherwise """ - def del_later(self,path: Path,spine, i, old_path_order): + def del_later(self,path: Path,layer, i, old_path_order): nodelist = old_path_order[i:] painter = QPainter(self._canvas.pixmap()) pen = QPen() for j in range(len(nodelist) - 1): - self.try_del_edge(painter,pen,path,spine,nodelist[j], nodelist[j+1]) + self.try_del_edge(painter,pen,path,layer,nodelist[j], nodelist[j+1]) """ The main heuristic of wrapping a path. @@ -620,20 +620,21 @@ class Wrapper(QObject): """ def wrap_path(self): path = self._canvas.graph - spines = self._canvas.spines - if (not spines): - self.message.emit("Configure the SPINES first.") + layers = self._canvas.layers + self._canvas.compute_ch() + if (not layers): + self.message.emit("Configure the layerS first.") else: self.stopped = False path = self._canvas.graph candidates = [path.getStart(), path.getEnd()] - if (not any([spines.index(self.NodeWhichSpine(spines,node)) == 0 for node in candidates])): + if (not any([layers.index(self.NodeWhichlayer(layers,node)) == 0 for node in candidates])): self.message.emit("Try SOLVE it first.") else: - candidates = [node for node in candidates if spines.index(self.NodeWhichSpine(spines,node)) == 0] + candidates = [node for node in candidates if layers.index(self.NodeWhichlayer(layers,node)) == 0] start = candidates[0] old_path = path.path_node_order() - new_path = self.get_wrapping(path,spines,start) + new_path = self.get_wrapping(path,layers,start) if (old_path[0] != new_path[0]): old_path.reverse() steps = 0 @@ -643,31 +644,31 @@ class Wrapper(QObject): print("Wrap step:", steps) if (self.stopped): break i = next(j for j in range(len(old_path)) if old_path[j] != new_path[j]) - if (spines.index(self.NodeWhichSpine(spines,new_path[i-1])) == 0): + if (layers.index(self.NodeWhichlayer(layers,new_path[i-1])) == 0): print("FIRST STEP:") - self.wrap_path_step_first(path,spines) + self.wrap_path_step_first(path,layers) if (steps % 2 == 0): - self.wrap_path_step(path,spines,old_path,new_path,i) + self.wrap_path_step(path,layers,old_path,new_path,i) else: - self.wrap_path_step_alt(path,spines,old_path,new_path,i) + self.wrap_path_step_alt(path,layers,old_path,new_path,i) if (steps % 10 == 0): - self.del_later(path,spines,i,old_path) + self.del_later(path,layers,i,old_path) old_path = path.path_node_order() candidates = [path.getStart(), path.getEnd()] try: - candidates = [node for node in candidates if spines.index(self.NodeWhichSpine(spines,node)) == 0] + candidates = [node for node in candidates if layers.index(self.NodeWhichlayer(layers,node)) == 0] start = candidates[0] - new_path = self.get_wrapping(path,spines,start) + new_path = self.get_wrapping(path,layers,start) if (old_path[0] != new_path[0]): old_path.reverse() except IndexError: print("PATH INVALID, CORRECTING...") - code = self.wrap_path_correction(path,spines,old_path[0]) + code = self.wrap_path_correction(path,layers,old_path[0]) if (code == 1): - code = self.wrap_path_correction(path,spines,old_path[1]) + code = self.wrap_path_correction(path,layers,old_path[1]) if (code == 1): ''' - new_path = self.get_wrapping(path,spines,start) + new_path = self.get_wrapping(path,layers,start) if (old_path[0] != new_path[0]): old_path.reverse() ''' @@ -678,9 +679,9 @@ class Wrapper(QObject): ''' except AssertionError: print("PATH INVALID, CORRECTING...") - code = self.wrap_path_correction(path,spines,old_start) + code = self.wrap_path_correction(path,layers,old_start) if (code == 1): - code = self.wrap_path_correction(path,spines,old_second) + code = self.wrap_path_correction(path,layers,old_second) if (code == 1): continue else: @@ -705,8 +706,8 @@ class Wrapper(QObject): points = self._canvas.graph.whichNodes(line) self._canvas.graph.connect(points[0],points[1]) self._canvas.drawGraph() - if ((spines.index(self.NodeWhichSpine(spines,old_path[0])) != 0 and - spines.index(self.NodeWhichSpine(spines,old_path[-1])) != 0)): + if ((layers.index(self.NodeWhichlayer(layers,old_path[0])) != 0 and + layers.index(self.NodeWhichlayer(layers,old_path[-1])) != 0)): self._canvas.message.emit("Path invalid. Consider SOLVE it again.") else: self._canvas.message.emit("Forced stop: Cancel") @@ -781,7 +782,7 @@ class WrapperWaitBox(QMessageBox): def wrap(self): self._wrapperThread.start() self._wrapperThread.quit() - if (self._wrapperThread._wrapper._canvas.spines): + if (self._wrapperThread._wrapper._canvas.layers): self.show() self.exec() sleep(1) \ No newline at end of file diff --git a/main.py b/main.py index 14dedddeba705f85bb2f085eec0789cc3ee39b70..7557a14a1b453423330ea3f0bec5dd3813282664 100644 --- a/main.py +++ b/main.py @@ -5,7 +5,7 @@ from Randomizer import * from Solver import * from Wrapper import * -VERSION = "v.2024-3-15" +VERSION = "v.2024-4-1" class MainWindow(QMainWindow): """ @@ -20,8 +20,12 @@ class MainWindow(QMainWindow): self.width_ = width self.height_ = height + + self.oldsize = QSize(width, height) + # MainWindow set self.setWindowTitle("FlipGraphin") + self.setMinimumSize(QSize(800,600)) # Variables self.main_mode_ = MainMode.EDIT_MODE @@ -32,8 +36,19 @@ class MainWindow(QMainWindow): self.setCentralWidget(self.canvas) # Toolbar & Buttons - self.toolbar = QToolBar() - self.addToolBar(self.toolbar) + self.toolbar1 = QToolBar() + self.toolbar2 = QToolBar() + self.toolbar3 = QToolBar() + self.addToolBar(Qt.TopToolBarArea, self.toolbar1) + self.addToolBarBreak() + self.addToolBar(Qt.TopToolBarArea, self.toolbar2) + self.addToolBarBreak() + self.addToolBar(Qt.TopToolBarArea, self.toolbar3) + + self.toolbar1.setFixedHeight(32) + self.toolbar2.setFixedHeight(32) + self.toolbar3.setFixedHeight(32) + self.button1 = QPushButton("NODE") self.button2 = QPushButton("EDGE") @@ -41,7 +56,7 @@ class MainWindow(QMainWindow): self.button4 = QPushButton("DEL_EDGE") self.button5 = QPushButton("FLIP") self.button6 = QPushButton("CLEAR") - self.button7 = QPushButton("SPINES") + self.button7 = QPushButton("LAYERS") self.button8 = QPushButton("UNDO") self.button9 = QPushButton("REDO") self.button10 = QPushButton("TO START") @@ -58,29 +73,41 @@ class MainWindow(QMainWindow): self.check_dict = {SubMode.DRAW_NODE:0, SubMode.DRAW_EDGE:1, SubMode.DEL_NODE:2,SubMode.DEL_EDGE:3} + # Flip Button + self.toolbar1.addWidget(self.button5) + self.button5.setCheckable(True) + self.toolbar1.addSeparator() + + # Basic functions for button in self.buttons: button.setCheckable(True) button.setChecked(False) - self.toolbar.addWidget(button) - self.toolbar.addWidget(self.button6) - self.toolbar.addWidget(self.button8) - self.toolbar.addWidget(self.button9) - self.toolbar.addWidget(self.button10) - self.toolbar.addWidget(self.button11) - self.toolbar.addSeparator() - self.toolbar.addWidget(self.button5) - self.toolbar.addWidget(self.button7) - self.toolbar.addWidget(self.button12) - self.toolbar.addWidget(self.button13) - self.toolbar.addWidget(self.button14) - self.toolbar.addSeparator() - self.toolbar.addWidget(self.button15) - self.toolbar.addWidget(self.button16) - self.toolbar.addSeparator() - self.toolbar.addWidget(self.button17) - self.toolbar.addWidget(self.button18) - self.toolbar.addSeparator() - self.toolbar.addWidget(self.statusText) + self.toolbar1.addWidget(button) + self.toolbar1.addSeparator() + + # Flip graph specific functions + self.toolbar1.addWidget(self.button12) + self.toolbar1.addWidget(self.button13) + self.toolbar1.addWidget(self.button14) + + # Advanced functions + self.toolbar2.addWidget(self.button6) + self.toolbar2.addWidget(self.button8) + self.toolbar2.addWidget(self.button9) + self.toolbar2.addWidget(self.button10) + self.toolbar2.addWidget(self.button11) + self.toolbar2.addWidget(self.button7) + self.toolbar2.addSeparator() + + + # Miscellaneous functions + self.toolbar2.addWidget(self.button15) + self.toolbar2.addWidget(self.button16) + + self.toolbar3.addWidget(self.button17) + self.toolbar3.addWidget(self.button18) + self.toolbar3.addSeparator() + self.toolbar3.addWidget(self.statusText) self.button1.clicked.connect(lambda: self.check_sub_mode(SubMode.DRAW_NODE)) @@ -151,7 +178,9 @@ class MainWindow(QMainWindow): self.button13.setEnabled(True) self.button14.setEnabled(True) self.button1.setEnabled(False) + self.button2.setEnabled(False) self.button3.setEnabled(False) + self.button4.setEnabled(False) self.canvas.first_point, self.canvas.second_point = None, None self.check_sub_mode(SubMode.DRAW_EDGE) else: @@ -168,6 +197,7 @@ class MainWindow(QMainWindow): self.button13.setEnabled(False) self.button14.setEnabled(False) self.button1.setEnabled(True) + self.button2.setEnabled(True) self.button3.setEnabled(True) self.canvas.first_point, self.canvas.second_point = None, None @@ -227,7 +257,7 @@ class MainWindow(QMainWindow): msg += "TO_END: Redo until it's not redoable\n\n" msg += "Flip graph specific Functionality: \n\n" msg += "FLIP: Switch to Flip Mode\n" - msg += "SPINES: Show the iteratively constructed convex hulls\n" + msg += "LAYERS: Show the iteratively constructed convex layers\n" msg += "RANDOM: Randomly generate a path fulfilling all conditions\n" msg += "SOLVE: Reconfigure the graph into a canonical path\n" msg += "WRAP: Reconfigure a canonical path into a wrapping path\n\n" @@ -238,6 +268,13 @@ class MainWindow(QMainWindow): msg += "HELP: Display this page\n" msgbox = QMessageBox.about(self,"FlipGraphin",msg) + def resizeEvent(self,e): + if (not self.isMaximized()): + self.oldsize = e.oldSize() + else: + self.resize(self.oldsize.width(), self.oldsize.height()) + self.canvas.graph.compute_ch() + """ Request to save the graph before closing the program. @@ -263,8 +300,7 @@ The main function. """ if __name__ == '__main__': app = QApplication(sys.argv) - # size = app.primaryScreen().size() - size = QSize(1920,980) + size = app.primaryScreen().size() window = MainWindow(size.width(), size.height()) window.showMaximized() window.show() diff --git a/title_image.png b/title_image.png deleted file mode 100644 index 5f9f9b11a6a877ab1bc9b76bd15e7fb08b724c8f..0000000000000000000000000000000000000000 Binary files a/title_image.png and /dev/null differ