def create_orthogonal_constraints(handles: Sequence[Handle], horizontal: bool) -> Iterable[Constraint]: rest = 1 if horizontal else 0 for pos, (h0, h1) in enumerate(zip(handles, handles[1:])): p0 = h0.pos p1 = h1.pos if pos % 2 == rest: yield EqualsConstraint(a=p0.x, b=p1.x) else: yield EqualsConstraint(a=p0.y, b=p1.y)
def test_juggle_error_is_raised_when_constraints_can_not_be_resolved(): solver = Solver() a = Variable() b = Variable() c = Variable(40, strength=REQUIRED) d = Variable(30, strength=REQUIRED) solver.add_constraint(EqualsConstraint(a, b)) solver.add_constraint(EqualsConstraint(a, c)) solver.add_constraint(EqualsConstraint(b, d)) with pytest.raises(JuggleError): solver.solve()
def test_reconnect_item(connections): i = item.Line(connections) ii = item.Line(connections) cons1 = EqualsConstraint(i.handles()[0].pos.x, i.handles()[0].pos.x) cons2 = EqualsConstraint(i.handles()[0].pos.y, i.handles()[0].pos.y) connections.connect_item(i, i.handles()[0], ii, ii.ports()[0], cons1) assert connections.get_connection(i.handles()[0]).constraint is cons1 assert cons1 in connections.solver.constraints connections.reconnect_item(i, i.handles()[0], constraint=cons2) assert connections.get_connection(i.handles()[0]).constraint is cons2 assert cons1 not in connections.solver.constraints assert cons2 in connections.solver.constraints
def test_remove_item_constraint_when_item_is_disconnected(connections): i = item.Line(connections) c1 = EqualsConstraint(i.handles()[0].pos.x, i.handles()[0].pos.x) connections.add_constraint(i, c1) connections.disconnect_item(i) assert list(connections.get_connections(item=i)) == []
def setup_canvas(self): super(LifelineItem, self).setup_canvas() top = self.lifetime.top bottom = self.lifetime.bottom # create constraints to: # - keep bottom handle below top handle # - keep top and bottom handle in the middle of the head c1 = CenterConstraint(self._handles[SW].pos.x, self._handles[SE].pos.x, bottom.pos.x) c2 = EqualsConstraint(top.pos.x, bottom.pos.x, delta=0.0) c3 = EqualsConstraint(self._handles[SW].pos.y, top.pos.y, delta=0.0) self.lifetime._c_min_length = LessThanConstraint(top.pos.y, bottom.pos.y, delta=LifetimeItem.MIN_LENGTH) self.__constraints = (c1, c2, c3, self.lifetime._c_min_length) list(map(self.canvas.solver.add_constraint, self.__constraints))
def setup_canvas(self): super().setup_canvas() h1, h2 = self._handles cadd = self.canvas.solver.add_constraint c1 = EqualsConstraint(a=h1.pos.x, b=h2.pos.x) c2 = LessThanConstraint(smaller=h1.pos.y, bigger=h2.pos.y, delta=30) self.__constraints = (cadd(c1), cadd(c2)) list(map(self.canvas.solver.add_constraint, self.__constraints))
def setup_constraints(self): top = self.lifetime.top bottom = self.lifetime.bottom # create constraints to: # - keep bottom handle below top handle # - keep top and bottom handle in the middle of the head c1 = CenterConstraint(self._handles[SW].pos.x, self._handles[SE].pos.x, bottom.pos.x) c2 = EqualsConstraint(top.pos.x, bottom.pos.x, delta=0.0) c3 = EqualsConstraint(self._handles[SW].pos.y, top.pos.y, delta=0.0) self.lifetime._c_min_length = LessThanConstraint( top.pos.y, bottom.pos.y, delta=LifetimeItem.MIN_LENGTH) for c in [c1, c2, c3, self.lifetime._c_min_length]: self._connections.add_constraint(self, c)
def test_add_item_constraint(connections): i = item.Line(connections) c1 = EqualsConstraint(i.handles()[0].pos.x, i.handles()[0].pos.x) connections.add_constraint(i, c1) cinfo = next(connections.get_connections(item=i)) assert cinfo.item is i assert cinfo.constraint is c1
def test_notify_on_constraint_solved(connections): events = [] def on_notify(cinfo): events.append(cinfo) i = item.Line(connections) c = EqualsConstraint(i.handles()[0].pos.x, i.handles()[0].pos.x) connections.add_constraint(i, c) connections.add_handler(on_notify) connections.solve() assert events assert events[0].constraint is c
def test_min_size(self): """Test minimal size constraint""" solver = Solver() v1 = Variable(0) v2 = Variable(10) v3 = Variable(10) c1 = EqualsConstraint(a=v2, b=v3) c2 = LessThanConstraint(smaller=v1, bigger=v3, delta=10) solver.add_constraint(c1) solver.add_constraint(c2) # check everyting is ok on start solver.solve() self.assertEquals(0, v1) self.assertEquals(10, v2) self.assertEquals(10, v3) # change v1 to 2, after solve it should be 0 again due to LT # constraint v1.value = 2 solver.solve() self.assertEquals(0, v1) self.assertEquals(10, v2) self.assertEquals(10, v3) # change v3 to 20, after solve v2 will follow thanks to EQ # constraint v3.value = 20 solver.solve() self.assertEquals(0, v1) self.assertEquals(20, v2) self.assertEquals(20, v3) # change v3 to 0, after solve it shoul be 10 due to LT.delta = 10, # v2 should also be 10 due to EQ constraint v3.value = 0 solver.solve() self.assertEquals(0, v1) self.assertEquals(10, v2) self.assertEquals(10, v3)
def test_min_size(solv): """Test minimal size constraint. """ v1 = Variable(0) v2 = Variable(10) v3 = Variable(10) c1 = EqualsConstraint(a=v2, b=v3) c2 = LessThanConstraint(smaller=v1, bigger=v3, delta=10) solv.solver.add_constraint(c1) solv.solver.add_constraint(c2) # Check everything is ok on start solv.solver.solve() assert 0 == v1 assert 10 == v2 assert 10 == v3 # Change v1 to 2, after solve it should be 0 again due to LT constraint v1.value = 2 solv.solver.solve() assert 0 == v1 assert 10 == v2 assert 10 == v3 # Change v3 to 20, after solve v2 will follow thanks to EQ constraint v3.value = 20 solv.solver.solve() assert 0 == v1 assert 20 == v2 assert 20 == v3 # Change v3 to 0, after solve it should be 10 due to LT.delta = 10, v2 # should also be 10 due to EQ constraint v3.value = 0 solv.solver.solve() assert 0 == v1 assert 10 == v2 assert 10 == v3
def test_notify_for_nested_constraint(): events = [] solver = Solver() a = Variable() b = Variable() nested = EqualsConstraint(a, b) multi = MultiConstraint(nested) solver.add_constraint(multi) solver.solve() def handler(constraint): events.append(constraint) solver.add_handler(handler) a.value = 10 solver.solve() assert multi in events assert nested not in events
def constraint( self, horizontal=None, vertical=None, left_of=None, above=None, line=None, delta=0.0, align=None, ): """ Utility (factory) method to create item's internal constraint between two positions or between a position and a line. Position is a tuple of coordinates, i.e. ``(2, 4)``. Line is a tuple of positions, i.e. ``((2, 3), (4, 2))``. This method shall not be used to create constraints between two different items. Created constraint is returned. :Parameters: horizontal=(p1, p2) Keep positions ``p1`` and ``p2`` aligned horizontally. vertical=(p1, p2) Keep positions ``p1`` and ``p2`` aligned vertically. left_of=(p1, p2) Keep position ``p1`` on the left side of position ``p2``. above=(p1, p2) Keep position ``p1`` above position ``p2``. line=(p, l) Keep position ``p`` on line ``l``. """ cc = None # created constraint if horizontal: p1, p2 = horizontal cc = EqualsConstraint(p1[1], p2[1], delta) elif vertical: p1, p2 = vertical cc = EqualsConstraint(p1[0], p2[0], delta) elif left_of: p1, p2 = left_of cc = LessThanConstraint(p1[0], p2[0], delta) elif above: p1, p2 = above cc = LessThanConstraint(p1[1], p2[1], delta) elif line: pos, l = line if align is None: cc = LineConstraint(line=l, point=pos) else: cc = LineAlignConstraint(line=l, point=pos, align=align, delta=delta) else: raise ValueError("Constraint incorrectly specified") assert cc is not None self._constraints.append(cc) return cc