def loadMap(self, mapLocation):
     with open(mapLocation) as file:
         mapObjList = json.load(file)
     for item in mapObjList["objects"]:
         if (item["type"] == "rect"):
             shape = QGraphicsRectItem(item["centerX"] - item["length"] / 2,
                                       -item["centerY"] - item["width"] / 2,
                                       item["length"], item["width"])
             shape.setTransformOriginPoint(
                 QPoint(item["centerX"], -item["centerY"]))
             shape.setPen(QPen(self.black))
             shape.setBrush(QBrush(self.black, Qt.SolidPattern))
             shape.setRotation(item["rotation"])
             self.scene.addItem(shape)
         elif (item["type"] == "text"):
             label = QGraphicsTextItem(item["text"])
             label.setX(item["centerX"] - item["length"] / 2)
             label.setY(-item["centerY"] - item["width"] / 2)
             font = QFont("Bavaria")
             font.setPointSize(24)
             font.setWeight(QFont.Bold)
             label.setFont(font)
             label.setRotation(item["rotation"])
             self.RoomNameList.append(label)
             self.scene.addItem(label)
         elif (item["type"] == "obstacle"):
             shape = QGraphicsRectItem(item["centerX"] - item["length"] / 2,
                                       -item["centerY"] - item["width"] / 2,
                                       item["length"], item["width"])
             shape.setTransformOriginPoint(
                 QPoint(item["centerX"], -item["centerY"]))
             shape.setPen(QPen(self.gray))
             shape.setBrush(QBrush(self.gray, Qt.SolidPattern))
             shape.setRotation(item["rotation"])
             self.ObstacleList.append(shape)
         elif (item["type"] == "plant"):
             shape = QGraphicsEllipseItem(
                 item["centerX"] - item["length"] / 2,
                 -item["centerY"] - item["width"] / 2, item["length"],
                 item["width"])
             shape.setTransformOriginPoint(
                 QPoint(item["centerX"], -item["centerY"]))
             shape.setPen(QPen(self.green))
             shape.setBrush(QBrush(self.green, Qt.SolidPattern))
             shape.setRotation(item["rotation"])
             self.ObstacleList.append(shape)
     self.SupervisorMap.scale(self.scaleFactor, self.scaleFactor)
