def __init__(self, parent=None, name='', lower_left=(0, 0), upper_right=(1, 1)): self.parent = parent self.name = name sn = self.name + '_' if parent is None: self.solver = kiwi.Solver() else: self.solver = parent.solver self.top = Variable(sn + 'top') self.bottom = Variable(sn + 'bottom') self.left = Variable(sn + 'left') self.right = Variable(sn + 'right') self.width = Variable(sn + 'width') self.height = Variable(sn + 'height') self.h_center = Variable(sn + 'h_center') self.v_center = Variable(sn + 'v_center') self.min_width = Variable(sn + 'min_width') self.min_height = Variable(sn + 'min_height') self.pref_width = Variable(sn + 'pref_width') self.pref_height = Variable(sn + 'pref_height') right, top = upper_right left, bottom = lower_left self.add_constraints()
def solve_ordering(nodes): """ Solve for the desired order of the list of nodes. This function is an implementation detail and should not be consumed by code outside of this module. Parameters ---------- nodes : list The list of PathNode objects which should be ordered. It is assumed that all nodes reside in the same group. Returns ------- result : list The PathNode objects ordered according to the constraints specified by the 'before' and 'after' items attributes. """ variables = {} for node in nodes: variables[node.id] = kiwi.Variable(str(node.id)) prev_var = None constraints = [] for node in nodes: this_var = variables[node.id] constraints.append(this_var >= 0) if prev_var is not None: # weakly preserve relative order constraints.append((prev_var + 0.1 <= this_var) | 'weak') before = node.item.before if before: if before not in variables: msg = "item '%s' has invalid `before` reference '%s'" raise ValueError(msg % (node.path, before)) target_var = variables[before] constraints.append((this_var + 0.1 <= target_var) | 'strong') after = node.item.after if after: if after not in variables: msg = "item '%s' has invalid `after` reference '%s'" raise ValueError(msg % (node.path, after)) target_var = variables[after] constraints.append((target_var + 0.1 <= this_var) | 'strong') prev_var = this_var solver = kiwi.Solver() for cn in constraints: solver.addConstraint(cn) solver.updateVariables() flat = [] for node in nodes: node_var = variables[node.id] flat.append((node_var.value(), node)) flat.sort() return [pair[1] for pair in flat]
def test(self): # Setup constrain programming variables. fig_w = ks.Variable('figure-width') fig_h = ks.Variable('figure-height') p1_w = ks.Variable('panel1-width') p1_h = ks.Variable('panel1-height') p2_w = ks.Variable('panel2-width') p2_h = ks.Variable('panel2-height') p2a_w = ks.Variable('panel2a-width') p2a_h = ks.Variable('panel2a-height') p2b_w = ks.Variable('panel2b-width') p2b_h = ks.Variable('panel2b-height') padding = ks.Variable('padding') # Setup solver. s = ks.Solver() # Setup constraints. c1 = fig_w - p1_w == 0 c2 = fig_w - p2_w == 0 c3 = p2_w - p2a_w - padding - p2b_w == 0 c4 = p2a_w - p2b_w == 0 c5 = fig_h - p1_h - padding - p2_h == 0 c6 = p2a_h == p2_h c7 = p2b_h == p2_h c8 = padding == 1.0 c9 = p1_w == 20.0 c10 = p1_h == 5.0 c11 = p2_h == 10.0 s.addConstraint(c1 | 'strong') s.addConstraint(c2 | 'strong') s.addConstraint(c3 | 'strong') s.addConstraint(c4 | 'strong') s.addConstraint(c5 | 'strong') s.addConstraint(c6 | 'strong') s.addConstraint(c7 | 'strong') s.addConstraint(c8 | 'strong') s.addConstraint(c9 | 'strong') s.addConstraint(c10 | 'strong') s.addConstraint(c11 | 'strong') s.updateVariables() # Check results self.assertEqual(fig_w.value(), 20) self.assertEqual(fig_h.value(), 16) self.assertEqual(p1_w.value(), 20) self.assertEqual(p1_h.value(), 5) self.assertEqual(p2_w.value(), 20) self.assertEqual(p2_h.value(), 10) self.assertEqual(p2a_w.value(), 9.5) self.assertEqual(p2a_h.value(), 10) self.assertEqual(p2b_w.value(), 9.5) self.assertEqual(p2b_h.value(), 10) self.assertEqual(padding.value(), 1.0)
def __init__(self, parent=None, name='', tight=False, artist=None, lower_left=(0, 0), upper_right=(1, 1), spine=False): Variable = kiwi.Variable self.parent = parent self.name = name sn = self.name + '_' if parent is None: self.solver = kiwi.Solver() else: self.solver = parent.solver parent.add_child(self) # keep track of artist associated w/ this layout. Can be none self.artist = artist # keep track if this box is supposed to be a spine that is constrained by the parent. self.spine = spine self.top = Variable(sn + 'top') self.bottom = Variable(sn + 'bottom') self.left = Variable(sn + 'left') self.right = Variable(sn + 'right') self.width = Variable(sn + 'width') self.height = Variable(sn + 'height') self.h_center = Variable(sn + 'h_center') self.v_center = Variable(sn + 'v_center') self.min_width = Variable(sn + 'min_width') self.min_height = Variable(sn + 'min_height') self.pref_width = Variable(sn + 'pref_width') self.pref_height = Variable(sn + 'pref_height') right, top = upper_right left, bottom = lower_left self.tight = tight self.add_constraints() self.children = [] self.subplotspec = None
def evaluate_constraints(view: IView[NT], top_rect: Rect[sym.Rational], constraints: List[IConstraint], strength: str = 'strong') -> IView[sym.Float]: solver = kiwisolver.Solver() env = make_kiwi_env([v for v in view]) add_linear_axioms(solver, [v for v in view], env) for constr in constraints: solver.addConstraint(constraint_to_kiwi(constr, env, strength=strength)) t_x, t_y = kiwi_lookup(view.left_anchor, env), kiwi_lookup(view.top_anchor, env) t_b, t_r = kiwi_lookup(view.bottom_anchor, env), kiwi_lookup(view.right_anchor, env) c_x, c_y, c_r, c_b = (top_rect.left, top_rect.top, top_rect.right, top_rect.bottom) solver.addConstraint((t_x == float(c_x)) | strength) solver.addConstraint((t_y == float(c_y)) | strength) solver.addConstraint((t_b == float(c_b)) | strength) solver.addConstraint((t_r == float(c_r)) | strength) solver.updateVariables() def get(anchor: IAnchor[NT]) -> float: kv = kiwi_lookup(anchor, env) return cast(float, kv.value()) def recurse(seed: IView[NT]) -> IViewBuilder: l, t = seed.left_anchor, seed.top_anchor r, b = seed.right_anchor, seed.bottom_anchor # left top right bottom rect = (get(l), get(t), get(r), get(b)) children = [recurse(inner) for inner in seed.children] return V(name=seed.name, rect=rect, children=children) return recurse(view).build(number_type=sym.Float)
def __init__(self): self._solver = kiwi.Solver() self._edit_stack = [] self._initialized = False self._running = False
def __init__(self, parent=None, name='', tightwidth=False, tightheight=False, artist=None, lower_left=(0, 0), upper_right=(1, 1), pos=False, subplot=False, h_pad=None, w_pad=None): Variable = kiwi.Variable self.parent = parent self.name = name sn = self.name + '_' if parent is None: self.solver = kiwi.Solver() self.constrained_layout_called = 0 else: self.solver = parent.solver self.constrained_layout_called = None # parent wants to know about this child! parent.add_child(self) # keep track of artist associated w/ this layout. Can be none self.artist = artist # keep track if this box is supposed to be a pos that is constrained # by the parent. self.pos = pos # keep track of whether we need to match this subplot up with others. self.subplot = subplot # we need the str below for Py 2 which complains the string is unicode self.top = Variable(str(sn + 'top')) self.bottom = Variable(str(sn + 'bottom')) self.left = Variable(str(sn + 'left')) self.right = Variable(str(sn + 'right')) self.width = Variable(str(sn + 'width')) self.height = Variable(str(sn + 'height')) self.h_center = Variable(str(sn + 'h_center')) self.v_center = Variable(str(sn + 'v_center')) self.min_width = Variable(str(sn + 'min_width')) self.min_height = Variable(str(sn + 'min_height')) self.pref_width = Variable(str(sn + 'pref_width')) self.pref_height = Variable(str(sn + 'pref_height')) # margis are only used for axes-position layout boxes. maybe should # be a separate subclass: self.left_margin = Variable(str(sn + 'left_margin')) self.right_margin = Variable(str(sn + 'right_margin')) self.bottom_margin = Variable(str(sn + 'bottom_margin')) self.top_margin = Variable(str(sn + 'top_margin')) # mins self.left_margin_min = Variable(str(sn + 'left_margin_min')) self.right_margin_min = Variable(str(sn + 'right_margin_min')) self.bottom_margin_min = Variable(str(sn + 'bottom_margin_min')) self.top_margin_min = Variable(str(sn + 'top_margin_min')) right, top = upper_right left, bottom = lower_left self.tightheight = tightheight self.tightwidth = tightwidth self.add_constraints() self.children = [] self.subplotspec = None if self.pos: self.constrain_margins() self.h_pad = h_pad self.w_pad = w_pad
def __init__(self, joints, layers): self.joints = joints self.layers = layers self.solver = kiwisolver.Solver() self.variables = {}
def __init__(self, parent=None, parent_pos=(0, 0), parent_inner=False, name='', ncols=1, nrows=1, h_pad=None, w_pad=None, width_ratios=None, height_ratios=None): Variable = kiwi.Variable self.parent = parent self.parent_pos = parent_pos self.parent_inner = parent_inner self.name = name self.nrows = nrows self.ncols = ncols self.height_ratios = np.atleast_1d(height_ratios) if height_ratios is None: self.height_ratios = np.ones(nrows) self.width_ratios = np.atleast_1d(width_ratios) if width_ratios is None: self.width_ratios = np.ones(ncols) sn = self.name + '_' if parent is None: self.parent = None self.solver = kiwi.Solver() else: self.parent = parent parent.add_child(self, *parent_pos) self.solver = self.parent.solver # keep track of artist associated w/ this layout. Can be none self.artists = np.empty((nrows, ncols), dtype=object) self.children = np.empty((nrows, ncols), dtype=object) self.margins = {} self.margin_vals = {} # all the boxes in each column share the same left/right margins: for todo in ['left', 'right', 'leftcb', 'rightcb']: # track the value so we can change only if a margin is larger # than the current value self.margin_vals[todo] = np.zeros(ncols) sol = self.solver # These are redundant, but make life easier if # we define them all. All that is really # needed is left/right, margin['left'], and margin['right'] self.widths = [Variable(f'{sn}widths[{i}]') for i in range(ncols)] self.lefts = [Variable(f'{sn}lefts[{i}]') for i in range(ncols)] self.rights = [Variable(f'{sn}rights[{i}]') for i in range(ncols)] self.inner_widths = [ Variable(f'{sn}inner_widths[{i}]') for i in range(ncols) ] for todo in ['left', 'right', 'leftcb', 'rightcb']: self.margins[todo] = [ Variable(f'{sn}margins[{todo}][{i}]') for i in range(ncols) ] for i in range(ncols): sol.addEditVariable(self.margins[todo][i], 'strong') for todo in ['bottom', 'top', 'bottomcb', 'topcb']: self.margins[todo] = np.empty((nrows), dtype=object) self.margin_vals[todo] = np.zeros(nrows) self.heights = [Variable(f'{sn}heights[{i}]') for i in range(nrows)] self.inner_heights = [ Variable(f'{sn}inner_heights[{i}]') for i in range(nrows) ] self.bottoms = [Variable(f'{sn}bottoms[{i}]') for i in range(nrows)] self.tops = [Variable(f'{sn}tops[{i}]') for i in range(nrows)] for todo in ['bottom', 'top', 'bottomcb', 'topcb']: self.margins[todo] = [ Variable(f'{sn}margins[{todo}][{i}]') for i in range(nrows) ] for i in range(nrows): sol.addEditVariable(self.margins[todo][i], 'strong') # set these margins to zero by default. They will be edited as # children are filled. self.reset_margins() self.add_constraints() self.h_pad = h_pad self.w_pad = w_pad
# 0|-------------| x1 ----- xm ----- x2 |-----------------------|100 x1 = kiwi.Variable('x1') x2 = kiwi.Variable('x2') xm = kiwi.Variable('xm') sm = kiwi.Variable('sm') sm2 = kiwi.Variable('sm') constraints = [ x1 >= 0, x2 <= 100, x2 >= x1 + 10, xm == (x1 + x2) / 2, sm == x1 + x2, ] # these all have strength 'required' solver = kiwi.Solver() for cn in constraints: solver.addConstraint(cn) solver.addEditVariable(xm, 'strong') solver.addEditVariable(sm, 'weak') solver.addConstraint(sm >= 100) solver.suggestValue(xm, 40) solver.updateVariables() print('x1:', x1.value()) print('x2:', x2.value()) print('xm:', xm.value()) print('sm:', sm.value())
def __init__(self, figwidth=Fixed(0.0), figheight=Fixed(0.0), margin_left=0.0, margin_right=0.0, margin_top=0.0, margin_bottom=0.0, layout='vertical', padding=0.0): """Default constructor. Args: :param figwidth: Width of the figure, base size is adjusted re: margins. :param figheight: Height of the figure, base is adjusted re: margins. :param margin_left float: Width of the margin on the left-hand side [cm]. :param margin_right float: Width of the margin on the right-hand side [cm]. :param margin_top float: Height of the margin at the top of the plot [cm]. :param margin_bottom float: Height of the margin at the bottom of the plot [cm]. :param layout str: Is the figure layed out with each element horizontally ('horizontal') or vertically ('vertical'). :param padding float: How much padding is there between elements [cm]. """ self.store = dict() self.solver = ks.Solver() self.label_index = 0 self.fig_width_constraint = figwidth self.fig_height_constraint = figheight # All the plot elements are arranged in a tree structure, built # from a linked list of PlotElement objects. Base is the root of # this tree. self.base = PlotElement() self.base.label = 'base' self.base.width.setName('base-w') self.base.height.setName('base-h') self.parent = None # Set base plot element parameters. if isinstance(figwidth, Fixed): self.solver.addConstraint((self.base.width == figwidth.size - margin_left - margin_right) | 'required') elif isinstance(figwidth, FromChildren): pass elif isinstance(figwidth, Named): pass else: raise InappropriateConstraint(type(figwidth),'base','Figure width setup can only be \ constrained using Fixed, FromChildren or Named.') self.base.width_constraint = figwidth if isinstance(figheight, Fixed): self.solver.addConstraint((self.base.height == figheight.size - margin_bottom - margin_top) | 'required') elif isinstance(figheight, FromChildren): pass elif isinstance(figheight, Named): pass else: raise InappropriateConstraint(type(figheight),'base','Figure height setup can only be \ constrained using Fixed, FromChildren or Named.') self.base.height_constraint = figheight self.base.margin_left = margin_left self.base.margin_right = margin_right self.base.margin_top = margin_top self.base.margin_bottom = margin_bottom self.base.padding = padding if layout=='horizontal': self.base.layout = 'horizontal' elif layout=='vertical': self.base.layout = 'vertical' else: raise ValueError('Unknown layout method <{}> (should be horizontal or vertical)'.format(layout)) # Initialise the dictionary (we are subclassing the dict class). self.store['base'] = self.base # Store the full figure dimensions - although this won't be determined until we # complete the layout. self.figure_width = 0.0 self.figure_height = 0.0
import sys import time import math import os import kiwisolver as K import pygame from pygame.locals import * from py.util.math import lerp_unlerp solver = K.Solver() width = K.Variable("width") height = K.Variable("height") pad = K.Variable("pad") plots_x = K.Variable("plots_x") plots_y = K.Variable("plots_y") plot_sz = K.Variable("plot_sz") solver.addEditVariable(width, "strong") solver.addEditVariable(height, "strong") solver.addEditVariable(pad, "strong") solver.addConstraint(pad <= plots_x) solver.addConstraint(pad <= plots_y) solver.addConstraint(plots_x + plot_sz + pad + plot_sz + plots_x == width) solver.addConstraint(plots_y + plot_sz + plots_y == height)