from PySide6.QtOpenGLWidgets import QOpenGLWidget from PySide6.QtCore import Qt, QPoint from OpenGL.GL import * from OpenGL.GLU import * from stl import mesh class OpenGLWidget(QOpenGLWidget): def __init__(self, parent=None): super().__init__(parent) self.stl_file = "out.stl" # Replace with your STL file path self.lastPos = QPoint() self.startPos = None self.endPos = None self.xRot = 0 self.yRot = 0 self.zoom = -10.0 self.sketch = [] self.gl_width = self.width() / 1000 self.gl_height = self.height() / 1000 print(self.gl_height) print(self.gl_width) def map_value_to_range(self, value, value_min: int = 0, value_max: int= 1920, range_min=-1, range_max=1): """ Maps a value from one range to another. Parameters: value (float): The value to be mapped. value_min (float): The minimum value of the input range. value_max (float): The maximum value of the input range. range_min (float, optional): The minimum value of the output range. Default is -1. range_max (float, optional): The maximum value of the output range. Default is 1. Returns: float: The mapped value in the output range. """ # Ensure value is within the input range value = max(value_min, min(value_max, value)) # Map the value to the output range mapped_value = ((value - value_min) / (value_max - value_min)) * (range_max - range_min) + range_min return mapped_value def load_stl(self, filename): try: stl_mesh = mesh.Mesh.from_file(filename) return stl_mesh.vectors except FileNotFoundError: print(f"Error: File {filename} not found.") except Exception as e: print(f"Error loading {filename}: {e}") return [] def initializeGL(self): glClearColor(0, 0, 0, 1) glEnable(GL_DEPTH_TEST) def resizeGL(self, width, height): glViewport(0, 0, width, height) glMatrixMode(GL_PROJECTION) glLoadIdentity() aspect = width / float(height) self.gl_width = self.width() / 1000 self.gl_height = self.height() / 1000 gluPerspective(45.0, aspect, 1.0, 100.0) glMatrixMode(GL_MODELVIEW) def paintGL(self): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glLoadIdentity() glTranslatef(0.0, 0.0, self.zoom) glRotatef(self.xRot, 1.0, 0.0, 0.0) glRotatef(self.yRot, 0.0, 1.0, 0.0) glColor3f(1.0, 1.0, 1.0) # Draw the rectangle if start and end positions are defined self.draw_area() if self.sketch: self.draw_lines_between_points(self.sketch) def draw_area(self): # Set line color glColor3f(0.5, 0.5, 0.5) # Gray color # Draw vertical lines glBegin(GL_LINES) for x in range(0, self.width(), 20): x_ndc = self.map_value_to_range(x, 0, value_max=self.width(), range_min=-self.gl_width, range_max=self.gl_width) glVertex2f(x_ndc, -self.gl_height) # Start from y = -1 glVertex2f(x_ndc, self.gl_height) # End at y = 1 # Draw horizontal lines for y in range(0, self.height(), 20): y_ndc = self.map_value_to_range(y, 0, value_max=self.height(), range_min=-self.gl_height, range_max=self.gl_height) glVertex2f(-self.gl_width, y_ndc) # Start from x = -1 glVertex2f(self.gl_width, y_ndc) # End at x = 1 glEnd() def draw_line(self, startPos, endPos): # Get normalized mouse coordinates print("start", startPos) print("end", endPos) x1, y1 = startPos x2, y2 = endPos # Adjust line width based on zoom level line_width = abs(2.0 / self.zoom) # Adjust line width inversely proportional to zoom glLineWidth(line_width) # Adjust line color glColor3f(1.0, 1.0, 0.0) # Yellow color # Draw the line glBegin(GL_LINES) glVertex2f(x1, y1) glVertex2f(x2, y2) glEnd() def draw_lines_between_points(self, points): glBegin(GL_LINES) glColor3f(1.0, 1.0, 1.0) # Set line color to white num_points = len(points) for i in range(num_points - 1): x1, y1 = points[i] x2, y2 = points[i + 1] glVertex2f(x1, y1) glVertex2f(x2, y2) # Connect the last point to the first point x1, y1 = points[num_points - 1] x2, y2 = points[0] glVertex2f(x1, y1) glVertex2f(x2, y2) glEnd() glPointSize(8) glBegin(GL_POINTS) glColor3f(1.0, 0.2, 1.0) # Set dot color to white for point in points: glVertex2f(point[0], point[1]) glEnd() def mousePressEvent(self, event): if event.buttons() & Qt.MouseButton.RightButton: # Get mouse position in widget coordinates mouse_pos = event.pos() # Map mouse position to normalized device coordinates normalized_x = self.map_value_to_range(mouse_pos.x(), 0, value_max=self.width(),range_min=-self.gl_width, range_max=self.gl_width) normalized_y = self.map_value_to_range(mouse_pos.y(), 0, value_max=self.height(),range_min=-self.gl_height, range_max=self.gl_height) self.startPos = [normalized_x * -self.zoom, -normalized_y * -self.zoom] # Now you have the mouse position in normalized coordinates print("Right mouse button pressed - Mouse position (normalized):", normalized_x, normalized_y) def mouseReleaseEvent(self, event): if event.button() == Qt.MouseButton.RightButton: mouse_pos = event.pos() # Map mouse position to normalized device coordinates normalized_x = self.map_value_to_range(mouse_pos.x(), 0, value_max=self.width(), range_min=-self.gl_width, range_max=self.gl_width) normalized_y = self.map_value_to_range(mouse_pos.y(), 0, value_max=self.height(), range_min=-self.gl_height, range_max=self.gl_height) self.endPos = [normalized_x * -self.zoom, -normalized_y * -self.zoom] self.add_to_sketch(self.startPos) self.add_to_sketch(self.endPos) self.update() print("releaseonly") # Now you have the mouse position in normalized coordinates print("Right mouse button pressed - Mouse position (normalized):", normalized_x, normalized_y) def mouseMoveEvent(self, event): dx = event.x() - self.lastPos.x() dy = event.y() - self.lastPos.y() if event.buttons() & Qt.MouseButton.LeftButton : self.xRot += 0.5 * dy self.yRot += 0.5 * dx self.lastPos = event.pos() self.update() def add_to_sketch(self, pos): self.sketch.append(pos) print(self.sketch) def wheelEvent(self, event): delta = event.angleDelta().y() self.zoom += delta / 120 self.update()