class SubScene(QtWidgets.QGraphicsScene): def __init__(self, parent=None, dist = distance, eps=30, modes = [0,1,2]): super().__init__(parent) self.mode = modes[0] self.modes = modes self.QGitem=None self.line = None self.polys = [] self.dist_func = dist self.eps = eps self.polyFinished = False self.selectedContour = None self.selectedVertex=None self.overrideCursor(QtCore.Qt.ArrowCursor) def setDrawing(self): self.mode = self.modes[1] def setEdit(self): self.mode = self.modes[2] def setMovement(self): self.mode = self.modes[0] def updatePolyPoint(self, poly, pos): poly.setPos(pos) poly.addPoint(pos) def clearContours(self): if self.selectedContour: self.selectedContour.highlightClear() self.selectedContour = None self.forceClearContours() self.update() def forceClearContours(self): for contour in self.items()[:-1]: contour.highlightClear() self.update() def returnPoints(self): if self.QGitem is not None: pts = self.QGitem.points elif len(self.polys) > 0: pts = self.polys[0].points else: return None return [[p.x(), p.y()] for p in pts] def addAIPolygon(self, points): qPoints = [QtCore.QPoint(x,y) for x,y in points]# if len(self.polys) ==0: if self.QGitem is None: self.QGitem = Contour(point_size=1.5) self.addItem(self.QGitem) self.updatePolyPoint(self.QGitem, qPoints[0]) self.QGitem.setZValue(len(self.polys) + 1) self.QGitem.prepareGeometryChange() self.QGitem.points = qPoints self.QGitem.addPoint((qPoints[0])) else: self.QGitem = self.polys[0] self.QGitem.prepareGeometryChange() self.QGitem.points = qPoints self.QGitem.addPoint((qPoints[0])) self.finalisePolygon() self.update() def mouseReleaseEvent(self, event): if self.mode == self.modes[0]: self.overrideCursor(QtCore.Qt.ArrowCursor) self.update() def isClose(self, p1, p2): return self.dist_func(p1-p2) <self.eps def finalisePolygon(self, premature=False): if self.QGitem: # if premature: something to do but will add later if self.line: self.removeItem(self.line) self.line.popPoint() self.QGitem.editable=False self.polys.append(self.QGitem) self.QGitem = None self.mode = self.modes[0] self.update() def selectContour(self, contour): contour.selected=True self.selectedContour = contour self.update() def selectShapeByPoint(self, pos): if self.vertexSelected(): self.selectedContour.highlightVertex(self.selectedVertex) return itemundermouse = self.itemAt(pos, QtGui.QTransform()) if itemundermouse in self.items()[:-1]: self.selectContour(itemundermouse) return def moveVertex(self, pos): self.selectedContour.prepareGeometryChange() self.selectedContour.moveBy(self.selectedVertex, pos - self.selectedContour[self.selectedVertex]) def vertexSelected(self): return self.selectedVertex is not None def ptDist(self, pt1, pt2): # A line between both line = QtCore.QLineF(pt1, pt2) # Length lineLength = line.length() return lineLength def getClosestPoint(self, pt): closest = (-1, -1) distTh = 4.0 dist = 1e9 # should be enough item_under_mouse = self.itemAt(pt, QtGui.QTransform()) for i in range(self.selectedContour.size()): pt1 = self.selectedContour.points[i] j = i+1 if j == self.selectedContour.size(): j=0 pt2 = self.selectedContour.points[j] edge = QtCore.QLineF(pt1, pt2) normal = edge.normalVector() normalTrhoughPos = QtCore.QLineF(pt.x(), pt.y(), pt.x()+(normal.dx()*10), pt.y()+(normal.dy()*10)) normalTrhoughPos2 = QtCore.QLineF(pt.x(), pt.y(), pt.x() - (normal.dx() * 10), pt.y() - (normal.dy() * 10)) for norm in [normalTrhoughPos, normalTrhoughPos2]: # if item_under_mouse in self.items()[:-1]: # normalTrhoughPos = QtCore.QLineF(pt.x(), pt.y(), pt.x()-(normal.dx()*10), pt.y()-(normal.dy()*10)) intersectionPt = QtCore.QPointF() intersectionType = edge.intersect( norm, intersectionPt) currDist = self.ptDist(intersectionPt, pt) if intersectionType ==QtCore.QLineF.BoundedIntersection: currDist = self.ptDist(intersectionPt, pt) if currDist < dist: closest = (i,j) dist = currDist return closest def reset(self): self.clearContours() self.forceClearContours() if self.line: self.removeItem(self.line) self.line=None if self.QGitem: self.removeItem(self.QGitem) self.QGitem = None for polys in self.polys: self.removeItem(polys) self.polys = [] self.mode = self.modes[0] self.update() def mousePressEvent(self, event): pos = event.scenePos() if event.button() == QtCore.Qt.LeftButton and self.mode == self.modes[1]: self.overrideCursor(QtCore.Qt.CrossCursor) if self.line is None or self.polyFinished: self.line = Contour(point_size=1.5) self.addItem(self.line) self.updatePolyPoint(self.line, pos) elif self.line and not self.polyFinished: self.line.prepareGeometryChange() self.line.points[0] = pos self.line.setPos(pos) if self.QGitem: self.QGitem.prepareGeometryChange() if len(self.QGitem.points) >1 and self.isClose(pos, self.QGitem.points[0]): self.overrideCursor(QtCore.Qt.PointingHandCursor) pos = self.QGitem.points[0] self.QGitem.highlightVertex(0) #need to add to close the polygone self.QGitem.addPoint(pos) if self.QGitem.points[0] == pos: self.finalisePolygon() else: self.QGitem = Contour(point_size=1.5) self.addItem(self.QGitem) self.updatePolyPoint(self.QGitem, pos) self.QGitem.setZValue(len(self.polys)+1) event.accept() self.update() if event.button() == QtCore.Qt.RightButton and self.mode == self.modes[1]: self.overrideCursor(QtCore.Qt.CrossCursor) if self.line: if len(self.line.points) > 1 and self.QGitem: self.QGitem.prepareGeometryChange() self.QGitem.remove(-1) if self.QGitem.points==1: self.removeItem(self.QGitem) self.removeItem(self.line) self.line=None return self.line.prepareGeometryChange() self.line.points[0] =self.QGitem.points[-1] event.accept() self.update() if self.mode == self.modes[2] and event.button() == QtCore.Qt.LeftButton: self.overrideCursor(QtCore.Qt.ClosedHandCursor) self.selectShapeByPoint(pos) event.accept() self.update() if self.mode == self.modes[2] and event.button() == QtCore.Qt.MiddleButton: self.overrideCursor(QtCore.Qt.CrossCursor) if len(self.polys) > 0: self.selectedContour = self.polys[0] pts = self.getClosestPoint(pos) self.selectedContour.points.insert(pts[1], pos) if self.vertexSelected() and event.button() == QtCore.Qt.RightButton and self.mode == self.modes[2]: self.overrideCursor(QtCore.Qt.PointingHandCursor) self.selectedContour.prepareGeometryChange() self.selectedContour.remove(self.selectedVertex) if len(self.selectedContour.points) ==1: self.removeItem(self.selectedContour) self.update() def overrideCursor(self, cursor): QtWidgets.QApplication.setOverrideCursor(cursor) def mouseMoveEvent(self, event): pos = event.scenePos() if self.mode == self.modes[1]: self.overrideCursor(QtCore.Qt.CrossCursor) if self.QGitem: if len(self.QGitem.points)==1: #intilaise line to the pooint self.line.points = [self.QGitem.points[0],self.QGitem.points[0] ] colorLine = QtGui.QColor(3,252,66) if len(self.QGitem.points) >1 and self.isClose(pos, self.QGitem.points[0]): self.overrideCursor(QtCore.Qt.PointingHandCursor) colorLine = self.QGitem.line_color pos = self.QGitem[0] self.QGitem.highlightVertex(0) if len(self.line.points)==2: self.line.points[1] = pos else: self.line.addPoint = pos self.line.line_color = colorLine return if self.mode == self.modes[2] and QtCore.Qt.LeftButton & event.buttons(): if self.vertexSelected(): self.overrideCursor(QtCore.Qt.ClosedHandCursor) self.selectedContour.prepareGeometryChange() self.moveVertex(pos) self.update() return elif self.mode == self.modes[2]: self.overrideCursor(QtCore.Qt.OpenHandCursor) id_point = [[i for i, y in enumerate(poly.points) if distance(pos - y) <= self.eps] for poly in self.polys] id_shape = [i for i, y in enumerate(id_point) if y != []] item_under_mouse = self.itemAt(pos, QtGui.QTransform()) self.clearContours() if id_shape!=[]: self.selectedVertex = id_point[id_shape[0]][0] self.selectContour(self.items()[:-1][::-1][id_shape[0]]) self.selectedContour.highlightVertex(self.selectedVertex) elif item_under_mouse in self.items()[:-1]: self.selectedVertex=None self.selectContour(item_under_mouse) self.selectedContour.hIndex=None else: self.selectedVertex = None self.update()