Fixed interactor
Added proj lines selected
This commit is contained in:
parent
048ace83ce
commit
a8d15d7b4b
@ -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):
|
||||
|
@ -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
87
main.py
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user