Beispiel #1
0
 def start_connection(self, port: TerminalItem):
     """
     Start the branch creation
     @param port:
     @return:
     """
     self.started_branch = LineGraphicItem(fromPort=port, toPort=None, diagramScene=self.diagramScene)
     self.started_branch.bus_from = port.parent
     port.setZValue(0)
     port.process_callbacks(port.parent.pos() + port.pos())
Beispiel #2
0
 def add_line(self, branch: Line):
     """
     Add branch to the schematic
     :param branch: Branch object
     """
     terminal_from = branch.bus_from.graphic_obj.terminal
     terminal_to = branch.bus_to.graphic_obj.terminal
     graphic_obj = LineGraphicItem(terminal_from, terminal_to, self.diagramScene, branch=branch)
     graphic_obj.diagramScene.circuit = self.circuit  # add pointer to the circuit
     terminal_from.hosting_connections.append(graphic_obj)
     terminal_to.hosting_connections.append(graphic_obj)
     graphic_obj.redraw()
     branch.graphic_obj = graphic_obj
Beispiel #3
0
    def add_api_line(self, branch: Line):
        """
        add API branch to the Scene
        :param branch: Branch instance
        """
        terminal_from = branch.bus_from.graphic_obj.terminal
        terminal_to = branch.bus_to.graphic_obj.terminal

        graphic_obj = LineGraphicItem(terminal_from, terminal_to, self.diagramScene, branch=branch)

        graphic_obj.diagramScene.circuit = self.circuit  # add pointer to the circuit
        terminal_from.hosting_connections.append(graphic_obj)
        terminal_to.hosting_connections.append(graphic_obj)
        graphic_obj.redraw()

        return graphic_obj
Beispiel #4
0
    def scene_mouse_release_event(self, event):
        """
        Finalize the branch creation if its drawing ends in a terminal
        @param event:
        @return:
        """
        # Clear or finnish the started connection:
        if self.started_branch:
            pos = event.scenePos()
            items = self.diagramScene.items(pos)  # get the item (the terminal) at the mouse position

            for item in items:
                if type(item) is TerminalItem:  # connect only to terminals
                    if item.parent is not self.started_branch.fromPort.parent:  # forbid connecting to itself

                        self.started_branch.setToPort(item)
                        item.hosting_connections.append(self.started_branch)
                        self.started_branch.bus_to = item.parent

                        if self.started_branch.bus_from.api_object.is_dc != self.started_branch.bus_to.api_object.is_dc:
                            # different DC status -> VSC

                            name = 'VSC ' + str(len(self.circuit.vsc_devices) + 1)
                            obj = VSC(bus_from=self.started_branch.bus_from.api_object,
                                      bus_to=self.started_branch.bus_to.api_object,
                                      name=name)

                            obj.graphic_obj = VscGraphicItem(fromPort=self.started_branch.fromPort,
                                                             toPort=self.started_branch.toPort,
                                                             diagramScene=self.diagramScene,
                                                             branch=obj)

                        elif self.started_branch.bus_from.api_object.is_dc and self.started_branch.bus_to.api_object.is_dc:
                            # both buses are DC

                            name = 'Dc line ' + str(len(self.circuit.dc_lines) + 1)
                            obj = DcLine(bus_from=self.started_branch.bus_from.api_object,
                                         bus_to=self.started_branch.bus_to.api_object,
                                         name=name)

                            obj.graphic_obj = DcLineGraphicItem(fromPort=self.started_branch.fromPort,
                                                                toPort=self.started_branch.toPort,
                                                                diagramScene=self.diagramScene,
                                                                branch=obj)

                        else:
                            # Same DC status -> line / trafo
                            v1 = self.started_branch.bus_from.api_object.Vnom
                            v2 = self.started_branch.bus_to.api_object.Vnom

                            if abs(v1 - v2) > 1.0:
                                name = 'Transformer ' + str(len(self.circuit.transformers2w) + 1)
                                obj = Transformer2W(bus_from=self.started_branch.bus_from.api_object,
                                                    bus_to=self.started_branch.bus_to.api_object,
                                                    name=name)

                                obj.graphic_obj = TransformerGraphicItem(fromPort=self.started_branch.fromPort,
                                                                         toPort=self.started_branch.toPort,
                                                                         diagramScene=self.diagramScene,
                                                                         branch=obj)

                            else:
                                name = 'Line ' + str(len(self.circuit.lines) + 1)
                                obj = Line(bus_from=self.started_branch.bus_from.api_object,
                                           bus_to=self.started_branch.bus_to.api_object,
                                           name=name)

                                obj.graphic_obj = LineGraphicItem(fromPort=self.started_branch.fromPort,
                                                                  toPort=self.started_branch.toPort,
                                                                  diagramScene=self.diagramScene,
                                                                  branch=obj)

                        # add the new object to the circuit
                        self.circuit.add_branch(obj)

                        # update the connection placement
                        obj.graphic_obj.fromPort.update()
                        obj.graphic_obj.toPort.update()

                        # set the connection placement
                        obj.graphic_obj.setZValue(-1)

            # if self.started_branch.toPort is None:
            self.started_branch.remove_widget()

        # release this pointer
        self.started_branch = None
