- Sketch projection partly works again :)

This commit is contained in:
bklronin 2024-12-30 13:54:15 +01:00
parent a5202e1630
commit 842799b35f
3 changed files with 199 additions and 239 deletions

View File

@ -19,3 +19,17 @@
- Transform to 2D xy - Transform to 2D xy
- Transform to linear space for 2D widget to draw. - Transform to linear space for 2D widget to draw.
- Result into 2D cartesian for body interaction extrude etc - Result into 2D cartesian for body interaction extrude etc
### Elements
So far these are the elements:
- Project: Main File
- Timeline : Used to track the steps
- Assembly: Uses Components and Connectors to from Assemblies
- Component: Container for multiple smaller elements "part"
- Connector: Preserves connections between parts even if the part in between is deleted
- Code: A special type that directly builds bodys from sdfCAD code.
- Body: The 3D meshed result from sdfCAD
- Sketch: The base to draw new entities.
- Interactor: A special component mesh that is used to manipulate the bodys in 3d view.

View File

@ -1,7 +1,7 @@
import math import math
import re import re
from copy import copy from copy import copy
from typing import Optional import uuid
import numpy as np import numpy as np
from PySide6.QtWidgets import QApplication, QWidget, QMessageBox, QInputDialog from PySide6.QtWidgets import QApplication, QWidget, QMessageBox, QInputDialog
@ -32,6 +32,11 @@ class SketchWidget(QWidget):
self.sketch = Sketch2d() self.sketch = Sketch2d()
def create_sketch(self, sketch_in ):
self.sketch = Sketch2d()
self.sketch.id = sketch_in.id
self.sketch.origin = sketch_in.origin
def get_sketch(self): def get_sketch(self):
return self.sketch return self.sketch
@ -45,28 +50,38 @@ class SketchWidget(QWidget):
#self.update() #self.update()
def create_workplane(self): def create_workplane(self):
self.sketch.working_plane = self.solv.create_2d_base() self.sketch.wp = self.sketch.create_2d_base()
def create_workplane_projected(self): def create_workplane_projected(self):
self.sketch.working_plane = self.solv.create_2d_base() self.sketch.wp = self.sketch.create_2d_base()
def convert_proj_points(self): def convert_proj_points(self, proj_points: list):
### This needs to create a proper Point2D class with bool construction enbaled
out_points = [] out_points = []
for point in self.sketch.proj_points: for point in proj_points:
x, y = point pnt = Point2D(point[0], point[1])
coord = QPoint(x, y) # Construction
out_points.append(coord) pnt.is_helper = True
print(point)
self.sketch.add_point(pnt)
self.sketch.proj_points = out_points def convert_proj_lines(self, proj_lines: list):
### same as for point
def convert_proj_lines(self):
out_lines = [] out_lines = []
for line in self.sketch.proj_lines: for line in proj_lines:
start = QPoint(line[0][0], line[0][1]) start = Point2D(line[0][0], line[0][1])
end = QPoint(line[1][0], line[1][1]) end = Point2D(line[1][0], line[1][1])
coord = QLine(start, end) start.is_helper = True
out_lines.append(coord) end.is_helper = True
self.sketch.proj_lines = out_lines
self.sketch.add_point(start)
self.sketch.add_point(end)
lne = Line2D(start, end)
#Construction
lne.is_helper = True
self.sketch.add_line(lne)
def find_duplicate_points_2d(self, edges): def find_duplicate_points_2d(self, edges):
points = [] points = []
@ -114,9 +129,9 @@ class SketchWidget(QWidget):
origin_handle = self.get_handle_from_ui_point(origin) origin_handle = self.get_handle_from_ui_point(origin)
qw, qx, qy, qz = self.normal_to_quaternion(normal) qw, qx, qy, qz = self.normal_to_quaternion(normal)
slv_normal = self.solv.add_normal_3d(qw, qx, qy, qz) slv_normal = self.sketch.add_normal_3d(qw, qx, qy, qz)
self.sketch.working_plane = self.solv.add_work_plane(origin_handle, slv_normal) self.sketch.wp = self.sketch.add_work_plane(origin_handle, slv_normal)
print(self.sketch.working_plane) print(self.sketch.wp)
def get_handle_nr(self, input_str: str) -> int: def get_handle_nr(self, input_str: str) -> int:
# Define the regex pattern to extract the handle number # Define the regex pattern to extract the handle number
@ -160,16 +175,16 @@ class SketchWidget(QWidget):
def get_line_handle_from_ui_point(self, ui_point: QPoint): def get_line_handle_from_ui_point(self, ui_point: QPoint):
"""Input Qpoint that is on a line and you shall receive the handle of the line!""" """Input Qpoint that is on a line and you shall receive the handle of the line!"""
for target_line_con in self.sketch.lines: for target_line_con in self.sketch.lines:
if self.is_point_on_line(ui_point, target_line_con['ui_points'][0], target_line_con['ui_points'][1]): if self.is_point_on_line(ui_point, target_line_con.crd1.ui_point, target_line_con.crd2.ui_point):
slv_handle = target_line_con['solv_handle'] slv_handle = target_line_con.handle
return slv_handle return slv_handle
def get_point_line_handles_from_ui_point(self, ui_point: QPoint) -> tuple: def get_point_line_handles_from_ui_point(self, ui_point: QPoint) -> tuple:
"""Input Qpoint that is on a line and you shall receive the handles of the points of the line!""" """Input Qpoint that is on a line and you shall receive the handles of the points of the line!"""
for target_line_con in self.sketch.slv_lines: for target_line_con in self.sketch.slv_lines:
if self.is_point_on_line(ui_point, target_line_con['ui_points'][0], target_line_con['ui_points'][1]): if self.is_point_on_line(ui_point, target_line_con.crd1.ui_point, target_line_con.crd2.ui_point):
lines_to_cons = target_line_con['solv_entity_points'] lines_to_cons = target_line_con.crd1.handle, target_line_con.crd2.handle
return lines_to_cons return lines_to_cons
@ -210,18 +225,22 @@ class SketchWidget(QWidget):
def viewport_to_local_coord(self, qt_pos : QPoint) -> QPoint: def viewport_to_local_coord(self, qt_pos : QPoint) -> QPoint:
return QPoint(self.to_quadrant_coords(qt_pos)) return QPoint(self.to_quadrant_coords(qt_pos))
def check_all_points(self,) -> list: def check_all_points(self) -> list:
"""
Go through solversystem and check points2d for changes in position after solving
:return: List with points that now have a different position
"""
old_points_ui = [] old_points_ui = []
new_points_ui = [] new_points_ui = []
for old_point_ui in self.sketch.points: for old_point_ui in self.sketch.points:
old_points_ui.append(old_point_ui.ui_point) old_points_ui.append(old_point_ui.ui_point)
for i in range(self.solv.entity_len()): for i in range(self.sketch.entity_len()):
# Iterate though full length because mixed list from SS # Iterate though full length because mixed list from SS
entity = self.solv.entity(i) entity = self.sketch.entity(i)
if entity.is_point_2d() and self.solv.params(entity.params): if entity.is_point_2d() and self.sketch.params(entity.params):
x_tbu, y_tbu = self.solv.params(entity.params) x_tbu, y_tbu = self.sketch.params(entity.params)
point_solved = QPoint(x_tbu, y_tbu) point_solved = QPoint(x_tbu, y_tbu)
new_points_ui.append(point_solved) new_points_ui.append(point_solved)
@ -248,7 +267,7 @@ class SketchWidget(QWidget):
index, old_point, new_point = tbu_points_idx index, old_point, new_point = tbu_points_idx
# Update the point in slv_points_main # Update the point in slv_points_main
self.sketch.points[index].point = new_point self.sketch.points[index].ui_point = new_point
# Print updated state # Print updated state
# print("Updated slv_points_main:", self.slv_points_main) # print("Updated slv_points_main:", self.slv_points_main)
@ -256,10 +275,10 @@ class SketchWidget(QWidget):
for tbu_points_idx in changed_points: for tbu_points_idx in changed_points:
index, old_point, new_point = tbu_points_idx index, old_point, new_point = tbu_points_idx
for line_needs_update in self.sketch.lines: for line_needs_update in self.sketch.lines:
if old_point == line_needs_update.points[0]: if old_point == line_needs_update.crd1.ui_point:
line_needs_update['ui_points'][0] = new_point line_needs_update.crd1.ui_point = new_point
elif old_point == line_needs_update.points[1]: elif old_point == line_needs_update.crd2.ui_point:
line_needs_update['ui_points'][1] = new_point line_needs_update.crd2.ui_point = new_point
def mouseReleaseEvent(self, event): def mouseReleaseEvent(self, event):
local_event_pos = self.viewport_to_local_coord(event.pos()) local_event_pos = self.viewport_to_local_coord(event.pos())
@ -345,19 +364,20 @@ class SketchWidget(QWidget):
if self.main_buffer[0] and self.main_buffer[1]: if self.main_buffer[0] and self.main_buffer[1]:
print("buf", self.main_buffer) print("buf", self.main_buffer)
self.solv.coincident(self.main_buffer[0], self.main_buffer[1], self.sketch.working_plane) self.sketch.coincident(self.main_buffer[0], self.main_buffer[1], self.sketch.wp)
if self.solv.solve() == ResultFlag.OKAY: if self.sketch.solve() == ResultFlag.OKAY:
print("Fuck yeah") print("Fuck yeah")
elif self.solv.solve() == ResultFlag.DIDNT_CONVERGE: elif self.sketch.solve() == ResultFlag.DIDNT_CONVERGE:
print("Solve_failed - Converge") print("Solve_failed - Converge")
elif self.solv.solve() == ResultFlag.TOO_MANY_UNKNOWNS: elif self.sketch.solve() == ResultFlag.TOO_MANY_UNKNOWNS:
print("Solve_failed - Unknowns") print("Solve_failed - Unknowns")
elif self.solv.solve() == ResultFlag.INCONSISTENT: elif self.sketch.solve() == ResultFlag.INCONSISTENT:
print("Solve_failed - Incons") print("Solve_failed - Incons")
self.constrain_done.emit() self.constrain_done.emit()
self.main_buffer = [None, None] self.main_buffer = [None, None]
@ -373,19 +393,19 @@ class SketchWidget(QWidget):
# Contrain point to line # Contrain point to line
if self.main_buffer[1]: if self.main_buffer[1]:
self.solv.coincident(self.main_buffer[0], self.main_buffer[1], self.sketch.working_plane) self.sketch.coincident(self.main_buffer[0], self.main_buffer[1], self.sketch.wp)
if self.solv.solve() == ResultFlag.OKAY: if self.sketch.solve() == ResultFlag.OKAY:
print("Fuck yeah") print("Fuck yeah")
self.constrain_done.emit() self.constrain_done.emit()
elif self.solv.solve() == ResultFlag.DIDNT_CONVERGE: elif self.sketch.solve() == ResultFlag.DIDNT_CONVERGE:
print("Solve_failed - Converge") print("Solve_failed - Converge")
elif self.solv.solve() == ResultFlag.TOO_MANY_UNKNOWNS: elif self.sketch.solve() == ResultFlag.TOO_MANY_UNKNOWNS:
print("Solve_failed - Unknowns") print("Solve_failed - Unknowns")
elif self.solv.solve() == ResultFlag.INCONSISTENT: elif self.sketch.solve() == ResultFlag.INCONSISTENT:
print("Solve_failed - Incons") print("Solve_failed - Incons")
self.constrain_done.emit() self.constrain_done.emit()
@ -404,18 +424,18 @@ class SketchWidget(QWidget):
# Contrain point to line # Contrain point to line
if self.main_buffer[1]: if self.main_buffer[1]:
self.solv.midpoint(self.main_buffer[0], self.main_buffer[1], self.sketch.working_plane) self.sketch.midpoint(self.main_buffer[0], self.main_buffer[1], self.sketch.wp)
if self.solv.solve() == ResultFlag.OKAY: if self.sketch.solve() == ResultFlag.OKAY:
print("Fuck yeah") print("Fuck yeah")
elif self.solv.solve() == ResultFlag.DIDNT_CONVERGE: elif self.sketch.solve() == ResultFlag.DIDNT_CONVERGE:
print("Solve_failed - Converge") print("Solve_failed - Converge")
elif self.solv.solve() == ResultFlag.TOO_MANY_UNKNOWNS: elif self.sketch.solve() == ResultFlag.TOO_MANY_UNKNOWNS:
print("Solve_failed - Unknowns") print("Solve_failed - Unknowns")
elif self.solv.solve() == ResultFlag.INCONSISTENT: elif self.sketch.solve() == ResultFlag.INCONSISTENT:
print("Solve_failed - Incons") print("Solve_failed - Incons")
self.constrain_done.emit() self.constrain_done.emit()
@ -426,36 +446,36 @@ class SketchWidget(QWidget):
line_selected = self.get_line_handle_from_ui_point(local_event_pos) line_selected = self.get_line_handle_from_ui_point(local_event_pos)
if line_selected: if line_selected:
self.solv.horizontal(line_selected, self.sketch.working_plane) self.sketch.horizontal(line_selected, self.sketch.wp)
if self.solv.solve() == ResultFlag.OKAY: if self.sketch.solve() == ResultFlag.OKAY:
print("Fuck yeah") print("Fuck yeah")
elif self.solv.solve() == ResultFlag.DIDNT_CONVERGE: elif self.sketch.solve() == ResultFlag.DIDNT_CONVERGE:
print("Solve_failed - Converge") print("Solve_failed - Converge")
elif self.solv.solve() == ResultFlag.TOO_MANY_UNKNOWNS: elif self.sketch.solve() == ResultFlag.TOO_MANY_UNKNOWNS:
print("Solve_failed - Unknowns") print("Solve_failed - Unknowns")
elif self.solv.solve() == ResultFlag.INCONSISTENT: elif self.sketch.solve() == ResultFlag.INCONSISTENT:
print("Solve_failed - Incons") print("Solve_failed - Incons")
if event.button() == Qt.LeftButton and self.mouse_mode == "vert": if event.button() == Qt.LeftButton and self.mouse_mode == "vert":
line_selected = self.get_line_handle_from_ui_point(local_event_pos) line_selected = self.get_line_handle_from_ui_point(local_event_pos)
if line_selected: if line_selected:
self.solv.vertical(line_selected, self.sketch.working_plane) self.sketch.vertical(line_selected, self.sketch.wp)
if self.solv.solve() == ResultFlag.OKAY: if self.sketch.solve() == ResultFlag.OKAY:
print("Fuck yeah") print("Fuck yeah")
elif self.solv.solve() == ResultFlag.DIDNT_CONVERGE: elif self.sketch.solve() == ResultFlag.DIDNT_CONVERGE:
print("Solve_failed - Converge") print("Solve_failed - Converge")
elif self.solv.solve() == ResultFlag.TOO_MANY_UNKNOWNS: elif self.sketch.solve() == ResultFlag.TOO_MANY_UNKNOWNS:
print("Solve_failed - Unknowns") print("Solve_failed - Unknowns")
elif self.solv.solve() == ResultFlag.INCONSISTENT: elif self.sketch.solve() == ResultFlag.INCONSISTENT:
print("Solve_failed - Incons") print("Solve_failed - Incons")
if event.button() == Qt.LeftButton and self.mouse_mode == "distance": if event.button() == Qt.LeftButton and self.mouse_mode == "distance":
@ -485,18 +505,18 @@ class SketchWidget(QWidget):
if e1 and e2: if e1 and e2:
# Ask fo the dimension and solve if both elements are present # Ask fo the dimension and solve if both elements are present
length, ok = QInputDialog.getDouble(self, 'Distance', 'Enter a mm value:', value=100, decimals=2) length, ok = QInputDialog.getDouble(self, 'Distance', 'Enter a mm value:', value=100, decimals=2)
self.solv.distance(e1, e2, length, self.sketch.working_plane) self.sketch.distance(e1, e2, length, self.sketch.wp)
if self.solv.solve() == ResultFlag.OKAY: if self.sketch.solve() == ResultFlag.OKAY:
print("Fuck yeah") print("Fuck yeah")
elif self.solv.solve() == ResultFlag.DIDNT_CONVERGE: elif self.sketch.solve() == ResultFlag.DIDNT_CONVERGE:
print("Solve_failed - Converge") print("Solve_failed - Converge")
elif self.solv.solve() == ResultFlag.TOO_MANY_UNKNOWNS: elif self.sketch.solve() == ResultFlag.TOO_MANY_UNKNOWNS:
print("Solve_failed - Unknowns") print("Solve_failed - Unknowns")
elif self.solv.solve() == ResultFlag.INCONSISTENT: elif self.sketch.solve() == ResultFlag.INCONSISTENT:
print("Solve_failed - Incons") print("Solve_failed - Incons")
self.constrain_done.emit() self.constrain_done.emit()
@ -661,33 +681,53 @@ class SketchWidget(QWidget):
# Set the transform to the painter # Set the transform to the painter
painter.setTransform(transform) painter.setTransform(transform)
pen = QPen(Qt.gray) pen_normal = QPen(Qt.gray)
pen.setWidthF(2 / self.zoom) pen_normal.setWidthF(2 / self.zoom)
painter.setPen(pen)
pen_construct = QPen(Qt.blue)
pen_construct.setStyle(Qt.PenStyle.DashLine)
pen_construct.setWidthF(2 / self.zoom)
pen_solver = QPen(Qt.green)
pen_solver.setWidthF(2 / self.zoom)
# Draw points # Draw points
if self.sketch: if self.sketch:
painter.setPen(pen_normal)
for point in self.sketch.points: for point in self.sketch.points:
painter.drawEllipse(point.ui_point, 3 / self.zoom, 3 / self.zoom) if point.is_helper:
painter.setPen(pen_construct)
painter.drawEllipse(point.ui_point, 10 / self.zoom, 10 / self.zoom)
else:
#Normal point
painter.setPen(pen_normal)
painter.drawEllipse(point.ui_point, 3 / self.zoom, 3 / self.zoom)
for line in self.sketch.lines: for line in self.sketch.lines:
p1 = line.crd1.ui_point if line.is_helper:
p2 = line.crd2.ui_point painter.setPen(pen_construct)
painter.drawLine(p1, p2) p1 = line.crd1.ui_point
p2 = line.crd2.ui_point
painter.drawLine(p1, p2)
else:
painter.setPen(pen_normal)
p1 = line.crd1.ui_point
p2 = line.crd2.ui_point
painter.drawLine(p1, p2)
dis = self.distance(p1, p2) dis = self.distance(p1, p2)
mid = self.calculate_midpoint(p1, p2) mid = self.calculate_midpoint(p1, p2)
painter.drawText(mid, str(round(dis, 2))) painter.drawText(mid, str(round(dis, 2)))
pen = QPen(Qt.green)
pen.setWidthF(2 / self.zoom)
painter.setPen(pen)
if self.solv.entity_len(): # Draw all solver points
for i in range(self.solv.entity_len()): if self.sketch.entity_len():
entity = self.solv.entity(i) painter.setPen(pen_solver)
if entity.is_point_2d() and self.solv.params(entity.params): for i in range(self.sketch.entity_len()):
x, y = self.solv.params(entity.params) entity = self.sketch.entity(i)
if entity.is_point_2d() and self.sketch.params(entity.params):
x, y = self.sketch.params(entity.params)
point = QPointF(x, y) point = QPointF(x, y)
painter.drawEllipse(point, 6 / self.zoom, 6 / self.zoom) painter.drawEllipse(point, 6 / self.zoom, 6 / self.zoom)
@ -723,149 +763,30 @@ class SketchWidget(QWidget):
return self.width() / self.height() * (1.0 / abs(self.zoom)) return self.width() / self.height() * (1.0 / abs(self.zoom))
class Point2D_ALT: ### GEOMETRY CLASSES
"""Improved oop aaproach?"""
def __init__(self):
self.ui_point = None
self.solve_handle_nr = None
self.solve_handle = None
self.part_of_entity = None
def to_quadrant_coords(self, point):
"""Translate linear coordinates to quadrant coordinates."""
center_x = self.width() // 2
center_y = self.height() // 2
quadrant_x = point.x() - center_x
quadrant_y = center_y - point.y() # Note the change here
return QPoint(quadrant_x, quadrant_y) / self.zoom
def from_quadrant_coords(self, point: QPoint):
"""Translate quadrant coordinates to linear coordinates."""
center_x = self.width() // 2
center_y = self.height() // 2
widget_x = center_x + point.x() * self.zoom
widget_y = center_y - point.y() * self.zoom # Note the subtraction here
return QPoint(int(widget_x), int(widget_y))
def from_quadrant_coords_no_center(self, point):
"""Invert Y Coordinate for mesh"""
center_x = 0
center_y = 0
widget_x = point.x()
widget_y = -point.y()
return QPoint(int(widget_x), int(widget_y))
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 get_handle_from_ui_point(self, ui_point: QPoint):
"""Input QPoint and you shall reveive a slvs entity handle!"""
for point in self.sketch.slv_points:
if ui_point == point['ui_point']:
slv_handle = point['solv_handle']
return slv_handle
def get_line_handle_from_ui_point(self, ui_point: QPoint):
"""Input Qpoint that is on a line and you shall receive the handle of the line!"""
for target_line_con in self.sketch.slv_lines:
if self.is_point_on_line(ui_point, target_line_con['ui_points'][0], target_line_con['ui_points'][1]):
slv_handle = target_line_con['solv_handle']
return slv_handle
def get_point_line_handles_from_ui_point(self, ui_point: QPoint) -> tuple:
"""Input Qpoint that is on a line and you shall receive the handles of the points of the line!"""
for target_line_con in self.sketch.slv_lines:
if self.is_point_on_line(ui_point, target_line_con['ui_points'][0], target_line_con['ui_points'][1]):
lines_to_cons = target_line_con['solv_entity_points']
return lines_to_cons
def distance(self, p1, p2):
return math.sqrt((p1.x() - p2.x())**2 + (p1.y() - p2.y())**2)
def calculate_midpoint(self, point1, point2):
mx = (point1.x() + point2.x()) // 2
my = (point1.y() + point2.y()) // 2
return QPoint(mx, my)
def is_point_on_line(self, p, p1, p2, tolerance=5):
# Calculate the lengths of the sides of the triangle
a = self.distance(p, p1)
b = self.distance(p, p2)
c = self.distance(p1, p2)
# Calculate the semi-perimeter
s = (a + b + c) / 2
# Calculate the area using Heron's formula
area = math.sqrt(s * (s - a) * (s - b) * (s - c))
# Calculate the height (perpendicular distance from the point to the line)
if c > 0:
height = (2 * area) / c
# Check if the height is within the tolerance distance to the line
if height > tolerance:
return False
# Check if the projection of the point onto the line is within the line segment
dot_product = ((p.x() - p1.x()) * (p2.x() - p1.x()) + (p.y() - p1.y()) * (p2.y() - p1.y())) / (c ** 2)
return 0 <= dot_product <= 1
else:
return None
def viewport_to_local_coord(self, qt_pos : QPoint) -> QPoint:
return QPoint(self.to_quadrant_coords(qt_pos))
class Point2D: class Point2D:
def __init__(self, x, y): def __init__(self, x, y):
self.id = None
self.ui_x: int = x self.ui_x: int = x
self.ui_y: int = y self.ui_y: int = y
self.ui_point = QPoint(self.ui_x, self.ui_y) self.ui_point = QPoint(self.ui_x, self.ui_y)
self.handle = None self.handle = None
self.handle_nr: int = None self.handle_nr: int = None
# Construction Geometry
self.is_helper: bool = False
class Line2D: class Line2D:
def __init__(self, point_s: Point2D, point_e: Point2D): def __init__(self, point_s: Point2D, point_e: Point2D):
self.id = None
self.crd1: Point2D = point_s self.crd1: Point2D = point_s
self.crd2: Point2D = point_e self.crd2: Point2D = point_e
self.handle = None self.handle = None
self.handle_nr = None self.handle_nr: int = None
# Construction Geometry
self.is_helper: bool = False
class Sketch2d(SolverSystem): class Sketch2d(SolverSystem):
""" """
@ -873,13 +794,16 @@ class Sketch2d(SolverSystem):
""" """
def __init__(self): def __init__(self):
self.id = uuid.uuid1()
self.wp = self.create_2d_base() self.wp = self.create_2d_base()
self.points = [] self.points = []
self.lines = [] self.lines = []
self.origin = [0,0,0]
def add_point(self, point: Point2D): def add_point(self, point: Point2D):
""" """
Adds a point into the solversystem and reurns the handle. Adds a point into the solversystem and returns the handle.
Appends the added point to the points list. Appends the added point to the points list.
:param point: 2D point in Point2D class format :param point: 2D point in Point2D class format
:return: :return:
@ -887,6 +811,7 @@ class Sketch2d(SolverSystem):
point.handle = self.add_point_2d(point.ui_x, point.ui_y, self.wp) point.handle = self.add_point_2d(point.ui_x, point.ui_y, self.wp)
point.handle_nr = self.get_handle_nr(str(point.handle)) point.handle_nr = self.get_handle_nr(str(point.handle))
point.id = uuid.uuid1()
self.points.append(point) self.points.append(point)
@ -899,6 +824,8 @@ class Sketch2d(SolverSystem):
:return: :return:
""" """
line.id = uuid.uuid1()
line.handle = self.add_line_2d(line.crd1.handle, line.crd2.handle, self.wp) line.handle = self.add_line_2d(line.crd1.handle, line.crd2.handle, self.wp)
line.handle_nr = self.get_handle_nr(str(line.handle)) line.handle_nr = self.get_handle_nr(str(line.handle))

69
main.py
View File

@ -49,7 +49,6 @@ class ExtrudeDialog(QDialog):
self.rounded_checkbox = QCheckBox('Round Edges') self.rounded_checkbox = QCheckBox('Round Edges')
self.seperator = create_hline() self.seperator = create_hline()
# OK and Cancel buttons # OK and Cancel buttons
button_layout = QHBoxLayout() button_layout = QHBoxLayout()
ok_button = QPushButton('OK') ok_button = QPushButton('OK')
@ -263,14 +262,12 @@ class MainWindow(QMainWindow):
sketch = Sketch() sketch = Sketch()
sketch.id = name sketch.id = name
sketch.origin = [0,0,0] sketch.origin = [0,0,0]
sketch.slv_points = []
sketch.slv_lines = []
sketch.proj_points = []
sketch.proj_lines = []
self.sketchWidget.reset_buffers() self.sketchWidget.reset_buffers()
self.sketchWidget.set_sketch(sketch) self.sketchWidget.create_sketch(sketch)
def add_new_sketch_wp(self): def add_new_sketch_wp(self):
## Sketch projected from 3d view into 2d
name = f"sketches-{str(names.get_first_name())}" name = f"sketches-{str(names.get_first_name())}"
sketch = Sketch() sketch = Sketch()
sketch.id = name sketch.id = name
@ -280,11 +277,13 @@ class MainWindow(QMainWindow):
sketch.slv_lines = [] sketch.slv_lines = []
sketch.proj_points = self.custom_3D_Widget.project_tosketch_points sketch.proj_points = self.custom_3D_Widget.project_tosketch_points
sketch.proj_lines = self.custom_3D_Widget.project_tosketch_lines sketch.proj_lines = self.custom_3D_Widget.project_tosketch_lines
self.sketchWidget.reset_buffers() self.sketchWidget.reset_buffers()
self.sketchWidget.set_sketch(sketch) self.sketchWidget.create_sketch(sketch)
self.sketchWidget.create_workplane_projected() self.sketchWidget.create_workplane_projected()
self.sketchWidget.convert_proj_points() if not sketch.proj_lines:
self.sketchWidget.convert_proj_lines() self.sketchWidget.convert_proj_points(sketch.proj_points)
self.sketchWidget.convert_proj_lines(sketch.proj_lines)
self.sketchWidget.update() self.sketchWidget.update()
# CLear all selections after it has been projected # CLear all selections after it has been projected
@ -295,15 +294,24 @@ class MainWindow(QMainWindow):
def add_sketch(self): def add_sketch(self):
""" """
:return: :return:
""" """
sketch = self.sketchWidget.get_sketch() sketch = Sketch()
sketch.convert_points_for_sdf() sketch_from_widget = self.sketchWidget.get_sketch()
points = sketch_from_widget.points
sketch.convert_points_for_sdf(points)
sketch.id = sketch_from_widget.id
sketch.filter_lines_for_interactor(sketch_from_widget.lines)
# Register sketch to timeline
self.project.timeline[-1].sketches[sketch.id] = sketch self.project.timeline[-1].sketches[sketch.id] = sketch
# Add Item to slection menu
self.ui.sketch_list.addItem(sketch.id) self.ui.sketch_list.addItem(sketch.id)
# Deactivate drawing
self.ui.pb_linetool.setChecked(False) self.ui.pb_linetool.setChecked(False)
self.sketchWidget.line_mode = False self.sketchWidget.line_mode = False
@ -387,7 +395,9 @@ class MainWindow(QMainWindow):
name = selected.text() name = selected.text()
# TODO: add selected element from timeline # TODO: add selected element from timeline
sel_compo = self.project.timeline[-1] sel_compo = self.project.timeline[-1]
print(sel_compo)
sketch = sel_compo.sketches[name] sketch = sel_compo.sketches[name]
print(sketch)
points = sketch.sdf_points points = sketch.sdf_points
if points[-1] == points[0]: if points[-1] == points[0]:
@ -428,7 +438,7 @@ class MainWindow(QMainWindow):
### Interactor ### Interactor
interactor = Interactor() interactor = Interactor()
interactor.add_lines_for_interactor(sketch.slv_lines) interactor.add_lines_for_interactor(sketch.interactor_lines)
if not invert: if not invert:
edges = interactor_mesh.generate_mesh(interactor.lines, 0, length) edges = interactor_mesh.generate_mesh(interactor.lines, 0, length)
@ -564,6 +574,8 @@ class Sketch:
sdf_points: list = None sdf_points: list = None
interactor_lines: list = None
# Points coming back from the 3D-Widget as projection to draw on # Points coming back from the 3D-Widget as projection to draw on
proj_points: list = None proj_points: list = None
proj_lines: list = None proj_lines: list = None
@ -623,13 +635,24 @@ class Sketch:
print("p2", p2) print("p2", p2)
return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2) return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
def convert_points_for_sdf(self): def convert_points_for_sdf(self, points):
points_for_sdf = [] points_for_sdf = []
for point_to_poly in self.slv_points: for point in points:
points_for_sdf.append(self.translate_points_tup(point_to_poly['ui_point'])) if point.is_helper is False:
print("point", point)
points_for_sdf.append(self.translate_points_tup(point.ui_point))
self.sdf_points = points_for_sdf self.sdf_points = points_for_sdf
def filter_lines_for_interactor(self, lines):
### Filter lines that are not meant to be drawn for the interactor like contruction lines
filtered_lines = []
for line in lines:
if not line.is_helper:
filtered_lines.append(line)
self.interactor_lines = filtered_lines
def extrude(self, height: float, symet: bool = True, invert: bool = False, offset_length: float = None): def extrude(self, height: float, symet: bool = True, invert: bool = False, offset_length: float = None):
""" """
Extrude a 2D shape into 3D, orient it along the normal, and position it relative to the centroid. Extrude a 2D shape into 3D, orient it along the normal, and position it relative to the centroid.
@ -677,7 +700,6 @@ class Sketch:
return f return f
@dataclass @dataclass
class Interactor: class Interactor:
"""Helper mesh consisting of edges for selection""" """Helper mesh consisting of edges for selection"""
@ -708,12 +730,13 @@ class Interactor:
return translation_along_normal return translation_along_normal
def add_lines_for_interactor(self, input_lines: list): def add_lines_for_interactor(self, input_lines: list):
"""Expects slvs_lines main list""" """Takes Line2D objects from the sketch widget and preparesit for interactor mesh.
Translates coordinates."""
points_for_interact = [] points_for_interact = []
for point_to_poly in input_lines: for point_to_poly in input_lines:
start, end = point_to_poly['ui_points'] from_coord_start = window.sketchWidget.from_quadrant_coords_no_center(point_to_poly.crd1.ui_point)
from_coord_start = window.sketchWidget.from_quadrant_coords_no_center(start) from_coord_end = window.sketchWidget.from_quadrant_coords_no_center(point_to_poly.crd2.ui_point)
from_coord_end = window.sketchWidget.from_quadrant_coords_no_center(end)
start_draw = self.translate_points_tup(from_coord_start) start_draw = self.translate_points_tup(from_coord_start)
end_draw = self.translate_points_tup(from_coord_end) end_draw = self.translate_points_tup(from_coord_end)
line = start_draw, end_draw line = start_draw, end_draw
@ -723,7 +746,6 @@ class Interactor:
self.lines = points_for_interact self.lines = points_for_interact
@dataclass @dataclass
class Body: class Body:
"""The actual body as sdf3 object""" """The actual body as sdf3 object"""
@ -743,7 +765,6 @@ class Body:
return f return f
class Output: class Output:
def export_mesh(self, sdf_object): def export_mesh(self, sdf_object):
"""FINAL EXPORT""" """FINAL EXPORT"""
@ -763,13 +784,11 @@ class Output:
except Exception as e: except Exception as e:
print("Error executing code:", e) print("Error executing code:", e)
class Project: class Project:
"""Project -> Timeline -> Component -> Sketch -> Body / Interactor -> Connector -> Assembly -> PB Render""" """Project -> Timeline -> Component -> Sketch -> Body / Interactor -> Connector -> Assembly -> PB Render"""
timeline: Timeline = None timeline: Timeline = None
assembly: Assembly = None assembly: Assembly = None
if __name__ == "__main__": if __name__ == "__main__":
app = QApplication([]) app = QApplication([])
window = MainWindow() window = MainWindow()