From e35ff3e9a1d6221d9922b033d6d7f8bdf1335d15 Mon Sep 17 00:00:00 2001 From: bklronin Date: Fri, 14 Jun 2024 14:38:11 +0200 Subject: [PATCH] - Basic polygon to body --- Gui.py | 321 +++++++++++++++++++--------- drawing_modules/draw_widget2d.py | 79 +++++++ drawing_modules/gl_widget.py | 151 +++++++++++++ gui.ui | 349 ++++++++++++++++++++++--------- main.py | 77 +++++-- modules/gl_widget.py | 200 ------------------ 6 files changed, 772 insertions(+), 405 deletions(-) create mode 100644 drawing_modules/draw_widget2d.py create mode 100644 drawing_modules/gl_widget.py delete mode 100644 modules/gl_widget.py diff --git a/Gui.py b/Gui.py index 72e7826..d4ffb62 100644 --- a/Gui.py +++ b/Gui.py @@ -15,118 +15,226 @@ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, QFont, QFontDatabase, QGradient, QIcon, QImage, QKeySequence, QLinearGradient, QPainter, QPalette, QPixmap, QRadialGradient, QTransform) -from PySide6.QtWidgets import (QApplication, QGroupBox, QHBoxLayout, QMainWindow, - QMenuBar, QPushButton, QSizePolicy, QStatusBar, - QTextEdit, QVBoxLayout, QWidget) +from PySide6.QtWidgets import (QApplication, QGridLayout, QGroupBox, QHBoxLayout, + QHeaderView, QMainWindow, QMenuBar, QPushButton, + QSizePolicy, QStatusBar, QTabWidget, QTextEdit, + QTreeView, QVBoxLayout, QWidget) class Ui_fluencyCAD(object): def setupUi(self, fluencyCAD): if not fluencyCAD.objectName(): fluencyCAD.setObjectName(u"fluencyCAD") - fluencyCAD.resize(892, 600) + fluencyCAD.resize(1755, 671) self.centralwidget = QWidget(fluencyCAD) self.centralwidget.setObjectName(u"centralwidget") - self.horizontalLayout_2 = QHBoxLayout(self.centralwidget) - self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") + self.gridLayout = QGridLayout(self.centralwidget) + self.gridLayout.setObjectName(u"gridLayout") self.groupBox_2 = QGroupBox(self.centralwidget) self.groupBox_2.setObjectName(u"groupBox_2") - self.verticalLayout_2 = QVBoxLayout(self.groupBox_2) - self.verticalLayout_2.setObjectName(u"verticalLayout_2") - self.pushButton_6 = QPushButton(self.groupBox_2) - self.pushButton_6.setObjectName(u"pushButton_6") + self.gridLayout_2 = QGridLayout(self.groupBox_2) + self.gridLayout_2.setObjectName(u"gridLayout_2") + self.pb_rectool = QPushButton(self.groupBox_2) + self.pb_rectool.setObjectName(u"pb_rectool") - self.verticalLayout_2.addWidget(self.pushButton_6) + self.gridLayout_2.addWidget(self.pb_rectool, 0, 1, 1, 1, Qt.AlignTop) + + self.pb_linetool = QPushButton(self.groupBox_2) + self.pb_linetool.setObjectName(u"pb_linetool") + + self.gridLayout_2.addWidget(self.pb_linetool, 0, 0, 1, 1, Qt.AlignTop) + + self.pb_circtool = QPushButton(self.groupBox_2) + self.pb_circtool.setObjectName(u"pb_circtool") + + self.gridLayout_2.addWidget(self.pb_circtool, 1, 0, 1, 1, Qt.AlignTop) + + self.pb_slotool = QPushButton(self.groupBox_2) + self.pb_slotool.setObjectName(u"pb_slotool") + + self.gridLayout_2.addWidget(self.pb_slotool, 1, 1, 1, 1, Qt.AlignTop) - self.horizontalLayout_2.addWidget(self.groupBox_2) - - self.verticalLayout = QVBoxLayout() - self.verticalLayout.setObjectName(u"verticalLayout") - self.gl_box = QGroupBox(self.centralwidget) - self.gl_box.setObjectName(u"gl_box") - sizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(4) - sizePolicy.setHeightForWidth(self.gl_box.sizePolicy().hasHeightForWidth()) - self.gl_box.setSizePolicy(sizePolicy) - self.horizontalLayout_4 = QHBoxLayout(self.gl_box) - self.horizontalLayout_4.setObjectName(u"horizontalLayout_4") - self.gl_canvas = QWidget(self.gl_box) - self.gl_canvas.setObjectName(u"gl_canvas") - - self.horizontalLayout_4.addWidget(self.gl_canvas) - - - self.verticalLayout.addWidget(self.gl_box) - - self.groupBox_3 = QGroupBox(self.centralwidget) - self.groupBox_3.setObjectName(u"groupBox_3") - sizePolicy1 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) - sizePolicy1.setHorizontalStretch(0) - sizePolicy1.setVerticalStretch(1) - sizePolicy1.setHeightForWidth(self.groupBox_3.sizePolicy().hasHeightForWidth()) - self.groupBox_3.setSizePolicy(sizePolicy1) - self.horizontalLayout_3 = QHBoxLayout(self.groupBox_3) - self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") - self.textEdit = QTextEdit(self.groupBox_3) - self.textEdit.setObjectName(u"textEdit") - - self.horizontalLayout_3.addWidget(self.textEdit) - - - self.verticalLayout.addWidget(self.groupBox_3) - - self.groupBox_4 = QGroupBox(self.centralwidget) - self.groupBox_4.setObjectName(u"groupBox_4") - self.horizontalLayout = QHBoxLayout(self.groupBox_4) - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.pb_apply_code = QPushButton(self.groupBox_4) - self.pb_apply_code.setObjectName(u"pb_apply_code") - - self.horizontalLayout.addWidget(self.pb_apply_code) - - self.pushButton = QPushButton(self.groupBox_4) - self.pushButton.setObjectName(u"pushButton") - - self.horizontalLayout.addWidget(self.pushButton) - - self.pushButton_2 = QPushButton(self.groupBox_4) - self.pushButton_2.setObjectName(u"pushButton_2") - - self.horizontalLayout.addWidget(self.pushButton_2) - - self.pushButton_4 = QPushButton(self.groupBox_4) - self.pushButton_4.setObjectName(u"pushButton_4") - - self.horizontalLayout.addWidget(self.pushButton_4) - - self.pushButton_5 = QPushButton(self.groupBox_4) - self.pushButton_5.setObjectName(u"pushButton_5") - - self.horizontalLayout.addWidget(self.pushButton_5) - - - self.verticalLayout.addWidget(self.groupBox_4) - - - self.horizontalLayout_2.addLayout(self.verticalLayout) + self.gridLayout.addWidget(self.groupBox_2, 1, 0, 1, 1) self.groupBox = QGroupBox(self.centralwidget) self.groupBox.setObjectName(u"groupBox") - self.verticalLayout_3 = QVBoxLayout(self.groupBox) - self.verticalLayout_3.setObjectName(u"verticalLayout_3") + self.gridLayout_3 = QGridLayout(self.groupBox) + self.gridLayout_3.setObjectName(u"gridLayout_3") self.pushButton_7 = QPushButton(self.groupBox) self.pushButton_7.setObjectName(u"pushButton_7") - self.verticalLayout_3.addWidget(self.pushButton_7) + self.gridLayout_3.addWidget(self.pushButton_7, 0, 0, 1, 1) + + self.pushButton_14 = QPushButton(self.groupBox) + self.pushButton_14.setObjectName(u"pushButton_14") + + self.gridLayout_3.addWidget(self.pushButton_14, 0, 1, 1, 1) + + self.pushButton_15 = QPushButton(self.groupBox) + self.pushButton_15.setObjectName(u"pushButton_15") + + self.gridLayout_3.addWidget(self.pushButton_15, 1, 1, 1, 1) + + self.pushButton_16 = QPushButton(self.groupBox) + self.pushButton_16.setObjectName(u"pushButton_16") + + self.gridLayout_3.addWidget(self.pushButton_16, 1, 0, 1, 1) - self.horizontalLayout_2.addWidget(self.groupBox) + self.gridLayout.addWidget(self.groupBox, 0, 5, 3, 1, Qt.AlignTop) + + self.groupBox_6 = QGroupBox(self.centralwidget) + self.groupBox_6.setObjectName(u"groupBox_6") + self.verticalLayout_2 = QVBoxLayout(self.groupBox_6) + self.verticalLayout_2.setObjectName(u"verticalLayout_2") + self.pb_nw_sktch = QPushButton(self.groupBox_6) + self.pb_nw_sktch.setObjectName(u"pb_nw_sktch") + + self.verticalLayout_2.addWidget(self.pb_nw_sktch) + + self.pb_edt_sktch = QPushButton(self.groupBox_6) + self.pb_edt_sktch.setObjectName(u"pb_edt_sktch") + + self.verticalLayout_2.addWidget(self.pb_edt_sktch) + + self.pb_del_sketch = QPushButton(self.groupBox_6) + self.pb_del_sketch.setObjectName(u"pb_del_sketch") + + self.verticalLayout_2.addWidget(self.pb_del_sketch) + + self.pushButton_13 = QPushButton(self.groupBox_6) + self.pushButton_13.setObjectName(u"pushButton_13") + + self.verticalLayout_2.addWidget(self.pushButton_13) + + + self.gridLayout.addWidget(self.groupBox_6, 0, 0, 1, 1) + + self.groupBox_3 = QGroupBox(self.centralwidget) + self.groupBox_3.setObjectName(u"groupBox_3") + self.gridLayout_4 = QGridLayout(self.groupBox_3) + self.gridLayout_4.setObjectName(u"gridLayout_4") + self.pb_con_line = QPushButton(self.groupBox_3) + self.pb_con_line.setObjectName(u"pb_con_line") + + self.gridLayout_4.addWidget(self.pb_con_line, 0, 1, 1, 1) + + self.pb_con_ptpt = QPushButton(self.groupBox_3) + self.pb_con_ptpt.setObjectName(u"pb_con_ptpt") + + self.gridLayout_4.addWidget(self.pb_con_ptpt, 0, 0, 1, 1) + + self.pb_con_horiz = QPushButton(self.groupBox_3) + self.pb_con_horiz.setObjectName(u"pb_con_horiz") + + self.gridLayout_4.addWidget(self.pb_con_horiz, 1, 0, 1, 1) + + self.pb_con_vert = QPushButton(self.groupBox_3) + self.pb_con_vert.setObjectName(u"pb_con_vert") + + self.gridLayout_4.addWidget(self.pb_con_vert, 1, 1, 1, 1) + + + self.gridLayout.addWidget(self.groupBox_3, 2, 0, 1, 1) + + self.groupBox_7 = QGroupBox(self.centralwidget) + self.groupBox_7.setObjectName(u"groupBox_7") + self.verticalLayout_5 = QVBoxLayout(self.groupBox_7) + self.verticalLayout_5.setObjectName(u"verticalLayout_5") + self.pb_apply_code = QPushButton(self.groupBox_7) + self.pb_apply_code.setObjectName(u"pb_apply_code") + + self.verticalLayout_5.addWidget(self.pb_apply_code) + + self.pushButton = QPushButton(self.groupBox_7) + self.pushButton.setObjectName(u"pushButton") + + self.verticalLayout_5.addWidget(self.pushButton) + + self.pushButton_5 = QPushButton(self.groupBox_7) + self.pushButton_5.setObjectName(u"pushButton_5") + + self.verticalLayout_5.addWidget(self.pushButton_5) + + self.pushButton_4 = QPushButton(self.groupBox_7) + self.pushButton_4.setObjectName(u"pushButton_4") + + self.verticalLayout_5.addWidget(self.pushButton_4) + + self.pushButton_2 = QPushButton(self.groupBox_7) + self.pushButton_2.setObjectName(u"pushButton_2") + + self.verticalLayout_5.addWidget(self.pushButton_2) + + + self.gridLayout.addWidget(self.groupBox_7, 3, 0, 1, 1) + + self.InputTab = QTabWidget(self.centralwidget) + self.InputTab.setObjectName(u"InputTab") + sizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.InputTab.sizePolicy().hasHeightForWidth()) + self.InputTab.setSizePolicy(sizePolicy) + self.sketch_tab = QWidget() + self.sketch_tab.setObjectName(u"sketch_tab") + self.verticalLayout_4 = QVBoxLayout(self.sketch_tab) + self.verticalLayout_4.setObjectName(u"verticalLayout_4") + self.InputTab.addTab(self.sketch_tab, "") + self.code_tab = QWidget() + self.code_tab.setObjectName(u"code_tab") + self.verticalLayout = QVBoxLayout(self.code_tab) + self.verticalLayout.setObjectName(u"verticalLayout") + self.textEdit = QTextEdit(self.code_tab) + self.textEdit.setObjectName(u"textEdit") + + self.verticalLayout.addWidget(self.textEdit) + + self.InputTab.addTab(self.code_tab, "") + + self.gridLayout.addWidget(self.InputTab, 0, 2, 4, 1) + + self.groupBox_5 = QGroupBox(self.centralwidget) + self.groupBox_5.setObjectName(u"groupBox_5") + sizePolicy1 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + sizePolicy1.setHorizontalStretch(0) + sizePolicy1.setVerticalStretch(0) + sizePolicy1.setHeightForWidth(self.groupBox_5.sizePolicy().hasHeightForWidth()) + self.groupBox_5.setSizePolicy(sizePolicy1) + self.groupBox_5.setMaximumSize(QSize(300, 16777215)) + self.verticalLayout_3 = QVBoxLayout(self.groupBox_5) + self.verticalLayout_3.setObjectName(u"verticalLayout_3") + self.comp_tree = QTreeView(self.groupBox_5) + self.comp_tree.setObjectName(u"comp_tree") + + self.verticalLayout_3.addWidget(self.comp_tree) + + + self.gridLayout.addWidget(self.groupBox_5, 0, 3, 4, 1) + + self.gl_box = QGroupBox(self.centralwidget) + self.gl_box.setObjectName(u"gl_box") + sizePolicy2 = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) + sizePolicy2.setHorizontalStretch(0) + sizePolicy2.setVerticalStretch(4) + sizePolicy2.setHeightForWidth(self.gl_box.sizePolicy().hasHeightForWidth()) + self.gl_box.setSizePolicy(sizePolicy2) + font = QFont() + font.setPointSize(12) + self.gl_box.setFont(font) + self.horizontalLayout_4 = QHBoxLayout(self.gl_box) +#ifndef Q_OS_MAC + self.horizontalLayout_4.setSpacing(-1) +#endif + self.horizontalLayout_4.setObjectName(u"horizontalLayout_4") + self.horizontalLayout_4.setContentsMargins(12, -1, -1, -1) + + self.gridLayout.addWidget(self.gl_box, 0, 4, 4, 1) fluencyCAD.setCentralWidget(self.centralwidget) self.menubar = QMenuBar(fluencyCAD) self.menubar.setObjectName(u"menubar") - self.menubar.setGeometry(QRect(0, 0, 892, 24)) + self.menubar.setGeometry(QRect(0, 0, 1755, 24)) fluencyCAD.setMenuBar(self.menubar) self.statusbar = QStatusBar(fluencyCAD) self.statusbar.setObjectName(u"statusbar") @@ -134,22 +242,43 @@ class Ui_fluencyCAD(object): self.retranslateUi(fluencyCAD) + self.InputTab.setCurrentIndex(0) + + QMetaObject.connectSlotsByName(fluencyCAD) # setupUi def retranslateUi(self, fluencyCAD): fluencyCAD.setWindowTitle(QCoreApplication.translate("fluencyCAD", u"fluencyCAD", None)) self.groupBox_2.setTitle(QCoreApplication.translate("fluencyCAD", u"Drawing", None)) - self.pushButton_6.setText(QCoreApplication.translate("fluencyCAD", u"PushButton", None)) - self.gl_box.setTitle(QCoreApplication.translate("fluencyCAD", u"Model Viewer", None)) - self.groupBox_3.setTitle(QCoreApplication.translate("fluencyCAD", u"Code Editor", None)) - self.groupBox_4.setTitle(QCoreApplication.translate("fluencyCAD", u"Code Tools", None)) + self.pb_rectool.setText(QCoreApplication.translate("fluencyCAD", u"Rctgl", None)) + self.pb_linetool.setText(QCoreApplication.translate("fluencyCAD", u"Line", None)) + self.pb_circtool.setText(QCoreApplication.translate("fluencyCAD", u"Circle", None)) + self.pb_slotool.setText(QCoreApplication.translate("fluencyCAD", u"Slot", None)) + self.groupBox.setTitle(QCoreApplication.translate("fluencyCAD", u"Modify", None)) + self.pushButton_7.setText(QCoreApplication.translate("fluencyCAD", u"Cut", None)) + self.pushButton_14.setText(QCoreApplication.translate("fluencyCAD", u"Arry", None)) + self.pushButton_15.setText(QCoreApplication.translate("fluencyCAD", u"Extrd", None)) + self.pushButton_16.setText(QCoreApplication.translate("fluencyCAD", u"Rev", None)) + self.groupBox_6.setTitle(QCoreApplication.translate("fluencyCAD", u"Sketchtools", None)) + self.pb_nw_sktch.setText(QCoreApplication.translate("fluencyCAD", u"Nw Sktch Wp", None)) + self.pb_edt_sktch.setText(QCoreApplication.translate("fluencyCAD", u"Edt Sketch", None)) + self.pb_del_sketch.setText(QCoreApplication.translate("fluencyCAD", u"Sktch del", None)) + self.pushButton_13.setText(QCoreApplication.translate("fluencyCAD", u"PushButton", None)) + self.groupBox_3.setTitle(QCoreApplication.translate("fluencyCAD", u"Constrain", None)) + self.pb_con_line.setText(QCoreApplication.translate("fluencyCAD", u"Pt_Line", None)) + self.pb_con_ptpt.setText(QCoreApplication.translate("fluencyCAD", u"Pt_Pt", None)) + self.pb_con_horiz.setText(QCoreApplication.translate("fluencyCAD", u"Horiz", None)) + self.pb_con_vert.setText(QCoreApplication.translate("fluencyCAD", u"Vert", None)) + self.groupBox_7.setTitle(QCoreApplication.translate("fluencyCAD", u"Executive", None)) self.pb_apply_code.setText(QCoreApplication.translate("fluencyCAD", u"Apply Code", None)) self.pushButton.setText(QCoreApplication.translate("fluencyCAD", u"Delete Code", None)) - self.pushButton_2.setText(QCoreApplication.translate("fluencyCAD", u"Export STL", None)) - self.pushButton_4.setText(QCoreApplication.translate("fluencyCAD", u"Save code", None)) self.pushButton_5.setText(QCoreApplication.translate("fluencyCAD", u"Load Code", None)) - self.groupBox.setTitle(QCoreApplication.translate("fluencyCAD", u"Modify", None)) - self.pushButton_7.setText(QCoreApplication.translate("fluencyCAD", u"PushButton", None)) + self.pushButton_4.setText(QCoreApplication.translate("fluencyCAD", u"Save code", None)) + self.pushButton_2.setText(QCoreApplication.translate("fluencyCAD", u"Export STL", None)) + self.InputTab.setTabText(self.InputTab.indexOf(self.sketch_tab), QCoreApplication.translate("fluencyCAD", u"Sketch", None)) + self.InputTab.setTabText(self.InputTab.indexOf(self.code_tab), QCoreApplication.translate("fluencyCAD", u"Code", None)) + self.groupBox_5.setTitle(QCoreApplication.translate("fluencyCAD", u"Components", None)) + self.gl_box.setTitle(QCoreApplication.translate("fluencyCAD", u"Model Viewer", None)) # retranslateUi diff --git a/drawing_modules/draw_widget2d.py b/drawing_modules/draw_widget2d.py new file mode 100644 index 0000000..13e8393 --- /dev/null +++ b/drawing_modules/draw_widget2d.py @@ -0,0 +1,79 @@ +from PySide6.QtWidgets import QApplication, QWidget, QMessageBox +from PySide6.QtGui import QPainter, QPen, QColor +from PySide6.QtCore import Qt, QPoint + + +class SnapLineWidget(QWidget): + def __init__(self): + super().__init__() + self.points = [] + self.selected_line = None + self.snapping_range = 20 # Range in pixels for snapping + + def mousePressEvent(self, event): + if event.button() == Qt.LeftButton: + self.points.append(event.pos()) + self.update() + + if event.button() == Qt.RightButton: + for i in range(len(self.points) - 1): + if self.is_point_on_line(event.pos(), self.points[i], self.points[i + 1]): + self.selected_line = i + break + else: + self.selected_line = None + + def mouseMoveEvent(self, event): + if event.buttons() & Qt.LeftButton: + if self.selected_line is not None: + self.points[self.selected_line] = event.pos() + else: + self.points[-1] = event.pos() + self.update() + + def mouseDoubleClickEvent(self, event): + pass + + def distance(self, p1, p2): + return ((p1.x() - p2.x()) ** 2 + (p1.y() - p2.y()) ** 2) ** 0.5 + + def is_point_on_line(self, p, p1, p2): + distance1 = self.distance(p, p1) + distance2 = self.distance(p, p2) + total_distance = self.distance(p1, p2) + return abs(distance1 + distance2 - total_distance) < 0.1 + + def paintEvent(self, event): + painter = QPainter(self) + + # Set the background color + painter.fillRect(self.rect(), QColor('white')) + + pen = QPen(Qt.black) + pen.setWidth(1) + painter.setPen(pen) + + for i in range(len(self.points) - 1): + painter.drawLine(self.points[i], self.points[i + 1]) + + # Draw points + for point in self.points: + painter.drawEllipse(point, 3, 3) + + if self.selected_line is not None: + p1 = self.points[self.selected_line] + p2 = self.points[self.selected_line + 1] + painter.setPen(QPen(Qt.red, 2)) + painter.drawLine(p1, p2) + + +# Example usage +if __name__ == "__main__": + import sys + + app = QApplication(sys.argv) + window = SnapLineWidget() + window.setWindowTitle("Snap Line Widget") + window.resize(800, 600) + window.show() + sys.exit(app.exec()) diff --git a/drawing_modules/gl_widget.py b/drawing_modules/gl_widget.py new file mode 100644 index 0000000..bf7e264 --- /dev/null +++ b/drawing_modules/gl_widget.py @@ -0,0 +1,151 @@ +import numpy as np +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 + + def map_value_to_range(self, value, value_min=0, value_max=1920, range_min=-1, range_max=1): + value = max(value_min, min(value_max, value)) + 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) + + # Extract vertices + vertices = np.concatenate([stl_mesh.v0, stl_mesh.v1, stl_mesh.v2]) + + # Calculate bounding box + min_x, min_y, min_z = vertices.min(axis=0) + max_x, max_y, max_z = vertices.max(axis=0) + + # Calculate centroid + centroid_x = (min_x + max_x) / 2.0 + centroid_y = (min_y + max_y) / 2.0 + centroid_z = (min_z + max_z) / 2.0 + + return stl_mesh.vectors, (centroid_x, centroid_y, centroid_z) + except FileNotFoundError: + print(f"Error: File {filename} not found.") + except Exception as e: + print(f"Error loading {filename}: {e}") + return None, (0, 0, 0) + + 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, 1000.0) + glMatrixMode(GL_MODELVIEW) + + def paintGL(self): + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + glLoadIdentity() + + mesh_loaded, centroid = self.load_stl(self.stl_file) + centroid_x, centroid_y, centroid_z = centroid + + glTranslatef(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) + + self.draw_area() + + if mesh is not None: + # Scale the object + scale_factor = 0.001 # Example scale factor (adjust as needed) + glScalef(scale_factor, scale_factor, scale_factor) + + # Translate to move the centroid of the object to the origin + glTranslatef(-centroid_x, -centroid_y, -centroid_z) + + + + self.draw_stl(mesh_loaded) + + 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, 1.0)) + + 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 vertex in vertices: + glVertex3fv(vertex) + glEnd()""" + + def draw_area(self): + glColor3f(0.5, 0.5, 0.5) # Gray color + + 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 + + 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 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 wheelEvent(self, event): + delta = event.angleDelta().y() + self.zoom += delta / 120 + self.update() + + def aspect_ratio(self): + return self.width() / self.height() * (1.0 / abs(self.zoom)) + diff --git a/gui.ui b/gui.ui index 13da2ca..a1fadf4 100644 --- a/gui.ui +++ b/gui.ui @@ -6,23 +6,118 @@ 0 0 - 892 - 600 + 1755 + 671 fluencyCAD - - + + Drawing + + + + + Rctgl + + + + + + + Line + + + + + + + Circle + + + + + + + Slot + + + + + + + + + + Modify + + + + + + Cut + + + + + + + Arry + + + + + + + Extrd + + + + + + + Rev + + + + + + + + + + Sketchtools + - + + + Nw Sktch Wp + + + + + + + Edt Sketch + + + + + + + Sktch del + + + + + PushButton @@ -31,103 +126,163 @@ - - - - - - - 0 - 4 - - - - Model Viewer - - - - - - - - - - - - - 0 - 1 - - - - Code Editor - - - - - - - - - - - - Code Tools - - - - - - Apply Code - - - - - - - Delete Code - - - - - - - Export STL - - - - - - - Save code - - - - - - - Load Code - - - - - - - - - - + + - Modify + Constrain - - - + + + - PushButton + Pt_Line + + + + Pt_Pt + + + + + + + Horiz + + + + + + + Vert + + + + + + + + + + Executive + + + + + + Apply Code + + + + + + + Delete Code + + + + + + + Load Code + + + + + + + Save code + + + + + + + Export STL + + + + + + + + + + + 0 + 0 + + + + 0 + + + + Sketch + + + + + + Code + + + + + + + + + + + + + + 0 + 0 + + + + + 300 + 16777215 + + + + Components + + + + + + + + + + + + + 0 + 4 + + + + + 12 + + + + Model Viewer + + + + -1 + + + 12 + @@ -138,7 +293,7 @@ 0 0 - 892 + 1755 24 diff --git a/main.py b/main.py index 78d7fe3..19ad85c 100644 --- a/main.py +++ b/main.py @@ -1,8 +1,9 @@ from PySide6.QtWidgets import QApplication, QMainWindow, QSizePolicy from Gui import Ui_fluencyCAD # Import the generated GUI module -from modules.gl_widget import OpenGLWidget +from drawing_modules.gl_widget import OpenGLWidget +from drawing_modules.draw_widget2d import SnapLineWidget from sdf import * - +import python_solvespace class MainWindow(QMainWindow): def __init__(self): @@ -13,14 +14,40 @@ class MainWindow(QMainWindow): self.ui.setupUi(self) self.openGLWidget = OpenGLWidget() - self.openGLWidget.setParent(self.ui.gl_canvas) - # Connect the resizeEvent of the parent widget to a function - self.ui.gl_canvas.resizeEvent = self.glCanvasResized + layout = self.ui.gl_box.layout() + layout.addWidget(self.openGLWidget) + size_policy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) + #self.openGLWidget.setSizePolicy(size_policy) - self.ui.pb_apply_code.pressed.connect(self.generate_mesh) + self.sketchWidget = SnapLineWidget() + layout2 = self.ui.sketch_tab.layout() # Get the layout of self.ui.gl_canvas + layout2.addWidget(self.sketchWidget) + size_policy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) + self.sketchWidget.setSizePolicy(size_policy) + self.sketchWidget.setStyleSheet("background-color: white; border: 1px solid red;") + + self.ui.pb_apply_code.pressed.connect(self.check_current_tab) + + def check_current_tab(self): + if self.ui.InputTab.currentIndex() == 0: + self.generate_mesh_from_draw() + elif self.ui.InputTab.currentIndex() == 1: + self.generate_mesh_from_code() + + def load_and_render(self, file, centroid): + self.openGLWidget.draw_stl(file) + self.openGLWidget.update() - def generate_mesh(self): + +class Geometry: + def distance(self, p1, p2): + """Calculate the distance between two points.""" + print("p1", p1) + print("p2", p2) + return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2) + + def generate_mesh_from_code(self): code_bytes = self.ui.textEdit.toPlainText().encode('utf-8') code_text = code_bytes.decode('utf-8') save_string = "\nf.save('out.stl', samples=2**12)" @@ -39,12 +66,38 @@ class MainWindow(QMainWindow): except Exception as e: print("Error executing code:", e) + def generate_mesh_from_draw(self, points, ): + f = None + points = MainWindow().sketchWidget.points + print(points) + p_list = [] + dimension = 0.001 + for ps in points: + p_list.append((ps.x() , ps.y())) + + #p_list.append(p_list[0]) + print(p_list) + f = polygon(p_list).extrude(100) + + """if len(points) > 3: + p1 = [points[0].x(), points[0].y()] + p2 = [points[1].x(), points[1].y()] + dimension = self.distance(p1, p2) + scale = 0.001 + f = box(dimension * scale) + elif len(points) < 3: + p1 = [points[0].x(), points[0].y()] + p2 = [points[1].x(), points[1].y()] + dimension = self.distance(p1, p2) + scale = 0.001 + print(dimension * scale) + f = sphere(dimension * scale)""" + + if f: + f.save('out.stl', samples=2**12, sparse=False) + + - def glCanvasResized(self, event): - # Get the size of the gl_canvas - canvas_size = self.ui.gl_canvas.size() - # Resize the OpenGL widget to match the size of the gl_canvas - self.openGLWidget.resize(canvas_size) if __name__ == "__main__": app = QApplication([]) diff --git a/modules/gl_widget.py b/modules/gl_widget.py deleted file mode 100644 index 4b702a0..0000000 --- a/modules/gl_widget.py +++ /dev/null @@ -1,200 +0,0 @@ -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() -