Exemplo n.º 1
0
    def testSelection(self, data):
        """
        Given a

        Parameters
        ----------
        data : (N, 2) array
            Point coordinates

        """
        if len(data) == 0:
            return numpy.zeros(0, dtype=bool)

        def contained(a, left, top, right, bottom):
            assert left <= right and bottom <= top
            x, y = a.T
            return (x >= left) & (x <= right) & (y <= top) & (y >= bottom)

        data = numpy.asarray(data)
        selected = numpy.zeros(len(data), dtype=bool)
        for p1, p2 in self.selection:
            r = QRectF(p1, p2).normalized()
            # Note the inverted top/bottom (Qt coordinate system)
            selected |= contained(data, r.left(), r.bottom(),
                                  r.right(), r.top())
        return selected
Exemplo n.º 2
0
    def testSelection(self, data):
        """
        Given a

        Parameters
        ----------
        data : (N, 2) array
            Point coordinates

        """
        if len(data) == 0:
            return numpy.zeros(0, dtype=bool)

        def contained(a, left, top, right, bottom):
            assert left <= right and bottom <= top
            x, y = a.T
            return (x >= left) & (x <= right) & (y <= top) & (y >= bottom)

        data = numpy.asarray(data)
        selected = numpy.zeros(len(data), dtype=bool)
        for p1, p2 in self.selection:
            r = QRectF(p1, p2).normalized()
            # Note the inverted top/bottom (Qt coordinate system)
            selected |= contained(data, r.left(), r.bottom(), r.right(),
                                  r.top())
        return selected
Exemplo n.º 3
0
 def inputLocation( self ):
     """
     Returns the input location for this connection.
     
     :return     <XConnectionLocation>
     """
     if ( not self.autoCalculateInputLocation() ):
         return self._inputLocation
     
     # auto calculate directions based on the scene
     if ( self._outputNode ):
         outputRect = self._outputNode.sceneRect()
     else:
         y = self._outputPoint.y()
         outputRect = QRectF( self._outputPoint.x(), y, 0, 0 )
     
     if ( self._inputNode ):
         inputRect  = self._inputNode.sceneRect()
     else:
         y = self._inputPoint.y()
         inputRect  = QRectF( self._inputPoint.x(), y, 0, 0 )
     
     # use the input location as potential places where it can be
     iloc    = self._inputLocation
     left    = XConnectionLocation.Left
     right   = XConnectionLocation.Right
     top     = XConnectionLocation.Top
     bot     = XConnectionLocation.Bottom
     
     if ( self._inputNode == self._outputNode ):
         if ( iloc & right ):
             return right
         elif ( iloc & left ):
             return left
         elif ( iloc & top ):
             return top
         else:
             return bot
             
     elif ( (iloc & left)    and outputRect.right() < inputRect.left() ):
         return left
     elif ( (iloc & right)   and inputRect.right() < outputRect.left() ):
         return right
     elif ( (iloc & top)     and outputRect.bottom() < inputRect.top() ):
         return top
     elif ( (iloc & bot) ):
         return bot
     elif ( (iloc & left) ):
         return left
     elif ( (iloc & right) ):
         return right
     elif ( (iloc & top) ):
         return top
     else:
         return left
Exemplo n.º 4
0
 def outputLocation( self ):
     """
     Returns the location for the output source position.
     
     :return     <XConnectionLocation>
     """
     if ( not self.autoCalculateOutputLocation() ):
         return self._outputLocation
     
     # auto calculate directions based on the scene
     if ( self._outputNode ):
         outputRect = self._outputNode.sceneRect()
     else:
         y = self._outputPoint.y()
         outputRect = QRectF( self._outputPoint.x(), y, 0, 0 )
     
     if ( self._inputNode ):
         inputRect  = self._inputNode.sceneRect()
     else:
         y = self._inputPoint.y()
         inputRect  = QRectF( self._inputPoint.x(), y, 0, 0 )
         
     oloc    = self._outputLocation
     left    = XConnectionLocation.Left
     right   = XConnectionLocation.Right
     top     = XConnectionLocation.Top
     bot     = XConnectionLocation.Bottom
     
     if ( self._inputNode == self._outputNode ):
         if ( oloc & right ):
             return right
         elif ( oloc & left ):
             return left
         elif ( oloc & top ):
             return top
         else:
             return bot
             
     elif ( (oloc & right)   and outputRect.right() < inputRect.left() ):
         return right
     elif ( (oloc & left)    and inputRect.right() < outputRect.left() ):
         return left
     elif ( (oloc & bot)     and outputRect.bottom() < inputRect.top() ):
         return bot
     elif ( (oloc & top) ):
         return top
     elif ( (oloc & right) ):
         return right
     elif ( (oloc & left) ):
         return left
     elif ( (oloc & bot) ):
         return bot
     else:
         return right
