Пример #1
0
 def mappedPolygon( self, polygon, path = None, percent = 0.5 ):
     """
     Maps the inputed polygon to the inputed path \
     used when drawing items along the path.  If no \
     specific path is supplied, then this object's own \
     path will be used.  It will rotate and move the \
     polygon according to the inputed percentage.
     
     :param      polygon     <QPolygonF>
     :param      path        <QPainterPath>
     :param      percent     <float>
     
     :return     <QPolygonF> mapped_poly
     """
     translatePerc   = percent
     anglePerc       = percent
     
     # we don't want to allow the angle percentage greater than 0.85
     # or less than 0.05 or we won't get a good rotation angle
     if ( 0.95 <= anglePerc ):
         anglePerc = 0.98
     elif ( anglePerc <= 0.05 ):
         anglePerc = 0.05
     
     if ( not path ):
         path = self.path()
     if ( not (path and path.length()) ):
         return QPolygonF()
     
     # transform the polygon to the path
     point   = path.pointAtPercent(translatePerc)
     angle   = path.angleAtPercent(anglePerc)
     
     # rotate about the 0 axis
     transform   = QTransform().rotate(-angle)
     polygon     = transform.map(polygon)
     
     # move to the translation point
     transform   = QTransform().translate(point.x(), point.y())
     
     # create the rotated polygon
     mapped_poly = transform.map(polygon)
     self._polygons.append(mapped_poly)
     
     return mapped_poly
Пример #2
0
    def _updateLayout(self):
        rect = self.geometry()
        n = len(self._items)
        if not n:
            return

        regions = venn_diagram(n, shape=self.shapeType)

        # The y axis in Qt points downward
        transform = QTransform().scale(1, -1)
        regions = list(map(transform.map, regions))

        union_brect = reduce(QRectF.united,
                             (path.boundingRect() for path in regions))

        scalex = rect.width() / union_brect.width()
        scaley = rect.height() / union_brect.height()
        scale = min(scalex, scaley)

        transform = QTransform().scale(scale, scale)

        regions = [transform.map(path) for path in regions]

        center = rect.width() / 2, rect.height() / 2
        for item, path in zip(self.items(), regions):
            item.setPath(path)
            item.setPos(*center)

        intersections = venn_intersections(regions)
        assert len(intersections) == 2 ** n
        assert len(self.vennareas()) == 2 ** n

        anchors = [(0, 0)] + subset_anchors(self._items)

        anchor_transform = QTransform().scale(rect.width(), -rect.height())
        for i, area in enumerate(self.vennareas()):
            area.setPath(intersections[setkey(i, n)])
            area.setPos(*center)
            x, y = anchors[i]
            anchor = anchor_transform.map(QPointF(x, y))
            area.setTextAnchor(anchor)
            area.setZValue(30)

        self._updateTextAnchors()
Пример #3
0
    def _updateLayout(self):
        rect = self.geometry()
        n = len(self._items)
        if not n:
            return

        regions = venn_diagram(n, shape=self.shapeType)

        # The y axis in Qt points downward
        transform = QTransform().scale(1, -1)
        regions = list(map(transform.map, regions))

        union_brect = reduce(QRectF.united,
                             (path.boundingRect() for path in regions))

        scalex = rect.width() / union_brect.width()
        scaley = rect.height() / union_brect.height()
        scale = min(scalex, scaley)

        transform = QTransform().scale(scale, scale)

        regions = [transform.map(path) for path in regions]

        center = rect.width() / 2, rect.height() / 2
        for item, path in zip(self.items(), regions):
            item.setPath(path)
            item.setPos(*center)

        intersections = venn_intersections(regions)
        assert len(intersections) == 2**n
        assert len(self.vennareas()) == 2**n

        anchors = [(0, 0)] + subset_anchors(self._items)

        anchor_transform = QTransform().scale(rect.width(), -rect.height())
        for i, area in enumerate(self.vennareas()):
            area.setPath(intersections[setkey(i, n)])
            area.setPos(*center)
            x, y = anchors[i]
            anchor = anchor_transform.map(QPointF(x, y))
            area.setTextAnchor(anchor)
            area.setZValue(30)

        self._updateTextAnchors()
Пример #4
0
def ellipse_path(center, a, b, rotation=0):
    if not isinstance(center, QPointF):
        center = QPointF(*center)

    brect = QRectF(-a, -b, 2 * a, 2 * b)

    path = QPainterPath()
    path.addEllipse(brect)

    if rotation != 0:
        transform = QTransform().rotate(rotation)
        path = transform.map(path)

    path.translate(center)
    return path
Пример #5
0
def ellipse_path(center, a, b, rotation=0):
    if not isinstance(center, QPointF):
        center = QPointF(*center)

    brect = QRectF(-a, -b, 2 * a, 2 * b)

    path = QPainterPath()
    path.addEllipse(brect)

    if rotation != 0:
        transform = QTransform().rotate(rotation)
        path = transform.map(path)

    path.translate(center)
    return path
Пример #6
0
def _define_symbols():
    """
    Add symbol ? to ScatterPlotItemSymbols,
    reflect the triangle to point upwards
    """
    symbols = pyqtgraph.graphicsItems.ScatterPlotItem.Symbols
    path = QPainterPath()
    path.addEllipse(QRectF(-0.35, -0.35, 0.7, 0.7))
    path.moveTo(-0.5, 0.5)
    path.lineTo(0.5, -0.5)
    path.moveTo(-0.5, -0.5)
    path.lineTo(0.5, 0.5)
    symbols["?"] = path

    tr = QTransform()
    tr.rotate(180)
    symbols['t'] = tr.map(symbols['t'])
Пример #7
0
def _define_symbols():
    """
    Add symbol ? to ScatterPlotItemSymbols,
    reflect the triangle to point upwards
    """
    symbols = pyqtgraph.graphicsItems.ScatterPlotItem.Symbols
    path = QPainterPath()
    path.addEllipse(QRectF(-0.35, -0.35, 0.7, 0.7))
    path.moveTo(-0.5, 0.5)
    path.lineTo(0.5, -0.5)
    path.moveTo(-0.5, -0.5)
    path.lineTo(0.5, 0.5)
    symbols["?"] = path

    tr = QTransform()
    tr.rotate(180)
    symbols['t'] = tr.map(symbols['t'])
Пример #8
0
    def overlay_for(pt1, pt2, frequency):
        # Construct the line-geometry, we'll use this to construct the ellipsoid
        line = QLineF(pt1, pt2)

        # Determine the radius for the ellipsoid
        radius = fresnel_radius(line.length(), frequency)

        # Draw the ellipsoid
        zone = QPainterPath()
        zone.addEllipse(QPointF(0., 0.), line.length() / 2, radius)

        # Rotate the ellipsoid - same angle as the line
        transform = QTransform()
        transform.rotate(-line.angle())
        zone = transform.map(zone)

        # Center the zone over the line
        lc = QRectF(pt1, pt2).center()
        zc = zone.boundingRect().center()
        zone.translate(lc.x() - zc.x(), lc.y() - zc.y())

        return line, zone
