Beispiel #1
0
 def addCanvasDashedWedge(self,
                          p1,
                          p2,
                          p3,
                          dash=(2, 2),
                          color=(0, 0, 0),
                          color2=None,
                          **kwargs):
     rgb = [int(c * 255) for c in color]
     pen = QtGui.QPen(QtGui.QColor(*rgb), 1, PenStile_DashLine)
     self.painter.setPen(pen)
     dash = (4, 4)
     pts1 = self._getLinePoints(p1, p2, dash)
     pts2 = self._getLinePoints(p1, p3, dash)
     if len(pts2) < len(pts1):
         pts2, pts1 = pts1, pts2
     for i in range(len(pts1)):
         qp1 = QtCore.QPointF(pts1[i][0], pts1[i][1])
         qp2 = QtCore.QPointF(pts2[i][0], pts2[i][1])
         self.painter.drawLine(qp1, qp2)
Beispiel #2
0
 def addCanvasLine(self, p1, p2, color=(0, 0, 0), color2=None, **kwargs):
     if 'dash' in kwargs:
         line_type = PenStile_DashLine
     else:
         line_type = PenStile_SolidLine
     qp1 = QtCore.QPointF(*p1)
     qp2 = QtCore.QPointF(*p2)
     qpm = QtCore.QPointF((p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2)
     if color2 and color2 != color:
         rgb = [int(c * 255) for c in color]
         pen = QtGui.QPen(QtGui.QColor(*rgb), 1, line_type)
         self.painter.setPen(pen)
         self.painter.drawLine(qp1, qpm)
         rgb2 = [int(c * 255) for c in color2]
         pen.setColor(QtGui.QColor(*rgb2))
         self.painter.setPen(pen)
         self.painter.drawLine(qpm, qp2)
     else:
         rgb = [int(c * 255) for c in color]
         pen = QtGui.QPen(QtGui.QColor(*rgb), 1, line_type)
         self.painter.setPen(pen)
         self.painter.drawLine(qp1, qp2)
Beispiel #3
0
    def load_points(self, file_name):
        file = open(file_name, 'r')
        self.directory = os.path.split(file_name)[0]
        self.directory_set.emit(self.directory)
        data = json.load(file)
        file.close()
        survey_id = data['metadata']['survey_id']

        # Backward compat
        if 'custom_fields' in data:
            self.custom_fields = data['custom_fields']
        else:
            self.custom_fields = {'fields': [], 'data': {}}
        if 'ui' in data:
            self.ui = data['ui']
        else:
            self.ui = {
                'grid': {
                    'size': 200,
                    'color': [255, 255, 255]
                },
                'point': {
                    'radius': 25,
                    'color': [255, 255, 0]
                }
            }
        # End Backward compat

        self.colors = data['colors']
        self.classes = data['classes']
        self.coordinates = data['metadata']['coordinates']
        self.points = {}
        if 'points' in data:
            self.points = data['points']

        for image in self.points:
            for class_name in self.points[image]:
                for p in range(len(self.points[image][class_name])):
                    point = self.points[image][class_name][p]
                    self.points[image][class_name][p] = QtCore.QPointF(
                        point['x'], point['y'])
        for class_name in data['colors']:
            self.colors[class_name] = QtGui.QColor(self.colors[class_name][0],
                                                   self.colors[class_name][1],
                                                   self.colors[class_name][2])
        self.points_loaded.emit(survey_id)
        self.fields_updated.emit(self.custom_fields['fields'])
        path = os.path.split(file_name)[0]
        if self.points.keys():
            path = os.path.join(path, list(self.points.keys())[0])
            self.load_image(path)
Beispiel #4
0
 def addCanvasText(self, text, pos, font, color=(0, 0, 0), **kwargs):
     orientation = kwargs.get('orientation', 'E')
     qfont = QtGui.QFont("Helvetica", int(font.size * 1.5))
     qtext = QtGui.QTextDocument()
     qtext.setDefaultFont(qfont)
     colored = [int(c * 255) for c in color]
     colored.append(text)
     html_format = "<span style='color:rgb({},{},{})'>{}</span>"
     formatted = html_format.format(*colored)
     qtext.setHtml(formatted)
     if orientation == 'N':
         qpos = QtCore.QPointF(pos[0] - qtext.idealWidth() / 2,
                               pos[1] - font.size)
     elif orientation == 'W':
         qpos = QtCore.QPointF(pos[0] - qtext.idealWidth() + font.size,
                               pos[1] - font.size)
     else:
         qpos = QtCore.QPointF(pos[0] - font.size, pos[1] - font.size)
     self.painter.save()
     self.painter.translate(qpos)
     qtext.drawContents(self.painter)
     self.painter.restore()
     return font.size * 1.8, font.size * 1.8, 0
Beispiel #5
0
 def addCanvasPolygon(self,
                      ps,
                      color=(0, 0, 0),
                      fill=True,
                      stroke=False,
                      **kwargs):
     polygon = QtGui.QPolygonF()
     for ver in ps:
         polygon.append(QtCore.QPointF(*ver))
     color = [int(c * 255) for c in color]
     pen = QtGui.QPen(QtGui.QColor(*color), 1, PenStile_DashLine)
     self.painter.setPen(pen)
     self.painter.setBrush(QtGui.QColor(0, 0, 0))
     self.painter.drawPolygon(polygon)
Beispiel #6
0
 def polyClose(self): #make into hot key not button
     if self.measuring_area:
         if self.line_count > 2: #cant make polygon w/ two lines
             self.measuring_area = False
             A = self.A.calcArea()
             self.areaValues = np.append(self.areaValues, A) #add area values
             #draw permanent polygon
             points = [ QtCore.QPointF(x,y) for x,y in zip( self.A.x, self.A.y ) ]
             self.scene.polyItem2 = QGraphicsPolygonItem(QtGui.QPolygonF(points))
             self.scene.polyItem2.setBrush( QtGui.QBrush(QtGui.QColor(255,255,255,127)) )
             if self.scene.polyItem:
                 self.scene.removeItem(self.scene.polyItem) #remove mouseover polygon
                 self.scene.polyItem = False #remove mouseover polygon
             self.scene.removeItem(self.scene.testline)
             self.scene.testline = False
             self.scene.addItem(self.scene.polyItem2) #shade in polygon
             self.parent().statusbar.showMessage('Polygon area measurement completed')
             self.parent().areaButton.setChecked(False)
             self.parent().bezier.setEnabled(True) #make bezier fit available again
         else:
             print("cannot draw polygon with fewer than three vertices")
Beispiel #7
0
    def __init__(self, parent=None):
        super(imwin, self).__init__(parent)
        self.scene = QGraphicsScene()
        self.view = QGraphicsView(self.scene)

        self.pixmap = None
        self._lastpos = None
        self._thispos = None
        self.delta = QtCore.QPointF(0, 0)
        self.nm = None
        self.measuring_length = False
        self.measuring_widths = False
        self.measuring_area = False
        self.measuring_angle = False
        self._zoom = 1
        self.newPos = None
        self.oldPos = None
        self.factor = 1.0
        self.numwidths = None
        self.widthNames = [] #initialize as empty list
        self.d = {}  #dictionary for line items
        #self.k = 0 #initialize counter so lines turn yellow
        self.L = posData(np.empty(shape=(0, 0)), np.empty(shape=(0, 0)))
        self.W = posData(np.empty(shape=(0, 0)), np.empty(shape=(0, 0)))
        self.scene.realline = None
        self.scene.testline = None
        self.setMouseTracking(True)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
        #self.setRenderHints(QtGui.QPainter.Antialiasing
        #                    | QtGui.QPainter.SmoothPixmapTransform)
        #self.setRenderHint(QtGui.QPainter.Antialiasing, True)
        #self.setRenderHint(QtGui.QPainter.HighQualityAntialiasing, True)
        self.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse)
        self.setResizeAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse)
        self.setInteractive(False)
