/* Setting the coefficient to 0 will remove the variable */ if (G_APPROX_VALUE (new_coefficient, 0.0, 0.001))
{ /* Update the tableau if needed */ if (solver != NULL)
gtk_constraint_solver_note_removed_variable (solver, variable, subject);
/* Otherwise, add the variable if the coefficient is non-zero */ if (!G_APPROX_VALUE (coefficient, 0.0, 0.001))
{
gtk_constraint_expression_add_term (expression, variable, coefficient);
if (solver != NULL)
gtk_constraint_solver_note_added_variable (solver, variable, subject);
}
}
iter = b_expr->last_term;
while (iter != NULL)
{
Term *next = iter->prev;
gtk_constraint_expression_add_variable (a_expr,
iter->variable, n * iter->coefficient,
subject,
solver);
iter = next;
}
}
/*< private >
* gtk_constraint_expression_plus_constant:
* @expression: a `GtkConstraintExpression`
* @constant: a constant value
*
* Adds a @constant value to the @expression.
*
* This is the equivalent of creating a new `GtkConstraintExpression` for
* the @constant and calling gtk_constraint_expression_add_expression().
*
* Returns: the @expression
*/
GtkConstraintExpression *
gtk_constraint_expression_plus_constant (GtkConstraintExpression *expression,
double constant)
{
GtkConstraintExpression *e;
e = gtk_constraint_expression_new (constant);
gtk_constraint_expression_add_expression (expression, e, 1.0, NULL, NULL);
gtk_constraint_expression_unref (e);
return expression;
}
/*< private >
* gtk_constraint_expression_minus_constant:
* @expression: a `GtkConstraintExpression`
* @constant: a constant value
*
* Removes a @constant value from the @expression.
*
* This is the equivalent of creating a new `GtkConstraintExpression` for
* the inverse of @constant and calling gtk_constraint_expression_add_expression().
*
* Returns: the @expression
*/
GtkConstraintExpression *
gtk_constraint_expression_minus_constant (GtkConstraintExpression *expression,
double constant)
{
return gtk_constraint_expression_plus_constant (expression, constant * -1.0);
}
/*< private >
* gtk_constraint_expression_plus_variable:
* @expression: a `GtkConstraintExpression`
* @variable: a `GtkConstraintVariable`
*
* Adds a @variable to the @expression.
*
* Returns: the @expression
*/
GtkConstraintExpression *
gtk_constraint_expression_plus_variable (GtkConstraintExpression *expression,
GtkConstraintVariable *variable)
{
GtkConstraintExpression *e;
e = gtk_constraint_expression_new_from_variable (variable);
gtk_constraint_expression_add_expression (expression, e, 1.0, NULL, NULL);
gtk_constraint_expression_unref (e);
return expression;
}
/*< private >
* gtk_constraint_expression_minus_variable:
* @expression: a `GtkConstraintExpression`
* @variable: a `GtkConstraintVariable`
*
* Subtracts a @variable from the @expression.
*
* Returns: the @expression
*/
GtkConstraintExpression *
gtk_constraint_expression_minus_variable (GtkConstraintExpression *expression,
GtkConstraintVariable *variable)
{
GtkConstraintExpression *e;
e = gtk_constraint_expression_new_from_variable (variable);
gtk_constraint_expression_add_expression (expression, e, -1.0, NULL, NULL);
gtk_constraint_expression_unref (e);
return expression;
}
/*< private >
* gtk_constraint_expression_multiply_by:
* @expression: a `GtkConstraintExpression`
* @factor: the multiplication factor
*
* Multiplies the constant part and the coefficient of all terms
* in @expression with the given @factor.
*
* Returns: the @expression
*/
GtkConstraintExpression *
gtk_constraint_expression_multiply_by (GtkConstraintExpression *expression,
double factor)
{
GHashTableIter iter;
gpointer value_p;
expression->constant *= factor;
if (expression->terms == NULL)
return expression;
g_hash_table_iter_init (&iter, expression->terms);
while (g_hash_table_iter_next (&iter, NULL, &value_p))
{
Term *t = value_p;
t->coefficient *= factor;
}
return expression;
}
/*< private >
* gtk_constraint_expression_divide_by:
* @expression: a `GtkConstraintExpression`
* @factor: the division factor
*
* Divides the constant part and the coefficient of all terms
* in @expression by the given @factor.
*
* Returns: the @expression
*/
GtkConstraintExpression *
gtk_constraint_expression_divide_by (GtkConstraintExpression *expression,
double factor)
{
if (G_APPROX_VALUE (factor, 0.0, 0.001))
return expression;
/*< private >
* gtk_constraint_expression_new_subject:
* @expression: a `GtkConstraintExpression`
* @subject: a `GtkConstraintVariable` part of @expression
*
* Modifies @expression to have a new @subject.
*
* A `GtkConstraintExpression` is a linear expression in the form of
* `@expression = 0`. If @expression contains @subject, for instance:
*
* |[
* c + (a × @subject) + (a1 × v1) + … + (an × vn) = 0
* ]|
*
* this function will make @subject the new subject of the expression:
*
* |[
* subject = - (c / a) - ((a1 / a) × v1) - … - ((an / a) × vn) = 0
* ]|
*
* The term @subject is removed from the @expression.
*
* Returns: the reciprocal of the coefficient of @subject, so we
* can use this function in gtk_constraint_expression_change_subject()
*/
double
gtk_constraint_expression_new_subject (GtkConstraintExpression *expression,
GtkConstraintVariable *subject)
{
double reciprocal = 1.0;
Term *term;
/*< private >
* gtk_constraint_expression_change_subject:
* @expression: a `GtkConstraintExpression`
* @old_subject: the old subject `GtkConstraintVariable` of @expression
* @new_subject: the new subject `GtkConstraintVariable` of @expression
*
* Turns an @expression in the form of:
*
* |[
* old_subject = c + (a × new_subject) + (a1 × v1) + … + (an × vn)
* ]|
*
* into the form of:
*
* |[
* new_subject = -c / a + old_subject / a - ((a1 / a) × v1) - … - ((an / a) × vn)
* ]|
*
* Which means resolving @expression for @new_subject.
*/
void
gtk_constraint_expression_change_subject (GtkConstraintExpression *expression,
GtkConstraintVariable *old_subject,
GtkConstraintVariable *new_subject)
{
double reciprocal;
/*< private >
* gtk_constraint_expression_get_coefficient:
* @expression: a `GtkConstraintExpression`
* @variable: a `GtkConstraintVariable`
*
* Retrieves the coefficient of the term for @variable inside @expression.
*
* Returns: the coefficient of @variable
*/
double
gtk_constraint_expression_get_coefficient (GtkConstraintExpression *expression,
GtkConstraintVariable *variable)
{
const Term *term;
term = g_hash_table_lookup (expression->terms, variable);
if (term == NULL)
return 0.0;
return term->coefficient;
}
/*< private >
* gtk_constraint_expression_substitute_out:
* @expression: a `GtkConstraintExpression`
* @out_var: the variable to replace
* @expr: the expression used to replace @out_var
* @subject: (nullable): a `GtkConstraintVariable`
* @solver: (nullable): a `GtkConstraintSolver`
*
* Replaces every term containing @out_var inside @expression with @expr.
*
* If @solver is not %NULL, this function will notify the `GtkConstraintSolver`
* for every variable added to or removed from @expression.
*/
void
gtk_constraint_expression_substitute_out (GtkConstraintExpression *expression,
GtkConstraintVariable *out_var,
GtkConstraintExpression *expr,
GtkConstraintVariable *subject,
GtkConstraintSolver *solver)
{
double multiplier;
Term *iter;
if (solver != NULL)
gtk_constraint_solver_note_added_variable (solver, clv, subject);
}
iter = next;
}
}
/*< private >
* gtk_constraint_expression_get_pivotable_variable:
* @expression: a `GtkConstraintExpression`
*
* Retrieves the first `GtkConstraintVariable` in @expression that
* is marked as pivotable.
*
* Returns: (transfer none) (nullable): a `GtkConstraintVariable`
*/
GtkConstraintVariable *
gtk_constraint_expression_get_pivotable_variable (GtkConstraintExpression *expression)
{
Term *iter;
if (expression->terms == NULL)
{
g_critical ("Expression %p is a constant", expression);
return NULL;
}
iter = expression->first_term;
while (iter != NULL)
{
Term *next = iter->next;
if (gtk_constraint_variable_is_pivotable (iter->variable))
return iter->variable;
iter = next;
}
return NULL;
}
/*< private >
* gtk_constraint_expression_to_string:
* @expression: a `GtkConstraintExpression`
*
* Creates a string containing @expression.
*
* This function is only useful for debugging.
*
* Returns: (transfer full): a string containing the given expression
*/
char *
gtk_constraint_expression_to_string (const GtkConstraintExpression *expression)
{
gboolean needs_plus = FALSE;
GString *buf;
Term *iter;
if (expression == NULL)
return g_strdup ("<null>");
buf = g_string_new (NULL);
if (!G_APPROX_VALUE (expression->constant, 0.0, 0.001))
{
g_string_append_printf (buf, "%g", expression->constant);
if (expression->terms != NULL)
needs_plus = TRUE;
}
if (expression->terms == NULL)
return g_string_free (buf, FALSE);
iter = expression->first_term;
while (iter != NULL)
{
char *str = gtk_constraint_variable_to_string (iter->variable);
Term *next = iter->next;
/*< private >
* gtk_constraint_expression_iter_next:
* @iter: a valid `GtkConstraintExpression`Iter
* @variable: (out): the variable of the next term
* @coefficient: (out): the coefficient of the next term
*
* Moves the given `GtkConstraintExpression`Iter forwards to the next
* term in the expression, starting from the first term.
*
* Returns: %TRUE if the iterator was moved, and %FALSE if the iterator
* has reached the end of the terms of the expression
*/
gboolean
gtk_constraint_expression_iter_next (GtkConstraintExpressionIter *iter,
GtkConstraintVariable **variable,
double *coefficient)
{
RealExpressionIter *riter = REAL_EXPRESSION_ITER (iter);
/*< private >
* gtk_constraint_expression_iter_prev:
* @iter: a valid `GtkConstraintExpression`Iter
* @variable: (out): the variable of the previous term
* @coefficient: (out): the coefficient of the previous term
*
* Moves the given `GtkConstraintExpression`Iter backwards to the previous
* term in the expression, starting from the last term.
*
* Returns: %TRUE if the iterator was moved, and %FALSE if the iterator
* has reached the beginning of the terms of the expression
*/
gboolean
gtk_constraint_expression_iter_prev (GtkConstraintExpressionIter *iter,
GtkConstraintVariable **variable,
double *coefficient)
{
RealExpressionIter *riter = REAL_EXPRESSION_ITER (iter);
/*< private >
* gtk_constraint_expression_builder_init:
* @builder: a `GtkConstraintExpression`Builder
* @solver: a `GtkConstraintSolver`
*
* Initializes the given `GtkConstraintExpression`Builder for the
* given `GtkConstraintSolver`.
*
* You can use the @builder to construct expressions to be added to the
* @solver, in the form of constraints.
*
* A typical use is:
*
* ```c
* GtkConstraintExpressionBuilder builder;
*
* // "solver" is set in another part of the code
* gtk_constraint_expression_builder_init (&builder, solver);
*
* // "width" is set in another part of the code
* gtk_constraint_expression_builder_term (&builder, width);
* gtk_constraint_expression_builder_divide_by (&builder);
* gtk_constraint_expression_builder_constant (&builder, 2.0);
*
* // "left" is set in another part of the code
* gtk_constraint_expression_builder_plus (&builder);
* gtk_constraint_expression_builder_term (&builder, left);
*
* // "expr" now contains the following expression:
* // width / 2.0 + left
* GtkConstraintExpression *expr =
* gtk_constraint_expression_builder_finish (&builder);
*
* // The builder is inert, and can be re-used by calling
* // gtk_constraint_expression_builder_init() again.
* ```
*/
void
gtk_constraint_expression_builder_init (GtkConstraintExpressionBuilder *builder,
GtkConstraintSolver *solver)
{
RealExpressionBuilder *rbuilder = REAL_EXPRESSION_BUILDER (builder);
/*< private >
* gtk_constraint_expression_builder_constant:
* @builder: a `GtkConstraintExpression`Builder
* @value: a constant value
*
* Adds a constant value to the @builder.
*/
void
gtk_constraint_expression_builder_constant (GtkConstraintExpressionBuilder *builder,
double value)
{
RealExpressionBuilder *rbuilder = REAL_EXPRESSION_BUILDER (builder);
switch (rbuilder->op)
{
case BUILDER_OP_NONE:
gtk_constraint_expression_set_constant (rbuilder->expression, value);
break;
case BUILDER_OP_PLUS:
gtk_constraint_expression_plus_constant (rbuilder->expression, value);
break;
case BUILDER_OP_MINUS:
gtk_constraint_expression_minus_constant (rbuilder->expression, value);
break;
case BUILDER_OP_MULTIPLY:
gtk_constraint_expression_multiply_by (rbuilder->expression, value);
break;
case BUILDER_OP_DIVIDE:
gtk_constraint_expression_divide_by (rbuilder->expression, value);
break;
default:
break;
}
rbuilder->op = BUILDER_OP_NONE;
}
/*< private >
* gtk_constraint_expression_builder_finish:
* @builder: a `GtkConstraintExpression`Builder
*
* Closes the given expression builder, and returns the expression.
*
* You can only call this function once.
*
* Returns: (transfer full): the built expression
*/
GtkConstraintExpression *
gtk_constraint_expression_builder_finish (GtkConstraintExpressionBuilder *builder)
{
RealExpressionBuilder *rbuilder = REAL_EXPRESSION_BUILDER (builder);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.