Пример #9
0
    def run_loader(self):
        filename = self.result
        try:
            self.retryObject = None
# First, prepare the data by getting the images and computing how big they
# should be
            f = open(filename)
            first_line = f.readline()
            f.close()
            if first_line.startswith("TRKR_VERSION"):
                result = Result(None)
                result.load(self.result, **self._loading_arguments)
                result_type = "Growth"
            else:
                result = TrackingData()
                result.load(self.result, **self._loading_arguments)
                result_type = "Data"
            self.result = result
            self.result_type = result_type
            if result_type == "Data":
                data = result
                images = data.images_name
                if data.cells:
                    self.has_cells = True
                    self.has_walls = True
                else:
                    self.has_cells = False
                    self.has_walls = False
                self.has_points = bool(data.cell_points)
            else:
                data = result.data
                images = result.images
                self.has_cells = False
                self.has_walls = False
                self.has_points = False
            self.images = images
            cache = image_cache.cache
            self.update_nb_images(len(result))
            bbox = QRectF()
            ms = data.minScale()
            for i in range(len(result)):
                img_name = images[i]
                img_data = data[img_name]
                img = cache.image(data.image_path(img_name))
                matrix = QTransform()
                matrix = img_data.matrix()
                sc = QTransform()
                sc.scale(1.0/ms, 1.0/ms)
                matrix *= sc
                r = QRectF(img.rect())
                rbox = matrix.map(QPolygonF(r)).boundingRect()
                bbox |= rbox
                log_debug("Image '%s':\n\tSize = %gx%g\n\tTransformed = %gx%g %+g %+g\n\tGlobal bbox = %gx%g %+g %+g\n" %
                             (img_name, r.width(), r.height(), rbox.width(), rbox.height(), rbox.left(), rbox.top(),
                              bbox.width(), bbox.height(), bbox.left(), bbox.top()))
                log_debug("Matrix:\n%g\t%g\t%g\n%g\t%g\t%g\n" %
                            (matrix.m11(), matrix.m12(), matrix.dx(), matrix.m21(), matrix.m22(), matrix.dy()))
                if result_type == "Growth":
                    if result.cells[i]:
                        self.has_cells = True
                    if result.walls[i]:
                        self.has_walls = True
                    self.has_points = bool(result.data.cell_points)
                self.nextImage()
            translate = bbox.topLeft()
            translate *= -1
            self.translate = translate
            size = bbox.size().toSize()
            self.img_size = size
            self._crop = QRect(QPoint(0,0), size)
            self.finished()
            self._loading_arguments = {} # All done, we don't need that anymore
        except RetryTrackingDataException as ex:
            ex.filename = filename
            self.retryObject = ex
            self.finished()
            return
        except Exception as ex:
            _, _, exceptionTraceback = sys.exc_info()
            self.abort(ex, traceback=exceptionTraceback)
            raise
        msg = object_detect.objects.data
        if (len(msg)):
            print("Len: {}".format(len(msg)))
            j = 0
            while j < len(msg):
                idx = msg[j]
                objectWidth = msg[j + 1]
                objectHeight = msg[j + 2]

                # Find corners Qt
                qtHomography = QTransform(msg[j + 3], msg[j + 4], msg[j + 5],
                                          msg[j + 6], msg[j + 7], msg[j + 8],
                                          msg[j + 9], msg[j + 10], msg[j + 11])

                qtTopLeft = qtHomography.map(QPointF(0, 0))
                qtTopRight = qtHomography.map(QPointF(objectWidth, 0))
                qtBottomLeft = qtHomography.map(QPointF(0, objectHeight))
                qtBottomRight = qtHomography.map(
                    QPointF(objectWidth, objectHeight))

                print(
                    "Object {} detected, Qt corners at ({},{}) ({},{}) ({},{}) ({},{})\n"
                    .format(idx, qtTopLeft.x(), qtTopLeft.y(), qtTopRight.x(),
                            qtTopRight.y(), qtBottomLeft.x(), qtBottomLeft.y(),
                            qtBottomRight.x(), qtBottomRight.y()))
                topleft = (int(qtTopLeft.x()), int(qtTopLeft.y()))
                bottomright = (int(qtBottomRight.x()), int(qtBottomRight.y()))
                cv2.rectangle(cv2_img, topleft, bottomright, (255, 255, 255),
                              3)
                #cv2.imshow("Teste", cv2_img)
Пример #11
0
    def paintEvent(self, event):
        painter = QPainter(self)
        width = self.width()
        height = self.height()

        if DEBUG:
            painter.fillRect(0, 0, width, height, Qt.blue)
        else:
            painter.fillRect(event.rect(), self.plot.canvas_color)

        y_min_scale = self.plot.y_scale.value_min
        y_max_scale = self.plot.y_scale.value_max

        factor_x = float(width) / self.plot.history_length_x
        factor_y = float(height - 1) / max(
            y_max_scale - y_min_scale, EPSILON
        )  # -1 to accommodate the 1px width of the curve

        if self.plot.x_min != None and self.plot.x_max != None:
            x_min = self.plot.x_min
            x_max = self.plot.x_max

            if self.plot.curve_start == "left":
                curve_x_offset = 0
            else:
                curve_x_offset = round((self.plot.history_length_x - (x_max - x_min)) * factor_x)

            transform = QTransform()

            transform.translate(
                curve_x_offset, height - 1 + self.plot.curve_y_offset
            )  # -1 to accommodate the 1px width of the curve
            transform.scale(factor_x, -factor_y)
            transform.translate(-x_min, -y_min_scale)

            if self.plot.curve_motion_granularity > 1:
                self.plot.partial_update_width = math.ceil(transform.map(QLineF(0, 0, 1.5, 0)).length())
                inverted_event_rect = transform.inverted()[0].mapRect(QRectF(event.rect()))

            painter.save()
            painter.setTransform(transform)

            for c in range(len(self.plot.curves_x)):
                if not self.plot.curves_visible[c]:
                    continue

                curve_x = self.plot.curves_x[c]
                curve_y = self.plot.curves_y[c]
                path = QPainterPath()
                lineTo = path.lineTo

                if self.plot.curve_motion_granularity > 1:
                    start = max(min(bisect.bisect_left(curve_x, inverted_event_rect.left()), len(curve_x) - 1) - 1, 0)
                else:
                    start = 0

                path.moveTo(curve_x[start], curve_y[start])

                for i in xrange(start + 1, len(curve_x)):
                    lineTo(curve_x[i], curve_y[i])

                painter.setPen(self.plot.configs[c][1])
                painter.drawPath(path)

            painter.restore()