Beispiel #8
0
    def mousePressEvent(self, event):
        #http://pyqt.sourceforge.net/Docs/PyQt4/qgraphicsscenemouseevent.html
        #https://stackoverflow.com/questions/21197658/how-to-get-pixel-on-qgraphicspixmapitem-on-a-qgraphicsview-from-a-mouse-click
        data = self.mapToScene(event.pos())

        #draw piecewise lines for non-width measurements
        rules = [self.measuring_length, self.measuring_angle, self.measuring_area]

        if self.scene.testline and self._thispos and any(rules):
            start = self._thispos
            end = QtCore.QPointF(data)

            if self._lastpos and self.measuring_angle:

                a = self._lastpos - self._thispos
                b = data - self._thispos
                a = np.array([a.x(), a.y()])
                b = np.array([b.x(), b.y()])
                self.measuring_angle = False
                t = np.arccos(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))
                t *= 180 / np.pi  #convert to degrees
                self.T.update(t)
                self.angleValues = np.append(self.angleValues,t)
                self.parent().statusbar.showMessage('Angle measurement complete')
                self.parent().angleButton.setChecked(False)
                self.parent().bezier.setEnabled(True)

            self.scene.realline = QGraphicsLineItem(QtCore.QLineF(start, end))
            self.scene.addItem(self.scene.realline)

        #Collect piecewise line start/end points
        self._lastpos = self._thispos  # save old position value
        self._thispos = QtCore.QPointF(data)  # update current position

        if self.measuring_length:
            self.L.update(data.x(), data.y())  # update total length
            self.line_count += 1

        elif self.measuring_area:
            self.line_count += 1
            intersect = False
            if self.line_count > 2: #cant make polygon w/ two lines
                intersect, xi, yi, k = self.A.checkIntersect(data.x(),data.y())
                self.parent().areaButton.setEnabled(True)
            if intersect:
                self.measuring_area = False
                self.A.update(xi,yi) #update with intersect point
                self.A.x, self.A.y = self.A.x[k:], self.A.y[k:] #only use points after intersection
                A = self.A.calcArea()
                self.areaValues = np.append(self.areaValues, A) #add area values
                #draw permanent polygon
                points = [ QtCore.QPointF(x,y) for x,y in zip( self.A.x, self.A.y ) ]
                self.scene.polyItem2 = QGraphicsPolygonItem(QtGui.QPolygonF(points))
                self.scene.polyItem2.setBrush( QtGui.QBrush(QtGui.QColor(255,255,255,127)) )
                self.scene.removeItem(self.scene.polyItem) #remove mouseover polygon
                self.scene.polyItem = False #remove mouseover polygon
                self.scene.addItem(self.scene.polyItem2) #shade in polygon
                self.parent().statusbar.showMessage('Polygon area measurement completed')
                self.parent().areaButton.setChecked(False)
                self.parent().bezier.setEnabled(True) #make bezier fit available again
                QApplication.setOverrideCursor(QtCore.Qt.ArrowCursor)  #change cursor
            else:
                self.A.update(data.x(),data.y()) #update with click point

        #https://stackoverflow.com/questions/30898846/qgraphicsview-items-not-being-placed-where-they-should-be
        if self.measuring_widths:  #measure widths, snap to spines

            k = int(self.k / 2) + 1  #same origin for spine on either side
            x0, y0 = self.xp[k], self.yp[k]
            x1, y1 = data.x(), data.y()

            #perpindicular slopes
            vx = self.slopes[:,k][1]
            vy = -self.slopes[:,k][0]

            A = np.matrix([[vx, -vy], [vy, vx]])
            b = np.array([x1 - x0, y1 - y0])
            t = np.linalg.solve(A,b)

            xi = x0 + t[0]*vx
            yi = y0 + t[0]*vy

            self.W.update(xi,yi)
            p = QtCore.QPointF(xi, yi)

            s = 10  #dot size
            self.scene.ellipseItem = QGraphicsEllipseItem(0, 0, s, s)
            self.scene.ellipseItem.setPos(p.x() - s / 2, p.y() - s / 2)
            qb = QtGui.QBrush()
            qb.setColor(QtGui.QColor('red'))
            self.scene.ellipseItem.setBrush(qb)
            self.scene.ellipseItem.setFlag(
                QGraphicsItem.GraphicsItemFlag.ItemIgnoresTransformations,
                False)  #size stays small, but doesnt translate if false
            self.scene.addItem(self.scene.ellipseItem)
            self.k += 1

            if self.k < self.nspines:
                self.d[str(self.k)].setPen(QtGui.QPen(
                    QtGui.QColor('yellow'))) #Highlight next spine
                    
            if self.k == self.nspines:
                self.parent().statusbar.showMessage('Width measurements complete')
                self.measuring_widths = False
                self.parent().widthsButton.setEnabled(False)
                self.parent().widthsButton.setChecked(False)
                self.parent().bezier.setEnabled(True)
                width = np.sqrt(
                    (self.W.x[1::2] - self.W.x[0::2])**2 +
                    (self.W.y[1::2] - self.W.y[0::2])**2)  #calculate widths
                self.widths[-1] = width
