Add new visualisation stuff.

Does apx. right thing, but the other right…
topo-mov
LEdoian 1 year ago
parent 3243ae1c26
commit 12b0c6578e

@ -0,0 +1,195 @@
from PySide6.QtWidgets import QGraphicsItem, QGraphicsRectItem, QGraphicsSimpleTextItem, QGraphicsLineItem
from PySide6.QtCore import QLineF, Qt
from PySide6.QtGui import QColor, QBrush, QPen
def _rid_to_str(rid):
from ipaddress import IPv4Address
return str(IPv4Address(rid))
def _addrs_as_str(addrs):
if addrs is None: return ''
from ipaddress import IPv4Network, IPv6Network
if isinstance(addrs, IPv4Network) or isinstance(addrs, IPv6Network): return str(addrs)
return '\n'.join(str(a) for a in addrs)
# TODO: we MAY WISH TO use QGraphicsItemGroup.
# TODO: Do not duplicate so much code!
# TODO: tooltips?
class RouterGraphicsItem(QGraphicsItem):
def __init__(self, vtxid, style, window, parent=None):
super().__init__(parent)
self.vertex_id = vtxid
self.window = window
size = 30
self.icon = QGraphicsRectItem(-size/2, -size/2, size, size, parent=self)
self.icon.setZValue(200)
self.icon.setBrush(QBrush(QColor('yellow')))
self.label = QGraphicsSimpleTextItem(parent=self.icon)
self.label.setY(size * 0.8)
self.label.setText(_rid_to_str(vtxid.router_id))
# Center text
text_width = self.label.boundingRect().width()
self.label.setX(-text_width/2)
br = self.icon.boundingRect()
br.adjust(-5, -5, 5, 5)
self.highlight = QGraphicsRectItem(br, parent=self)
self.highlight.setZValue(190)
p = self.highlight.pen()
p.setStyle(Qt.PenStyle.NoPen)
self.highlight.setPen(p)
self.setFlag(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable)
self.apply_position(style)
self.apply_style(style)
self.setZValue(200)
def apply_position(self, style):
x, y = style['position']
self.setPos(x, y)
def apply_style(self, style):
# Highlight:
r,g,b,a = style['highlight_colour']
color = QColor(r,g,b,a)
br = self.highlight.brush()
br.setStyle(Qt.BrushStyle.SolidPattern)
br.setColor(color)
self.highlight.setBrush(br)
# Vertex moving
def mouseMoveEvent(self, evt):
# Other selected graphics items do not receive the event, so we need to
# move everything.
selected_items = self.window.scene.selectedItems()
all_edges = set()
for qgri in selected_items:
# It is a vertex.
vtxid = self.window.topologyitems[qgri]
vtx = self.window.annot_topo.topology.vertices[vtxid]
all_edges |= vtx.incoming_edges | vtx.outgoing_edges
for edge in all_edges:
self.window.graphicsitems[edge].update_line()
super().mouseMoveEvent(evt)
# Admit we are basically only a wrapper of the icon.
def boundingRect(self):
return self.icon.boundingRect()
def paint(self, painter, option, widget):
self.icon.paint(painter, option, widget)
class NetworkGraphicsItem(QGraphicsItem):
def __init__(self, vtxid, style, window, parent=None):
super().__init__(parent)
self.vertex_id = vtxid
self.window = window
size = 40
self.icon = QGraphicsRectItem(-size/2, -size/2, size, size, parent=self)
self.icon.setZValue(200)
self.icon.setBrush(QBrush(QColor('gray')))
self.label = QGraphicsSimpleTextItem(parent=self.icon)
self.label.setText(_addrs_as_str(vtxid.address))
# Center text
text_width = self.label.boundingRect().width()
self.label.setX(-text_width/2)
text_height = self.label.boundingRect().height()
self.label.setY(-text_height/2)
br = self.icon.boundingRect()
br.adjust(-5, -5, 5, 5)
self.highlight = QGraphicsRectItem(br, parent=self)
self.highlight.setZValue(190)
p = self.highlight.pen()
p.setStyle(Qt.PenStyle.NoPen)
self.highlight.setPen(p)
self.setFlag(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable)
self.apply_position(style)
self.apply_style(style)
self.setZValue(200)
def apply_position(self, style):
x, y = style['position']
self.setPos(x, y)
def apply_style(self, style):
# Highlight:
r,g,b,a = style['highlight_colour']
color = QColor(r,g,b,a)
br = self.highlight.brush()
br.setColor(color)
br.setStyle(Qt.BrushStyle.SolidPattern)
self.highlight.setBrush(br)
# Vertex moving
def mouseMoveEvent(self, evt):
# Other selected graphics items do not receive the event, so we need to
# move everything.
selected_items = self.window.scene.selectedItems()
all_edges = set()
for qgri in selected_items:
# It is a vertex.
vtxid = self.window.topologyitems[qgri]
vtx = self.window.annot_topo.topology.vertices[vtxid]
all_edges |= vtx.incoming_edges | vtx.outgoing_edges
for edge in all_edges:
self.window.graphicsitems[edge].update_line()
super().mouseMoveEvent(evt)
# Admit we are basically only a wrapper of the icon.
def boundingRect(self):
return self.icon.boundingRect()
def paint(self, painter, option, widget):
self.icon.paint(painter, option, widget)
class EdgeGraphicsItem(QGraphicsItem):
def __init__(self, edge, style, window, parent=None):
super().__init__(parent)
self.edge = edge
self.window = window
# Cache the two related objects.
# NOTE: this is only possible because the main window first creates vertices and then edges.
self.e_source = self.window.graphicsitems[edge.source]
self.e_target = self.window.graphicsitems[edge.target]
qlinef = QLineF(self.e_source.x(), self.e_source.y(), self.e_target.x(), self.e_target.y())
self.top_line = QGraphicsLineItem(qlinef, parent=self)
self.top_line.setZValue(100)
self.bottom_line = QGraphicsLineItem(qlinef, parent=self.top_line)
self.bottom_line.setZValue(90)
self.apply_style(style)
self.setZValue(100)
def update_line(self):
qlinef = QLineF(self.e_source.x(), self.e_source.y(), self.e_target.x(), self.e_target.y())
self.top_line.setLine(qlinef)
self.bottom_line.setLine(qlinef)
def apply_style(self, style):
if 'width' in style:
p = self.top_line.pen()
p.setWidth(style['width'])
self.top_line.setPen(p)
p = QPen(p)
p.setWidth(1.5*style['width'])
self.bottom_line.setPen(p)
if 'colour' in style:
r,g,b,a = style['colour']
col = QColor(r,g,b,a)
p = self.top_line.pen()
p.setColor(col)
self.top_line.setPen(p)
if 'highlight_colour' in style:
r,g,b,a = style['highlight_colour']
col = QColor(r,g,b,a)
p = self.bottom_line.pen()
p.setColor(col)
self.bottom_line.setPen(p)
def boundingRect(self):
return self.top_line.boundingRect()
def paint(self, painter, option, widget):
return self.top_line.paint(painter, option, widget)