Пример #12
0
 def run_loader(self):
     filename = self.result
     try:
         self.retryObject = None
         # First, prepare the data by getting the images and computing how big they
         # should be
         f = open(filename)
         first_line = f.readline()
         f.close()
         if first_line.startswith("TRKR_VERSION"):
             result = Result(None)
             result.load(self.result, **self._loading_arguments)
             result_type = "Growth"
         else:
             result = TrackingData()
             result.load(self.result, **self._loading_arguments)
             result_type = "Data"
         self.result = result
         self.result_type = result_type
         if result_type == "Data":
             data = result
             images = data.images_name
             if data.cells:
                 self.has_cells = True
                 self.has_walls = True
             else:
                 self.has_cells = False
                 self.has_walls = False
             self.has_points = bool(data.cell_points)
         else:
             data = result.data
             images = result.images
             self.has_cells = False
             self.has_walls = False
             self.has_points = False
         self.images = images
         cache = image_cache.cache
         self.update_nb_images(len(result))
         bbox = QRectF()
         ms = data.minScale()
         for i in range(len(result)):
             img_name = images[i]
             img_data = data[img_name]
             img = cache.image(data.image_path(img_name))
             matrix = QTransform()
             matrix = img_data.matrix()
             sc = QTransform()
             sc.scale(1.0 / ms, 1.0 / ms)
             matrix *= sc
             r = QRectF(img.rect())
             rbox = matrix.map(QPolygonF(r)).boundingRect()
             bbox |= rbox
             log_debug(
                 "Image '%s':\n\tSize = %gx%g\n\tTransformed = %gx%g %+g %+g\n\tGlobal bbox = %gx%g %+g %+g\n"
                 % (img_name, r.width(), r.height(), rbox.width(),
                    rbox.height(), rbox.left(), rbox.top(), bbox.width(),
                    bbox.height(), bbox.left(), bbox.top()))
             log_debug("Matrix:\n%g\t%g\t%g\n%g\t%g\t%g\n" %
                       (matrix.m11(), matrix.m12(), matrix.dx(),
                        matrix.m21(), matrix.m22(), matrix.dy()))
             if result_type == "Growth":
                 if result.cells[i]:
                     self.has_cells = True
                 if result.walls[i]:
                     self.has_walls = True
                 self.has_points = bool(result.data.cell_points)
             self.nextImage()
         translate = bbox.topLeft()
         translate *= -1
         self.translate = translate
         size = bbox.size().toSize()
         self.img_size = size
         self._crop = QRect(QPoint(0, 0), size)
         self.finished()
         self._loading_arguments = {
         }  # All done, we don't need that anymore
     except RetryTrackingDataException as ex:
         ex.filename = filename
         self.retryObject = ex
         self.finished()
         return
     except Exception as ex:
         _, _, exceptionTraceback = sys.exc_info()
         self.abort(ex, traceback=exceptionTraceback)
         raise
