瀏覽代碼

Attract line to starting point

This approach seems much cleaner and more intuitive than the previous
one.

Take the opportunity to refactor the code.
Michael Pitidis 13 年之前
父節點
當前提交
57cf61b1a1
共有 2 個文件被更改,包括 58 次插入50 次删除
  1. 40 37
      canvas.py
  2. 18 13
      shape.py

+ 40 - 37
canvas.py

@@ -7,32 +7,58 @@ from PyQt4.QtCore import *
 from shape import Shape
 
 class Canvas(QLabel):
-    done = pyqtSignal()
-    epsilon = 7.0 # TODO: Tune value
+    epsilon = 9.0 # TODO: Tune value
 
     def __init__(self, *args, **kwargs):
         super(Canvas, self).__init__(*args, **kwargs)
         self.shapes = []
         self.current = None
-        self.line = Shape(line_color=QColor(0, 0, 255))
+        self.line_color = QColor(0, 0, 255)
+        self.line = Shape(line_color=self.line_color)
+
+    def mouseMoveEvent(self, ev):
+        """Update line with last point and current coordinates."""
+        if self.current:
+            if len(self.current) > 1 and self.closeEnough(ev.pos(), self.current[0]):
+                self.line[1] = self.current[0]
+                self.line.line_color = self.current.line_color
+            else:
+                self.line[1] = ev.pos()
+                self.line.line_color = self.line_color
+            self.repaint()
 
     def mousePressEvent(self, ev):
         if ev.button() == 1:
             if self.current:
-                self.current.vertices.append(ev.pos())
-                if self.isClosed():
+                self.current.addPoint(self.line[1])
+                self.line[0] = self.current[-1]
+                if self.current.isClosed():
                     self.finalise()
                 self.repaint()
             else:
                 self.current = Shape()
-                self.current.vertices.append(ev.pos())
+                self.line.points = [ev.pos(), ev.pos()]
+                self.current.addPoint(ev.pos())
                 self.setMouseTracking(True)
 
     def mouseDoubleClickEvent(self, ev):
         if self.current:
-            self.current.vertices.append(self.current[0])
+            self.current.addPoint(self.current[0])
             self.finalise()
 
+    def paintEvent(self, event):
+        super(Canvas, self).paintEvent(event)
+        qp = QPainter()
+        qp.begin(self)
+        qp.setRenderHint(QPainter.Antialiasing)
+        for shape in self.shapes:
+            shape.paint(qp)
+        if self.current:
+            self.current.paint(qp)
+            self.line.paint(qp)
+        qp.end()
+
+
     def finalise(self):
         assert self.current
         self.current.fill = True
@@ -41,38 +67,15 @@ class Canvas(QLabel):
         # TODO: Mouse tracking is still useful for selecting shapes!
         self.setMouseTracking(False)
         self.repaint()
-        self.done.emit()
 
-    def isClosed(self):
-        assert self.current
-        return len(self.current) > 1\
-           and self.closeEnough()
-        return len(self.points) > 1 and self.closeEnough(self.points[0], self.points[-1])
+    def closeEnough(self, p1, p2):
+        #d = distance(p1 - p2)
+        #m = (p1-p2).manhattanLength()
+        #print "d %.2f, m %d, %.2f" % (d, m, d - m)
+        return distance(p1 - p2) < self.epsilon
 
-    def mouseMoveEvent(self, ev):
-        """Update line with last point and current coordinates."""
-        if self.current:
-            self.line.vertices = (self.current[-1], ev.pos())
-            self.repaint()
 
-    def closeEnough(self):
-        assert self.current
-        def distance(p):
-            return sqrt(p.x() * p.x() + p.y() * p.y())
-        p1, p2 = self.current.vertices[0], self.current.vertices[-1]
-        d = distance(p1 - p2)
-        m = (p1-p2).manhattanLength()
-        print "d %.2f, m %d, %.2f" % (d, m, d - m)
-        return distance(p1 - p2) < self.epsilon
 
-    def paintEvent(self, event):
-        super(Canvas, self).paintEvent(event)
-        qp = QPainter()
-        qp.begin(self)
-        for shape in self.shapes:
-            shape.paint(qp)
-        if self.current:
-            self.current.paint(qp)
-            self.line.paint(qp)
-        qp.end()
+def distance(p):
+    return sqrt(p.x() * p.x() + p.y() * p.y())
 

+ 18 - 13
shape.py

@@ -14,34 +14,39 @@ class Shape(object):
         self.line_color = line_color
         self.fill_color = fill_color
 
-        self.vertices = []
+        self.points = []
         self.fill = False
 
-    def addVertex(self, vertex):
-        self.vertices.append(vertex)
+    def addPoint(self, point):
+        self.points.append(point)
 
-    def popVertex(self):
-        if self.vertices:
-            return self.vertices.pop()
+    def popPoint(self):
+        if self.points:
+            return self.points.pop()
         return None
 
+    def isClosed(self):
+        return len(self.points) > 1 and self[0] == self[-1]
+
     def paint(self, painter):
-        if self.vertices:
+        if self.points:
             pen = QPen(self.line_color)
             painter.setPen(pen)
             path = QPainterPath()
-            p0 = self.vertices[0]
-            path.moveTo(p0.x(), p0.y())
-            for v in self.vertices[1:]:
-                path.lineTo(v.x(), v.y())
+            path.moveTo(self.points[0].x(), self.points[0].y())
+            for p in self.points[1:]:
+                path.lineTo(p.x(), p.y())
             painter.drawPath(path)
 
             if self.fill:
                 painter.fillPath(path, self.fill_color)
 
     def __len__(self):
-        return len(self.vertices)
+        return len(self.points)
 
     def __getitem__(self, key):
-        return self.vertices[key]
+        return self.points[key]
+
+    def __setitem__(self, key, value):
+        self.points[key] = value