diff --git a/drawing_modules/draw_widget2d.py b/drawing_modules/draw_widget2d.py index be796b1..c02d9bb 100644 --- a/drawing_modules/draw_widget2d.py +++ b/drawing_modules/draw_widget2d.py @@ -72,7 +72,6 @@ class SketchWidget(QWidget): print("lines", self.slv_lines_main) print("lines", lines) - def find_duplicate_points_2d(self, edges): points = [] seen = set() diff --git a/drawing_modules/vtk_widget.py b/drawing_modules/vtk_widget.py index 0dec7a8..24463a8 100644 --- a/drawing_modules/vtk_widget.py +++ b/drawing_modules/vtk_widget.py @@ -17,8 +17,13 @@ class VTKWidget(QtWidgets.QWidget): self.selected_normal = None self.selected_edges = [] self.cell_normals = None + + self.project_tosketch_edge = [] + self.vtk_widget = QVTKRenderWindowInteractor(self) + self.picked_edge_actors = [] + # Create layout and add VTK widget layout = QtWidgets.QVBoxLayout() layout.addWidget(self.vtk_widget) @@ -43,8 +48,12 @@ class VTKWidget(QtWidgets.QWidget): self.picked_actor = vtk.vtkActor() self.picked_actor.SetMapper(self.picked_mapper) self.picked_actor.GetProperty().SetColor(1.0, 0.0, 0.0) # Red color for picked faces + self.picked_actor.VisibilityOff() # Initially hide the actor self.renderer.AddActor(self.picked_actor) + # Create an extract selection filter + self.extract_selection = vtk.vtkExtractSelection() + # Set up interactor style self.style = vtk.vtkInteractorStyleTrackballCamera() self.interactor.SetInteractorStyle(self.style) @@ -86,15 +95,11 @@ class VTKWidget(QtWidgets.QWidget): polydata.SetPoints(points) polydata.SetLines(lines) - # Verify that the polydata is not empty - if polydata.GetNumberOfPoints() == 0 or polydata.GetNumberOfCells() == 0: - print("Error: PolyData is empty") - sys.exit(1) - # Create a mapper and actor mapper = vtk.vtkPolyDataMapper() mapper.SetInputData(polydata) + actor = vtk.vtkActor() actor.SetMapper(mapper) actor.GetProperty().SetColor(0.0, 0.0, 1.0) # Set color to red @@ -104,9 +109,7 @@ class VTKWidget(QtWidgets.QWidget): self.renderer.AddActor(actor) #self.renderer.SetBackground(0.1, 0.2, 0.4) # Set background color - # Render and interact - # Force an update of the pipeline - # mapper.Update() + mapper.Update() self.vtk_widget.GetRenderWindow().Render() def render_from_points_direct_with_faces(self, vertices, faces): @@ -190,6 +193,25 @@ class VTKWidget(QtWidgets.QWidget): mapper.Update() self.vtk_widget.GetRenderWindow().Render() + def get_points_and_edges_from_polydata(self, polydata) -> list: + # Extract points + points = {} + vtk_points = polydata.GetPoints() + for i in range(vtk_points.GetNumberOfPoints()): + point = vtk_points.GetPoint(i) + points[i] = np.array(point) + + # Extract edges + edges = [] + for i in range(polydata.GetNumberOfCells()): + cell = polydata.GetCell(i) + if cell.GetCellType() == vtk.VTK_LINE: + point_ids = cell.GetPointIds() + edge = (point_ids.GetId(0), point_ids.GetId(1)) + edges.append(edge) + + return points, edges + def on_click(self, obj, event): click_pos = self.interactor.GetEventPosition() @@ -226,6 +248,24 @@ class VTKWidget(QtWidgets.QWidget): # Store this line for later use if needed self.selected_edges.append((point1, point2)) + # Create a new vtkLineSource for the picked edge + line_source = vtk.vtkLineSource() + line_source.SetPoint1(point1) + line_source.SetPoint2(point2) + + # Create a mapper and actor for the picked edge + edge_mapper = vtk.vtkPolyDataMapper() + edge_mapper.SetInputConnection(line_source.GetOutputPort()) + + edge_actor = vtk.vtkActor() + edge_actor.SetMapper(edge_mapper) + edge_actor.GetProperty().SetColor(1.0, 0.0, 0.0) # Red color for picked edges + edge_actor.GetProperty().SetLineWidth(4) # Make the line thicker + + # Add the actor to the renderer and store it + self.renderer.AddActor(edge_actor) + self.picked_edge_actors.append(edge_actor) + if len(self.selected_edges) == 2: # Compute the normal from the two selected edges edge1 = self.selected_edges[0][1] - self.selected_edges[0][0] @@ -234,10 +274,17 @@ class VTKWidget(QtWidgets.QWidget): self.selected_normal = self.selected_normal / np.linalg.norm(self.selected_normal) print("Computed normal:", self.selected_normal) + # Compute the centroid of the selected edges + centroid = ( + 0, 0, 0) # point1 #np.mean([point for edge in self.selected_edges for point in edge], axis=0) + # Create a transform for projection transform = vtk.vtkTransform() transform.Identity() + # Translate to center the transform on the centroid + transform.Translate(-centroid[0], -centroid[1], -centroid[2]) + # Compute rotation to align normal with Z-axis z_axis = np.array([0, 0, 1]) rotation_axis = np.cross(self.selected_normal, z_axis) @@ -252,6 +299,9 @@ class VTKWidget(QtWidgets.QWidget): # Apply the inverse rotation to bring it back to original orientation transform.RotateWXYZ(-rotation_angle, rotation_axis[0], rotation_axis[1], rotation_axis[2]) + # Translate back + transform.Translate(centroid[0], centroid[1], centroid[2]) + # Apply the transform to the polydata transformFilter = vtk.vtkTransformPolyDataFilter() transformFilter.SetInputData(polydata) @@ -260,6 +310,7 @@ class VTKWidget(QtWidgets.QWidget): # Get the projected polydata projected_polydata = transformFilter.GetOutput() + print("Polydata", projected_polydata) # Create a mapper and actor for the projected data mapper = vtk.vtkPolyDataMapper() @@ -275,7 +326,7 @@ class VTKWidget(QtWidgets.QWidget): # Add a plane to visualize the projection plane plane_source = vtk.vtkPlaneSource() - plane_source.SetCenter(0, 0, 0) + plane_source.SetCenter(centroid) plane_source.SetNormal(self.selected_normal) plane_mapper = vtk.vtkPolyDataMapper() plane_mapper.SetInputConnection(plane_source.GetOutputPort()) @@ -291,13 +342,23 @@ class VTKWidget(QtWidgets.QWidget): # Render and interact self.vtk_widget.GetRenderWindow().Render() - # Reset selected edges - self.selected_edges = [] + self.project_tosketch_edge = self.get_points_and_edges_from_polydata(projected_polydata) + print("Edges", self.project_tosketch_edge[0]) + elif len(self.access_selected_points) > 2: self.access_selected_points = [] + # Clear the picked edge actors + for actor in self.picked_edge_actors: + self.renderer.RemoveActor(actor) + self.picked_edge_actors.clear() + # Reset selected edges + self.selected_edges = [] else: print("Selected cell is not a line") + + # Render the scene + self.vtk_widget.GetRenderWindow().Render() def start(self): self.interactor.Initialize() self.interactor.Start() diff --git a/main.py b/main.py index e0fe266..74143c8 100644 --- a/main.py +++ b/main.py @@ -74,8 +74,8 @@ class MainWindow(QMainWindow): def add_new_sketch_wp(self): self.sketchWidget.clear_sketch() - edges = [((-158.0, -20.0, -25.0), (286.0, -195.0, -25.0)), ((-158.0, -20.0, 25.0), (-158.0, -20.0, -25.0))] - #edges = self.custom_3D_Widget.access_selected_points + #edges = [((-158.0, -20.0, -25.0), (286.0, -195.0, -25.0)), ((-158.0, -20.0, 25.0), (-158.0, -20.0, -25.0))] + edges = self.custom_3D_Widget.project_tosketch_edge normal = self.custom_3D_Widget.selected_normal self.sketchWidget.create_workplane_projected() @@ -310,7 +310,7 @@ class MainWindow(QMainWindow): items = self.ui.body_list.findItems(name_op, Qt.MatchExactly)[0] self.ui.body_list.setCurrentItem(items) self.calc_sketch_projection_3d(lines, 0, length) - #self.draw_mesh() + self.draw_mesh() def send_cut(self): name = self.ui.body_list.currentItem().text()