Skip to content

Instantly share code, notes, and snippets.

@rvodden
Created September 16, 2021 15:47
Show Gist options
  • Save rvodden/c5d7d6ecea734006469d8dc758f9d1ae to your computer and use it in GitHub Desktop.
Save rvodden/c5d7d6ecea734006469d8dc758f9d1ae to your computer and use it in GitHub Desktop.
PySketcher Geometric Solver Recap of Part 1
from abc import ABC
class Constraint(ABC):
"""Used to restrict that value of a ```ConstrainedValue```."""
pass
class FixedValueConstraint(Constraint):
def __init__(self, value):
self._value = value
@property
def value(self):
return self._value
def __repr__(self):
return f"{self.__class__.__name__}<{self.value}>"
class LinkedValueConstraint(Constraint):
def __init__(self, constraint_set):
self._constraint_set = constraint_set
@property
def constraint_set(self):
return self._constraint_set
def __repr__(self):
return f"{self.__class__.__name__}<{self.constraint_set}>"
class ConstraintSet:
def __init__(self, name=""):
self._constraints = []
self._name = name
def constrain_with(self, constraint):
"""Add a constraint to this objects list of constraints."""
self._constraints.append(constraint)
def reset_constraints(self):
"""Removes the existing constraints from the constraint set"""
self._constraints = []
def resolve(self):
"""Naive implementation to aid testing"""
for constraint in self._constraints:
if isinstance(constraint, FixedValueConstraint):
return constraint.value
if isinstance(constraint, LinkedValueConstraint):
return constraint.constraint_set.resolve()
raise UnderconstrainedError("Fixed Value has not been provided.")
def __repr__(self):
retval = "ConstraintSet("
if len(self._constraints) == 0:
retval += ")"
return retval
for constraint in self._constraints:
retval += f"\n {constraint}"
retval += "\n)"
return retval
def __str__(self):
return self._name
class UnderConstrainedError(RuntimeError):
pass
class ConstrainedValue:
"""An object which can be passed around to represent a value."""
def __set_name__(self, owner, name):
self.public_name = name
self.private_name = f"_{name}"
def __get__(self, instance, typ=None):
# grab the ConstraintSet from the instance
constraint_set = getattr(instance, self.private_name, None)
# If the instance didn't have an initialized ConstraintSet then
# give it one
if constraint_set is None:
constraint_set = ConstraintSet(f"{instance.name}.{self.public_name}")
setattr(instance, self.private_name, constraint_set)
return constraint_set
def __set__(self, instance, value):
# Grab the ConstraintSet from the instance
constraint_set = self.__get__(instance, None)
constraint_set.reset_constraints()
# if the value we've been asked to assign is a ConstraintSet
# then add a LinkedValueConstraint:
if isinstance(value, ConstraintSet):
constraint_set.constrain_with(LinkedValueConstraint(value))
return
# otherwise use a FixedValueConstraint to constrain to the provided
# value
constraint_set.constrain_with(FixedValueConstraint(value))
class Point:
x = ConstrainedValue()
y = ConstrainedValue()
def __init__(self, name="", x=None, y=None):
self._name = name
if x is not None:
self.x = x
if y is not None :
self.y = y
@property
def name(self):
return self._name
p = Point('p', 1,2)
q = Point('q')
print(f"p.x is {p.x}")
print(f"p.x resolves to {p.x.resolve()}")
q.x = p.x
print(f"q.x is {repr(q.x)}")
print(f"q.x resolves to {q.x.resolve()}")
p.x = 2
print(f"Now p.x has changed, q.x resolves to {q.x.resolve()}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment