php-tui/cassowary

Cassowary 约束求解算法实现

0.1.0 2023-10-23 16:11 UTC

This package is auto-updated.

Last update: 2024-09-11 10:24:26 UTC


README

CI

Cassowary 约束求解算法的实现。在大量借鉴 cassowary-rs 的基础上,而 cassowary-rs 又是基于 kiwi 开发的。

此库可用于指定和解决用户界面的约束。

状态

我只将足够的代码移植以支持求解约束。我没有移植对编辑变量或更改约束的支持。欢迎PR。

安装

$ composer require phptui/cassowary

它做什么?

假设我们想在定义大小的屏幕上渲染布局。布局有两个部分

+-------+-------------------+
|   A   |         B         |
+-------+-------------------+

我们需要为部分 ab 中的每个点引入变量

       0                           30

       ax1     ax2,bx1             bx2
0  y1  +-------+-------------------+
       |       |                   |
2  y2  +-------+-------------------+

然后指定必须保持的约束

ax1 = 0         // the left-most point is CONSTANT at 0
ax2 >= ax1      // ax2 is REQUIRED to be greater than equal to ax1
ax2 >= ax1 + 10 // ax2 must have a WEAK requirement to be greater than equal to ax1 plus 10
bx1 = ax2       // bx1 and bx2 are REQUIRED to be contiguous
bx2 = 30        // bx2 is REQUIRED be at the right-most point - 30
// etc

有两件有趣的事情

  • 约束可以相互关联
  • 约束有 强度,这决定了在存在冲突时考虑哪个约束。

约束求解器能够将这些约束解决为最优解。

用法

使用上述示例

<?php
require __DIR__ . '/vendor/autoload.php';

use PhpTui\Cassowary\AddConstraintaintError;
use PhpTui\Cassowary\Constraint;
use PhpTui\Cassowary\RelationalOperator;
use PhpTui\Cassowary\Solver;
use PhpTui\Cassowary\Strength;
use PhpTui\Cassowary\Variable;

$ax1 = Variable::new();
$ax2 = Variable::new();
$bx1 = Variable::new();
$bx2 = Variable::new();
$y1 = Variable::new();
$y2 = Variable::new();

$s = Solver::new();
$s->addConstraints([
    Constraint::equalTo($ax1, 0.0, Strength::REQUIRED),
    Constraint::greaterThanOrEqualTo($ax2, $ax1, Strength::REQUIRED),
    Constraint::greaterThanOrEqualTo($ax2, $ax1->add(10.0), Strength::WEAK),
    Constraint::equalTo($bx1, $ax2, Strength::REQUIRED),
    Constraint::equalTo($bx2, 30.0, Strength::REQUIRED),
    Constraint::equalTo($y1, 0.0, Strength::REQUIRED),
    Constraint::equalTo($y2, 3.0, Strength::REQUIRED),
]);
$changes = $s->fetchChanges();
var_dump($changes->getValue($ax2)); // 10
var_dump($changes->getValue($bx1);  // 10
var_dump($changes->getValue($bx2)); // 30
var_dump($changes->getValue($y2));  // 3

注意 $changes 只包含已更改的值,并且默认情况下变量从 0.0 开始。此API更适用于变量可以更新时。

它是如何工作的?

我不知道,但它确实做到了!我只是带着极大的决心将代码移植并调试,直到它工作。

您可以在这里阅读论文。