예제 #1
0
 def initMap(self):
     features = json.load(open("Data/world.json",
                               encoding="utf8")).get("features")
     for feature in features:
         geometry = feature.get("geometry")
         if not geometry:
             continue
         _type = geometry.get("type")
         coordinates = geometry.get("coordinates")
         for coordinate in coordinates:
             if _type == "Polygon":
                 polygon = QPolygonF([
                     QPointF(latitude, -longitude)
                     for latitude, longitude in coordinate
                 ])
                 item = QGraphicsPolygonItem(polygon)
                 item.setPen(QPen(self.borderColor, 0))
                 item.setBrush(QBrush(self.backgroundColor))
                 item.setPos(0, 0)
                 self._scene.addItem(item)
             elif _type == "MultiPolygon":
                 for _coordinate in coordinate:
                     polygon = QPolygonF([
                         QPointF(latitude, -longitude)
                         for latitude, longitude in _coordinate
                     ])
                     item = QGraphicsPolygonItem(polygon)
                     item.setPen(QPen(self.borderColor, 0))
                     item.setBrush(QBrush(self.backgroundColor))
                     item.setPos(0, 0)
                     self._scene.addItem(item)
예제 #2
0
 def create_arrow(tile):
     item = QGraphicsPolygonItem(qt_drawings.arrow_polygon)
     item.setPen(qt_drawings.no_pen)
     if tile:
         item.setBrush(qt_drawings.cyan_brush if tile.is_frozen else qt_drawings.black_brush)
         item.setTransformOriginPoint(qt_drawings.tile_size / 2, qt_drawings.tile_size / 2)
         angle = base_scene_reactor.tile_rotation_angles[tile.is_horizontal][tile.is_positive]
         item.setRotation(angle)
     else:
         item.setBrush(qt_drawings.black_brush)
     return item
예제 #3
0
class RPolygon(QObject):
    def __init__(self, points, color, line_width):
        self._points = [QPointF(p[0], p[1]) for p in points]
        self._pos = self._points[0]
        super().__init__()
        # The underlying QGraphicsPolygonItem
        self.polygon = QGraphicsPolygonItem()
        self.polygon.setPolygon(QPolygonF(self._points))
        self.polygon.setBrush(QtGui.QBrush(color))
        pen = QPen()
        pen.setWidthF(line_width)
        self.polygon.setPen(pen)
        self._visible = 1

    def x(self):
        return self._pos.x()

    def y(self):
        return self._pos.y()

    def points(self):
        return self._points

    # The following functions are for animation support

    @pyqtProperty(QPointF)
    def pos(self):
        return self._pos

    @pos.setter
    def pos(self, value):
        delta_x = value.x() - self._pos.x()
        delta_y = value.y() - self._pos.y()
        self._points = [
            QPointF(p.x() + delta_x,
                    p.y() + delta_y) for p in self._points
        ]
        self.polygon.setPolygon(QPolygonF(self._points))
        self._pos = value

    @pyqtProperty(int)
    def visible(self):
        return self._visible

    @visible.setter
    def visible(self, value):
        if (value > 0): self.polygon.show()
        else: self.polygon.hide()
        self._visible = value
예제 #4
0
	def cloneBody(self, bodyspecName, dropPos, itemId=None, width=0):
		bodyDef = self.bodies[bodyspecName];
		if not itemId:
			if bodyspecName not in self.nameIndex:
				self.nameIndex[bodyspecName] = 0;
			self.nameIndex[bodyspecName] += 1;
			itemId = "{}{}".format(bodyspecName, self.nameIndex[bodyspecName]);
		body = BodyItem(itemId, bodyspecName, 2);
		self.bodyInstances.append(body);
		body.setPos(dropPos);
		group = QGraphicsItemGroup(body);
		self.renderScene.addItem(body);
		width = width*self.UNITS_PER_METER or self.DEFAULT_BODY_SIZE;

		for shape in bodyDef["shapes"]:
			vertices = shape["vertices"];
			if shape["type"] == "POLYGON":
				newItem = QGraphicsPolygonItem(QPolygonF(vertices));
			if shape["type"] == "CIRCLE":
				p1, p2 = vertices
				radius = math.hypot(p2.x()-p1.x(), p2.y()-p1.y());
				newItem = QGraphicsEllipseItem(p1.x()-radius, p1.y()-radius, radius*2, radius*2);
			pen = QPen();
			pen.setWidth(0);			
			newItem.setPen(pen);
			newItem.setParentItem(group);
		bounding = group.childrenBoundingRect();
		imagePath = None;
		height = 0;
		if (bodyDef["image"]):
			imagePath = bodyDef["image"];
			pixmap = QPixmap(imagePath);
			body.setPixmap(pixmap);
			pm = QGraphicsPixmapItem(pixmap.scaledToWidth(width), body);
			body.setImg(pm);
			pm.setFlags(QGraphicsItem.ItemStacksBehindParent);
			pm.setOffset(0, -pm.boundingRect().height());
			group.setScale(width/self.TRANSCOORD_X);
			height = pm.boundingRect().height();
		else:
			group.setScale(width/bounding.width());
			height = bounding.height();
		for item in body.childItems():
			item.setPos(item.pos().x(), item.pos().y() + height)
		body.updateBorder();

		return body;
예제 #5
0
 def draw_polygons(self):
     sf = shapefile.Reader(self.shapefile)
     polygons = sf.shapes()
     for polygon in polygons:
         # convert shapefile geometries into shapely geometries
         # to extract the polygons of a multipolygon
         polygon = shapely.geometry.shape(polygon)
         # if it is a polygon, we use a list to make it iterable
         if polygon.geom_type == 'Polygon':
             polygon = [polygon]
         for land in polygon:
             qt_polygon = QPolygonF()
             for lon, lat in land.exterior.coords:
                 px, py = self.to_canvas_coordinates(lon, lat)
                 if px > 1e+10:
                     continue
                 qt_polygon.append(QPointF(px, py))
             polygon_item = QGraphicsPolygonItem(qt_polygon)
             polygon_item.setBrush(self.land_brush)
             polygon_item.setPen(self.land_pen)
             polygon_item.setZValue(1)
             yield polygon_item
예제 #6
0
    def create_element_model(self, gscene):
        clut = rgbt.RGBTable(filename='gui/red_blue64.csv',
                             data_range=[10.0, 100.])
        ele_model = ele.ElementModel()
        ele_model.elements_from_sequence(self.seq_model)
        pen = QPen()
        pen.setCosmetic(True)
        for e in ele_model.elements:
            poly = e.shape()
            polygon = QPolygonF()
            for p in poly:
                polygon.append(QPointF(p[0], p[1]))
            gpoly = QGraphicsPolygonItem()
            gpoly.setPolygon(polygon)
            # set element color based on V-number
            gc = float(e.medium.glass_code())
            vnbr = round(100.0 * (gc - int(gc)), 3)
            ergb = clut.get_color(vnbr)
            gpoly.setBrush(QColor(*ergb))
            gpoly.setPen(pen)

            t = e.tfrm[1]
            gpoly.setPos(QPointF(t[2], -t[1]))
            gscene.addItem(gpoly)
예제 #7
0
    def create_ray_model(self, gscene, start_surf=1):
        tfrms = self.seq_model.compute_global_coords(start_surf)
        rayset = self.seq_model.trace_boundary_rays()

        start_offset = 0.1 * gscene.sceneRect().width()
        if abs(tfrms[0][1][2]) > start_offset:
            tfrms[0] = self.seq_model.shift_start_of_rayset(
                rayset, start_offset)

        pen = QPen()
        pen.setCosmetic(True)
        for rays in rayset:
            poly1 = []
            for i, r in enumerate(rays[3][0][0:]):
                rot, trns = tfrms[i]
                p = rot.dot(r[0]) + trns
                #                print(i, r[0], rot, trns, p)
                poly1.append(QPointF(p[2], -p[1]))

            poly2 = []
            for i, r in enumerate(rays[4][0][0:]):
                rot, trns = tfrms[i]
                p = rot.dot(r[0]) + trns
                #                print(i, r[0], rot, trns, p)
                poly2.append(QPointF(p[2], -p[1]))

            poly2.reverse()
            poly1.extend(poly2)
            polygon = QPolygonF()
            for p in poly1:
                polygon.append(p)
            gpoly = QGraphicsPolygonItem()
            gpoly.setPolygon(polygon)
            gpoly.setBrush(QColor(254, 197, 254, 64))  # magenta, 25%
            gpoly.setPen(pen)
            gscene.addItem(gpoly)
예제 #8
0
 def draw_polygons(self):
     sf = shapefile.Reader(self.shapefile)
     polygons = sf.shapes()
     for polygon in polygons:
         # convert shapefile geometries into shapely geometries
         # to extract the polygons of a multipolygon
         polygon = shapely.geometry.shape(polygon)
         # if it is a polygon, we use a list to make it iterable
         if polygon.geom_type == 'Polygon':
             polygon = [polygon]
         for land in polygon:
             qt_polygon = QPolygonF()
             land = str(land)[10:-2].replace(', ', ',').replace(' ', ',')
             coords = land.replace('(', '').replace(')', '').split(',')
             for lon, lat in zip(coords[0::2], coords[1::2]):
                 px, py = self.to_canvas_coordinates(lon, lat)
                 if px > 1e+10:
                     continue
                 qt_polygon.append(QPointF(px, py))
             polygon_item = QGraphicsPolygonItem(qt_polygon)
             polygon_item.setBrush(self.land_brush)
             polygon_item.setPen(self.land_pen)
             polygon_item.setZValue(1)
             yield polygon_item
예제 #9
0
class Tower(StaticGameObject):
    def __init__(self):
        super().__init__()
        # initialize attack range (area)
        self.attack_area = QGraphicsPolygonItem()
        self.attack_dest = QPointF(0, 0)
        self.has_target = False

        # set the graphics
        self.setPixmap(
            QPixmap('./res/imgs/lol_tower.png').scaled(80, 80,
                                                       Qt.KeepAspectRatio))

        # initializes health
        h = Bar(self)
        h.set_max_val(250)
        h.set_current_val(250)
        self.set_health(h)
        self.attack = 30

        # create points vector
        points = [
            QPointF(1, 0),
            QPointF(2, 0),
            QPointF(3, 1),
            QPointF(3, 2),
            QPointF(2, 3),
            QPointF(1, 3),
            QPointF(0, 2),
            QPointF(0, 1)
        ]

        # scale points
        SCALE_FACTOR = 100
        points = [p * SCALE_FACTOR for p in points]
        self.range = SCALE_FACTOR

        # create polygon
        self.polygon = QPolygonF(points)

        # create QGraphicsPolygonItem
        self.attack_area = QGraphicsPolygonItem(self.polygon, self)
        self.attack_area.setPen(QPen(Qt.DotLine))

        # move the polygon
        poly_center = QPointF(1.5 * SCALE_FACTOR, 1.5 * SCALE_FACTOR)
        poly_center = self.mapToScene(poly_center)
        tower_center = QPointF(self.x() + 40, self.y() + 40)
        ln = QLineF(poly_center, tower_center)
        self.attack_area.setPos(self.x() + ln.dx(), self.y() + ln.dy())

        # connect a timer to acquire target
        self.damage_timer = QTimer()
        self.damage_timer.timeout.connect(self.acquire_target)
        self.damage_timer.start(1000)

        # allow responding to hover events
        self.setAcceptHoverEvents(True)

    def fire(self):
        if not self.scene():
            return
        bullet = Bullet(self)
        bullet.setPos(self.x() + 40, self.y() + 40)

        # set the angle to be paralel to the line that connects the
        # tower and target
        ln = QLineF(QPointF(self.x() + 40, self.y() + 40), self.attack_dest)
        angle = -1 * ln.angle()  # -1 to make it clock wise

        bullet.setRotation(angle)
        self.scene().addItem(bullet)

    def acquire_target(self):
        # get a list of all items colliding with attack area
        colliding_items = self.attack_area.collidingItems()

        self.has_target = False
        closest_dist = 300
        closest_point = QPointF(0, 0)
        for i in colliding_items:
            if hasattr(i, 'team') and i.team != self.team:
                this_distance = self.distance_to(i)
                if this_distance < closest_dist:
                    closest_dist = this_distance
                    closest_point = i.pos()
                    self.has_target = True

        self.attack_dest = closest_point
        if self.has_target:
            self.fire()

    def distance_to(self, item):
        '''item: QGraphicsItem '''
        ln = QLineF(self.pos(), item.pos())
        return ln.length()

    def hoverEnterEvent(self, event):
        '''event: QGraphicsSceneHoverEvent '''
        # change pixmap
        if self.team == 2:
            self.setPixmap(
                QPixmap('./res/imgs/lol_tower_red.png').scaled(
                    80, 80, Qt.KeepAspectRatio))

    def hoverLeaveEvent(self, event):
        '''event: QGraphicsSceneHoverEvent '''
        # change back pixmap
        if self.team == 2:
            self.setPixmap(
                QPixmap('./res/imgs/lol_tower.png').scaled(
                    80, 80, Qt.KeepAspectRatio))
