Source code for pyleecan.GUI.Dxf.DXF_Hole

from logging import getLogger
from os.path import dirname, isfile, splitext, basename
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import (
    FigureCanvasQTAgg,
    NavigationToolbar2QT as NavigationToolbar,
)
from ezdxf import readfile
import numpy as np
from PySide2.QtCore import QUrl, Qt
from PySide2.QtGui import QIcon, QPixmap, QDesktopServices
from PySide2.QtWidgets import (
    QComboBox,
    QDialog,
    QFileDialog,
    QMessageBox,
    QPushButton,
    QHeaderView,
)
from ...Classes.HoleUD import HoleUD
from ...Classes.Magnet import Magnet
from ...Classes.SurfLine import SurfLine
from ...GUI.Dxf.dxf_to_pyleecan import dxf_to_pyleecan_list, convert_dxf_with_FEMM
from ...GUI.Resources import pixmap_dict
from ...GUI.Tools.MPLCanvas import MPLCanvas
from ...GUI.Tools.FloatEdit import FloatEdit
from ...GUI import gui_option
from ...loggers import GUI_LOG_NAME
from .Ui_DXF_Hole import Ui_DXF_Hole
from ...Functions.labels import HOLEM_LAB, HOLEV_LAB
from ...Functions.init_fig import init_fig

# Column index for table

DEL_COL = 0
HL_COL = 1
TYPE_COL = 2
REF_COL = 3
OFF_COL = 4

ICON_SIZE = 24
# Unselected, selected, selected-bottom-mag
COLOR_LIST = ["k", "r", "c"]
Z_TOL = 1e-4  # Point comparison tolerance
AUTO_SELECT = True
IS_ADD_LINE_ID = False  # For debug


