From 81eeac9ec62a6c755be066a24dabf2427416943f Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Thu, 5 Dec 2019 16:37:48 -0800 Subject: [PATCH] merged drawing antenna code to graph node class --- coretk/coretk/graph/edges.py | 57 +++++++---- coretk/coretk/graph/graph.py | 61 ++++++------ coretk/coretk/graph/graph_helper.py | 144 ---------------------------- coretk/coretk/graph/node.py | 49 +++++++++- coretk/coretk/nodeutils.py | 3 + 5 files changed, 120 insertions(+), 194 deletions(-) delete mode 100644 coretk/coretk/graph/graph_helper.py diff --git a/coretk/coretk/graph/edges.py b/coretk/coretk/graph/edges.py index 92f99400..d62a309b 100644 --- a/coretk/coretk/graph/edges.py +++ b/coretk/coretk/graph/edges.py @@ -1,5 +1,7 @@ import tkinter as tk +from coretk.nodeutils import NodeUtils + class CanvasWirelessEdge: def __init__(self, token, position, src, dst, canvas): @@ -22,7 +24,7 @@ class CanvasEdge: width = 1.4 - def __init__(self, x1, y1, x2, y2, src, canvas, is_wired=None): + def __init__(self, x1, y1, x2, y2, src, canvas): """ Create an instance of canvas edge object :param int x1: source x-coord @@ -30,41 +32,56 @@ class CanvasEdge: :param int x2: destination x-coord :param int y2: destination y-coord :param int src: source id - :param tkinter.Canvas canvas: canvas object + :param coretk.graph.graph.GraphCanvas canvas: canvas object """ self.src = src self.dst = None self.src_interface = None self.dst_interface = None self.canvas = canvas - if is_wired is None or is_wired is True: - self.id = self.canvas.create_line( - x1, y1, x2, y2, tags="edge", width=self.width, fill="#ff0000" - ) - else: - self.id = self.canvas.create_line( - x1, - y1, - x2, - y2, - tags="edge", - width=self.width, - fill="#ff0000", - state=tk.HIDDEN, - ) + self.id = self.canvas.create_line( + x1, y1, x2, y2, tags="edge", width=self.width, fill="#ff0000" + ) self.token = None self.link_info = None self.throughput = None - self.wired = is_wired - def complete(self, dst, x, y): + def complete(self, dst): self.dst = dst self.token = tuple(sorted((self.src, self.dst))) + x, y = self.canvas.coords(self.dst) x1, y1, _, _ = self.canvas.coords(self.id) self.canvas.coords(self.id, x1, y1, x, y) - self.canvas.helper.draw_wireless_case(self.src, self.dst, self) + self.check_wireless() self.canvas.tag_raise(self.src) self.canvas.tag_raise(self.dst) + def check_wireless(self): + src_node = self.canvas.nodes[self.src] + dst_node = self.canvas.nodes[self.dst] + src_node_type = src_node.core_node.type + dst_node_type = dst_node.core_node.type + is_src_wireless = NodeUtils.is_wireless_node(src_node_type) + is_dst_wireless = NodeUtils.is_wireless_node(dst_node_type) + if is_src_wireless or is_dst_wireless: + self.canvas.itemconfig(self.id, state=tk.HIDDEN) + self._check_antenna() + + def _check_antenna(self): + src_node = self.canvas.nodes[self.src] + dst_node = self.canvas.nodes[self.dst] + src_node_type = src_node.core_node.type + dst_node_type = dst_node.core_node.type + is_src_wireless = NodeUtils.is_wireless_node(src_node_type) + is_dst_wireless = NodeUtils.is_wireless_node(dst_node_type) + if is_src_wireless or is_dst_wireless: + if is_src_wireless and not is_dst_wireless: + dst_node.add_antenna() + elif not is_src_wireless and is_dst_wireless: + src_node.add_antenna() + # TODO: remove this? dont allow linking wireless nodes? + else: + src_node.add_antenna() + def delete(self): self.canvas.delete(self.id) diff --git a/coretk/coretk/graph/graph.py b/coretk/coretk/graph/graph.py index 95ad19dc..ad6788c5 100644 --- a/coretk/coretk/graph/graph.py +++ b/coretk/coretk/graph/graph.py @@ -8,7 +8,6 @@ from core.api.grpc.core_pb2 import NodeType from coretk.dialogs.shapemod import ShapeDialog from coretk.graph.edges import CanvasEdge, CanvasWirelessEdge from coretk.graph.enums import GraphMode, ScaleOption -from coretk.graph.graph_helper import GraphHelper from coretk.graph.linkinfo import LinkInfo, Throughput from coretk.graph.node import CanvasNode from coretk.graph.shape import Shape @@ -16,6 +15,18 @@ from coretk.images import ImageEnum, Images from coretk.nodeutils import NodeUtils ABOVE_WALLPAPER = ["edge", "linkinfo", "wireless", "antenna", "nodename", "node"] +CANVAS_COMPONENT_TAGS = [ + "edge", + "node", + "nodename", + "wallpaper", + "linkinfo", + "antenna", + "wireless", + "selectednodes", + "shape", + "shapetext", +] class CanvasGraph(tk.Canvas): @@ -40,7 +51,6 @@ class CanvasGraph(tk.Canvas): self.setup_bindings() self.draw_grid(width, height) self.core = core - self.helper = GraphHelper(self, core) self.throughput_draw = Throughput(self, core) self.shape_drawing = False @@ -96,7 +106,8 @@ class CanvasGraph(tk.Canvas): :return: nothing """ # delete any existing drawn items - self.helper.delete_canvas_components() + for tag in CANVAS_COMPONENT_TAGS: + self.delete(tag) # set the private variables to default value self.mode = GraphMode.SELECT @@ -195,9 +206,6 @@ class CanvasGraph(tk.Canvas): if link.type == core_pb2.LinkType.WIRELESS: self.add_wireless_edge(canvas_node_one, canvas_node_two) else: - is_node_one_wireless = NodeUtils.is_wireless_node(node_one.type) - is_node_two_wireless = NodeUtils.is_wireless_node(node_two.type) - has_no_wireless = not (is_node_one_wireless or is_node_two_wireless) edge = CanvasEdge( node_one.position.x, node_one.position.y, @@ -205,15 +213,14 @@ class CanvasGraph(tk.Canvas): node_two.position.y, canvas_node_one.id, self, - is_wired=has_no_wireless, ) edge.token = tuple(sorted((canvas_node_one.id, canvas_node_two.id))) edge.dst = canvas_node_two.id + edge.check_wireless() canvas_node_one.edges.add(edge) canvas_node_two.edges.add(edge) self.edges[edge.token] = edge self.core.links[edge.token] = link - self.helper.redraw_antenna(canvas_node_one, canvas_node_two) edge.link_info = LinkInfo(self, edge, link) if link.HasField("interface_one"): canvas_node_one.interfaces.append(link.interface_one) @@ -311,21 +318,23 @@ class CanvasGraph(tk.Canvas): edge.delete() return - # set dst node and snap edge to center - x, y = self.coords(self.selected) - edge.complete(self.selected, x, y) - logging.debug(f"drawing edge token: {edge.token}") - if edge.token in self.edges: + # ignore repeated edges + token = tuple(sorted((edge.src, self.selected))) + if token in self.edges: edge.delete() - else: - self.edges[edge.token] = edge - node_src = self.nodes[edge.src] - node_src.edges.add(edge) - node_dst = self.nodes[edge.dst] - node_dst.edges.add(edge) - link = self.core.create_link(edge, node_src, node_dst) - edge.link_info = LinkInfo(self, edge, link) - logging.debug(f"edges: {self.find_withtag('edge')}") + return + + # set dst node and snap edge to center + edge.complete(self.selected) + logging.debug("drawing edge token: %s", edge.token) + + self.edges[edge.token] = edge + node_src = self.nodes[edge.src] + node_src.edges.add(edge) + node_dst = self.nodes[edge.dst] + node_dst.edges.add(edge) + link = self.core.create_link(edge, node_src, node_dst) + edge.link_info = LinkInfo(self, edge, link) def select_object(self, object_id, choose_multiple=False): """ @@ -374,11 +383,8 @@ class CanvasGraph(tk.Canvas): self.delete(object_id) self.delete(selection_id) self.delete(canvas_node.text_id) - - # delete antennas + canvas_node.delete_antennae() is_wireless = NodeUtils.is_wireless_node(canvas_node.core_node.type) - if is_wireless: - canvas_node.antenna_draw.delete_antennas() # delete related edges for edge in canvas_node.edges: @@ -401,7 +407,7 @@ class CanvasGraph(tk.Canvas): except ValueError: pass if is_wireless: - other_node.antenna_draw.delete_antenna() + other_node.delete_antenna() if object_id in self.shapes: selection_id = self.selection[object_id] self.shapes[object_id].delete() @@ -424,6 +430,7 @@ class CanvasGraph(tk.Canvas): if self.mode == GraphMode.EDGE and is_node: x, y = self.coords(selected) self.drawing_edge = CanvasEdge(x, y, x, y, selected, self) + self.tag_raise(selected) if ( self.mode == GraphMode.ANNOTATION and self.annotation_type in [ImageEnum.OVAL, ImageEnum.RECTANGLE] diff --git a/coretk/coretk/graph/graph_helper.py b/coretk/coretk/graph/graph_helper.py deleted file mode 100644 index af6d4823..00000000 --- a/coretk/coretk/graph/graph_helper.py +++ /dev/null @@ -1,144 +0,0 @@ -""" -Some graph helper functions -""" -import logging -import tkinter as tk - -from coretk.images import ImageEnum, Images -from coretk.nodeutils import NodeUtils - -CANVAS_COMPONENT_TAGS = [ - "edge", - "node", - "nodename", - "wallpaper", - "linkinfo", - "antenna", - "wireless", - "selectednodes", - "shape", - "shapetext", -] - - -class GraphHelper: - def __init__(self, canvas, core): - """ - create an instance of GraphHelper object - """ - self.canvas = canvas - self.core = core - - def delete_canvas_components(self): - """ - delete the components of the graph leaving only the blank canvas - - :return: nothing - """ - for tag in CANVAS_COMPONENT_TAGS: - for i in self.canvas.find_withtag(tag): - self.canvas.delete(i) - - def draw_wireless_case(self, src_id, dst_id, edge): - src_node_type = self.canvas.nodes[src_id].core_node.type - dst_node_type = self.canvas.nodes[dst_id].core_node.type - is_src_wireless = NodeUtils.is_wireless_node(src_node_type) - is_dst_wireless = NodeUtils.is_wireless_node(dst_node_type) - if is_src_wireless or is_dst_wireless: - self.canvas.itemconfig(edge.id, state=tk.HIDDEN) - edge.wired = False - if edge.token not in self.canvas.edges: - if is_src_wireless and is_dst_wireless: - self.canvas.nodes[src_id].antenna_draw.add_antenna() - elif is_src_wireless: - self.canvas.nodes[dst_id].antenna_draw.add_antenna() - else: - self.canvas.nodes[src_id].antenna_draw.add_antenna() - edge.wired = True - - def redraw_antenna(self, node_one, node_two): - is_node_one_wireless = NodeUtils.is_wireless_node(node_one.core_node.type) - is_node_two_wireless = NodeUtils.is_wireless_node(node_two.core_node.type) - if is_node_one_wireless or is_node_two_wireless: - if is_node_one_wireless and not is_node_two_wireless: - node_two.antenna_draw.add_antenna() - elif not is_node_one_wireless and is_node_two_wireless: - node_one.antenna_draw.add_antenna() - else: - logging.error("bad link between two wireless nodes") - - def update_wlan_connection(self, old_x, old_y, new_x, new_y, edge_ids): - for eid in edge_ids: - x1, y1, x2, y2 = self.canvas.coords(eid) - if x1 == old_x and y1 == old_y: - self.canvas.coords(eid, new_x, new_y, x2, y2) - else: - self.canvas.coords(eid, x1, y1, new_x, new_y) - - -class WlanAntennaManager: - def __init__(self, canvas, node_id): - """ - crate an instance for AntennaManager - """ - self.canvas = canvas - self.node_id = node_id - self.quantity = 0 - self._max = 5 - self.antennas = [] - self.image = Images.get(ImageEnum.ANTENNA, 32) - - # distance between each antenna - self.offset = 0 - - def add_antenna(self): - """ - add an antenna to a node - - :return: nothing - """ - if self.quantity < 5: - x, y = self.canvas.coords(self.node_id) - aid = self.canvas.create_image( - x - 16 + self.offset, - y - 23, - anchor=tk.CENTER, - image=self.image, - tags="antenna", - ) - # self.canvas.tag_raise("antenna") - self.antennas.append(aid) - self.quantity = self.quantity + 1 - self.offset = self.offset + 8 - - def delete_antenna(self): - """ - delete one antenna - - :return: nothing - """ - if len(self.antennas) > 0: - self.canvas.delete(self.antennas.pop()) - self.quantity -= 1 - self.offset -= 8 - - def delete_antennas(self): - """ - delete all antennas - - :return: nothing - """ - for aid in self.antennas: - self.canvas.delete(aid) - self.antennas.clear() - self.quantity = 0 - self.offset = 0 - - def update_antennas_position(self, offset_x, offset_y): - """ - redraw antennas of a node according to the new node position - - :return: nothing - """ - for i in self.antennas: - self.canvas.move(i, offset_x, offset_y) diff --git a/coretk/coretk/graph/node.py b/coretk/coretk/graph/node.py index a4e4a539..2d34780e 100644 --- a/coretk/coretk/graph/node.py +++ b/coretk/coretk/graph/node.py @@ -7,8 +7,8 @@ from coretk.dialogs.mobilityconfig import MobilityConfigDialog from coretk.dialogs.nodeconfig import NodeConfigDialog from coretk.dialogs.wlanconfig import WlanConfigDialog from coretk.graph.enums import GraphMode -from coretk.graph.graph_helper import WlanAntennaManager from coretk.graph.tooltip import CanvasTooltip +from coretk.nodeutils import NodeUtils NODE_TEXT_OFFSET = 5 @@ -35,7 +35,6 @@ class CanvasNode: font=text_font, fill="#0000CD", ) - self.antenna_draw = WlanAntennaManager(self.canvas, self.id) self.tooltip = CanvasTooltip(self.canvas) self.canvas.tag_bind(self.id, "", self.click_press) self.canvas.tag_bind(self.id, "", self.click_release) @@ -48,6 +47,50 @@ class CanvasNode: self.interfaces = [] self.wireless_edges = set() self.moving = None + self.antennae = [] + + def add_antenna(self): + x, y = self.canvas.coords(self.id) + offset = len(self.antennae) * 8 + + antenna_id = self.canvas.create_image( + x - 16 + offset, + y - 23, + anchor=tk.CENTER, + image=NodeUtils.ANTENNA_ICON, + tags="antenna", + ) + self.antennae.append(antenna_id) + + def delete_antenna(self): + """ + delete one antenna + + :return: nothing + """ + if self.antennae: + antenna_id = self.antennae.pop() + self.canvas.delete(antenna_id) + + def delete_antennae(self): + """ + delete all antennas + + :return: nothing + """ + logging.info("deleting antennae: %s", self.antennae) + for antenna_id in self.antennae: + self.canvas.delete(antenna_id) + self.antennae.clear() + + def move_antennae(self, x_offset, y_offset): + """ + redraw antennas of a node according to the new node position + + :return: nothing + """ + for antenna_id in self.antennae: + self.canvas.move(antenna_id, x_offset, y_offset) def redraw(self): self.canvas.itemconfig(self.id, image=self.image) @@ -62,7 +105,7 @@ class CanvasNode: self.core_node.position.y = int(y) self.canvas.move(self.id, x_offset, y_offset) self.canvas.move(self.text_id, x_offset, y_offset) - self.antenna_draw.update_antennas_position(x_offset, y_offset) + self.move_antennae(x_offset, y_offset) self.canvas.object_drag(self.id, x_offset, y_offset) for edge in self.edges: x1, y1, x2, y2 = self.canvas.coords(edge.id) diff --git a/coretk/coretk/nodeutils.py b/coretk/coretk/nodeutils.py index 6d880126..10d926f7 100644 --- a/coretk/coretk/nodeutils.py +++ b/coretk/coretk/nodeutils.py @@ -2,6 +2,7 @@ from core.api.grpc.core_pb2 import NodeType from coretk.images import ImageEnum, Images ICON_SIZE = 48 +ANTENNA_SIZE = 32 class NodeDraw: @@ -49,6 +50,7 @@ class NodeUtils: WIRELESS_NODES = {NodeType.WIRELESS_LAN, NodeType.EMANE} IGNORE_NODES = {NodeType.CONTROL_NET, NodeType.PEER_TO_PEER} NODE_MODELS = {"router", "host", "PC", "mdr", "prouter"} + ANTENNA_ICON = None @classmethod def is_ignore_node(cls, node_type): @@ -104,3 +106,4 @@ class NodeUtils: node_draw = NodeDraw.from_setup(image_enum, node_type, tooltip=tooltip) cls.NETWORK_NODES.append(node_draw) cls.NODE_ICONS[(node_type, None)] = node_draw.image + cls.ANTENNA_ICON = Images.get(ImageEnum.ANTENNA, ANTENNA_SIZE)