def align_left_or_top(self, rows, padding, column_or_row, aligned_axis, below_or_right_axis, width_or_height): """ Align columns or rows to the left or top edge """ constraints = [] for i in range(0, len(rows) - 1): row1 = rows[i] row2 = rows[i + 1] if len(row1) > 0 and len(row2) > 0: shape1 = row1[0] shape2 = row2[0] # Width or height of shape1 w_or_h = str(shape1.computed_width() ) if width_or_height == "width" else str( shape1.computed_height()) # Shape1 row is left or top aligned to shape2 row constraints.append( cb.eq(shape1.variables[aligned_axis].id, shape2.variables[aligned_axis].id)) # shape2 row is below or to the right of shape1 row constraints.append( cb.lte( cb.add(shape1.variables[below_or_right_axis].id, cb.add(w_or_h, padding)), shape2.variables[below_or_right_axis].id)) if len(constraints): return cb.and_expr(constraints) return True
def set_container_size_main_axis(self, container, padding, rows_or_columns, width_or_height): """ Constraint for the main axis size of the container """ size = "" num_rows_or_columns = len(rows_or_columns) outside_padding = container.variables.outside_padding.id if container.at_root else "0" for i in range(0, num_rows_or_columns): row_or_column = rows_or_columns[i] if len(row_or_column): spacing = padding if i < num_rows_or_columns - 1 else 0 m_height_or_width = None if width_or_height == "width": m_height_or_width = size_constraint_helpers.get_max_width_constraint( 1, 0, row_or_column) else: m_height_or_width = size_constraint_helpers.get_max_height_constraint( 1, 0, row_or_column) if len(size): size = cb.add(size, cb.add(m_height_or_width, str(spacing))) else: size = cb.add(m_height_or_width, str(spacing)) container_size = cb.add( cb.mult("2", outside_padding), str(container.computed_width()) ) if width_or_height == "width" else str(container.computed_height()) return cb.eq(container_size, size)
def set_container_size_cross_axis(self, container, padding, rows_or_columns, width_or_height): """ Constraint for the cross axis size of the container """ outside_padding = container.variables.outside_padding.id if container.at_root else "0" size = self.get_widest_row_constraint( 1, 0, rows_or_columns, padding ) if width_or_height == "width" else self.get_tallest_column_constraint( 1, 0, rows_or_columns, padding) container_size = cb.add( cb.mult("2", outside_padding), str(container.computed_width()) ) if width_or_height == "width" else str(container.computed_height()) return cb.eq(container_size, size)
def align_rows_or_columns(self, container, padding, rows, column_or_row, aligned_axis, aligned_axis_size, layout_axis, layout_axis_size): """ Align rows or columns elements with a column or row to the alignment of the parent container """ constraints = [] l_index = container.variables.alignment.domain.index("left") c_index = container.variables.alignment.domain.index("center") is_left = cb.eq(container.variables.alignment.id, str(l_index)) is_center = cb.eq(container.variables.alignment.id, str(c_index)) for row in rows: for i in range(len(row) - 1): shape1 = row[i] shape2 = row[i + 1] aligned_axis_size_value = str(shape1.computed_width( )) if aligned_axis_size == "width" else str( shape1.computed_height()) aligned_axis_size_value2 = str(shape2.computed_width( )) if aligned_axis_size == "width" else str( shape2.computed_height()) left_top_aligned = cb.eq(shape1.variables[aligned_axis].id, shape2.variables[aligned_axis].id) right_bottom_aligned = cb.eq( cb.add(shape1.variables[aligned_axis].id, aligned_axis_size_value), cb.add(shape2.variables[aligned_axis].id, aligned_axis_size_value2)) center_aligned = cb.eq( cb.add(shape1.variables[aligned_axis].id, cb.div(aligned_axis_size_value, "2")), cb.add(shape2.variables[aligned_axis].id, cb.div(aligned_axis_size_value2, "2"))) constraints.append( cb.ite( is_left, left_top_aligned, cb.ite(is_center, center_aligned, right_bottom_aligned))) # Shape 2 is exactly to the right of shape 1 or to the bottom if in a column layout_axis_size_value = str(shape1.computed_width( )) if layout_axis_size == "width" else str( shape1.computed_height()) constraints.append( cb.eq( cb.add(shape1.variables[layout_axis].id, cb.add(layout_axis_size_value, padding)), shape2.variables[layout_axis].id)) if len(constraints): return cb.and_expr(constraints) return True
def encode_previous_solution_from_model(self, model, solution_id): # The next solution cannot be the exact same outputs as the previous assignment # It may be possible for multiple solutions to have the same outputs (exact x,y coordinates for all shapes) # So to restrict this, we encode the X,Y positions in the clauses to prevent these solutions all_values = [] variables = solution.parse_variables_from_model(model) decl_constraints = "" # Because from_string requires declaring vars again even if already defined :( for v_i in range(0, len(self.output_variables)): variable = self.output_variables[v_i] model_var = variables[variable.id] variable_value = model[model_var] variable_value = variable_value.as_string() variable_value = int(variable_value) all_values.append(smt.eq(variable.id, str(variable_value))) decl_constraints += smt.declare(variable.id, variable.type) constraints = smt.assert_expr( smt.not_expr(smt.and_expr(all_values)), "prevent_prev_solution_" + solution_id + "_from_appearing_again") constraints = decl_constraints + constraints self.override_solver.load_constraints(constraints)
def encode_assigned_variable(self, variable): """ Used by the search loops to create constraints to encode an equality constraint for a variable value to the value it has been assigned by the search """ constraints = smt.declare(variable.id, variable.type) if variable.name == "grid_layout": assigned_value = variable.domain[variable.assigned] marg_var = self.shapes[variable.shape_id].variables.margin constraints += smt.declare(marg_var.id, marg_var.type) marg = smt.eq(marg_var.id, str(assigned_value[0])) cols_var = self.shapes[variable.shape_id].variables.columns constraints += smt.declare(cols_var.id, cols_var.type) cols = smt.eq(cols_var.id, str(assigned_value[1])) gutter_width_var = self.shapes[ variable.shape_id].variables.gutter_width constraints += smt.declare(gutter_width_var.id, gutter_width_var.type) gutter_width = smt.eq(gutter_width_var.id, str(assigned_value[2])) col_width_var = self.shapes[ variable.shape_id].variables.column_width constraints += smt.declare(col_width_var.id, col_width_var.type) col_width = smt.eq(col_width_var.id, str(assigned_value[3])) and_expr = smt.and_expr([marg, cols, gutter_width, col_width]) constraints += smt.assert_expr( and_expr, "variable_" + variable.id + "_assigned_to_" + str(variable.assigned)) self.override_solver.load_constraints(constraints) elif variable.name == "size_combo": assigned_value = variable.domain[variable.assigned] width_var = self.shapes[variable.shape_id].variables.width constraints += smt.declare(width_var.id, width_var.type) width = smt.eq(width_var.id, str(assigned_value[0])) height_var = self.shapes[variable.shape_id].variables.height constraints += smt.declare(height_var.id, height_var.type) height = smt.eq(height_var.id, str(assigned_value[1])) size_factor = self.shapes[variable.shape_id].variables.size_factor constraints += smt.declare(size_factor.id, size_factor.type) size_fact = smt.eq(size_factor.id, str(assigned_value[2])) and_expr = smt.and_expr([width, height, size_fact]) constraints += smt.assert_expr( and_expr, "variable_" + variable.id + "_assigned_to_" + str(variable.assigned)) self.override_solver.load_constraints(constraints) elif variable.index_domain: constraints += smt.assert_expr( smt.eq(variable.id, str(variable.assigned)), "variable_" + variable.id + "_assigned_to_" + str(variable.assigned)) self.override_solver.load_constraints(constraints) else: dom_value = variable.domain[variable.assigned] if variable.type == "String": dom_value = "\"" + dom_value + "\"" constraints += smt.assert_expr( smt.eq(variable.id, str(dom_value)), "variable_" + variable.id + "_assigned_to_" + str(variable.assigned)) self.override_solver.load_constraints(constraints)