@ -1,60 +0,0 @@
def create_qgritems(at):
shape = MyGraphicsRectItem(-size/2, -size/2, size, size)
shape.setBrush(brush)
shape.setPos(x, y)
shape.setToolTip(rk)
label = QtWidgets.QGraphicsSimpleTextItem(rk, parent=shape)
label.setY(size*0.8)
# Centering:
text_width = label.boundingRect().width()
label.setX(-text_width/2)
shape.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable | QtWidgets.QGraphicsItem.ItemIsSelectable)
at.router_annotations[rk].append(shape)
for nk, n in topo.networks.items():
size = 10
brush = None
for tag in at.network_annotations[nk][-1::-1]:
if isinstance(tag, QtGui.QBrush):
brush = tag
break
pos = None
for tag in at.network_annotations[nk][-1::-1]:
if isinstance(tag, Position):
pos = tag
break
x = pos.x
y = pos.y
shape = MyGraphicsRectItem(-size/2, -size/2, size, size)
shape.setBrush(brush)
shape.setPos(x, y)
shape.setToolTip(nk)
label = QtWidgets.QGraphicsSimpleTextItem(nk, parent=shape)
label.setY(size*0.8)
# Centering:
text_width = label.boundingRect().width()
label.setX(-text_width/2)
shape.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable | QtWidgets.QGraphicsItem.ItemIsSelectable)
at.network_annotations[nk].append(shape)
for lk, l in topo.links.items():
rid = l.router.ident
nid = l.network.ident
rpos = None
for tag in at.router_annotations[rid][-1::-1]:
if isinstance(tag, QtWidgets.QGraphicsRectItem):
ritem = tag
if isinstance(tag, Position):
rpos = tag
break
npos = None
for tag in at.network_annotations[nid][-1::-1]:
if isinstance(tag, QtWidgets.QGraphicsRectItem):
nitem = tag
if isinstance(tag, Position):
npos = tag
break

@ -1,23 +0,0 @@
from PySide6.QtWidgets import QGraphicsRectItem
from PySide6.QtCore import QLineF
class MyGraphicsRectItem(QGraphicsRectItem):
#def __init__(self, *a, **kwa):
# return super().__init__(*a, **kwa)
#def itemChange(self, change, val):
# return super().itemChange(change, val)
def mouseMoveEvent(self, evt):
print(f'Moving: {self}')
line = self.data(0)
other_end = line.data(0)
if other_end == self:
other_end = line.data(1)
new_qlinef = QLineF(
self.x(),
self.y(),
other_end.x(),
other_end.y(),
)
line.setLine(new_qlinef)
return super().mouseMoveEvent(evt)