Exemplo n.º 5
0
    def toSearchRect(self, point):
        size = 20
        rect = QRectF()
        rect.setLeft(point.x() - size)
        rect.setRight(point.x() + size)
        rect.setTop(point.y() - size)
        rect.setBottom(point.y() + size)

        transform = self.canvas.getCoordinateTransform()
        ll = transform.toMapCoordinates(rect.left(), rect.bottom())
        ur = transform.toMapCoordinates(rect.right(), rect.top())

        rect = QgsRectangle(ur, ll)
        return rect
Exemplo n.º 6
0
    def toSearchRect(self, point):
        size = 20
        rect = QRectF()
        rect.setLeft(point.x() - size)
        rect.setRight(point.x() + size)
        rect.setTop(point.y() - size)
        rect.setBottom(point.y() + size)

        transform = self.canvas.getCoordinateTransform()
        ll = transform.toMapCoordinates(rect.left(), rect.bottom())
        ur = transform.toMapCoordinates(rect.right(), rect.top())

        rect = QgsRectangle(ur, ll)
        return rect
Exemplo n.º 7
0
    def draw(self, painter, size=None):
        """
        :Arguments:
            painter : QPainter
                Opened painter on which to draw
        """
        bounding_rect = QRectF()
        position = self.position
        transfer_function = self.transfer_function
        font = QFont(self.font)
        text_color = self.text_color
        line_color = self.line_color
        line_thickness = self.line_thickness
        value_range = self.value_range
        if size is None:
            viewport = painter.viewport()  # viewport rectangle
            mat, ok = painter.worldMatrix().inverted()
            if not ok:
                raise ValueError(
                    "Transformation matrix of painter is singular.")
            viewport = mat.mapRect(viewport)
        else:
            viewport = size
# First, prepare the gradient
        w = viewport.width()
        h = viewport.height()
        #print("Size of viewport: {0}x{1}".format(w, h))
        gr = QLinearGradient()
        nb_values = ceil(w / 5.0)
        brush_color = QColor()
        for i in range(int(nb_values)):
            brush_color.setRgbF(*transfer_function.rgba(i / nb_values))
            gr.setColorAt(i / nb_values, brush_color)
# Second, find its position
        metric = QFontMetricsF(font, painter.device())
        font_test = [str(i) * 5 for i in range(10)]
        lim_width = 0
        lim_height = 0
        for t in font_test:
            rect = metric.boundingRect(t)
            lim_width = max(lim_width, rect.width())
            lim_height = max(lim_height, rect.height())
        lim_height *= 3
        length = self.scale_length
        shift_length = (1 - length) / 2
        width = self.scale_width
        shift_width = self.scale_shift_width
        delta_value = value_range[1] - value_range[0]
        if position == "Top":
            scale_rect = QRectF(shift_length * w, shift_width * h, length * w,
                                width * h)
            limit_rect(scale_rect, viewport, lim_width, lim_height)
            gr.setStart(scale_rect.left(), scale_rect.center().y())
            gr.setFinalStop(scale_rect.right(), scale_rect.center().y())
            start_pos = scale_rect.bottomLeft()
            end_pos = scale_rect.bottomRight()
        elif position == "Right":
            scale_rect = QRectF((1 - shift_width - width) * w,
                                shift_length * h, width * w, length * h)
            limit_rect(scale_rect, viewport, lim_width, lim_height)
            gr.setStart(scale_rect.center().x(), scale_rect.bottom())
            gr.setFinalStop(scale_rect.center().x(), scale_rect.top())
            start_pos = scale_rect.bottomLeft()
            end_pos = scale_rect.topLeft()
        elif position == "Bottom":
            scale_rect = QRectF(shift_length * w,
                                (1 - shift_width - width) * h, length * w,
                                width * h)
            limit_rect(scale_rect, viewport, lim_width, lim_height)
            gr.setStart(scale_rect.left(), scale_rect.center().y())
            gr.setFinalStop(scale_rect.right(), scale_rect.center().y())
            start_pos = scale_rect.topLeft()
            end_pos = scale_rect.topRight()
        elif position == "Left":
            scale_rect = QRectF(shift_width * w, shift_length * h, width * w,
                                length * h)
            limit_rect(scale_rect, viewport, lim_width, lim_height)
            gr.setStart(scale_rect.center().x(), scale_rect.bottom())
            gr.setFinalStop(scale_rect.center().x(), scale_rect.top())
            start_pos = scale_rect.bottomRight()
            end_pos = scale_rect.topRight()
        else:
            raise ValueError("Invalid scale position: %s" % position)
        shift_pos = (end_pos - start_pos) / delta_value
        if position in ["Left", "Right"]:
            is_vertical = True
            length = scale_rect.height()
        else:
            is_vertical = False
            length = scale_rect.width()