예제 #2
0
class BlockItem(QGraphicsPixmapItem):
    def __init__(self, trnsysType, parent, **kwargs):
        super().__init__(None)

        self.logger = parent.logger

        self.w = 120
        self.h = 120
        self.parent = parent
        self.id = self.parent.parent().idGen.getID()
        self.propertyFile = []

        if "displayName" in kwargs:
            self.displayName = kwargs["displayName"]
        else:
            self.displayName = trnsysType + "_" + str(self.id)

        if "loadedBlock" not in kwargs:
            self.parent.parent().trnsysObj.append(self)

        self.inputs = []
        self.outputs = []

        # Export related:
        self.name = trnsysType
        self.trnsysId = self.parent.parent().idGen.getTrnsysID()

        # Transform related
        self.flippedV = False
        self.flippedH = False
        self.rotationN = 0
        self.flippedHInt = -1
        self.flippedVInt = -1

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

        # To set flags of this item
        self.setFlags(self.ItemIsSelectable | self.ItemIsMovable)
        self.setFlag(self.ItemSendsScenePositionChanges, True)
        self.setCursor(QCursor(QtCore.Qt.PointingHandCursor))

        self.label = QGraphicsTextItem(self.displayName, self)
        self.label.setVisible(False)

        if self.name == "Bvi":
            self.inputs.append(_cspi.createSinglePipePortItem("i", 0, self))
            self.outputs.append(_cspi.createSinglePipePortItem("o", 2, self))

        if self.name == "StorageTank":
            # Inputs get appended in ConfigStorage
            pass

        self.logger.debug("Block name is " + str(self.name))

        # Update size for generic block:
        if self.name == "Bvi":
            self.changeSize()

        # Experimental, used for detecting genereated blocks attached to storage ports
        self.inFirstRow = False

        # Undo framework related
        self.oldPos = None

        self.origOutputsPos = None
        self.origInputsPos = None

    def _getImageAccessor(self) -> _tp.Optional[_img.ImageAccessor]:
        if type(self) == BlockItem:
            raise AssertionError(
                "`BlockItem' cannot be instantiated directly.")

        currentClassName = BlockItem.__name__
        currentMethodName = f"{currentClassName}.{BlockItem._getImageAccessor.__name__}"

        message = (
            f"{currentMethodName} has been called. However, this method should not be called directly but must\n"
            f"implemented in a child class. This means that a) someone instantiated `{currentClassName}` directly\n"
            f"or b) a child class of it doesn't implement `{currentMethodName}`. Either way that's an\n"
            f"unrecoverable error and therefore the program will be terminated now. Please do get in touch with\n"
            f"the developers if you've encountered this error. Thanks.")

        exception = AssertionError(message)

        # I've seen exception messages mysteriously swallowed that's why we're logging the message here, too.
        self.logger.error(message, exc_info=exception, stack_info=True)

        raise exception

    def addTree(self):
        pass

    # Setter functions
    def setParent(self, p):
        self.parent = p

        if self not in self.parent.parent().trnsysObj:
            self.parent.parent().trnsysObj.append(self)
            # self.logger.debug("trnsysObj are " + str(self.parent.parent().trnsysObj))

    def setId(self, newId):
        self.id = newId

    def setName(self, newName):
        self.displayName = newName
        self.label.setPlainText(newName)

    # Interaction related
    def contextMenuEvent(self, event):
        menu = QMenu()

        a1 = menu.addAction("Launch NotePad++")
        a1.triggered.connect(self.launchNotepadFile)

        rr = _img.ROTATE_TO_RIGHT_PNG.icon()
        a2 = menu.addAction(rr, "Rotate Block clockwise")
        a2.triggered.connect(self.rotateBlockCW)

        ll = _img.ROTATE_LEFT_PNG.icon()
        a3 = menu.addAction(ll, "Rotate Block counter-clockwise")
        a3.triggered.connect(self.rotateBlockCCW)

        a4 = menu.addAction("Reset Rotation")
        a4.triggered.connect(self.resetRotation)

        b1 = menu.addAction("Print Rotation")
        b1.triggered.connect(self.printRotation)

        c1 = menu.addAction("Delete this Block")
        c1.triggered.connect(self.deleteBlockCom)

        menu.exec_(event.screenPos())

    def launchNotepadFile(self):
        self.logger.debug("Launching notpad")
        global FilePath
        os.system("start notepad++ " + FilePath)

    def mouseDoubleClickEvent(self, event):
        if hasattr(self, "isTempering"):
            self.parent.parent().showTVentilDlg(self)
        elif self.name == "Pump":
            self.parent.parent().showPumpDlg(self)
        elif self.name == "TeePiece" or self.name == "WTap_main":
            self.parent.parent().showBlockDlg(self)
        elif self.name in ["SPCnr", "DPCnr", "DPTee"]:
            self.parent.parent().showDoublePipeBlockDlg(self)
        else:
            self.parent.parent().showBlockDlg(self)
            if len(self.propertyFile) > 0:
                for files in self.propertyFile:
                    os.startfile(files, "open")

    def mouseReleaseEvent(self, event):
        # self.logger.debug("Released mouse over block")
        if self.oldPos is None:
            self.logger.debug("For Undo Framework: oldPos is None")
        else:
            if self.scenePos() != self.oldPos:
                self.logger.debug("Block was dragged")
                self.logger.debug("Old pos is" + str(self.oldPos))
                command = MoveCommand(self, self.oldPos, "Move BlockItem")
                self.parent.parent().parent().undoStack.push(command)
                self.oldPos = self.scenePos()

        super(BlockItem, self).mouseReleaseEvent(event)

    # Transform related
    def changeSize(self):
        self._positionLabel()

        w, h = self._getCappedWithAndHeight()

        if self.name == "Bvi":
            delta = 4

            self.inputs[0].setPos(
                -2 * delta + 4 * self.flippedH * delta + self.flippedH * w,
                h / 3)
            self.outputs[0].setPos(
                -2 * delta + 4 * self.flippedH * delta + self.flippedH * w,
                2 * h / 3)
            self.inputs[0].side = 0 + 2 * self.flippedH
            self.outputs[0].side = 0 + 2 * self.flippedH

    def _positionLabel(self):
        width, height = self._getCappedWithAndHeight()
        rect = self.label.boundingRect()
        labelWidth, lableHeight = rect.width(), rect.height()
        labelPosX = (height - labelWidth) / 2
        self.label.setPos(labelPosX, width)

    def _getCappedWithAndHeight(self):
        width = self.w
        height = self.h
        if height < 20:
            height = 20
        if width < 40:
            width = 40
        return width, height

    def updateFlipStateH(self, state):
        self.flippedH = bool(state)

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

        self.flippedHInt = 1 if self.flippedH else -1

        if self.flippedH:
            for i in range(0, len(self.inputs)):
                distanceToMirrorAxis = self.w / 2.0 - self.origInputsPos[i][0]
                self.inputs[i].setPos(
                    self.origInputsPos[i][0] + 2.0 * distanceToMirrorAxis,
                    self.inputs[i].pos().y(),
                )

            for i in range(0, len(self.outputs)):
                distanceToMirrorAxis = self.w / 2.0 - self.origOutputsPos[i][0]
                self.outputs[i].setPos(
                    self.origOutputsPos[i][0] + 2.0 * distanceToMirrorAxis,
                    self.outputs[i].pos().y(),
                )

        else:
            for i in range(0, len(self.inputs)):
                self.inputs[i].setPos(self.origInputsPos[i][0],
                                      self.inputs[i].pos().y())

            for i in range(0, len(self.outputs)):
                self.outputs[i].setPos(self.origOutputsPos[i][0],
                                       self.outputs[i].pos().y())

    def updateFlipStateV(self, state):
        self.flippedV = bool(state)

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

        self.flippedVInt = 1 if self.flippedV else -1

        if self.flippedV:
            for i in range(0, len(self.inputs)):
                distanceToMirrorAxis = self.h / 2.0 - self.origInputsPos[i][1]
                self.inputs[i].setPos(
                    self.inputs[i].pos().x(),
                    self.origInputsPos[i][1] + 2.0 * distanceToMirrorAxis,
                )

            for i in range(0, len(self.outputs)):
                distanceToMirrorAxis = self.h / 2.0 - self.origOutputsPos[i][1]
                self.outputs[i].setPos(
                    self.outputs[i].pos().x(),
                    self.origOutputsPos[i][1] + 2.0 * distanceToMirrorAxis,
                )

        else:
            for i in range(0, len(self.inputs)):
                self.inputs[i].setPos(self.inputs[i].pos().x(),
                                      self.origInputsPos[i][1])

            for i in range(0, len(self.outputs)):
                self.outputs[i].setPos(self.outputs[i].pos().x(),
                                       self.origOutputsPos[i][1])

    def updateSidesFlippedH(self):
        if self.rotationN % 2 == 0:
            for p in self.inputs:
                if p.side == 0 or p.side == 2:
                    self.updateSide(p, 2)
            for p in self.outputs:
                if p.side == 0 or p.side == 2:
                    self.updateSide(p, 2)
        if self.rotationN % 2 == 1:
            for p in self.inputs:
                if p.side == 1 or p.side == 3:
                    self.updateSide(p, 2)
            for p in self.outputs:
                if p.side == 1 or p.side == 3:
                    self.updateSide(p, 2)

    def updateSidesFlippedV(self):
        if self.rotationN % 2 == 1:
            for p in self.inputs:
                if p.side == 0 or p.side == 2:
                    self.updateSide(p, 2)
            for p in self.outputs:
                if p.side == 0 or p.side == 2:
                    self.updateSide(p, 2)
        if self.rotationN % 2 == 0:
            for p in self.inputs:
                if p.side == 1 or p.side == 3:
                    self.updateSide(p, 2)
            for p in self.outputs:
                if p.side == 1 or p.side == 3:
                    self.updateSide(p, 2)

    def updateSide(self, port, n):
        port.side = (port.side + n) % 4
        # self.logger.debug("Port side is " + str(port.side))

    def rotateBlockCW(self):
        # Rotate block clockwise
        # self.setTransformOriginPoint(50, 50)
        # self.setTransformOriginPoint(self.w/2, self.h/2)
        self.setTransformOriginPoint(0, 0)
        self.setRotation((self.rotationN + 1) * 90)
        self.label.setRotation(-(self.rotationN + 1) * 90)
        self.rotationN += 1
        self.logger.debug("rotated by " + str(self.rotationN))

        for p in self.inputs:
            p.itemChange(27, p.scenePos())
            self.updateSide(p, 1)

        for p in self.outputs:
            p.itemChange(27, p.scenePos())
            self.updateSide(p, 1)

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

    def rotateBlockToN(self, n):
        if n > 0:
            while self.rotationN != n:
                self.rotateBlockCW()
        if n < 0:
            while self.rotationN != n:
                self.rotateBlockCCW()

    def rotateBlockCCW(self):
        # Rotate block clockwise
        # self.setTransformOriginPoint(50, 50)
        self.setTransformOriginPoint(0, 0)
        self.setRotation((self.rotationN - 1) * 90)
        self.label.setRotation(-(self.rotationN - 1) * 90)
        self.rotationN -= 1
        self.logger.debug("rotated by " + str(self.rotationN))

        for p in self.inputs:
            p.itemChange(27, p.scenePos())
            self.updateSide(p, -1)

        for p in self.outputs:
            p.itemChange(27, p.scenePos())
            self.updateSide(p, -1)

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

    def resetRotation(self):
        self.logger.debug("Resetting rotation...")
        self.setRotation(0)
        self.label.setRotation(0)

        for p in self.inputs:
            p.itemChange(27, p.scenePos())
            self.updateSide(p, -self.rotationN)
            # self.logger.debug("Portside of port " + str(p) + " is " + str(p.portSide))

        for p in self.outputs:
            p.itemChange(27, p.scenePos())
            self.updateSide(p, -self.rotationN)
            # self.logger.debug("Portside of port " + str(p) + " is " + str(p.portSide))

        self.rotationN = 0

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

    def printRotation(self):
        self.logger.debug("Rotation is " + str(self.rotationN))

    # Deletion related
    def deleteConns(self):

        for p in self.inputs:
            while len(p.connectionList) > 0:
                p.connectionList[0].deleteConn()

        for p in self.outputs:
            while len(p.connectionList) > 0:
                p.connectionList[0].deleteConn()

    def deleteBlock(self):
        self.parent.parent().trnsysObj.remove(self)
        self.parent.scene().removeItem(self)
        widgetToRemove = self.parent.parent().findChild(
            QTreeView, self.displayName + "Tree")
        if widgetToRemove:
            widgetToRemove.hide()

    def deleteBlockCom(self):
        self.parent.deleteBlockCom(self)

    def getConnections(self):
        """
        Get the connections from inputs and outputs of this block.
        Returns
        -------
        c : :obj:`List` of :obj:`BlockItem`
        """
        c = []
        for i in self.inputs:
            for cl in i.connectionList:
                c.append(cl)
        for o in self.outputs:
            for cl in o.connectionList:
                c.append(cl)
        return c

    # Scaling related
    def mousePressEvent(self, event):  # create resizer
        """
        Using try catch to avoid creating extra resizers.

        When an item is clicked on, it will check if a resizer already existed. If
        there exist a resizer, returns. else, creates one.

        Resizer will not be created for GenericBlock due to complications in the code.
        Resizer will not be created for storageTank as there's already a built in function for it in the storageTank
        dialog.

        Resizers are deleted inside mousePressEvent function inside GUI.py

        """
        self.logger.debug("Inside Block Item mouse click")

        self.isSelected = True
        if self.name == "GenericBlock" or self.name == "StorageTank":
            return
        try:
            self.resizer
        except AttributeError:
            self.resizer = ResizerItem(self)
            self.resizer.setPos(self.w, self.h)
            self.resizer.itemChange(self.resizer.ItemPositionChange,
                                    self.resizer.pos())
        else:
            return

    def setItemSize(self, w, h):
        self.logger.debug("Inside block item set item size")
        self.w, self.h = w, h
        # if h < 20:
        #     self.h = 20
        # if w < 40:
        #     self.w = 40

    def updateImage(self):
        self.logger.debug("Inside block item update image")

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

        if self.flippedH:
            self.updateFlipStateH(self.flippedH)

        if self.flippedV:
            self.updateFlipStateV(self.flippedV)

    def _getPixmap(self) -> QPixmap:
        imageAccessor = self._getImageAccessor()

        image = imageAccessor.image(width=self.w, height=self.h).mirrored(
            horizontal=self.flippedH, vertical=self.flippedV)
        pixmap = QPixmap(image)

        return pixmap

    def deleteResizer(self):
        try:
            self.resizer
        except AttributeError:
            self.logger.debug("No resizer")
        else:
            del self.resizer

    # AlignMode related
    def itemChange(self, change, value):
        # self.logger.debug(change, value)
        # Snap grid excludes alignment

        if change == self.ItemPositionChange:
            if self.parent.parent().snapGrid:
                snapSize = self.parent.parent().snapSize
                self.logger.debug("itemchange")
                self.logger.debug(type(value))
                value = QPointF(value.x() - value.x() % snapSize,
                                value.y() - value.y() % snapSize)
                return value
            else:
                # if self.hasElementsInYBand() and not self.elementInY() and not self.aligned:
                if self.parent.parent().alignMode:
                    if self.hasElementsInYBand():
                        return self.alignBlock(value)
                    else:
                        # self.aligned = False
                        return value

                else:
                    return value
        else:
            return super(BlockItem, self).itemChange(change, value)

    def alignBlock(self, value):
        for t in self.parent.parent().trnsysObj:
            if isinstance(t, BlockItem) and t is not self:
                if self.elementInYBand(t):
                    value = QPointF(self.pos().x(), t.pos().y())
                    self.parent.parent().alignYLineItem.setLine(
                        self.pos().x() + self.w / 2,
                        t.pos().y(),
                        t.pos().x() + t.w / 2,
                        t.pos().y())

                    self.parent.parent().alignYLineItem.setVisible(True)

                    qtm = QTimer(self.parent.parent())
                    qtm.timeout.connect(self.timerfunc)
                    qtm.setSingleShot(True)
                    qtm.start(1000)

                    e = QMouseEvent(
                        QEvent.MouseButtonRelease,
                        self.pos(),
                        QtCore.Qt.NoButton,
                        QtCore.Qt.NoButton,
                        QtCore.Qt.NoModifier,
                    )
                    self.parent.mouseReleaseEvent(e)
                    self.parent.parent().alignMode = False
                    # self.setPos(self.pos().x(), t.pos().y())
                    # self.aligned = True

                if self.elementInXBand(t):
                    value = QPointF(t.pos().x(), self.pos().y())
                    self.parent.parent().alignXLineItem.setLine(
                        t.pos().x(),
                        t.pos().y() + self.w / 2,
                        t.pos().x(),
                        self.pos().y() + t.w / 2)

                    self.parent.parent().alignXLineItem.setVisible(True)

                    qtm = QTimer(self.parent.parent())
                    qtm.timeout.connect(self.timerfunc2)
                    qtm.setSingleShot(True)
                    qtm.start(1000)

                    e = QMouseEvent(
                        QEvent.MouseButtonRelease,
                        self.pos(),
                        QtCore.Qt.NoButton,
                        QtCore.Qt.NoButton,
                        QtCore.Qt.NoModifier,
                    )
                    self.parent.mouseReleaseEvent(e)
                    self.parent.parent().alignMode = False

        return value

    def timerfunc(self):
        self.parent.parent().alignYLineItem.setVisible(False)

    def timerfunc2(self):
        self.parent.parent().alignXLineItem.setVisible(False)

    def hasElementsInYBand(self):
        for t in self.parent.parent().trnsysObj:
            if isinstance(t, BlockItem):
                if self.elementInYBand(t):
                    return True

        return False

    def hasElementsInXBand(self):
        for t in self.parent.parent().trnsysObj:
            if isinstance(t, BlockItem):
                if self.elementInXBand(t):
                    return True

        return False

    def elementInYBand(self, t):
        eps = 50
        return self.scenePos().y() - eps <= t.scenePos().y(
        ) <= self.scenePos().y() + eps

    def elementInXBand(self, t):
        eps = 50
        return self.scenePos().x() - eps <= t.scenePos().x(
        ) <= self.scenePos().x() + eps

    def elementInY(self):
        for t in self.parent.parent().trnsysObj:
            if isinstance(t, BlockItem):
                if self.scenePos().y == t.scenePos().y():
                    return True
        return False

    def encode(self):
        portListInputs = []
        portListOutputs = []

        for inp in self.inputs:
            portListInputs.append(inp.id)
        for output in self.outputs:
            portListOutputs.append(output.id)

        blockPosition = (float(self.pos().x()), float(self.pos().y()))

        blockItemModel = BlockItemModel(
            self.name,
            self.displayName,
            blockPosition,
            self.id,
            self.trnsysId,
            portListInputs,
            portListOutputs,
            self.flippedH,
            self.flippedV,
            self.rotationN,
        )

        dictName = "Block-"
        return dictName, blockItemModel.to_dict()

    def decode(self, i, resBlockList):
        model = BlockItemModel.from_dict(i)

        self.setName(model.BlockDisplayName)
        self.setPos(float(model.blockPosition[0]),
                    float(model.blockPosition[1]))
        self.id = model.Id
        self.trnsysId = model.trnsysId

        if len(self.inputs) != len(model.portsIdsIn) or len(
                self.outputs) != len(model.portsIdsOut):
            temp = model.portsIdsIn
            model.portsIdsIn = model.portsIdsOut
            model.portsIdsOut = temp

        for index, inp in enumerate(self.inputs):
            inp.id = model.portsIdsIn[index]

        for index, out in enumerate(self.outputs):
            out.id = model.portsIdsOut[index]

        self.updateFlipStateH(model.flippedH)
        self.updateFlipStateV(model.flippedV)
        self.rotateBlockToN(model.rotationN)

        resBlockList.append(self)

    def decodePaste(self, i, offset_x, offset_y, resConnList, resBlockList,
                    **kwargs):
        self.setPos(
            float(i["BlockPosition"][0] + offset_x),
            float(i["BlockPosition"][1] + offset_y),
        )

        self.updateFlipStateH(i["FlippedH"])
        self.updateFlipStateV(i["FlippedV"])
        self.rotateBlockToN(i["RotationN"])

        for x in range(len(self.inputs)):
            self.inputs[x].id = i["PortsIDIn"][x]

        for x in range(len(self.outputs)):
            self.outputs[x].id = i["PortsIDOut"][x]

        resBlockList.append(self)

    # Export related
    def exportBlackBox(self):
        equation = []
        if (len(self.inputs + self.outputs) == 2 and self.isVisible()
                and not isinstance(self.outputs[0], DoublePipePortItem)):
            files = glob.glob(os.path.join(self.path, "**/*.ddck"),
                              recursive=True)
            if not (files):
                status = "noDdckFile"
            else:
                status = "noDdckEntry"
            lines = []
            for file in files:
                infile = open(file, "r")
                lines += infile.readlines()
            for i in range(len(lines)):
                if "output" in lines[i].lower() and "to" in lines[i].lower(
                ) and "hydraulic" in lines[i].lower():
                    for j in range(i, len(lines) - i):
                        if lines[j][0] == "T":
                            outputT = lines[j].split("=")[0].replace(" ", "")
                            status = "success"
                            break
                    equation = ["T" + self.displayName + "=" + outputT]
                    break
        else:
            status = "noBlackBoxOutput"

        if status == "noDdckFile" or status == "noDdckEntry":
            equation.append("T" + self.displayName + "=1")

        return status, equation

    def exportPumpOutlets(self):
        return "", 0

    def exportMassFlows(self):
        return "", 0

    def exportDivSetting1(self):
        return "", 0

    def exportDivSetting2(self, nUnit):
        return "", nUnit

    def exportPipeAndTeeTypesForTemp(self, startingUnit):
        return "", startingUnit

    def getTemperatureVariableName(self, portItem: SinglePipePortItem) -> str:
        return f"T{self.displayName}"

    def getFlowSolverParametersId(self, portItem: SinglePipePortItem) -> int:
        return self.trnsysId

    def assignIDsToUninitializedValuesAfterJsonFormatMigration(
            self, generator: _id.IdGenerator) -> None:
        pass

    def deleteLoadedFile(self):
        for items in self.loadedFiles:
            try:
                self.parent.parent().fileList.remove(str(items))
            except ValueError:
                self.logger.debug("File already deleted from file list.")
                self.logger.debug("filelist:", self.parent.parent().fileList)
    def __init__(self,
                 radius=200,
                 parent=None,
                 categories=[],
                 loglevel=logging.DEBUG):
        super(WheelScene, self).__init__(parent)
        self.logger = logs.build_logger(__name__, loglevel)
        self.loglevel = loglevel
        #super(TestWheelScene, self).__init__(parent)
        families = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
        if len(categories) == 0:
            sector_names = [
                "freespin", "bankruptcy", "dogs", "cats", "PC", "OP",
                "loseturn", "colors", "numbers", "states", "countries",
                "people"
            ]
        else:
            sector_names = categories
        self.radius = radius
        total = 0
        set_angle = 0
        count1 = 0
        colours = []
        total = sum(families)

        for count in range(len(families)):
            number = []
            for count in range(3):
                number.append(random.randrange(0, 255))
            colours.append(QColor(number[0], number[1], number[2]))

        for i, family in enumerate(families):
            # Max span is 5760, so we have to calculate corresponding span angle
            angle = round(float(family * 5760) / total)
            subangle = round(float((family * 5760) / total / 2))
            subangle += 120
            # ellipse = QGraphicsEllipseItem(0,0,400,400)
            ellipse = QGraphicsEllipseItem(0, 0, self.radius * 2,
                                           self.radius * 2)
            #ellipse.setPos(QPointF(0, 0))
            # ellipse.setPos(ellipse.boundingRect().center())
            #print(ellipse.rect().center())
            #ellipse.setTransformOriginPoint(200, 200)
            # ellipse.setRect(-200,200,400,400)
            ellipse.setStartAngle(set_angle)
            ellipse.setSpanAngle(angle)
            ellipse.setBrush(colours[count1])
            # https://stackoverflow.com/questions/3312016/text-in-a-qgraphicsscene
            text = QGraphicsTextItem()

            #text.setFont(QFont("Helvetica", 65))
            #text.setTextWidth(20)
            # print("angle=%s, set_angle=%s, sector_name=%s" % (angle, set_angle, sector_names[i]))

            document = QtGui.QTextDocument()
            document.setDocumentMargin(0)
            text.setDocument(document)
            self.font = QFont()
            self.default_font_size = 14
            self.font.setPointSize(self.default_font_size)
            self.font.setBold(True)
            self.font.setFamily("Helvetica")
            self.font.setCapitalization(True)
            text.setPlainText(textwrap.fill(sector_names[i], width=1))
            text.setFont(self.font)

            # print("render_piece label=%s, textangle=%s sub_angle=%s, set_angle=%s, angle=%s" %
            #                         (sector_names[i],
            #                          ((set_angle+subangle)/5760)*360,
            #                          subangle,
            #                          set_angle,
            #                          angle))
            #print("textpos=%s" % ellipse.rect().center())

            reduction_factor = 0
            while text.boundingRect().height() > self.radius - (self.radius *
                                                                .01):

                # print("category=%s, real_height=%s, radius=%s" % (sector_names[i],
                #                                                   text.boundingRect().height(),
                #                                                   self.radius))
                # print("trying changing reduction factor from %s to %s" % (reduction_factor,
                #                                                           reduction_factor + 1))
                reduction_factor += 1
                self.font.setPointSize(self.default_font_size -
                                       reduction_factor)
                text.deleteLater()
                text = None
                text = QGraphicsTextItem()
                text.setDocument(document)
                #text.setFont(QFont("Helvetica", 65- reduction_factor))
                text.setPlainText(textwrap.fill(sector_names[i], width=1))
                text.setFont(self.font)

            text.setZValue(2)

            if sector_names[i] == False:
                #scrap this part for now until we can figure out how to safely offset titles.
                # print("ellipse center=%s" % ellipse.rect().center())
                hypotenuse = self.radius * .01
                degree_subangle = (((set_angle + subangle) / 5760) * 360)
                degree_subangle += 90
                degree_subangle = degree_subangle % 360
                doTranslate = True
                if doTranslate:
                    #math.cos(degree_subangle) = adjacent/hypotenuse
                    x = math.cos(degree_subangle) * hypotenuse
                    y = math.sin(degree_subangle) * hypotenuse
                    extra = True
                    if extra:
                        if degree_subangle > 0. and degree_subangle < 90.:
                            pass
                        elif degree_subangle > 90 and degree_subangle < 180:
                            pass
                        elif degree_subangle > 180 and degree_subangle < 270:
                            pass
                            #y = -y
                        elif degree_subangle > 270:
                            pass
                    target = ellipse.rect().center()
                    target.setX(x + target.x())
                    target.setY(y + target.y())
                    # print("target=%s" % target)
                    print(
                        "do_move_text_offset cat=%s, offset=%s degree_subangle=%s, x=%s, y=%s"
                        % (sector_names[i], target, degree_subangle, x, y))
                    text.setPos(target)
                else:
                    text.setPos(ellipse.rect().center())
            text.setPos(ellipse.rect().center())
            self.logger.debug("ellipse rect: %s" % ellipse.rect())

            text.setRotation((((set_angle + subangle) / 5760) * 360))
            #text.setRotation(30)
            # set_angle+=1
            set_angle += angle
            count1 += 1
            self.addItem(ellipse)
            self.addItem(text)
        self.setSceneRect(0, 0, self.radius * 2, self.radius * 2)
        self.logger.debug("scenesize= %s" % self.sceneRect())
    def drawRobotCallback(self, result):
        for item in self.RobotShapes:
            self.scene.removeItem(item)
        self.RobotShapes.clear()
        self.RobotNames.clear()
        for item in self.robotMarkerShapes:
            self.augmentedRealityScene.removeItem(item)
        self.robotMarkerShapes.clear()
        frameRotation = 0
        obSize = 70
        controlledRobot = None
        for item in result.robots:
            shape = QGraphicsEllipseItem(int(item.pose.pose.pose.position.x*100 - obSize / 2), -int(item.pose.pose.pose.position.y*100 + obSize / 2), obSize, obSize)
            shape.setPen(QPen(self.black))
            color = self.yellow
            if self.currentRobot is not None:
                if item.name == self.currentRobot.name:
                    color = self.blue
                    controlledRobot = item
            if self.helperRobot is not None:
                if self.helperRobot == item.name:
                    color = self.purple
            shape.setBrush(QBrush(color, Qt.SolidPattern))
            self.scene.addItem(shape)
            self.RobotShapes.append(shape)
            self.RobotNames.append(item.name)
            quat = item.pose.pose.pose.orientation
            siny_cosp = 2 * (quat.w * quat.z + quat.x * quat.y)
            cosy_cosp = 1 - 2 * (quat.y * quat.y + quat.z * quat.z)
            yaw = math.atan2(siny_cosp, cosy_cosp)
            #making the arrow
            startArrowX = int(item.pose.pose.pose.position.x*100-math.cos(yaw)*obSize/4)
            startArrowY = -int(item.pose.pose.pose.position.y*100-math.sin(yaw)*obSize/4)
            endArrowX =int(item.pose.pose.pose.position.x*100+math.cos(yaw)*obSize/2-math.cos(yaw)*obSize/4)
            endArrowY = -int(item.pose.pose.pose.position.y*100+math.sin(yaw)*obSize/2-math.sin(yaw)*obSize/4)
            line = QGraphicsLineItem(startArrowX,
                                     startArrowY,
                                     endArrowX,
                                    endArrowY)
            line.setPen(QPen(self.black, 5))
            self.scene.addItem(line)
            self.RobotShapes.append(line)
            line = QGraphicsLineItem(endArrowX,
                                    endArrowY,
                                     endArrowX-math.cos(3.14/4+yaw)*obSize/4,
                                     endArrowY+math.sin(3.14/4+yaw)*obSize/4)

            line.setPen(QPen(self.black, 5))
            self.scene.addItem(line)
            self.RobotShapes.append(line)
            line = QGraphicsLineItem(endArrowX,
                                    endArrowY,
                                     endArrowX- math.cos(3.14 / 4 - yaw) * obSize / 4,
                                     endArrowY- math.sin(3.14 / 4 - yaw) * obSize / 4)

            line.setPen(QPen(self.black, 5))
            self.scene.addItem(line)
            self.RobotShapes.append(line)
            if self.currentRobot is not None:
                if item.name == self.currentRobot.name:
                    self.OperatorMap.centerOn(int(item.pose.pose.pose.position.x * 100),
                                              -int(item.pose.pose.pose.position.y * 100))
                    deltaRotate = math.degrees(yaw)-90-self.previousMapRotation
                    self.previousMapRotation = math.degrees(yaw)-90
                    self.OperatorMap.rotate(deltaRotate)
                    frameRotation = math.degrees(yaw)-90
            else:
                self.OperatorMap.rotate(-self.previousMapRotation)
                self.previousMapRotation = 0
                frameRotation = 0

        for item in result.robots:
            color = self.yellow
            if self.currentRobot is not None:
                if item.name == self.currentRobot.name:
                    color = self.blue
            if self.helperRobot is not None:
                if self.helperRobot == item.name:
                    color = self.purple
            label = QGraphicsTextItem(item.name)
            label.setX(int(item.pose.pose.pose.position.x * 100 + obSize * 1.1*math.cos(math.radians(-frameRotation-45))))
            label.setY(int(-item.pose.pose.pose.position.y * 100 + obSize * 1.1*math.sin(math.radians(-frameRotation-45))))
            label.setRotation(-frameRotation)
            font = QFont("Bavaria")
            font.setPointSize(18)
            font.setWeight(QFont.Bold)
            label.setDefaultTextColor(color)
            label.setFont(font)
            self.scene.addItem(label)
            self.RobotShapes.append(label)
        for item in self.RoomNames:
            item.setRotation(-frameRotation)
        if self.RobotWarningCB.isChecked():
            for item in result.robots:#draw arrows to other bots
                if controlledRobot is not None:
                    if item.name is not controlledRobot.name:
                        deltaX = controlledRobot.pose.pose.pose.position.x - item.pose.pose.pose.position.x
                        deltaY = controlledRobot.pose.pose.pose.position.y - item.pose.pose.pose.position.y
                        robotDistance = math.sqrt(
                            math.pow(deltaX, 2)+
                            math.pow(deltaY, 2))
                        if robotDistance<self.robotWarningDistance:
                            color = self.yellow
                            if self.helperRobot is not None:
                                if self.helperRobot == item.name:
                                    color = self.purple
                            quat = controlledRobot.pose.pose.pose.orientation
                            siny_cosp = 2 * (quat.w * quat.z + quat.x * quat.y)
                            cosy_cosp = 1 - 2 * (quat.y * quat.y + quat.z * quat.z)
                            yaw = math.atan2(siny_cosp, cosy_cosp)
                            difAngle = math.atan2(deltaY, deltaX)
                            totalAngle = yaw-difAngle+math.pi/2
                            startArrowX = int(self.AugmentedRealityPanel.height()*math.cos(totalAngle)*0.45)
                            startArrowY = int(self.AugmentedRealityPanel.height()*math.sin(totalAngle)*0.45)
                            endArrowX = int(self.AugmentedRealityPanel.height()*math.cos(totalAngle)*0.49)
                            endArrowY = int(self.AugmentedRealityPanel.height()*math.sin(totalAngle)*0.49)
                            line = QGraphicsLineItem(startArrowX, startArrowY, endArrowX,endArrowY)
                            line.setPen(QPen(color, 10))
                            self.augmentedRealityScene.addItem(line)
                            self.robotMarkerShapes.append(line)
                            line = QGraphicsLineItem(endArrowX,
                                                     endArrowY,
                                                     endArrowX - math.cos(3.14 / 4 + totalAngle) * self.AugmentedRealityPanel.height()*0.02,
                                                     endArrowY - math.sin(3.14 / 4 + totalAngle) * self.AugmentedRealityPanel.height()*0.02)

                            line.setPen(QPen(color, 10))
                            self.augmentedRealityScene.addItem(line)
                            self.robotMarkerShapes.append(line)
                            line = QGraphicsLineItem(endArrowX,
                                                     endArrowY,
                                                     endArrowX - math.cos(3.14 / 4 - totalAngle) * self.AugmentedRealityPanel.height()*0.02,
                                                     endArrowY + math.sin(3.14 / 4 - totalAngle) * self.AugmentedRealityPanel.height()*0.02)

                            line.setPen(QPen(color, 10))
                            self.augmentedRealityScene.addItem(line)
                            self.robotMarkerShapes.append(line)
