Exemple #1
0
    def test_multiedit1(self):
        # This test stresses the edit session stack. begin_edit() starts a new
        # "edit variable group" and "end_edit" closes it, leaving only the
        # previously opened edit variables still active.
        x = Variable('x')
        y = Variable('y')
        w = Variable('w')
        h = Variable('h')
        solver = SimplexSolver()

        # Add some stays
        solver.add_stay(x)
        solver.add_stay(y)
        solver.add_stay(w)
        solver.add_stay(h)

        # start an editing session
        solver.add_edit_var(x)
        solver.add_edit_var(y)

        with solver.edit():
            solver.suggest_value(x, 10)
            solver.suggest_value(y, 20)

            # Force the system to resolve.
            solver.resolve()

            self.assertAlmostEqual(x.value, 10)
            self.assertAlmostEqual(y.value, 20)
            self.assertAlmostEqual(w.value, 0)
            self.assertAlmostEqual(h.value, 0)

            # Open a second set of variables for editing
            solver.add_edit_var(w)
            solver.add_edit_var(h)

            with solver.edit():
                solver.suggest_value(w, 30)
                solver.suggest_value(h, 40)

            # Close the second set...
            self.assertAlmostEqual(x.value, 10)
            self.assertAlmostEqual(y.value, 20)
            self.assertAlmostEqual(w.value, 30)
            self.assertAlmostEqual(h.value, 40)

            # Now make sure the first set can still be edited
            solver.suggest_value(x, 50)
            solver.suggest_value(y, 60)

        self.assertAlmostEqual(x.value, 50)
        self.assertAlmostEqual(y.value, 60)
        self.assertAlmostEqual(w.value, 30)
        self.assertAlmostEqual(h.value, 40)
    def test_multiedit1(self):
        # This test stresses the edit session stack. begin_edit() starts a new
        # "edit variable group" and "end_edit" closes it, leaving only the
        # previously opened edit variables still active.
        x = Variable('x')
        y = Variable('y')
        w = Variable('w')
        h = Variable('h')
        solver = SimplexSolver()

        # Add some stays
        solver.add_stay(x)
        solver.add_stay(y)
        solver.add_stay(w)
        solver.add_stay(h)

        # start an editing session
        solver.add_edit_var(x)
        solver.add_edit_var(y)

        with solver.edit():
            solver.suggest_value(x, 10)
            solver.suggest_value(y, 20)

            # Force the system to resolve.
            solver.resolve()

            self.assertAlmostEqual(x.value, 10)
            self.assertAlmostEqual(y.value, 20)
            self.assertAlmostEqual(w.value, 0)
            self.assertAlmostEqual(h.value, 0)

            # Open a second set of variables for editing
            solver.add_edit_var(w)
            solver.add_edit_var(h)

            with solver.edit():
                solver.suggest_value(w, 30)
                solver.suggest_value(h, 40)

            # Close the second set...
            self.assertAlmostEqual(x.value, 10)
            self.assertAlmostEqual(y.value, 20)
            self.assertAlmostEqual(w.value, 30)
            self.assertAlmostEqual(h.value, 40)

            # Now make sure the first set can still be edited
            solver.suggest_value(x, 50)
            solver.suggest_value(y, 60)

        self.assertAlmostEqual(x.value, 50)
        self.assertAlmostEqual(y.value, 60)
        self.assertAlmostEqual(w.value, 30)
        self.assertAlmostEqual(h.value, 40)
    def test_multiedit3(self):
        MIN = 100
        MAX = 500

        width = Variable('width')
        height = Variable('height')
        top = Variable('top')
        bottom = Variable('bottom')
        left = Variable('left')
        right = Variable('right')

        solver = SimplexSolver()

        iw = Variable('window_innerWidth', random.randrange(MIN, MAX))
        ih = Variable('window_innerHeight', random.randrange(MIN, MAX))

        solver.add_constraint(Constraint(width, Constraint.EQ, iw, strength=STRONG, weight=0.0))
        solver.add_constraint(Constraint(height, Constraint.EQ, ih, strength=STRONG, weight=0.0))
        solver.add_constraint(Constraint(top, Constraint.EQ, 0, strength=WEAK, weight=0.0))
        solver.add_constraint(Constraint(left, Constraint.EQ, 0, strength=WEAK, weight=0.0))
        solver.add_constraint(Constraint(bottom, Constraint.EQ, top + height, strength=MEDIUM, weight=0.0))
        # Right is at least left + width
        solver.add_constraint(Constraint(right, Constraint.EQ,  left + width, strength=MEDIUM, weight=0.0))
        solver.add_stay(iw)
        solver.add_stay(ih)

        # Propegate viewport size changes.
        for i in range(0, 30):

            # Measurement should be cheap here.
            iwv = random.randrange(MIN, MAX)
            ihv = random.randrange(MIN, MAX)

            solver.add_edit_var(iw)
            solver.add_edit_var(ih)

            with solver.edit():
                solver.suggest_value(iw, iwv)
                solver.suggest_value(ih, ihv)
                # solver.resolve()

            self.assertAlmostEqual(top.value, 0)
            self.assertAlmostEqual(left.value, 0)
            self.assertLessEqual(bottom.value, MAX)
            self.assertGreaterEqual(bottom.value, MIN)
            self.assertLessEqual(right.value, MAX)
            self.assertGreaterEqual(right.value, MIN)
Exemple #4
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)
Exemple #5
0
    def test_multiedit3(self):
        MIN = 100
        MAX = 500

        width = Variable('width')
        height = Variable('height')
        top = Variable('top')
        bottom = Variable('bottom')
        left = Variable('left')
        right = Variable('right')

        solver = SimplexSolver()

        iw = Variable('window_innerWidth', random.randrange(MIN, MAX))
        ih = Variable('window_innerHeight', random.randrange(MIN, MAX))

        solver.add_constraint(
            Constraint(width, Constraint.EQ, iw, strength=STRONG, weight=0.0))
        solver.add_constraint(
            Constraint(height, Constraint.EQ, ih, strength=STRONG, weight=0.0))
        solver.add_constraint(
            Constraint(top, Constraint.EQ, 0, strength=WEAK, weight=0.0))
        solver.add_constraint(
            Constraint(left, Constraint.EQ, 0, strength=WEAK, weight=0.0))
        solver.add_constraint(
            Constraint(bottom,
                       Constraint.EQ,
                       top + height,
                       strength=MEDIUM,
                       weight=0.0))
        # Right is at least left + width
        solver.add_constraint(
            Constraint(right,
                       Constraint.EQ,
                       left + width,
                       strength=MEDIUM,
                       weight=0.0))
        solver.add_stay(iw)
        solver.add_stay(ih)

        # Propegate viewport size changes.
        for i in range(0, 30):

            # Measurement should be cheap here.
            iwv = random.randrange(MIN, MAX)
            ihv = random.randrange(MIN, MAX)

            solver.add_edit_var(iw)
            solver.add_edit_var(ih)

            with solver.edit():
                solver.suggest_value(iw, iwv)
                solver.suggest_value(ih, ihv)
                # solver.resolve()

            self.assertAlmostEqual(top.value, 0)
            self.assertAlmostEqual(left.value, 0)
            self.assertLessEqual(bottom.value, MAX)
            self.assertGreaterEqual(bottom.value, MIN)
            self.assertLessEqual(right.value, MAX)
            self.assertGreaterEqual(right.value, MIN)