Beispiel #9
0
    def measure_widths(self):

        def qpt2pt(x, y):
            Q = self.mapFromScene( self.mapToScene( int(x), int(y)) )
            return Q.x(), Q.y()

        self.measuring_widths = True
        self.parent().widthsButton.setChecked(True)
        self.k = 0
        self.W = posData(
            np.empty(shape=(0, 0)),
            np.empty(shape=(0, 0)))  #preallocate custom widths
        #number of possible measurements per segment (length + #widths)
        #self.measurements = np.empty((0, self.iw.nm + 1), int) * np.nan
        self.numwidths = int(self.parent().subWin.numwidths.text())
        #self.measurements[-1] = np.append( self.l[-1], np.zeros(self.numwidths-1)*np.nan ) #preallocate measurements
        self.widths[-1] = np.empty(self.numwidths-1, dtype='float') #preallocate measurements
        self.widthNames[-1] = [
            '{0:2.2f}% Width'.format(100 * f / self.numwidths)
            for f in np.arange(1, self.numwidths)
        ]

        self.nspines = 2 * (self.numwidths - 1)
        self.parent().statusbar.showMessage(
            'Click point along spines to make width measurements perpindicular to the length segment'
        )

        #get pts for width drawing
        bins = np.linspace(0, self.l[-1], self.numwidths + 1)
        inds = np.digitize(self.l, bins)
        __, self.inddec = np.unique(inds, return_index = True)

        pts = np.array(list(map(qpt2pt, self.xs, self.ys)))
        x, y = pts[:, 0], pts[:, 1]
        self.xp, self.yp = x[self.inddec], y[self.inddec]
        self.slopes = self.m[:,self.inddec]
        
        #Identify width spine points
        self.xsw = x[inds]
        self.ysw = y[inds]

        #Draw Widths
        for k,(x,y) in enumerate(zip(self.xp[1:-1], self.yp[1:-1])):

            x1, y1 = x,y
            L = self.pixmap_fit.width()
            H = self.pixmap_fit.height()
            v = self.slopes[:,k+1]
            vx =  v[1]
            vy = -v[0]
            t0 = np.hypot(L,H)
            t2 = 0

            #intersect: rectangle
            for offset in ([0,0],[L,H]):
                for ev in ([1,0],[0,1]):
                    A = np.matrix([ [vx, ev[0]] , [vy, ev[1]] ])
                    b = np.array([offset[0] - x1, offset[1] - y1])
                    T = np.linalg.solve(A,b)[0]
                    t0 = min(T, t0, key=abs) #find nearest intersection to bounds

            #Find 2nd furthest intersection within bounds
            bounds = np.array( [(L - x1)/vx, (H - y1)/vy, -x1/vx, -y1/vy] )
            t2 = max(-t0, np.sign(-t0)* np.partition(bounds,-2)[-2], key=abs)

            x0 = x1 + t0*vx
            y0 = y1 + t0*vy
            x2 = x1 + t2*vx
            y2 = y1 + t2*vy

            for l, (x, y) in enumerate(zip([x0, x2], [y0, y2])):
                start = QtCore.QPointF(x1, y1)
                end = QtCore.QPointF(x, y)
                self.scene.interpLine = QGraphicsLineItem(
                    QtCore.QLineF(start, end))
                self.d["{}".format(2 * k + l)] = self.scene.interpLine
                self.scene.addItem(self.scene.interpLine)
                if k == 0 and l == 0:
                    self.scene.interpLine.setPen(
                        QtGui.QPen(QtGui.QColor('yellow')))