예제 #10
0
class GraphicLine(QGraphicsLineItem):
    """
    This class is a graphic line with an arrow which connects
    two blocks in the scene.

    Attributes
    ----------
    origin : QGraphicsRectItem
        Origin rect of the line.
    destination : QGraphicsRectItem
        Destination rect of the line.
    scene : QGraphicsScene
        Current drawing scene.
    brush : QBrush
        Brush to draw the arrow.
    pen : QPen
        Pen to draw the arrow.
    arrow_head : QGraphicsPolygonItem
        Final arrow of the line.
    arrow_size : int
        Size of the head of the arrow.
    dim_label : QGraphicsTextItem
        Text showing the dimensions of the edge.
    is_valid : bool
        Flag monitoring whether the connection is consistent.

    Methods
    ----------
    gen_endpoints(QRectF, QRectF)
        Returns the shortest connection between the two rects.
    draw_arrow()
        Draws the polygon for the arrow.
    set_valid(bool)
        Assign validity for this line.
    update_dims(tuple)
        Update the line dimensions.
    update_pos(QRectF)
        Update the line position given the new rect position.
    remove_self()
        Delete this line.

    """
    def __init__(self, origin: QGraphicsRectItem,
                 destination: QGraphicsRectItem, scene):
        super(GraphicLine, self).__init__()
        self.origin = origin
        self.destination = destination
        self.scene = scene

        # This flag confirms a legal connection
        self.is_valid = True

        # Get the four sides of the rects
        destination_lines = u.get_sides_of(
            self.destination.sceneBoundingRect())
        origin_lines = u.get_sides_of(self.origin.sceneBoundingRect())

        # Get the shortest edge between the two blocks
        self.setLine(self.gen_endpoints(origin_lines, destination_lines))

        self.brush = QBrush(QColor(style.GREY_0))
        self.pen = QPen(QColor(style.GREY_0))
        self.pen.setWidth(4)
        self.pen.setCapStyle(Qt.RoundCap)
        self.pen.setJoinStyle(Qt.RoundJoin)
        self.setPen(self.pen)

        # Dimensions labels
        self.dim_label = QGraphicsTextItem()
        self.dim_label.setZValue(6)
        self.scene.addItem(self.dim_label)

        # Arrow head
        self.arrow_head = QGraphicsPolygonItem()
        self.arrow_head.setPen(self.pen)
        self.arrow_head.setBrush(self.brush)
        self.arrow_size = 15.0

        self.draw_arrow()

    @staticmethod
    def gen_endpoints(origin_sides: dict, destination_sides: dict) -> QLineF:
        """
        This method finds the shortest path between two rectangles.

        Parameters
        ----------
        origin_sides : dict
            The dictionary {side_label: side_size} of the starting rect.
        destination_sides : dict
            The dictionary {side_label: side_size} of the ending rect.

        Returns
        ----------
        QLineF
            The shortest line.

        """

        # Init the line with the maximum possible value
        shortest_line = QLineF(-sys.maxsize / 2, -sys.maxsize / 2,
                               sys.maxsize / 2, sys.maxsize / 2)
        for o_side, origin_side in origin_sides.items():
            o_mid_x, o_mid_y = u.get_midpoint(o_side, origin_side)

            for d_side, destination_side in destination_sides.items():
                d_mid_x, d_mid_y = u.get_midpoint(d_side, destination_side)

                # Update line
                line = QLineF(o_mid_x, o_mid_y, d_mid_x, d_mid_y)
                if line.length() < shortest_line.length():
                    shortest_line = line

        return shortest_line

    def draw_arrow(self) -> None:
        """
        This method draws an arrow at the end of the line.

        """

        polygon_arrow_head = QPolygonF()

        # Compute the arrow angle
        angle = math.acos(self.line().dx() / self.line().length())
        angle = ((math.pi * 2) - angle)

        # Compute the direction where the arrow points (1 up, -1 down)
        arrow_direction = 1
        if math.asin(self.line().dy() / self.line().length()) < 0:
            arrow_direction = -1

        # First point of the arrow tail
        arrow_p1 = self.line().p2() - arrow_direction * QPointF(
            arrow_direction * math.sin(angle + math.pi / 2.5) *
            self.arrow_size,
            math.cos(angle + math.pi / 2.5) * self.arrow_size)
        # Second point of the arrow tail
        arrow_p2 = self.line().p2() - arrow_direction * QPointF(
            arrow_direction * math.sin(angle + math.pi - math.pi / 2.5) *
            self.arrow_size,
            math.cos(angle + math.pi - math.pi / 2.5) * self.arrow_size)

        # Third point is the line end
        polygon_arrow_head.append(self.line().p2())
        polygon_arrow_head.append(arrow_p2)
        polygon_arrow_head.append(arrow_p1)

        # Add the arrow to the scene
        self.arrow_head.setZValue(1)
        self.arrow_head.setParentItem(self)
        self.arrow_head.setPolygon(polygon_arrow_head)

    def set_valid(self, valid: bool) -> None:
        """
        This method changes the arrow style: if the connection 
        is not valid the arrow becomes red, otherwise it 
        remains grey with dimensions displayed. 
        
        Parameters
        ----------
        valid : bool
            New value for the legality flag.

        """

        if valid:
            self.is_valid = True
            self.pen.setColor(QColor(style.GREY_0))
            self.brush.setColor(QColor(style.GREY_0))
            self.dim_label.setVisible(False)
        else:
            self.is_valid = False
            self.pen.setColor(QColor(style.RED_2))
            self.brush.setColor(QColor(style.RED_2))

            if self.scene.is_dim_visible:
                self.dim_label.setVisible(True)

    def update_dims(self, dims: tuple) -> None:
        """
        This method updates the input & output dimensions.
        
        Parameters
        ----------
        dims : tuple
            The new dimensions to update.

        """

        self.dim_label.setHtml("<div style = 'background-color: " +
                               style.RED_2 +
                               "; color: white; font-family: consolas;'>" +
                               str(dims) + "</div>")
        self.dim_label.setPos(self.line().center())

    def update_pos(self, new_target: QRectF):
        """
        This method updates the line as it origin or its destination has
        changed location.

        Parameters
        ----------
        new_target : QRectF

        """

        if new_target == self.destination:
            self.destination = new_target
        elif new_target == self.origin:
            self.origin = new_target

        # Get the four sides of the rects
        destination_lines = u.get_sides_of(
            self.destination.sceneBoundingRect())
        origin_lines = u.get_sides_of(self.origin.sceneBoundingRect())

        # Get the shortest edge between the two blocks
        self.setLine(self.gen_endpoints(origin_lines, destination_lines))
        self.draw_arrow()
        self.dim_label.setPos(self.line().center())

    def remove_self(self) -> None:
        """
        The line is removed from the scene along with origin and destination
        pointers.

        """

        self.scene.removeItem(self)
        self.scene.edges.remove(self)
        self.scene.removeItem(self.dim_label)
        self.origin = None
        self.destination = None
예제 #11
0
class RelationItem():
    ''' This represents one relationship on the diagram.
        This class creates the arc graphics item and the text graphics item and draws them on the scene.
        The RelationInstance class manages reading and writing the relationship to Neo4j
        '''    
    def __init__(self, scene, relationInstance=None):
        
        self.scene = scene
        self.model = self.scene.parent.model
        self.diagramType = "Instance Relationship"
        self.logMsg = None
        # self.relationInstance should have been called self.itemInstance to be consistent
        # with NodeItem.  so we'll set it to none and someday fix this.
        self.itemInstance = None 
        self.relationInstance = relationInstance
        self.startNZID = self.relationInstance.startNZID
        self.endNZID = self.relationInstance.endNZID
        # get the NodeItem objects for the start and end nodes
        self.startNode = self.scene.parent.itemDict[self.startNZID]
        self.endNode = self.scene.parent.itemDict[self.endNZID]

        self.numRels = self.scene.parent.numRels(self.relationInstance.startNZID, self.relationInstance.endNZID)
#        print("numRels:{}".format(self.numRels))
        self.lineType = None
#        print("num rels{}".format(str(self.numRels)))
        # initialize the two qgraphicsitems needed to draw a relationship to None
        self.IRel = None
        self.IRtext = None  
        self.bunnyEar = None
        self.endDot = None
        self.arrowHead = None
        self.TAline1 = None
        self.TAline2 = None
        self.debugTriangle = None
        self.drawRelationship()

        
    def name(self, ):
        return self.relationInstance.NZID 
        
    def NZID(self, ):
        return self.relationInstance.NZID      
        
    def getFormat(self, ):
        '''
        determine if the rel instance has a template format or should use the project default format
        '''
        # get the default
        self.relFormat = IRelFormat(formatDict=self.model.modelData["IRformat"])
        # get a custom template format if there is one
        if not self.relationInstance.relTemplate is None:
            index, relTemplateDict = self.model.getDictByName(topLevel="Relationship Template",objectName=self.relationInstance.relTemplate)
            if not relTemplateDict is None:
                self.instanceRelFormatDict = relTemplateDict.get("IRformat", None)
                if not self.instanceRelFormatDict is None:
                    self.relFormat = IRelFormat(formatDict=self.instanceRelFormatDict) 

    def getNodeId(self):
        '''return the rel id for the relationship from the IREL or bunnyear graphic item - which ever it is
        '''
        if not self.IRel is None:
            nodeID = self.IRel.data(NODEID)
        elif not self.bunnyEar is None:
            nodeID = self.bunnyEar.data(NODEID)
        else:
            nodeID = None
        return nodeID
        
    def clearItem(self, ):

        if (not self.IRel is None and not self.IRel.scene() is None):
            self.IRel.scene().removeItem(self.IRel)        
        if (not self.IRtext is None and not self.IRtext.scene() is None):
            self.IRtext.scene().removeItem(self.IRtext)     
        if (not self.bunnyEar is None and not self.bunnyEar.scene() is None):
            self.bunnyEar.scene().removeItem(self.bunnyEar)                
        if (not self.endDot is None and not self.endDot.scene() is None):
            self.endDot.scene().removeItem(self.endDot)        
        if (not self.arrowHead is None and not self.arrowHead.scene() is None):
            self.arrowHead.scene().removeItem(self.arrowHead)  
        if (not self.TAline2 is None and not self.TAline2.scene() is None):
            self.TAline2.scene().removeItem(self.TAline2)  
        if (not self.TAline1 is None and not self.TAline1.scene() is None):
            self.TAline1.scene().removeItem(self.TAline1)  
#        if (not self.debugTriangle is None and not self.debugTriangle.scene() is None):
#            self.debugTriangle.scene().removeItem(self.debugTriangle)                

    def drawIt(self, ):
        '''
        for consistency, drawIt should be used instead of drawRelationship
        '''
        self.drawRelationship()
        
    def drawRelationship(self, ):
        # relationship is between two different nodes
        if self.startNZID != self.endNZID:
            #  set the line type if it hasn't been determined yet.  This happens on first draw
            if self.lineType is None:
                if self.scene.parent.anyRels(self.relationInstance.startNZID, self.relationInstance.endNZID):
                    self.lineType = CURVE
                else:
                    self.lineType = STRAIGHT
            # now draw the line or arc
            if self.lineType == CURVE:
                self.drawRel()
            else:
                self.drawStraightRel()
        # relationship is between the same node
        if self.startNZID == self.endNZID:
            self.drawBunnyEars()        
        
    def drawBunnyEars(self, ):
        # force the rel instance to update its values in case it has been updated from another diagram or the tree view
        self.relationInstance.reloadDictValues()
        # get the format in case it changed
        self.getFormat()
        # if the arc and text graphics items already exist on the scene then delete them
        self.clearItem()
        # draw the relationship arc
        pen = self.relFormat.pen()
        brush = self.relFormat.brush()
        brush.setColor(QColor(Qt.white))
        # create an ellipse like the startNode
        x = self.startNode.INode.sceneBoundingRect().center().x()
        y = self.startNode.INode.sceneBoundingRect().center().y()
        w = self.startNode.INode.sceneBoundingRect().width()/2.0
        h = self.startNode.INode.sceneBoundingRect().height()/2.0
        myEllipse = Ellipse(x, y, w, h)    
        # move the bunny ears around the ellipse until we run out of room
        startDegree = 360 - (self.numRels * 40)
        if startDegree < 40:
            startDegree = 40
            
        startPoint = myEllipse.pointFromAngle(radians(startDegree))
        endPoint = myEllipse.pointFromAngle(radians(startDegree-35))
        lineMidPoint = centerLine (startPoint[0], startPoint[1], endPoint[0], endPoint[1])
        lineDist = distanceLine (startPoint[0], startPoint[1], endPoint[0], endPoint[1])
        circleRad = lineDist/2.0

        self.bunnyEar = QGraphicsEllipseItem(QRectF(lineMidPoint[0]-circleRad,lineMidPoint[1]-circleRad,circleRad*2,circleRad*2), parent=None)
        self.bunnyEar.setZValue(RELATIONLAYER)
        self.bunnyEar.setBrush(brush)
        self.bunnyEar.setPen(pen)
        self.bunnyEar.setFlag(QGraphicsItem.ItemIsMovable, True) 
        self.bunnyEar.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True) 
        self.bunnyEar.setFlag(QGraphicsItem.ItemIsSelectable, False) 
        self.bunnyEar.setSelected(False)
        
        # create arrowhead
        self.circlex = lineMidPoint[0]
        self.circley = lineMidPoint[1]
        
#        self.circleDot = QGraphicsEllipseItem(QRectF(self.circlex-1.5,self.circley-1.5,3, 3), parent=None)
#        self.circleDot.setZValue(NODELAYER)
#        self.scene.addItem(self.circleDot) 
#        self.pointDot = QGraphicsEllipseItem(QRectF(endPoint[0]-1.5,endPoint[1]-1.5,3, 3), parent=None)
#        self.pointDot.setZValue(NODELAYER)
#        self.scene.addItem(self.pointDot) 
        
        # compute the arrow base center point 
        arrowLen = 5    # this is half the distance of the arrowhead base which determines how wide the arrow head is
        # compute a point on the arc that is a short distance away from the edge of the ellipse.  this is the base of the arrow head        

        # get the slope of the line from the start point to the end point on the node ellipse
        if endPoint[0] == startPoint[0]:
            startPoint[0] = startPoint[0] + .001
#        slope1 = (startPoint[1] - endPoint[1])/(startPoint[0] - endPoint[0])
        slope1 = (endPoint[1] - startPoint[1] )/(endPoint[0] - startPoint[0])
        if slope1 == 1.0:
            slope1 = 1.001
        slope1Squared = slope1 * slope1
        perpSlope1 =  -1.0 / slope1
        perpSlope1Squared = perpSlope1 * perpSlope1
