diff options
author | sumit | 2020-06-08 17:17:41 +0530 |
---|---|---|
committer | sumit | 2020-06-08 17:17:41 +0530 |
commit | 6679f42a74e0ca9556c260f4c9d710c0e83e13d0 (patch) | |
tree | f005540fc13afe071cc407d2e1be66af9ee9885d /src/main/python/shapes/line.py | |
parent | 8b3337c29d33cd4fe9fb4d3f1796daa4b623616a (diff) | |
download | Chemical-PFD-6679f42a74e0ca9556c260f4c9d710c0e83e13d0.tar.gz Chemical-PFD-6679f42a74e0ca9556c260f4c9d710c0e83e13d0.tar.bz2 Chemical-PFD-6679f42a74e0ca9556c260f4c9d710c0e83e13d0.zip |
make line connect able another line
Diffstat (limited to 'src/main/python/shapes/line.py')
-rw-r--r-- | src/main/python/shapes/line.py | 293 |
1 files changed, 203 insertions, 90 deletions
diff --git a/src/main/python/shapes/line.py b/src/main/python/shapes/line.py index d968ace..dc0a09c 100644 --- a/src/main/python/shapes/line.py +++ b/src/main/python/shapes/line.py @@ -31,8 +31,29 @@ class Grabber(QGraphicsPathItem): p = QPointF(self.pos()) if self._direction == Qt.Horizontal: p.setX(value.x()) + if self.parentItem().refLine and self.m_index == len(self.parentItem().points) - 2: + points = self.parentItem().refLine.points + point1 = points[self.parentItem().refIndex] + point2 = points[self.parentItem().refIndex + 1] + point1 = self.parentItem().mapFromItem(self.parentItem().refLine, point1) + point2 = self.parentItem().mapFromItem(self.parentItem().refLine, point2) + if p.x() < min(point1.x(), point2.x()): + p.setX(min(point1.x(), point2.x())) + elif p.x() > max(point1.x(), point2.x()): + p.setX(max(point1.x(), point2.x())) elif self._direction == Qt.Vertical: p.setY(value.y()) + if self.parentItem().refLine and self.m_index == len(self.parentItem().points) - 2: + points = self.parentItem().refLine.points + point1 = points[self.parentItem().refIndex] + point2 = points[self.parentItem().refIndex + 1] + point1 = self.parentItem().mapFromItem(self.parentItem().refLine, point1) + point2 = self.parentItem().mapFromItem(self.parentItem().refLine, point2) + if p.y() < min(point1.y(), point2.y()): + p.setY(min(point1.y(), point2.y())) + elif p.y() > max(point1.y(), point2.y()): + p.setY(max(point1.y(), point2.y())) + movement = p - self.pos() self.m_annotation_item.movePoints(self.m_index, movement) return p @@ -105,23 +126,23 @@ class LineLabel(QGraphicsTextItem): self.setPlainText("abc") self.index = None self.gap = None - self.setTextInteractionFlags(Qt.TextEditorInteraction) self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable) + self.setTextInteractionFlags(Qt.NoTextInteraction) self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True) - self.line = QGraphicsLineItem() - self.setPos(pos-self.boundingRect().center()) + self.setPos(pos - self.boundingRect().center()) self.setParentItem(parent) + self.line = QGraphicsLineItem() self.line.setParentItem(self) + self.line.setFlag(QGraphicsItem.ItemStacksBehindParent) self.resetPos() - # self.line.setFlag(QGraphicsItem.ItemStacksBehindParent) def paint(self, painter, option, widget): - # painter.save() - # painter.setBrush(QBrush(Qt.white)) + painter.save() + painter.setBrush(QBrush(Qt.white)) painter.drawEllipse(self.boundingRect()) - # painter.restore() + painter.restore() super(LineLabel, self).paint(painter, option, widget) def updateLabel(self): @@ -155,7 +176,7 @@ class LineLabel(QGraphicsTextItem): for i in range(len(points) - 1): A = points[i] B = points[i + 1] - C = QPointF(self.pos()+self.boundingRect().center()) + C = QPointF(self.pos() + self.boundingRect().center()) BAx = B.x() - A.x() BAy = B.y() - A.y() CAx = C.x() - A.x() @@ -177,10 +198,10 @@ class LineLabel(QGraphicsTextItem): point = self.mapFromScene(min_A) if min_A.x() == min_B.x(): self.setPos(self.parentItem().mapFromScene(QPointF(min_A.x() + 10, self.y()))) - self.gap = 10+self.boundingRect().width()/2 + self.gap = 10 + self.boundingRect().width() / 2 else: self.setPos(self.parentItem().mapFromScene(QPointF(self.x(), min_A.y() - 30))) - self.gap = -30+self.boundingRect().height()/2 + self.gap = -30 + self.boundingRect().height() / 2 def itemChange(self, change, value): if change == QGraphicsItem.ItemPositionChange and self.scene(): @@ -230,42 +251,81 @@ class LineLabel(QGraphicsTextItem): else: self.line.setLine(center.x(), center.y(), center.x(), point.y()) + def mouseDoubleClickEvent(self, event): + self.setTextInteractionFlags(Qt.TextEditorInteraction) + self.setFocus() + super(LineLabel, self).mouseDoubleClickEvent(event) + + def focusOutEvent(self, event): + super(LineLabel, self).focusOutEvent(event) + self.setTextInteractionFlags(Qt.NoTextInteraction) + + +def findIndex(line, pos): + points = line.points + min_A = QPointF() + min_B = QPointF() + min_dis = math.inf + index = -1 + for i in range(len(points) - 1): + A = points[i] + B = points[i + 1] + C = pos + BAx = B.x() - A.x() + BAy = B.y() - A.y() + CAx = C.x() - A.x() + CAy = C.y() - A.y() + length = math.sqrt(BAx * BAx + BAy * BAy) + if BAx == 0: + if not min(A.y(), B.y()) <= C.y() <= max(A.y(), B.y()): + continue + if BAy == 0: + if not min(A.x(), B.x()) <= C.x() <= max(A.x(), B.x()): + continue + if length > 0: + dis = (BAx * CAy - CAx * BAy) / length + if abs(dis) < abs(min_dis): + min_dis = dis + min_A = A + min_B = B + index = i + return index + class Line(QGraphicsPathItem): """ Extends QGraphicsPathItem to draw zig-zag line consisting of multiple points """ - penStyle = Qt.SolidLine - def __init__(self, startPoint, endPoint, **args): QGraphicsItem.__init__(self, **args) self.startPoint = startPoint self.endPoint = endPoint - #stores all points of line + # stores all points of line self.points = [] - self.points.extend([startPoint, endPoint]) self.startGripItem = None self.endGripItem = None - self._selected = False self.m_grabbers = [] - # stores current pen style of line - self.penStyle = Line.penStyle - # set graphical settings for this item + # set graphical settings for line self.setFlag(QGraphicsItem.ItemIsSelectable, True) self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True) self.setAcceptHoverEvents(True) - # initiates path - self.createPath() - self.commonPaths=[] - self.label = None + # store reference if line connect another line + self.refLine = None # reference line + self.refIndex = None # start index of segment to which it connects + self.commonPathsCenters = [] + self.midLines = [] + self.label = [] def advance(self, phase): + if not phase: + return # items colliding with line - items = self.scene().items(self.shape(),Qt.IntersectsItemShape,Qt.AscendingOrder) - self.commonPaths = [] - # if item is line and stacked above self + # items = self.collidingItems(Qt.IntersectsItemShape) + items = self.scene().items(self.shape(), Qt.IntersectsItemShape, Qt.AscendingOrder) + self.commonPathsCenters = [] + # if item is line and stacked above for item in items: - if type(item) in [type(self)]: + if type(item) in [type(self)]: if item == self: break shape = item.shape() @@ -274,50 +334,57 @@ class Line(QGraphicsPathItem): polygons = commonPath.toSubpathPolygons() for polygon in polygons: center = polygon.boundingRect().center() - self.commonPaths.append(center) + if polygon.size() == 5: + if item.refLine: + i = len(item.points) - 2 + x1, y1 = item.points[i].x(), item.points[i].y() + x2, y2 = item.points[i+1].x(), item.points[i+1].y() + x, y = center.x(), center.y() + if x == x1 == x2 and not min(y1, y2) + 8 <= y < max(y1, y2) - 8: + continue + elif y == y1 == y2 and not min(x1, x2) + 8 <= x < max(x1, x2) - 8: + continue + else: + self.commonPathsCenters.append(center) + else: + self.commonPathsCenters.append(center) self.update() - + def paint(self, painter, option, widget): color = Qt.red if self.isSelected() else Qt.black - painter.setPen(QPen(color, 2, self.penStyle)) - # path = self.path() - # painter.drawPath(path) + painter.setPen(QPen(color, 2, Qt.SolidLine)) path = QPainterPath(self.startPoint) # iterating over all points of line for i in range(len(self.points) - 1): x1, y1 = self.points[i].x(), self.points[i].y() - x2, y2 = self.points[i+1].x(), self.points[i+1].y() - for point in sorted(self.commonPaths, key = lambda x: x.x() + x.y(), reverse=x2<x1 or y2<y1): + x2, y2 = self.points[i + 1].x(), self.points[i + 1].y() + for point in sorted(self.commonPathsCenters, key=lambda x: x.x() + x.y(), reverse=x2 < x1 or y2 < y1): x, y = point.x(), point.y() - # if not x1 * (y - y2) + x * (y2 - y1) + x2 * (y1 - y) : if x == x1 == x2: - #vertical - if min(y1, y2) <= y < max(y1, y2): - if y2>y1: + # vertical + if min(y1, y2) + 8 <= y < max(y1, y2) - 8: + if y2 > y1: path.lineTo(point - QPointF(0, 8)) - path.arcTo(QRectF(x-8, y-8, 16, 16), 90, -180) + path.arcTo(QRectF(x - 8, y - 8, 16, 16), 90, -180) path.moveTo(point + QPointF(0, 8)) else: path.lineTo(point + QPointF(0, 8)) - path.arcTo(QRectF(x-8, y-8, 16, 16), -90, 180) + path.arcTo(QRectF(x - 8, y - 8, 16, 16), -90, 180) path.moveTo(point - QPointF(0, 8)) elif y == y1 == y2: - #horizontal - if min(x1, x2) <= x < max(x1, x2): - if x2>x1: + # horizontal + if min(x1, x2) + 8 <= x < max(x1, x2) - 8: + if x2 > x1: path.lineTo(point - QPointF(8, 0)) - path.arcTo(QRectF(x-8, y-8, 16, 16), 180, 180) + path.arcTo(QRectF(x - 8, y - 8, 16, 16), 180, 180) path.moveTo(point + QPointF(8, 0)) else: path.lineTo(point + QPointF(8, 0)) - path.arcTo(QRectF(x-8, y-8, 16, 16), 0, -180) + path.arcTo(QRectF(x - 8, y - 8, 16, 16), 0, -180) path.lineTo(point - QPointF(8, 0)) - path.lineTo(self.points[i+1]) - - painter.drawPath(path) - - + path.lineTo(self.points[i + 1]) + painter.drawPath(path) def createPath(self): """ @@ -327,9 +394,28 @@ class Line(QGraphicsPathItem): offset = 30 x0, y0 = self.startPoint.x(), self.startPoint.y() x1, y1 = self.endPoint.x(), self.endPoint.y() - # create line is in process + # create path for line in process self.points = [self.startPoint, QPointF((x0 + x1) / 2, y0), QPointF((x0 + x1) / 2, y1), self.endPoint] # final path of line + if self.refLine: + from .shapes import LineGripItem + direction = "left" + points = self.refLine.points + point1 = points[self.refIndex] + point2 = points[self.refIndex + 1] + if point1.x() == point2.x(): + if point1.x() < self.startPoint.x(): + direction = "right" + else: + direction = "left" + elif point1.y() == point2.y(): + if point1.y() > self.startPoint.y(): + direction = "top" + else: + direction = "bottom" + + self.endGripItem = LineGripItem(self, -1, direction, self) + self.endGripItem.setPos(self.endPoint) if self.startGripItem and self.endGripItem: # determine ns (point next to start) item = self.startGripItem @@ -342,7 +428,7 @@ class Line(QGraphicsPathItem): ns = QPointF(self.startPoint.x(), self.startPoint.y() + offset) else: ns = QPointF(self.startPoint.x() + offset, self.startPoint.y()) - # pe (point previous to end) + # determine pe (point previous to end) item = self.endGripItem self.endPoint = item.parentItem().mapToScene(item.pos()) if item.m_location == "top": @@ -610,6 +696,11 @@ class Line(QGraphicsPathItem): for i in range(1, len(self.points)): path.lineTo(self.points[i]) self.setPath(path) + + if self.refLine: + self.scene().removeItem(self.endGripItem) + self.endGripItem = None + self.addGrabber() if self.endGripItem: self.addGrabber() @@ -623,8 +714,10 @@ class Line(QGraphicsPathItem): path.lineTo(self.points[i]) path.lineTo(self.endPoint) self.setPath(path) - if self.label: - self.label.updateLabel() + self.updateGrabber() + for label in self.label: + label.updateLabel() + self.updateMidLines() def updatePoints(self): """ @@ -632,29 +725,21 @@ class Line(QGraphicsPathItem): :return: """ if self.startGripItem: - self.points[0]= self.startPoint - if self.endGripItem: - self.points[len(self.points) - 1] = self.endPoint - if self.startGripItem.m_location in ["left", "right"]: + self.points[0] = self.startPoint point = self.points[1] - self.points[1] = QPointF(point.x(), self.startPoint.y()) - if self.endGripItem.m_location in ["left", "right"]: - point = self.points[len(self.points) - 2] - self.points[len(self.points) - 2] = QPointF(point.x(), self.endPoint.y()) + if self.startGripItem.m_location in ["left", "right"]: + self.points[1] = QPointF(point.x(), self.startPoint.y()) else: - point = self.points[len(self.points) - 2] - self.points[len(self.points) - 2] = QPointF(self.endPoint.x(), point.y()) - else: - point = self.points[1] - self.points[1] = QPointF(self.startPoint.x(), point.y()) + self.points[1] = QPointF(self.startPoint.x(), point.y()) + + if self.endGripItem: + self.points[len(self.points) - 1] = self.endPoint + point = self.points[len(self.points) - 2] if self.endGripItem.m_location in ["left", "right"]: - point = self.points[len(self.points) - 2] self.points[len(self.points) - 2] = QPointF(point.x(), self.endPoint.y()) else: - point = self.points[len(self.points) - 2] self.points[len(self.points) - 2] = QPointF(self.endPoint.x(), point.y()) - def shape(self): """generates outline for path """ @@ -670,21 +755,25 @@ class Line(QGraphicsPathItem): point = self.points[i] point += movement self.points[i] = point - self.updatePath() - self.updateGrabber([index]) + self.updatePath() def addGrabber(self): """adds grabber when line is moved """ - if self.startGripItem.m_location in ["left", "right"]: - direction = [Qt.Horizontal, Qt.Vertical] + for grabber in self.m_grabbers: + self.scene().removeItem(grabber) + if self.endGripItem: + count = range(1, len(self.points) - 2) else: - direction = [Qt.Vertical, Qt.Horizontal] - for i in range(1, len(self.points) - 2): - item = Grabber(self, i, direction[(i - 1)%2]) + count = range(1, len(self.points) - 1) + for i in count: + if self.points[i].x() == self.points[i + 1].x(): + direction = Qt.Horizontal + else: + direction = Qt.Vertical + item = Grabber(self, i, direction) item.setParentItem(self) item.setPos(self.pos()) - self.scene().addItem(item) self.m_grabbers.append(item) def updateGrabber(self, index_no_updates=None): @@ -692,7 +781,7 @@ class Line(QGraphicsPathItem): """ index_no_updates = index_no_updates or [] for grabber in self.m_grabbers: - if grabber.m_index in index_no_updates: continue + if grabber.m_index in index_no_updates or grabber.isSelected(): continue index = grabber.m_index startPoint = self.points[index] endPoint = self.points[index + 1] @@ -705,13 +794,15 @@ class Line(QGraphicsPathItem): if change == QGraphicsItem.ItemSelectedHasChanged: if value == 1: self.showGripItem() + items = self.collidingItems(Qt.IntersectsItemShape) + for item in items: + if type(item) == type(self): + item.stackBefore(self) + self.scene().update() else: self.hideGripItem() return - if change == QGraphicsItem.ItemSceneHasChanged and self.scene(): - # self.addGrabber() - # self.updateGrabber() - return + return super(Line, self).itemChange(change, value) def updateLine(self, startPoint=None, endPoint=None): @@ -727,7 +818,6 @@ class Line(QGraphicsPathItem): self.endPoint = endPoint self.createPath() self.updateGrabber() - self.scene().update() return if self.startGripItem and self.endGripItem: @@ -736,7 +826,35 @@ class Line(QGraphicsPathItem): item = self.endGripItem self.endPoint = item.parentItem().mapToScene(item.pos()) self.updatePath() - self.updateGrabber() + + if self.startGripItem and self.refLine: + item = self.startGripItem + self.startPoint = item.parentItem().mapToScene(item.pos()) + self.updatePath() + + def updateMidLines(self): + for line in self.midLines: + points = line.refLine.points + point1 = points[line.refIndex] + point2 = points[line.refIndex + 1] + i = len(line.points) - 1 + if point1.x() == point2.x(): + line.points[i].setX(point1.x()) + if line.points[i].y() < min(point1.y(), point2.y()): + line.points[i].setY(min(point1.y(), point2.y())) + line.points[i-1].setY(min(point1.y(), point2.y())) + elif line.points[i].y() > max(point1.y(), point2.y()): + line.points[i].setY(max(point1.y(), point2.y())) + line.points[i-1].setY(max(point1.y(), point2.y())) + elif point1.y() == point2.y(): + line.points[i].setY(point1.y()) + if line.points[i].x() < min(point1.x(), point2.x()): + line.points[i].setX(min(point1.x(), point2.x())) + line.points[i-1].setX(min(point1.x(), point2.x())) + elif line.points[i].x() > max(point1.x(), point2.x()): + line.points[i].setX(max(point1.x(), point2.x())) + line.points[i-1].setX(max(point1.x(), point2.x())) + line.updatePath() def removeFromCanvas(self): """This function is used to remove connecting line from canvas @@ -767,17 +885,12 @@ class Line(QGraphicsPathItem): def setEndGripItem(self, item): self.endGripItem = item - def setPenStyle(self, style): - """change current pen style for line""" - self.penStyle = style - def contextMenuEvent(self, event): """Pop up menu :return: """ contextMenu = QMenu() addLableAction = contextMenu.addAction("add Label") - # addLableAction.triggered.connect(self.addLabel) action = contextMenu.exec_(event.screenPos()) if action == addLableAction: - self.label = LineLabel(event.scenePos(), self)
\ No newline at end of file + self.label.append(LineLabel(event.scenePos(), self))
\ No newline at end of file |