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 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_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 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
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()