예제 #1
0
    def test_delete1(self):
        solver = SimplexSolver()
        x = Variable('x')
        cbl = Constraint(x, Constraint.EQ, 100, WEAK)
        solver.add_constraint(cbl)

        c10 = Constraint(x, Constraint.LEQ, 10)
        c20 = Constraint(x, Constraint.LEQ, 20)
        solver.add_constraint(c10)
        solver.add_constraint(c20)
        self.assertAlmostEqual(x.value, 10)

        solver.remove_constraint(c10)
        self.assertAlmostEqual(x.value, 20)

        solver.remove_constraint(c20)
        self.assertAlmostEqual(x.value, 100)

        c10again = Constraint(x, Constraint.LEQ, 10)
        solver.add_constraint(c10)
        solver.add_constraint(c10again)
        self.assertAlmostEqual(x.value, 10)

        solver.remove_constraint(c10)
        self.assertAlmostEqual(x.value, 10)

        solver.remove_constraint(c10again)
        self.assertAlmostEqual(x.value, 100)
예제 #2
0
    def test_delete1(self):
        solver = SimplexSolver()
        x = Variable('x')
        cbl = Constraint(x, Constraint.EQ, 100, WEAK)
        solver.add_constraint(cbl)

        c10 = Constraint(x, Constraint.LEQ, 10)
        c20 = Constraint(x, Constraint.LEQ, 20)
        solver.add_constraint(c10)
        solver.add_constraint(c20)
        self.assertAlmostEqual(x.value, 10)

        solver.remove_constraint(c10)
        self.assertAlmostEqual(x.value, 20)

        solver.remove_constraint(c20)
        self.assertAlmostEqual(x.value, 100)

        c10again = Constraint(x, Constraint.LEQ, 10)
        solver.add_constraint(c10)
        solver.add_constraint(c10again)
        self.assertAlmostEqual(x.value, 10)

        solver.remove_constraint(c10)
        self.assertAlmostEqual(x.value, 10)

        solver.remove_constraint(c10again)
        self.assertAlmostEqual(x.value, 100)
예제 #3
0
    def test_delete2(self):
        solver = SimplexSolver()
        x = Variable('x')
        y = Variable('y')

        solver.add_constraint(Constraint(x, Constraint.EQ, 100, WEAK))
        solver.add_constraint(Constraint(y, Constraint.EQ, 120, STRONG))
        c10 = Constraint(x, Constraint.LEQ, 10)
        c20 = Constraint(x, Constraint.LEQ, 20)
        solver.add_constraint(c10)
        solver.add_constraint(c20)
        self.assertAlmostEqual(x.value, 10)
        self.assertAlmostEqual(y.value, 120)

        solver.remove_constraint(c10)
        self.assertAlmostEqual(x.value, 20)
        self.assertAlmostEqual(y.value, 120)

        cxy = Constraint(x * 2, Constraint.EQ, y)
        solver.add_constraint(cxy)
        self.assertAlmostEqual(x.value, 20)
        self.assertAlmostEqual(y.value, 40)

        solver.remove_constraint(c20)
        self.assertAlmostEqual(x.value, 60)
        self.assertAlmostEqual(y.value, 120)

        solver.remove_constraint(cxy)
        self.assertAlmostEqual(x.value, 100)
        self.assertAlmostEqual(y.value, 120)
예제 #4
0
    def test_delete2(self):
        solver = SimplexSolver()
        x = Variable('x')
        y = Variable('y')

        solver.add_constraint(Constraint(x, Constraint.EQ, 100, WEAK))
        solver.add_constraint(Constraint(y, Constraint.EQ, 120, STRONG))
        c10 = Constraint(x, Constraint.LEQ, 10)
        c20 = Constraint(x, Constraint.LEQ, 20)
        solver.add_constraint(c10)
        solver.add_constraint(c20)
        self.assertAlmostEqual(x.value, 10)
        self.assertAlmostEqual(y.value, 120)

        solver.remove_constraint(c10)
        self.assertAlmostEqual(x.value, 20)
        self.assertAlmostEqual(y.value, 120)

        cxy = Constraint(x * 2, Constraint.EQ, y)
        solver.add_constraint(cxy)
        self.assertAlmostEqual(x.value, 20)
        self.assertAlmostEqual(y.value, 40)

        solver.remove_constraint(c20)
        self.assertAlmostEqual(x.value, 60)
        self.assertAlmostEqual(y.value, 120)

        solver.remove_constraint(cxy)
        self.assertAlmostEqual(x.value, 100)
        self.assertAlmostEqual(y.value, 120)
