def define_shape(self, layer): i = 0 x_p = 0 y_p = 0 xp_p = 0.0 yp_p = 0.0 for p in layer.straight_pairs: #path4581_p1_x name = layer.name + '_p' + str(i) + '_' nameX = name + 'x' nameY = name + 'y' x = kiwisolver.Variable(nameX) y = kiwisolver.Variable(nameY) self.variables[nameX] = x self.variables[nameY] = y xp = p[0] yp = p[1] if i > 0: x_constraint = (x == (x_p + (xp - xp_p))) y_constraint = (y == (y_p + (yp - yp_p))) self.solver.addConstraint(x_constraint | "strong") self.solver.addConstraint(y_constraint | "strong") x_p = x y_p = y xp_p = xp yp_p = yp i += 1 return layer
def add_joint(self, jname, lname, pname, p): #path4581_p1_x layername = lname + '_p' + str(pname) + '_' layernameX = layername + 'x' layernameY = layername + 'y' # lx = kiwisolver.Variable(layernameX) # ly = kiwisolver.Variable(layernameY) lx = self.variables[layernameX] ly = self.variables[layernameY] jointname = 'joint_' + str(jname) + '_' jointnameX = jointname + 'x' jointnameY = jointname + 'y' if jointnameX not in self.variables.keys(): jx = kiwisolver.Variable(jointnameX) jy = kiwisolver.Variable(jointnameY) self.variables[jointnameX] = jx self.variables[jointnameY] = jy else: jx = self.variables[jointnameX] jy = self.variables[jointnameY] self.solver.addConstraint((lx == jx) | strength_joint) self.solver.addConstraint((ly == jy) | strength_joint)
def add_fixed(self, layer): i = 0 for p in layer.straight_pairs: #path4581_p1_x name = layer.name + '_p' + str(i) + '_' nameX = name + 'x' nameY = name + 'y' x = kiwisolver.Variable(nameX) y = kiwisolver.Variable(nameY) self.solver.addConstraint((x == p[0]) | strength_define) self.solver.addConstraint((y == p[1]) | strength_define) i += 1 return layer
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 solve(self): joints = self.joints layers = self.layers for l in layers: #Todo: check that shape actually needs constraints before defining l = self.define_shape(l) #Todo: Finish / test if l.fixed == True: self.add_fixed(l) print(joints) for jointlayer in joints: print(jointlayer) for jp in joints[jointlayer]: for l in layers: print(l.name) #print(l) i = 0 for p in l.straight_pairs: if (self.encloses(p, jp)): print(jointlayer, l.name, i, p) self.add_joint(jointlayer, l.name, i, p) #joint_assoc[jointlayer].append(l.name) i += 1 #print(joint_assoc) print(self.solver.dumps()) print(self.solver) print(dir(self.solver)) print(dir(kiwisolver.Variable())) print(layers) # print(dir(kiwisolver.Expression())) #needs term # print(dir(kiwisolver.Term())) #needs variable print(dir(kiwisolver.Term(self.variables['path4518_p3_y']))) print(self.variables) print(self.variables['path4518_p3_y']) print(self.variables['path4518_p3_y'].value()) print(self.variables['path4518_p3_x'].value()) print(self.variables['path4520_p1_y']) print(self.variables['path4520_p1_y'].value()) print(self.variables['path4520_p1_x'].value()) self.solver.updateVariables() print(self.variables['path4518_p3_y']) print(self.variables['path4518_p3_y'].value()) print(self.variables['path4518_p3_x'].value()) print(self.variables['path4520_p1_y']) print(self.variables['path4520_p1_y'].value()) print(self.variables['path4520_p1_x'].value()) return self.incorporate(self.variables, layers)
def __init__(self): """Default constructor. """ # Margins. self.margin_left = 0 self.margin_right = 0 self.margin_top = 0 self.margin_bottom = 0 # Dimensions of the element. We also have some flags so that we can # determine if the dimensions have been properly set yet, and where # the dimension information originates. self.width = ks.Variable() self.height = ks.Variable() self.width_constraint = 'none' self.height_constraint = 'none' # Coordinates of the four edges of the element. self.xl = 0.0 self.xr = 0.0 self.yt = 0.0 self.yb = 0.0 # Layout control information: How does this element lay out its child # elements, by row or column? What padding is there between elements? self.layout = 'none' self.padding = 0.0 # Label for this element. self.label = '' # Figure axis. self.ax = None # Parent and child nodes for the linked list. self.parent = None self.children = dict()
def default(self, owner): return kiwi.Variable(self.name)
def constraints(self, component): """ Generate the grid constraints for the given component. Parameters ---------- component : Constrainable or None The constrainable object which represents the conceptual owner of the generated constraints. Returns ------- result : list The list of Constraint objects for the given component. """ # Create the outer boundary box constraints. cns = self.box_constraints(component) # Compute the cell spans for the items in the grid. cells = [] cell_map = {} num_cols = 0 num_rows = len(self.rows) for row_idx, row in enumerate(self.rows): num_cols = max(num_cols, len(row)) for col_idx, item in enumerate(row): if item is None: continue elif item in cell_map: cell_map[item].expand_to(row_idx, col_idx) else: cell = self._Cell(item, row_idx, col_idx) cell_map[item] = cell cells.append(cell) # Create the row and column variables and their default limits. row_vars = [] col_vars = [] for idx in xrange(num_rows + 1): var = kiwi.Variable('row%d' % idx) row_vars.append(var) cns.append(var >= 0) for idx in xrange(num_cols + 1): var = kiwi.Variable('col%d' % idx) col_vars.append(var) cns.append(var >= 0) # Add the neighbor constraints for the row and column vars. for r1, r2 in zip(row_vars[:-1], row_vars[1:]): cns.append(r1 <= r2) for c1, c2 in zip(col_vars[:-1], col_vars[1:]): cns.append(c1 <= c2) # Setup the initial interior bounding box for the grid. firsts = (self.top, col_vars[-1], row_vars[-1], self.left) seconds = (row_vars[0], self.right, self.bottom, col_vars[0]) for size, first, second in zip(self.margins, firsts, seconds): cns.extend(EqSpacer(size).create_constraints(first, second)) # Setup the spacer lists for constraining the cell items row_spacer = FlexSpacer(self.row_spacing / 2) # floor division col_spacer = FlexSpacer(self.column_spacing / 2) rspace = [row_spacer] * len(row_vars) cspace = [col_spacer] * len(col_vars) rspace[0] = rspace[-1] = cspace[0] = cspace[-1] = 0 # Create the helpers for each constrainable grid cell item. The # helper validation is bypassed since the items are known-valid. helpers = [] for cell in cells: sr = cell.start_row er = cell.end_row + 1 sc = cell.start_column ec = cell.end_column + 1 item = cell.item ritems = (row_vars[sr], rspace[sr], item, rspace[er], row_vars[er]) citems = (col_vars[sc], cspace[sc], item, cspace[ec], col_vars[ec]) rhelper = SequenceHelper('bottom', 'top', ()) chelper = SequenceHelper('right', 'left', ()) rhelper.items = ritems chelper.items = citems helpers.extend((rhelper, chelper)) if isinstance(item, ConstraintHelper): helpers.append(item) # Add the row alignment helpers if needed. This will only create # the helpers for items which do not span multiple rows. anchor = self.row_align if anchor: row_map = defaultdict(list) for cell in cells: if cell.start_row == cell.end_row: row_map[cell.start_row].append(cell.item) for items in row_map.itervalues(): if len(items) > 1: helper = SequenceHelper(anchor, anchor, (), 0) helper.items = tuple(items) helpers.append(helper) # Add the column alignment helpers if needed. This will only # create the helpers for items which do not span multiple rows. anchor = self.column_align if anchor: col_map = defaultdict(list) for cell in cells: if cell.start_column == cell.end_column: col_map[cell.start_column].append(cell.item) for items in col_map.itervalues(): if len(items) > 1: helper = SequenceHelper(anchor, anchor, (), 0) helper.items = tuple(items) helpers.append(helper) # Generate the constraints from the helpers. for helper in helpers: cns.extend(helper.create_constraints(None)) return cns
import kiwisolver as kiwi # 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 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 anchorid_to_kv(aid: IAnchorID) -> kiwisolver.Variable: return kiwisolver.Variable(str(aid))
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)