- Started Solvespace implementation solver

This commit is contained in:
bklronin
2024-06-19 17:14:58 +02:00
parent a64971e0fe
commit edbd5ed0d3
5 changed files with 374 additions and 177 deletions

View File

@@ -1,3 +1,6 @@
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
@@ -6,61 +9,154 @@ 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.line_mode = False
self.setMouseTracking(True)
self.mouse_mode = False
self.wp = None
self.solv = SolverSystem()
def solve_constraint(self):
solv = SolverSystem()
wp = solv.create_2d_base() # Workplane (Entity)
p0 = solv.add_point_2d(0, 0, wp) # Entity
solv.dragged(p0, wp) # Make a constraint with the entity
...
line0 = solv.add_line_2d(p0, p1, wp) # Create entity with others
...
line1 = solv.add_line_2d(p0, p3, wp)
solv.angle(line0, line1, 45, wp) # Constrain two entities
line1 = solv.entity(-1) # Entity handle can be re-generated and negatively indexed
...
if solv.solve() == ResultFlag.OKAY:
# Get the result (unpack from the entity or parameters)
# x and y are actually float type
dof = solv.dof()
x, y = solv.params(p2.params)
...
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:
# Error!
# Get the list of all constraints
failures = solv.failures()
...
print("Handle number not found.")
return 0
def set_points(self, points: list):
self.points = points
#self.update()
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):
if event.button() == Qt.LeftButton and self.line_mode:
self.points.append(event.pos())
self.update()
relation = {
'handle_nr': None,
'solv_handle': None
}
elif 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
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
self.solventies[clicked_pos] = relation
self.points = list(self.solventies)
#print(self.points)
if event.button() == Qt.LeftButton and self.mouse_mode == "pt_pt":
point_solve_now = self.solventies[self.hovered_point]['solv_handle']
if self.pt_pt_buffer:
point_solve_old = self.solventies[self.pt_pt_buffer]['solv_handle']
print(point_solve_old)
print(point_solve_now)
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)
if self.pt_pt_buffer:
# Get the entry form the old point and copy it into new point with the new key and postion (key = postiion
move_point = self.solventies[self.pt_pt_buffer]
print(move_point)
del self.solventies[self.pt_pt_buffer]
self.solventies[self.hovered_point] = move_point
#print(f"Coordinates: {x1}, {y1}; {x2}, {y2}")
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 = []
self.points = list(self.solventies)
print(self.points)
self.pt_pt_buffer = self.hovered_point
def mouseMoveEvent(self, event):
if event.buttons() & Qt.RightButton:
if self.selected_line is not None:
self.points[self.selected_line] = event.pos()
else:
self.points[-1] = event.pos()
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):
@@ -69,6 +165,10 @@ class SketchWidget(QWidget):
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)
@@ -93,11 +193,18 @@ class SketchWidget(QWidget):
for point in self.points:
painter.drawEllipse(point, 3, 3)
if self.selected_line is not None:
#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.drawLine(p1, p2)"""
painter.end()
def clear_sketch(self):

View File

@@ -0,0 +1,25 @@
from python_solvespace import SolverSystem, ResultFlag
def solve_constraint(self):
solv = SolverSystem()
wp = solv.create_2d_base() # Workplane (Entity)
p0 = solv.add_point_2d(0, 0, wp) # Entity
solv.dragged(p0, wp) # Make a constraint with the entity
...
line0 = solv.add_line_2d(p0, p1, wp) # Create entity with others
...
line1 = solv.add_line_2d(p0, p3, wp)
solv.angle(line0, line1, 45, wp) # Constrain two entities
line1 = solv.entity(-1) # Entity handle can be re-generated and negatively indexed
...
if solv.solve() == ResultFlag.OKAY:
# Get the result (unpack from the entity or parameters)
# x and y are actually float type
dof = solv.dof()
x, y = solv.params(p2.params)
...
else:
# Error!
# Get the list of all constraints
failures = solv.failures()
...