# Get the ticks
        ticks = self.selectValues(length, is_vertical, painter)
        if len(ticks) == 0:
            return
        ticks_str, ticks_extra = self._tick2str(ticks)
        # Figure the shifts
        dist_to_bar = self.text_to_bar
        max_width = 0
        max_height = 0
        for t in ticks_str:
            rect = metric.boundingRect(t)
            max_width = max(rect.width(), max_width)
            max_height = max(rect.height(), max_height)
        if position == "Left":
            shift_left = dist_to_bar
            shift_top = None
        elif position == "Right":
            shift_left = -dist_to_bar - max_width
            shift_top = None
        elif position == "Top":
            shift_left = None
            shift_top = dist_to_bar
        else:
            shift_left = None
            shift_top = -dist_to_bar - max_height
        painter.save()
        painter.translate(viewport.topLeft())
        #print("viewport.topLeft() = {0}x{1}".format(viewport.left(), viewport.top()))
        painter.setBrush(gr)
        line_pen = QPen(line_color)
        line_pen.setWidth(line_thickness)
        painter.setPen(line_pen)
        painter.drawRect(scale_rect)
        bounding_rect |= scale_rect
        #print("Scale rect: +{0}+{1}x{2}x{3}".format(scale_rect.left(),
        #scale_rect.top(), scale_rect.width(), scale_rect.height()))
        painter.setFont(font)
        painter.setPen(text_color)
        for ts, t in zip(ticks_str, ticks):
            r = metric.boundingRect(ts)
            pos = start_pos + shift_pos * (t - value_range[0])
            if shift_left is None:
                pos.setX(pos.x() - r.width() / 2)
            else:
                pos.setX(pos.x() + shift_left)
            if shift_top is None:
                pos.setY(pos.y() - r.height() / 2)
            else:
                pos.setY(pos.y() + shift_top)
            r.moveTo(pos)
            real_rect = painter.drawText(
                r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, ts)
            bounding_rect |= real_rect
        if ticks_extra is not None or self.unit:
            unit = self.unit
            exp_width = width = space_width = 0
            exp_txt = ""
            r = exp_r = unit_r = QRectF()
            exp_font = None
            if ticks_extra is not None:
                exp_txt = u"×10"
                r = metric.boundingRect(exp_txt)
                exp_font = QFont(font)
                exp_size = self.exp_size
                if exp_font.pixelSize() != -1:
                    exp_font.setPixelSize(exp_size * exp_font.pixelSize())
                else:
                    exp_font.setPointSizeF(exp_size * exp_font.pointSizeF())
                exp_metric = QFontMetricsF(exp_font, painter.device())
                exp_r = exp_metric.boundingRect(ticks_extra)
            if unit:
                unit_r = metric.boundingRect(unit)
            total_width = r.width() + exp_r.width() + unit_r.width()
            total_height = max(r.height(),
                               unit_r.height()) + exp_r.height() / 2
            pos = scale_rect.topRight()
            log_debug("top right of scale bar = (%g,%g)" % (pos.x(), pos.y()))
            log_debug("Size of image = (%d,%d)" % (w, h))
            log_debug("Size of text = (%g,%g)" % (total_width, total_height))
            if position == "Bottom":
                pos.setY(pos.y() + scale_rect.height() + dist_to_bar)
                pos.setX(pos.x() - total_width)
            elif position == "Top":
                pos.setY(pos.y() - dist_to_bar - total_height)
                pos.setX(pos.x() - total_width)
            else:  # position == "left" or "right"
                pos.setX(pos.x() - (scale_rect.width() + total_width) / 2)
                if pos.x() < 0:
                    pos.setX(dist_to_bar)
                elif pos.x() + total_width + dist_to_bar > w:
                    pos.setX(w - total_width - dist_to_bar)
                pos.setY(pos.y() - dist_to_bar - total_height)
            log_debug("Display unit at position: (%g,%g)" % (pos.x(), pos.y()))

            if ticks_extra is not None:
                r.moveTo(pos)
                real_rect = painter.drawText(
                    r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter,
                    exp_txt)
                bounding_rect |= real_rect
                pos.setX(pos.x() + r.width())
                pos.setY(pos.y() - metric.ascent() / 2)
                exp_r.moveTo(pos)
                painter.setFont(exp_font)
                real_rect = painter.drawText(
                    exp_r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter,
                    ticks_extra)
                bounding_rect |= real_rect
                pos.setY(pos.y() + metric.ascent() / 2)
            if unit:
                pos.setX(pos.x() + space_width + exp_r.width())
                unit_r.moveTo(pos)
                painter.setFont(font)
                real_rect = painter.drawText(
                    unit_r,
                    Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, unit)
                bounding_rect |= real_rect
        # Draw the ticks now
        painter.setPen(line_pen)
        tick_size = self.tick_size
        if is_vertical:
            width = scale_rect.width() * tick_size
        else:
            width = scale_rect.height() * tick_size
        pen_width = painter.pen().widthF()
        if pen_width == 0:
            pen_width = 1.0
        for t in ticks:
            pos1 = start_pos + shift_pos * (t - value_range[0])
            pos2 = QPointF(pos1)
            if is_vertical:
                pos1.setX(scale_rect.left() + pen_width)
                pos2.setX(pos1.x() + width - pen_width)
                painter.drawLine(pos1, pos2)
                pos1.setX(scale_rect.right() - pen_width)
                pos2.setX(pos1.x() - width + pen_width)
                painter.drawLine(pos1, pos2)
            else:
                pos1.setY(scale_rect.top() + pen_width)
                pos2.setY(pos1.y() + width - pen_width)
                painter.drawLine(pos1, pos2)
                pos1.setY(scale_rect.bottom() - pen_width)
                pos2.setY(pos1.y() - width + pen_width)
                painter.drawLine(pos1, pos2)
        painter.restore()
        bounding_rect = bounding_rect.adjusted(-pen_width, -pen_width,
                                               pen_width, pen_width)
        return bounding_rect
Exemplo n.º 8
0
    def draw(self, painter, size = None):
        """
        :Arguments:
            painter : QPainter
                Opened painter on which to draw
        """
        bounding_rect = QRectF()
        position = self.position
        transfer_function = self.transfer_function
        font = QFont(self.font)
        text_color = self.text_color
        line_color = self.line_color
        line_thickness = self.line_thickness
        value_range = self.value_range
        if size is None:
            viewport = painter.viewport() # viewport rectangle
            mat, ok = painter.worldMatrix().inverted()
            if not ok:
                raise ValueError("Transformation matrix of painter is singular.")
            viewport = mat.mapRect(viewport)
        else:
            viewport = size
# First, prepare the gradient
        w = viewport.width()
        h = viewport.height()
        #print("Size of viewport: {0}x{1}".format(w, h))
        gr = QLinearGradient()
        nb_values = ceil(w/5.0)
        brush_color = QColor()
        for i in range(int(nb_values)):
            brush_color.setRgbF(*transfer_function.rgba(i/nb_values))
            gr.setColorAt(i/nb_values, brush_color)
# Second, find its position
        metric = QFontMetricsF(font, painter.device())
        font_test = [ str(i)*5 for i in range(10) ]
        lim_width = 0
        lim_height = 0
        for t in font_test:
            rect = metric.boundingRect(t)
            lim_width  = max(lim_width,  rect.width())
            lim_height = max(lim_height, rect.height())
        lim_height *= 3
        length = self.scale_length
        shift_length = (1-length)/2
        width = self.scale_width
        shift_width = self.scale_shift_width
        delta_value = value_range[1]-value_range[0]
        if position == "Top":
            scale_rect = QRectF(shift_length*w, shift_width*h, length*w, width*h)
            limit_rect(scale_rect, viewport, lim_width, lim_height)
            gr.setStart(scale_rect.left(), scale_rect.center().y())
            gr.setFinalStop(scale_rect.right(), scale_rect.center().y())
            start_pos = scale_rect.bottomLeft()
            end_pos = scale_rect.bottomRight()
        elif position == "Right":
            scale_rect = QRectF((1-shift_width-width)*w, shift_length*h, width*w, length*h)
            limit_rect(scale_rect, viewport, lim_width, lim_height)
            gr.setStart(scale_rect.center().x(), scale_rect.bottom())
            gr.setFinalStop(scale_rect.center().x(), scale_rect.top())
            start_pos = scale_rect.bottomLeft()
            end_pos = scale_rect.topLeft()
        elif position == "Bottom":
            scale_rect = QRectF(shift_length*w, (1-shift_width-width)*h, length*w, width*h)
            limit_rect(scale_rect, viewport, lim_width, lim_height)
            gr.setStart(scale_rect.left(), scale_rect.center().y())
            gr.setFinalStop(scale_rect.right(), scale_rect.center().y())
            start_pos = scale_rect.topLeft()
            end_pos = scale_rect.topRight()
        elif position == "Left":
            scale_rect = QRectF(shift_width*w, shift_length*h, width*w, length*h)
            limit_rect(scale_rect, viewport, lim_width, lim_height)
            gr.setStart(scale_rect.center().x(), scale_rect.bottom())
            gr.setFinalStop(scale_rect.center().x(), scale_rect.top())
            start_pos = scale_rect.bottomRight()
            end_pos = scale_rect.topRight()
        else:
            raise ValueError("Invalid scale position: %s" % position)
        shift_pos = (end_pos-start_pos)/delta_value
        if position in ["Left", "Right"]:
            is_vertical = True
            length = scale_rect.height()
        else:
            is_vertical = False
            length = scale_rect.width()