Beispiel #5
0
class GridEditor(QSplitter):

    def __init__(self, circuit: MultiCircuit):
        """
        Creates the Diagram Editor
        Args:
            circuit: Circuit that is handling
        """
        QSplitter.__init__(self)

        # store a reference to the multi circuit instance
        self.circuit = circuit

        # nodes distance "explosion" factor
        self.expand_factor = 1.5

        # Widget layout and child widgets:
        self.horizontalLayout = QHBoxLayout(self)
        self.object_editor_table = QTableView(self)
        self.libraryBrowserView = QListView(self)
        self.libraryModel = LibraryModel(self)
        self.libraryModel.setColumnCount(1)

        # Create an icon with an icon:
        object_factory = ObjectFactory()

        # initialize library of items
        self.libItems = list()
        self.libItems.append(QStandardItem(object_factory.get_box(), 'Bus'))
        for i in self.libItems:
            self.libraryModel.appendRow(i)

        # set the objects list
        self.object_types = [dev.device_type.value for dev in circuit.objects_with_profiles]

        self.catalogue_types = ['Wires', 'Overhead lines', 'Underground lines', 'Sequence lines', 'Transformers']

        # Actual libraryView object
        self.libraryBrowserView.setModel(self.libraryModel)
        self.libraryBrowserView.setViewMode(self.libraryBrowserView.ListMode)
        self.libraryBrowserView.setDragDropMode(self.libraryBrowserView.DragOnly)

        # create all the schematic objects and replace the existing ones
        self.diagramScene = DiagramScene(self, circuit)  # scene to add to the QGraphicsView
        self.diagramView = EditorGraphicsView(self.diagramScene, parent=self, editor=self)

        # create the grid name editor
        self.frame1 = QFrame()
        self.frame1_layout = QVBoxLayout()
        self.frame1_layout.setContentsMargins(0, 0, 0, 0)

        self.name_editor_frame = QFrame()
        self.name_layout = QHBoxLayout()
        self.name_layout.setContentsMargins(0, 0, 0, 0)

        self.name_label = QLineEdit()
        self.name_label.setText(str(self.circuit.name))
        self.name_layout.addWidget(self.name_label)
        self.name_editor_frame.setLayout(self.name_layout)

        self.frame1_layout.addWidget(self.name_editor_frame)
        self.frame1_layout.addWidget(self.libraryBrowserView)
        self.frame1.setLayout(self.frame1_layout)

        # Add the two objects into a layout
        splitter2 = QSplitter(self)
        splitter2.addWidget(self.frame1)
        splitter2.addWidget(self.object_editor_table)
        splitter2.setOrientation(Qt.Vertical)
        self.addWidget(splitter2)
        self.addWidget(self.diagramView)

        # factor 1:10
        splitter2.setStretchFactor(0, 1)
        splitter2.setStretchFactor(1, 5)

        self.started_branch = None

        self.setStretchFactor(0, 0.1)
        self.setStretchFactor(1, 2000)

    def start_connection(self, port: TerminalItem):
        """
        Start the branch creation
        @param port:
        @return:
        """
        self.started_branch = LineGraphicItem(fromPort=port, toPort=None, diagramScene=self.diagramScene)
        self.started_branch.bus_from = port.parent
        port.setZValue(0)
        port.process_callbacks(port.parent.pos() + port.pos())

    def scene_mouse_move_event(self, event):
        """

        @param event:
        @return:
        """
        if self.started_branch:
            pos = event.scenePos()
            self.started_branch.setEndPos(pos)

    def scene_mouse_release_event(self, event):
        """
        Finalize the branch creation if its drawing ends in a terminal
        @param event:
        @return:
        """
        # Clear or finnish the started connection:
        if self.started_branch:
            pos = event.scenePos()
            items = self.diagramScene.items(pos)  # get the item (the terminal) at the mouse position

            for item in items:
                if type(item) is TerminalItem:  # connect only to terminals
                    if item.parent is not self.started_branch.fromPort.parent:  # forbid connecting to itself

                        self.started_branch.setToPort(item)
                        item.hosting_connections.append(self.started_branch)
                        self.started_branch.bus_to = item.parent

                        if self.started_branch.bus_from.api_object.is_dc != self.started_branch.bus_to.api_object.is_dc:
                            # different DC status -> VSC

                            name = 'VSC ' + str(len(self.circuit.vsc_devices) + 1)
                            obj = VSC(bus_from=self.started_branch.bus_from.api_object,
                                      bus_to=self.started_branch.bus_to.api_object,
                                      name=name)

                            obj.graphic_obj = VscGraphicItem(fromPort=self.started_branch.fromPort,
                                                             toPort=self.started_branch.toPort,
                                                             diagramScene=self.diagramScene,
                                                             branch=obj)

                        elif self.started_branch.bus_from.api_object.is_dc and self.started_branch.bus_to.api_object.is_dc:
                            # both buses are DC

                            name = 'Dc line ' + str(len(self.circuit.dc_lines) + 1)
                            obj = DcLine(bus_from=self.started_branch.bus_from.api_object,
                                         bus_to=self.started_branch.bus_to.api_object,
                                         name=name)

                            obj.graphic_obj = DcLineGraphicItem(fromPort=self.started_branch.fromPort,
                                                                toPort=self.started_branch.toPort,
                                                                diagramScene=self.diagramScene,
                                                                branch=obj)

                        else:
                            # Same DC status -> line / trafo
                            v1 = self.started_branch.bus_from.api_object.Vnom
                            v2 = self.started_branch.bus_to.api_object.Vnom

                            if abs(v1 - v2) > 1.0:
                                name = 'Transformer ' + str(len(self.circuit.transformers2w) + 1)
                                obj = Transformer2W(bus_from=self.started_branch.bus_from.api_object,
                                                    bus_to=self.started_branch.bus_to.api_object,
                                                    name=name)

                                obj.graphic_obj = TransformerGraphicItem(fromPort=self.started_branch.fromPort,
                                                                         toPort=self.started_branch.toPort,
                                                                         diagramScene=self.diagramScene,
                                                                         branch=obj)

                            else:
                                name = 'Line ' + str(len(self.circuit.lines) + 1)
                                obj = Line(bus_from=self.started_branch.bus_from.api_object,
                                           bus_to=self.started_branch.bus_to.api_object,
                                           name=name)

                                obj.graphic_obj = LineGraphicItem(fromPort=self.started_branch.fromPort,
                                                                  toPort=self.started_branch.toPort,
                                                                  diagramScene=self.diagramScene,
                                                                  branch=obj)

                        # add the new object to the circuit
                        self.circuit.add_branch(obj)

                        # update the connection placement
                        obj.graphic_obj.fromPort.update()
                        obj.graphic_obj.toPort.update()

                        # set the connection placement
                        obj.graphic_obj.setZValue(-1)

            # if self.started_branch.toPort is None:
            self.started_branch.remove_widget()

        # release this pointer
        self.started_branch = None

    def bigger_nodes(self):
        """
        Expand the grid
        @return:
        """
        min_x = sys.maxsize
        min_y = sys.maxsize
        max_x = -sys.maxsize
        max_y = -sys.maxsize

        if len(self.diagramScene.selectedItems()) > 0:

            # expand selection
            for item in self.diagramScene.selectedItems():
                if type(item) is BusGraphicItem:
                    x = item.pos().x() * self.expand_factor
                    y = item.pos().y() * self.expand_factor
                    item.setPos(QPointF(x, y))

                    # apply changes to the API objects
                    if item.api_object is not None:
                        item.api_object.x = x
                        item.api_object.y = y

                    max_x = max(max_x, x)
                    min_x = min(min_x, x)
                    max_y = max(max_y, y)
                    min_y = min(min_y, y)

        else:

            # expand all
            for item in self.diagramScene.items():
                if type(item) is BusGraphicItem:
                    x = item.pos().x() * self.expand_factor
                    y = item.pos().y() * self.expand_factor
                    item.setPos(QPointF(x, y))

                    max_x = max(max_x, x)
                    min_x = min(min_x, x)
                    max_y = max(max_y, y)
                    min_y = min(min_y, y)

                    # apply changes to the API objects
                    if item.api_object is not None:
                        item.api_object.x = x
                        item.api_object.y = y

        # set the limits of the view
        self.set_limits(min_x, max_x, min_y, max_y)

    def smaller_nodes(self):
        """
        Contract the grid
        @return:
        """
        min_x = sys.maxsize
        min_y = sys.maxsize
        max_x = -sys.maxsize
        max_y = -sys.maxsize

        if len(self.diagramScene.selectedItems()) > 0:

            # shrink selection only
            for item in self.diagramScene.selectedItems():
                if type(item) is BusGraphicItem:
                    x = item.pos().x() / self.expand_factor
                    y = item.pos().y() / self.expand_factor
                    item.setPos(QPointF(x, y))

                    # apply changes to the API objects
                    if item.api_object is not None:
                        item.api_object.x = x
                        item.api_object.y = y

                    max_x = max(max_x, x)
                    min_x = min(min_x, x)
                    max_y = max(max_y, y)
                    min_y = min(min_y, y)
        else:

            # shrink all
            for item in self.diagramScene.items():
                if type(item) is BusGraphicItem:
                    x = item.pos().x() / self.expand_factor
                    y = item.pos().y() / self.expand_factor
                    item.setPos(QPointF(x, y))

                    # apply changes to the API objects
                    if item.api_object is not None:
                        item.api_object.x = x
                        item.api_object.y = y

                    max_x = max(max_x, x)
                    min_x = min(min_x, x)
                    max_y = max(max_y, y)
                    min_y = min(min_y, y)

        # set the limits of the view
        self.set_limits(min_x, max_x, min_y, max_y)

    def set_limits(self, min_x, max_x, min_y, max_y, margin_factor=0.1):
        """
        Set the picture limits
        :param min_x: Minimum x value of the buses location
        :param max_x: Maximum x value of the buses location
        :param min_y: Minimum y value of the buses location
        :param max_y: Maximum y value of the buses location
        :param margin_factor: factor of separation between the buses
        """
        dx = max_x - min_x
        dy = max_y - min_y
        mx = margin_factor * dx
        my = margin_factor * dy
        h = dy + 2 * my + 80
        w = dx + 2 * mx + 80
        self.diagramScene.setSceneRect(min_x - mx, min_y - my, w, h)

    def center_nodes(self):
        """
        Center the view in the nodes
        @return: Nothing
        """
        self.diagramView.fitInView(self.diagramScene.sceneRect(), Qt.KeepAspectRatio)
        self.diagramView.scale(1.0, 1.0)

    def auto_layout(self):
        """
        Automatic layout of the nodes
        """

        if self.circuit.graph is None:
            self.circuit.build_graph()

        pos = nx.spectral_layout(self.circuit.graph, scale=2, weight='weight')

        pos = nx.fruchterman_reingold_layout(self.circuit.graph, dim=2,
                                             k=None, pos=pos, fixed=None, iterations=500,
                                             weight='weight', scale=20.0, center=None)

        # assign the positions to the graphical objects of the nodes
        for i, bus in enumerate(self.circuit.buses):
            try:
                x, y = pos[i] * 500
                bus.graphic_obj.setPos(QPoint(x, y))

                # apply changes to the API objects
                bus.x = x
                bus.y = y

            except KeyError as ex:
                warn('auto_layout: Node ' + str(i) + ' not in the graph!!!! \n' + str(ex))

        self.center_nodes()

    def export(self, filename, w=1920, h=1080):
        """
        Save the grid to a png file
        """

        name, extension = os.path.splitext(filename.lower())

        if extension == '.png':
            image = QImage(w, h, QImage.Format_ARGB32_Premultiplied)
            image.fill(Qt.transparent)
            painter = QPainter(image)
            painter.setRenderHint(QPainter.Antialiasing)
            self.diagramScene.render(painter)
            image.save(filename)
            painter.end()

        elif extension == '.svg':
            svg_gen = QSvgGenerator()
            svg_gen.setFileName(filename)
            svg_gen.setSize(QSize(w, h))
            svg_gen.setViewBox(QRect(0, 0, w, h))
            svg_gen.setTitle("Electrical grid schematic")
            svg_gen.setDescription("An SVG drawing created by GridCal")

            painter = QPainter(svg_gen)
            self.diagramScene.render(painter)
            painter.end()
        else:
            raise Exception('Extension ' + str(extension) + ' not supported :(')

    def add_line(self, branch: Line):
        """
        Add branch to the schematic
        :param branch: Branch object
        """
        terminal_from = branch.bus_from.graphic_obj.terminal
        terminal_to = branch.bus_to.graphic_obj.terminal
        graphic_obj = LineGraphicItem(terminal_from, terminal_to, self.diagramScene, branch=branch)
        graphic_obj.diagramScene.circuit = self.circuit  # add pointer to the circuit
        terminal_from.hosting_connections.append(graphic_obj)
        terminal_to.hosting_connections.append(graphic_obj)
        graphic_obj.redraw()
        branch.graphic_obj = graphic_obj

    def add_dc_line(self, branch: DcLine):
        """
        Add branch to the schematic
        :param branch: Branch object
        """
        terminal_from = branch.bus_from.graphic_obj.terminal
        terminal_to = branch.bus_to.graphic_obj.terminal
        graphic_obj = DcLineGraphicItem(terminal_from, terminal_to, self.diagramScene, branch=branch)
        graphic_obj.diagramScene.circuit = self.circuit  # add pointer to the circuit
        terminal_from.hosting_connections.append(graphic_obj)
        terminal_to.hosting_connections.append(graphic_obj)
        graphic_obj.redraw()
        branch.graphic_obj = graphic_obj

    def add_transformer(self, branch: Transformer2W):
        """
        Add branch to the schematic
        :param branch: Branch object
        """
        terminal_from = branch.bus_from.graphic_obj.terminal
        terminal_to = branch.bus_to.graphic_obj.terminal
        graphic_obj = TransformerGraphicItem(terminal_from, terminal_to, self.diagramScene, branch=branch)
        graphic_obj.diagramScene.circuit = self.circuit  # add pointer to the circuit
        terminal_from.hosting_connections.append(graphic_obj)
        terminal_to.hosting_connections.append(graphic_obj)
        graphic_obj.redraw()
        branch.graphic_obj = graphic_obj

    def add_api_bus(self, bus: Bus, explode_factor=1.0):
        """
        Add API bus to the diagram
        :param bus: Bus instance
        :param explode_factor: explode factor
        """
        # add the graphic object to the diagram view
        graphic_obj = self.diagramView.add_bus(bus=bus, explode_factor=explode_factor)

        # add circuit pointer to the bus graphic element
        graphic_obj.diagramScene.circuit = self.circuit  # add pointer to the circuit

        # create the bus children
        graphic_obj.create_children_icons()

        # arrange the children
        graphic_obj.arrange_children()

        return graphic_obj

    def add_api_line(self, branch: Line):
        """
        add API branch to the Scene
        :param branch: Branch instance
        """
        terminal_from = branch.bus_from.graphic_obj.terminal
        terminal_to = branch.bus_to.graphic_obj.terminal

        graphic_obj = LineGraphicItem(terminal_from, terminal_to, self.diagramScene, branch=branch)

        graphic_obj.diagramScene.circuit = self.circuit  # add pointer to the circuit
        terminal_from.hosting_connections.append(graphic_obj)
        terminal_to.hosting_connections.append(graphic_obj)
        graphic_obj.redraw()

        return graphic_obj

    def add_api_dc_line(self, branch: DcLine):
        """
        add API branch to the Scene
        :param branch: Branch instance
        """
        terminal_from = branch.bus_from.graphic_obj.terminal
        terminal_to = branch.bus_to.graphic_obj.terminal

        graphic_obj = DcLineGraphicItem(terminal_from, terminal_to, self.diagramScene, branch=branch)

        graphic_obj.diagramScene.circuit = self.circuit  # add pointer to the circuit
        terminal_from.hosting_connections.append(graphic_obj)
        terminal_to.hosting_connections.append(graphic_obj)
        graphic_obj.redraw()

        return graphic_obj

    def add_api_hvdc(self, branch: HvdcLine):
        """
        add API branch to the Scene
        :param branch: Branch instance
        """
        terminal_from = branch.bus_from.graphic_obj.terminal
        terminal_to = branch.bus_to.graphic_obj.terminal

        graphic_obj = HvdcGraphicItem(terminal_from, terminal_to, self.diagramScene, branch=branch)

        graphic_obj.diagramScene.circuit = self.circuit  # add pointer to the circuit
        terminal_from.hosting_connections.append(graphic_obj)
        terminal_to.hosting_connections.append(graphic_obj)
        graphic_obj.redraw()

        return graphic_obj

    def add_api_vsc(self, branch: VSC):
        """
        add API branch to the Scene
        :param branch: Branch instance
        """
        terminal_from = branch.bus_from.graphic_obj.terminal
        terminal_to = branch.bus_to.graphic_obj.terminal

        graphic_obj = VscGraphicItem(terminal_from, terminal_to, self.diagramScene, branch=branch)

        graphic_obj.diagramScene.circuit = self.circuit  # add pointer to the circuit
        terminal_from.hosting_connections.append(graphic_obj)
        terminal_to.hosting_connections.append(graphic_obj)
        graphic_obj.redraw()

        return graphic_obj

    def add_api_upfc(self, branch: UPFC):
        """
        add API branch to the Scene
        :param branch: Branch instance
        """
        terminal_from = branch.bus_from.graphic_obj.terminal
        terminal_to = branch.bus_to.graphic_obj.terminal

        graphic_obj = UpfcGraphicItem(terminal_from, terminal_to, self.diagramScene, branch=branch)

        graphic_obj.diagramScene.circuit = self.circuit  # add pointer to the circuit
        terminal_from.hosting_connections.append(graphic_obj)
        terminal_to.hosting_connections.append(graphic_obj)
        graphic_obj.redraw()

        return graphic_obj

    def add_api_transformer(self, branch: Transformer2W):
        """
        add API branch to the Scene
        :param branch: Branch instance
        """
        terminal_from = branch.bus_from.graphic_obj.terminal
        terminal_to = branch.bus_to.graphic_obj.terminal

        graphic_obj = TransformerGraphicItem(terminal_from, terminal_to, self.diagramScene, branch=branch)

        graphic_obj.diagramScene.circuit = self.circuit  # add pointer to the circuit
        terminal_from.hosting_connections.append(graphic_obj)
        terminal_to.hosting_connections.append(graphic_obj)
        graphic_obj.redraw()

        return graphic_obj

    def convert_line_to_hvdc(self, line: Line):
        """
        Convert a line to HVDC, this is the GUI way to create HVDC objects
        :param line: Line instance
        :return: Nothing
        """
        hvdc = HvdcLine(bus_from=line.bus_from,
                        bus_to=line.bus_to,
                        name='HVDC Line',
                        active=line.active,
                        rate=line.rate,
                        active_prof=line.active_prof,
                        rate_prof=line.rate_prof)

        # add device to the circuit
        self.circuit.add_hvdc(hvdc)

        # add device to the schematic
        hvdc.graphic_obj = self.add_api_hvdc(hvdc)

        # update position
        hvdc.graphic_obj.fromPort.update()
        hvdc.graphic_obj.toPort.update()

        # delete the line from the circuit
        self.circuit.delete_line(line)

        # delete from the schematic
        self.diagramScene.removeItem(line.graphic_obj)

    def convert_line_to_transformer(self, line: Line):
        """
        Convert a line to Transformer
        :param line: Line instance
        :return: Nothing
        """
        transformer = Transformer2W(bus_from=line.bus_from,
                                    bus_to=line.bus_to,
                                    name='Transformer',
                                    active=line.active,
                                    rate=line.rate,
                                    r=line.R,
                                    x=line.X,
                                    b=line.B,
                                    active_prof=line.active_prof,
                                    rate_prof=line.rate_prof)

        # add device to the circuit
        self.circuit.add_transformer2w(transformer)

        # add device to the schematic
        transformer.graphic_obj = self.add_api_transformer(transformer)

        # update position
        transformer.graphic_obj.fromPort.update()
        transformer.graphic_obj.toPort.update()

        # delete the line from the circuit
        self.circuit.delete_line(line)

        # delete from the schematic
        self.diagramScene.removeItem(line.graphic_obj)

    def convert_line_to_vsc(self, line: Line):
        """
        Convert a line to voltage source converter
        :param line: Line instance
        :return: Nothing
        """
        vsc = VSC(bus_from=line.bus_from,
                  bus_to=line.bus_to,
                  name='VSC',
                  active=line.active,
                  rate=line.rate,
                  r1=line.R,
                  x1=line.X,
                  Beq=line.B,
                  m=1.0,
                  active_prof=line.active_prof,
                  rate_prof=line.rate_prof)

        # add device to the circuit
        self.circuit.add_vsc(vsc)

        # add device to the schematic
        vsc.graphic_obj = self.add_api_vsc(vsc)

        # update position
        vsc.graphic_obj.fromPort.update()
        vsc.graphic_obj.toPort.update()

        # delete the line from the circuit
        self.circuit.delete_line(line)

        # delete from the schematic
        self.diagramScene.removeItem(line.graphic_obj)

    def convert_line_to_upfc(self, line: Line):
        """
        Convert a line to voltage source converter
        :param line: Line instance
        :return: Nothing
        """
        upfc = UPFC(bus_from=line.bus_from,
                    bus_to=line.bus_to,
                    name='UPFC',
                    active=line.active,
                    rate=line.rate,
                    rl=line.R,
                    xl=line.X,
                    bl=line.B,
                    active_prof=line.active_prof,
                    rate_prof=line.rate_prof)

        # add device to the circuit
        self.circuit.add_upfc(upfc)

        # add device to the schematic
        upfc.graphic_obj = self.add_api_upfc(upfc)

        # update position
        upfc.graphic_obj.fromPort.update()
        upfc.graphic_obj.toPort.update()

        # delete the line from the circuit
        self.circuit.delete_line(line)

        # delete from the schematic
        self.diagramScene.removeItem(line.graphic_obj)

    def add_elements_to_schematic(self, buses, lines, dc_lines, transformers2w, hvdc_lines, vsc_devices,
                                  upfc_devices, explode_factor=1.0, prog_func=None, text_func=None):
        """
        Add a elements to the schematic scene
        :param buses: list of Bus objects
        :param lines: list of Line objects
        :param dc_lines: list of DcLine objects
        :param transformers2w: list of Transformer Objects
        :param hvdc_lines: list of HvdcLine objects
        :param vsc_devices: list Vsc objects
        :param explode_factor: factor of "explosion": Separation of the nodes factor
        :param prog_func: progress report function
        :param text_func: Text report function
        """
        # first create the buses
        if text_func is not None:
            text_func('Creating schematic buses')

        nn = len(buses)
        for i, bus in enumerate(buses):

            if prog_func is not None:
                prog_func((i+1) / nn * 100.0)

            bus.graphic_obj = self.add_api_bus(bus, explode_factor)

        # --------------------------------------------------------------------------------------------------------------
        if text_func is not None:
            text_func('Creating schematic line devices')

        nn = len(lines)
        for i, branch in enumerate(lines):

            if prog_func is not None:
                prog_func((i+1) / nn * 100.0)

            branch.graphic_obj = self.add_api_line(branch)

        # --------------------------------------------------------------------------------------------------------------
        if text_func is not None:
            text_func('Creating schematic line devices')

        nn = len(dc_lines)
        for i, branch in enumerate(dc_lines):

            if prog_func is not None:
                prog_func((i + 1) / nn * 100.0)

            branch.graphic_obj = self.add_api_dc_line(branch)

        # --------------------------------------------------------------------------------------------------------------
        if text_func is not None:
            text_func('Creating schematic transformer devices')

        nn = len(transformers2w)
        for i, branch in enumerate(transformers2w):

            if prog_func is not None:
                prog_func((i + 1) / nn * 100.0)

            branch.graphic_obj = self.add_api_transformer(branch)

        # --------------------------------------------------------------------------------------------------------------
        if text_func is not None:
            text_func('Creating schematic HVDC devices')

        nn = len(hvdc_lines)
        for i, branch in enumerate(hvdc_lines):

            if prog_func is not None:
                prog_func((i + 1) / nn * 100.0)

            branch.graphic_obj = self.add_api_hvdc(branch)

        # --------------------------------------------------------------------------------------------------------------
        if text_func is not None:
            text_func('Creating schematic VSC devices')

        nn = len(vsc_devices)
        for i, branch in enumerate(vsc_devices):

            if prog_func is not None:
                prog_func((i + 1) / nn * 100.0)

            branch.graphic_obj = self.add_api_vsc(branch)

        # --------------------------------------------------------------------------------------------------------------
        if text_func is not None:
            text_func('Creating schematic UPFC devices')

        nn = len(upfc_devices)
        for i, branch in enumerate(upfc_devices):

            if prog_func is not None:
                prog_func((i + 1) / nn * 100.0)

            branch.graphic_obj = self.add_api_upfc(branch)

    def add_circuit_to_schematic(self, circuit: "MultiCircuit", explode_factor=1.0, prog_func=None, text_func=None):
        """
        Add a complete circuit to the schematic scene
        :param circuit: MultiCircuit instance
        :param explode_factor: factor of "explosion": Separation of the nodes factor
        :param prog_func: progress report function
        :param text_func: Text report function
        """

        self.add_elements_to_schematic(buses=circuit.buses,
                                       lines=circuit.lines,
                                       dc_lines=circuit.dc_lines,
                                       transformers2w=circuit.transformers2w,
                                       hvdc_lines=circuit.hvdc_lines,
                                       vsc_devices=circuit.vsc_devices,
                                       upfc_devices=circuit.upfc_devices,
                                       explode_factor=explode_factor,
                                       prog_func=prog_func,
                                       text_func=text_func)

    def align_schematic(self):
        """
        Align the scene view to the content
        """
        # figure limits
        min_x = sys.maxsize
        min_y = sys.maxsize
        max_x = -sys.maxsize
        max_y = -sys.maxsize

        # Align lines
        for bus in self.circuit.buses:
            bus.graphic_obj.arrange_children()
            # get the item position
            x = bus.graphic_obj.pos().x()
            y = bus.graphic_obj.pos().y()

            # compute the boundaries of the grid
            max_x = max(max_x, x)
            min_x = min(min_x, x)
            max_y = max(max_y, y)
            min_y = min(min_y, y)

        # set the figure limits
        self.set_limits(min_x, max_x, min_y, max_y)

        #  center the view
        self.center_nodes()

    def schematic_from_api(self, explode_factor=1.0, prog_func=None, text_func=None):
        """
        Generate schematic from the API
        :param explode_factor: factor to separate the nodes
        :param prog_func: progress report function
        :param text_func: Text report function
        :return: Nothing
        """
        # clear all
        self.diagramView.scene_.clear()

        # add to schematic
        self.add_circuit_to_schematic(self.circuit,
                                      explode_factor=explode_factor,
                                      prog_func=prog_func,
                                      text_func=text_func)

        if text_func is not None:
            text_func('Aligning schematic...')

        self.align_schematic()