#        print("numrels:{} startDegree:{} radius:{} slope:{} perpslope:{}".format(self.numRels, startDegree, circleRad, slope1,  perpSlope1))
        # now find a point on the line tangent to the point on the bunny ear circle.  This is the base of the arrow
#        ax = (arrowLen / sqrt(1 + (perpSlope1Squared)))
#        ay = ax * perpSlope1   
        if lineMidPoint[0] < x:
            baseX = endPoint[0] - (arrowLen / sqrt(1 + (perpSlope1Squared)))
            baseY = endPoint[1] - ((arrowLen / sqrt(1 + (perpSlope1Squared))) * perpSlope1 )
        else:
            baseX = endPoint[0] + (arrowLen / sqrt(1 + (perpSlope1Squared)))
            baseY = endPoint[1] + ((arrowLen / sqrt(1 + (perpSlope1Squared))) * perpSlope1 )
#        print("ax:{} ay:{} slope1:{} perslope1:{}".format(ax, ay, slope1, perpSlope1))
#        self.anchorDot = QGraphicsEllipseItem(QRectF(baseX-1.5,baseY-1.5,3, 3), parent=None)
#        self.anchorDot.setZValue(NODELAYER)
#        self.scene.addItem(self.anchorDot) 
        
        # get first arrowhead base corner
        ab1dx = (arrowLen / sqrt(1 + (slope1Squared)))
        ab1dy = ab1dx * slope1
        self.b1x = baseX + ab1dx
        self.b1y = baseY + ab1dy
        # get 2nd arrowhead base corner
        ab2dx = (arrowLen / sqrt(1 + (slope1Squared)))
        ab2dy = ab2dx * slope1
        self.b2x = baseX - ab2dx
        self.b2y = baseY - ab2dy        

        
#        # calculate the arrowhead points
#        cx = self.endNode.INode.sceneBoundingRect().center().x()
#        cy = self.endNode.INode.sceneBoundingRect().center().y()
#        self.calcArrowHead(QPointF(cx, cy), QPointF( endPoint[0], endPoint[1]), bunnyEars=True)


        #create an empty polygon
        arrowPolygon = QPolygonF()
#        # add arrowhead points
#        arrowPolygon.append(QPointF(self.ah1x, self.ah1y))
#        arrowPolygon.append(QPointF(endPoint[0], endPoint[1]))
#        arrowPolygon.append(QPointF(self.ah2x, self.ah2y))
        # add arrowhead points
        arrowPolygon.append(QPointF(self.b1x, self.b1y))
        arrowPolygon.append(QPointF(endPoint[0], endPoint[1]))
        arrowPolygon.append(QPointF(self.b2x, self.b2y))        
        
        self.arrowHead = QGraphicsPolygonItem(arrowPolygon, parent=None, )
        self.arrowHead.setZValue(RELATIONLAYER)
        self.arrowHead.setBrush(brush)
        self.arrowHead.setPen(pen)
        self.arrowHead.setFlag(QGraphicsItem.ItemIsMovable, True) 
        self.arrowHead.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True) 
        self.arrowHead.setFlag(QGraphicsItem.ItemIsSelectable, False) 
        self.arrowHead.setSelected(False)
        
        # set data in the bunnyEar object
        self.bunnyEar.setData(NODEID, self.relationInstance.NZID) 
        self.bunnyEar.setData(ITEMTYPE, RELINSTANCEARC)
        self.scene.addItem(self.bunnyEar) 
        self.scene.addItem(self.arrowHead) 

        # calculate position  of text
        bunnyEllipse = Ellipse(lineMidPoint[0],lineMidPoint[1],circleRad,circleRad)  
        # use the same midpoint angle as the bunny ear start and end point
        bunnyMidPoint = bunnyEllipse.pointFromAngle(radians(startDegree-17.5))
        # draw the text
        self.drawText(bunnyMidPoint[0], bunnyMidPoint[1], startPoint[0], startPoint[1], endPoint[0], endPoint[1])
#        self.anchorDot = QGraphicsEllipseItem(QRectF(bunnyMidPoint[0]-1.5,bunnyMidPoint[1]-1.5,3, 3), parent=None)
#        self.anchorDot.setZValue(NODELAYER)
#        self.scene.addItem(self.anchorDot) 

    def drawStraightRel(self):
#        print("draw straight rel")
        # force the rel instance to update its values in case it has been updated from another diagram or the tree view
        self.relationInstance.reloadDictValues()
        # get the format in case it changed
        self.getFormat()
        # if the arc and text graphics items already exist on the scene then delete them
        self.clearItem()
        # draw the relationship arc
        pen = self.relFormat.pen()
        brush = self.relFormat.brush()
    
        # get the centerpoint of the end node
        cx = self.endNode.INode.sceneBoundingRect().center().x()
        cy = self.endNode.INode.sceneBoundingRect().center().y()
        
        # get the start and end points of the line
        esx, esy, eex, eey = self.calcLine3()
        # create the arc qgraphicsitem
        self.IRel = QGraphicsLineItem(esx, esy, eex, eey, parent=None) 
        arrowLine = self.IRel
        # text location 
        tx = self.IRel.line().pointAt(.5).x()
        ty = self.IRel.line().pointAt(.5).y()                   

        # draw the relationship line
        pen = self.relFormat.pen()      
        # configure the lines and add them to the scene
        self.IRel.setPen(pen)
        self.IRel.setZValue(RELATIONLAYER)   
        self.IRel.setData(NODEID, self.relationInstance.NZID) 
        self.IRel.setData(ITEMTYPE, RELINSTANCEARC)
        self.IRel.setFlag(QGraphicsItem.ItemIsSelectable, True) 
        self.scene.addItem(self.IRel)   

        # line arrowhead
        # compute the arrow base center point 
        arrowLen = 5    # this is half the distance of the arrowhead base which determines how wide the arrow head is
        # compute a point on the arc that is a short distance away from the edge of the ellipse.  this is the base of the arrow head        


        ax =  self.IRel.line().pointAt(1-(10.0/self.IRel.line().length())).x()
        ay = self.IRel.line().pointAt(1-(10.0/self.IRel.line().length())).y()
        # compute the arrow base corners
        if eex == ax:
            ax = ax + .001
        # get the slope of the line from the ellipse to the arrowhead base
        slope = (eey - ay)/(eex - ax)
        if slope == 1.0:
            slope = 1.001
        # get the perpindicular slope
        perpSlope = -1.0 / slope
        perpSlopeSquared = perpSlope * perpSlope
        # get first arrowhead base corner
        ab1dx = (arrowLen / sqrt(1 + (perpSlopeSquared)))
        ab1dy = ab1dx * perpSlope
        self.b1x = ax + ab1dx
        self.b1y = ay + ab1dy
        # get 2nd arrowhead base corner
        ab2dx = (arrowLen / sqrt(1 + (perpSlopeSquared)))
        ab2dy = ab2dx * perpSlope
        self.b2x = ax - ab2dx
        self.b2y = ay - ab2dy        


        #create an empty polygon
        arrowPolygon = QPolygonF()
        # add arrowhead points
        arrowPolygon.append(QPointF(self.b1x, self.b1y))
        arrowPolygon.append(QPointF(eex, eey))
        arrowPolygon.append(QPointF(self.b2x, self.b2y))
        
        self.arrowHead = QGraphicsPolygonItem(arrowPolygon, parent=None, )
        self.arrowHead.setZValue(RELATIONLAYER)
        self.arrowHead.setBrush(brush)
        self.arrowHead.setPen(pen)
        self.arrowHead.setFlag(QGraphicsItem.ItemIsMovable, True) 
        self.arrowHead.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True) 
        self.arrowHead.setFlag(QGraphicsItem.ItemIsSelectable, False) 
        self.arrowHead.setSelected(False)        
        self.scene.addItem(self.arrowHead) 
        
        # draw the text
        self.drawText(tx, ty, esx, esy, eex, eey)
        
    def drawRel(self, ):
        # draw the curved relationship line
#        print("draw curve rel")
        # force the rel instance to update its values in case it has been updated from another diagram or the tree view
        self.relationInstance.reloadDictValues()
        # get the format in case it changed
        self.getFormat()
        # if the arc and text graphics items already exist on the scene then delete them
        self.clearItem()
        # draw the relationship arc
        pen = self.relFormat.pen()
        brush = self.relFormat.brush()
        
        # METHOD 1 use ellipse center points
#        # get the center points of the qgraphicellipses
#        sx = self.startNode.INode.sceneBoundingRect().center().x()
#        sy = self.startNode.INode.sceneBoundingRect().center().y()
#        ex = self.endNode.INode.sceneBoundingRect().center().x()
#        ey = self.endNode.INode.sceneBoundingRect().center().y()
#        # if the x's or y's are equal offset one slightly to avoid divide by zero errors
#        if sx == ex:
#            ex = ex + .001
#        if sy == ey:
#            ey = ey + .001        
#        self.IRel = RelArc(parent=None, sx=sx, sy=sy, ex=ex, ey=ey, pen=pen, brush=brush, numRels=self.numRels)
        
        # METHOD 2 use points on the ellipse
#        esx, esy, eex, eey = self.calcLine()
#        self.IRel = RelArc(parent=None, sx=esx, sy=esy, ex=eex, ey=eey, pen=pen, brush=brush, numRels=self.numRels)

        # METHOD 3 use regularly spaced endpoints on the ellipse
        # get the centerpoint of the end node
        cx = self.endNode.INode.sceneBoundingRect().center().x()
        cy = self.endNode.INode.sceneBoundingRect().center().y()
        

        # get the start and end points of the arc 
        esx, esy, eex, eey = self.calcLine2()
        # create the arc qgraphicsitem
        self.IRel = RelArc(parent=None, sx=esx, sy=esy, ex=eex, ey=eey, cx=cx, cy=cy, pen=pen, brush=brush, numRels=self.numRels)

        #create an empty polygon
        arrowPolygon = QPolygonF()
        # add arrowhead points
        arrowPolygon.append(QPointF(self.IRel.b1x, self.IRel.b1y))
        arrowPolygon.append(QPointF(eex, eey))
        arrowPolygon.append(QPointF(self.IRel.b2x, self.IRel.b2y))
        
        self.arrowHead = QGraphicsPolygonItem(arrowPolygon, parent=None, )
        self.arrowHead.setZValue(RELATIONLAYER)
        self.arrowHead.setBrush(brush)
        self.arrowHead.setPen(pen)
        self.arrowHead.setFlag(QGraphicsItem.ItemIsMovable, True) 
        self.arrowHead.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True) 
        self.arrowHead.setFlag(QGraphicsItem.ItemIsSelectable, False) 
        self.arrowHead.setSelected(False)
        
        # set data in the RelLine object
        self.IRel.setData(NODEID, self.relationInstance.NZID) 
        self.IRel.setData(ITEMTYPE, RELINSTANCEARC)
        # add the RelLine object to the scene
        self.scene.addItem(self.IRel) 
        # add arrowhead to the scene
        self.scene.addItem(self.arrowHead) 
        # draw the text
        self.drawText(self.IRel.mx, self.IRel.my, esx, esy, eex, eey)

        
    def drawText(self, mx, my, esx, esy, eex, eey):
        # mx,my is the center point of the arc
        # esx,esy is the start point of the arc
        # eex,eey is the end point of the arc
        
        # get the center points of the node qgraphicellipses
        sx = self.startNode.INode.sceneBoundingRect().center().x()
        sy = self.startNode.INode.sceneBoundingRect().center().y()
        sh = self.startNode.INode.sceneBoundingRect().height()
        ex = self.endNode.INode.sceneBoundingRect().center().x()
        ey = self.endNode.INode.sceneBoundingRect().center().y()
        eh = self.endNode.INode.sceneBoundingRect().height()
        # if the x's or y's are equal offset one slightly to avoid divide by zero errors
        if sx == ex:
            ex = ex + .001
        if sy == ey:
            ey = ey + .001        
        # draw the text 
#        self.IRtext = QGraphicsTextItem(self.relationInstance.relName, parent=None)
        self.IRtext = RelText(parent=None)
#        self.IRtext.setZValue(RELATIONLAYER)
#        self.IRtext.setFlag(QGraphicsItem.ItemIsMovable, True) 
#        self.IRtext.setFlag(QGraphicsItem.ItemIsSelectable, True) 
#        self.IRtext.setSelected(True)
#        self.IRtext.setAcceptHoverEvents(True)
        self.IRtext.setData(NODEID, self.relationInstance.NZID) 
        self.IRtext.setData(ITEMTYPE, RELINSTANCETEXT)
        self.IRtext.setHtml(self.genRelHTML())
        
        #calculate rotation angle
        adj = abs(esx-eex)
        opp = abs(esy-eey)
        OOA = opp/adj
        rotateAnglerad = (atan(OOA))
        rotateAngledeg = degrees(atan(OOA))
        
        # get the height and width of the text graphics item
        th = self.IRtext.boundingRect().height()
        tw  = self.IRtext.boundingRect().width()
        
        # position the relation name text centered on the arc centerpoint
        if self.startNZID != self.endNZID:
#            esx, esy, eex, eey
            if esy >= eey and esx <= eex:
                # end node is above and to the right 
                self.IRtext.setRotation((360 - rotateAngledeg))
                xoffset = (tw/2) * cos(rotateAnglerad)
                yoffset = (tw/2) * sin(rotateAnglerad)                
                self.IRtext.setPos(QPointF(mx - xoffset, my + yoffset ))
            
            elif esy <= eey and esx <= eex:
                # end node is below and to the right
                self.IRtext.setRotation(rotateAngledeg)
                xoffset = (tw/2) * (cos(rotateAnglerad))
                yoffset = (tw/2) * (sin(rotateAnglerad))
                self.IRtext.setPos(QPointF(mx - xoffset, my - yoffset ))
            
            elif esy >= eey and esx >= eex:
                # end node is above and to the left
                self.IRtext.setRotation(rotateAngledeg)
                xoffset = (tw/2) * (cos(rotateAnglerad))
                yoffset = (tw/2) * (sin(rotateAnglerad))
                self.IRtext.setPos(QPointF(mx - xoffset, my - yoffset ))       
                
            elif esy <= eey and esx >= eex:
                # end node is below and to the left
                self.IRtext.setRotation((360 - rotateAngledeg))
                xoffset = (tw/2) * cos(rotateAnglerad)
                yoffset = (tw/2) * sin(rotateAnglerad)                
                self.IRtext.setPos(QPointF(mx - xoffset, my + yoffset ))
                
            # this shouldn't happen      
            else:
                xoffset = (tw/2)
                yoffset = (tw/2)             
                self.IRtext.setPos(QPointF(mx, my ))
                
