from PyQt5.QtGui import * from libs.lib import distance DEFAULT_LINE_COLOR = QColor(0, 255, 0, 128) DEFAULT_FILL_COLOR = QColor(255, 0, 0, 128) DEFAULT_SELECT_LINE_COLOR = QColor(255, 255, 255) DEFAULT_SELECT_FILL_COLOR = QColor(0, 128, 255, 155) DEFAULT_VERTEX_FILL_COLOR = QColor(0, 255, 0, 255) DEFAULT_HVERTEX_FILL_COLOR = QColor(255, 0, 0) MIN_Y_LABEL = 10 class Shape(object): P_SQUARE, P_ROUND = range(2) MOVE_VERTEX, NEAR_VERTEX = range(2) line_color = DEFAULT_LINE_COLOR fill_color = DEFAULT_FILL_COLOR select_line_color = DEFAULT_SELECT_LINE_COLOR select_fill_color = DEFAULT_SELECT_FILL_COLOR vertex_fill_color = DEFAULT_VERTEX_FILL_COLOR hvertex_fill_color = DEFAULT_HVERTEX_FILL_COLOR point_type = P_ROUND point_size = 8 scale = 1.0 def __init__(self, label=None, line_color=None): self.label = label self.points = [] self.fill = False self.selected = True self._highlightIndex = None self._highlightMode = self.NEAR_VERTEX self._highlightSettings = { self.NEAR_VERTEX: (4, self.P_ROUND), self.MOVE_VERTEX: (1.5, self.P_SQUARE), } if line_color is not None: self.line_color = line_color def reachMaxPoints(self): if len(self.points) >= 2: return True return False def addPoint(self, point): if not self.reachMaxPoints(): self.points.append(point) def popPonit(self): if self.points: return self.points.pop() return None def paint(self, painter): if self.points: color = self.select_line_color if self.selected else self.line_color pen = QPen(color) pen.setWidth(max(1, int(round(2.0 / self.scale)))) painter.setPen(pen) line_path = QPainterPath() vrtx_path = QPainterPath() line_path.moveTo(self.points[0]) for i, p in enumerate(self.points): line_path.lineTo(p) self.drawVertex(vrtx_path, i) painter.drawPath(line_path) painter.drawPath(vrtx_path) painter.fillPath(vrtx_path, self.vertex_fill_color) if self.fill: color = self.select_fill_color if self.selected else self.fill_color painter.fillPath(line_path, color) def drawVertex(self, path, i): d = self.point_size / self.scale shape = self.point_type point = self.points[i] if i == self._highlightIndex: size, shape = self._highlightSettings[self._highlightMode] d *= size if self._highlightIndex is not None: self.vertex_fill_color = self.hvertex_fill_color else: self.vertex_fill_color = Shape.vertex_fill_color if shape == self.P_SQUARE: path.addRect(point.x() - d / 2, point.y() - d / 2, d, d) elif shape == self.P_ROUND: path.addEllipse(point, d / 2.0, d / 2.0) else: assert False, "unsupported vertex shape" def nearestVertex(self, point, epsilon): for i, p in enumerate(self.points): if distance(p - point) <= epsilon: return i return None def containsPoint(self, point): return self.makePath().contains(point) def makePath(self): path = QPainterPath(self.points[0]) path.lineTo(self.points[0].x()+6, self.points[0].y()+6) for p in self.points[1:]: path.lineTo(p) path.lineTo(p.x()-6, p.y()-6) return path def moveBy(self, offset): self.points = [p + offset for p in self.points] def moveVertexBy(self, i, offset): self.points[i] = self.points[i] + offset def boundingRect(self): return self.makePath().boundingRect() def highlightVertex(self, i, action): self._highlightIndex = i def highlightClear(self): self._highlightIndex = None def __len__(self): return len(self.points) def __getitem__(self, key): return self.points[key] def __setitem__(self, key, value): self.points[key] = value