Explorar o código

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 %!s(int64=13) %!d(string=hai) anos
pai
achega
57cf61b1a1
Modificáronse 2 ficheiros con 58 adicións e 50 borrados
  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