#            print("tw {} xoffset {} yoffset {} angle {}".format(tw,  xoffset, yoffset, rotateAngledeg)) 
            
        elif self.startNZID == self.endNZID:
            if mx > sx:
                self.IRtext.setPos(QPointF(mx, my - (th) ))
            if mx < sx:
                self.IRtext.setPos(QPointF(mx - tw, my - (th) ))
        else:
            # this shouldn't happen
            self.IRtext.setPos(QPointF(mx, my ))   

        self.scene.addItem(self.IRtext) 
        
    def updateText(self, ):
        # force the node instance to update its values in case it has been updated from another diagram or the tree view
        self.relationInstance.reloadDictValues()
#        self.IRtext.setPlainText(self.relationInstance.relName)
        self.IRtext.setHtml(self.genRelHTML())
    
    def genRelHTML(self):
        '''generate html to display the relationship type
        '''
        prefix = '<html><body>'
        suffix = "</body></html>"
        myHTML = ('{}<p><font size="1"> [{}]</font></p>{}'.format(prefix, self.relationInstance.relName, suffix))
        return myHTML
        
#    def calcLine(self, ):
#        '''calculate the points on the two ellipses to draw a straight line through their centers'''
#        self.startNodeX = self.startNode.INode.sceneBoundingRect().center().x()
#        self.startNodeY = self.startNode.INode.sceneBoundingRect().center().y()
#        self.endNodeX = self.endNode.INode.sceneBoundingRect().center().x()
#        self.endNodeY = self.endNode.INode.sceneBoundingRect().center().y()   
#        
#        self.distanceX = abs(self.startNodeX - self.endNodeX) + .001
#        self.distanceY = abs(self.startNodeY - self.endNodeY) + .001
#        temp = (pow(self.distanceX,2) + pow(self.distanceY,2)) - (2 * self.distanceX * self.distanceY * cos(radians(90)))
#        self.distanceXY = sqrt(temp)
#        a = self.distanceX
#        b = self.distanceY
#        c = self.distanceXY
##        angA = angle(a,b,c)
##        angB = angle(b,c,a)
#        angC = angleDegrees(c,a,b)
#        
#        if self.endNodeX == self.startNodeX:
#            self.endNodeX = self.endNodeX + .001
#        if self.endNodeY == self.startNodeY:
#            self.endNodeY = self.endNodeY + .001
#        
#        if self.endNodeX > self.startNodeX and self.endNodeY > self.startNodeY:
#                startangle = angC
#                endangle = 180 + angC
#        elif self.endNodeX < self.startNodeX and self.endNodeY > self.startNodeY:
#                startangle = 180 - angC
#                endangle = 360 - angC
#        elif self.endNodeX < self.startNodeX and self.endNodeY < self.startNodeY:
#                startangle = 180 + angC
#                endangle = angC
#        elif self.endNodeX > self.startNodeX and self.endNodeY < self.startNodeY:
#                startangle = 360 - angC
#                endangle = 180 - angC
#                
#        #print("angA: {} angleB: {} angleC: {} startangle: {}".format(angA, angB, angC, startangle))
#        aa = self.startNode.INode.boundingRect().width()/2.0
#        bb = self.startNode.INode.boundingRect().height()/2.0        
#        sn = Ellipse(self.startNodeX, self.startNodeY, aa, bb)
#        sx, sy = sn.pointFromAngle(radians(startangle))
#        cc = self.endNode.INode.boundingRect().width()/2.0
#        dd = self.endNode.INode.boundingRect().height()/2.0                
#        en = Ellipse(self.endNodeX, self.endNodeY, cc, dd)  #need to calc width/height of end node.
#        ex, ey = en.pointFromAngle(radians(endangle))
#        #print("sx {} - sy {} - ex {} - ey {}".format(sx,sy,ex,sy))
#        return sx, sy, ex, ey

    def calcLine2(self, ):
        '''calculate the point on the start and end node ellipse for an arc
        '''
        # get centerpoints of the two nodes
        self.startNodeX = self.startNode.INode.sceneBoundingRect().center().x()
        self.startNodeY = self.startNode.INode.sceneBoundingRect().center().y()
        self.endNodeX = self.endNode.INode.sceneBoundingRect().center().x()
        self.endNodeY = self.endNode.INode.sceneBoundingRect().center().y()   
        
        self.distanceX = abs(self.startNodeX - self.endNodeX) + .001
        self.distanceY = abs(self.startNodeY - self.endNodeY) + .001
        temp = (pow(self.distanceX,2) + pow(self.distanceY,2)) - (2 * self.distanceX * self.distanceY * cos(radians(90)))
        self.distanceXY = sqrt(temp)
        a = self.distanceX
        b = self.distanceY
        c = self.distanceXY
#        angA = angle(a,b,c)
#        angB = angle(b,c,a)
        angC = angleDegrees(c,a,b)
#        print("angC {}".format(angC))
        
        if self.endNodeX == self.startNodeX:
            self.endNodeX = self.endNodeX + .001
        if self.endNodeY == self.startNodeY:
            self.endNodeY = self.endNodeY + .001
        
        # adjust starting and ending points based on the number of rels between the node, if more than 7 in the same direction just start stacking them one on top of the other.
        if self.numRels > 6:
            adjustDegree = (7) * 10
        else:
            adjustDegree = (self.numRels+1) * 10
            
        if self.endNodeX > self.startNodeX and self.endNodeY > self.startNodeY:
                startangle = angC - adjustDegree
                endangle = 180 + angC + adjustDegree
        elif self.endNodeX < self.startNodeX and self.endNodeY > self.startNodeY:
                startangle = 180 - angC - adjustDegree
                endangle = 360 - angC + adjustDegree
        elif self.endNodeX < self.startNodeX and self.endNodeY < self.startNodeY:
                startangle = 180 + angC - adjustDegree
                endangle = angC + adjustDegree
        elif self.endNodeX > self.startNodeX and self.endNodeY < self.startNodeY:
                startangle = 360 - angC - adjustDegree
                endangle = 180 - angC + adjustDegree
                
#        print("adjust: {}startangle: {} endangle: {}".format(adjustDegree, startangle, endangle))
        aa = self.startNode.INode.boundingRect().width()/2.0
        bb = self.startNode.INode.boundingRect().height()/2.0        
        sn = Ellipse(self.startNodeX, self.startNodeY, aa, bb)
        sx, sy = sn.pointFromAngle(radians(startangle))
        cc = self.endNode.INode.boundingRect().width()/2.0
        dd = self.endNode.INode.boundingRect().height()/2.0                
        en = Ellipse(self.endNodeX, self.endNodeY, cc, dd)  #need to calc width/height of end node.
        ex, ey = en.pointFromAngle(radians(endangle))
        #print("sx {} - sy {} - ex {} - ey {}".format(sx,sy,ex,sy))
        return sx, sy, ex, ey
        
    def calcLine3(self, ):
        '''calculate the point on the start and end node ellipse for a straight line
        '''
        # get centerpoints of the two nodes
        self.startNodeX = self.startNode.INode.sceneBoundingRect().center().x()
        self.startNodeY = self.startNode.INode.sceneBoundingRect().center().y()
        self.endNodeX = self.endNode.INode.sceneBoundingRect().center().x()
        self.endNodeY = self.endNode.INode.sceneBoundingRect().center().y()   
        
        self.distanceX = abs(self.startNodeX - self.endNodeX) + .001
        self.distanceY = abs(self.startNodeY - self.endNodeY) + .001
        temp = (pow(self.distanceX,2) + pow(self.distanceY,2)) - (2 * self.distanceX * self.distanceY * cos(radians(90)))
        self.distanceXY = sqrt(temp)
        a = self.distanceX
        b = self.distanceY
        c = self.distanceXY
#        angA = angle(a,b,c)
#        angB = angle(b,c,a)
        angC = angleDegrees(c,a,b)
#        print("angC {}".format(angC))
        
        if self.endNodeX == self.startNodeX:
            self.endNodeX = self.endNodeX + .001
        if self.endNodeY == self.startNodeY:
            self.endNodeY = self.endNodeY + .001
        
#        # adjust starting and ending points based on the number of rels between the node, if more than 7 in the same direction just start stacking them one on top of the other.
#        if self.numRels > 6:
#            adjustDegree = (7) * 10
#        else:
#            adjustDegree = (self.numRels+1) * 10

        adjustDegree = 0    
        if self.endNodeX > self.startNodeX and self.endNodeY > self.startNodeY:
                startangle = angC - adjustDegree
                endangle = 180 + angC + adjustDegree
        elif self.endNodeX < self.startNodeX and self.endNodeY > self.startNodeY:
                startangle = 180 - angC - adjustDegree
                endangle = 360 - angC + adjustDegree
        elif self.endNodeX < self.startNodeX and self.endNodeY < self.startNodeY:
                startangle = 180 + angC - adjustDegree
                endangle = angC + adjustDegree
        elif self.endNodeX > self.startNodeX and self.endNodeY < self.startNodeY:
                startangle = 360 - angC - adjustDegree
                endangle = 180 - angC + adjustDegree
                
#        print("adjust: {}startangle: {} endangle: {}".format(adjustDegree, startangle, endangle))
        aa = self.startNode.INode.boundingRect().width()/2.0
        bb = self.startNode.INode.boundingRect().height()/2.0        
        sn = Ellipse(self.startNodeX, self.startNodeY, aa, bb)
        sx, sy = sn.pointFromAngle(radians(startangle))
        cc = self.endNode.INode.boundingRect().width()/2.0
        dd = self.endNode.INode.boundingRect().height()/2.0                
        en = Ellipse(self.endNodeX, self.endNodeY, cc, dd)  #need to calc width/height of end node.
        ex, ey = en.pointFromAngle(radians(endangle))
        #print("sx {} - sy {} - ex {} - ey {}".format(sx,sy,ex,sy))
        return sx, sy, ex, ey
                
#    def moveRelationshipLine(self, ):
#        self.drawRelationship()

    def getObjectDict(self, ):
        objectDict = {}
        objectDict["NZID"] = self.relationInstance.NZID
        objectDict["diagramType"] = self.diagramType
        return objectDict