예제 #5
0
class TTSolver:

  def initialSetup(self, layer):
    self.solver = SimplexSolver()
    self.nodehash = {}
    for p in layer.paths:
      for n in p.nodes:
        nid = n.hash()
        self.nodehash[nid] = {
          "node": n,
          "xvar": Variable("x"+str(nid), n.position.x),
          "yvar": Variable("y"+str(nid), n.position.y),
          "affected": set()
        }
    self.setConstraintsFromHints(layer)

  def yvar(self,n):
    if not n:
      raise ValueError
    if not (n.hash() in self.nodehash):
      raise KeyError(n)
    return self.nodehash[n.hash()]["yvar"]

  def xvar(self,n):
    if not n:
      raise ValueError
    if not (n.hash() in self.nodehash):
      raise KeyError(n)
    return self.nodehash[n.hash()]["xvar"]

  def setConstraintsFromHints(self, layer):
    c = []
    for h in layer.hints:
      if h.type == TAG:
        try:
          if h.options() == DIAGONAL or (h.options() < 8 and not h.horizontal):
            v1 = self.yvar(h.originNode)
            v2 = self.yvar(h.targetNode)
            yValue = v1.value - v2.value
            ystem = v1 - v2
            c.append(ystem == yValue)

          if h.options() == DIAGONAL or (h.options() < 8 and h.horizontal):
            v1 = self.xvar(h.originNode)
            v2 = self.xvar(h.targetNode)
            xValue = v1.value - v2.value
            xstem = v1 - v2
            c.append(xstem == xValue)

          if h.options() == PROPORTIONAL_TRIPLE:
            if h.horizontal:
              v1 = self.xvar(h.originNode)
              v2 = self.xvar(h.targetNode)
              v3 = self.xvar(h.otherNode1)
              proportion = safediv(h.targetNode.position.x - h.originNode.position.x , h.otherNode1.position.x - h.targetNode.position.x)
            else:
              v1 = self.yvar(h.originNode)
              v2 = self.yvar(h.targetNode)
              v3 = self.yvar(h.otherNode1)
              proportion = safediv(h.targetNode.position.y - h.originNode.position.y, h.otherNode1.position.y - h.targetNode.position.y)
            d1 = v2 - v1
            d2 = v3 - v2
            c.append(d2 * proportion == d1)

          if h.options() == PROPORTIONAL_QUAD:
            on2 = h.valueForKey_("otherNode2") # Glyphs bug
            if h.horizontal:
              v1 = self.xvar(h.originNode)
              v2 = self.xvar(h.targetNode)
              v3 = self.xvar(h.otherNode1)
              v4 = self.xvar(on2)
              proportion = safediv(h.targetNode.position.x - h.originNode.position.x, on2.position.x - h.otherNode1.position.x)
            else:
              v1 = self.yvar(h.originNode)
              v2 = self.yvar(h.targetNode)
              v3 = self.yvar(h.otherNode1)
              v4 = self.yvar(on2)
              proportion = safediv(h.targetNode.position.y - h.originNode.position.y, on2.position.y - h.otherNode1.position.y)
            d1 = v2 - v1
            d2 = v4 - v3
            # print(d1,d2,proportion)
            c.append(d2 * proportion == d1)
        except ValueError:
          print("I found a busted constraint. It'll get cleaned up soon.")
    for cs in c:
      self.solver.add_constraint(cs)

  def _diagonalConstraints(self, c, n1,n2):
    v1 = self.xvar(n1)
    v2 = self.xvar(n2)
    xValue = v1.value - v2.value
    xstem = v1 - v2
    v1 = self.yvar(n1)
    v2 = self.yvar(n2)
    yValue = v1.value - v2.value
    ystem = v1 - v2
    c.append(xstem == xValue)
    c.append(ystem == yValue)

  def _makeEditable(self,node):
    n = self.nodehash[node.hash()]
    self.solver.add_edit_var(n["xvar"])
    self.solver.add_edit_var(n["yvar"])

  def _suggest(self,node):
    n = self.nodehash[node.hash()]
    # print("Suggesting ",n["node"].position.x,n["node"].position.y)
    self.solver.suggest_value(n["xvar"], n["node"].position.x)
    self.solver.suggest_value(n["yvar"], n["node"].position.y)

  def setStayFromNodes(self, layer):
    nodes = filter(lambda x:x.hash() in self.nodehash, layer.selection)
    if len(nodes) < 1:
      return

    temporaryConstraints = []
    c = []
    for p in layer.paths:
      for n in p.nodes:
        if n.type != GSOFFCURVE:
          # Constrain left handle and this node
          if n.prevNode.type == GSOFFCURVE and not n.prevNode.selected:
              self._diagonalConstraints(c, n, n.prevNode)
          if n.nextNode.type == GSOFFCURVE and not n.nextNode.selected:
            self._diagonalConstraints(c, n, n.nextNode)

    for cs in c:
      temporaryConstraints.append(self.solver.add_constraint(cs, strength=WEAK))

    # print("Putting stuff into solver")
    for n in nodes:
      self._makeEditable(n)
      if n.type != GSOFFCURVE:
        if n.nextNode.type == GSOFFCURVE:
          self._makeEditable(n.nextNode)
        if n.prevNode.type == GSOFFCURVE:
          self._makeEditable(n.prevNode)
      else:
        if n.nextNode.type == CURVE and n.nextNode.smooth:
          self._makeEditable(n.nextNode)
          self._makeEditable(n.nextNode.nextNode)
        elif n.prevNode.type == CURVE and n.prevNode.smooth:
          self._makeEditable(n.prevNode)
          self._makeEditable(n.prevNode.prevNode)

    with self.solver.edit():
      for n in nodes:
        self._suggest(n)
        if n.type != GSOFFCURVE:
          if n.nextNode.type == GSOFFCURVE:
            self._suggest(n.nextNode)
          if n.prevNode.type == GSOFFCURVE:
            self._suggest(n.prevNode)
        else:
          if n.nextNode.type == CURVE and n.nextNode.smooth:
            self._suggest(n.nextNode)
            self._suggest(n.nextNode.nextNode)
          elif n.prevNode.type == CURVE and n.prevNode.smooth:
            self._suggest(n.prevNode)
            self._suggest(n.prevNode.prevNode)

    for j in nodes:
      n = self.nodehash[j.hash()]
      # print("Got: ",n["xvar"],n["yvar"])

    for c in temporaryConstraints:
      self.solver.remove_constraint(c)

  def updateGlyphWithSolution(self):
    for i in self.nodehash:
      n = self.nodehash[i]
      # print(n["node"], "->", n["xvar"].value, n["yvar"].value)
      n["node"].position = (n["xvar"].value, n["yvar"].value)

  def updateSolverFromGlyph(self):
    for i in self.nodehash:
      n = self.nodehash[i]
      n["xvar"].value = n["node"].position.x
      n["yvar"].value = n["node"].position.y
      n["xstay"] = self.solver.add_stay(n["xvar"], strength=WEAK)
      n["ystay"] = self.solver.add_stay(n["yvar"], strength=WEAK)
      self.solver.add_edit_var(n["xvar"])
      self.solver.add_edit_var(n["yvar"])

    if len(self.nodehash) > 0:
      with self.solver.edit():
        for i in self.nodehash:
          n = self.nodehash[i]
          self.solver.suggest_value(n["xvar"], n["node"].position.x)
          self.solver.suggest_value(n["yvar"], n["node"].position.y)