Beispiel #10
0
    def mouseDoubleClickEvent(self, event):

        def qpt2pt(x, y):
            Q = self.mapFromScene(self.mapToScene( int(x), int(y)))
            return Q.x(), Q.y()

        #only delete lines if bezier fit
        if self.measuring_length and self.parent().bezier.isChecked() and (len(np.vstack((self.L.x, self.L.y)).T) > 2):
            self.parent().statusbar.showMessage('Length measurement complete.')
            #Remove most recent items drawn (exact lines)
            nl = self.line_count
            for k, i in enumerate(self.scene.items()):
                if k < nl:
                    self.scene.removeItem(i) #set item to false?

        if self._lastpos and self.measuring_length:
            # catmull roms spline instead?
            # or rational bezier curve - tuneable approximating/interpolating. ref. wikipedia
            # https://codeplea.com/introduction-to-splines

            if (self.parent().bezier.isChecked()) and (len(np.vstack((self.L.x, self.L.y)).T) > 2):
                nt = 2000 #max(1000, self.numwidths * 50)  #num of interpolating points
                
                def bernstein(i, n, t):
                    return comb(n,i) * t**(n-i) * (1-t)**i

                def bezier_rational(points, nt):
                    """Rational Bezier Curve fit"""
                    # https://gist.github.com/Alquimista/1274149
                    # https://pages.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/Bezier/bezier-der.html
                    n = len(points)
                    xp = np.array([p[0] for p in points])
                    yp = np.array([p[1] for p in points])
                    t = np.linspace(0.0, 1.0, nt)

                    #Bezier curve
                    B = np.array([ bernstein(i,n-1,t) for i in range(0,n) ])
                    xb = np.dot(xp, B)[::-1]
                    yb = np.dot(yp, B)[::-1]

                    #Analytic gradient for bezier curve
                    Qx = n*np.diff(xp)
                    Qy = n*np.diff(yp)
                    Bq = np.array([ bernstein(i,n-2,t) for i in range(0,n-1) ])
                    dxb = np.dot(Qx, Bq)[::-1]
                    dyb = np.dot(Qy, Bq)[::-1]

                    m = np.vstack((dxb,dyb))
                    m *= (1/np.linalg.norm(m, axis=0))
                    return xb, yb, m

                points = np.vstack((self.L.x, self.L.y)).T
                self.xs, self.ys, self.m = bezier_rational(points, nt)

                pts = np.array(list(map(qpt2pt, self.xs, self.ys)))
                x, y = pts[:, 0], pts[:, 1]
                self.l = np.cumsum(np.hypot(np.gradient(x), np.gradient(y))) #integrate for length

                #draw cubic line to interpolated points
                for i in range(1, nt - 1):
                    P0 = QtCore.QPointF( self.xs[i-1], self.ys[i-1] )#.toPoint()
                    P1 = QtCore.QPointF( self.xs[i  ], self.ys[i  ] )#.toPoint()
                    P2 = QtCore.QPointF( self.xs[i+1], self.ys[i+1] )#.toPoint() 
                    start = self.mapFromScene(self.mapToScene(P0.toPoint()))
                    mid = self.mapFromScene(self.mapToScene(P1.toPoint())) 
                    end = self.mapFromScene(self.mapToScene(P2.toPoint()))
                    path = QtGui.QPainterPath(P0)
                    path.cubicTo(P0, P1, P2)
                    self.scene.addPath(path)

            if (not self.parent().bezier.isChecked()) or (len(np.vstack((self.L.x, self.L.y)).T) <= 2):
                """Simple linear points if piecewise mode (or only two points used?)"""
                pts = np.array(list(map(qpt2pt, self.L.x, self.L.y)))
                x, y = pts[:, 0], pts[:, 1]
                slope = (y[-1] - y[0]) / (x[-1] - x[0])
                theta = np.arctan(slope)
                distance = np.hypot( x[-1] - x[0], y[-1] - y[0] )
                r = np.linspace(0, distance, 1000)
                
                self.xs, self.ys = x[0] + r*np.cos(theta), y[0] + r*np.sin(theta)
                self.m = np.vstack(( slope*(r*0 + 1), -slope*(r*0 + 1) ))
                #self.m = np.vstack(( (y[-1] - y[0])*(r*0 + 1), (x[-1] - x[0])*(r*0 + 1) ))
                self.m = np.vstack((  (x[-1] - x[0])*(r*0 + 1), (y[-1] - y[0])*(r*0 + 1) ))
                self.l = np.cumsum(np.hypot(np.diff(self.xs), np.diff(self.ys)))  #integrate for length
               
            self.lengths[-1] = self.l[-1]
            self.lengths.extend([np.nan])
            self.widths.append([])
            self.widthNames.append([])

        QApplication.setOverrideCursor(QtCore.Qt.CursorShape.ArrowCursor)  #change cursor
        if self.parent().bezier.isChecked() or (len(np.vstack((self.L.x, self.L.y)).T) <= 2):
            #measure widths possible if bezier or if single piecewise segment
            self.parent().widthsButton.setEnabled(True)

        self.parent().lengthButton.setChecked(False)
        self.parent().angleButton.setChecked(False)
        self.measuring_length = False
        self.measuring_angle = False
        self._thispos = False