예제 #12
0
class EdgeItem(GraphItem):

    _qt_pen_styles = {
        'dashed': Qt.DashLine,
        'dotted': Qt.DotLine,
        'solid': Qt.SolidLine,
    }

    def __init__(self,
                 highlight_level,
                 spline,
                 label_center,
                 label,
                 from_node,
                 to_node,
                 parent=None,
                 penwidth=1,
                 edge_color=None,
                 style='solid'):
        super(EdgeItem, self).__init__(highlight_level, parent)

        self.from_node = from_node
        self.from_node.add_outgoing_edge(self)
        self.to_node = to_node
        self.to_node.add_incoming_edge(self)

        self._default_edge_color = self._COLOR_BLACK
        if edge_color is not None:
            self._default_edge_color = edge_color

        self._default_text_color = self._COLOR_BLACK
        self._default_color = self._COLOR_BLACK
        self._text_brush = QBrush(self._default_color)
        self._shape_brush = QBrush(self._default_color)
        if style in ['dashed', 'dotted']:
            self._shape_brush = QBrush(Qt.transparent)
        self._label_pen = QPen()
        self._label_pen.setColor(self._default_text_color)
        self._label_pen.setJoinStyle(Qt.RoundJoin)
        self._edge_pen = QPen(self._label_pen)
        self._edge_pen.setWidth(penwidth)
        self._edge_pen.setColor(self._default_edge_color)
        self._edge_pen.setStyle(self._qt_pen_styles.get(style, Qt.SolidLine))

        self._sibling_edges = set()

        self._label = None
        if label is not None:
            self._label = QGraphicsSimpleTextItem(label)
            self._label.setFont(GraphItem._LABEL_FONT)
            label_rect = self._label.boundingRect()
            label_rect.moveCenter(label_center)
            self._label.setPos(label_rect.x(), label_rect.y())
            self._label.hoverEnterEvent = self._handle_hoverEnterEvent
            self._label.hoverLeaveEvent = self._handle_hoverLeaveEvent
            self._label.setAcceptHoverEvents(True)

        # spline specification according to
        # http://www.graphviz.org/doc/info/attrs.html#k:splineType
        coordinates = spline.split(' ')
        # extract optional end_point
        end_point = None
        if (coordinates[0].startswith('e,')):
            parts = coordinates.pop(0)[2:].split(',')
            end_point = QPointF(float(parts[0]), -float(parts[1]))
        # extract optional start_point
        if (coordinates[0].startswith('s,')):
            parts = coordinates.pop(0).split(',')

        # first point
        parts = coordinates.pop(0).split(',')
        point = QPointF(float(parts[0]), -float(parts[1]))
        path = QPainterPath(point)

        while len(coordinates) > 2:
            # extract triple of points for a cubic spline
            parts = coordinates.pop(0).split(',')
            point1 = QPointF(float(parts[0]), -float(parts[1]))
            parts = coordinates.pop(0).split(',')
            point2 = QPointF(float(parts[0]), -float(parts[1]))
            parts = coordinates.pop(0).split(',')
            point3 = QPointF(float(parts[0]), -float(parts[1]))
            path.cubicTo(point1, point2, point3)

        self._arrow = None
        if end_point is not None:
            # draw arrow
            self._arrow = QGraphicsPolygonItem()
            polygon = QPolygonF()
            polygon.append(point3)
            offset = QPointF(end_point - point3)
            corner1 = QPointF(-offset.y(), offset.x()) * 0.35
            corner2 = QPointF(offset.y(), -offset.x()) * 0.35
            polygon.append(point3 + corner1)
            polygon.append(end_point)
            polygon.append(point3 + corner2)
            self._arrow.setPolygon(polygon)
            self._arrow.hoverEnterEvent = self._handle_hoverEnterEvent
            self._arrow.hoverLeaveEvent = self._handle_hoverLeaveEvent
            self._arrow.setAcceptHoverEvents(True)

        self._path = QGraphicsPathItem(parent)
        self._path.setPath(path)
        self.addToGroup(self._path)

        self.set_node_color()
        self.set_label_color()

    def add_to_scene(self, scene):
        scene.addItem(self)
        if self._label is not None:
            scene.addItem(self._label)
        if self._arrow is not None:
            scene.addItem(self._arrow)

    def setToolTip(self, tool_tip):
        super(EdgeItem, self).setToolTip(tool_tip)
        if self._label is not None:
            self._label.setToolTip(tool_tip)
        if self._arrow is not None:
            self._arrow.setToolTip(tool_tip)

    def add_sibling_edge(self, edge):
        self._sibling_edges.add(edge)

    def set_node_color(self, color=None):
        if color is None:
            self._label_pen.setColor(self._default_text_color)
            self._text_brush.setColor(self._default_color)
            if self._shape_brush.isOpaque():
                self._shape_brush.setColor(self._default_edge_color)
            self._edge_pen.setColor(self._default_edge_color)
        else:
            self._label_pen.setColor(color)
            self._text_brush.setColor(color)
            if self._shape_brush.isOpaque():
                self._shape_brush.setColor(color)
            self._edge_pen.setColor(color)

        self._path.setPen(self._edge_pen)
        if self._arrow is not None:
            self._arrow.setBrush(self._shape_brush)
            self._arrow.setPen(self._edge_pen)

    def set_label_color(self, color=None):
        if color is None:
            self._label_pen.setColor(self._default_text_color)
        else:
            self._label_pen.setColor(color)

        if self._label is not None:
            self._label.setBrush(self._text_brush)
            self._label.setPen(self._label_pen)

    def _handle_hoverEnterEvent(self, event):
        # hovered edge item in red
        self.set_node_color(self._COLOR_RED)
        self.set_label_color(self._COLOR_RED)

        if self._highlight_level > 1:
            if self.from_node != self.to_node:
                # from-node in blue
                self.from_node.set_node_color(self._COLOR_BLUE)
                # to-node in green
                self.to_node.set_node_color(self._COLOR_GREEN)
            else:
                # from-node/in-node in teal
                self.from_node.set_node_color(self._COLOR_TEAL)
                self.to_node.set_node_color(self._COLOR_TEAL)
        if self._highlight_level > 2:
            # sibling edges in orange
            for sibling_edge in self._sibling_edges:
                sibling_edge.set_node_color(self._COLOR_ORANGE)

    def _handle_hoverLeaveEvent(self, event):
        self.set_node_color()
        self.set_label_color()
        if self._highlight_level > 1:
            self.from_node.set_node_color()
            self.to_node.set_node_color()
        if self._highlight_level > 2:
            for sibling_edge in self._sibling_edges:
                sibling_edge.set_node_color()
예제 #13
0
class MorphingApp(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MorphingApp, self).__init__(parent)
        self.setupUi(self)
        self.btnBlend.setEnabled(False)
        self.chkTriangles.setEnabled(False)
        self.sliderAlpha.setEnabled(False)
        self.startSetImg = QGraphicsScene()
        self.endSetImg = QGraphicsScene()
        self.Morpher = QGraphicsScene()
        self.initialPoints = False
        self.addPoints = False
        self.comfirm = False
        #       QGraphicsScene()

        # self.leftImg =
        #self.rightImg =
        self.state = "first_state"
        self.gfxLeft.setScene(self.startSetImg)
        self.gfxRight.setScene(self.endSetImg)
        self.gfxBlendImg.setScene(self.Morpher)
        self.btnStartImg.clicked.connect(self.loadLeftImage)
        self.btnEndImg.clicked.connect(self.loadRightImage)
        self.sliderAlpha.valueChanged.connect(self.setAlpha)
        self.chkTriangles.stateChanged.connect(self.triangulation)
        self.btnBlend.clicked.connect(self.getImageAtAlpha)
        self.gfxLeft.mousePressEvent = self.setLeftPoints
        self.gfxRight.mousePressEvent = self.setRightPoints
        self.centralwidget.mousePressEvent = self.secondWaySave
        self.keyPressEvent = self.BackSpace
        #self.retriangulation()

    def loadLeftImage(self):
        """
        *** DO NOT MODIFY THIS METHOD! ***
        Obtain a file name from a file dialog, and pass it on to the loading method. This is to facilitate automated
        testing. Invoke this method when clicking on the 'load' button.

        You must modify the method below.
        """
        self.filePath, _ = QFileDialog.getOpenFileName(
            self, caption='Open JPG file ...', filter="Image (*.jpg *.png)")

        if not self.filePath:
            return
        self.startImage = imageio.imread(self.filePath)
        self.startSetImg.clear()
        self.startSetImg.addPixmap(QPixmap(self.filePath))
        self.gfxLeft.fitInView(self.startSetImg.itemsBoundingRect(),
                               QtCore.Qt.KeepAspectRatio)
        self.LeftimgPoints = self.filePath + '.txt'
        try:
            fh = open(self.LeftimgPoints, 'r')
            redPen = QPen(QtCore.Qt.red)
            redBrush = QBrush(QtCore.Qt.red)
            self.leftPoints = np.loadtxt(self.LeftimgPoints)
            self.initialPoints = True
            for x, y in self.leftPoints:
                self.startSetImg.addEllipse(x, y, 20, 20, redPen, redBrush)
        except FileNotFoundError:
            open(self.LeftimgPoints, 'w').close()
            self.initialPoints = False
            self.addPoints = False

    def loadRightImage(self):
        """
        *** DO NOT MODIFY THIS METHOD! ***
        Obtain a file name from a file dialog, and pass it on to the loading method. This is to facilitate automated
        testing. Invoke this method when clicking on the 'load' button.

        You must modify the method below.
        """
        self.filePath1, _ = QFileDialog.getOpenFileName(
            self, caption='Open JPG file ...', filter="Image (*.jpg *.png)")

        if not self.filePath1:
            return
        self.endImage = imageio.imread(self.filePath1)
        self.endSetImg.clear()
        self.endSetImg.addPixmap(QPixmap(self.filePath1))
        self.gfxRight.fitInView(self.endSetImg.itemsBoundingRect(),
                                QtCore.Qt.KeepAspectRatio)
        self.btnBlend.setEnabled(True)
        self.chkTriangles.setEnabled(True)
        self.sliderAlpha.setEnabled(True)
        self.txtAlpha.setEnabled(True)

        #load point correspondence
        self.RightimgPoints = self.filePath1 + '.txt'
        try:
            fh = open(self.RightimgPoints, 'r')
            self.rightPoints = np.loadtxt(self.RightimgPoints)
            redPen = QPen(QtCore.Qt.red)
            print(self.rightPoints)
            redBrush = QBrush(QtCore.Qt.red)
            self.initialPoints = True
            for x, y in self.rightPoints:
                self.endSetImg.addEllipse(x, y, 20, 20, redPen, redBrush)
        except FileNotFoundError:
            open(self.RightimgPoints, 'w').close()
            self.initialPoints = False
            self.addPoints = False

    def setAlpha(self):
        self.txtAlpha.setText(str(self.sliderAlpha.value() / 20.0))

    def retriangulation(self):
        if self.state == "right_set":
            if self.chkTriangles.isChecked():
                self.chkTriangles.setChecked(False)
                self.chkTriangles.setChecked(True)

    def triangulation(self):
        if self.chkTriangles.isChecked() == True:
            self.tri1 = []
            self.tri2 = []
            self.leftSimplices = Delaunay(self.leftPoints).simplices
            if self.initialPoints == True and self.addPoints == True:
                Pen = QPen(QtCore.Qt.cyan)
                print(1)
            elif self.addPoints == True:
                Pen = QPen(QtCore.Qt.blue)
                print(2)
            else:
                Pen = QPen(QtCore.Qt.red)
            for triangle in self.leftSimplices.tolist():
                #TriLeft = self.leftPoints[triangle]
                #TriRight = self.rightPoints[triangle]
                #leftTriangles.append(Tri)
                # print(self.leftPoints[triangle])
                #print(self.leftPoints[triangle[0]])

                pointA = QtCore.QPointF(self.leftPoints[triangle[0]][0],
                                        self.leftPoints[triangle[0]][1])
                PointB = QtCore.QPointF(self.leftPoints[triangle[1]][0],
                                        self.leftPoints[triangle[1]][1])
                PointC = QtCore.QPointF(self.leftPoints[triangle[2]][0],
                                        self.leftPoints[triangle[2]][1])
                self.drawTriangle = QtGui.QPolygonF([pointA, PointB, PointC])
                self.tri1Item = QGraphicsPolygonItem(self.drawTriangle)
                self.tri1Item.setPen(Pen)
                self.startSetImg.addItem(self.tri1Item)

                self.tri1.append(self.tri1Item)

                pointAA = QtCore.QPointF(self.rightPoints[triangle[0]][0],
                                         self.rightPoints[triangle[0]][1])
                PointBB = QtCore.QPointF(self.rightPoints[triangle[1]][0],
                                         self.rightPoints[triangle[1]][1])
                PointCC = QtCore.QPointF(self.rightPoints[triangle[2]][0],
                                         self.rightPoints[triangle[2]][1])
                self.drawTriangle1 = QtGui.QPolygonF(
                    [pointAA, PointBB, PointCC])
                self.tri2Item = QGraphicsPolygonItem(self.drawTriangle1)
                self.tri2Item.setPen(Pen)
                self.endSetImg.addItem(self.tri2Item)
                self.tri2.append(self.tri2Item)

        else:
            #print("111111111")
            for item1 in self.tri1:
                self.startSetImg.removeItem(item1)
            for item2 in self.tri2:
                self.endSetImg.removeItem(item2)

    def getImageAtAlpha(self):
        triangleTuple = loadTriangles(self.filePath + '.txt',
                                      self.filePath1 + '.txt')
        #img = Morpher(leftImage, triangleTuple[0], rightImage, triangleTuple[1]).getImageAtAlpha()

        alpha = self.sliderAlpha.value()
        img = Morpher(self.startImage, triangleTuple[0], self.endImage,
                      triangleTuple[1]).getImageAtAlpha(alpha / 20.0)
        imgQt = QImage(ImageQt.ImageQt(Image.fromarray(img)))
        result = QPixmap.fromImage(imgQt)
        self.Morpher.addPixmap(result)
        self.gfxBlendImg.fitInView(self.Morpher.itemsBoundingRect(),
                                   QtCore.Qt.KeepAspectRatio)

    def secondWaySave(self, e):
        if self.state == "right_set":
            self.comfirmPoints()
            self.state = "first_state"

    def setLeftPoints(self, e):
        if self.state == "first_state":
            ## if it contains points already
            self.leftPoint = self.gfxLeft.mapToScene(e.pos())
            greenPen = QPen(QtCore.Qt.green)
            greenBrush = QBrush(QtCore.Qt.green)
            self.leftPointItem = QGraphicsEllipseItem(self.leftPoint.x(),
                                                      self.leftPoint.y(), 20,
                                                      20)
            self.leftPointItem.setPen(greenPen)
            self.leftPointItem.setBrush(greenBrush)
            self.startSetImg.addItem(self.leftPointItem)
            self.state = "left_set"
        elif self.state == "right_set":
            self.comfirmPoints()
            ## if it contains points already
            self.leftPoint = self.gfxLeft.mapToScene(e.pos())
            greenPen = QPen(QtCore.Qt.green)
            greenBrush = QBrush(QtCore.Qt.green)
            self.leftPointItem = QGraphicsEllipseItem(self.leftPoint.x(),
                                                      self.leftPoint.y(), 20,
                                                      20)
            self.leftPointItem.setPen(greenPen)
            self.leftPointItem.setBrush(greenBrush)
            self.startSetImg.addItem(self.leftPointItem)
            self.state = "left_set"

    def setRightPoints(self, e):
        if self.state == "left_set":
            ## if it contains points already
            self.rightPoint = self.gfxRight.mapToScene(e.pos())
            greenPen = QPen(QtCore.Qt.green)
            greenBrush = QBrush(QtCore.Qt.green)
            self.rightPointItem = QGraphicsEllipseItem(self.rightPoint.x(),
                                                       self.rightPoint.y(), 20,
                                                       20)
            self.rightPointItem.setPen(greenPen)
            self.rightPointItem.setBrush(greenBrush)
            self.endSetImg.addItem(self.rightPointItem)
            self.state = "right_set"

    def comfirmPoints(self):
        #print(123)
        self.addPoints = True
        self.comfirm = True
        bluePen = QPen(QtCore.Qt.blue)
        blueBrush = QBrush(QtCore.Qt.blue)
        self.startSetImg.removeItem(self.leftPointItem)
        self.endSetImg.removeItem(self.rightPointItem)
        self.leftPointItem.setPen(bluePen)
        self.leftPointItem.setBrush(blueBrush)
        self.rightPointItem.setPen(bluePen)
        self.rightPointItem.setBrush(blueBrush)
        self.endSetImg.addItem(self.rightPointItem)
        self.startSetImg.addItem(self.leftPointItem)

        if os.stat(self.LeftimgPoints).st_size == 0 and os.stat(
                self.RightimgPoints).st_size == 0:
            self.leftPoints = np.array(
                [[self.leftPoint.x(), self.leftPoint.y()]])
            self.rightPoints = np.array(
                [[self.rightPoint.x(),
                  self.rightPoint.y()]])
        else:
            self.leftPoints = np.vstack(
                (self.leftPoints, [self.leftPoint.x(),
                                   self.leftPoint.y()]))
            #self.leftPoints.append([self.leftPoint.x(), self.leftPoint.y()])
            #self.rightPoints.append([self.rightPoint.x(), self.rightPoint.y()])
            self.rightPoints = np.vstack(
                (self.rightPoints, [self.rightPoint.x(),
                                    self.rightPoint.y()]))
        self.retriangulation()
        with open(self.filePath + '.txt', "w") as fin:
            for point in self.leftPoints.tolist():
                fin.write(
                    str((round(point[0], 1))) + '     ' +
                    str((round(point[1], 1))) + '\n')
        with open(self.filePath1 + '.txt', "w") as fin1:
            for point in self.rightPoints.tolist():
                fin1.write(
                    str((round(point[0], 1))) + '     ' +
                    str((round(point[1], 1))) + '\n')

    def BackSpace(self, e):
        key = e.key()
        if key == QtCore.Qt.Key_Backspace:

            if self.state == "left_set":
                self.startSetImg.removeItem(self.leftPointItem)
                self.state = "first_state"
            elif self.state == "right_set":
                self.endSetImg.removeItem(self.rightPointItem)
                self.state = "left_set"