예제 #6
0
    def test_buttons(self):
        "A test of a horizontal layout of two buttons on a screen."

        class Button(object):
            def __init__(self, identifier):
                self.left = Variable('left' + identifier, 0)
                self.width = Variable('width' + identifier, 0)

            def __repr__(self):
                return u'(%s:%s)' % (self.left.value, self.width.value)

        solver = SimplexSolver()

        b1 = Button('b1')
        b2 = Button('b2')
        left_limit = Variable('left', 0)
        right_limit = Variable('width', 0)

        left_limit.value = 0
        solver.add_stay(left_limit, REQUIRED)
        stay = solver.add_stay(right_limit, WEAK)

        # The two buttons are the same width
        solver.add_constraint(b1.width == b2.width)

        # b1 starts 50 from the left margin.
        solver.add_constraint(b1.left == left_limit + 50)

        # b2 ends 50 from the right margin
        solver.add_constraint(left_limit + right_limit == b2.left + b2.width +
                              50)

        # b2 starts at least 100 from the end of b1
        solver.add_constraint(b2.left >= (b1.left + b1.width + 100))

        # b1 has a minimum width of 87
        solver.add_constraint(b1.width >= 87)

        # b1's preferred width is 87
        solver.add_constraint(b1.width == 87, STRONG)

        # b2's minimum width is 113
        solver.add_constraint(b2.width >= 113)

        # b2's preferred width is 113
        solver.add_constraint(b2.width == 113, STRONG)

        # Without imposign a stay on the right, right_limit will be the minimum width for the layout
        self.assertAlmostEqual(b1.left.value, 50.0)
        self.assertAlmostEqual(b1.width.value, 113.0)
        self.assertAlmostEqual(b2.left.value, 263.0)
        self.assertAlmostEqual(b2.width.value, 113.0)
        self.assertAlmostEqual(right_limit.value, 426.0)

        # The window is 500 pixels wide.
        right_limit.value = 500
        stay = solver.add_stay(right_limit, REQUIRED)
        self.assertAlmostEqual(b1.left.value, 50.0)
        self.assertAlmostEqual(b1.width.value, 113.0)
        self.assertAlmostEqual(b2.left.value, 337.0)
        self.assertAlmostEqual(b2.width.value, 113.0)
        self.assertAlmostEqual(right_limit.value, 500.0)
        solver.remove_constraint(stay)

        # Expand to 700 pixels
        right_limit.value = 700
        stay = solver.add_stay(right_limit, REQUIRED)
        self.assertAlmostEqual(b1.left.value, 50.0)
        self.assertAlmostEqual(b1.width.value, 113.0)
        self.assertAlmostEqual(b2.left.value, 537.0)
        self.assertAlmostEqual(b2.width.value, 113.0)
        self.assertAlmostEqual(right_limit.value, 700.0)
        solver.remove_constraint(stay)

        # Contract to 600
        right_limit.value = 600
        stay = solver.add_stay(right_limit, REQUIRED)
        self.assertAlmostEqual(b1.left.value, 50.0)
        self.assertAlmostEqual(b1.width.value, 113.0)
        self.assertAlmostEqual(b2.left.value, 437.0)
        self.assertAlmostEqual(b2.width.value, 113.0)
        self.assertAlmostEqual(right_limit.value, 600.0)
        solver.remove_constraint(stay)