# Get the ticks
        ticks = self.selectValues(length, is_vertical, painter)
        if len(ticks) == 0:
            return
        ticks_str, ticks_extra = self._tick2str(ticks)
# Figure the shifts
        dist_to_bar = self.text_to_bar
        max_width = 0
        max_height = 0
        for t in ticks_str:
            rect = metric.boundingRect(t)
            max_width = max(rect.width(), max_width)
            max_height = max(rect.height(), max_height)
        if position == "Left":
            shift_left = dist_to_bar
            shift_top = None
        elif position == "Right":
            shift_left = -dist_to_bar-max_width
            shift_top = None
        elif position == "Top":
            shift_left = None
            shift_top = dist_to_bar
        else:
            shift_left = None
            shift_top = -dist_to_bar-max_height
        painter.save()
        painter.translate(viewport.topLeft())
        #print("viewport.topLeft() = {0}x{1}".format(viewport.left(), viewport.top()))
        painter.setBrush(gr)
        line_pen = QPen(line_color)
        line_pen.setWidth(line_thickness)
        painter.setPen(line_pen)
        painter.drawRect(scale_rect)
        bounding_rect |= scale_rect
        #print("Scale rect: +{0}+{1}x{2}x{3}".format(scale_rect.left(),
            #scale_rect.top(), scale_rect.width(), scale_rect.height()))
        painter.setFont(font)
        painter.setPen(text_color)
        for ts,t in zip(ticks_str, ticks):
            r = metric.boundingRect(ts)
            pos = start_pos+shift_pos*(t-value_range[0])
            if shift_left is None:
                pos.setX( pos.x() - r.width()/2 )
            else:
                pos.setX( pos.x() + shift_left )
            if shift_top is None:
                pos.setY( pos.y() - r.height()/2)
            else:
                pos.setY( pos.y() + shift_top )
            r.moveTo(pos)
            real_rect = painter.drawText(r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, ts)
            bounding_rect |= real_rect
        if ticks_extra is not None or self.unit:
            unit = self.unit
            exp_width = width = space_width = 0
            exp_txt = ""
            r = exp_r = unit_r = QRectF()
            exp_font = None
            if ticks_extra is not None:
                exp_txt = u"×10"
                r = metric.boundingRect(exp_txt)
                exp_font = QFont(font)
                exp_size = self.exp_size
                if exp_font.pixelSize() != -1:
                    exp_font.setPixelSize(exp_size*exp_font.pixelSize())
                else:
                    exp_font.setPointSizeF(exp_size*exp_font.pointSizeF())
                exp_metric = QFontMetricsF(exp_font, painter.device())
                exp_r = exp_metric.boundingRect(ticks_extra)
            if unit:
                unit_r = metric.boundingRect(unit)
            total_width = r.width()+exp_r.width()+unit_r.width()
            total_height = max(r.height(),unit_r.height())+exp_r.height()/2
            pos = scale_rect.topRight()
            log_debug("top right of scale bar = (%g,%g)" % (pos.x(), pos.y()))
            log_debug("Size of image = (%d,%d)" % (w,h))
            log_debug("Size of text = (%g,%g)" % (total_width, total_height))
            if position == "Bottom":
                pos.setY(pos.y() + scale_rect.height() + dist_to_bar)
                pos.setX(pos.x() - total_width)
            elif position == "Top":
                pos.setY(pos.y() - dist_to_bar - total_height)
                pos.setX(pos.x() - total_width)
            else: # position == "left" or "right"
                pos.setX(pos.x() - (scale_rect.width() + total_width)/2)
                if pos.x() < 0:
                    pos.setX(dist_to_bar)
                elif pos.x()+total_width+dist_to_bar > w:
                    pos.setX(w - total_width - dist_to_bar)
                pos.setY(pos.y() - dist_to_bar - total_height)
            log_debug("Display unit at position: (%g,%g)" % (pos.x(), pos.y()))

            if ticks_extra is not None:
                r.moveTo(pos)
                real_rect = painter.drawText(r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, exp_txt)
                bounding_rect |= real_rect
                pos.setX( pos.x() + r.width() )
                pos.setY( pos.y() - metric.ascent()/2 )
                exp_r.moveTo(pos)
                painter.setFont(exp_font)
                real_rect = painter.drawText(exp_r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, ticks_extra)
                bounding_rect |= real_rect
                pos.setY(pos.y() + metric.ascent()/2)
            if unit:
                pos.setX(pos.x() + space_width + exp_r.width())
                unit_r.moveTo(pos)
                painter.setFont(font)
                real_rect = painter.drawText(unit_r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, unit)
                bounding_rect |= real_rect
        # Draw the ticks now
        painter.setPen(line_pen)
        tick_size = self.tick_size
        if is_vertical:
            width = scale_rect.width()*tick_size
        else:
            width = scale_rect.height()*tick_size
        pen_width = painter.pen().widthF()
        if pen_width == 0:
            pen_width = 1.0
        for t in ticks:
            pos1 = start_pos + shift_pos*(t-value_range[0])
            pos2 = QPointF(pos1)
            if is_vertical:
                pos1.setX(scale_rect.left() + pen_width)
                pos2.setX(pos1.x() + width - pen_width)
                painter.drawLine(pos1, pos2)
                pos1.setX(scale_rect.right() - pen_width)
                pos2.setX(pos1.x() - width + pen_width)
                painter.drawLine(pos1, pos2)
            else:
                pos1.setY(scale_rect.top() + pen_width)
                pos2.setY(pos1.y() + width - pen_width)
                painter.drawLine(pos1, pos2)
                pos1.setY(scale_rect.bottom() - pen_width)
                pos2.setY(pos1.y() - width + pen_width)
                painter.drawLine(pos1, pos2)
        painter.restore()
        bounding_rect = bounding_rect.adjusted(-pen_width, -pen_width, pen_width, pen_width)
        return bounding_rect