Пример #13
0
class TrackingScene(QGraphicsScene):
    """
    Signals:
      - hasSelection(bool)
      - realSceneSizeChanged
    """

    hasSelectionChanged = Signal(bool)
    realSceneSizeChanged = Signal()
    zoomIn = Signal([], [QPointF])
    zoomOut = Signal([], [QPointF])
    templatePosChange = Signal(QPointF)

    Pan = "Pan"
    Add = "Add"
    Move = "Move"
    ZoomIn = "ZoomIn"
    ZoomOut = "ZoomOut"
    AddCell = "AddCell"
    RemoveCell = "RemoveCell"

    modes = [Pan, Add, Move, AddCell, RemoveCell, ZoomIn, ZoomOut]

    def __init__(self, undo_stack, delete_act, sel_actions, *args):
        """
        Constructor
        """
        params = parameters.instance
        QGraphicsScene.__init__(self, *args)
        self.delete_act = delete_act
        self.undo_stack = undo_stack
        self.data_manager = None
        self._mode = None
        self.link = None
        self.image_path = None
        self.image_name = None
        self.background_image = None
        self.template = TemplateItem()
        self.template.setPos(QPointF(0, 0))
        self.template.setVisible(params.show_template)
        self.show_template = False
        self.points = {}
        self.cells = {}
        self._real_scene_rect = QRectF()
        params.pointParameterChange.connect(self.updatePoints)
        params.cellParameterChange.connect(self.updateCells)
        params.searchParameterChange.connect(self.updateTemplate)
        self.had_selection = None
        self.selectionChanged.connect(self.updateSelectionActions)
        self.current_data = None
        self.back_matrix = QTransform()
        self.invert_back_matrix = QTransform()
        self.clear()
        popup = QMenu("Scene menu")
        validate_cell_act = popup.addAction("Validate cell", self.validateCell)
        validate_cell_act.setVisible(False)
        self._validate_cell_act = validate_cell_act
        lifespan_act = popup.addAction("Change cell lifespan", self.changeLifespan)
        lifespan_act.setVisible(False)
        self.lifespan_act = lifespan_act
        make_starshape_act = popup.addAction("Make cell star shaped", self.makeCellStarshaped)
        make_starshape_act.setVisible(False)
        self.make_starshape_act = make_starshape_act
        sel = popup.addMenu("Selection")
        for act in sel_actions:
            if act == "-":
                sel.addSeparator()
            else:
                sel.addAction(act)
        popup.addAction(delete_act)
        self._popup = popup
        self._sel_rect = None
        self._sel_first_pt = None
        self._current_cell = None
        self._first_point = None
        self.mode = TrackingScene.Pan

    def __del__(self):
        cleanQObject(self)

    def hasSelection(self):
        """
        Returns true if any item is selected
        """
        for pt in self.items():
            if isinstance(pt, PointItem) and pt.isSelected():
                return True
        return False

    def updateSelectionActions(self):
        """
        Slot called when the selection changed. May emit the signal `hasSelection(bool)`
        """
        try:
            value = self.hasSelection()
            if value != self.had_selection:
                self.had_selection = value
                self.hasSelectionChanged.emit(value)
        except:
            pass

    @property
    def has_current_cell(self):
        return self._current_cell is not None

    @property
    def current_cell(self):
        """
        Currently edited cell.

        If needed the cell will be created when accessed.
        """
        if self.selected_cell is None:
            self._current_cell = self.data_manager.createNewCell()
        return self._current_cell

    @current_cell.setter
    def current_cell(self, value):
        if value != self._current_cell and self._current_cell in self.cells:
            self.cells[self._current_cell].setCurrent(False)
        if value in self.cells:
            self._current_cell = value
            self.cells[value].setCurrent()

    @current_cell.deleter
    def current_cell(self):
        if self._current_cell in self.cells:
            self.cells[self._current_cell].setCurrent(False)
        self._current_cell = None

    @property
    def selected_cell(self):
        """
        Currently selected cell.

        This is the same as the current cell, but doesn't create one if requested.
        """
        if self._current_cell is not None and self._current_cell not in self.cells:
            self._current_cell = None
        return self._current_cell

    @selected_cell.setter
    def selected_cell(self, value):
        self.current_cell = value

    @selected_cell.deleter
    def selected_cell(self):
        del self.current_cell

    def updatePoints(self):
        for p in self.items():
            if isinstance(p, PointItem):
                p.setGeometry()
        self.update()

    def updateCells(self):
        for c in self.cells.values():
            c.setGeometry()
            c.update()
        self.update()

    def selectedPoints(self):
        return [it for it in self.selectedItems() if isinstance(it, PointItem)]

    def selectedCells(self):
        return [it for it in self.selectedItems() if isinstance(it, CellItem)]

    def mousePressEvent(self, event):
        if event.buttons() == Qt.LeftButton:
            global current_id
            current_id += 1
            if self.mode == TrackingScene.Add:
                event.accept()
                if self.image_name is not None:
                    pos = event.scenePos()*self.min_scale
                    self.planAddPoints(None, [pos])
            elif self.mode == TrackingScene.ZoomOut:
                event.accept()
                self.zoomOut[QPointF].emit(event.scenePos())
            elif self.mode == TrackingScene.ZoomIn:
                event.accept()
                self.zoomIn[QPointF].emit(event.scenePos())
            elif self.mode == TrackingScene.AddCell:
                for item in self.items(event.scenePos()):
                    if isinstance(item, CellItem):
                        if item.hover:
                            if self.has_current_cell and item.cell_id == self.current_cell:
                                del self.current_cell
                            else:
                                self.current_cell = item.cell_id
                            event.accept()
                            return
                QGraphicsScene.mousePressEvent(self, event)
            elif self.mode == TrackingScene.RemoveCell:
                remove_cell = None
                for item in self.items(event.scenePos()):
                    if isinstance(item, CellItem):
                        remove_cell = item.cell_id
                        break
                if remove_cell is not None:
                    self.planRemoveCells([remove_cell])
            else:
                QGraphicsScene.mousePressEvent(self, event)
        else:
            QGraphicsScene.mousePressEvent(self, event)

    def contextMenuEvent(self, event):
        cell_under = None
        for it in self.items(event.scenePos()):
            if isinstance(it, CellItem):
                cell_under = it.cell_id
                break
        self._cell_under = cell_under
        if cell_under is not None:
            self.make_starshape_act.setVisible(True)
            self.lifespan_act.setVisible(True)
        else:
            self.make_starshape_act.setVisible(False)
            self.lifespan_act.setVisible(False)
        self._popup.popup(event.screenPos())

    def planAddPoints(self, pt_ids, poss):
        self.undo_stack.push(AddPoints(self.data_manager, self.image_name, pt_ids, poss))

    def planMovePoints(self, pt_ids, new_poss, starts=None):
        self.undo_stack.push(MovePoints(self.data_manager, self.image_name, pt_ids, new_poss, starts=starts))

    def planRemovePoints(self, pt_ids):
        self.undo_stack.push(RemovePoints(self.data_manager, self.image_name, pt_ids))

    def planAddCell(self, cell_id, pt_ids):
        log_debug("Planning adding cell %d" % cell_id)
        self.undo_stack.push(AddCellCommand(self.data_manager, cell_id, pt_ids))

    def planChangeCell(self, cell_id, pt_ids, lifespan=None):
        log_debug("Planning change cell %d" % cell_id)
        self.undo_stack.push(ChangeCellCommand(self.data_manager, cell_id, pt_ids, lifespan))

    def planInsertPointInWall(self, new_pt, wall):
        log_debug("Planning insert point %d in wall (%d,%d)" % ((new_pt,)+wall))
        self.undo_stack.push(InsertPointInWallCommand(self.data_manager, new_pt, wall))

    def planDivideCell(self, cell_id, cid1, cid2, p1, p2):
        log_debug("Planning divide cell %d into %d and %d" % (cell_id, cid1, cid2))
        self.undo_stack.push(DivideCellCommand(self.data_manager, self.image_name, cell_id, cid1, cid2, p1, p2))

    def planRemoveCells(self, cell_ids):
        log_debug("Planning remove cells %s" % ", ".join("%d" % c for c in cell_ids))
        self.undo_stack.push(RemoveCellsCommand(self.data_manager, cell_ids))

    def mouseReleaseEvent(self, event):
        items = self.getSelected()
        if items:
            starts = []
            ends = []
            moved_ids = []
            data = self.current_data
            #pt_scale = (self.scale[0]/self.img_scale[0], self.scale[1]/self.scale[1])
            for item in items:
                pos = item.pos()*self.min_scale
                old_pos = data[item.pt_id]
                if pos != old_pos:
                    moved_ids.append(item.pt_id)
                    starts.append(old_pos)
                    ends.append(pos)
            if moved_ids:
                self.planMovePoints(moved_ids, ends, starts)
        elif self.mode == TrackingScene.AddCell:
            QGraphicsScene.mouseReleaseEvent(self, event)
            if event.isAccepted():
                return
            items = self.items(event.scenePos())
            if items:
                pt = items[0]
                if isinstance(pt, PointItem):
                    pt_id = pt.pt_id
                    cells = self.current_data.cells
                    if self.has_current_cell:
                        cid = self.current_cell
                        cell_shape = list(cells[cid])
                        if pt_id in cell_shape:
                            cell_shape.remove(pt_id)
                            self.planChangeCell(cid, cell_shape)
                        else:
                            cell_shape.append(pt_id)
                            self.planChangeCell(cid, cell_shape)
                    else:
                        cid = self.current_cell
                        cell_shape = [pt_id]
                        self.planAddCell(cid, cell_shape)
            return
        QGraphicsScene.mouseReleaseEvent(self, event)

    def setPointCellSelection(self, region):
        add_pts = []
        remove_pts = []
        items = [p.pt_id for p in self.items(region) if isinstance(p, PointItem)]
        if items:
            #print "New cell with: %s" % (items,)
            cells = self.current_data.cells
            cell = self.current_cell
            cell_points = []
            if cell in cells:
                cell_points = list(cells[cell])
            for pt_id in items:
                if pt_id in cell_points:
                    remove_pts.append(pt_id)
                else:
                    add_pts.append(pt_id)
            for pt_id in remove_pts:
                cell_points.remove(pt_id)
            cell_points += add_pts
            cell_points = makeStarShaped(cell_points, self.current_data)
            if cell in cells:
                self.planChangeCell(cell, cell_points)
            else:
                #print "Adding cell %d with %s" % (cell, cell_points)
                self.planAddCell(cell, cell_points)

    def setDivisionLine(self, first_point, second_point):
        dm = self.data_manager
        cid1 = dm.createNewCell()
        cid2 = dm.createNewCell()
        self.planDivideCell(self.current_cell, cid1, cid2, first_point.pt_id, second_point.pt_id)

    def changeLifespan(self):
        cid = self._cell_under
        ls = self.data_manager.lifespan(cid)
        dlg = createForm("lifespan.ui", None)
        self.lifespan_dlg = dlg
        images = list(self.data_manager.images_name)
        images << "End Of Time"
        dlg.images = images
        assert ls.end < len(images) or ls.end == EndOfTime()
        dlg.start_index = ls.start
        if ls.end == EndOfTime():
            dlg.end_index = -1
        else:
            dlg.end_index = ls.end - ls.start
        dlg.startImages.addItems(images[:ls.end])
        dlg.endImages.addItems(images[ls.start:])
        dlg.startImages.setCurrentIndex(ls.start)
        if dlg.end_index != -1:
            dlg.endImages.setCurrentIndex(dlg.end_index)
        else:
            dlg.endImages.setCurrentIndex(dlg.endImages.count()-1)
        dlg.startImages.currentIndexChanged[int].connect(self.updateLifepsanEndImages)
        dlg.endImages.currentIndexChanged[int].connect(self.updateLifepsanStartImages)
        if ls.parent is not None:
            dlg.created.setChecked(True)
        if ls.daughters is not None:
            dlg.divides.setChecked(True)
        if dlg.exec_() == QDialog.Accepted:
            new_ls = ls.copy()
            new_ls.start = dlg.start_index
            if dlg.end_index == -1:
                new_ls.end = EndOfTime()
            else:
                new_ls.end = dlg.end_index + dlg.start_index
            log_debug("Change lifespan of cell %d to %s" % (cid, new_ls))
            self.planChangeCell(cid, self.data_manager.cells[cid], new_ls)

    @Slot(int)
    def updateLifepsanEndImages(self, new_idx):
        dlg = self.lifespan_dlg
        start_idx = dlg.start_index
        if start_idx != new_idx:
            dlg.endImages.currentIndexChanged[int].disconnect(self.updateLifepsanStartImages)
            dlg.endImages.clear()
            dlg.endImages.addItems(dlg.images[new_idx:])
            if dlg.end_index != -1:
                dlg.end_index += start_idx - new_idx
                dlg.endImages.setCurrentIndex(dlg.end_index)
            else:
                dlg.endImages.setCurrentIndex(dlg.endImages.count()-1)
            dlg.start_index = new_idx
            dlg.endImages.currentIndexChanged[int].connect(self.updateLifepsanStartImages)

    @Slot(int)
    def updateLifepsanStartImages(self, new_idx):
        dlg = self.lifespan_dlg
        start_idx = dlg.start_index
        end_idx = dlg.end_index
        if end_idx == -1:
            end_idx = dlg.endImages.count()-1
        if new_idx != end_idx:
            dlg.startImages.currentIndexChanged[int].disconnect(self.updateLifepsanEndImages)
            dlg.startImages.clear()
            dlg.startImages.addItems(dlg.images[:new_idx+start_idx])
            dlg.startImages.setCurrentIndex(dlg.start_index)
            if new_idx == dlg.endImages.count()-1:
                dlg.end_index = -1
            else:
                dlg.end_index = new_idx
            dlg.startImages.currentIndexChanged[int].connect(self.updateLifepsanEndImages)

    def makeCellStarshaped(self):
        cid = self._cell_under
        pts = self.current_data.cells[cid]
        #pts = self.makeStarShaped(pts)
        pts = makeStarShaped(pts, self.current_data)
        self.planChangeCell(cid, pts)

    #def makeStarShaped(self, pts):
    #    if len(pts) > 2:
    #        points = self.points
    #        coords = [ points[pt_id].pos() for pt_id in pts ]
    #        center = sum(coords, QPointF())/len(coords)
    #        ref = coords[0] - center
    #        angles = [ angle(ref, p-center) for p in coords ]
    #        to_sort = range(len(angles))
    #        to_sort.sort(key=lambda k:angles[k])
    #        return [ pts[i] for i in to_sort ]
    #    else:
    #        return pts

    def addPointToCell(self, cid, side, pt):
        pts = [p.pt_id for p in self.items(pt) if isinstance(p, PointItem)]
        if pts:
            data = self.data_manager
            pt_id = pts[0]
            #print "Add point %d to cell %d in side %d" % (pt_id, cid, side)
            cell_points = list(self.current_data.cells[cid])
            prev_pt = cell_points[side-1]
            next_pt = cell_points[side]
            self.planInsertPointInWall(pt_id, data.wallId(prev_pt, next_pt))

    def clearItems(self):
        for it in self.items():
            if isinstance(it, PointItem) or isinstance(it, OldPointItem):
                it.removePoint()
            elif isinstance(it, ArrowItem):
                it.removeArrow()
            else:
                self.removeItem(it)
        self.points.clear()
        self.cells.clear()
        self.addItem(self.template)

    def clear(self):
        self.clearItems()
        if self.data_manager is not None:
            data_manager = self.data_manager
            data_manager.pointsAdded.disconnect(self.addPoints)
            data_manager.pointsMoved.disconnect(self.movePoints)
            data_manager.pointsDeleted.disconnect(self.delPoints)
            data_manager.imageMoved.disconnect(self.moveImage)
            data_manager.dataChanged.disconnect(self.dataChanged)
            data_manager.cellsAdded.disconnect(self.addCells)
            data_manager.cellsRemoved.disconnect(self.removeCells)
            data_manager.cellsChanged.disconnect(self.changeCells)
        self.current_data = None
        self.data_manager = None
        self.image_path = None

    def changeDataManager(self, data_manager):
        self.clear()
        self.data_manager = data_manager
        self.min_scale = 1.0
        self.scale = (1.0, 1.0)
        data_manager.pointsAdded.connect(self.addPoints)
        data_manager.pointsMoved.connect(self.movePoints)
        data_manager.pointsDeleted.connect(self.delPoints)
        data_manager.dataChanged.connect(self.dataChanged)
        data_manager.imageMoved.connect(self.moveImage)
        data_manager.cellsAdded.connect(self.addCells)
        data_manager.cellsRemoved.connect(self.removeCells)
        data_manager.cellsChanged.connect(self.changeCells)

    def moveImage(self, image_name, scale, pos, angle):
        if image_name == self.image_name:
            self.setImageMove(scale, pos, angle)
            self.updateElements()
            self.invalidate()
            self.update()

    def updateElements(self):
        for pt in self.items():
            pt.scale = self.img_scale
            pt.setGeometry()

    def setImageMove(self, scale, pos, angle):
        log_debug("New scale = %s" % (scale,))
        self.scale = scale
        self.min_scale = self.data_manager.minScale()
        self.img_scale = (scale[0]/self.min_scale, scale[1]/self.min_scale)
        back_matrix = QTransform()
        back_matrix.scale(*self.img_scale)
        back_matrix.translate(pos.x(), pos.y())
        back_matrix.rotate(angle)
        self.back_matrix = back_matrix
        rect = back_matrix.mapRect(QRectF(self.background_image.rect()))
        inv, ok = back_matrix.inverted()
        if not ok:
            raise ValueError("The movement is not invertible !?!")
        self.invert_back_matrix = inv
        self.real_scene_rect = rect

    @property
    def real_scene_rect(self):
        '''Real size of the scene'''
        return self._real_scene_rect

    @real_scene_rect.setter
    def real_scene_rect(self, value):
        if self._real_scene_rect != value:
            self._real_scene_rect = value
            self.realSceneSizeChanged.emit()

    def changeImage(self, image_path):
        log_debug("Changed image to {0}".format(image_path))
        if image_path is None:
            image_path = self.image_path
        if image_path is None:
            return
        image_name = image_path.basename()
        self.image_name = image_name
        self.current_data = self.data_manager[image_name]
        current_data = self.current_data
        self.clearItems()
        self.image_path = image_path
        img = image_cache.cache.image(image_path)
        self.background_image = img
        pos = current_data.shift[0]
        angle = current_data.shift[1]
        scale = current_data.scale
        log_debug('Scale of image "%s": %s' % (image_name, scale))
        self.setImageMove(scale, pos, angle)
        self.invalidate()
        for pt_id in current_data:
            self.addPoint(pt_id, current_data[pt_id], new=False)
        cells = self.current_data.cells
        log_debug("Found {0} cells".format(len(cells)))
        if cells:
            self.addCells(list(cells.keys()))
        del self.current_cell
        self.setTemplatePos()

    def dataChanged(self, image_name):
        if image_name == self.image_name:
            self.current_data = self.data_manager[image_name]

    def drawBackground(self, painter, rect):
        painter.fillRect(rect, QBrush(QColor(0, 0, 0)))
        if self.background_image:
            #bm = self.back_matrix
            #log_debug("m = [%g %g ; %g %g ]" % (bm.m11(), bm.m12(), bm.m21(), bm.m22()))
            painter.setWorldTransform(self.back_matrix, True)
            #real_rect = self.invert_back_matrix.mapRect(rect)
            #rect = self.back_matrix.mapRect(real_rect)
            #painter.drawImage(rect,self.background_image, real_rect)
            painter.drawImage(QPointF(0, 0), self.background_image)

    def drawForeground(self, painter, rect):
        QGraphicsScene.drawForeground(self, painter, rect)

    def _addPoint(self, pt_id, pos, new):
        point = PointItem(self.img_scale, pt_id, new=new)
        point.setSelected(new)
        self.addItem(point)
        self.points[pt_id] = point
        point.setPos(QPointF(pos.x()/self.min_scale, pos.y()/self.min_scale))
        return point

    def addPoint(self, pt_id, pos, new=True):
        point = self._addPoint(pt_id, pos, new)
        if self.link is not None and pt_id in self.link.points:
            self.link.linkPoint(point, self.link.points[pt_id])
        cell_points = self.data_manager.cell_points
        cells = self.cells
        cs = [cells[cid] for cid in cell_points[pt_id] if cid in cells]
        point.setCells(cs)
        return point

    def addPoints(self, image_name, pt_ids):
        #print "TrackingScene - Adding points [%s]" % ','.join('%d' % c for c in pt_ids)
        if image_name == self.image_name:
            #print "... in this image!"
            data = self.current_data
            dm = self.data_manager
            cells = self.cells
            for pt_id in pt_ids:
                pt = self.addPoint(pt_id, data[pt_id], new=True)
                pt.setCells([cells[cid] for cid in dm.cell_points[pt_id] if cid in cells])
            cids = set(cid for pt_id in pt_ids for cid in dm.cell_points[pt_id])
            cells_to_add = []
            for cid in cids:
                if cid in cells:
                    cells[cid].setGeometry()
                else:
                    cells_to_add.append(cid)
            if cells_to_add:
                self.addCells(cells_to_add)

    def delPoint(self, point):
        del self.points[point.pt_id]
        point.removePoint()

    def delPoints(self, image_name, pt_ids):
        if image_name == self.image_name:
            dm = self.data_manager
            cells = self.cells
            for pt_id in pt_ids:
                self.delPoint(self.points[pt_id])
                for cid in dm.cell_points[pt_id]:
                    cell = cells.get(cid, None)
                    if cell is not None:
                        cells[cid].setGeometry()

    def movePoints(self, image_name, pt_ids):
        if image_name == self.image_name:
            data = self.current_data
            dm = self.data_manager
            points = self.points
            cells = self.cells
            for pt_id in pt_ids:
                pos = data[pt_id]
                pos = QPointF(pos.x() / self.min_scale, pos.y() / self.min_scale)
                points[pt_id].setPos(pos)
                for cid in dm.cell_points[pt_id]:
                    cell = cells.get(cid, None)
                    if cell is not None and cell.isVisible():
                        cell.setGeometry()

    def addCells(self, cell_ids, image_list=None):
        log_debug("addCell signal with images: (%s,%s)" % (cell_ids, image_list))
        if image_list is not None:
            used_ids = []
            used_il = []
            for cid, il in zip(cell_ids, image_list):
                if il is None or self.image_name in il:
                    used_ids.append(cid)
                    used_il = il
            if not used_ids:
                log_debug("Current image is: '%s' and is not in any of the lists" % self.image_name)
                return
            cell_ids = used_ids
            image_list = used_il
        log_debug("Adding cells %s to image %s" % (','.join("%d" % c for c in cell_ids), self.image_name))
        data = self.data_manager
        current_data = self.current_data
        cell_ids = [cid for cid in cell_ids if cid in current_data.cells]
        log_debug("cell_ids = %s" % (cell_ids,))
        points = self.points
        cells = self.cells
        cell_points = data.cell_points
        for cid in cell_ids:
            if cid in cells or not [pid for pid in current_data.cells[cid] if pid in current_data]:
                continue
            log_debug("-- Add cell %d with points %s" % (cid, current_data.cells[cid]))
            ci = CellItem(self.img_scale, self.min_scale, cid, current_data.cells[cid], points, current_data.walls)
            self.addItem(ci)
            cells[cid] = ci
            ci.setEditable(self.mode == TrackingScene.AddCell)
            if self.has_current_cell and cid == self.current_cell:
                ci.setCurrent()
            pid = data.cells_lifespan[cid].parent
            if pid is not None:
                ls = data.cells_lifespan[pid]
                if data.images_name[ls.end] == self.image_name:
                    div_line = ls.division
                    ci.setDivisionLine(div_line[0], div_line[1])
        for cid in cell_ids:
            for pid in current_data.cells[cid]:
                if pid in points:
                    pt = points[pid]
                    pt.setCells(cells[i] for i in cell_points[pid] if i in cells)

    def removeCells(self, cell_ids, image_list=None):
        log_debug("removeCells signal with images: (%s,%s)" % (cell_ids, image_list))
        if image_list is not None:
            used_ids = []
            used_il = []
            for cid, il in zip(cell_ids, image_list):
                if il is None or self.image_name in il:
                    used_ids.append(cid)
                    used_il = il
            if not used_ids:
                log_debug("Current image is: '%s' and is not in any of the lists" % self.image_name)
                return
            cell_ids = used_ids
            image_list = used_il
        log_debug("Removing cells %s to image %s" % (','.join("%d" % c for c in cell_ids), self.image_name))
        if self.has_current_cell and self.current_cell in cell_ids:
            del self.current_cell
        cells = self.cells
        for cid in cell_ids:
            cell = cells.get(cid, None)
            if cell is not None:
                self.removeItem(cell)
                del self.cells[cid]

    def changeCells(self, cell_ids):
        #print "TrackingScene - Changing cells: [%s]" % ','.join("%d" % c for c in cell_ids)
        log_debug("Change cells %s in image %s" % (','.join("%d" % c for c in cell_ids), self.image_name))
        data = self.data_manager
        current_data = self.current_data
        cell_ids = [cid for cid in cell_ids if cid in current_data.cells]
        points = self.points
        cells = self.cells
        for cid in cell_ids:
            ci = cells.get(cid, None)
            if ci is not None:
                ci.changePoints(current_data.cells[cid])
                for pid in current_data.cells[cid]:
                    if pid in points:
                        pt = points[pid]
                        pt.setCells(cells[i] for i in data.cell_points[pid] if i in cells)
                pid = data.cells_lifespan[cid].parent
                if pid is not None:
                    ls = data.cells_lifespan[pid]
                    if data.images_name[ls.end] == self.image_name:
                        div_line = ls.division
                        ci.setDivisionLine(div_line[0], div_line[1])

    def pointMoved(self, pt_id, start_pos, end_pos):
        self.planMovePoints([pt_id], [end_pos], starts=[start_pos])

    def selectNew(self):
        for it in self.points.values():
            it.setSelected(it.new)

    def selectAll(self):
        for it in self.points.values():
            it.setSelected(True)

    def selectNone(self):
        for it in self.points.values():
            it.setSelected(False)

    def selectInvert(self):
        for it in self.points.values():
            it.setSelected(not it.isSelected())

    def selectNonAssociated(self):
        for it in self.points.values():
            if it.arrow is None and it.link is None:
                it.setSelected(True)
            else:
                it.setSelected(False)

    def selectAssociated(self):
        for it in self.points.values():
            if it.arrow is None and it.link is None:
                it.setSelected(False)
            else:
                it.setSelected(True)

    def getSelected(self):
        return [pt for pt in self.points.values() if pt.isSelected()]

    def getSelectedIds(self):
        return [pt.pt_id for pt in self.points.values() if pt.isSelected()]

    def getAllItems(self):
        return self.points.values()

    def getAllIds(self):
        return self.points.keys()

    def _set_pan_view(self, view):
        view.setInteractive(True)
        view.setCursor(Qt.ArrowCursor)
        view.setDragMode(QGraphicsView.ScrollHandDrag)

    def _set_select_view(self, view):
        view.setInteractive(True)
        view.setDragMode(QGraphicsView.RubberBandDrag)
        view.setCursor(Qt.PointingHandCursor)

    def _set_add_view(self, view):
        view.setInteractive(True)
        view.setDragMode(QGraphicsView.NoDrag)
        view.setCursor(Qt.CrossCursor)

    def _set_zoomin_view(self, view):
        view.setInteractive(True)
        view.setDragMode(QGraphicsView.NoDrag)
        view.setCursor(QCursor(QPixmap(":/icons/gtk-zoom-in.png")))

    def _set_zoomout_view(self, view):
        view.setInteractive(True)
        view.setDragMode(QGraphicsView.NoDrag)
        view.setCursor(QCursor(QPixmap(":/icons/gtk-zoom-out.png")))

    def _set_pan(self):
        params = parameters.instance
        del self.current_cell
        self._validate_cell_act.setVisible(False)
        params.is_point_selectable = False
        params.is_point_editable = False
        params.is_cell_editable = False

    def _set_normal(self):
        params = parameters.instance
        del self.current_cell
        self._validate_cell_act.setVisible(False)
        params.is_point_selectable = True
        params.is_point_editable = True
        params.is_cell_editable = False

    def _set_cell_view(self, view):
        view.setInteractive(True)
        view.setCursor(Qt.ArrowCursor)
        view.setDragMode(QGraphicsView.NoDrag)

    def _set_add_cell(self):
        params = parameters.instance
        self._validate_cell_act.setVisible(True)
        params.is_point_selectable = True
        params.is_point_editable = False
        params.is_cell_editable = True

    def _set_remove_cell(self):
        params = parameters.instance
        del self.current_cell
        self._validate_cell_act.setVisible(False)
        params.is_point_selectable = False
        params.is_point_editable = False
        params.is_cell_editable = False

    _init_view = {
        Pan: (_set_pan_view, _set_pan),
        Move: (_set_select_view, _set_normal),
        Add: (_set_add_view, _set_normal),
        AddCell: (_set_cell_view, _set_add_cell),
        RemoveCell: (_set_cell_view, _set_remove_cell),
        ZoomIn: (_set_zoomin_view, _set_normal),
        ZoomOut: (_set_zoomout_view, _set_normal)
    }

    @property
    def mode(self):
        """
        Mouse interaction mode
        """
        return self._mode

    @mode.setter
    def mode(self, new_mode):
        if new_mode in TrackingScene.modes:
            if new_mode != self._mode:
                log_debug("Changed mode to %s" % new_mode)
                self._mode = new_mode
                fct_view, fct = self._init_view[new_mode]
                fct(self)
                for v in self.views():
                    fct_view(self, v)

    def validateCell(self):
        del self.current_cell

    def keyPressEvent(self, event):
        if event.matches(QKeySequence.Delete):
            if self.mode == TrackingScene.RemoveCell:
                c_ids = []
                for item in self.selectedCells():
                    c_ids = item.cell_id
                if c_ids:
                    self.planRemoveCells(c_ids)
            elif self.mode != TrackingScene.AddCell:
                pt_ids = []
                for item in self.selectedPoints():
                    pt_ids.append(item.pt_id)
                if pt_ids:
                    self.planRemovePoints(pt_ids)
        elif event.key() == Qt.Key_Delete and event.modifiers() | Qt.ShiftModifier:
            self.delete_act.trigger()
        elif event.matches(QKeySequence.ZoomIn):
            self.zoomIn.emit()
        elif event.matches(QKeySequence.ZoomOut):
            self.zoomOut.emit()
        elif event.matches(QKeySequence.SelectAll):
            path = QPainterPath()
            path.addRect(self.sceneRect())
            self.setSelectionArea(path)

    def setSelectedIds(self, ids):
        for it in self.points.values():
            it.setSelected(False)
        for id in ids:
            it = self.points.get(id)
            if it:
                it.setSelected(True)

    def deleteInAllImages(self):
        if self.mode == TrackingScene.RemoveCell:
            c_ids = []
            for item in self.selectedCells():
                c_ids.append(item.cell_id)
            if c_ids:
                self.planRemoveCells(c_ids)
        else:
            pt_ids = []
            for item in self.selectedPoints():
                pt_ids.append(item.pt_id)
            if pt_ids:
                self.undo_stack.push(RemovePointsInAllImages(self.data_manager, self.image_name, pt_ids))

    def deleteFromImage(self):
        if self.mode == TrackingScene.RemoveCell:
            c_ids = []
            for item in self.selectedCells():
                c_ids.append(item.cell_id)
            if c_ids:
                self.planRemoveCells(c_ids)
        else:
            pt_ids = []
            for item in self.selectedPoints():
                pt_ids.append(item.pt_id)
            if pt_ids:
                self.undo_stack.push(RemovePointsFromImage(self.data_manager, self.image_name, pt_ids))

    def deleteToImage(self):
        if self.mode == TrackingScene.RemoveCell:
            c_ids = []
            for item in self.selectedCells():
                c_ids.append(item.cell_id)
            if c_ids:
                self.planRemoveCells(c_ids)
        else:
            pt_ids = []
            for item in self.selectedPoints():
                pt_ids.append(item.pt_id)
            if pt_ids:
                self.undo_stack.push(RemovePointsToImage(self.data_manager, self.image_name, pt_ids))

    def findPoint(self, im1, im2, other, point):
        params = parameters.instance
        ppos = self.current_data[point.pt_id]
        pos = self.invert_back_matrix.map(ppos)
        npos = other.invert_back_matrix.map(ppos)
        pos = (int(pos.x()), int(pos.y()))
        npos = (int(npos.x()), int(npos.y()))
        size = (params.template_size, params.template_size)
        search_size = (params.search_size, params.search_size)
        new_pos, value = findTemplate(im1, pos, size, npos, search_size, im2)
        if value < 0.5:
            return ppos
        p = QPointF(new_pos[0], new_pos[1])*self.min_scale
        return other.back_matrix.map(p)

    def transferPoints(self, other):
        params = parameters.instance
        current_data = self.current_data
        items = self.selectedItems()
        if len(items) == 0:
            items = [it for it in self.points.values() if it.arrow is None and it.link is None]
        new_pt_ids = []
        new_pt_pos = []
        move_pt_ids = []
        move_pt_new_pos = []
        if params.estimate:
            progress = QProgressDialog("Estimating position of the points...", "Abort", 0, len(items), self.parent())
            progress.setMinimumDuration(1)
            size = (params.filter_size, params.filter_size)
            im1 = image_cache.cache.numpy_array(self.image_path, size)
            im2 = image_cache.cache.numpy_array(other.image_path, size)
            for i, it in enumerate(items):
                pos = self.findPoint(im1, im2, other, it)
                id = it.pt_id
                if id in other.points:
                    move_pt_ids.append(id)
                    move_pt_new_pos.append(pos)
                else:
                    new_pt_ids.append(id)
                    new_pt_pos.append(pos)
                progress.setValue(i+1)
                if progress.wasCanceled():
                    progress.hide()
                    break
        else:
            for it in items:
                id = it.pt_id
                pos = current_data[id]
                if id in other.points:
                    move_pt_ids.append(id)
                    move_pt_new_pos.append(pos)
                else:
                    new_pt_ids.append(id)
                    new_pt_pos.append(pos)
        if new_pt_ids or move_pt_ids:
            self.undo_stack.beginMacro("Transfer point(s) from %s to %s" % (self.image_name, other.image_name))
            if new_pt_ids:
                other.planAddPoints(new_pt_ids, new_pt_pos)
            if move_pt_ids:
                other.planMovePoints(move_pt_ids, move_pt_new_pos)
            self.undo_stack.endMacro()

    def copyToLinked(self, linked):
        self.transferPoints(linked)

    def setTemplatePos(self, pos=None):
        if pos is None:
            views = self.views()
            if len(views) > 0:
                view = views[0]
                pos = view.mapToScene(view.rect().center())
        if pos is not None:
            self.template.setPos(pos)

    def showTemplates(self, value=True):
        params = parameters.instance
        self.show_template = value
        if not params.show_template:
            if value:
                self.template.setGeometry()
                self.template.setVisible(True)
                self.setTemplatePos()
            else:
                self.template.setVisible(False)

    def updateTemplate(self):
        params = parameters.instance
        if params.show_template or self.show_template:
            self.template.setGeometry()
            if not self.template.isVisible():
                self.template.setVisible(True)
                self.setTemplatePos()
        else:
            self.template.setVisible(False)
        self.update()

    def resetNewPoints(self):
        for items in self.points.values():
            items.new = False
        self.update()
Пример #14
0
    def paintEvent(self, event):
        painter = QPainter(self)
        width = self.width()
        height = self.height()

        if DEBUG:
            painter.fillRect(0, 0, width, height, Qt.blue)
        else:
            painter.fillRect(event.rect(), self.plot.canvas_color)

        y_min_scale = self.plot.y_scale.value_min
        y_max_scale = self.plot.y_scale.value_max

        factor_x = float(width) / self.plot.x_diff
        factor_y = float(height - 1) / max(
            y_max_scale - y_min_scale,
            EPSILON)  # -1 to accommodate the 1px width of the curve

        if self.plot.x_min != None and self.plot.x_max != None:
            x_min = self.plot.x_min
            x_max = self.plot.x_max

            if self.plot.curve_start == 'left':
                curve_x_offset = 0
            else:
                curve_x_offset = round(
                    (self.plot.x_diff - (x_max - x_min)) * factor_x)

            transform = QTransform()

            transform.translate(
                curve_x_offset, height - 1 + self.plot.curve_y_offset
            )  # -1 to accommodate the 1px width of the curve
            transform.scale(factor_x, -factor_y)
            transform.translate(-x_min, -y_min_scale)

            if self.plot.curve_motion_granularity > 1:
                self.plot.partial_update_width = math.ceil(
                    transform.map(QLineF(0, 0, 1.5, 0)).length())
                inverted_event_rect = transform.inverted()[0].mapRect(
                    QRectF(event.rect()))

            painter.save()
            painter.setTransform(transform)

            if False and self.plot.curves_visible[0]:
                # Currently unused support for bar graphs.
                # If we need this later on we should add an option to the
                # PlotWidget for it.
                # I tested this for the Sound Pressure Level Bricklet and it works,
                # but it didnt't look good.
                curve_x = self.plot.curves_x[0]
                curve_y = self.plot.curves_y[0]

                t = time.time()
                if self.max_points == None:
                    self.max_points = []
                    for y in curve_y:
                        self.max_points.append((t, y))
                else:
                    for i in range(len(curve_y)):
                        if (curve_y[i] > self.max_points[i][1]) or (
                            (t - self.max_points[i][0]) > 5):
                            self.max_points[i] = (t, curve_y[i])

                for i in range(len(self.plot.curves_x[0])):
                    painter.setPen(self.plot.curve_configs[0].color)
                    painter.drawLine(QPoint(curve_x[i], 0),
                                     QPoint(curve_x[i], curve_y[i]))
                    painter.setPen(Qt.white)
                    painter.drawLine(QPoint(curve_x[i], curve_y[i]),
                                     QPoint(curve_x[i], y_max_scale))
                    painter.setPen(Qt.darkGreen)
                    painter.drawPoint(QPoint(curve_x[i],
                                             self.max_points[i][1]))
            else:
                for c in range(len(self.plot.curves_x)):
                    if not self.plot.curves_visible[c]:
                        continue

                    curve_x = self.plot.curves_x[c]
                    curve_y = self.plot.curves_y[c]
                    path = QPainterPath()
                    lineTo = path.lineTo

                    if self.plot.curve_motion_granularity > 1:
                        start = max(
                            min(
                                bisect.bisect_left(curve_x,
                                                   inverted_event_rect.left()),
                                len(curve_x) - 1) - 1, 0)
                    else:
                        start = 0

                    path.moveTo(curve_x[start], curve_y[start])

                    for i in xrange(start + 1, len(curve_x)):
                        lineTo(curve_x[i], curve_y[i])

                    painter.setPen(self.plot.curve_configs[c].color)
                    painter.drawPath(path)

            painter.restore()