예제 #5
0
class TVentil(BlockItem, MassFlowNetworkContributorMixin):
    def __init__(self, trnsysType, parent, **kwargs):
        super(TVentil, self).__init__(trnsysType, parent, **kwargs)

        self.h = 40
        self.w = 40
        self.isTempering = False
        self.positionForMassFlowSolver = 1.0
        self.posLabel = QGraphicsTextItem(str(self.positionForMassFlowSolver),
                                          self)
        self.posLabel.setVisible(False)

        self.inputs.append(_cspi.createSinglePipePortItem("i", 0, self))
        self.inputs.append(_cspi.createSinglePipePortItem("i", 1, self))
        self.outputs.append(_cspi.createSinglePipePortItem("o", 2, self))

        self.changeSize()

    def _getImageAccessor(self) -> _tp.Optional[_img.ImageAccessor]:
        return _img.T_VENTIL_SVG

    def changeSize(self):
        w = self.w
        h = self.h

        delta = 20
        # Limit the block size:
        if h < 20:
            h = 20
        if w < 40:
            w = 40

        # center label:
        rect = self.label.boundingRect()
        lw, lh = rect.width(), rect.height()
        lx = (w - lw) / 2

        self.label.setPos(lx, h - self.flippedV * (h + h / 2))
        self.posLabel.setPos(lx + 5, -15)

        self.origInputsPos = [[0, delta], [delta, 0]]
        self.origOutputsPos = [[w, delta]]
        self.inputs[0].setPos(self.origInputsPos[0][0],
                              self.origInputsPos[0][1])
        self.inputs[1].setPos(self.origInputsPos[1][0],
                              self.origInputsPos[1][1])
        self.outputs[0].setPos(self.origOutputsPos[0][0],
                               self.origOutputsPos[0][1])

        self.updateFlipStateH(self.flippedH)
        self.updateFlipStateV(self.flippedV)

        self.inputs[0].side = (self.rotationN + 2 * self.flippedH) % 4
        self.inputs[1].side = (self.rotationN + 1 + 2 * self.flippedV) % 4
        self.outputs[0].side = (self.rotationN + 2 - 2 * self.flippedH) % 4

        return w, h

    def rotateBlockCW(self):
        super().rotateBlockCW()
        # Rotate valve position label back so it will always stay horizontal
        self._updateRotation()

    def rotateBlockCCW(self):
        super().rotateBlockCCW()
        # Rotate valve position label back so it will always stay horizontal
        self._updateRotation()

    def resetRotation(self):
        super().resetRotation()
        # Rotate valve position label back so it will always stay horizontal
        self._updateRotation()

    def _updateRotation(self):
        self.posLabel.setRotation(-self.rotationN * 90)

    def setComplexDiv(self, b):
        self.isTempering = bool(b)

    def setPositionForMassFlowSolver(self, f):
        self.positionForMassFlowSolver = f

    def encode(self):
        dictName, dct = super(TVentil, self).encode()
        dct["IsTempering"] = self.isTempering
        dct["PositionForMassFlowSolver"] = self.positionForMassFlowSolver
        return dictName, dct

    def decode(self, i, resBlockList):
        super().decode(i, resBlockList)
        if "IsTempering" not in i or "PositionForMassFlowSolver" not in i:
            self.logger.debug("Old version of diagram")
            self.positionForMassFlowSolver = 1.0
        else:
            self.isTempering = i["IsTempering"]
            self.positionForMassFlowSolver = i["PositionForMassFlowSolver"]

    def decodePaste(self, i, offset_x, offset_y, resConnList, resBlockList,
                    **kwargs):
        super(TVentil, self).decodePaste(i, offset_x, offset_y, resConnList,
                                         resBlockList, **kwargs)
        if "IsTempering" or "PositionForMassFlowSolver" not in i:
            self.logger.debug("Old version of diagram")
            self.positionForMassFlowSolver = 1.0
        else:
            self.isTempering = i["IsTempering"]
            self.positionForMassFlowSolver = i["PositionForMassFlowSolver"]

    def exportMassFlows(self):
        if not self.isTempering:
            resStr = "xFrac" + self.displayName + " = " + str(
                self.positionForMassFlowSolver) + "\n"
            equationNr = 1
            return resStr, equationNr
        else:
            return "", 0

    def exportDivSetting1(self):
        if self.isTempering:
            constants = 1
            f = "T_set_" + self.displayName + "=50\n"
            return f, constants
        else:
            return "", 0

    def exportDivSetting2(self, nUnit):
        if self.isTempering:
            f = ""
            nUnit = nUnit + 1
            f += "UNIT %d TYPE 811 ! Passive Divider for heating \n" % nUnit
            f += "PARAMETERS 1" + "\n"
            f += "5 !Nb.of iterations before fixing the value \n"
            f += "INPUTS 4 \n"

            if (self.outputs[0].pos().y() == self.inputs[0].pos().y()
                    or self.outputs[0].pos().x() == self.inputs[0].pos().x()):
                first = self.inputs[0]
                second = self.inputs[1]

            f += "T" + first.connectionList[0].displayName + "\n"
            f += "T" + second.connectionList[0].displayName + "\n"
            f += "Mfr" + self.outputs[0].connectionList[0].displayName + "\n"

            f += "T_set_" + self.displayName + "\n"
            f += "*** INITIAL INPUT VALUES" + "\n"
            f += "35.0 21.0 800.0 T_set_" + self.displayName + "\n"

            f += "EQUATIONS 1\n"
            f += "xFrac" + self.displayName + " =  1.-[%d,5] \n\n" % nUnit

            return f, nUnit
        else:
            return "", nUnit

    def getInternalPiping(self) -> _mfs.InternalPiping:
        teePiece, modelPortItemsToGraphicalPortItem = self._getModelAndMapping(
        )

        return _mfs.InternalPiping([teePiece],
                                   modelPortItemsToGraphicalPortItem)

    def _getModelAndMapping(self):
        input1 = _mfn.PortItem("TVentil Input 1", _mfn.PortItemType.INPUT)
        input2 = _mfn.PortItem("TVentil Input 2", _mfn.PortItemType.INPUT)
        output = _mfn.PortItem("TVentil Output", _mfn.PortItemType.OUTPUT)
        teePiece = _mfn.Diverter(self.displayName, self.trnsysId, output,
                                 input1, input2)
        modelPortItemsToGraphicalPortItem = {
            input1: self.inputs[0],
            input2: self.inputs[1],
            output: self.outputs[0]
        }
        return teePiece, modelPortItemsToGraphicalPortItem

    def exportPipeAndTeeTypesForTemp(self, startingUnit):
        if self.isVisible():
            f = ""
            unitNumber = startingUnit
            tNr = 929  # Temperature calculation from a tee-piece

            unitText = ""
            ambientT = 20

            equationConstant = 1

            unitText += "UNIT " + str(unitNumber) + " TYPE " + str(tNr) + "\n"
            unitText += "!" + self.displayName + "\n"
            unitText += "PARAMETERS 0\n"
            unitText += "INPUTS 6\n"

            openLoops, nodesToIndices = self._getOpenLoopsAndNodeToIndices()
            assert len(openLoops) == 1
            openLoop = openLoops[0]

            assert len(openLoop.realNodes) == 1
            realNode = openLoop.realNodes[0]

            outputVariables = realNode.serialize(
                nodesToIndices).outputVariables
            for outputVariable in outputVariables:
                if not outputVariable:
                    continue

                unitText += outputVariable.name + "\n"

            unitText += f"T{self.outputs[0].connectionList[0].displayName}\n"
            unitText += f"T{self.inputs[0].connectionList[0].displayName}\n"
            unitText += f"T{self.inputs[1].connectionList[0].displayName}\n"

            unitText += "***Initial values\n"
            unitText += 3 * "0 " + 3 * (str(ambientT) + " ") + "\n"

            unitText += "EQUATIONS 1\n"
            unitText += "T" + self.displayName + "= [" + str(
                unitNumber) + "," + str(equationConstant) + "]\n"

            unitNumber += 1
            f += unitText + "\n"

            return f, unitNumber
        else:
            return "", startingUnit