okami.mom/ultraviolet
git clone https://git.nkp.pet/okami.mom/ultraviolet
2c67e98
main
1// Package casso implements a Cassowary constraint solver. 2// 3// Ported from github.com/lithdew/casso with unused API removed. 4package casso 5 6import "sync/atomic" 7 8type symbolKind uint8 9 10const ( 11external symbolKind = iota 12slack 13errorSym 14dummy 15) 16 17func (s symbolKind )restricted ()bool {return s == slack || s == errorSym } 18 19// Symbol is an opaque identifier for a variable in the solver. 20type Symbol uint64 21 22var ( 23count uint64 24zero Symbol 25) 26 27// New creates a new external symbol. 28func New ()Symbol {return next (external ) } 29 30func next (typ symbolKind )Symbol { 31return Symbol ((atomic .AddUint64 (& count ,1 )& 0x3fffffffffffffff )| (uint64 (typ )<< 62 )) 32} 33 34func (sym Symbol )kind ()symbolKind {return symbolKind (sym >> 62 ) } 35func (sym Symbol )isZero ()bool {return sym == zero } 36func (sym Symbol )restricted ()bool {return ! sym .isZero ()&& sym .kind ().restricted () } 37func (sym Symbol )external ()bool {return ! sym .isZero ()&& sym .kind ()== external } 38func (sym Symbol )isDummy ()bool {return ! sym .isZero ()&& sym .kind ()== dummy } 39 40// T creates a Term with the given coefficient. 41func (sym Symbol )T (coeff float64 )Term {return Term {coeff :coeff ,id :sym } } 42 43// Priority represents the strength of a constraint. 44type Priority float64 45 46// Op represents a constraint operator. 47type Op uint8 48 49const ( 50EQ Op = iota 51GTE 52LTE 53) 54 55// Constraint represents a linear constraint. 56type Constraint struct { 57op Op 58expr expr 59} 60 61// NewConstraint creates a new constraint. 62func NewConstraint (op Op ,constant float64 ,terms ... Term )Constraint { 63return Constraint {op :op ,expr :newExpr (constant ,terms ... )} 64} 65 66func (c Constraint )clone ()Constraint { 67return Constraint {op :c .op ,expr :c .expr .clone ()} 68} 69 70// Term represents a variable with a coefficient. 71type Term struct { 72coeff float64 73id Symbol 74} 75 76type expr struct { 77constant float64 78terms []Term 79} 80 81func newExpr (constant float64 ,terms ... Term )expr { 82return expr {constant :constant ,terms :terms } 83} 84 85func (c expr )clone ()expr { 86res := expr {constant :c .constant ,terms :make ([]Term ,len (c .terms ))} 87copy (res .terms ,c .terms ) 88return res 89} 90 91func (c expr )find (id Symbol )int { 92for i := 0 ;i < len (c .terms );i ++ { 93if c .terms [i ].id == id { 94return i 95 } 96 } 97return - 1 98} 99 100func (c * expr )delete (idx int ) { 101copy (c .terms [idx :],c .terms [idx + 1 :]) 102c .terms = c .terms [:len (c .terms )- 1 ] 103} 104 105func (c * expr )addSymbol (coeff float64 ,id Symbol ) { 106idx := c .find (id ) 107if idx == - 1 { 108if ! eqz (coeff ) { 109c .terms = append (c .terms ,Term {coeff :coeff ,id :id }) 110 } 111return 112 } 113c .terms [idx ].coeff += coeff 114if eqz (c .terms [idx ].coeff ) { 115c .delete (idx ) 116 } 117} 118 119func (c * expr )addExpr (coeff float64 ,other expr ) { 120c .constant += coeff * other .constant 121for i := 0 ;i < len (other .terms );i ++ { 122c .addSymbol (coeff * other .terms [i ].coeff ,other .terms [i ].id ) 123 } 124} 125 126func (c * expr )negate () { 127c .constant = - c .constant 128for i := 0 ;i < len (c .terms );i ++ { 129c .terms [i ].coeff = - c .terms [i ].coeff 130 } 131} 132 133func (c * expr )solveFor (id Symbol ) { 134idx := c .find (id ) 135if idx == - 1 { 136return 137 } 138 139coeff := - 1.0 / c .terms [idx ].coeff 140c .delete (idx ) 141 142if coeff == 1.0 { 143return 144 } 145 146c .constant *= coeff 147for i := 0 ;i < len (c .terms );i ++ { 148c .terms [i ].coeff *= coeff 149 } 150} 151 152func (c * expr )solveForSymbols (lhs ,rhs Symbol ) { 153c .addSymbol (- 1.0 ,lhs ) 154c .solveFor (rhs ) 155} 156 157func (c * expr )substitute (id Symbol ,other expr ) { 158idx := c .find (id ) 159if idx == - 1 { 160return 161 } 162coeff := c .terms [idx ].coeff 163c .delete (idx ) 164c .addExpr (coeff ,other ) 165} 166 167func eqz (val float64 )bool { 168if val < 0 { 169return - val < 1.0e-8 170 } 171return val < 1.0e-8 172}