Fixed interactor

Added proj lines selected
This commit is contained in:
bklronin 2024-07-17 16:53:25 +02:00
parent 048ace83ce
commit a8d15d7b4b
4 changed files with 185 additions and 60 deletions

View File

@ -5,7 +5,7 @@ from copy import copy
import numpy as np
from PySide6.QtWidgets import QApplication, QWidget, QMessageBox, QInputDialog
from PySide6.QtGui import QPainter, QPen, QColor, QTransform
from PySide6.QtCore import Qt, QPoint, QPointF, Signal
from PySide6.QtCore import Qt, QPoint, QPointF, Signal, QLine
from python_solvespace import SolverSystem, ResultFlag
@ -51,13 +51,11 @@ class SketchWidget(QWidget):
def create_workplane_projected(self):
self.wp = self.solv.create_2d_base()
def create_proj_lines(self, lines):
def create_proj_points(self, proj_points):
"""Lines as orientation projected from the sketch"""
for point in lines:
for point in proj_points:
x, y = point
self.proj_snap_lines = lines
# Invert X from projection might be happening in the projection for some reason Careful
coord = QPoint(x, y)
self.proj_snap_points.append(coord)
@ -69,6 +67,24 @@ class SketchWidget(QWidget):
self.slv_points_main.append(relation_point)"""
def create_proj_lines(self, sel_edges):
"""Lines as orientation projected from the sketch"""
print("Incoming corrd lines", sel_edges)
for line in sel_edges:
start = QPoint(line[0][0], line[0][1] )
end = QPoint(line[1][0], line[1][1])
coord = QLine(start, end)
self.proj_snap_lines.append(coord)
"""relation_point = {} # Reinitialize the dictionary
#handle_nr = self.get_handle_nr(str(point))
#relation_point['handle_nr'] = handle_nr
#relation_point['solv_handle'] = point
relation_point['ui_point'] = QPoint(x, y)
self.slv_points_main.append(relation_point)"""
def find_duplicate_points_2d(self, edges):
points = []
seen = set()
@ -675,11 +691,11 @@ class SketchWidget(QWidget):
return QPoint(int(widget_x), int(widget_y))
def from_quadrant_coords_no_center(self, point):
"""Translate quadrant coordinates to linear coordinates."""
"""Invert Y Coordinate for mesh"""
center_x = 0
center_y = 0
widget_x = center_x + point.x() * self.zoom
widget_y = center_y - point.y() * self.zoom # Note the subtraction here
widget_x = point.x()
widget_y = -point.y()
return QPoint(int(widget_x), int(widget_y))
def paintEvent(self, event):
@ -746,6 +762,11 @@ class SketchWidget(QWidget):
for cross in self.proj_snap_points:
self.draw_cross(painter, cross, 10 / self.zoom)
for selected in self.proj_snap_lines:
pen = QPen(Qt.white, 1, Qt.DashLine)
painter.setPen(pen)
painter.drawLine(selected)
painter.end()
def wheelEvent(self, event):

View File

@ -13,6 +13,7 @@ class VTKWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.selected_vtk_line = []
self.access_selected_points = []
self.selected_normal = None
self.centroid = None
@ -21,7 +22,8 @@ class VTKWidget(QtWidgets.QWidget):
self.local_matrix = None
self.project_tosketch_edge = []
self.project_tosketch_points = []
self.project_tosketch_lines = []
self.vtk_widget = QVTKRenderWindowInteractor(self)
@ -112,10 +114,12 @@ class VTKWidget(QtWidgets.QWidget):
mapper.SetInputData(grid)
actor = vtk.vtkActor()
actor.SetPickable(False)
actor.SetMapper(mapper)
actor.GetProperty().SetColor(0.5, 0.5, 0.5) # Set grid color to gray
self.renderer.AddActor(actor)
def create_grid(self, size=100, spacing=10):
# Create a vtkPoints object and store the points in it
points = vtk.vtkPoints()
@ -169,7 +173,7 @@ class VTKWidget(QtWidgets.QWidget):
normal = normal / np.linalg.norm(normal)
return normal
def load_interactor_mesh(self, edges):
def load_interactor_mesh(self, edges, off_vector):
# Create vtkPoints to store all points
points = vtk.vtkPoints()
@ -195,28 +199,34 @@ class VTKWidget(QtWidgets.QWidget):
polydata.SetLines(lines)
# Create a transform for mirroring across the y-axis
mirror_transform = vtk.vtkTransform()
matrix_transform = vtk.vtkTransform()
"""if self.local_matrix:
if self.local_matrix:
print(self.local_matrix)
matrix = vtk.vtkMatrix4x4()
matrix.DeepCopy(self.local_matrix)
matrix.Invert()
mirror_transform.SetMatrix(matrix)
matrix_transform.SetMatrix(matrix)
#matrix_transform.Scale(1, 1, 1) # This mirrors across the y-axis
mirror_transform.Scale(-1, -1, 1) # Inverting the original mirror look down
mirror_transform.Scale(1, 1, 1) # This mirrors across the y-axis"""
# Apply the transform to the polydata
# Apply the matrix transform
transformFilter = vtk.vtkTransformPolyDataFilter()
transformFilter.SetInputData(polydata)
transformFilter.SetTransform(mirror_transform)
transformFilter.SetTransform(matrix_transform)
transformFilter.Update()
# Create and apply the offset transform
offset_transform = vtk.vtkTransform()
offset_transform.Translate(off_vector[0], off_vector[1], off_vector[2])
offsetFilter = vtk.vtkTransformPolyDataFilter()
offsetFilter.SetInputConnection(transformFilter.GetOutputPort())
offsetFilter.SetTransform(offset_transform)
offsetFilter.Update()
# Create a mapper and actor
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputData(transformFilter.GetOutput())
mapper.SetInputConnection(offsetFilter.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
@ -270,6 +280,9 @@ class VTKWidget(QtWidgets.QWidget):
actor.GetProperty().SetColor(color)
actor.GetProperty().EdgeVisibilityOff()
actor.GetProperty().SetLineWidth(line_width)
actor.GetProperty().SetMetallic(1)
actor.GetProperty().SetOpacity(0.8)
actor.SetPickable(False)
self.renderer.AddActor(actor)
self.body_actors_orig.append(actor)
@ -385,6 +398,62 @@ class VTKWidget(QtWidgets.QWidget):
return xy_coordinates
def compute_2d_coordinates_line(self, line_cell, normal):
# Ensure the input is a vtkLine
if not isinstance(line_cell, vtk.vtkLine):
raise ValueError("Input must be a vtkLine cell")
# Normalize the normal vector
normal = np.array(normal)
normal = normal / np.linalg.norm(normal)
# Create a vtkTransform
transform = vtk.vtkTransform()
transform.PostMultiply() # This ensures transforms are applied in the order we specify
# Rotate so that the normal aligns with the Z-axis
rotation_axis = np.cross(normal, [0, 0, 1])
angle = np.arccos(np.dot(normal, [0, 0, 1])) * 180 / np.pi # Convert to degrees
if np.linalg.norm(rotation_axis) > 1e-6: # Check if rotation is needed
transform.RotateWXYZ(angle, rotation_axis[0], rotation_axis[1], rotation_axis[2])
# Get the transformation matrix
matrix = transform.GetMatrix()
local_matrix = [matrix.GetElement(i, j) for i in range(4) for j in range(4)]
# Create a vtkPoints object to store the line points
points = vtk.vtkPoints()
points.InsertNextPoint(line_cell.GetPoints().GetPoint(0))
points.InsertNextPoint(line_cell.GetPoints().GetPoint(1))
# Create a vtkPolyData to represent the line
polydata = vtk.vtkPolyData()
polydata.SetPoints(points)
# Create a vtkCellArray to store the line cell
cells = vtk.vtkCellArray()
cells.InsertNextCell(line_cell)
polydata.SetLines(cells)
# Apply the transform to the polydata
transform_filter = vtk.vtkTransformPolyDataFilter()
transform_filter.SetInputData(polydata)
transform_filter.SetTransform(transform)
transform_filter.Update()
# Get the transformed points
transformed_polydata = transform_filter.GetOutput()
transformed_points = transformed_polydata.GetPoints()
# Extract 2D coordinates
xy_coordinates = []
for i in range(transformed_points.GetNumberOfPoints()):
point = transformed_points.GetPoint(i)
xy_coordinates.append((point[0], point[1]))
return xy_coordinates
def project_2d_to_3d(self, xy_coordinates, normal):
# Normalize the normal vector
normal = np.array(normal)
@ -494,6 +563,8 @@ class VTKWidget(QtWidgets.QWidget):
# Ensure it's a line
if cell.GetCellType() == vtk.VTK_LINE:
self.selected_vtk_line.append(cell)
# Get the two points of the line
point_id1 = cell.GetPointId(0)
point_id2 = cell.GetPointId(1)
@ -533,9 +604,11 @@ class VTKWidget(QtWidgets.QWidget):
if len(self.selected_edges) == 2:
self.compute_projection(False)
elif len(self.selected_edges) > 2:
del self.selected_edges[0]
pass
if len(self.selected_edges) > 2:
self.selected_vtk_line.clear()
self.selected_edges.clear()
self.clear_actors_projection()
self.clear_edge_select()
def find_origin_vertex(self, edge1, edge2):
if edge1[0] == edge2[0]or edge1[0] == edge2[1]:
@ -559,6 +632,7 @@ class VTKWidget(QtWidgets.QWidget):
self.renderer.RemoveActor(normals)
def compute_projection(self, direction_invert: bool= False):
# Compute the normal from the two selected edges )
edge1 = self.selected_edges[0][1] - self.selected_edges[0][0]
edge2 = self.selected_edges[1][1] - self.selected_edges[1][0]
@ -583,11 +657,14 @@ class VTKWidget(QtWidgets.QWidget):
polydata = self.picker.GetActor().GetMapper().GetInput()
projected_polydata = self.project_mesh_to_plane(polydata, self.selected_normal, self.centroid)
projected_points = projected_polydata.GetPoints()
#print("proj_points", projected_points)
# Extract 2D coordinates
self.project_tosketch_edge = self.compute_2d_coordinates(projected_polydata, self.selected_normal)
self.project_tosketch_points = self.compute_2d_coordinates(projected_polydata, self.selected_normal)
# Seperately rotate selected edges for drawing
for vtk_line in self.selected_vtk_line:
proj_vtk_line = self.compute_2d_coordinates_line(vtk_line, self.selected_normal)
self.project_tosketch_lines.append(proj_vtk_line)
# Create a mapper and actor for the projected data
mapper = vtk.vtkPolyDataMapper()
@ -595,13 +672,14 @@ class VTKWidget(QtWidgets.QWidget):
actor = vtk.vtkActor()
actor.SetMapper(mapper)
#actor.GetProperty().SetRenderLinesAsTubes(True)
actor.GetProperty().SetColor(0.0, 1.0, 0.0) # Set color to green
actor.GetProperty().SetLineWidth(4) # Set line width
actor.GetProperty().SetLineWidth(8) # Set line width
self.renderer.AddActor(normal_actor)
self.displayed_normal_actors.append(normal_actor)
# Add the actor to the scene
# Add the edge lines actor to the scene
self.renderer.AddActor(actor)
self.picked_edge_actors.append(actor)

87
main.py
View File

@ -133,11 +133,14 @@ 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.project_tosketch_edge
points = self.custom_3D_Widget.project_tosketch_points
normal = self.custom_3D_Widget.selected_normal
selected_lines = self.custom_3D_Widget.project_tosketch_lines
print("Selected lines", selected_lines)
self.sketchWidget.create_workplane_projected()
self.sketchWidget.create_proj_lines(edges)
self.sketchWidget.create_proj_points(points)
self.sketchWidget.create_proj_lines(selected_lines)
# CLear all selections after it has been projected
#self.custom_3D_Widget.clear_edge_select()
@ -377,7 +380,6 @@ class MainWindow(QMainWindow):
selected = self.ui.sketch_list.currentItem()
name = selected.text()
points = self.model['sketch'][name]['sketch_points']
lines = self.convert_lines_for_interactor()
if points[-1] == points[0]:
#detect loop that causes problems in mesh generation
@ -391,12 +393,8 @@ class MainWindow(QMainWindow):
length = 0
print("Extrude cancelled")
#Create and draw Interactor
geo = Geometry()
# Rotation is done in vtk matrix trans
angle = 0
normal = self.custom_3D_Widget.selected_normal
print("Normie enter", normal)
if normal is None:
@ -407,20 +405,9 @@ class MainWindow(QMainWindow):
centroid = [0, 0, 0]
else:
centroid = list(centroid)
print("THis centroid ",centroid)
print("This centroid ", centroid)
f = geo.extrude_shape(points, length, angle, normal, centroid, is_symmetric, invert)
z_origin = centroid[2]
if is_symmetric:
z_origin = z_origin - length / 2
if invert:
edges = interactor_mesh.generate_mesh(lines, z_origin, length, True)
else:
edges = interactor_mesh.generate_mesh(lines, z_origin, length, False)
self.custom_3D_Widget.load_interactor_mesh(edges)
f = geo.extrude_shape(points, length, normal, centroid, is_symmetric, invert, 0)
name_op = f"extrd-{name}"
element = {
@ -428,7 +415,18 @@ class MainWindow(QMainWindow):
'type': 'extrude',
'sdf_object': f,
}
#print(element)
### Interactor
lines = self.convert_lines_for_interactor()
edges = interactor_mesh.generate_mesh(lines, 0, length)
offset_vector = geo.vector_to_centroid(None, centroid, normal)
#print("off_ved", offset_vector)
if len(offset_vector) == 0 :
offset_vector = [0, 0, 0]
self.custom_3D_Widget.load_interactor_mesh(edges, offset_vector)
self.model['operation'][name_op] = element
self.ui.body_list.addItem(name_op)
@ -500,7 +498,22 @@ class Geometry:
print("p2", p2)
return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
def extrude_shape(self, points, length: float, angle, normal, centroid, symet: bool = True, invert: bool = False):
def vector_to_centroid(self, shape_center, centroid, normal):
if not shape_center:
# Calculate the current center of the shape
shape_center = [0, 0, 0]
# Calculate the vector from the shape's center to the centroid
center_to_centroid = np.array(centroid) - np.array(shape_center)
# Project this vector onto the normal to get the required translation along the normal
translation_along_normal = np.dot(center_to_centroid, normal) * normal
return translation_along_normal
def extrude_shape(self, points, length: float, normal, centroid, symet: bool = True, invert: bool = False,
offset_length: float = None):
"""
Extrude a 2D shape into 3D, orient it along the normal, and position it relative to the centroid.
"""
@ -520,17 +533,29 @@ class Geometry:
# Orient the shape along the normal vector
f = f.orient(normal)
# Calculate the current center of the shape
shape_center = [0,0,0]
offset_vector = self.vector_to_centroid(None, centroid, normal)
# Adjust the offset vector by subtracting the inset distance along the normal direction
adjusted_offset = offset_vector - (normal * length)
if invert:
# Translate the shape along the adjusted offset vector
f = f.translate(adjusted_offset)
else:
f = f.translate(offset_vector)
# Calculate the vector from the shape's center to the centroid
center_to_centroid = np.array(centroid) - np.array(shape_center)
# If offset_length is provided, adjust the offset_vector
if offset_length is not None:
# Check if offset_vector is not a zero vector
offset_vector_magnitude = np.linalg.norm(offset_vector)
if offset_vector_magnitude > 1e-10: # Use a small threshold to avoid floating-point issues
# Normalize the offset vector
offset_vector_norm = offset_vector / offset_vector_magnitude
# Scale the normalized vector by the desired length
offset_vector = offset_vector_norm * offset_length
f = f.translate(offset_vector)
else:
print("Warning: Offset vector has zero magnitude. Using original vector.")
# Project this vector onto the normal to get the required translation along the normal
translation_along_normal = np.dot(center_to_centroid, normal) * normal
# Translate the shape along the normal
f = f.translate(translation_along_normal)
# Translate the shape along the adjusted offset vector
return f

View File

@ -1,8 +1,9 @@
# Draw simple boundary based on the lines and depth
def generate_mesh(lines: list, z_origin: float, depth: float, invert :bool = False):
def generate_mesh(lines: list, z_origin: float, depth: float, invert: bool = False):
origin = create_3D(lines, z_origin)
if invert :
extruded = create_3D(lines, z_origin - depth)
else: