- Fixed 2d sketch with transfrom
This commit is contained in:
@@ -4,14 +4,10 @@ from copy import copy
|
||||
|
||||
import numpy as np
|
||||
from PySide6.QtWidgets import QApplication, QWidget, QMessageBox, QInputDialog
|
||||
from PySide6.QtGui import QPainter, QPen, QColor
|
||||
from PySide6.QtGui import QPainter, QPen, QColor, QTransform
|
||||
from PySide6.QtCore import Qt, QPoint, QPointF, Signal
|
||||
from python_solvespace import SolverSystem, ResultFlag
|
||||
|
||||
class DrawingTools():
|
||||
pass
|
||||
class Costrains():
|
||||
pass
|
||||
|
||||
class SketchWidget(QWidget):
|
||||
constrain_done = Signal()
|
||||
@@ -59,13 +55,10 @@ class SketchWidget(QWidget):
|
||||
"""Lines as orientation projected from the sketch"""
|
||||
|
||||
for point in lines:
|
||||
print(point)
|
||||
x, y = point
|
||||
self.proj_snap_lines = lines
|
||||
self.proj_snap_points.append(QPoint(x, y))
|
||||
|
||||
|
||||
#point = self.solv.add_point_2d(x, y, self.wp)
|
||||
coord = QPoint(x, y)
|
||||
self.proj_snap_points.append(coord)
|
||||
|
||||
"""relation_point = {} # Reinitialize the dictionary
|
||||
#handle_nr = self.get_handle_nr(str(point))
|
||||
@@ -215,7 +208,6 @@ class SketchWidget(QWidget):
|
||||
return None
|
||||
|
||||
def viewport_to_local_coord(self, qt_pos : QPoint) -> QPoint:
|
||||
self.to_quadrant_coords(qt_pos)
|
||||
return QPoint(self.to_quadrant_coords(qt_pos))
|
||||
|
||||
def check_all_points(self,) -> list:
|
||||
@@ -647,11 +639,13 @@ class SketchWidget(QWidget):
|
||||
painter.setPen(QPen(Qt.red, 4))
|
||||
painter.drawPoint(middle_x, middle_y)
|
||||
|
||||
def draw_cross(self, painter, x, y, size=10):
|
||||
def draw_cross(self, painter, pos: QPoint, size=10):
|
||||
# Set up the pen
|
||||
pen = QPen(QColor('green')) # You can change the color as needed
|
||||
pen.setWidth(int(2 / self.zoom)) # Set the line widt)h
|
||||
painter.setPen(pen)
|
||||
x = pos.x()
|
||||
y = pos.y()
|
||||
|
||||
# Calculate the endpoints of the cross
|
||||
half_size = size // 2
|
||||
@@ -667,23 +661,47 @@ class SketchWidget(QWidget):
|
||||
center_x = self.width() // 2
|
||||
center_y = self.height() // 2
|
||||
quadrant_x = point.x() - center_x
|
||||
quadrant_y = point.y() - center_y
|
||||
quadrant_y = center_y - point.y() # Note the change here
|
||||
return QPoint(quadrant_x, quadrant_y) / self.zoom
|
||||
|
||||
def from_quadrant_coords(self, point: QPoint):
|
||||
"""Translate quadrant coordinates to linear coordinates."""
|
||||
center_x = self.width() // 2
|
||||
center_y = self.height() // 2
|
||||
widget_x = center_x + point.x() * self.zoom
|
||||
widget_y = center_y - point.y() * self.zoom # Note the subtraction here
|
||||
|
||||
return QPoint(int(widget_x), int(widget_y))
|
||||
|
||||
def from_quadrant_coords_no_center(self, point):
|
||||
"""Translate quadrant coordinates to linear coordinates."""
|
||||
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
|
||||
return QPoint(int(widget_x), int(widget_y))
|
||||
|
||||
def paintEvent(self, event):
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHint(QPainter.Antialiasing)
|
||||
|
||||
self.drawAxes(painter)
|
||||
|
||||
# Create a QTransform object
|
||||
transform = QTransform()
|
||||
|
||||
# Translate the origin to the center of the widget
|
||||
center = QPoint(self.width() // 2, self.height() // 2)
|
||||
painter.translate(center)
|
||||
center = QPointF(self.width() / 2, self.height() / 2)
|
||||
transform.translate(center.x(), center.y())
|
||||
|
||||
# Apply the zoom factor
|
||||
painter.scale(self.zoom, self.zoom)
|
||||
transform.scale(self.zoom, -self.zoom) # Negative y-scale to invert y-axis
|
||||
|
||||
# Set the transform to the painter
|
||||
painter.setTransform(transform)
|
||||
|
||||
pen = QPen(Qt.gray)
|
||||
pen.setWidth(2 / self.zoom)
|
||||
pen.setWidthF(2 / self.zoom)
|
||||
painter.setPen(pen)
|
||||
|
||||
# Draw points
|
||||
@@ -700,36 +718,33 @@ class SketchWidget(QWidget):
|
||||
painter.drawText(mid, str(round(dis, 2)))
|
||||
|
||||
pen = QPen(Qt.green)
|
||||
pen.setWidth(2)
|
||||
pen.setWidthF(2 / self.zoom)
|
||||
painter.setPen(pen)
|
||||
|
||||
if self.solv.entity_len():
|
||||
for i in range(self.solv.entity_len()):
|
||||
# 3 Entitys in the beginning of the workplane normal and point
|
||||
entity = self.solv.entity(i)
|
||||
if entity.is_point_2d() and self.solv.params(entity.params):
|
||||
x, y = self.solv.params(entity.params)
|
||||
point = QPoint(x, y)
|
||||
point = QPointF(x, y)
|
||||
painter.drawEllipse(point, 6 / self.zoom, 6 / self.zoom)
|
||||
|
||||
#Highlight point hovered
|
||||
# Highlight point hovered
|
||||
if self.hovered_point:
|
||||
highlight_pen = QPen(QColor(255, 0, 0))
|
||||
highlight_pen.setWidth(2)
|
||||
highlight_pen.setWidthF(2 / self.zoom)
|
||||
painter.setPen(highlight_pen)
|
||||
painter.drawEllipse(self.hovered_point, 5 / self.zoom, 5 / self.zoom)
|
||||
|
||||
# Highlight line hovered
|
||||
if self.selected_line and not self.hovered_point:
|
||||
p1, p2 = self.selected_line
|
||||
painter.setPen(QPen(Qt.red, 2))
|
||||
painter.setPen(QPen(Qt.red, 2 / self.zoom))
|
||||
painter.drawLine(p1, p2)
|
||||
|
||||
for cross in self.proj_snap_lines:
|
||||
# Calculate the endpoints of the cross
|
||||
self.draw_cross(painter, cross[0], cross[1], 10)
|
||||
for cross in self.proj_snap_points:
|
||||
self.draw_cross(painter, cross, 10 / self.zoom)
|
||||
|
||||
# self.drawBackgroundGrid(painter)
|
||||
painter.end()
|
||||
|
||||
def wheelEvent(self, event):
|
||||
|
||||
@@ -15,6 +15,7 @@ class VTKWidget(QtWidgets.QWidget):
|
||||
super().__init__(parent)
|
||||
self.access_selected_points = []
|
||||
self.selected_normal = None
|
||||
self.centroid = None
|
||||
self.selected_edges = []
|
||||
self.cell_normals = None
|
||||
|
||||
@@ -26,6 +27,7 @@ class VTKWidget(QtWidgets.QWidget):
|
||||
|
||||
self.picked_edge_actors = []
|
||||
self.displayed_normal_actors = []
|
||||
self.body_actors_orig = []
|
||||
|
||||
self.flip_toggle = False
|
||||
|
||||
@@ -102,6 +104,54 @@ class VTKWidget(QtWidgets.QWidget):
|
||||
self.interactor.Initialize()
|
||||
self.interactor.Start()
|
||||
|
||||
# Create the grid
|
||||
grid = self.create_grid(size=100, spacing=10)
|
||||
|
||||
# Setup actor and mapper
|
||||
mapper = vtk.vtkPolyDataMapper()
|
||||
mapper.SetInputData(grid)
|
||||
|
||||
actor = vtk.vtkActor()
|
||||
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()
|
||||
|
||||
# Create lines
|
||||
lines = vtk.vtkCellArray()
|
||||
|
||||
# Create the grid
|
||||
for i in range(-size, size + 1, spacing):
|
||||
# X-direction line
|
||||
points.InsertNextPoint(i, -size, 0)
|
||||
points.InsertNextPoint(i, size, 0)
|
||||
line = vtk.vtkLine()
|
||||
line.GetPointIds().SetId(0, points.GetNumberOfPoints() - 2)
|
||||
line.GetPointIds().SetId(1, points.GetNumberOfPoints() - 1)
|
||||
lines.InsertNextCell(line)
|
||||
|
||||
# Y-direction line
|
||||
points.InsertNextPoint(-size, i, 0)
|
||||
points.InsertNextPoint(size, i, 0)
|
||||
line = vtk.vtkLine()
|
||||
line.GetPointIds().SetId(0, points.GetNumberOfPoints() - 2)
|
||||
line.GetPointIds().SetId(1, points.GetNumberOfPoints() - 1)
|
||||
lines.InsertNextCell(line)
|
||||
|
||||
# Create a polydata to store everything in
|
||||
grid = vtk.vtkPolyData()
|
||||
|
||||
# Add the points to the dataset
|
||||
grid.SetPoints(points)
|
||||
|
||||
# Add the lines to the dataset
|
||||
grid.SetLines(lines)
|
||||
|
||||
return grid
|
||||
|
||||
def on_receive_command(self, command):
|
||||
"""Calls the individual commands pressed in main"""
|
||||
print("Receive command: ", command)
|
||||
@@ -147,7 +197,7 @@ class VTKWidget(QtWidgets.QWidget):
|
||||
# Create a transform for mirroring across the y-axis
|
||||
mirror_transform = vtk.vtkTransform()
|
||||
|
||||
if self.local_matrix:
|
||||
"""if self.local_matrix:
|
||||
print(self.local_matrix)
|
||||
matrix = vtk.vtkMatrix4x4()
|
||||
matrix.DeepCopy(self.local_matrix)
|
||||
@@ -156,8 +206,7 @@ class VTKWidget(QtWidgets.QWidget):
|
||||
|
||||
mirror_transform.Scale(-1, -1, 1) # Inverting the original mirror look down
|
||||
else:
|
||||
pass
|
||||
#mirror_transform.Scale(1, -1, 1) # This mirrors across the y-axis
|
||||
mirror_transform.Scale(1, 1, 1) # This mirrors across the y-axis"""
|
||||
|
||||
# Apply the transform to the polydata
|
||||
transformFilter = vtk.vtkTransformPolyDataFilter()
|
||||
@@ -172,7 +221,7 @@ class VTKWidget(QtWidgets.QWidget):
|
||||
actor = vtk.vtkActor()
|
||||
actor.SetMapper(mapper)
|
||||
actor.GetProperty().SetColor(1.0, 1.0, 1.0)
|
||||
actor.GetProperty().SetLineWidth(2) # Set line width
|
||||
actor.GetProperty().SetLineWidth(4) # Set line width
|
||||
|
||||
# Add the actor to the scene
|
||||
self.renderer.AddActor(actor)
|
||||
@@ -180,8 +229,9 @@ class VTKWidget(QtWidgets.QWidget):
|
||||
mapper.Update()
|
||||
self.vtk_widget.GetRenderWindow().Render()
|
||||
|
||||
|
||||
def render_from_points_direct_with_faces(self, vertices, faces, color=(0.1, 0.2, 0.8), line_width=2, point_size=5):
|
||||
"""Sketch Widget has inverted Y axiis therefore we invert y via scale here until fix"""
|
||||
|
||||
points = vtk.vtkPoints()
|
||||
|
||||
# Use SetData with numpy array
|
||||
@@ -209,32 +259,11 @@ class VTKWidget(QtWidgets.QWidget):
|
||||
normalGenerator.ComputeCellNormalsOn()
|
||||
normalGenerator.Update()
|
||||
|
||||
# Create a transform for mirroring across the y-axis
|
||||
mirror_transform = vtk.vtkTransform()
|
||||
|
||||
if self.local_matrix:
|
||||
"""Transforming to the position of the sketch projection with invert matrix"""
|
||||
print(self.local_matrix)
|
||||
matrix = vtk.vtkMatrix4x4()
|
||||
matrix.DeepCopy(self.local_matrix)
|
||||
matrix.Invert()
|
||||
mirror_transform.SetMatrix(matrix)
|
||||
|
||||
mirror_transform.Scale(-1, 1, 1) #Inverting the original mirror look down
|
||||
else:
|
||||
mirror_transform.Scale(1, -1, 1) # This mirrors across the y-axis
|
||||
|
||||
# Apply the transform to the polydata
|
||||
transformFilter = vtk.vtkTransformPolyDataFilter()
|
||||
transformFilter.SetInputData(polydata)
|
||||
transformFilter.SetTransform(mirror_transform)
|
||||
transformFilter.Update()
|
||||
|
||||
self.cell_normals = vtk_to_numpy(normalGenerator.GetOutput().GetCellData().GetNormals())
|
||||
|
||||
# Create a mapper and actor
|
||||
mapper = vtk.vtkPolyDataMapper()
|
||||
mapper.SetInputData(transformFilter.GetOutput())
|
||||
mapper.SetInputData(polydata)
|
||||
|
||||
actor = vtk.vtkActor()
|
||||
actor.SetMapper(mapper)
|
||||
@@ -243,8 +272,13 @@ class VTKWidget(QtWidgets.QWidget):
|
||||
actor.GetProperty().SetLineWidth(line_width)
|
||||
|
||||
self.renderer.AddActor(actor)
|
||||
self.body_actors_orig.append(actor)
|
||||
self.vtk_widget.GetRenderWindow().Render()
|
||||
|
||||
def clear_body_actors(self):
|
||||
for actor in self.body_actors_orig:
|
||||
self.renderer.RemoveActor(actor)
|
||||
|
||||
def visualize_matrix(self, matrix):
|
||||
points = vtk.vtkPoints()
|
||||
for i in range(4):
|
||||
@@ -277,40 +311,6 @@ class VTKWidget(QtWidgets.QWidget):
|
||||
|
||||
return vtk_array
|
||||
|
||||
def load_custom_mesh(self, vertices, faces):
|
||||
### Load meshes by own module
|
||||
# Create a vtkPoints object and store the points in it
|
||||
points = vtk.vtkPoints()
|
||||
for vertex in vertices:
|
||||
points.InsertNextPoint(vertex)
|
||||
|
||||
# Create a vtkCellArray to store the faces
|
||||
cells = vtk.vtkCellArray()
|
||||
for face in faces:
|
||||
triangle = vtk.vtkTriangle()
|
||||
triangle.GetPointIds().SetId(0, face[0])
|
||||
triangle.GetPointIds().SetId(1, face[1])
|
||||
triangle.GetPointIds().SetId(2, face[2])
|
||||
cells.InsertNextCell(triangle)
|
||||
|
||||
# Create a polydata object
|
||||
polydata = vtk.vtkPolyData()
|
||||
polydata.SetPoints(points)
|
||||
polydata.SetPolys(cells)
|
||||
|
||||
# Create mapper and actor
|
||||
mapper = vtk.vtkPolyDataMapper()
|
||||
mapper.SetInputData(polydata) # Make sure this line is present
|
||||
actor = vtk.vtkActor()
|
||||
actor.SetMapper(mapper)
|
||||
|
||||
# Add to renderer
|
||||
self.renderer.AddActor(actor)
|
||||
|
||||
# Force an update of the pipeline
|
||||
mapper.Update()
|
||||
self.vtk_widget.GetRenderWindow().Render()
|
||||
|
||||
def get_points_and_edges_from_polydata(self, polydata) -> list:
|
||||
# Extract points
|
||||
points = {}
|
||||
@@ -353,7 +353,7 @@ class VTKWidget(QtWidgets.QWidget):
|
||||
center_of_mass.SetInputData(projected_mesh)
|
||||
center_of_mass.SetUseScalarsAsWeights(False)
|
||||
center_of_mass.Update()
|
||||
centroid = center_of_mass.GetCenter()
|
||||
centroid = np.array(center_of_mass.GetCenter())
|
||||
|
||||
# Create a coordinate system on the plane
|
||||
z_axis = np.array(normal)
|
||||
@@ -363,68 +363,33 @@ class VTKWidget(QtWidgets.QWidget):
|
||||
x_axis = x_axis / np.linalg.norm(x_axis)
|
||||
y_axis = np.cross(z_axis, x_axis)
|
||||
|
||||
# Create transformation matrix
|
||||
matrix = vtk.vtkMatrix4x4()
|
||||
for i in range(3):
|
||||
matrix.SetElement(i, 0, x_axis[i])
|
||||
matrix.SetElement(i, 1, y_axis[i])
|
||||
matrix.SetElement(i, 2, z_axis[i])
|
||||
matrix.SetElement(i, 3, centroid[i])
|
||||
self.local_matrix = matrix
|
||||
matrix.Invert()
|
||||
# Create rotation matrix (3x3)
|
||||
rotation_matrix = np.column_stack((x_axis, y_axis, z_axis))
|
||||
|
||||
# Store the full transformation for later use if needed
|
||||
full_transform = np.eye(4)
|
||||
full_transform[:3, :3] = rotation_matrix
|
||||
full_transform[:3, 3] = centroid
|
||||
self.local_matrix = full_transform
|
||||
|
||||
# Transform points to 2D coordinates
|
||||
transform = vtk.vtkTransform()
|
||||
transform.SetMatrix(matrix)
|
||||
transform.Scale([1,1,1])
|
||||
|
||||
transformer = vtk.vtkTransformPolyDataFilter()
|
||||
transformer.SetInputData(projected_mesh)
|
||||
transformer.SetTransform(transform)
|
||||
transformer.Update()
|
||||
|
||||
transformed_mesh = transformer.GetOutput()
|
||||
points = transformed_mesh.GetPoints()
|
||||
|
||||
points = projected_mesh.GetPoints()
|
||||
xy_coordinates = []
|
||||
|
||||
for i in range(points.GetNumberOfPoints()):
|
||||
point = points.GetPoint(i)
|
||||
xy_coordinates.append((-point[0], point[1]))
|
||||
point = np.array(points.GetPoint(i))
|
||||
|
||||
# Translate point to origin
|
||||
point_centered = point - centroid
|
||||
|
||||
# Rotate point
|
||||
rotated_point = np.dot(rotation_matrix.T, point_centered)
|
||||
|
||||
# Store only x and y coordinates
|
||||
xy_coordinates.append((rotated_point[0], rotated_point[1]))
|
||||
|
||||
return xy_coordinates
|
||||
|
||||
def create_normal_gizmo(self, normal, scale=1.0):
|
||||
# Normalize the normal vector
|
||||
normal = np.array(normal)
|
||||
normal = normal / np.linalg.norm(normal)
|
||||
|
||||
# Create an arrow source
|
||||
arrow_source = vtk.vtkArrowSource()
|
||||
arrow_source.SetTipResolution(20)
|
||||
arrow_source.SetShaftResolution(20)
|
||||
|
||||
# Create a transform to orient and position the arrow
|
||||
transform = vtk.vtkTransform()
|
||||
|
||||
# Translate to the origin point
|
||||
transform.SetMatrix(self.local_matrix)
|
||||
|
||||
# Apply the transform to the arrow
|
||||
transform_filter = vtk.vtkTransformPolyDataFilter()
|
||||
transform_filter.SetInputConnection(arrow_source.GetOutputPort())
|
||||
transform_filter.SetTransform(transform)
|
||||
transform_filter.Update()
|
||||
|
||||
# Create mapper and actor
|
||||
mapper = vtk.vtkPolyDataMapper()
|
||||
mapper.SetInputConnection(transform_filter.GetOutputPort())
|
||||
|
||||
actor = vtk.vtkActor()
|
||||
actor.SetMapper(mapper)
|
||||
actor.GetProperty().SetColor(1, 0, 0) # Red color for the arrow
|
||||
|
||||
return actor
|
||||
|
||||
def add_normal_line(self, origin, normal, length=10.0, color=(1, 0, 0)):
|
||||
# Normalize the normal vector
|
||||
normal = np.array(normal)
|
||||
@@ -520,7 +485,7 @@ class VTKWidget(QtWidgets.QWidget):
|
||||
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
|
||||
edge_actor.GetProperty().SetLineWidth(8) # Make the line thicker
|
||||
|
||||
# Add the actor to the renderer and store it
|
||||
self.renderer.AddActor(edge_actor)
|
||||
@@ -530,9 +495,18 @@ class VTKWidget(QtWidgets.QWidget):
|
||||
self.compute_projection(False)
|
||||
|
||||
elif len(self.selected_edges) > 2:
|
||||
del self.selected_edges[0]
|
||||
pass
|
||||
|
||||
def clear_edge_select(self, ):
|
||||
def find_origin_vertex(self, edge1, edge2):
|
||||
if edge1[0] == edge2[0]or edge1[0] == edge2[1]:
|
||||
return edge1[0]
|
||||
elif edge1[1] == edge2[0] or edge1[1] == edge2[1]:
|
||||
return edge1[1]
|
||||
else:
|
||||
return None # The edges don't share a vertex
|
||||
|
||||
def clear_edge_select(self ):
|
||||
# Clear selection after projection was succesful
|
||||
self.selected_edges = []
|
||||
self.selected_normal = []
|
||||
@@ -559,21 +533,22 @@ class VTKWidget(QtWidgets.QWidget):
|
||||
else:
|
||||
self.selected_normal = selected_normal
|
||||
|
||||
centroid = np.mean([point for edge in self.selected_edges for point in edge], axis=0)
|
||||
self.centroid = np.mean([point for edge in self.selected_edges for point in edge], axis=0)
|
||||
#self.centroid = self.find_origin_vertex(edge1, edge2)
|
||||
|
||||
# Draw the normal line
|
||||
normal_length = 50 # Adjust this value to change the length of the normal line
|
||||
normal_actor = self.add_normal_line(centroid, self.selected_normal, length=normal_length,
|
||||
normal_actor = self.add_normal_line(self.centroid, self.selected_normal, length=normal_length,
|
||||
color=(1, 0, 0))
|
||||
|
||||
polydata = self.picker.GetActor().GetMapper().GetInput()
|
||||
|
||||
projected_polydata = self.project_mesh_to_plane(polydata, self.selected_normal, centroid)
|
||||
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_edge = self.compute_2d_coordinates(projected_polydata, self.selected_normal)
|
||||
#print("3d_points_proj", self.project_tosketch_edge)
|
||||
|
||||
# Create a mapper and actor for the projected data
|
||||
|
||||
Reference in New Issue
Block a user