Exemplo n.º 9
0
class DrawManager(QObject):
    """
    DEPRECATED.
    Will be replaced with BrushingModel, BrushingControler, BrushStroke.
    """
     
    brushSizeChanged  = pyqtSignal(int)
    brushColorChanged = pyqtSignal(QColor)
    
    minBrushSize       = 1
    maxBrushSize       = 61
    defaultBrushSize   = 3
    defaultDrawnNumber = 1
    defaultColor       = Qt.white
    erasingColor       = Qt.black
    
    def __init__(self):
        QObject.__init__(self)
        self.shape = None
        self.bb    = QRect() #bounding box enclosing the drawing
        self.brushSize = self.defaultBrushSize
        self.drawColor = self.defaultColor
        self.drawnNumber = self.defaultDrawnNumber

        self.penVis  = QPen(self.drawColor, self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
        self.penDraw = QPen(self.drawColor, self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
        self.pos = None
        self.erasing = False
        
        #on which layer do we want to draw when self.drawingEnabled?
        self.drawOnto = None
        
        #an empty scene, where we add all drawn line segments
        #a QGraphicsLineItem, and which we can use to then
        #render to an image
        self.scene = QGraphicsScene()

    def growBoundingBox(self):
        self.bb.setLeft(  max(0, self.bb.left()-self.brushSize-1))
        self.bb.setTop(   max(0, self.bb.top()-self.brushSize-1 ))
        self.bb.setRight( min(self.shape[0], self.bb.right()+self.brushSize+1))
        self.bb.setBottom(min(self.shape[1], self.bb.bottom()+self.brushSize+1))

    def toggleErase(self):
        self.erasing = not(self.erasing)

    def setErasing(self):
        self.erasing = True
        self.brushColorChanged.emit(self.erasingColor)
    
    def disableErasing(self):
        self.erasing = False
        self.brushColorChanged.emit(self.drawColor)

    def setBrushSize(self, size):
        self.brushSize = size
        self.penVis.setWidth(size)
        self.penDraw.setWidth(size)
        self.brushSizeChanged.emit(self.brushSize)
    
    def setDrawnNumber(self, num):
        self.drawnNumber = num
        self.drawnNumberChanged.emit(num)
        
    def getBrushSize(self):
        return self.brushSize
    
    def brushSmaller(self):
        b = self.brushSize
        if b > self.minBrushSize:
            self.setBrushSize(b-1)
        
    def brushBigger(self):
        b = self.brushSize
        if self.brushSize < self.maxBrushSize:
            self.setBrushSize(b+1)
        
    def setBrushColor(self, color):
        self.drawColor = color
        self.penVis.setColor(color)
        self.emit.brushColorChanged(self.drawColor)
        
    def beginDrawing(self, pos, shape):
        self.shape = shape
        self.bb = QRectF(0, 0, self.shape[0], self.shape[1])
        self.scene.clear()
        if self.erasing:
            self.penVis.setColor(self.erasingColor)
        else:
            self.penVis.setColor(self.drawColor)
        self.pos = QPointF(pos.x()+0.0001, pos.y()+0.0001)
        line = self.moveTo(pos)
        return line

    def endDrawing(self, pos):
        self.moveTo(pos)
        self.growBoundingBox()

        tempi = QImage(QSize(self.bb.width(), self.bb.height()), QImage.Format_ARGB32_Premultiplied) #TODO: format
        tempi.fill(0)
        painter = QPainter(tempi)
        
        self.scene.render(painter, QRectF(QPointF(0,0), self.bb.size()), self.bb)
        
        return (self.bb.left(), self.bb.top(), tempi) #TODO: hackish, probably return a class ??

    def dumpDraw(self, pos):
        res = self.endDrawing(pos)
        self.beginDrawing(pos, self.shape)
        return res

    def moveTo(self, pos):    
        lineVis = QGraphicsLineItem(self.pos.x(), self.pos.y(), pos.x(), pos.y())
        lineVis.setPen(self.penVis)
        
        line = QGraphicsLineItem(self.pos.x(), self.pos.y(), pos.x(), pos.y())
        line.setPen(self.penDraw)
        self.scene.addItem(line)

        self.pos = pos
        x = pos.x()
        y = pos.y()
        #update bounding Box :
        if x > self.bb.right():
            self.bb.setRight(x)
        if x < self.bb.left():
            self.bb.setLeft(x)
        if y > self.bb.bottom():
            self.bb.setBottom(y)
        if y < self.bb.top():
            self.bb.setTop(y)
        return lineVis
Exemplo n.º 10
0
    def layout(self,
               scene,
               nodes,
               center=None,
               padX=None,
               padY=None,
               direction=None,
               animationGroup=None):
        """
        Lays out the nodes for this scene based on a block layering algorithm.
        
        :param      scene          | <XNodeScene>
                    nodes          | [<XNode>, ..]
                    center         | <QPointF> || None
                    padX           | <int> || None
                    padY           | <int> || None
                    direction      | <Qt.Direction>
                    animationGroup | <QAnimationGroup> || None
        
        :return     {<XNode>: <QRectF>, ..} | new rects per affected node
        """
        nodes = filter(lambda x: x is not None and x.isVisible(), nodes)

        # make sure we have at least 1 node, otherwise, it is already laid out
        if not nodes or len(nodes) == 1:
            return {}

        # calculate the default padding based on the scene
        if padX == None:
            if direction == Qt.Vertical:
                padX = 2 * scene.cellWidth()
            else:
                padX = 4 * scene.cellWidth()

        if padY == None:
            if direction == Qt.Vertical:
                padY = 4 * scene.cellHeight()
            else:
                padY = 2 * scene.cellWidth()

        # step 1: create a mapping of the connections
        connection_map = self.connectionMap(scene, nodes)

        # step 2: organize the nodes into layers based on their connection chain
        layers = self.generateLayers(scene, nodes, connection_map)
        layers = list(reversed(layers))

        # step 3: calculate the total dimensions for the layout
        bounds = QRectF()

        # step 3.1: compare the nodes together that have common connections
        layer_widths = []
        layer_heights = []
        node_heights = {}
        node_widths = {}

        for layer_index, layer in enumerate(layers):
            layer_w = 0
            layer_h = 0

            layer_node_w = []
            layer_node_h = []

            self.organizeLayer(layer, connection_map)

            for node in layer:
                rect = node.rect()

                layer_node_w.append(rect.width())
                layer_node_h.append(rect.height())

                if direction == Qt.Vertical:
                    layer_w += rect.width()
                    layer_h = max(rect.height(), layer_h)
                else:
                    layer_w = max(rect.width(), layer_w)
                    layer_h += rect.height()

            # update the bounding area
            if direction == Qt.Vertical:
                layer_w += padX * 1 - len(layer)
                bounds.setWidth(max(layer_w, bounds.width()))
                bounds.setHeight(bounds.height() + layer_h)
            else:
                layer_h += padY * 1 - len(layer)
                bounds.setWidth(bounds.width() + layer_w)
                bounds.setHeight(max(layer_h, bounds.height()))

            node_widths[layer_index] = layer_node_w
            node_heights[layer_index] = layer_node_h

            layer_widths.append(layer_w)
            layer_heights.append(layer_h)

        if not center:
            center = scene.sceneRect().center()

        w = bounds.width()
        h = bounds.height()
        bounds.setX(center.x() - bounds.width() / 2.0)
        bounds.setY(center.y() - bounds.height() / 2.0)
        bounds.setWidth(w)
        bounds.setHeight(h)

        # step 4: assign positions for each node by layer
        processed_nodes = {}
        layer_grps = [(i, layer) for i, layer in enumerate(layers)]
        layer_grps.sort(key=lambda x: len(x[1]))

        for layer_index, layer in reversed(layer_grps):
            layer_width = layer_widths[layer_index]
            layer_height = layer_heights[layer_index]

            # determine the starting point for this layer
            if direction == Qt.Vertical:
                offset = layer_index * padY + sum(layer_heights[:layer_index])
                point = QPointF(bounds.x(), offset + bounds.y())
            else:
                offset = layer_index * padX + sum(layer_widths[:layer_index])
                point = QPointF(offset + bounds.x(), bounds.y())

            # assign node positions based on existing connections
            for node_index, node in enumerate(layer):
                max_, min_ = (None, None)
                inputs, outputs = connection_map[node]
                for connected_node in inputs + outputs:
                    if not connected_node in processed_nodes:
                        continue

                    npos = processed_nodes[connected_node]
                    nrect = connected_node.rect()
                    rect = QRectF(npos.x(), npos.y(), nrect.width(),
                                  nrect.height())

                    if direction == Qt.Vertical:
                        if min_ is None:
                            min_ = rect.left()
                        min_ = min(rect.left(), min_)
                        max_ = max(rect.right(), max_)
                    else:
                        if min_ is None:
                            min_ = rect.top()
                        min_ = min(rect.top(), min_)
                        max_ = max(rect.bottom(), max_)

                if direction == Qt.Vertical:
                    off_x = 0
                    off_y = (layer_height - node.rect().height()) / 2.0
                    start_x = (bounds.width() - layer_width)
                    start_y = 0
                else:
                    off_x = (layer_width - node.rect().width()) / 2.0
                    off_y = 0
                    start_x = 0
                    start_y = (bounds.height() - layer_height)

                # align against existing nodes
                if not None in (min_, max):
                    if direction == Qt.Vertical:
                        off_x = (max_ - min_) / 2.0 - node.rect().width() / 2.0
                        point_x = min_ + off_x
                        point_y = point.y() + off_y
                    else:
                        off_y = (max_ -
                                 min_) / 2.0 - node.rect().height() / 2.0
                        point_x = point.x() + off_x
                        point_y = min_ + off_y

                # otherwise, align based on its position in the layer
                else:
                    if direction == Qt.Vertical:
                        off_x = sum(node_widths[layer_index][:node_index])
                        off_x += node_index * padX
                        off_x += start_x

                        point_x = point.x() + off_x
                        point_y = point.y() + off_y
                    else:
                        off_y = sum(node_heights[layer_index][:node_index])
                        off_y += node_index * padY
                        off_y += start_y

                        point_x = point.x() + off_x
                        point_y = point.y() + off_y

                if not animationGroup:
                    node.setPos(point_x, point_y)
                else:
                    anim = XNodeAnimation(node, 'setPos')
                    anim.setStartValue(node.pos())
                    anim.setEndValue(QPointF(point_x, point_y))
                    animationGroup.addAnimation(anim)

                processed_nodes[node] = QPointF(point_x, point_y)

                if self._testing:
                    QApplication.processEvents()
                    time.sleep(1)

        return processed_nodes