예제 #14
0
class ASCGraphicsView(QGraphicsView):
    scale_signal = pyqtSignal('float', 'float')
    set_focus_point_signal = pyqtSignal('int', 'int', 'int')
    set_focus_point_percent_signal = pyqtSignal('float', 'float', 'float')
    move_focus_point_signal = pyqtSignal('int', 'int', 'int')
    # x, y, z, BRUSH_TYPE, BRUSH_SIZE, ERASE
    paint_anno_on_point_signal = pyqtSignal('int', 'int', 'int', 'int', 'int',
                                            'bool', 'bool')

    def __init__(self, parent=None):
        super(ASCGraphicsView, self).__init__(parent)
        self.scene = QGraphicsScene(self)

        self.raw_img_item = QGraphicsPixmapItem()
        self.raw_img_item.setZValue(0)
        self.anno_img_item = QGraphicsPixmapItem()
        self.anno_img_item.setZValue(1)

        self.cross_bar_v_line_item = QGraphicsLineItem()
        self.cross_bar_h_line_item = QGraphicsLineItem()
        self.cross_bar_v_line_item.setZValue(100)
        self.cross_bar_h_line_item.setZValue(100)
        self.cross_bar_v_line_item.setPen(
            QPen(Qt.blue, 0, Qt.DotLine, Qt.FlatCap, Qt.RoundJoin))
        self.cross_bar_h_line_item.setPen(
            QPen(Qt.blue, 0, Qt.DotLine, Qt.FlatCap, Qt.RoundJoin))

        self.paint_brush_circle_item = QGraphicsEllipseItem()
        self.paint_brush_rect_item = QGraphicsPolygonItem()
        self.paint_brush_circle_item.setZValue(10)
        self.paint_brush_rect_item.setZValue(11)
        self.paint_brush_circle_item.setVisible(False)
        self.paint_brush_rect_item.setVisible(False)
        self.paint_brush_circle_item.setPen(
            QPen(Qt.red, 0, Qt.DotLine, Qt.FlatCap, Qt.RoundJoin))
        self.paint_brush_rect_item.setPen(
            QPen(Qt.red, 0, Qt.DotLine, Qt.FlatCap, Qt.RoundJoin))

        self.scene.addItem(self.raw_img_item)
        self.scene.addItem(self.anno_img_item)
        self.scene.addItem(self.cross_bar_v_line_item)
        self.scene.addItem(self.cross_bar_h_line_item)
        self.scene.addItem(self.paint_brush_circle_item)
        self.scene.addItem(self.paint_brush_rect_item)

        self.setScene(self.scene)
        self.setViewport(QOpenGLWidget())

        self._last_button_press = Qt.NoButton
        self._last_pos_middle_button = None
        self._last_pos_right_button = None

        self._brush_stats = {'type': BRUSH_TYPE_NO_BRUSH, 'size': 5}

        self.setResizeAnchor(QGraphicsView.AnchorViewCenter)

        self.slice_scroll_bar = None
        self.image_size = None
        self.is_valid = False

    def clear(self):
        """before loading new image"""
        self._last_pos_middle_button = None
        self._last_pos_right_button = None
        self._last_button_press = Qt.NoButton
        self.raw_img_item.setPixmap(QPixmap())
        self.anno_img_item.setPixmap(QPixmap())
        self.paint_brush_circle_item.setVisible(False)
        self.paint_brush_rect_item.setVisible(False)
        self.image_size = None
        self.is_valid = False

    def init_view(self, image_size):
        """after loading new image"""
        self.is_valid = True
        self.image_size = image_size
        self.slice_scroll_bar = self.parent().findChild(
            QScrollBar,
            self.objectName()[0] + 'SliceScrollBar')

        trans_mat = item2scene_transform[self.objectName()[0]]
        self.raw_img_item.setTransform(trans_mat)
        self.anno_img_item.setTransform(trans_mat)
        self.cross_bar_v_line_item.setTransform(trans_mat)
        self.cross_bar_h_line_item.setTransform(trans_mat)
        self.paint_brush_rect_item.setTransform(trans_mat)
        self.paint_brush_circle_item.setTransform(trans_mat)

        self.fitInView(self.raw_img_item, Qt.KeepAspectRatio)
        self.paint_brush_circle_item.setVisible(False)
        self.paint_brush_rect_item.setVisible(False)

    @property
    def brush_stats(self):
        return self._brush_stats

    @brush_stats.setter
    def brush_stats(self, stats_tuple):
        b_type, size = stats_tuple
        if b_type in [
                BRUSH_TYPE_NO_BRUSH, BRUSH_TYPE_CIRCLE_BRUSH,
                BRUSH_TYPE_RECT_BRUSH
        ]:
            self._brush_stats['type'] = b_type
            self._brush_stats['size'] = size
        if b_type != BRUSH_TYPE_NO_BRUSH:
            self.setMouseTracking(True)
        else:
            self.setMouseTracking(False)

    def update_brush_preview(self, x, y, out_of_sight=False):
        if not self.is_valid or self.brush_stats[
                'type'] == BRUSH_TYPE_NO_BRUSH or out_of_sight:
            self.paint_brush_rect_item.setVisible(False)
            self.paint_brush_circle_item.setVisible(False)
            return

        center = self.anno_img_item.mapFromScene(self.mapToScene(x, y))

        start_x = self.raw_img_item.boundingRect().topLeft().x()
        start_y = self.raw_img_item.boundingRect().topLeft().y()
        end_x = self.raw_img_item.boundingRect().bottomRight().x()
        end_y = self.raw_img_item.boundingRect().bottomRight().y()
        center.setX(min(max(start_x, center.x()), end_x) + 0.5)
        center.setY(min(max(start_y, center.y()), end_y) + 0.5)
        top_left_x = int(center.x() - self.brush_stats['size'] / 2)
        top_left_y = int(center.y() - self.brush_stats['size'] / 2)
        rect = QRectF(top_left_x, top_left_y, self.brush_stats['size'],
                      self.brush_stats['size'])
        if self.brush_stats['type'] == BRUSH_TYPE_CIRCLE_BRUSH:
            self.paint_brush_rect_item.setVisible(False)
            self.paint_brush_circle_item.setVisible(True)
            self.paint_brush_circle_item.setRect(rect)
        if self.brush_stats['type'] == BRUSH_TYPE_RECT_BRUSH:
            self.paint_brush_rect_item.setVisible(True)
            self.paint_brush_circle_item.setVisible(False)
            self.paint_brush_rect_item.setPolygon(QPolygonF(rect))

    def anno_paint(self, x, y, erase=False, new_step=False):
        pos_on_item = self.raw_img_item.mapFromScene(self.mapToScene(x, y))
        if self.objectName() == 'aGraphicsView':
            paint_point = [pos_on_item.y(), pos_on_item.x(), 999999]
        if self.objectName() == 'sGraphicsView':
            paint_point = [999999, pos_on_item.y(), pos_on_item.x()]
        if self.objectName() == 'cGraphicsView':
            paint_point = [pos_on_item.y(), 999999, pos_on_item.x()]
        self.paint_anno_on_point_signal.emit(math.floor(paint_point[0]),
                                             math.floor(paint_point[1]),
                                             math.floor(paint_point[2]),
                                             self.brush_stats['type'],
                                             self.brush_stats['size'], erase,
                                             new_step)

    @pyqtSlot('int')
    def on_slice_scroll_bar_changed(self, value):
        if not self.is_valid:
            return
        ratios = [-1, -1, -1]
        ratio = (value - self.slice_scroll_bar.minimum()) / \
                (self.slice_scroll_bar.maximum() - self.slice_scroll_bar.minimum())
        if self.objectName() == 'aGraphicsView':
            ratios[2] = ratio
        if self.objectName() == 'sGraphicsView':
            ratios[0] = ratio
        if self.objectName() == 'cGraphicsView':
            ratios[1] = ratio
        self.set_focus_point_percent_signal.emit(ratios[0], ratios[1],
                                                 ratios[2])

    @pyqtSlot('int', 'int')
    def set_brush_stats(self, b_type, size):
        self.brush_stats = [b_type, size]

    @pyqtSlot('int', 'int', 'int')
    def set_cross_bar(self, x, y, z):
        if self.objectName() == 'aGraphicsView':
            cross_bar_x = y
            cross_bar_y = x
            slice_bar_ratio = z / self.image_size[2]
        if self.objectName() == 'sGraphicsView':
            cross_bar_x = z
            cross_bar_y = y
            slice_bar_ratio = x / self.image_size[0]
        if self.objectName() == 'cGraphicsView':
            cross_bar_x = z
            cross_bar_y = x
            slice_bar_ratio = y / self.image_size[1]
        # cross line in voxel center
        cross_bar_x = cross_bar_x + 0.5
        cross_bar_y = cross_bar_y + 0.5
        start_x = self.raw_img_item.boundingRect().topLeft().x()
        start_y = self.raw_img_item.boundingRect().topLeft().y()
        end_x = self.raw_img_item.boundingRect().bottomRight().x()
        end_y = self.raw_img_item.boundingRect().bottomRight().y()
        self.cross_bar_v_line_item.setLine(cross_bar_x, start_y, cross_bar_x,
                                           end_y)
        self.cross_bar_h_line_item.setLine(start_x, cross_bar_y, end_x,
                                           cross_bar_y)

        slice_bar_value = round(slice_bar_ratio * (self.slice_scroll_bar.maximum() - self.slice_scroll_bar.minimum())) \
                          + self.slice_scroll_bar.minimum()
        self.slice_scroll_bar.setValue(slice_bar_value)

    def mousePressEvent(self, event: QtGui.QMouseEvent):
        self._last_button_press = event.button()

        if self.brush_stats['type'] == BRUSH_TYPE_NO_BRUSH:
            if event.button() == Qt.LeftButton:
                item_coord_pos = self.raw_img_item.mapFromScene(
                    self.mapToScene(event.pos()))
                if self.objectName() == 'aGraphicsView':
                    new_focus_point = [
                        item_coord_pos.y(),
                        item_coord_pos.x(), 999999
                    ]
                if self.objectName() == 'sGraphicsView':
                    new_focus_point = [
                        999999, item_coord_pos.y(),
                        item_coord_pos.x()
                    ]
                if self.objectName() == 'cGraphicsView':
                    new_focus_point = [
                        item_coord_pos.y(), 999999,
                        item_coord_pos.x()
                    ]
                self.set_focus_point_signal.emit(
                    math.floor(new_focus_point[0]),
                    math.floor(new_focus_point[1]),
                    math.floor(new_focus_point[2]))
            elif event.button() == Qt.MiddleButton:
                self._last_pos_middle_button = event.pos()
                self.setCursor(Qt.ClosedHandCursor)
            elif event.button() == Qt.RightButton:
                self._last_pos_right_button = event.pos()
            else:
                super(ASCGraphicsView, self).mousePressEvent(event)
        if self.brush_stats['type'] in [
                BRUSH_TYPE_CIRCLE_BRUSH, BRUSH_TYPE_RECT_BRUSH
        ]:
            if event.button() == Qt.LeftButton:
                self.anno_paint(event.x(),
                                event.y(),
                                erase=False,
                                new_step=True)
            elif event.button() == Qt.MiddleButton:
                self._last_pos_middle_button = event.pos()
                self.setCursor(Qt.ClosedHandCursor)
            elif event.button() == Qt.RightButton:
                self.anno_paint(event.x(),
                                event.y(),
                                erase=True,
                                new_step=True)

    def mouseMoveEvent(self, event: QtGui.QMouseEvent):
        if self.brush_stats['type'] == BRUSH_TYPE_NO_BRUSH:
            if self._last_button_press == Qt.LeftButton:
                item_coord_pos = self.raw_img_item.mapFromScene(
                    self.mapToScene(event.pos()))
                if self.objectName() == 'aGraphicsView':
                    new_focus_point = [
                        item_coord_pos.y(),
                        item_coord_pos.x(), 999999
                    ]
                if self.objectName() == 'sGraphicsView':
                    new_focus_point = [
                        999999, item_coord_pos.y(),
                        item_coord_pos.x()
                    ]
                if self.objectName() == 'cGraphicsView':
                    new_focus_point = [
                        item_coord_pos.y(), 999999,
                        item_coord_pos.x()
                    ]
                self.set_focus_point_signal.emit(
                    math.floor(new_focus_point[0]),
                    math.floor(new_focus_point[1]),
                    math.floor(new_focus_point[2]))
            elif self._last_button_press == Qt.MiddleButton:
                delta_x = event.x() - self._last_pos_middle_button.x()
                delta_y = event.y() - self._last_pos_middle_button.y()
                self.horizontalScrollBar().setValue(
                    self.horizontalScrollBar().value() - delta_x)
                self.verticalScrollBar().setValue(
                    self.verticalScrollBar().value() - delta_y)
                self._last_pos_middle_button = event.pos()
            elif self._last_button_press == Qt.RightButton:
                delta = event.pos().y() - self._last_pos_right_button.y()
                scale = 1 - float(delta) / float(self.size().height())
                self.scale_signal.emit(scale, scale)
                self._last_pos_right_button = event.pos()
            else:
                super(ASCGraphicsView, self).mouseMoveEvent(event)
        if self.brush_stats['type'] in [
                BRUSH_TYPE_CIRCLE_BRUSH, BRUSH_TYPE_RECT_BRUSH
        ]:
            self.update_brush_preview(event.x(), event.y())
            if self._last_button_press == Qt.LeftButton:
                self.anno_paint(event.x(),
                                event.y(),
                                erase=False,
                                new_step=False)
            elif self._last_button_press == Qt.MiddleButton:
                delta_x = event.x() - self._last_pos_middle_button.x()
                delta_y = event.y() - self._last_pos_middle_button.y()
                self.horizontalScrollBar().setValue(
                    self.horizontalScrollBar().value() - delta_x)
                self.verticalScrollBar().setValue(
                    self.verticalScrollBar().value() - delta_y)
                self._last_pos_middle_button = event.pos()
            elif self._last_button_press == Qt.RightButton:
                self.anno_paint(event.x(),
                                event.y(),
                                erase=True,
                                new_step=False)

    def mouseReleaseEvent(self, event: QtGui.QMouseEvent):
        self._last_button_press = Qt.NoButton

        if self.brush_stats['type'] == BRUSH_TYPE_NO_BRUSH:
            if event.button() == Qt.MiddleButton:
                self.setCursor(Qt.ArrowCursor)
        if self.brush_stats['type'] in [
                BRUSH_TYPE_CIRCLE_BRUSH, BRUSH_TYPE_RECT_BRUSH
        ]:
            if event.button() == Qt.LeftButton:
                pass
            elif event.button() == Qt.RightButton:
                pass
        else:
            super(ASCGraphicsView, self).mouseReleaseEvent(event)

    def wheelEvent(self, event: QtGui.QWheelEvent):
        # super(ASCGraphicsView, self).wheelEvent(event)
        if self.objectName() == 'aGraphicsView':
            if event.angleDelta().y() > 0:
                self.move_focus_point_signal.emit(0, 0, -1)
            elif event.angleDelta().y() < 0:
                self.move_focus_point_signal.emit(0, 0, 1)
        if self.objectName() == 'sGraphicsView':
            if event.angleDelta().y() > 0:
                self.move_focus_point_signal.emit(-1, 0, 0)
            elif event.angleDelta().y() < 0:
                self.move_focus_point_signal.emit(1, 0, 0)
        if self.objectName() == 'cGraphicsView':
            if event.angleDelta().y() > 0:
                self.move_focus_point_signal.emit(0, -1, 0)
            elif event.angleDelta().y() < 0:
                self.move_focus_point_signal.emit(0, 1, 0)

    def leaveEvent(self, event: QtCore.QEvent):
        self._last_button_press = Qt.NoButton
        if self.brush_stats['type'] == BRUSH_TYPE_NO_BRUSH:
            super(ASCGraphicsView, self).leaveEvent(event)
        else:
            self.update_brush_preview(0, 0, out_of_sight=True)