Beispiel #11
0
    def mouseMoveEvent(self, event):
        data = self.mapToScene(event.position().toPoint())
        rules = [self.measuring_length, self.measuring_angle, self.measuring_area]

        modifiers = QApplication.keyboardModifiers()
        if modifiers == QtCore.Qt.KeyboardModifier.ShiftModifier and self.oldPos:
            QApplication.setOverrideCursor(QtCore.Qt.CursorShape.OpenHandCursor)
            self.newPos = data
            delta = self.newPos - self.oldPos
            self.translate(delta.x(), delta.y())
        elif (any(rules) or self.measuring_widths):
            QApplication.setOverrideCursor(QtCore.Qt.CursorShape.CrossCursor)  #change cursor
        else:
            QApplication.setOverrideCursor(QtCore.Qt.CursorShape.ArrowCursor)  #change cursor   

        #dragging line
        if self._thispos and any(rules):
            if self.measuring_length:
                self.parent().statusbar.showMessage(
                    'Click to place next point... double click to finish')
            if self.measuring_area:
                self.parent().statusbar.showMessage(
                    'Click to place next point... close polygon to finish')
            if self.measuring_angle:
                self.parent().statusbar.showMessage(
                    'Click point to define vector')

            end = QtCore.QPointF(data)#self.mapToScene(event.pos()))
            start = self._thispos

            if self.measuring_angle and self._lastpos:
                start = self._thispos

            if self.scene.testline:  #remove old line
                self.scene.removeItem(self.scene.testline)
                self.scene.testline = False

            if self.measuring_area and self.line_count > 2:
                intersect, xi, yi, k = self.A.checkIntersect(data.x(),data.y())
                if self.scene.area_ellipseItem: #remove existing intersect
                    self.scene.removeItem(self.scene.area_ellipseItem)
                    self.scene.area_ellipseItem = False
                if self.scene.polyItem:
                    self.scene.removeItem(self.scene.polyItem)
                    self.scene.polyItem = False
                if intersect:
                    #indicate intersect point
                    p = QtCore.QPointF(xi, yi)
                    self.scene.area_ellipseItem = QGraphicsEllipseItem(0, 0, 10, 10)
                    self.scene.area_ellipseItem.setPos(p.x() - 10 / 2, p.y() - 10 / 2)
                    self.scene.area_ellipseItem.setBrush(
                    QtGui.QBrush(QtCore.QtColor('blue'))) #, style=QtCore.Qt.BrushStyle.SolidPattern))
                    self.scene.area_ellipseItem.setFlag(
                    QGraphicsItem.GraphicsItemFlag.ItemIgnoresTransformations,
                    False)  #size stays small, but doesnt translate if set to false
                    self.scene.addItem(self.scene.area_ellipseItem)
                    #shade polygon region
                    points = [ QtCore.QPointF(x,y) for x,y in zip( self.A.x[k:], self.A.y[k:] ) ]
                    points.append(QtCore.QPointF(xi,yi))
                    self.scene.polyItem = QGraphicsPolygonItem(QtGui.QPolygonF(points))
                    self.scene.polyItem.setBrush( QtGui.QBrush(QtGui.QColor(255,255,255,127)) )
                    self.scene.addItem(self.scene.polyItem)

            self.scene.testline = QGraphicsLineItem(QtCore.QLineF(start, end))
            self.scene.addItem(self.scene.testline)