diff --git a/2d_draw.py b/2d_draw.py new file mode 100644 index 0000000..f2b6ffd --- /dev/null +++ b/2d_draw.py @@ -0,0 +1,81 @@ +import sys + +from OpenGL.raw.GL.VERSION.GL_1_0 import glClearColor +from PySide6.QtCore import Qt +from PySide6.QtOpenGLWidgets import QOpenGLWidget +from PySide6.QtWidgets import QDoubleSpinBox, QPushButton, QVBoxLayout, QApplication, QWidget +from OpenGL.GL import * +from OpenGL.GLUT import * + +class GLWidget(QOpenGLWidget): + def __init__(self, parent=None): + super(GLWidget, self).__init__(parent) + self.shapes = [] + self.extruded_shapes = [] + + def initializeGL(self): + glClearColor(1, 1, 1, 1) + + def paintGL(self): + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + glLoadIdentity() + glColor3f(1, 0, 0) + + for shape in self.shapes: + glBegin(GL_LINE_LOOP) + glVertex2f(shape[0], shape[1]) # Access x and y coordinates of the point + glEnd() + + def resizeGL(self, w, h): + glViewport(0, 0, w, h) + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + glOrtho(0, w, h, 0, -1, 1) + glMatrixMode(GL_MODELVIEW) + + def mousePressEvent(self, event): + if event.button() == Qt.LeftButton: + pos = event.pos() + x = int(pos.x()) + y = int(pos.y()) + self.shapes.append((x, y)) # Append coordinate tuple (x, y) + self.update() + def extrude_shapes(self, height): + self.extruded_shapes = [] + for shape in self.shapes: + extruded_shape = [] + for point in shape: + extruded_shape.append([point[0], point[1]]) + for point in shape: + extruded_shape.append([point[0], point[1] + height]) + self.extruded_shapes.append(extruded_shape) + +class MainWindow(QWidget): + def __init__(self): + super(MainWindow, self).__init__() + self.gl_widget = GLWidget() + self.height_spin_box = QDoubleSpinBox() + self.height_spin_box.setRange(0, 100) + self.height_spin_box.setValue(10) + self.extrude_button = QPushButton("Extrude") + self.extrude_button.clicked.connect(self.extrude_shapes) + + layout = QVBoxLayout() + layout.addWidget(self.gl_widget) + layout.addWidget(self.height_spin_box) + layout.addWidget(self.extrude_button) + + self.setLayout(layout) + + def extrude_shapes(self): + height = self.height_spin_box.value() + self.gl_widget.extrude_shapes(height) + self.gl_widget.update() + +if __name__ == "__main__": + app = QApplication(sys.argv) + window = MainWindow() + window.setGeometry(100, 100, 800, 600) + window.setWindowTitle("Extrude Shapes") + window.show() + sys.exit(app.exec_()) \ No newline at end of file diff --git a/main.py b/main.py index 1688d58..78d7fe3 100644 --- a/main.py +++ b/main.py @@ -19,6 +19,7 @@ class MainWindow(QMainWindow): self.ui.pb_apply_code.pressed.connect(self.generate_mesh) + def generate_mesh(self): code_bytes = self.ui.textEdit.toPlainText().encode('utf-8') code_text = code_bytes.decode('utf-8') diff --git a/modules/gl_widget.py b/modules/gl_widget.py index af01371..86179ab 100644 --- a/modules/gl_widget.py +++ b/modules/gl_widget.py @@ -1,19 +1,42 @@ from PySide6.QtOpenGLWidgets import QOpenGLWidget -from PySide6.QtCore import QSize, Qt, QPoint +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 + 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) @@ -28,11 +51,13 @@ class OpenGLWidget(QOpenGLWidget): glClearColor(0, 0, 0, 1) glEnable(GL_DEPTH_TEST) - def resizeGL(self, w, h): - glViewport(0, 0, w, h) + def resizeGL(self, width, height): + glViewport(0, 0, width, height) glMatrixMode(GL_PROJECTION) glLoadIdentity() - gluPerspective(45, w/h, 0.1, 100.0) + aspect = width / float(height) + + gluPerspective(45.0, aspect, 1.0, 100.0) glMatrixMode(GL_MODELVIEW) def paintGL(self): @@ -43,66 +68,116 @@ class OpenGLWidget(QOpenGLWidget): glRotatef(self.yRot, 0.0, 1.0, 0.0) glColor3f(1.0, 1.0, 1.0) - mesh_data = self.load_stl(self.stl_file) - if mesh_data.any(): - self.draw_stl(mesh_data) + # Draw the rectangle if start and end positions are defined + self.draw_area() + if self.startPos and self.endPos: + self.draw_line(self.startPos, self.endPos) - def draw_stl(self, vertices): - glEnable(GL_LIGHTING) - glEnable(GL_LIGHT0) - glEnable(GL_DEPTH_TEST) - glEnable(GL_COLOR_MATERIAL) - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE) - glLightfv(GL_LIGHT0, GL_POSITION, (0, 1, 1, 0)) - glLightfv(GL_LIGHT0, GL_DIFFUSE, (0.6, 0.6, 0.6, 0.6)) + def draw_area(self): + # Set line color + glColor3f(0.5, 0.5, 0.5) # Gray color - glBegin(GL_TRIANGLES) - for triangle in vertices: - for vertex in triangle: - glVertex3fv(vertex) - glEnd() - - # Draw outer vertices as points - glDisable(GL_LIGHTING) - glColor3f(1.0, 0.0, 0.0) # Set color to red - glPointSize(5.0) # Set point size - glBegin(GL_POINTS) - for triangle in vertices: - for vertex in triangle: - glVertex3fv(vertex) - glEnd() - - # Draw edges - glColor3f(0.0, 0.0, 1.0) # Set color to blue - glLineWidth(2.0) # Set line width + # Draw vertical lines glBegin(GL_LINES) - for triangle in vertices: - glVertex3fv(triangle[0]) - glVertex3fv(triangle[1]) + for x in range(0, self.width(), 20): + x_ndc = self.map_value_to_range(x, 0, value_max=self.width(), range_min=-1, range_max=1) + glVertex2f(x_ndc, -1) # Start from y = -1 + glVertex2f(x_ndc, 1) # End at y = 1 + glEnd() - glVertex3fv(triangle[1]) - glVertex3fv(triangle[2]) + # Draw horizontal lines + glBegin(GL_LINES) + for y in range(0, self.height(), 20): + y_ndc = self.map_value_to_range(y, 0, value_max=self.height(),range_min=-1, range_max=1) + glVertex2f(-1, y_ndc) # Start from x = -1 + glVertex2f(1, y_ndc) # End at x = 1 + glEnd() - glVertex3fv(triangle[2]) - glVertex3fv(triangle[0]) + 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 mousePressEvent(self, event): - self.lastPos = event.pos() + if event.buttons() & Qt.MouseButton.LeftButton: + # 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, self.width()) + normalized_y = self.map_value_to_range(mouse_pos.y(), 0, self.height()) + + 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=-1, range_max=1) + normalized_y = self.map_value_to_range(mouse_pos.y(), 0, value_max=self.height(),range_min=-1, range_max=1) + + self.startPos = [normalized_x, -normalized_y] + + # 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): + print("release") + + # 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, self.width()) + normalized_y = self.map_value_to_range(mouse_pos.y(), 0, self.height()) + + self.endPos = [normalized_x, normalized_y] + print(self.endPos) + + # Now you have the mouse position in normalized coordinates + print("Right mouse button rel - Mouse position (normalized):", normalized_x, normalized_y) + #self.update()""" def mouseMoveEvent(self, event): dx = event.x() - self.lastPos.x() dy = event.y() - self.lastPos.y() - if event.buttons() & Qt.LeftButton: + if event.buttons() & Qt.MouseButton.LeftButton: self.xRot += 0.5 * dy self.yRot += 0.5 * dx self.update() - self.lastPos = event.pos() + if event.buttons() & 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, self.width()) + normalized_y = self.map_value_to_range(mouse_pos.y(), 0, self.height()) + + self.endPos = [normalized_x, -normalized_y] + print(self.endPos) + + # Now you have the mouse position in normalized coordinates + print("Right mouse button rel - Mouse position (normalized):", normalized_x, normalized_y) + self.update() def wheelEvent(self, event): delta = event.angleDelta().y() self.zoom += delta / 120 self.update() +