[docs]class DXF_Hole(Ui_DXF_Hole, QDialog): """Dialog to create HoleUD objects from DXF files""" convert_dxf_with_FEMM = convert_dxf_with_FEMM def __init__(self, dxf_path=None, Zh=None, Lmag=None, lam=None): """Initialize the Dialog Parameters ---------- self : DXF_Hole a DXF_Hole object dxf_path : str Path to a dxf file to read """ # Widget setup QDialog.__init__(self) self.setupUi(self) # Icon preparation self.delete_icon = QPixmap(pixmap_dict["cross"]) self.delete_icon.scaled(ICON_SIZE, ICON_SIZE, Qt.KeepAspectRatio) self.highlight_icon = QPixmap(pixmap_dict["search"]) self.highlight_icon.scaled(ICON_SIZE, ICON_SIZE, Qt.KeepAspectRatio) # Tutorial video link self.url = "https://pyleecan.org/videos.html#feature-tutorials" self.b_tuto.setEnabled(True) # Set units self.lf_mag_len.unit = "m" wid_list = [ self.unit_mag_len, ] for wid in wid_list: wid.setText("[" + gui_option.unit.get_m_name() + "]") # Initialize the graph self.init_graph() # Not used yet self.lf_axe_angle.hide() self.in_axe_angle.hide() self.unit_axe_angle.hide() # Set default values if Zh is not None: self.si_Zh.setValue(Zh) if Lmag is not None: self.lf_mag_len.setValue(Lmag) if lam is None: self.lam = lam else: self.lam = lam.copy() # Init properties self.line_list = list() # List of lines from DXF self.selected_line = np.array([]) # Array of selected lines indices self.surf_list = list() # List of defined surfaces self.Zcenter = 0 # For translate offset # Connection related variables # matrix of points coordinates (ndarray[Npoint, 2]) self.point_coord = None # start point id (in point_coord) and end point id for each line (ndarray[Nline, 2]) self.line2point = None # lines id (in line_list) connected to each point (list[Npoints, n]) self.point2line = None # Set DXF edit widget self.lf_center_x.setValue(0) self.lf_center_y.setValue(0) self.lf_scaling.validator().setBottom(0) self.lf_scaling.setValue(1) # Load the DXF file if provided self.dxf_path = dxf_path if dxf_path is not None and isfile(dxf_path): self.open_document() # Setup Path selector for DXF files self.w_path_selector.obj = self self.w_path_selector.param_name = "dxf_path" self.w_path_selector.verbose_name = "DXF File" self.w_path_selector.extension = "DXF file (*.dxf)" self.w_path_selector.set_path_txt(self.dxf_path) self.w_path_selector.update() # Set table column width header = self.w_surface_list.horizontalHeader() header.setSectionResizeMode(DEL_COL, QHeaderView.ResizeToContents) header.setSectionResizeMode(HL_COL, QHeaderView.ResizeToContents) header.setSectionResizeMode(TYPE_COL, QHeaderView.ResizeToContents) header.setSectionResizeMode(REF_COL, QHeaderView.ResizeToContents) header.setSectionResizeMode(OFF_COL, QHeaderView.ResizeToContents) # Connect signals to slot self.w_path_selector.pathChanged.connect(self.open_document) self.b_save.pressed.connect(self.save) self.b_plot.pressed.connect(self.plot) self.b_reset.pressed.connect(self.update_graph) self.b_cancel.pressed.connect(self.remove_selection) self.b_tuto.pressed.connect(self.open_tuto) self.is_convert.toggled.connect(self.enable_tolerance) self.lf_center_x.editingFinished.connect(self.set_center) self.lf_center_y.editingFinished.connect(self.set_center) # Display the GUI self.show()
[docs] def enable_tolerance(self): """Enable/Disable tolerance widget""" self.lf_tol.setEnabled(self.is_convert.isChecked()) self.in_tol.setEnabled(self.is_convert.isChecked())
[docs] def open_document(self): """Open a new dxf in the viewer Parameters ---------- self : DXF_Hole a DXF_Hole object """ # Check convertion if self.is_convert.isChecked() and "_converted" not in basename(self.dxf_path): getLogger(GUI_LOG_NAME).info("Converting dxf file: " + self.dxf_path) self.dxf_path = self.convert_dxf_with_FEMM( self.dxf_path, self.lf_tol.value() ) self.w_path_selector.blockSignals(True) self.w_path_selector.set_path_txt(self.dxf_path) self.w_path_selector.blockSignals(False) getLogger(GUI_LOG_NAME).debug("Reading dxf file: " + self.dxf_path) # Read the DXF file try: document = readfile(self.dxf_path) modelspace = document.modelspace() # Convert DXF to pyleecan objects self.line_list = dxf_to_pyleecan_list(modelspace) # selected line: 0: unselected, 1:selected, 2: selected bottom magnet self.selected_line = np.zeros(len(self.line_list), dtype=int) self.surf_list = list() self.w_surface_list.setRowCount(0) # Calculate connection matrix and matrix of points coordinates if AUTO_SELECT: self.comp_connection() # Display self.update_graph() except Exception as e: QMessageBox().critical( self, self.tr("Error"), self.tr("Error while reading dxf file:\n" + str(e)), )
[docs] def comp_connection(self): """Calculate connection matrices: - line2point: start point id and end point id for each line (ndarray[Nline, 2]) - point2lines: lines id connected to each point (list[Npoints, n]) - point_coord: matrix of points coordinates (ndarray[Npoint, 2]) Parameters ---------- self : DXF_Hole a DXF_Hole object """ line2point = np.zeros((len(self.line_list), 2), dtype=int) point_coord = list() point2line = list() for ii, line in enumerate(self.line_list): # Add begin point point_begin = line.get_begin() # Tolerance to avoid duplicate points index = np.where(np.abs(np.array(point_coord) - point_begin) < Z_TOL)[0] if len(index) == 1: point_id = index[0] line2point[ii, 0] = point_id point2line[point_id].append(ii) else: point_coord.append(point_begin) line2point[ii, 0] = len(point_coord) - 1 point2line.append([ii]) # Add end point point_end = line.get_end() index = np.where(np.abs(np.array(point_coord) - point_end) < Z_TOL)[0] if len(index) == 1: point_id = index[0] line2point[ii, 1] = point_id point2line[point_id].append(ii) else: point_coord.append(point_end) line2point[ii, 1] = len(point_coord) - 1 point2line.append([ii]) # Store connection matrix for later use self.line2point = line2point self.point2line = point2line # Convert point list to matrix point_coord = np.array(point_coord, dtype=complex) self.point_coord = np.zeros((point_coord.size, 2)) self.point_coord[:, 0] = np.real(point_coord) self.point_coord[:, 1] = np.imag(point_coord)
[docs] def get_closest_line_id(self, X, Y): """Get closest line id to input X and Y coordinates Parameters ---------- self : DXF_Hole a DXF_Hole object X: float x coordinate Y: float y coordinate """ point2line = self.point2line line_list = self.line_list # Get 10 closest points to click coordinates x = self.point_coord[:, 0] y = self.point_coord[:, 1] Npts = min([10, x.size]) Ipts = np.argpartition((x - X) ** 2 + (y - Y) ** 2, Npts)[:Npts] # Find all line indices containing 10 closest Ilin = list() for ii in Ipts: Ilin.extend(point2line[ii]) Ilin = np.unique(Ilin) # Find id of closest line Z = X + 1j * Y # XY position as complex number point_dist = [line_list[ii].comp_distance(Z) for ii in Ilin] closest_id = Ilin[np.argmin(point_dist)] return closest_id
[docs] def get_connected_lines(self, connected_lines, lin_curr, pt_curr): """Get connected lines to the current line starting at the current point (need to call method on both end points of the lines) return if the connected lines results in a closed surface and extend connected_lines Parameters ---------- self : DXF_Hole a DXF_Hole object connected_lines: list List of line index connected to current line and point lin_curr: int current line id pt_curr: int current point id Results ---------- is_closed: bool True if the connected lines results in a closed surface """ line2point = self.line2point point2line = self.point2line is_closed = False is_next = True # Is there another line to select while is_next: l_i = point2line[pt_curr] # list of line connected to the point if len(l_i) == 2: # We select the next line only if the point is connected to 2 lines next_line = l_i[0] if l_i[1] == lin_curr else l_i[1] if next_line not in connected_lines: connected_lines.append(next_line) lin_curr = next_line p_i = line2point[lin_curr] pt_curr = p_i[0] if p_i[1] == pt_curr else p_i[1] else: # Next line is already in connected lines is_next = False is_closed = True else: is_next = False return is_closed
[docs] def init_graph(self): """Initialize the viewer Parameters ---------- self : DXF_Hole a DXF_Hole object """ # Init fig fig, axes = plt.subplots(tight_layout=False) self.fig = fig self.axes = axes # Set plot layout canvas = FigureCanvasQTAgg(fig) toolbar = NavigationToolbar(canvas, self) # Remove Subplots button unwanted_buttons = ["Subplots", "Customize", "Save"] for x in toolbar.actions(): if x.text() in unwanted_buttons: toolbar.removeAction(x) # Adding custom icon on mpl toobar icons_buttons = [ "Home", "Pan", "Zoom", "Back", "Forward", ] for action in toolbar.actions(): if action.text() in icons_buttons and "mpl_" + action.text() in pixmap_dict: action.setIcon(QIcon(pixmap_dict["mpl_" + action.text()])) # Change default file name canvas.get_default_filename = "DXF_hole_visu.png" self.layout_plot.insertWidget(1, toolbar) self.layout_plot.insertWidget(2, canvas) self.canvas = canvas axes.set_axis_off() self.toolbar = toolbar self.xlim = self.axes.get_xlim() self.ylim = self.axes.get_ylim() def on_draw(event): self.xlim = self.axes.get_xlim() self.ylim = self.axes.get_ylim() # Setup interaction with graph def select_line(event): """Function to select/unselect the closest line from click""" # Ignore if matplotlib action is clicked is_ignore = False for action in self.toolbar.actions(): if action.isChecked(): is_ignore = True if not is_ignore: X = event.xdata # X position of the click Y = event.ydata # Y position of the click # Get id of closest line to click closest_id = self.get_closest_line_id(X, Y) connected_lines = [closest_id] is_closed = False # If the line is not already selected (else edit only the line) if self.selected_line[closest_id] == 0 and AUTO_SELECT: # Select all points starting from begin point lin_curr = closest_id pt_curr = self.line2point[closest_id, 0] is_closed = self.get_connected_lines( connected_lines, lin_curr, pt_curr ) # Select all points starting from end point if not is_closed: lin_curr = closest_id pt_curr = self.line2point[closest_id, 1] is_closed = self.get_connected_lines( connected_lines, lin_curr, pt_curr ) # Make sure that all the lines will be set to "1" for index in connected_lines: self.selected_line[index] = 0 # Select/unselect line (needed for add_surface) for id_line in connected_lines: if self.selected_line[id_line] == 0: # Unselected to selected self.selected_line[id_line] = 1 elif self.selected_line[id_line] == 1: # Selected to selected bottom mag Imag = np.where(self.selected_line == 2)[0] if Imag.size > 0: current_bot_mag = Imag[0] # Only one selected bottom mag line at the time point_list = np.array( self.line_list[current_bot_mag].discretize(20) ) self.selected_line[current_bot_mag] = 1 axes.plot( point_list.real, point_list.imag, COLOR_LIST[1], zorder=2, ) self.selected_line[id_line] = 2 elif self.selected_line[id_line] == 2: # selected bottom mag to Unselected self.selected_line[id_line] = 0 # Check if the surface is complete # (is_close=True: surface selected in one click) if is_closed or self.check_selection(): self.add_surface() else: # Update line color on plot for id_line in connected_lines: point_list = np.array(self.line_list[id_line].discretize(20)) color = COLOR_LIST[self.selected_line[id_line]] axes.plot(point_list.real, point_list.imag, color, zorder=2) self.axes.set_xlim(self.xlim) self.axes.set_ylim(self.ylim) self.canvas.draw() def zoom(event): """Function to zoom/unzoom according the mouse wheel""" base_scale = 0.8 # Scaling factor # get the current x and y limits ax = self.axes cur_xlim = ax.get_xlim() cur_ylim = ax.get_ylim() cur_xrange = (cur_xlim[1] - cur_xlim[0]) * 0.5 cur_yrange = (cur_ylim[1] - cur_ylim[0]) * 0.5 xdata = event.xdata # get event x location ydata = event.ydata # get event y location if event.button == "down": # deal with zoom in scale_factor = 1 / base_scale elif event.button == "up": # deal with zoom out scale_factor = base_scale else: # deal with something that should never happen scale_factor = 1 # set new limits ax.set_xlim( [xdata - cur_xrange * scale_factor, xdata + cur_xrange * scale_factor] ) ax.set_ylim( [ydata - cur_yrange * scale_factor, ydata + cur_yrange * scale_factor] ) self.canvas.draw() # force re-draw # Connect the function self.canvas.mpl_connect("draw_event", on_draw) self.canvas.mpl_connect("button_press_event", select_line) self.canvas.mpl_connect("scroll_event", zoom) # Axis cleanup axes.axis("equal") axes.set_axis_off()
[docs] def set_center(self): """Update the position of the center""" self.Zcenter = self.lf_center_x.value() + 1j * self.lf_center_y.value() self.update_graph()
[docs] def update_graph(self): """Clean and redraw all the lines in viewer Parameters ---------- self : DXF_Hole a DXF_Hole object """ _, axes = self.fig, self.axes axes.clear() axes.set_axis_off() # Draw the lines in the correct color for ii, line in enumerate(self.line_list): point_list = np.array(line.discretize(20)) color = COLOR_LIST[self.selected_line[ii]] axes.plot(point_list.real, point_list.imag, color, zorder=1) if IS_ADD_LINE_ID: Zmid = line.get_middle() axes.text(Zmid.real, Zmid.imag, str(ii)) # Add lamination center axes.plot(self.Zcenter.real, self.Zcenter.imag, "rx", zorder=0) axes.text(self.Zcenter.real, self.Zcenter.imag, "O") self.canvas.draw()
[docs] def check_selection(self): """Check if every line in the selection form a surface Parameters ---------- self : DXF_Hole a DXF_Hole object Returns ------- is_surf : bool True if it forms a surface """ Iselect = np.where(self.selected_line)[0] if len(Iselect) == 0: # No line selected return False # line2point contains index (int), no need for Z_tol _, count0 = np.unique(self.line2point[Iselect, :].ravel(), return_counts=True) return np.all(count0 == 2)
[docs] def sort_lines(self): """Sort selected lines so that current line's starting point is the same as previous line's ending point and that current line's ending point is the same as next line's start point Parameters ---------- self : DXF_Hole a DXF_Hole object Returns ------- curve_list : [Line] List of sorted lines str_list: [str] List of line indices as str (to be printed in combobox) """ Iselect = np.where(self.selected_line)[0] l2p = self.line2point p2l_select = list() for lines in self.point2line: if len(lines) == 2: p2l_select.append(lines) else: p2l_select.append([ll for ll in lines if ll in Iselect]) ii = Iselect[0] pt_start = l2p[ii, 0] pt_curr = l2p[ii, 1] index_list = [ii] curve_list = [self.line_list[ii].copy()] while pt_curr != pt_start: l_i = p2l_select[pt_curr] kk = l_i[1] if l_i[0] in index_list else l_i[0] index_list.append(kk) line_k = self.line_list[kk].copy() if pt_curr == l2p[kk, 0]: pt_curr = l2p[kk, 1] elif pt_curr == l2p[kk, 1]: pt_curr = l2p[kk, 0] line_k.reverse() curve_list.append(line_k) str_list = [str(kk) for kk in index_list] return curve_list, str_list
[docs] def add_surface(self): """Validate the selection and create a surface object Parameters ---------- self : DXF_Hole a DXF_Hole object """ # Sort the selected lines (begin = end) curve_list, str_list = self.sort_lines() # Create the Surface object self.surf_list.append(SurfLine(line_list=curve_list)) self.surf_list[-1].comp_point_ref(is_set=True) # Add a line in the Table nrows = self.w_surface_list.rowCount() self.w_surface_list.setRowCount(nrows + 1) # Adding Surface Type combobox combobox = QComboBox() combobox.addItems(["Hole", "Magnet"]) self.w_surface_list.setCellWidget( nrows, TYPE_COL, combobox, ) if np.any(self.selected_line == 2): combobox.setCurrentIndex(1) # Magnet combobox.currentIndexChanged.connect(self.enable_magnetization) # Adding Delete button del_button = QPushButton("") del_button.setIcon(QIcon(self.delete_icon)) del_button.pressed.connect(self.delete_surface) self.w_surface_list.setCellWidget( nrows, DEL_COL, del_button, ) # Adding Highlight button HL_button = QPushButton("") HL_button.setIcon(QIcon(self.highlight_icon)) HL_button.pressed.connect(self.highlight_surface) self.w_surface_list.setCellWidget( nrows, HL_COL, HL_button, ) # Add reference combobox combobox = QComboBox() combobox.addItems(str_list) self.w_surface_list.setCellWidget( nrows, REF_COL, combobox, ) Imag = np.where(self.selected_line == 2)[0] if Imag.size > 0: combobox.setCurrentIndex(str_list.index(str(Imag[0]))) else: combobox.setEnabled(False) # Add Offset FloatEdit lf_off = FloatEdit() lf_off.validator().setBottom(-360) lf_off.validator().setTop(360) lf_off.setValue(0) # lf_off.setText("0") lf_off.setEnabled(np.any(self.selected_line == 2)) self.w_surface_list.setCellWidget( nrows, OFF_COL, lf_off, ) # Remove selection to start new one self.remove_selection()
[docs] def enable_magnetization(self): """Enable/Disable the combobox/float edit for magnetization according to type""" for ii in range(self.w_surface_list.rowCount()): if self.w_surface_list.cellWidget(ii, TYPE_COL).currentIndex() == 0: self.w_surface_list.cellWidget(ii, REF_COL).setEnabled(False) self.w_surface_list.cellWidget(ii, OFF_COL).setEnabled(False) else: self.w_surface_list.cellWidget(ii, REF_COL).setEnabled(True) self.w_surface_list.cellWidget(ii, OFF_COL).setEnabled(True)
[docs] def remove_selection(self): # Remove selection self.selected_line = np.zeros(len(self.line_list), dtype=int) # Redraw all the lines (in black) for ii, line in enumerate(self.line_list): point_list = np.array(line.discretize(20)) color = COLOR_LIST[self.selected_line[ii]] self.axes.plot(point_list.real, point_list.imag, color, zorder=2) self.canvas.draw()
[docs] def get_hole(self): """Generate the HoleUD object corresponding to the selected surfaces Parameters ---------- self : DXF_Hole a DXF_Hole object Returns ------- hole : HoleUD User defined hole according to selected surfaces """ if self.lf_scaling.value() == 0: # Avoid error self.lf_scaling.setValue(1) hole = HoleUD(surf_list=[]) bottom_list = list() offset_list = list() # Set labels Nmag = 0 for ii in range(self.w_surface_list.rowCount()): hole.surf_list.append(self.surf_list[ii].copy()) hole.surf_list[ii].scale(self.lf_scaling.value()) if self.w_surface_list.cellWidget(ii, TYPE_COL).currentIndex() == 0: hole.surf_list[ii].label = HOLEV_LAB else: hole.surf_list[ii].label = HOLEM_LAB Nmag += 1 bottom_list.append( self.line_list[ int(self.w_surface_list.cellWidget(ii, REF_COL).currentText()) ] ) offset_list.append(self.w_surface_list.cellWidget(ii, OFF_COL).value()) # Create magnet objects hole.magnet_dict = dict() for ii in range(Nmag): hole.magnet_dict["magnet_" + str(ii)] = Magnet(type_magnetization=1) # Sort the surfaces angles = [np.angle(surf.point_ref) for surf in hole.surf_list] idx = sorted(range(len(angles)), key=lambda k: angles[k]) surf_list_sorted = [hole.surf_list[ii] for ii in idx] bottom_list_sorted = [bottom_list[ii] for ii in idx] offset_list_sorted = [offset_list[ii] for ii in idx] hole.surf_list = surf_list_sorted # Translate if self.Zcenter != 0: for surf in hole.surf_list: surf.translate(-self.Zcenter * self.lf_scaling.value()) # Rotation Zref = sum([surf.point_ref for surf in hole.surf_list]) for surf in hole.surf_list: surf.rotate(-1 * np.angle(Zref)) # Magnetization dict mag_dict = dict() Nmag = 0 for ii in range(len(hole.surf_list)): if HOLEM_LAB in hole.surf_list[ii].label: line = bottom_list_sorted[ii].copy() line.rotate(-1 * np.angle(Zref)) mag_dict["magnet_" + str(Nmag)] = line.comp_normal() mag_dict["magnet_" + str(Nmag)] += offset_list_sorted[ii] * np.pi / 180 Nmag += 1 hole.magnetization_dict_offset = mag_dict # Set metadata hole.Zh = self.si_Zh.value() for magnet in hole.magnet_dict.values(): magnet.Lmag = self.lf_mag_len.value() # Remove all materials => To be set in GUI hole.mat_void = None for magnet in hole.magnet_dict.values(): magnet.mat_type = None # Sort Hole then magnets # (for plot when Magnets are inside Hole surface) mag_list = list() hole_list = list() for surf in hole.surf_list: if HOLEM_LAB in surf.label: mag_list.append(surf) else: hole_list.append(surf) hole.surf_list = hole_list + mag_list # Correct hole ref_point (when Magnets are inside Hole surface) for surf in hole.surf_list: if HOLEV_LAB in surf.label: line_list = surf.get_lines() # Get middle list middle_array = np.array([line.get_middle() for line in line_list]) # Get the extrema line on the top or bottom of the hole if np.min(middle_array.imag) > 0 and np.max(middle_array.imag) > 0: start_idx = np.argmax(middle_array.imag) else: start_idx = np.argmin(middle_array.imag) # Get the two lines middle besides the extrema line middle if start_idx == 0: ref_mid = [middle_array[-1], middle_array[0], middle_array[1]] elif start_idx == len(line_list) - 1: ref_mid = [middle_array[-2], middle_array[-1], middle_array[0]] else: ref_mid = [ middle_array[start_idx - 1], middle_array[start_idx], middle_array[start_idx + 1], ] # Barycenter of these middles as new reference surf.point_ref = sum(ref_mid) / 3 return hole
[docs] def plot(self): """Plot the current state of the hole Parameters ---------- self : DXF_Hole a DXF_Hole object """ hole = self.get_hole() if self.lam is None: hole.plot(is_add_arrow=True) else: fig, (ax1, ax2) = plt.subplots(1, 2) hole.plot(fig=fig, ax=ax1, is_add_arrow=True, is_add_ref=False) self.lam.hole = [hole] self.lam.plot(fig=fig, ax=ax2)
[docs] def delete_surface(self): """Delete a selected surface Parameters ---------- self : DXF_Hole a DXF_Hole object """ nrow = self.w_surface_list.currentRow() self.surf_list.pop(nrow) self.w_surface_list.removeRow(nrow)
[docs] def highlight_surface(self): """Highlight a surface to find it on the viewer Parameters ---------- self : DXF_Hole a DXF_Hole object """ self.selected_line = np.zeros(len(self.line_list), dtype=int) surf = self.surf_list[self.w_surface_list.currentRow()] # Find the index of the surface line in self.line_list for surf_line in surf.line_list: mid = surf_line.get_middle() for ii, line in enumerate(self.line_list): if abs(mid - line.get_middle()) < Z_TOL: self.selected_line[ii] = 1 self.axes.text( mid.real, mid.imag, str(ii), # fontsize=fontsize, ) self.update_graph() # Add Label for ii in range(len(self.selected_line)): if self.selected_line[ii] == 1: Zmid = self.line_list[ii].get_middle() self.axes.text( Zmid.real, Zmid.imag, str(ii), # fontsize=fontsize, )
[docs] def save(self): """Save the HoleUD object in a json file Parameters ---------- self : DXF_Hole a DXF_Hole object """ hole = self.get_hole() save_file_path = QFileDialog.getSaveFileName( self, self.tr("Save file"), dirname(self.dxf_path), "Json (*.json)" )[0] if save_file_path not in ["", ".json", None]: self.save_path = save_file_path hole.name = splitext(basename(self.save_path))[0] try: hole.save(save_file_path) self.accept() except Exception as e: QMessageBox().critical( self, self.tr("Error"), self.tr("Error while saving hole json file:\n" + str(e)), )
[docs] def open_tuto(self): """Open the tutorial video in a web browser""" QDesktopServices.openUrl(QUrl(self.url))