diff --git a/__init__.py b/__init__.py index 20dfd83d..ad4b9450 100644 --- a/__init__.py +++ b/__init__.py @@ -42,7 +42,7 @@ def register(): # Check Module and register all modules try: - check_module("py_slvs") + check_module("solvespace") register_full() global_data.registered = True diff --git a/base/install_op.py b/base/install_op.py index 3d102dd1..602a9663 100644 --- a/base/install_op.py +++ b/base/install_op.py @@ -33,7 +33,7 @@ def execute(self, context): if install_package(self.package): try: - check_module("py_slvs") + check_module("solvespace") from ..registration import register_full register_full() @@ -46,7 +46,7 @@ def execute(self, context): {"WARNING"}, msg, ) - show_package_info("py_slvs") + show_package_info("solvespace") else: self.report({"WARNING"}, "Cannot install package: {}".format(self.package)) return {"CANCELLED"} diff --git a/base/preferences.py b/base/preferences.py index 2b986753..94d8606d 100644 --- a/base/preferences.py +++ b/base/preferences.py @@ -178,7 +178,7 @@ def draw(self, context): box.label(text="Solver Module") if global_data.registered: box.label(text="Registered", icon="CHECKMARK") - module = sys.modules["py_slvs"] + module = sys.modules["solvespace"] box.label(text="Path: " + module.__path__[0]) else: row = box.row() diff --git a/model/angle.py b/model/angle.py index 2c579da0..171f60b4 100644 --- a/model/angle.py +++ b/model/angle.py @@ -71,22 +71,9 @@ def needs_wp(self): def to_displayed_value(self, value): return HALF_TURN - value if self.setting else value - def create_slvs_data(self, solvesys, group=Solver.group_fixed): - kwargs = { - "group": group, - } - + def create_slvs_data(self, solvesys): wp = self.get_workplane() - if wp: - kwargs["wrkpln"] = wp - - return solvesys.addAngle( - math.degrees(self.value), - self.setting, - self.entity1.py_data, - self.entity2.py_data, - **kwargs, - ) + return solvesys.angle(self.entity1.py_data, self.entity2.py_data, math.degrees(self.value), wp, self.setting) def matrix_basis(self): if self.sketch_i == -1: diff --git a/model/arc.py b/model/arc.py index 58229d79..9a7a2260 100644 --- a/model/arc.py +++ b/model/arc.py @@ -102,13 +102,13 @@ def update(self): self._batch = batch_for_shader(self._shader, "LINE_STRIP", kwargs) self.is_dirty = False - def create_slvs_data(self, solvesys, group=Solver.group_fixed): - handle = solvesys.addArcOfCircle( - self.wp.py_data, + def create_slvs_data(self, solvesys): + handle = solvesys.add_arc( + self.nm.py_data, self.ct.py_data, self.start.py_data, self.end.py_data, - group=group, + self.wp.py_data, ) self.py_data = handle diff --git a/model/base_constraint.py b/model/base_constraint.py index 3f08d1a4..cad0ca3f 100644 --- a/model/base_constraint.py +++ b/model/base_constraint.py @@ -48,9 +48,8 @@ def get_workplane(self): elif needs_wp == WpReq.NOT_FREE: return None else: - from py_slvs import slvs - - return slvs.SLVS_FREE_IN_3D + from solvespace import Entity + return Entity.FREE_IN_3D def entities(self): props = [] diff --git a/model/circle.py b/model/circle.py index d2762719..7fff4528 100644 --- a/model/circle.py +++ b/model/circle.py @@ -80,25 +80,18 @@ def update(self): self._batch = batch_for_shader(self._shader, "LINE_STRIP", kwargs) self.is_dirty = False - def create_slvs_data(self, solvesys, group=Solver.group_fixed): - self.param = solvesys.addParamV(self.radius, group) - - nm = None - if self.nm != -1: - nm = self.nm - else: - nm = self.wp.nm - - handle = solvesys.addCircle( - self.ct.py_data, + def create_slvs_data(self, solvesys): + self._radius = solvesys.add_distance(self.radius, self.wp.py_data) + handle = solvesys.add_circle( self.nm.py_data, - solvesys.addDistance(self.param), - group=group, + self.ct.py_data, + self._radius, + self.wp.py_data ) self.py_data = handle def update_from_slvs(self, solvesys): - self.radius = solvesys.getParam(self.param).val + self.radius = solvesys.params(self._radius.params)[0] def point_on_curve(self, angle): return pol2cart(self.radius, angle) + self.ct.co diff --git a/model/coincident.py b/model/coincident.py index be82872a..6fe69662 100644 --- a/model/coincident.py +++ b/model/coincident.py @@ -6,7 +6,7 @@ from ..solver import Solver from ..global_data import WpReq from .base_constraint import GenericConstraint -from .utilities import slvs_entity_pointer, make_coincident +from .utilities import slvs_entity_pointer from .categories import POINT, LINE from .workplane import SlvsWorkplane from .arc import SlvsArc @@ -37,10 +37,8 @@ def needs_wp(self): return WpReq.FREE return WpReq.OPTIONAL - def create_slvs_data(self, solvesys, group=Solver.group_fixed): - return make_coincident( - solvesys, self.entity1.py_data, self.entity2, self.get_workplane(), group - ) + def create_slvs_data(self, solvesys): + return solvesys.coincident(self.entity1.py_data, self.entity2.py_data, self.get_workplane()) def placements(self): return (self.entity1,) diff --git a/model/diameter.py b/model/diameter.py index d622ef6a..917ca65b 100644 --- a/model/diameter.py +++ b/model/diameter.py @@ -76,8 +76,8 @@ def radius(self): def needs_wp(self): return WpReq.OPTIONAL - def create_slvs_data(self, solvesys, group=Solver.group_fixed): - return solvesys.addDiameter(self.diameter, self.entity1.py_data, group=group) + def create_slvs_data(self, solvesys): + return solvesys.diameter(self.entity1.py_data, self.diameter) def init_props(self, **kwargs): diff --git a/model/distance.py b/model/distance.py index cd6a0237..d4cc981b 100644 --- a/model/distance.py +++ b/model/distance.py @@ -107,77 +107,102 @@ def get_value(self): return value * -1 return value - def create_slvs_data(self, solvesys, group=Solver.group_fixed): + # def create_slvs_data(self, solvesys, group=Solver.group_fixed): + # if self.entity1 == self.entity2: + # raise AttributeError("Cannot create constraint between one entity itself") + # # TODO: don't allow Distance if Point -> Line if (Point in Line) + + # e1, e2 = self.entity1, self.entity2 + # if e1.is_line(): + # e1, e2 = e1.p1, e1.p2 + + # func = None + # set_wp = False + # wp = self.get_workplane() + # alignment = self.align + # align = self.use_align() and alignment != "NONE" + # handles = [] + + # value = self.get_value() + + # # circle/arc -> line/point + # if type(e1) in CURVE: + # # TODO: make Horizontal and Vertical alignment work + # if type(e2) in LINE: + # return solvesys.addPointLineDistance( + # value + e1.radius, e1.ct.py_data, e2.py_data, wp, group + # ) + # else: + # assert isinstance(e2, SlvsPoint2D) + # return solvesys.addPointsDistance( + # value + e1.radius, e1.ct.py_data, e2.py_data, wp, group + # ) + + # elif type(e2) in LINE: + # func = solvesys.addPointLineDistance + # set_wp = True + # elif isinstance(e2, SlvsWorkplane): + # func = solvesys.addPointPlaneDistance + # elif type(e2) in POINT: + # if align and all([e.is_2d() for e in (e1, e2)]): + # # Get Point in between + # p1, p2 = e1.co, e2.co + # coords = (p2.x, p1.y) + + # params = [solvesys.addParamV(v, group) for v in coords] + # p = solvesys.addPoint2d(wp, *params, group=group) + + # handles.append( + # solvesys.addPointsHorizontal(p, e2.py_data, wp, group=group) + # ) + # handles.append( + # solvesys.addPointsVertical(p, e1.py_data, wp, group=group) + # ) + + # base_point = e1 if alignment == "VERTICAL" else e2 + # handles.append( + # solvesys.addPointsDistance( + # value, p, base_point.py_data, wrkpln=wp, group=group + # ) + # ) + # return handles + # else: + # func = solvesys.addPointsDistance + # set_wp = True + + # kwargs = { + # "group": group, + # } + + # if set_wp: + # kwargs["wrkpln"] = self.get_workplane() + + # return func(value, e1.py_data, e2.py_data, **kwargs) + + def create_slvs_data(self, solvesys): if self.entity1 == self.entity2: - raise AttributeError("Cannot create constraint between one entity itself") - # TODO: don't allow Distance if Point -> Line if (Point in Line) + raise AttributeError( + "Cannot create constraint between one entity itself") e1, e2 = self.entity1, self.entity2 if e1.is_line(): e1, e2 = e1.p1, e1.p2 - func = None - set_wp = False wp = self.get_workplane() - alignment = self.align - align = self.use_align() and alignment != "NONE" - handles = [] - value = self.get_value() - # circle/arc -> line/point - if type(e1) in CURVE: - # TODO: make Horizontal and Vertical alignment work - if type(e2) in LINE: - return solvesys.addPointLineDistance( - value + e1.radius, e1.ct.py_data, e2.py_data, wp, group - ) - else: - assert isinstance(e2, SlvsPoint2D) - return solvesys.addPointsDistance( - value + e1.radius, e1.ct.py_data, e2.py_data, wp, group - ) - - elif type(e2) in LINE: - func = solvesys.addPointLineDistance - set_wp = True - elif isinstance(e2, SlvsWorkplane): - func = solvesys.addPointPlaneDistance - elif type(e2) in POINT: - if align and all([e.is_2d() for e in (e1, e2)]): - # Get Point in between - p1, p2 = e1.co, e2.co - coords = (p2.x, p1.y) - - params = [solvesys.addParamV(v, group) for v in coords] - p = solvesys.addPoint2d(wp, *params, group=group) - - handles.append( - solvesys.addPointsHorizontal(p, e2.py_data, wp, group=group) - ) - handles.append( - solvesys.addPointsVertical(p, e1.py_data, wp, group=group) - ) - - base_point = e1 if alignment == "VERTICAL" else e2 - handles.append( - solvesys.addPointsDistance( - value, p, base_point.py_data, wrkpln=wp, group=group - ) + if e1.is_curve(): + if e2.is_line() or (e2.is_point() and e2.is_2d()): + return solvesys.distance( + e1.ct.py_data, e2.py_data, value + e1.radius, wp ) - return handles else: - func = solvesys.addPointsDistance - set_wp = True - - kwargs = { - "group": group, - } + raise NotImplementedError() - if set_wp: - kwargs["wrkpln"] = self.get_workplane() + kwargs = {} if isinstance(e2, SlvsWorkplane) else { + "wp": self.get_workplane()} - return func(value, e1.py_data, e2.py_data, **kwargs) + return solvesys.distance(e1.py_data, e2.py_data, value, **kwargs) def matrix_basis(self): if self.sketch_i == -1 or not self.entity1.is_2d(): diff --git a/model/equal.py b/model/equal.py index 156d8500..e66004f6 100644 --- a/model/equal.py +++ b/model/equal.py @@ -10,6 +10,7 @@ from .line_2d import SlvsLine2D from .arc import SlvsArc from .circle import SlvsCircle +from functools import partial logger = logging.getLogger(__name__) @@ -41,31 +42,8 @@ def get_types(cls, index, entities): return (type(e),) return cls.signature[index] - def create_slvs_data(self, solvesys, group=Solver.group_fixed): - # TODO: Don't allow to add Equal between Line and Circle - e1, e2 = self.entity1, self.entity2 - - func = None - set_wp = False - - if all([type(e) in LINE for e in (e1, e2)]): - func = solvesys.addEqualLength - set_wp = True - elif all([type(e) in CURVE for e in (e1, e2)]): - func = solvesys.addEqualRadius - else: - # TODO: Do a proper check to see if there's really one Arc and one Line - func = solvesys.addEqualLineArcLength - set_wp = True - - kwargs = { - "group": group, - } - - if set_wp: - kwargs["wrkpln"] = self.get_workplane() - - return func(e1.py_data, e2.py_data, **kwargs) + def create_slvs_data(self, solvesys): + return solvesys.equal(self.entity1.py_data, self.entity2.py_data, self.get_workplane()) def placements(self): return (self.entity1, self.entity2) diff --git a/model/horizontal.py b/model/horizontal.py index ffe71508..90f7fed0 100644 --- a/model/horizontal.py +++ b/model/horizontal.py @@ -35,13 +35,11 @@ def get_types(cls, index, entities): def needs_wp(self): return WpReq.NOT_FREE - def create_slvs_data(self, solvesys, group=Solver.group_fixed): + def create_slvs_data(self, solvesys): wp = self.get_workplane() - if self.entity1.is_point(): - return solvesys.addPointsHorizontal( - self.entity1.py_data, self.entity2.py_data, wp, group=group - ) - return solvesys.addLineHorizontal(self.entity1.py_data, wrkpln=wp, group=group) + if self.entity2: + return solvesys.horizontal(self.entity1.py_data, wp, self.entity2.py_data) + return solvesys.horizontal(self.entity1.py_data, wp) def placements(self): return (self.entity1,) diff --git a/model/line_2d.py b/model/line_2d.py index ab5c4c1d..b7b0932b 100644 --- a/model/line_2d.py +++ b/model/line_2d.py @@ -58,8 +58,8 @@ def update(self): self._batch = batch_for_shader(self._shader, "LINES", kwargs) self.is_dirty = False - def create_slvs_data(self, solvesys, group=Solver.group_fixed): - handle = solvesys.addLineSegment(self.p1.py_data, self.p2.py_data, group=group) + def create_slvs_data(self, solvesys): + handle = solvesys.add_line_2d(self.p1.py_data, self.p2.py_data, self.wp.py_data) self.py_data = handle def closest_picking_point(self, origin, view_vector): diff --git a/model/line_3d.py b/model/line_3d.py index e7d1bb82..4a558100 100644 --- a/model/line_3d.py +++ b/model/line_3d.py @@ -52,8 +52,8 @@ def update(self): self.is_dirty = False - def create_slvs_data(self, solvesys, group=Solver.group_fixed): - handle = solvesys.addLineSegment(self.p1.py_data, self.p2.py_data, group=group) + def create_slvs_data(self, solvesys): + handle = solvesys.add_line_3d(self.p1.py_data, self.p2.py_data) self.py_data = handle def closest_picking_point(self, origin, view_vector): diff --git a/model/midpoint.py b/model/midpoint.py index d451c055..f7e5deda 100644 --- a/model/midpoint.py +++ b/model/midpoint.py @@ -22,16 +22,10 @@ class SlvsMidpoint(GenericConstraint, PropertyGroup): def needs_wp(self): return WpReq.NOT_FREE - def create_slvs_data(self, solvesys, group=Solver.group_fixed): - kwargs = { - "group": group, - } - + def create_slvs_data(self, solvesys): wp = self.get_workplane() - if wp: - kwargs["wrkpln"] = wp - - return solvesys.addMidPoint( + kwargs = {"wp": wp} if wp else {} + return solvesys.midpoint( self.entity1.py_data, self.entity2.py_data, **kwargs, diff --git a/model/normal_2d.py b/model/normal_2d.py index 7173e8da..5a2244ae 100644 --- a/model/normal_2d.py +++ b/model/normal_2d.py @@ -31,8 +31,8 @@ def draw(self, context): def draw_id(self, context): pass - def create_slvs_data(self, solvesys, group=Solver.group_fixed): - handle = solvesys.addNormal2d(self.wp.py_data, group=group) + def create_slvs_data(self, solvesys): + handle = solvesys.add_normal_2d(self.wp.py_data) self.py_data = handle diff --git a/model/normal_3d.py b/model/normal_3d.py index ee5ddc5a..c7218b58 100644 --- a/model/normal_3d.py +++ b/model/normal_3d.py @@ -22,9 +22,9 @@ def draw(self, context: Context): def draw_id(self, context: Context): pass - def create_slvs_data(self, solvesys, group=Solver.group_fixed): + def create_slvs_data(self, solvesys): quat = self.orientation - handle = solvesys.addNormal3dV(quat.w, quat.x, quat.y, quat.z, group=group) + handle = solvesys.add_normal_3d(quat.w, quat.x, quat.y, quat.z) self.py_data = handle diff --git a/model/parallel.py b/model/parallel.py index b1fa97e6..f2d9b431 100644 --- a/model/parallel.py +++ b/model/parallel.py @@ -22,12 +22,11 @@ class SlvsParallel(GenericConstraint, PropertyGroup): def needs_wp(self): return WpReq.NOT_FREE - def create_slvs_data(self, solvesys, group=Solver.group_fixed): - return solvesys.addParallel( + def create_slvs_data(self, solvesys): + return solvesys.parallel( self.entity1.py_data, self.entity2.py_data, - wrkpln=self.get_workplane(), - group=group, + wp=self.get_workplane(), ) def placements(self): diff --git a/model/perpendicular.py b/model/perpendicular.py index 4e9fe102..ec31c4d2 100644 --- a/model/perpendicular.py +++ b/model/perpendicular.py @@ -25,12 +25,11 @@ class SlvsPerpendicular(GenericConstraint, PropertyGroup): def needs_wp(self): return WpReq.NOT_FREE - def create_slvs_data(self, solvesys, group=Solver.group_fixed): - return solvesys.addPerpendicular( + def create_slvs_data(self, solvesys): + return solvesys.perpendicular( self.entity1.py_data, self.entity2.py_data, - wrkpln=self.get_workplane(), - group=group, + wp=self.get_workplane(), ) def placements(self): diff --git a/model/point_2d.py b/model/point_2d.py index 1142eab4..7fe1b62b 100644 --- a/model/point_2d.py +++ b/model/point_2d.py @@ -12,7 +12,7 @@ from ..solver import Solver from .base_entity import SlvsGenericEntity from .base_entity import Entity2D -from .utilities import slvs_entity_pointer, make_coincident +from .utilities import slvs_entity_pointer from .line_2d import SlvsLine2D logger = logging.getLogger(__name__) @@ -49,18 +49,15 @@ def location(self): def placement(self): return self.location - def create_slvs_data(self, solvesys, coords=None, group=Solver.group_fixed): + def create_slvs_data(self, solvesys, coords=None): if not coords: coords = self.co - self.params = [solvesys.addParamV(v, group) for v in coords] - - handle = solvesys.addPoint2d(self.wp.py_data, *self.params, group=group) + handle = solvesys.add_point_2d(*coords, self.wp.py_data) self.py_data = handle def update_from_slvs(self, solvesys): - coords = [solvesys.getParam(i).val for i in self.params] - self.co = coords + self.co = solvesys.params(self.py_data.params) def closest_picking_point(self, origin, view_vector): """Returns the point on this entity which is closest to the picking ray""" @@ -90,10 +87,10 @@ def dependencies(self) -> List[SlvsGenericEntity]: ] def tweak(self, solvesys, pos, group): - wrkpln = self.sketch.wp - u, v, _ = wrkpln.matrix_basis.inverted() @ pos + wp = self.sketch.wp + u, v, _ = wp.matrix_basis.inverted() @ pos - self.create_slvs_data(solvesys, group=group) + self.create_slvs_data(solvesys) # NOTE: When simply initializing the point on the tweaking positions # the solver fails regularly, addWhereDragged fixes a point and might @@ -106,17 +103,13 @@ def tweak(self, solvesys, pos, group): tweak_vec = tweak_pos - orig_pos perpendicular_vec = Vector((tweak_vec[1], -tweak_vec[0])) - params = [solvesys.addParamV(val, group) for val in (u, v)] - startpoint = solvesys.addPoint2d(wrkpln.py_data, *params, group=group) + startpoint = solvesys.add_point_2d(u, v, wp=wp.py_data) p2 = tweak_pos + perpendicular_vec - params = [solvesys.addParamV(val, group) for val in (p2.x, p2.y)] - endpoint = solvesys.addPoint2d(wrkpln.py_data, *params, group=group) + endpoint = solvesys.add_point_2d(p2.x, p2.y, wp=wp.py_data) - edge = solvesys.addLineSegment(startpoint, endpoint, group=group) - make_coincident( - solvesys, self.py_data, edge, wrkpln.py_data, group, entity_type=SlvsLine2D - ) + edge = solvesys.add_line_2d(startpoint, endpoint, self.wp.py_data) + solvesys.coincident(self.py_data, edge, wp.py_data) def draw_props(self, layout): sub = super().draw_props(layout) diff --git a/model/point_3d.py b/model/point_3d.py index e69db921..d2e9e3f9 100644 --- a/model/point_3d.py +++ b/model/point_3d.py @@ -33,17 +33,15 @@ def update(self): def placement(self): return self.location - def create_slvs_data(self, solvesys, coords=None, group=Solver.group_fixed): + def create_slvs_data(self, solvesys, coords=None): if not coords: coords = self.location - self.params = [solvesys.addParamV(v, group) for v in coords] - - handle = solvesys.addPoint3d(*self.params, group=group) + handle = solvesys.add_point_3d(*coords) self.py_data = handle def update_from_slvs(self, solvesys): - coords = [solvesys.getParam(i).val for i in self.params] + coords = solvesys.params(self.py_data.params) self.location = coords def closest_picking_point(self, origin, view_vector): diff --git a/model/ratio.py b/model/ratio.py index 7f6ff9f8..2f599fcd 100644 --- a/model/ratio.py +++ b/model/ratio.py @@ -40,15 +40,14 @@ def needs_wp(self): return WpReq.NOT_FREE return WpReq.FREE - def create_slvs_data(self, solvesys, group=Solver.group_fixed): + def create_slvs_data(self, solvesys): e1, e2 = self.entity1, self.entity2 - return solvesys.addLengthRatio( - self.value, + return solvesys.ratio( e1.py_data, e2.py_data, + self.value, self.get_workplane(), - group=group, ) def init_props(self, **kwargs): diff --git a/model/sketch.py b/model/sketch.py index c0b5a81a..20cb5d8b 100644 --- a/model/sketch.py +++ b/model/sketch.py @@ -83,7 +83,7 @@ def draw(self, context): def draw_id(self, context): pass - def create_slvs_data(self, solvesys, group=Solver.group_fixed): + def create_slvs_data(self, solvesys): pass def remove_objects(self): diff --git a/model/symmetry.py b/model/symmetry.py index cff9f59c..a025ccbb 100644 --- a/model/symmetry.py +++ b/model/symmetry.py @@ -40,27 +40,14 @@ def needs_wp(self): return WpReq.NOT_FREE return WpReq.FREE - def create_slvs_data(self, solvesys, group=Solver.group_fixed): + def create_slvs_data(self, solvesys): e1, e2, e3 = self.entity1, self.entity2, self.entity3 - - # NOTE: this doesn't seem to work correctly, acts like addSymmetricVertical - if isinstance(e3, SlvsLine2D): - return solvesys.addSymmetricLine( - e1.py_data, - e2.py_data, - e3.py_data, - self.get_workplane(), - group=group, - ) - - elif isinstance(e3, SlvsWorkplane): - return solvesys.addSymmetric( - e1.py_data, - e2.py_data, - e3.py_data, - wrkpln=self.get_workplane(), - group=group, - ) + return solvesys.symmetric( + e1.py_data, + e2.py_data, + e3.py_data, + self.get_workplane() + ) def placements(self): return (self.entity1, self.entity2, self.entity3) diff --git a/model/tangent.py b/model/tangent.py index 4c2baf21..dda58576 100644 --- a/model/tangent.py +++ b/model/tangent.py @@ -6,11 +6,12 @@ from ..solver import Solver from ..global_data import WpReq from .base_constraint import GenericConstraint -from .utilities import slvs_entity_pointer, make_coincident, get_connection_point +from .utilities import slvs_entity_pointer, get_connection_point from .categories import CURVE from .line_2d import SlvsLine2D from .arc import SlvsArc from .circle import SlvsCircle +from .utilities import make_coincident logger = logging.getLogger(__name__) @@ -25,53 +26,23 @@ class SlvsTangent(GenericConstraint, PropertyGroup): def needs_wp(self): return WpReq.NOT_FREE - def create_slvs_data(self, solvesys, group=Solver.group_fixed): + def create_slvs_data(self, solvesys): e1, e2 = self.entity1, self.entity2 wp = self.get_workplane() - # check if entities share a point point = get_connection_point(e1, e2) if point and not isinstance(e2, SlvsCircle): - if isinstance(e2, SlvsLine2D): - return solvesys.addArcLineTangent( - e1.direction(point), - e1.py_data, - e2.py_data, - group=group, - ) - elif isinstance(e2, SlvsArc): - return solvesys.addCurvesTangent( - e1.direction(point), - e2.direction(point), - e1.py_data, - e2.py_data, - wrkpln=wp, - group=group, - ) - + if isinstance(e2, (SlvsLine2D, SlvsArc)): + return solvesys.tangent(e1.py_data, e2.py_data, wp) elif isinstance(e2, SlvsLine2D): orig = e2.p1.co coords = (e1.ct.co - orig).project(e2.p2.co - orig) + orig - params = [solvesys.addParamV(v, group) for v in coords] - p = solvesys.addPoint2d(wp, *params, group=group) - line = solvesys.addLineSegment(e1.ct.py_data, p, group=group) - - return ( - make_coincident(solvesys, p, e1, wp, group), - make_coincident(solvesys, p, e2, wp, group), - solvesys.addPerpendicular(e2.py_data, line, wrkpln=wp, group=group), - ) - - elif e2.is_curve(): - coords = (e1.ct.co + e2.ct.co) / 2 - params = [solvesys.addParamV(v, group) for v in coords] - p = solvesys.addPoint2d(wp, *params, group=group) - line = solvesys.addLineSegment(e1.ct.py_data, e2.ct.py_data, group=group) - + p = solvesys.add_point_2d(*tuple(coords), wp) + l = solvesys.add_line_2d(e1.ct.py_data, p, wp=wp) return ( - make_coincident(solvesys, p, e1, wp, group), - make_coincident(solvesys, p, e2, wp, group), - solvesys.addPointOnLine(p, line, group=group, wrkpln=wp), + make_coincident(solvesys, p, e1, wp), + make_coincident(solvesys, p, e2, wp), + solvesys.perpendicular(e2.py_data, l, wp=wp), ) def placements(self): diff --git a/model/utilities.py b/model/utilities.py index 74c6742a..b0cd0a1d 100644 --- a/model/utilities.py +++ b/model/utilities.py @@ -108,12 +108,9 @@ def create_bezier_curve( # NOTE: When tweaking, it's necessary to constrain a point that is only temporary available # and has no SlvsPoint representation -def make_coincident(solvesys, point_handle, e2, wp, group, entity_type=None): - from .categories import LINE, CURVE, POINT +def make_coincident(solvesys, point_handle, e2, wp, entity_type=None): from .workplane import SlvsWorkplane - - func = None - set_wp = False + from .categories import LINE, CURVE, POINT if entity_type: handle = e2 @@ -121,26 +118,19 @@ def make_coincident(solvesys, point_handle, e2, wp, group, entity_type=None): entity_type = type(e2) handle = e2.py_data - if entity_type in LINE: - func = solvesys.addPointOnLine - set_wp = True - elif entity_type in CURVE: - func = solvesys.addPointOnCircle - elif entity_type == SlvsWorkplane: - func = solvesys.addPointInPlane - elif entity_type in POINT: - func = solvesys.addPointsCoincident - set_wp = True - - kwargs = { - "group": group, - } - - if set_wp: - kwargs["wrkpln"] = wp + if entity_type in CURVE: + # Has to use the C Enum Flag for the constraint, as it hasn't been fixed. + # See https://github.com/KmolYuan/solvespace/blob/python/cython/python_solvespace/slvs.pyx#L729 + # Doc solvesystem: https://github.com/solvespace/solvespace/blob/master/exposed/DOC.txt#L376 + from solvespace import Constraint, Entity + _E_NONE = Entity() # empty entities + return solvesys.add_constraint(Constraint.PT_ON_CIRCLE, wp, 0., point_handle, _E_NONE, handle, _E_NONE) - return func(point_handle, handle, **kwargs) + kwargs = [] + if entity_type != SlvsWorkplane: + kwargs = {"wp": wp} + return solvesys.coincident(point_handle, handle, **kwargs) def update_pointers(scene, index_old, index_new): """Replaces all references to an entity index with its new index""" diff --git a/model/vertical.py b/model/vertical.py index 30ae37bf..51e41a2d 100644 --- a/model/vertical.py +++ b/model/vertical.py @@ -34,13 +34,11 @@ def get_types(cls, index, entities): def needs_wp(self): return WpReq.NOT_FREE - def create_slvs_data(self, solvesys, group=Solver.group_fixed): + def create_slvs_data(self, solvesys): wp = self.get_workplane() - if self.entity1.is_point(): - return solvesys.addPointsVertical( - self.entity1.py_data, self.entity2.py_data, wp, group=group - ) - return solvesys.addLineVertical(self.entity1.py_data, wrkpln=wp, group=group) + if self.entity2: + return solvesys.vertical(self.entity1.py_data, wp, self.entity2.py_data) + return solvesys.vertical(self.entity1.py_data, wp) def placements(self): return (self.entity1,) diff --git a/model/workplane.py b/model/workplane.py index 69494a11..6adcea21 100644 --- a/model/workplane.py +++ b/model/workplane.py @@ -93,8 +93,8 @@ def draw_id(self, context): gpu.matrix.scale(Vector((scale, scale, scale))) super().draw_id(context) - def create_slvs_data(self, solvesys, group=Solver.group_fixed): - handle = solvesys.addWorkplane(self.p1.py_data, self.nm.py_data, group=group) + def create_slvs_data(self, solvesys): + handle = solvesys.add_work_plane(self.p1.py_data, self.nm.py_data) self.py_data = handle @property diff --git a/solver.py b/solver.py index 8874a97b..525987ce 100644 --- a/solver.py +++ b/solver.py @@ -31,11 +31,11 @@ def __init__(self, context, sketch, all=False): logger.info( "--- Start solving ---\nAll:{}, Sketch:{}, g:{}".format(all, sketch, group) ) - from py_slvs import slvs - self.solvesys = slvs.System() + from solvespace import SolverSystem, Entity + self.solvesys = SolverSystem() - self.FREE_IN_3D = slvs.SLVS_FREE_IN_3D + self.FREE_IN_3D = Entity.FREE_IN_3D self.sketch = sketch self.ok = True @@ -71,35 +71,28 @@ def _init_slvs_data(self): group = self._get_group(e.sketch) else: group = self.group_3d - + self.solvesys.set_group(group) if self.tweak_entity and e == self.tweak_entity: wp = self.get_workplane() if hasattr(e, "tweak"): e.tweak(self.solvesys, self.tweak_pos, group) else: if not self.sketch: - params = [ - self.solvesys.addParamV(val, group) - for val in self.tweak_pos - ] - p = self.solvesys.addPoint3d(*params, group=group) + p = self.solvesys.add_point_3d(*self.tweak_pos) else: wrkpln = self.sketch.wp u, v, _ = wrkpln.matrix_basis.inverted() @ self.tweak_pos - params = [self.solvesys.addParamV(val, group) for val in (u, v)] - p = self.solvesys.addPoint2d( - wrkpln.py_data, *params, group=group - ) + p = self.solvesys.add_point_2d(u, v, wrkpln.py_data) - e.create_slvs_data(self.solvesys, group=group) + e.create_slvs_data(self.solvesys) self.tweak_constraint = make_coincident( - self.solvesys, p, e, wp, group + self.solvesys, p, e, wp ) - self.solvesys.addWhereDragged(p, wrkpln=wp, group=group) + self.solvesys.dragged(p, wp) continue - e.create_slvs_data(self.solvesys, group=group) + e.create_slvs_data(self.solvesys) def _get_msg_entities(): msg = "Initialize entities:" @@ -122,7 +115,7 @@ def _get_msg_entities(): # Store a index-constraint mapping from collections.abc import Iterable - indices = c.py_data(self.solvesys, group=group) + indices = c.create_slvs_data(self.solvesys) self._store_constraint_indices( c, indices if isinstance(indices, Iterable) else (indices,) ) @@ -193,7 +186,6 @@ def needs_update(self, e): def solve(self, report=True): self.report = report self._init_slvs_data() - if self.all: sse = self.context.scene.sketcher.entities sketches = [None, *sse.sketches] @@ -203,12 +195,7 @@ def solve(self, report=True): ] for sketch in sketches: - g = self._get_group(sketch) - retval = self.solvesys.solve( - group=g, - reportFailed=report, - findFreeParams=False, - ) + retval = self.solvesys.solve() if retval > 5: logger.debug("Solver returned undocumented value: {}".format(retval)) @@ -217,7 +204,7 @@ def solve(self, report=True): if report and sketch: sketch.solver_state = self.result.index - sketch.dof = self.solvesys.Dof + sketch.dof = self.solvesys.dof() if retval != 0 and retval != 5: self.ok = False @@ -227,7 +214,8 @@ def solve(self, report=True): logger.info(self.result.description) - fails = self.solvesys.Failed + fails = self.solvesys.failures() + print("fails: {}".format(fails)) if report and fails: for i in fails: diff --git a/testing/constraints/angle.blend b/testing/constraints/angle.blend new file mode 100644 index 00000000..792d24b4 Binary files /dev/null and b/testing/constraints/angle.blend differ diff --git a/testing/constraints/coincident_point_arc.blend b/testing/constraints/coincident_point_arc.blend new file mode 100644 index 00000000..7d458166 Binary files /dev/null and b/testing/constraints/coincident_point_arc.blend differ diff --git a/testing/constraints/coincident_point_circle.blend b/testing/constraints/coincident_point_circle.blend new file mode 100644 index 00000000..e9507376 Binary files /dev/null and b/testing/constraints/coincident_point_circle.blend differ diff --git a/testing/constraints/coincident_point_line.blend b/testing/constraints/coincident_point_line.blend new file mode 100644 index 00000000..9d8fb593 Binary files /dev/null and b/testing/constraints/coincident_point_line.blend differ diff --git a/testing/constraints/diameter.blend b/testing/constraints/diameter.blend new file mode 100644 index 00000000..0732425d Binary files /dev/null and b/testing/constraints/diameter.blend differ diff --git a/testing/constraints/distance_point_arc.blend b/testing/constraints/distance_point_arc.blend new file mode 100644 index 00000000..3248fdcf Binary files /dev/null and b/testing/constraints/distance_point_arc.blend differ diff --git a/testing/constraints/distance_point_circle.blend b/testing/constraints/distance_point_circle.blend new file mode 100644 index 00000000..c439f355 Binary files /dev/null and b/testing/constraints/distance_point_circle.blend differ diff --git a/testing/constraints/distance_point_line.blend b/testing/constraints/distance_point_line.blend new file mode 100644 index 00000000..59ee5bad Binary files /dev/null and b/testing/constraints/distance_point_line.blend differ diff --git a/testing/constraints/distance_point_point.blend b/testing/constraints/distance_point_point.blend new file mode 100644 index 00000000..3e1976a2 Binary files /dev/null and b/testing/constraints/distance_point_point.blend differ diff --git a/testing/constraints/equal_circle_arc.blend b/testing/constraints/equal_circle_arc.blend new file mode 100644 index 00000000..e426f2e8 Binary files /dev/null and b/testing/constraints/equal_circle_arc.blend differ diff --git a/testing/constraints/equal_line_2d.blend b/testing/constraints/equal_line_2d.blend new file mode 100644 index 00000000..458bcbca Binary files /dev/null and b/testing/constraints/equal_line_2d.blend differ diff --git a/testing/constraints/equal_line_arc.blend b/testing/constraints/equal_line_arc.blend new file mode 100644 index 00000000..c9b89294 Binary files /dev/null and b/testing/constraints/equal_line_arc.blend differ diff --git a/testing/constraints/horizontal_line.blend b/testing/constraints/horizontal_line.blend new file mode 100644 index 00000000..e46f4041 Binary files /dev/null and b/testing/constraints/horizontal_line.blend differ diff --git a/testing/constraints/horizontal_points.blend b/testing/constraints/horizontal_points.blend new file mode 100644 index 00000000..7528da0b Binary files /dev/null and b/testing/constraints/horizontal_points.blend differ diff --git a/testing/constraints/midpoint.blend b/testing/constraints/midpoint.blend new file mode 100644 index 00000000..1aed8194 Binary files /dev/null and b/testing/constraints/midpoint.blend differ diff --git a/testing/constraints/parallel.blend b/testing/constraints/parallel.blend new file mode 100644 index 00000000..6bc80191 Binary files /dev/null and b/testing/constraints/parallel.blend differ diff --git a/testing/constraints/perpendicular.blend b/testing/constraints/perpendicular.blend new file mode 100644 index 00000000..c03b59d0 Binary files /dev/null and b/testing/constraints/perpendicular.blend differ diff --git a/testing/constraints/ratio.blend b/testing/constraints/ratio.blend new file mode 100644 index 00000000..e6767db5 Binary files /dev/null and b/testing/constraints/ratio.blend differ diff --git a/testing/constraints/tangent_arc_arc.blend b/testing/constraints/tangent_arc_arc.blend new file mode 100644 index 00000000..fe5e62c4 Binary files /dev/null and b/testing/constraints/tangent_arc_arc.blend differ diff --git a/testing/constraints/tangent_arc_line.blend b/testing/constraints/tangent_arc_line.blend new file mode 100644 index 00000000..e0b1c4e5 Binary files /dev/null and b/testing/constraints/tangent_arc_line.blend differ diff --git a/testing/constraints/vertical_line.blend b/testing/constraints/vertical_line.blend new file mode 100644 index 00000000..032def1a Binary files /dev/null and b/testing/constraints/vertical_line.blend differ diff --git a/testing/constraints/vertical_points.blend b/testing/constraints/vertical_points.blend new file mode 100644 index 00000000..4b18eeae Binary files /dev/null and b/testing/constraints/vertical_points.blend differ diff --git a/testing/constraints/vertical_points.blend1 b/testing/constraints/vertical_points.blend1 new file mode 100644 index 00000000..b66ee9b0 Binary files /dev/null and b/testing/constraints/vertical_points.blend1 differ diff --git a/testing/test_constraints.py b/testing/test_constraints.py new file mode 100644 index 00000000..b683427d --- /dev/null +++ b/testing/test_constraints.py @@ -0,0 +1,15 @@ +import glob +from pathlib import Path +from CAD_Sketcher.testing.utils import BgsTestCase + +class TestConstraints(BgsTestCase): + def test_constraints(self): + import bpy + path = str(Path(__file__).parent.absolute() / "constraints" / "*.blend") + test_files = glob.glob(path) + for test_file in test_files: + with bpy.data.libraries.load(test_file) as (data_from, data_to): + for attr in dir(data_to): + setattr(data_to, attr, getattr(data_from, attr)) + ok = self.context.scene.sketcher.solve(self.context) + self.assertTrue(ok)