Make Constraint a protocol
So constraint and multi-constraint can be interchangeable.
This commit is contained in:
parent
447279d823
commit
81a76750e6
@ -100,9 +100,7 @@ class Port:
|
||||
"""Get glue point on the port and distance to the port."""
|
||||
raise NotImplementedError("Glue method not implemented")
|
||||
|
||||
def constraint(
|
||||
self, item: Item, handle: Handle, glue_item: Item
|
||||
) -> Union[Constraint, MultiConstraint]:
|
||||
def constraint(self, item: Item, handle: Handle, glue_item: Item) -> Constraint:
|
||||
"""Create connection constraint between item's handle and glue item."""
|
||||
raise NotImplementedError("Constraint method not implemented")
|
||||
|
||||
@ -131,9 +129,7 @@ class LinePort(Port):
|
||||
)
|
||||
return pl, d
|
||||
|
||||
def constraint(
|
||||
self, item: Item, handle: Handle, glue_item: Item
|
||||
) -> Union[Constraint, MultiConstraint]:
|
||||
def constraint(self, item: Item, handle: Handle, glue_item: Item) -> Constraint:
|
||||
"""Create connection line constraint between item's handle and the
|
||||
port."""
|
||||
start = MatrixProjection(self.start, glue_item.matrix_i2c)
|
||||
|
@ -31,7 +31,7 @@ import math
|
||||
from typing import Dict, Optional, Tuple
|
||||
|
||||
from gaphas.position import Position
|
||||
from gaphas.solver import Constraint, Variable
|
||||
from gaphas.solver import BaseConstraint, Constraint, Variable
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -102,7 +102,7 @@ def _update(variable, value):
|
||||
variable.value = value
|
||||
|
||||
|
||||
class EqualsConstraint(Constraint):
|
||||
class EqualsConstraint(BaseConstraint):
|
||||
"""Constraint, which ensures that two arguments ``a`` and ``b`` are equal:
|
||||
|
||||
a + delta = b
|
||||
@ -140,7 +140,7 @@ class EqualsConstraint(Constraint):
|
||||
)
|
||||
|
||||
|
||||
class CenterConstraint(Constraint):
|
||||
class CenterConstraint(BaseConstraint):
|
||||
"""Simple Constraint, takes three arguments: 'a', 'b' and center. When
|
||||
solved, the constraint ensures 'center' is located in the middle of 'a' and
|
||||
'b'.
|
||||
@ -174,7 +174,7 @@ class CenterConstraint(Constraint):
|
||||
_update(self.center, v)
|
||||
|
||||
|
||||
class LessThanConstraint(Constraint):
|
||||
class LessThanConstraint(BaseConstraint):
|
||||
"""Ensure ``smaller`` is less than ``bigger``. The variable that is passed
|
||||
as to-be-solved is left alone (cause it is the variable that has not been
|
||||
moved lately). Instead the other variable is solved.
|
||||
@ -219,7 +219,7 @@ class LessThanConstraint(Constraint):
|
||||
ITERLIMIT = 1000 # iteration limit
|
||||
|
||||
|
||||
class EquationConstraint(Constraint):
|
||||
class EquationConstraint(BaseConstraint):
|
||||
"""Equation solver using attributes and introspection.
|
||||
|
||||
Takes a function, named arg value (opt.) and returns a Constraint
|
||||
@ -349,7 +349,7 @@ class EquationConstraint(Constraint):
|
||||
return x1
|
||||
|
||||
|
||||
class BalanceConstraint(Constraint):
|
||||
class BalanceConstraint(BaseConstraint):
|
||||
"""Ensure that a variable ``v`` is between values specified by ``band`` and
|
||||
in distance proportional from ``band[0]``.
|
||||
|
||||
@ -398,7 +398,7 @@ class BalanceConstraint(Constraint):
|
||||
_update(var, value)
|
||||
|
||||
|
||||
class LineConstraint(Constraint):
|
||||
class LineConstraint(BaseConstraint):
|
||||
"""Ensure a point is kept on a line.
|
||||
|
||||
Attributes:
|
||||
@ -476,7 +476,7 @@ class LineConstraint(Constraint):
|
||||
_update(py, y)
|
||||
|
||||
|
||||
class PositionConstraint(Constraint):
|
||||
class PositionConstraint(BaseConstraint):
|
||||
"""Ensure that point is always in origin position.
|
||||
|
||||
Attributes:
|
||||
@ -498,7 +498,7 @@ class PositionConstraint(Constraint):
|
||||
_update(self._point[1], y)
|
||||
|
||||
|
||||
class LineAlignConstraint(Constraint):
|
||||
class LineAlignConstraint(BaseConstraint):
|
||||
"""Ensure a point is kept on a line in position specified by align and
|
||||
padding information.
|
||||
|
||||
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
from typing import SupportsFloat, Tuple, Union
|
||||
|
||||
from gaphas.matrix import Matrix
|
||||
from gaphas.solver import NORMAL, Constraint, Variable
|
||||
from gaphas.solver import NORMAL, BaseConstraint, Variable
|
||||
from gaphas.types import SupportsFloatPos, TypedProperty
|
||||
|
||||
|
||||
@ -76,7 +76,7 @@ class Position:
|
||||
return self[0] < other[0] and self[1] < other[1]
|
||||
|
||||
|
||||
class MatrixProjection(Constraint):
|
||||
class MatrixProjection(BaseConstraint):
|
||||
def __init__(self, pos: Position, matrix: Matrix):
|
||||
proj_pos = Position(0, 0, pos.strength)
|
||||
super().__init__(proj_pos.x, proj_pos.y, pos.x, pos.y)
|
||||
|
@ -1,4 +1,4 @@
|
||||
from gaphas.solver.constraint import Constraint, MultiConstraint
|
||||
from gaphas.solver.constraint import BaseConstraint, Constraint, MultiConstraint
|
||||
from gaphas.solver.solver import JuggleError, Solver
|
||||
from gaphas.solver.variable import (
|
||||
NORMAL,
|
||||
|
@ -2,10 +2,23 @@ from __future__ import annotations
|
||||
|
||||
from typing import Callable, Set
|
||||
|
||||
from typing_extensions import Protocol
|
||||
|
||||
from gaphas.solver.variable import Variable
|
||||
|
||||
|
||||
class Constraint:
|
||||
class Constraint(Protocol):
|
||||
def add_handler(self, handler: Callable[[Constraint], None]) -> None:
|
||||
...
|
||||
|
||||
def remove_handler(self, handler: Callable[[Constraint], None]) -> None:
|
||||
...
|
||||
|
||||
def solve(self) -> None:
|
||||
...
|
||||
|
||||
|
||||
class BaseConstraint:
|
||||
"""Constraint base class.
|
||||
|
||||
- variables - list of all variables
|
||||
|
@ -32,9 +32,9 @@ every constraint is being asked to solve itself
|
||||
(`constraint.Constraint.solve_for()` method) changing appropriate
|
||||
variables to make the constraint valid again.
|
||||
"""
|
||||
from typing import Collection, List, Set, Union
|
||||
from typing import Collection, List, Set
|
||||
|
||||
from gaphas.solver.constraint import Constraint, MultiConstraint
|
||||
from gaphas.solver.constraint import Constraint
|
||||
from gaphas.state import observed, reversible_pair
|
||||
|
||||
|
||||
@ -46,18 +46,16 @@ class Solver:
|
||||
|
||||
def __init__(self) -> None:
|
||||
# a dict of constraint -> name/variable mappings
|
||||
self._constraints: Set[Union[Constraint, MultiConstraint]] = set()
|
||||
self._marked_cons: List[Union[Constraint, MultiConstraint]] = []
|
||||
self._constraints: Set[Constraint] = set()
|
||||
self._marked_cons: List[Constraint] = []
|
||||
self._solving = False
|
||||
|
||||
@property
|
||||
def constraints(self) -> Collection[Union[Constraint, MultiConstraint]]:
|
||||
def constraints(self) -> Collection[Constraint]:
|
||||
return self._constraints
|
||||
|
||||
@observed
|
||||
def add_constraint(
|
||||
self, constraint: Union[Constraint, MultiConstraint]
|
||||
) -> Union[Constraint, MultiConstraint]:
|
||||
def add_constraint(self, constraint: Constraint) -> Constraint:
|
||||
"""Add a constraint. The actual constraint is returned, so the
|
||||
constraint can be removed later on.
|
||||
|
||||
@ -84,7 +82,7 @@ class Solver:
|
||||
return constraint
|
||||
|
||||
@observed
|
||||
def remove_constraint(self, constraint: Union[Constraint, MultiConstraint]) -> None:
|
||||
def remove_constraint(self, constraint: Constraint) -> None:
|
||||
"""Remove a constraint from the solver.
|
||||
|
||||
>>> from gaphas.constraint import EquationConstraint
|
||||
|
@ -1,6 +1,6 @@
|
||||
import pytest
|
||||
|
||||
from gaphas.solver import Constraint, MultiConstraint, Variable
|
||||
from gaphas.solver import BaseConstraint, MultiConstraint, Variable
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@ -16,7 +16,7 @@ def handler():
|
||||
|
||||
def test_constraint_propagates_variable_changed(handler):
|
||||
v = Variable()
|
||||
c = Constraint(v)
|
||||
c = BaseConstraint(v)
|
||||
c.add_handler(handler)
|
||||
|
||||
v.value = 3
|
||||
@ -26,7 +26,7 @@ def test_constraint_propagates_variable_changed(handler):
|
||||
|
||||
def test_multi_constraint(handler):
|
||||
v = Variable()
|
||||
c = Constraint(v)
|
||||
c = BaseConstraint(v)
|
||||
m = MultiConstraint(c)
|
||||
m.add_handler(handler)
|
||||
|
||||
@ -37,7 +37,7 @@ def test_multi_constraint(handler):
|
||||
|
||||
def test_default_constraint_can_not_solve():
|
||||
v = Variable()
|
||||
c = Constraint(v)
|
||||
c = BaseConstraint(v)
|
||||
|
||||
with pytest.raises(NotImplementedError):
|
||||
c.solve()
|
||||
@ -45,7 +45,7 @@ def test_default_constraint_can_not_solve():
|
||||
|
||||
def test_constraint_handlers_are_set_just_in_time():
|
||||
v = Variable()
|
||||
c = Constraint(v)
|
||||
c = BaseConstraint(v)
|
||||
|
||||
def handler(c):
|
||||
pass
|
||||
|
Loading…
x
Reference in New Issue
Block a user