227 lines
7.1 KiB
Python
227 lines
7.1 KiB
Python
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())
|