import re from copy import copy from PySide6.QtWidgets import QApplication, QWidget, QMessageBox from PySide6.QtGui import QPainter, QPen, QColor from PySide6.QtCore import Qt, QPoint from python_solvespace import SolverSystem, ResultFlag class SketchWidget(QWidget): def __init__(self): super().__init__() self.hovered_point = None self.line_buffer = None self.pt_pt_buffer = None self.points = [] self.selected_line = None self.snapping_range = 20 # Range in pixels for snapping self.setMouseTracking(True) self.mouse_mode = False self.wp = None self.solv = SolverSystem() self.solventies = [] def create_worplane(self): self.wp = self.solv.create_2d_base() def get_handle_nr(self, input_str: str) -> int: # Define the regex pattern to extract the handle number pattern = r"handle=(\d+)" # Use re.search to find the handle number in the string match = re.search(pattern, input_str) if match: handle_number = int(match.group(1)) print(f"Handle number: {handle_number}") return int(handle_number) else: print("Handle number not found.") return 0 def get_keys(self, d: dict, target: QPoint) -> list: result = [] path = [] print(d) print(target) for k, v in d.items(): path.append(k) if isinstance(v, dict): self.get_keys(v, target) if v == target: result.append(copy(path)) path.pop() return result def mousePressEvent(self, event): relation = { 'handle_nr': None, 'solv_handle': None } if event.button() == Qt.LeftButton and self.mouse_mode == "line": clicked_pos = event.pos() # Paintline """self.points.append(clicked_pos) self.update()""" u = clicked_pos.x() v = clicked_pos.y() point = self.solv.add_point_2d(u, v, self.wp) #print(point) #self.solv.dragged(point, self.wp) # Solverline if self.line_buffer: line = self.solv.add_line_2d(self.line_buffer, point, self.wp) #print(line) self.line_buffer = point # Track Relationship handle_nr = self.get_handle_nr(str(point)) relation['handle_nr'] = handle_nr relation['solv_handle'] = point relation['ui_point'] = clicked_pos self.solventies.append(relation) self.points.append(clicked_pos) print(self.points) if event.button() == Qt.LeftButton and self.mouse_mode == "pt_pt": #point_solve_now = self.solventies[self.hovered_point]['solv_handle'] for new_id, entry in enumerate(self.solventies): if self.hovered_point == entry['ui_point']: point_solve_now = entry['solv_handle'] print(point_solve_now) target_id = new_id if self.pt_pt_buffer: for old_id, entry in enumerate(self.solventies): if self.pt_pt_buffer == entry['ui_point']: point_solve_old = entry['solv_handle'] move_id = old_id #point_solve_old = self.solventies[self.pt_pt_buffer]['solv_handle'] #self.solv.dragged(point_solve_now, self.wp) self.solv.coincident(point_solve_now, point_solve_old, self.wp) if self.solv.solve() == ResultFlag.OKAY: # Get the result (unpack from the entity or parameters) # x and y are actually float type dof = self.solv.dof() print(dof) print(self.solventies[move_id]['ui_point']) print(self.solventies[target_id]['ui_point']) x, y = self.solv.params(self.solventies[move_id]['solv_handle'].params) self.solventies[move_id]['ui_point'] = QPoint(x, y) print(f"{x}, {y}") print(self.solventies) #after adding the result elif self.solv.solve() == ResultFlag.DIDNT_CONVERGE: print("Solve_failed - Converge" ) elif self.solv.solve() == ResultFlag.TOO_MANY_UNKNOWNS: print("Solve_failed - Unknowns" ) elif self.solv.solve() == ResultFlag.INCONSISTENT: print("Solve_failed - Incons" ) self.points = [] for points_ui in self.solventies: self.points.append(points_ui['ui_point']) print(self.points) self.pt_pt_buffer = self.hovered_point self.update() def mouseMoveEvent(self, event): closest_point = None min_distance = float('inf') threshold = 10 # Distance threshold for highlighting for point in self.points: distance = (event.pos() - point).manhattanLength() if distance < threshold and distance < min_distance: closest_point = point min_distance = distance if closest_point != self.hovered_point: self.hovered_point = closest_point 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 set_points(self, points: list): self.points = points #self.update() 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) < 1 def paintEvent(self, event): painter = QPainter(self) # Set the background color painter.fillRect(self.rect(), QColor('black')) pen = QPen(Qt.gray) pen.setWidth(2) painter.setPen(pen) # Draw points for point in self.points: painter.drawEllipse(point, 3, 3) if len (self.points) > 0: for i in range(len(self.points)-1): painter.drawLine(self.points[i], self.points[i + 1]) #Highlight point hovered if self.hovered_point: highlight_pen = QPen(QColor(255, 0, 0)) highlight_pen.setWidth(2) painter.setPen(highlight_pen) painter.drawEllipse(self.hovered_point, 5, 5) """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)""" painter.end() def clear_sketch(self): self.points = [] self.update() # Example usage if __name__ == "__main__": import sys app = QApplication(sys.argv) window = SketchWidget() window.setWindowTitle("Snap Line Widget") window.resize(800, 600) window.show() sys.exit(app.exec())