diff --git a/src/controller.py b/src/controller.py index b84db13..1acd514 100644 --- a/src/controller.py +++ b/src/controller.py @@ -19,8 +19,8 @@ from PyQt5 import QtCore, QtGui, QtWidgets from src import gui_utils, locales, qt_utils -from src.figure_editor import PlaneEditor, ConeEditor -from src.gui_utils import showErrorDialog, plane_tf, read_planes, Plane, Cone, showInfoDialog +from src.figure_editor import PlaneEditor, ConeEditor, CylinderEditor +from src.gui_utils import showErrorDialog, plane_tf, read_planes, Plane, Cone, Cylinder, showInfoDialog from src.process import Process from src.settings import sett, save_settings, load_settings, get_color, PathBuilder @@ -81,6 +81,7 @@ def _connect_signals(self): # bottom panel self.view.add_plane_button.clicked.connect(self.add_splane) self.view.add_cone_button.clicked.connect(self.add_cone) + self.view.add_cylinder_button.clicked.connect(self.add_cylinder) self.view.edit_figure_button.clicked.connect(self.change_figure_parameters) self.view.save_planes_button.clicked.connect(self.save_planes) self.view.download_planes_button.clicked.connect(self.download_planes) @@ -171,6 +172,8 @@ def change_figure_parameters(self): self.view.parameters_tooling = PlaneEditor(self.view.tabs, self.update_plane_common, self.model.splanes[ind].params()) elif isinstance(self.model.splanes[ind], Cone): self.view.parameters_tooling = ConeEditor(self.view.tabs, self.update_cone_common, self.model.splanes[ind].params()) + elif isinstance(self.model.splanes[ind], Cylinder): + self.view.parameters_tooling = CylinderEditor(self.view.tabs, self.update_cylinder_common, self.model.splanes[ind].params()) def save_planes(self): try: @@ -559,6 +562,12 @@ def add_cone(self): self.view.reload_splanes(self.model.splanes) self.change_figure_parameters() + def add_cylinder(self): + self.view.hide_checkbox.setChecked(False) + self.model.add_cylinder() + self.view.reload_splanes(self.model.splanes) + self.change_figure_parameters() + def remove_splane(self): self.view.hide_checkbox.setChecked(False) ind = self.view.splanes_tree.currentIndex().row() @@ -609,6 +618,17 @@ def update_cone_common(self, values: Dict[str, float]): self.view.splanes_tree.topLevelItem(i).setText(1, str(i + 1)) self.view.splanes_tree.topLevelItem(i).setText(2, self.model.splanes[i].toFile()) + def update_cylinder_common(self, values: Dict[str, float]): + ind = self.view.splanes_tree.currentIndex().row() + if ind == -1: + return + self.model.splanes[ind] = gui_utils.Cylinder(values.get("Z", 0), values.get("R0", 0)) + self.view.update_cylinder(self.model.splanes[ind], ind) + + for i in range(len(self.model.splanes)): + self.view.splanes_tree.topLevelItem(i).setText(1, str(i + 1)) + self.view.splanes_tree.topLevelItem(i).setText(2, self.model.splanes[i].toFile()) + def update_interface(self, filename = ""): s = sett() diff --git a/src/figure_editor.py b/src/figure_editor.py index 67008f9..dcc135d 100644 --- a/src/figure_editor.py +++ b/src/figure_editor.py @@ -95,7 +95,7 @@ def emmit_value(state: int): slider.setOrientation(QtCore.Qt.Horizontal) slider.setMinimum(constrains[param_idx][0]) slider.setMaximum(constrains[param_idx][1]) - slider.setValue((initial_params.get(param, 0))) + slider.setValue(int(initial_params.get(param, 0))) slider.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) slider.setMinimumWidth(200) @@ -146,6 +146,18 @@ def params(self): return self.__params +class CylinderEditor(FigureEditor): + __params = ["Z", "R0"] + __constrains = [(0, 200), (0, 150)] + + def __init__(self, tabs, on_change: Callable[[Dict[str, float]], None], + initial_params: Optional[Dict[str, float]] = None): + super().__init__(tabs, self.__params, self.__constrains, on_change, initial_params) + + def params(self): + return self.__params + + class StlMovePanel(QWidget): def __init__(self, methods, captions): diff --git a/src/gui_utils.py b/src/gui_utils.py index c5f1c8a..08b7bd8 100644 --- a/src/gui_utils.py +++ b/src/gui_utils.py @@ -5,7 +5,7 @@ from vtkmodules.vtkCommonColor import vtkNamedColors from vtkmodules.vtkCommonMath import vtkMatrix4x4 from vtkmodules.vtkCommonTransforms import vtkTransform -from vtkmodules.vtkFiltersSources import vtkLineSource, vtkConeSource +from vtkmodules.vtkFiltersSources import vtkLineSource, vtkConeSource, vtkCylinderSource from vtkmodules.vtkRenderingCore import vtkActor, vtkPolyDataMapper, vtkAssembly from src.settings import sett, get_color, PathBuilder @@ -140,6 +140,42 @@ def create_cone_actor(vertex: Tuple[float, float, float], bending_angle: float, return actor +def create_cylinder_actor(z: float, r0: float, r1: float): + height = 30 + + sourceOuter = vtkCylinderSource() + sourceOuter.SetCenter(0.0, z, 0.0) + sourceOuter.SetRadius(r1) + sourceOuter.SetHeight(0.1) + sourceOuter.SetResolution(50) + sourceOuter.SetCapping(1) + sourceOuter.Update() + input1 = sourceOuter.GetOutput() + + sourceInner = vtkCylinderSource() + sourceInner.SetCenter(0.0, z + height / 2, 0.0) + sourceInner.SetRadius(r0) + sourceInner.SetHeight(height) + sourceInner.SetResolution(50) + sourceInner.SetCapping(0) + sourceInner.Update() + input2 = sourceInner.GetOutput() + + # append the two meshes + appendFilter = vtk.vtkAppendPolyData() + appendFilter.AddInputData(input1) + appendFilter.AddInputData(input2) + appendFilter.Update() + + mapper = vtkPolyDataMapper() + mapper.SetInputConnection(appendFilter.GetOutputPort()) + + actor = vtkActor() + actor.SetMapper(mapper) + actor.GetProperty().SetColor(get_color(sett().colors.splane)) + actor.GetProperty().SetRepresentationToWireframe() + actor.RotateX(90) + return actor def createBoxActors(): s = sett() @@ -473,6 +509,18 @@ def params(self) -> Dict[str, float]: return {"X": self.x, "Y": self.y, "Z": self.z, "A": self.cone_angle, "H1": self.h1, "H2": self.h2} +class Cylinder: + def __init__(self, z: float, r0: float): + self.z = z + self.r0 = r0 + self.r1 = r0 + 10 + + def toFile(self) -> str: + return f"cylinder Z{self.z} R{self.r0}" + + def params(self) -> Dict[str, float]: + return {"Z": self.z, "R0": self.r0} + def read_planes(filename): planes = [] with open(filename) as fp: @@ -483,9 +531,12 @@ def read_planes(filename): #plane X10 Y10 Z10 T-60 R0 - Plane string format planes.append( Plane(float(v[4][1:]), float(v[5][1:]), (float(v[1][1:]), float(v[2][1:]), float(v[3][1:])))) - else: + elif v[0] == 'cone': #cone X0 Y0 Z10 A60 H10 H50 - Cone string format planes.append(Cone(float(v[4][1:]), (float(v[1][1:]), float(v[2][1:]), float(v[3][1:])), float(v[5][1:]), float(v[6][1:]))) + elif v[0] == 'cylinder': + #cylinder Z10 R10 R20 - Cylinder string format + planes.append(Cylinder(float(v[1][1:]), float(v[2][1:]))) return planes diff --git a/src/model.py b/src/model.py index f4ca03b..a99e2c8 100644 --- a/src/model.py +++ b/src/model.py @@ -26,3 +26,6 @@ def add_splane(self): def add_cone(self): self.splanes.append(gui_utils.Cone(60, (0, 0, 10), 0, 100)) + + def add_cylinder(self): + self.splanes.append(gui_utils.Cylinder(10, 10, 250)) diff --git a/src/window.py b/src/window.py index 151cbe2..ab16a91 100644 --- a/src/window.py +++ b/src/window.py @@ -12,7 +12,7 @@ from src import locales, gui_utils, interactor_style from src.InteractorAroundActivePlane import InteractionAroundActivePlane -from src.gui_utils import plane_tf, Plane, Cone +from src.gui_utils import plane_tf, Plane, Cone, Cylinder from src.settings import sett, get_color, save_settings from src.figure_editor import StlMovePanel @@ -645,11 +645,14 @@ def init_figure_panel(self): self.add_cone_button = QPushButton(self.locale.AddCone) bottom_layout.addWidget(self.add_cone_button, 2, 2) + self.add_cylinder_button = QPushButton("Add cylinder") + bottom_layout.addWidget(self.add_cylinder_button, 3, 2) + self.remove_plane_button = QPushButton(self.locale.DeletePlane) - bottom_layout.addWidget(self.remove_plane_button, 3, 2) + bottom_layout.addWidget(self.remove_plane_button, 4, 2) self.edit_figure_button = QPushButton(self.locale.EditFigure) - bottom_layout.addWidget(self.edit_figure_button, 4, 2) + bottom_layout.addWidget(self.edit_figure_button, 5, 2) self.save_planes_button = QPushButton(self.locale.SavePlanes) bottom_layout.addWidget(self.save_planes_button, 1, 3) @@ -956,8 +959,10 @@ def _recreate_splanes(self, splanes): for i, p in enumerate(splanes): if isinstance(p, Plane): act = gui_utils.create_splane_actor([p.x, p.y, p.z], p.incline, p.rot) - else: # isinstance(p, Cone): + elif isinstance(p, Cone): act = gui_utils.create_cone_actor((p.x, p.y, p.z), p.cone_angle, p.h1, p.h2) + elif isinstance(p, Cylinder): + act = gui_utils.create_cylinder_actor(p.z, p.r0, p.r1) row = self.splanes_tree.topLevelItem(i) if row != None: @@ -999,6 +1004,18 @@ def update_cone(self, cone: Cone, ind): self.splanes_actors[sel].GetProperty().SetOpacity(sett().common.opacity_current_plane) self.reload_scene() + def update_cylinder(self, cylinder: Cylinder, ind): + self.render.RemoveActor(self.splanes_actors[ind]) + act = gui_utils.create_cylinder_actor(cylinder.z, cylinder.r0, cylinder.r1) + self.splanes_actors[ind] = act + self.render.AddActor(act) + sel = self.splanes_tree.currentIndex().row() + if sel == ind: + self.splanes_actors[sel].GetProperty().SetColor(get_color(sett().colors.last_layer)) + self.splanes_actors[sel].GetProperty().SetOpacity(sett().common.opacity_current_plane) + self.reload_scene() + + def change_combo_select(self, plane, ind): for p in self.splanes_actors: p.GetProperty().SetColor(get_color(sett().colors.splane))