예제 #15
0
class CallOut():
    ''' This represents a callouton the diagram
        This class creates a text item and then surrounds it with a polygon that is a rectangle
        with a pointer to another object on the diagram.
        This can be used by hover over functions or be displayed as a part of a node or relationship
        '''
    def __init__(self, scene, text, anchorPoint, diagramType, format):

        self.scene = scene
        self.model = self.scene.parent.model
        self.text = text
        self.anchorPoint = anchorPoint
        self.diagramType = diagramType
        self.format = format

        # initialize the two qgraphicsitems needed to draw a relationship to None
        self.itemText = None
        self.itemPolygon = None
        self.drawIt

    def name(self, ):
        return "no name"

    def NZID(self, ):
        return None

    def clearItem(self, ):

        if (not self.itemText is None and not self.itemText.scene() is None):
            self.itemText.scene().removeItem(self.itemText)
        if (not self.itemPolygon is None
                and not self.itemPolygon.scene() is None):
            self.itemPolygon.scene().removeItem(self.itemPolygon)

    def drawIt(self, ):
        '''
        draw the callout
        '''

        # if the polygon and text graphics items already exist on the scene then delete them
        self.clearItem()

        # draw the relationship arc
        pen = self.format.pen()
        brush = self.format.brush()

        # create text box
        # draw the text
        self.itemText = QGraphicsTextItem(self.relationInstance.relName,
                                          parent=None)
        self.itemText.setZValue(CALLOUTLAYER)
        self.itemText.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.itemText.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.itemText.setSelected(False)
        self.itemText.setData(NODEID, self.relationInstance.NZID)
        self.itemText.setData(ITEMTYPE, CALLOUT)
        self.itemText.setHtml(self.genTextHTML())
        # set the position of the text
        self.itemText.setPos(self.anchorPoint)

        # get the height and width of the text graphics item
        th = self.IRtext.boundingRect().height()
        tw = self.IRtext.boundingRect().width()

        #create an empty polygon
        arrowPolygon = QPolygonF()
        # add callout points
        arrowPolygon.append(self.anchorPoint)
        arrowPolygon.append(
            QPointF(self.anchorPoint.x() + tw, self.anchorPoint.y()))
        arrowPolygon.append(
            QPointF(self.anchorPoint.x() + tw, self.anchorPoint.y()))
        arrowPolygon.append(
            QPointF(self.anchorPoint.x() + tw,
                    self.anchorPoint.y() + th))
        arrowPolygon.append(
            QPointF(self.anchorPoint.x(),
                    self.anchorPoint.y() + th))
        self.itemPolygon = QGraphicsPolygonItem(
            arrowPolygon,
            parent=None,
        )
        self.itemPolygon.setZValue(CALLOUTLAYER)
        self.itemPolygon.setBrush(brush)
        self.itemPolygon.setPen(pen)
        self.itemPolygon.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.itemPolygon.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
        self.itemPolygon.setFlag(QGraphicsItem.ItemIsSelectable, False)
        self.itemPolygon.setSelected(False)

        # set data in the RelLine object
        self.IRel.setData(NODEID, self.relationInstance.NZID)
        self.IRel.setData(ITEMTYPE, RELINSTANCEARC)
        # add the polygon object to the scene
        self.scene.addItem(self.itemPolygon)
        # add text to the scene
        self.scene.addItem(self.itemText)

    def updateText(self, ):
        #        # force the node instance to update its values in case it has been updated from another diagram or the tree view
        #        self.relationInstance.reloadDictValues()
        #        self.IRtext.setPlainText(self.relationInstance.relName)
        self.itemText.setHtml(self.genTextHTML())

    def genTextHTML(self):
        '''generate html to display the text
        '''
        prefix = '<html><body>'
        suffix = "</body></html>"
        myHTML = ('{}<p><font size="1"> [{}]</font></p>{}'.format(
            prefix, self.text, suffix))
        return myHTML

    def moveIt(self, ):
        self.drawIt()
예제 #16
0
class Tower(QGraphicsPixmapItem):

    SCALE_FACTOR = 300

    def __init__(self, parent=None):
        super(Tower, self).__init__(parent)
        self.setPixmap(QPixmap(':/Resources/images/Tower.png'))
        self.setScale(0.5)
        self.points = [
            QPointF(1, 0),
            QPointF(2, 0),
            QPointF(3, 1),
            QPointF(3, 2),
            QPointF(2, 3),
            QPointF(1, 3),
            QPointF(0, 2),
            QPointF(0, 1)
        ]
        for point in self.points:
            point.setX(point.x() * Tower.SCALE_FACTOR)
            point.setY(point.y() * Tower.SCALE_FACTOR)

        self.polygon = QPolygonF(self.points)
        self.border = QGraphicsPolygonItem(self.polygon, self)
        #        self.border.setPen(QPen(Qt.red))

        self.border.setScale(0.5)

        self.border.setPen(QPen(Qt.DashLine))
        self.poly_center = QPointF(1.5, 1.5)
        self.poly_center *= Tower.SCALE_FACTOR

        self.poly_center = self.mapToScene(self.poly_center)
        self.tower_center = QPointF(self.x() + 50, self.y() + 50)
        self.line = QLineF(self.poly_center, self.tower_center)
        self.border.setPos(self.border.x() + self.line.dx(),
                           self.border.y() + self.line.dy())

        #        self.attack_destination = QPointF(800,0)

        self.timer = QTimer()
        self.timer.timeout.connect(lambda: self.accquire_target())
        self.timer.start(1000)

    def fire(self):
        arrow = Arrow()
        arrow.setPos(self.x(), self.y())
        attack_line = QLineF(QPointF(self.x() + 25,
                                     self.y() + 25), self.attack_destination)
        line = QGraphicsLineItem(attack_line)
        line.setPen(QPen(Qt.blue))
        #       self.scene().addItem(line)
        attack_angle = -1 * attack_line.angle(
        )  # Multiplied by -1 because the angle is given in counter clockwise direction
        arrow.setRotation(attack_angle)
        self.scene().addItem(arrow)

    def distance_to(self, item):

        distance = QLineF(QPointF(self.pos().x() + 25,
                                  self.pos().y() + 25), item.pos())
        line = QGraphicsLineItem(distance)
        line.setPen(QPen(Qt.red))
        #        self.scene().addItem(line)
        return distance.length()

    def accquire_target(self):

        attack_item = self.border.collidingItems()

        if (len(attack_item) == 1):
            self.has_target = False
            return

        closet_distance = 300
        closet_pt = QPointF(0, 0)

        for item in attack_item:
            if isinstance(item, Enemy):
                distance = self.distance_to(item)
                if (distance < closet_distance):
                    closet_distance = distance
                    closet_pt = QPointF(item.pos().x() + 50,
                                        item.pos().y() + 50)
                    self.has_target = True

                self.attack_destination = closet_pt
                self.fire()
예제 #17
0
class DynamicGameObject(StaticGameObject):
    '''Class to modelate objects that can move and attack (minions, Ia's champion) '''
    def __init__(self):
        super().__init__()
        # set speed
        self.speed = 0
        self.attack = 1

        # set pos / destination
        self.x_prev = 0
        self.y_prev = 0
        self.setPos(0, 0)
        self.destination = QPointF(0, 0)

        # initialize attack range (area)
        self.attack_area = QGraphicsPolygonItem()
        self.attack_dest = QPointF(0, 0)
        self.has_target = False

    def set_range(self, SCALE_FACTOR):
        '''It gives the object a QGraphicsPolygonItem to attack at a certain range '''
        # create points vector
        self.range = SCALE_FACTOR

        points = [
            QPointF(1, 0),
            QPointF(2, 0),
            QPointF(3, 1),
            QPointF(3, 2),
            QPointF(2, 3),
            QPointF(1, 3),
            QPointF(0, 2),
            QPointF(0, 1)
        ]

        # scale points
        points = [p * SCALE_FACTOR for p in points]

        # create polygon
        self.polygon = QPolygonF(points)

        # create QGraphicsPolygonItem
        self.attack_area = QGraphicsPolygonItem(self.polygon, self)
        self.attack_area.setPen(QPen(Qt.DotLine))

        # move the polygon
        poly_center = QPointF(1.5 * SCALE_FACTOR, 1.5 * SCALE_FACTOR)
        poly_center = self.mapToScene(poly_center)
        minion_center = QPointF(self.x() + self.pixmap().width() / 2,
                                self.y() + self.pixmap().height() / 2)
        ln = QLineF(poly_center, minion_center)
        self.attack_area.setPos(self.x() + ln.dx(), self.y() + ln.dy())

    def fire(self):
        if not self.scene():
            return

        bullet = Bullet(self)
        bullet.setPos(self.x() + self.pixmap().width() / 2,
                      self.y() + self.pixmap().height() / 2)

        # set the angle to be paralel to the line that connects the
        # tower and target
        ln = QLineF(
            QPointF(self.x() + self.pixmap().width() / 2,
                    self.y() + self.pixmap().height() / 2), self.attack_dest)
        angle = -1 * ln.angle()  # -1 to make it clock wise

        bullet.setRotation(angle)

        self.scene().addItem(bullet)

    def acquire_target(self):
        # get a list of all items colliding with attack area
        colliding_items = self.attack_area.collidingItems()

        self.has_target = False
        closest_dist = 300
        closest_point = QPointF(0, 0)
        for i in colliding_items:
            if hasattr(i, 'team') and i.team != self.team:
                this_distance = self.distance_to(i)
                if this_distance < closest_dist:
                    closest_dist = this_distance
                    closest_point = i.pos()
                    self.has_target = True

        self.attack_dest = closest_point
        if self.has_target:
            self.fire()

    def set_attack(self, value):
        self.attack = value

    def set_destination(self, point):
        '''QPoinF : point '''
        self.destination = point

    def set_speed(self, s):
        self.speed = s

    @property
    def should_be_moving(self):
        ln = QLineF(self.pos(), self.destination)
        CLOSE_DIST = 30

        if ln.length() > CLOSE_DIST:
            return True
        else:
            return False

    def move_forward(self):
        # move object
        if self.should_be_moving:
            ln = QLineF(self.pos(), self.destination)
            ln.setLength(self.speed)

            self.rotate_to_point(self.destination)

            # avoid collision
            colliding_items = self.collidingItems()
            for i in colliding_items:
                if isinstance(i, StaticGameObject):
                    collision_line = QLineF(self.pos(), i.pos())
                    collision_line.setLength(30)
                    self.setPos(self.x() - collision_line.dx(),
                                self.y() - collision_line.dy())

            # move object forward at current angle
            self.setPos(self.x() + ln.dx(), self.y() + ln.dy())

        self.x_prev = self.pos().x()
        self.y_prev = self.pos().y()

    def distance_to(self, item):
        '''item: QGraphicsItem '''
        ln = QLineF(self.pos(), item.pos())
        return ln.length()

    def set_dest_to_closest(self):
        '''Sets destination to closest enemy '''
        if not self.scene():
            return
        scene_items = self.scene().items()

        closest_point = QPointF(0, 0)
        closest_dist = 1000
        for i in scene_items:
            if hasattr(i, 'team') and i.team != self.team:
                this_distance = self.distance_to(i)
                if this_distance < closest_dist:
                    closest_dist = this_distance
                    closest_point = i.pos()

        self.set_destination(closest_point)

    def rotate_to_point(self, point):
        '''point: QPointF'''
        ln = QLineF(self.pos(), point)
        # that 90 is because sprite sheet is pointing north
        self.setRotation(-1 * ln.angle() + 90)
