Commit cd540b01 authored by Pierre-Antoine Rouby's avatar Pierre-Antoine Rouby
Browse files

Network: Display edge as an arc.

Showing with 183 additions and 37 deletions
+183 -37
...@@ -176,11 +176,11 @@ class Graph(object): ...@@ -176,11 +176,11 @@ class Graph(object):
return edge return edge
def _add_edge(self, edge): def _add_edge(self, edge):
# This edge already exists ? # # This edge already exists ?
if any(filter(lambda e: (e.node1 == edge.node1 and # if any(filter(lambda e: (e.node1 == edge.node1 and
e.node2 == edge.node2), # e.node2 == edge.node2),
self._edges)): # self._edges)):
return None # return None
self._edges.append(edge) self._edges.append(edge)
......
...@@ -120,6 +120,8 @@ class NodeItem(QGraphicsItem): ...@@ -120,6 +120,8 @@ class NodeItem(QGraphicsItem):
class EdgeItem(QGraphicsItem): class EdgeItem(QGraphicsItem):
_arc_dist = 0.1
Type = QGraphicsItem.UserType + 2 Type = QGraphicsItem.UserType + 2
def __init__(self, src_node_item, dest_node_item, def __init__(self, src_node_item, dest_node_item,
...@@ -131,6 +133,21 @@ class EdgeItem(QGraphicsItem): ...@@ -131,6 +133,21 @@ class EdgeItem(QGraphicsItem):
self.edge = edge self.edge = edge
self.graph = graph_widget self.graph = graph_widget
self._ind = 1
geometry = self.compute_arc_two_point(
QPointF(
self.src_node.pos().x(),
self.src_node.pos().y()
),
QPointF(
self.dest_node.pos().x(),
self.dest_node.pos().y()
),
)
self._bound_rect = geometry['bound_rect']
self._arc = geometry['arc']
self.setAcceptedMouseButtons(Qt.NoButton) self.setAcceptedMouseButtons(Qt.NoButton)
...@@ -142,30 +159,19 @@ class EdgeItem(QGraphicsItem): ...@@ -142,30 +159,19 @@ class EdgeItem(QGraphicsItem):
pen_width = 2.0 pen_width = 2.0
extra = (pen_width + 5) / 2.0 extra = (pen_width + 5) / 2.0
return QRectF( return self._bound_rect.normalized().adjusted(
self.src_node.pos(), -extra, -extra, extra, extra
QSizeF( )
self.dest_node.pos().x() - self.src_node.pos().x(),
self.dest_node.pos().y() - self.src_node.pos().y()
)
).normalized().adjusted(-extra, -extra, extra, extra)
def shape(self): def shape(self):
# Shape around edge for mouse selection return self._arc
vec = self.dest_node.pos() - self.src_node.pos()
vec = vec * (5 / math.sqrt(QPointF.dotProduct(vec, vec)))
extra = QPointF(vec.y(), -vec.x())
result = QPainterPath(self.src_node.pos() - vec + extra) def paint(self, painter, option, widget):
result.lineTo(self.src_node.pos() - vec - extra) #self.paint_line(painter, option, widget)
result.lineTo(self.dest_node.pos() + vec - extra) self.paint_arc(painter, option, widget)
result.lineTo(self.dest_node.pos() + vec + extra)
result.closeSubpath()
return result
@timer @timer
def paint(self, painter, option, widget): def paint_line(self, painter, option, widget):
# Draw shape of the edge # Draw shape of the edge
# color = QColor(Qt.white) # color = QColor(Qt.white)
# color.setAlpha(128) # color.setAlpha(128)
...@@ -191,40 +197,169 @@ class EdgeItem(QGraphicsItem): ...@@ -191,40 +197,169 @@ class EdgeItem(QGraphicsItem):
color, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin color, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin
) )
) )
# Draw the line
painter.drawLine(line) painter.drawLine(line)
line_center = QPointF( # Draw arrow
center = QPointF(
(self.src_node.pos().x() + self.dest_node.pos().x()) / 2, (self.src_node.pos().x() + self.dest_node.pos().x()) / 2,
(self.src_node.pos().y() + self.dest_node.pos().y()) / 2, (self.src_node.pos().y() + self.dest_node.pos().y()) / 2,
) )
angle = math.acos(line.dx() / line.length())
if line.dy() >= 0:
angle = (math.pi * 2.0) - angle
# Draw the arrows self.paint_arrow(
brush = QBrush() painter, option, widget,
brush.setColor(color) color, center, angle
brush.setStyle(Qt.SolidPattern) )
@timer
def paint_arc(self, painter, option, widget):
line = QLineF(self.src_node.pos(), self.dest_node.pos())
if line.length() == 0.0:
return
# Select color
# color = Qt.darkBlue
color = Qt.black
if self.graph.selected_item() == self:
color = Qt.red
elif self.graph.current_edge() == self:
color = Qt.blue
elif not self.graph.graph.is_enable_edge(self.edge):
color = Qt.darkGray
painter.setPen(
QPen(
color, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin
)
)
geometry = self.compute_arc_two_point(
QPointF(
self.src_node.pos().x(),
self.src_node.pos().y()
),
QPointF(
self.dest_node.pos().x(),
self.dest_node.pos().y()
),
)
self._bound_rect = geometry['bound_rect']
self._arc = geometry['arc']
painter.drawPath(self._arc)
line = geometry['line']
angle = math.acos(line.dx() / line.length()) angle = math.acos(line.dx() / line.length())
if line.dy() >= 0: if line.dy() >= 0:
angle = (math.pi * 2.0) - angle angle = (math.pi * 2.0) - angle
self.paint_arrow(
painter, option, widget,
color, geometry['c'], angle,
)
def compute_arc_two_point(self, a, b):
# This function is a black magic spell for invoking an arc
# path between two points in Qt! (In fact, it's just cryptic
# trigonometry functions from stackoverflow:
# https://stackoverflow.com/questions/26901540/arc-in-qgraphicsscene)
c = self.compute_arc_p3(a, b)
line_ac = QLineF(a, c)
line_bc = QLineF(b, c)
line_ab = QLineF(a, b)
rad = abs(
line_bc.length() / (
2 * math.sin(
math.radians(
line_ac.angleTo(line_ab)
)
)
)
)
bisector_bc = QLineF(line_bc.pointAt(0.5), line_bc.p2())
bisector_bc.setAngle(line_bc.normalVector().angle())
bisector_ab = QLineF(line_ab.pointAt(0.5), line_ab.p2())
bisector_ab.setAngle(line_ab.normalVector().angle())
center = QPointF(0,0)
bisector_ab.intersect(bisector_bc, center)
circle = QRectF(
center.x() - rad,
center.y() - rad,
rad * 2, rad * 2
)
line_oa = QLineF(center, a)
line_ob = QLineF(center, b)
line_oc = QLineF(center, c)
start = line_ob
end = line_oa
w = 1
bounding_rect = circle.adjusted(
-w, -w, w, w
)
path = QPainterPath()
path.arcMoveTo(circle, start.angle())
path.arcTo(circle, start.angle(), start.angleTo(end))
return {
'bound_rect': bounding_rect,
'arc': path,
'c': c,
'line': line_ab,
}
def compute_arc_p3(self, p1, p2):
dist_p3 = self._ind * self._arc_dist
center_p1_p2 = QPointF(
(p1.x() + p2.x()) / 2,
(p1.y() + p2.y()) / 2
)
# u = (p2.x() - p1.x(), p2.y() - p1.y())
v = (p2.y() - p1.y(), p1.x() - p2.x())
p3 = QPointF(
center_p1_p2.x() + dist_p3 * v[0],
center_p1_p2.y() + dist_p3 * v[1]
)
return p3
def paint_arrow(self, painter, option, widget,
color, center, angle):
brush = QBrush()
brush.setColor(color)
brush.setStyle(Qt.SolidPattern)
size = 10.0 size = 10.0
arrow_p1 = line_center + QPointF( arrow_p1 = center + QPointF(
math.sin(angle - math.pi / 3) * size, math.sin(angle - math.pi / 3) * size,
math.cos(angle - math.pi / 3) * size math.cos(angle - math.pi / 3) * size
) )
arrow_p2 = line_center + QPointF( arrow_p2 = center + QPointF(
math.sin(angle - math.pi + math.pi / 3) * size, math.sin(angle - math.pi + math.pi / 3) * size,
math.cos(angle - math.pi + math.pi / 3) * size math.cos(angle - math.pi + math.pi / 3) * size
) )
poly = QPolygonF([line_center, arrow_p1, arrow_p2]) poly = QPolygonF([center, arrow_p1, arrow_p2])
path = QPainterPath() path = QPainterPath()
path.addPolygon(poly) path.addPolygon(poly)
painter.drawPolygon(poly) painter.drawPolygon(poly)
painter.fillPath(path, brush) painter.fillPath(path, brush)
class NodeText(QGraphicsTextItem): class NodeText(QGraphicsTextItem):
def __init__(self, node_item): def __init__(self, node_item):
super(NodeText, self).__init__() super(NodeText, self).__init__()
...@@ -364,22 +499,33 @@ class GraphWidget(QGraphicsView): ...@@ -364,22 +499,33 @@ class GraphWidget(QGraphicsView):
curr_edge = self.graph.current_reach() curr_edge = self.graph.current_reach()
multiple_edges = {}
for edge in self.graph.edges(): for edge in self.graph.edges():
n1 = list( n1 = next(
filter( filter(
lambda n: n.node.name == edge.node1.name, lambda n: n.node.name == edge.node1.name,
self.node_items self.node_items
) )
) )
n2 = list( n2 = next(
filter( filter(
lambda n: n.node.name == edge.node2.name, lambda n: n.node.name == edge.node2.name,
self.node_items self.node_items
) )
) )
iedge = EdgeItem(n1[0], n2[0], edge, self) # Multiple edges counter
if (n1,n2) not in multiple_edges:
ind = 1
else:
ind = multiple_edges[(n1,n2)] + 1
multiple_edges[(n1,n2)] = ind
iedge = EdgeItem(n1, n2, edge, self)
iedge._ind = ind
if edge == curr_edge: if edge == curr_edge:
self._current_edge = iedge self._current_edge = iedge
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment