Skip to content

Commit

Permalink
Checks for duplicate constraints. (#461)
Browse files Browse the repository at this point in the history
* Checks for duplicate constraints.
On constraint creation checks are added to see if it exists on the selected entity or entitiies.
The exists method was added to GenericConstraintOp for this.
Line distances have been replaced for point to point distances.

* Flake8 cleanups

* Simplify exists method and version changes
Simplified the exists method in base_constraint not to do specific checks and moved this logic into the add_distance operator.
Added version check for older drawings. This updates all distance constraints on a line to the endpoints of that line.
Changed addon version from 0.27.3 to 0.27.4

* Removed nested if statements
Added extra check on length of line_entities to avoid errors if it would somehow be out of bounds
  • Loading branch information
TimStrauven committed Apr 25, 2024
1 parent f297800 commit 1476235
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 72 deletions.
2 changes: 1 addition & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
bl_info = {
"name": "CAD Sketcher",
"author": "hlorus",
"version": (0, 27, 3),
"version": (0, 27, 4),
"blender": (3, 3, 0),
"location": "View3D > Toolbar",
"description": "Parametric, constraint-based geometry sketcher",
Expand Down
2 changes: 1 addition & 1 deletion blender_manifest.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
schema_version = "1.0.0"

id = "CAD_Sketcher"
version = "0.27.3"
version = "0.27.4"
name = "CAD Sketcher"
tagline = "Parametric, constraint-based geometry sketcher"
maintainer = "hlorus <dave19924@gmail.com>"
Expand Down
17 changes: 10 additions & 7 deletions operators/add_angle.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from ..stateful_operator.utilities.register import register_stateops_factory
from .base_constraint import GenericConstraintOp

from ..model.angle import SlvsAngle

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -45,13 +47,14 @@ class VIEW3D_OT_slvs_add_angle(Operator, GenericConstraintOp):
property_keys = ("value", "setting")

def main(self, context):
self.target = context.scene.sketcher.constraints.add_angle(
self.entity1,
self.entity2,
sketch=self.sketch,
init=not self.initialized,
**self.get_settings()
)
if not self.exists(context, SlvsAngle):
self.target = context.scene.sketcher.constraints.add_angle(
self.entity1,
self.entity2,
sketch=self.sketch,
init=not self.initialized,
**self.get_settings()
)

return super().main(context)

Expand Down
15 changes: 9 additions & 6 deletions operators/add_diameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from ..stateful_operator.utilities.register import register_stateops_factory
from .base_constraint import GenericConstraintOp

from ..model.diameter import SlvsDiameter

logger = logging.getLogger(__name__)


Expand All @@ -30,12 +32,13 @@ class VIEW3D_OT_slvs_add_diameter(Operator, GenericConstraintOp):
property_keys = ("value", "setting")

def main(self, context):
self.target = context.scene.sketcher.constraints.add_diameter(
self.entity1,
sketch=self.sketch,
init=not self.initialized,
**self.get_settings(),
)
if not self.exists(context, SlvsDiameter):
self.target = context.scene.sketcher.constraints.add_diameter(
self.entity1,
sketch=self.sketch,
init=not self.initialized,
**self.get_settings(),
)

return super().main(context)

Expand Down
43 changes: 36 additions & 7 deletions operators/add_distance.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
from ..declarations import Operators
from ..stateful_operator.utilities.register import register_stateops_factory

from ..model.distance import SlvsDistance
from ..model.line_2d import SlvsLine2D
from ..model.point_2d import SlvsPoint2D
from ..model.types import SlvsPoint3D
from ..model.types import SlvsLine3D

logger = logging.getLogger(__name__)

Expand All @@ -33,13 +38,37 @@ class VIEW3D_OT_slvs_add_distance(Operator, GenericConstraintOp):
property_keys = ("value", "align", "flip")

def main(self, context):
self.target = context.scene.sketcher.constraints.add_distance(
self.entity1,
self.entity2,
sketch=self.sketch,
init=not self.initialized,
**self.get_settings(),
)
if isinstance(self.entity1, SlvsLine2D) and self.entity2 is None:
dependencies = self.entity1.dependencies()
if (isinstance(dependencies[0], SlvsPoint2D) and
isinstance(dependencies[1], SlvsPoint2D)):
# for loop changes the values of self.entity1 and self.entity2
# from a line entity to its endpoints
for i in range(0, 2):
state_data = self.get_state_data(i)
state_data["hovered"] = -1
state_data["type"] = type(dependencies[i])
state_data["is_existing_entity"] = True
state_data["entity_index"] = dependencies[i].slvs_index
self.next_state(context) # end user selection, no need for second entity

if (isinstance(self.entity1, (SlvsPoint3D, SlvsLine3D)) or
isinstance(self.entity2, (SlvsPoint3D, SlvsLine3D))):
max_constraints = 3
elif ((isinstance(self.entity1, SlvsLine2D) and self.entity2 is None) or
isinstance(self.entity1, SlvsPoint2D) and isinstance(self.entity2, SlvsPoint2D)):
max_constraints = 2
else:
max_constraints = 1

if not self.exists(context, SlvsDistance, max_constraints):
self.target = context.scene.sketcher.constraints.add_distance(
self.entity1,
self.entity2,
sketch=self.sketch,
init=not self.initialized,
**self.get_settings(),
)
return super().main(context)

def fini(self, context: Context, succeede: bool):
Expand Down
112 changes: 65 additions & 47 deletions operators/add_geometric_constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@
from ..utilities.view import refresh
from ..solver import solve_system

from ..model.coincident import SlvsCoincident
from ..model.equal import SlvsEqual
from ..model.vertical import SlvsVertical
from ..model.horizontal import SlvsHorizontal
from ..model.parallel import SlvsParallel
from ..model.perpendicular import SlvsPerpendicular
from ..model.tangent import SlvsTangent
from ..model.midpoint import SlvsMidpoint
from ..model.ratio import SlvsRatio

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -52,11 +61,12 @@ def main(self, context: Context):
if self.handle_merge(context):
return True

self.target = context.scene.sketcher.constraints.add_coincident(
self.entity1,
self.entity2,
sketch=self.sketch,
)
if not self.exists(context, SlvsCoincident):
self.target = context.scene.sketcher.constraints.add_coincident(
self.entity1,
self.entity2,
sketch=self.sketch,
)
return super().main(context)


Expand All @@ -70,11 +80,12 @@ class VIEW3D_OT_slvs_add_equal(Operator, GenericConstraintOp):
type = "EQUAL"

def main(self, context):
self.target = context.scene.sketcher.constraints.add_equal(
self.entity1,
self.entity2,
sketch=self.sketch,
)
if not self.exists(context, SlvsEqual):
self.target = context.scene.sketcher.constraints.add_equal(
self.entity1,
self.entity2,
sketch=self.sketch,
)

return super().main(context)

Expand All @@ -89,11 +100,12 @@ class VIEW3D_OT_slvs_add_vertical(Operator, GenericConstraintOp):
type = "VERTICAL"

def main(self, context):
self.target = context.scene.sketcher.constraints.add_vertical(
self.entity1,
entity2=self.entity2,
sketch=self.sketch,
)
if not self.exists(context, SlvsVertical):
self.target = context.scene.sketcher.constraints.add_vertical(
self.entity1,
entity2=self.entity2,
sketch=self.sketch,
)

return super().main(context)

Expand All @@ -108,11 +120,12 @@ class VIEW3D_OT_slvs_add_horizontal(Operator, GenericConstraintOp):
type = "HORIZONTAL"

def main(self, context):
self.target = context.scene.sketcher.constraints.add_horizontal(
self.entity1,
entity2=self.entity2,
sketch=self.sketch,
)
if not self.exists(context, SlvsHorizontal):
self.target = context.scene.sketcher.constraints.add_horizontal(
self.entity1,
entity2=self.entity2,
sketch=self.sketch,
)

return super().main(context)

Expand All @@ -127,11 +140,12 @@ class VIEW3D_OT_slvs_add_parallel(Operator, GenericConstraintOp):
type = "PARALLEL"

def main(self, context):
self.target = context.scene.sketcher.constraints.add_parallel(
self.entity1,
self.entity2,
sketch=self.sketch,
)
if not self.exists(context, SlvsParallel):
self.target = context.scene.sketcher.constraints.add_parallel(
self.entity1,
self.entity2,
sketch=self.sketch,
)

return super().main(context)

Expand All @@ -146,11 +160,12 @@ class VIEW3D_OT_slvs_add_perpendicular(Operator, GenericConstraintOp):
type = "PERPENDICULAR"

def main(self, context):
self.target = context.scene.sketcher.constraints.add_perpendicular(
self.entity1,
self.entity2,
sketch=self.sketch,
)
if not self.exists(context, SlvsPerpendicular):
self.target = context.scene.sketcher.constraints.add_perpendicular(
self.entity1,
self.entity2,
sketch=self.sketch,
)

return super().main(context)

Expand All @@ -165,11 +180,12 @@ class VIEW3D_OT_slvs_add_tangent(Operator, GenericConstraintOp):
type = "TANGENT"

def main(self, context):
self.target = context.scene.sketcher.constraints.add_tangent(
self.entity1,
self.entity2,
sketch=self.sketch,
)
if not self.exists(context, SlvsTangent):
self.target = context.scene.sketcher.constraints.add_tangent(
self.entity1,
self.entity2,
sketch=self.sketch,
)

return super().main(context)

Expand All @@ -184,11 +200,12 @@ class VIEW3D_OT_slvs_add_midpoint(Operator, GenericConstraintOp):
type = "MIDPOINT"

def main(self, context):
self.target = context.scene.sketcher.constraints.add_midpoint(
self.entity1,
self.entity2,
sketch=self.sketch,
)
if not self.exists(context, SlvsMidpoint):
self.target = context.scene.sketcher.constraints.add_midpoint(
self.entity1,
self.entity2,
sketch=self.sketch,
)

return super().main(context)

Expand All @@ -211,13 +228,14 @@ class VIEW3D_OT_slvs_add_ratio(Operator, GenericConstraintOp):
property_keys = ("value",)

def main(self, context):
self.target = context.scene.sketcher.constraints.add_ratio(
self.entity1,
self.entity2,
sketch=self.sketch,
init=not self.initialized,
**self.get_settings(),
)
if not self.exists(context, SlvsRatio):
self.target = context.scene.sketcher.constraints.add_ratio(
self.entity1,
self.entity2,
sketch=self.sketch,
init=not self.initialized,
**self.get_settings(),
)

return super().main(context)

Expand Down
19 changes: 16 additions & 3 deletions operators/base_constraint.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
from ..utilities.select import deselect_all
from ..utilities.view import refresh
from .base_2d import Operator2d
from ..utilities.select import deselect_all
from ..utilities.view import refresh
from ..solver import solve_system


logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -124,3 +121,19 @@ def draw(self, context: Context):

for key in self.property_keys:
layout.prop(self, key)

def exists(self, context, constraint_type=None, max_constraints=1) -> bool:
if hasattr(self, "entity2"):
new_dependencies = [i for i in [self.entity1, self.entity2, self.sketch] if i is not None]
else:
new_dependencies = [i for i in [self.entity1, self.sketch] if i is not None]

constraint_counter = 0
for c in context.scene.sketcher.constraints.all:
if isinstance(c, constraint_type):
if set(c.dependencies()) == set(new_dependencies):
constraint_counter += 1
if constraint_counter >= max_constraints:
return True

return False
24 changes: 24 additions & 0 deletions versioning.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,28 @@ def do_versioning(self):
)
c.is_reference = True

if version < (0, 27, 4):
# update distance constraints on only a line
# to distance constraints on the endpoints of that line.
from .model.line_2d import SlvsLine2D
from .model.distance import SlvsDistance
from .model.point_2d import SlvsPoint2D
from .model.sketch import SlvsSketch

for c in context.scene.sketcher.constraints.dimensional:
if len(c.dependencies()) != 2:
continue
if not (isinstance(c, SlvsDistance) and
isinstance(c.dependencies()[0], SlvsLine2D) and
isinstance(c.dependencies()[1], SlvsSketch)):
continue

line_dependencies = c.dependencies()[0].dependencies()
if len(line_dependencies) != 3:
continue
if (isinstance(line_dependencies[0], SlvsPoint2D) and
isinstance(line_dependencies[1], SlvsPoint2D)):
setattr(c, "entity1", line_dependencies[0])
setattr(c, "entity2", line_dependencies[1])

logger.debug(msg)

0 comments on commit 1476235

Please sign in to comment.