예제 #18
0
 def create_cross():
     item = QGraphicsPolygonItem(qt_drawings.cross_polygon)
     item.setBrush(qt_drawings.red_brush)
     item.setPen(qt_drawings.red_pen)
     return item
예제 #19
0
class StoreIcon(QGraphicsPixmapItem):

    def __init__(self, parent=None):
        super().__init__()
        # bool to check if it is available
        self.available = False

        # set store gui
        self.gui = Store()

        # set graphics
        self.setPixmap(QPixmap('./res/imgs/blue_chest.png').scaled(80, 80, Qt.KeepAspectRatio))

        # create points vector
        points = [QPointF(1, 0), QPointF(2, 0), QPointF(3, 1),
                  QPointF(3, 2), QPointF(2, 3), QPointF(1, 3),
                  QPointF(0, 2), QPointF(0, 1)]

        # scale points
        SCALE_FACTOR = 100
        points = [p * SCALE_FACTOR for p in points]

        # create polygon
        self.polygon = QPolygonF(points)

        # create QGraphicsPolygonItem
        self.available_area = QGraphicsPolygonItem(self.polygon, self)
        self.available_area.setPen(QPen(Qt.DotLine))

        # move the polygon
        poly_center = QPointF(1.5 * SCALE_FACTOR, 1.5 * SCALE_FACTOR)
        poly_center = self.mapToScene(poly_center)
        store_center = QPointF(self.x() + 40, self.y() + 40)
        ln = QLineF(poly_center, store_center)
        self.available_area.setPos(self.x() + ln.dx(), self.y() + ln.dy())

        # connect the timer to acquire_champion
        self.timer = QTimer()
        self.timer.timeout.connect(self.acquire_champion)
        self.timer.start(1000)

    def mousePressEvent(self, event):
        if self.available:
            self.launch_store()

    def acquire_champion(self):
        colliding_items = self.available_area.collidingItems()

        found = False
        for item in colliding_items:
            if isinstance(item, PlayerChampion):
                self.set_available(True)
                found = True
        if not found:
            self.set_available(False)

    def set_available(self, bool_input):
        self.available = bool_input
        if not self.available and self.gui.isVisible():
            self.gui.close()

    def launch_store(self):
        self.gui.show()
예제 #20
0
class GraphicsScene(QGraphicsScene):
    def __init__(self, annotation_manager, count_label, parent=None):
        super(GraphicsScene, self).__init__(parent)
        self.annotations = set()
        self.negative_annotations = set()
        self.roi_point_items = set()

        self.removal_tool = RemovalTool(annotation_manager, self)
        self.annotation_tool = AnnotationTool(annotation_manager, self)

        self.currently_drawing = False
        self.currently_deleting = False
        self.image_name = None
        self.image_path = None
        self.curr_image = None
        self.annotation_manager = annotation_manager
        self.count_label = count_label
        self.saved = True
        self.enabled = False

        self.polygon = None
        self.roi_polygon = None
        self.picked_tool = 0
        self.removal_circle_item = None
        self.removal_circle_radius = 100

        # stack of tuples such as: (add/remove, annotation_item)
        self.annotation_undo_stack = []

        # stack of ints depicting which action needs undoing
        self.action_undo_stack = []

    def add_image(self, image_path):
        image = QImage(image_path)
        self.image = image
        self.original_image = image.copy()
        h, w = image.height(), image.width()
        self.pixmap_item = self.addPixmap(QPixmap.fromImage(image))

    def change_annotations_on_image(self):
        print("Changing image annotations")
        self.enabled = True
        self.clear()
        self.annotations = set()
        self.negative_annotations = set()

        self.polygon = None
        self.roi_polygon = None
        self.removal_circle_item = None
        self.annotation_undo_stack = []
        self.action_undo_stack = []

        self.add_image(self.image_path)
        self.setSceneRect(self.itemsBoundingRect())

        for a in self.annotation_manager.annotations_rect[self.image_name]:
            tmp_annot = AnnotationItem(QPointF(a[0], a[1]), self, a)
            self.annotations.add(tmp_annot)
            self.addItem(tmp_annot)

        for a in self.annotation_manager.negative_annotations_rect[
                self.image_name]:
            tmp_annot = AnnotationItem(QPointF(a[0], a[1]),
                                       self,
                                       a,
                                       annotation_negative=True)
            self.negative_annotations.add(tmp_annot)
            self.addItem(tmp_annot)

        for a in self.annotation_manager.roi_points[self.image_name]:
            tmp_annot = PolygonPointItem(self, (a[0], a[1]))
            self.roi_point_items.add(tmp_annot)
            self.addItem(tmp_annot)

        self.annotation_tool.draw_convex_hull()
        self.draw_roi_polygon()
        self.count_label.setText("Number of annotations: " +
                                 str(len(self.annotations)))
        self.update()

    def change_image(self, image_path, image_name):
        self.enabled = True
        self.clear()
        self.annotations = set()
        self.negative_annotations = set()
        self.roi_point_items = set()

        self.polygon = None
        self.roi_polygon = None
        self.removal_circle_item = None
        self.annotation_undo_stack = []
        self.action_undo_stack = []

        self.add_image(image_path)
        self.setSceneRect(self.itemsBoundingRect())

        self.image_path = image_path
        self.annotation_manager.image_shapes[image_name] = [
            self.image.width(), self.image.height()
        ]

        for a in self.annotation_manager.annotations_rect[image_name]:
            tmp_annot = AnnotationItem(QPointF(a[0], a[1]), self, a)
            self.annotations.add(tmp_annot)
            self.addItem(tmp_annot)

        for a in self.annotation_manager.negative_annotations_rect[image_name]:
            tmp_annot = AnnotationItem(QPointF(a[0], a[1]),
                                       self,
                                       a,
                                       annotation_negative=True)
            self.negative_annotations.add(tmp_annot)
            self.addItem(tmp_annot)

        for a in self.annotation_manager.roi_points[image_name]:
            tmp_annot = PolygonPointItem(self, (a[0], a[1]))
            self.roi_point_items.add(tmp_annot)
            self.addItem(tmp_annot)

        self.image_name = image_name
        self.count_label.setText("Number of annotations: " +
                                 str(len(self.annotations)))
        self.annotation_tool.draw_convex_hull()
        self.draw_roi_polygon()
        self.update()

    def get_annotations(self):
        return self.annotations

    def draw_roi_polygon(self):
        if len(self.annotation_manager.roi_points[self.image_name]) > 2:
            if self.roi_polygon != None:
                self.removeItem(self.roi_polygon)
                self.roi_polygon = None
            brush = QBrush(QColor("#fc8803"))
            pen = QPen(brush, 5)

            polygon = QPolygonF([
                QPointF(x[0], x[1]) for x in np.array(
                    self.annotation_manager.roi_points[self.image_name])
            ])
            self.roi_polygon = QGraphicsPolygonItem(polygon)
            self.roi_polygon.setPen(pen)
            self.addItem(self.roi_polygon)
        else:
            if self.roi_polygon != None:
                self.removeItem(self.roi_polygon)
                self.roi_polygon = None

    def keyPressEvent(self, QKeyEvent):
        # Changes the cursor icon when deleting
        if self.picked_tool == 0 or self.picked_tool == 2:
            if QKeyEvent.key(
            ) == Qt.Key_Control and not self.currently_deleting:
                self.currently_deleting = True
                QApplication.setOverrideCursor(QCursor(Qt.CrossCursor))

    def keyReleaseEvent(self, QKeyEvent):
        # Changes the cursor icon back to normal when deleting stops
        if self.picked_tool == 0 or self.picked_tool == 2:
            if QKeyEvent.key() == Qt.Key_Control and self.currently_deleting:
                self.currently_deleting = False
                QApplication.setOverrideCursor(QCursor(Qt.ArrowCursor))

    def handle_remove_action(self, pos):
        num_removed = self.removal_tool.remove_action(pos)
        if num_removed > 0:
            self.annotation_manager.annotations_changed[self.image_name] = True
            self.count_label.setText("Number of annotations: " +
                                     str(len(self.annotations)))
            self.annotation_tool.draw_convex_hull()
            self.saved = False

    def handle_undo_remove_action(self):
        removed = self.removal_tool.undo_remove_action()
        if removed:
            self.annotation_manager.annotations_changed[self.image_name] = True
            self.count_label.setText("Number of annotations: " +
                                     str(len(self.annotations)))
            self.annotation_tool.draw_convex_hull()
            self.saved = False

    def handle_undo_annotation_action(self):
        removed = self.annotation_tool.undo_annotation()
        if removed:
            self.annotation_manager.annotations_changed[self.image_name] = True
            self.count_label.setText("Number of annotations: " +
                                     str(len(self.annotations)))
            self.saved = False
            self.annotation_tool.draw_convex_hull()

    def handle_undo_action(self):
        print("Test")
        if len(self.action_undo_stack) > 0:
            tool_used = self.action_undo_stack.pop()
            if tool_used == 0 or tool_used == 2:
                print("Undo for annotations")
                self.handle_undo_annotation_action()
            elif tool_used == 1:
                print("Undo remove")
                self.handle_undo_remove_action()

    def mousePressEvent(self, QMouseEvent):
        super(GraphicsScene, self).mousePressEvent(QMouseEvent)
        # if left mouse button
        pos = QMouseEvent.scenePos()
        modifiers = QApplication.keyboardModifiers()
        # if tool is annotation adding
        if self.picked_tool == 0 or self.picked_tool == 2:
            if (QMouseEvent.button() == 1):
                self.currently_drawing = True
                self.annotation_tool.add_progress_annotation(
                    pos,
                    [pos.x(), pos.y(),
                     pos.x() + 1, pos.y() + 1])
                self.start_x = pos.x()
                self.start_y = pos.y()
        elif self.picked_tool == 1 and QMouseEvent.buttons() == Qt.LeftButton:
            self.handle_remove_action(pos)
        elif self.picked_tool == 3 and QMouseEvent.button(
        ) == 1 and modifiers != Qt.ControlModifier:
            print("poly tool pressed")
            tmp_annot = PolygonPointItem(self, (pos.x(), pos.y()))
            self.currently_drawing = False
            self.addItem(tmp_annot)
            self.roi_point_items.add(tmp_annot)
            self.annotation_manager.roi_points[self.image_name].append(
                (pos.x(), pos.y()))
            self.draw_roi_polygon()

        self.update()

    def mouseMoveEvent(self, QMouseEvent):
        # pos = QPointF(QMouseEvent.pos())
        super(GraphicsScene, self).mouseMoveEvent(QMouseEvent)
        pos = QMouseEvent.scenePos()
        modifiers = QApplication.keyboardModifiers()

        # if tool is annotation adding
        if self.picked_tool == 0 or self.picked_tool == 2 or self.picked_tool == 3:
            if self.currently_drawing:
                self.end_x = pos.x()
                self.end_y = pos.y()
                x1 = self.end_x
                y1 = self.end_y
                x2 = self.start_x
                y2 = self.start_y
                if self.picked_tool == 3 or self.picked_tool == 2:
                    self.annotation_tool.add_progress_annotation(
                        pos, [x1, y1, x2, y2], rectangular=True)
                else:
                    self.annotation_tool.add_progress_annotation(
                        pos, [x1, y1, x2, y2])

        elif self.picked_tool == 1 and QMouseEvent.buttons() == Qt.LeftButton:
            self.handle_remove_action(pos)

        if self.picked_tool == 1 or self.picked_tool == 4:
            self.removal_tool.draw_removal_circle(pos)

        self.update()

    def mouseReleaseEvent(self, QMouseEvent):
        pos = QMouseEvent.scenePos()
        # Handle adding positive/negative anotations
        if self.picked_tool == 0 or self.picked_tool == 2:
            if (QMouseEvent.button() == 1):
                self.currently_drawing = False
                self.end_x = pos.x()
                self.end_y = pos.y()
                # add annotation
                if (abs(self.start_x - self.end_x) > 1
                        and abs(self.start_y - self.end_y) > 1):
                    self.annotation_tool.add_annotation(
                        pos,
                        [self.start_x, self.start_y, self.end_x, self.end_y])
                # remove in progress annotation
                self.annotation_tool.remove_progress_annotation()

        # Save remove action to undo stack
        elif self.picked_tool == 1 and QMouseEvent.button() == 1:
            removed = self.removal_tool.end_of_action()
            if removed:
                self.action_undo_stack.append(self.picked_tool)

        self.update()

    def drawRect(self, event, qp, rect):
        qp.setPen(QColor(168, 34, 3))
        qp.setFont(QFont('Decorative', 10))
        qp.drawRect(*rect)
        self.update()