예제 #7
0
    def test_buttons(self):
        "A test of a horizontal layout of two buttons on a screen."

        class Button(object):
            def __init__(self, identifier):
                self.left = Variable('left' + identifier, 0)
                self.width = Variable('width' + identifier, 0)

            def __repr__(self):
                return u'(%s:%s)' % (self.left.value, self.width.value)

        solver = SimplexSolver()

        b1 = Button('b1')
        b2 = Button('b2')
        left_limit = Variable('left', 0)
        right_limit = Variable('width', 0)

        left_limit.value = 0
        solver.add_stay(left_limit, REQUIRED)
        stay = solver.add_stay(right_limit, WEAK)

        # The two buttons are the same width
        solver.add_constraint(b1.width == b2.width)

        # b1 starts 50 from the left margin.
        solver.add_constraint(b1.left == left_limit + 50)

        # b2 ends 50 from the right margin
        solver.add_constraint(left_limit + right_limit == b2.left + b2.width + 50)

        # b2 starts at least 100 from the end of b1
        solver.add_constraint(b2.left >= (b1.left + b1.width + 100))

        # b1 has a minimum width of 87
        solver.add_constraint(b1.width >= 87)

        # b1's preferred width is 87
        solver.add_constraint(b1.width == 87, STRONG)

        # b2's minimum width is 113
        solver.add_constraint(b2.width >= 113)

        # b2's preferred width is 113
        solver.add_constraint(b2.width == 113, STRONG)

        # Without imposign a stay on the right, right_limit will be the minimum width for the layout
        self.assertAlmostEqual(b1.left.value, 50.0)
        self.assertAlmostEqual(b1.width.value, 113.0)
        self.assertAlmostEqual(b2.left.value, 263.0)
        self.assertAlmostEqual(b2.width.value, 113.0)
        self.assertAlmostEqual(right_limit.value, 426.0)

        # The window is 500 pixels wide.
        right_limit.value = 500
        stay = solver.add_stay(right_limit, REQUIRED)
        self.assertAlmostEqual(b1.left.value, 50.0)
        self.assertAlmostEqual(b1.width.value, 113.0)
        self.assertAlmostEqual(b2.left.value, 337.0)
        self.assertAlmostEqual(b2.width.value, 113.0)
        self.assertAlmostEqual(right_limit.value, 500.0)
        solver.remove_constraint(stay)

        # Expand to 700 pixels
        right_limit.value = 700
        stay = solver.add_stay(right_limit, REQUIRED)
        self.assertAlmostEqual(b1.left.value, 50.0)
        self.assertAlmostEqual(b1.width.value, 113.0)
        self.assertAlmostEqual(b2.left.value, 537.0)
        self.assertAlmostEqual(b2.width.value, 113.0)
        self.assertAlmostEqual(right_limit.value, 700.0)
        solver.remove_constraint(stay)

        # Contract to 600
        right_limit.value = 600
        stay = solver.add_stay(right_limit, REQUIRED)
        self.assertAlmostEqual(b1.left.value, 50.0)
        self.assertAlmostEqual(b1.width.value, 113.0)
        self.assertAlmostEqual(b2.left.value, 437.0)
        self.assertAlmostEqual(b2.width.value, 113.0)
        self.assertAlmostEqual(right_limit.value, 600.0)
        solver.remove_constraint(stay)