@ -6,37 +6,18 @@ from birdvisu.annotations.layout import MegaStyler
from birdvisu.ospfsock import BirdSocketConnection from birdvisu.ospfsock import BirdSocketConnection
from birdvisu.providers import BirdSocketTopologyProvider, OspfFileTopologyProvider, OspfFileParseError from birdvisu.providers import BirdSocketTopologyProvider, OspfFileTopologyProvider, OspfFileParseError
from birdvisu.topo_v3 import TopologyV3, VertexID from birdvisu.topo_v3 import TopologyV3, VertexID
from birdvisu.graphics_items import RouterGraphicsItem, NetworkGraphicsItem, EdgeGraphicsItem
from collections import defaultdict from collections import defaultdict
from enum import Enum, auto from enum import Enum, auto
from ipaddress import IPv4Address from ipaddress import IPv4Address
from PySide6 import QtCore, QtGui, QtWidgets from PySide6 import QtCore, QtGui, QtWidgets
from PySide6.QtCore import Slot from PySide6.QtCore import Slot, QObject
from random import randint from random import randint
import sys import sys
app = QtWidgets.QApplication([]) app = QtWidgets.QApplication([])
class MyGraphicsRectItem(QtWidgets.QGraphicsRectItem):
def __init__(self, nei, shapes, *a, **kwa):
self.nei = nei
self.shapes = shapes
return super().__init__(*a, **kwa)
#def itemChange(self, change, val):
# return super().itemChange(change, val)
def mouseMoveEvent(self, evt):
vtxid = self.data(0)
for e in self.nei[vtxid]:
x1 = self.x()
y1 = self.y()
other = e.source if e.source != vtxid else e.target
x2 = self.shapes[other].x()
y2 = self.shapes[other].y()
qlinef = QtCore.QLineF(x1, y1, x2, y2)
self.shapes[e].setLine(qlinef)
return super().mouseMoveEvent(evt)
class BirdTopologyLoader(QtWidgets.QDialog): class BirdTopologyLoader(QtWidgets.QDialog):
def __init__(self, *a, **kwa): def __init__(self, *a, **kwa):
super().__init__(*a, **kwa) super().__init__(*a, **kwa)
@ -268,49 +249,13 @@ class MainWindow(QtWidgets.QMainWindow):
self.scene.addItem(gritem) self.scene.addItem(gritem)
def create_vertex(self, vtxid, style): def create_vertex(self, vtxid, style):
... if vtxid.is_router:
return RouterGraphicsItem(vtxid, style, self)
else:
return NetworkGraphicsItem(vtxid, style, self)
def create_edge(self, edge, style): def create_edge(self, edge, style):
... return EdgeGraphicsItem(edge, style, self)
def ad_hoc_draw_visu(self):
shapes = dict()
self.nei = defaultdict(lambda: [])
for k, v in self.annot_topo.topology.vertices.items():
size = 30 if k.is_router else 10
x, y = randint(0, 1920), randint(0, 1080)
shape = MyGraphicsRectItem(self.nei, shapes, -size/2, -size/2, size, size)
shape.setPos(x,y)
# TODO:brush
label_text = str(IPv4Address(k.router_id)) if k.is_router else str(k.address) # Surprisingly works for all the possible addresses.
label = QtWidgets.QGraphicsSimpleTextItem(label_text, parent=shape)
label.setY(size*0.8)
text_width = label.boundingRect().width()
label.setX(-text_width/2)
shape.setData(0, k)
shape.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable | QtWidgets.QGraphicsItem.ItemIsSelectable)
shapes[k] = shape
for e in self.annot_topo.topology.edges:
start = shapes[e.source].pos()
end = shapes[e.target].pos()
qlinef = QtCore.QLineF(start, end)
line = QtWidgets.QGraphicsLineItem(qlinef)
line.setData(0, e)
self.nei[e.source].append(e)
self.nei[e.target].append(e)
shapes[e] = line
if self.highlighter is not None and self.highlighter in self.annot_topo.annotations:
ann = self.annot_topo.annotations[self.highlighter]
for shk in ann.for_vertex.keys() | ann.for_edge.keys():
pen = QtGui.QPen(QtGui.QColor('blue'))
pen.setWidth(pen.width() * 3)
c = pen.color()
c.setAlpha(128)
pen.setColor(c)
shapes[shk].setPen(pen)
# FIXME: also color edges in opposite direction
for sh in shapes.values(): self.scene.addItem(sh)
main_window = MainWindow() main_window = MainWindow()
main_window.show() main_window.show()

Loading…
Cancel
Save