<> <> <> DIRECTORY Convert, LinearSolver, SymTab, Rope, TableBase, TableConstraints, TableLayout, TSTypes; TableConstraintsImpl: CEDAR PROGRAM IMPORTS Convert, LinearSolver, SymTab, Rope, TableBase, TableLayout, TSTypes EXPORTS TableConstraints = BEGIN ROPE: TYPE = Rope.ROPE; constraintSymTab: SymTab.Ref; SolveConstraints: PUBLIC PROCEDURE [table: TableBase.RefTable] = { <> constraintSymTab _ SymTab.Create[101]; table.tableau _ LinearSolver.Init[]; IF table.rowConstraints # NIL THEN EstablishConstraints[table, table.rowConstraints]; TableBase.EnumerateByRows[table, GenerateRowConstraints]; IF NOT LinearSolver.Satisfiable[table.tableau] THEN ERROR TableBase.ImplementationError["Unsatisifiable row constraints"]; table.rowGridPositions _ NEW[TableBase.GridVector[table.rowGrids+1]]; FOR i: TableBase.GridNumber IN [0..table.rowGrids] DO table.rowGridPositions.grid[i] _ TSTypes.Pt[LinearSolver.Solution[table.tableau, LookUpUnknown[table.tableau, Rope.Concat["gy", Convert.RopeFromInt[i]]]]]; ENDLOOP; <> { SetBoxY: TableBase.EnumeratedEntryProc ~ { WITH entry SELECT FROM box: TableBase.RefTableBox => { boxNumber: ROPE ~ Convert.RopeFromInt[box.left*1000 + box.top]; box.y _ TSTypes.Pt[LinearSolver.Solution[table.tableau, LookUpUnknown[table.tableau, Rope.Concat["y", boxNumber]]]]; box.y _ box.y.SubDimn[box.yOffset]; }; ENDCASE; }; TableBase.EnumerateByRows[table, SetBoxY]; }; <<>> <> constraintSymTab _ SymTab.Create[101]; table.tableau _ LinearSolver.Init[]; IF table.colConstraints # NIL THEN EstablishConstraints[table, table.colConstraints]; TableBase.EnumerateByRows[table, GenerateColumnConstraints]; IF NOT LinearSolver.Satisfiable[table.tableau] THEN ERROR TableBase.ImplementationError["Unsatisifiable column constraints"]; table.colGridPositions _ NEW[TableBase.GridVector[table.columnGrids+1]]; FOR i: TableBase.GridNumber IN [0..table.columnGrids] DO table.colGridPositions.grid[i] _ TSTypes.Pt[LinearSolver.Solution[table.tableau, LookUpUnknown[table.tableau, Rope.Concat["gx", Convert.RopeFromInt[i]]]]]; ENDLOOP; <> { SetBoxX: TableBase.EnumeratedEntryProc ~ { WITH entry SELECT FROM box: TableBase.RefTableBox => { boxNumber: ROPE ~ Convert.RopeFromInt[box.left*1000 + box.top]; box.x _ TSTypes.Pt[LinearSolver.Solution[table.tableau, LookUpUnknown[table.tableau, Rope.Concat["x", boxNumber]]]]; box.x _ box.x.AddDimn[box.xOffset]; }; ENDCASE; }; TableBase.EnumerateByRows[table, SetBoxX]; }; }; EstablishConstraints: PROC [table: TableBase.RefTable, constraintList: LIST OF TableBase.RefConstraint] ~ { FOR c: LIST OF TableBase.RefConstraint _ constraintList, c.rest WHILE c # NIL DO lsConstraint: LinearSolver.Constraint; FOR l: LIST OF TableBase.Coefficient _ c.first.coefficients, l.rest WHILE l # NIL DO unknown: LinearSolver.Unknown ~ IF l.first.unknown.IsEmpty THEN table.tableau.unity ELSE LookUpUnknown[table.tableau, l.first.unknown]; lsConstraint _ CONS[NEW[LinearSolver.LinearMonomial _ [l.first.coefficient, unknown]], lsConstraint]; ENDLOOP; IF lsConstraint = NIL THEN LOOP; IF c.first.equality THEN LinearSolver.AssertZero[table.tableau, lsConstraint] ELSE LinearSolver.AssertGEZero[table.tableau, lsConstraint]; ENDLOOP; }; GenerateRowConstraints: TableBase.EnumeratedEntryProc = { WITH entry SELECT FROM box: TableBase.RefTableBox =>{ boxNumber: ROPE ~ Convert.RopeFromInt[box.left*1000 + box.top]; boxY: LinearSolver.Unknown ~ LookUpUnknown[table.tableau, Rope.Concat["y", boxNumber]]; gridTop: LinearSolver.Unknown ~ LookUpUnknown[table.tableau, Rope.Concat["gy", Convert.RopeFromInt[box.top]]]; gridBottom: LinearSolver.Unknown ~ LookUpUnknown[table.tableau, Rope.Concat["gy", Convert.RopeFromInt[box.bottom]]]; extents: TSTypes.Dimensions _ TableLayout.AlignExtents[table, box]; SELECT box.rowAlignment FROM flushTop => { LinearSolver.AssertZero3[table.tableau, 1,boxY, extents[up].texPts,table.tableau.unity, -1,gridTop]; LinearSolver.AssertGEZero3[table.tableau, 1,boxY, -(extents[down].texPts),table.tableau.unity, -1,gridBottom]; }; flushBottom => { LinearSolver.AssertZero3[table.tableau, 1,gridBottom, extents[down].texPts,table.tableau.unity, -1,boxY]; LinearSolver.AssertGEZero3[table.tableau, 1,gridTop, -(extents[up].texPts),table.tableau.unity, -1,boxY]; }; center => { LinearSolver.AssertGEZero3[table.tableau, 1,gridTop, -(extents[down].texPts+extents[up].texPts),table.tableau.unity, -1,gridBottom]; LinearSolver.AssertZero[table.tableau, LIST[ LinearSolver.C[[1.0, gridBottom]], LinearSolver.C[[extents[down].texPts-extents[up].texPts, table.tableau.unity]], LinearSolver.C[[1.0, gridTop]], LinearSolver.C[[-2.0, boxY]]]]; }; topBaseline, bottomBaseline, centerOnTopBaseline, centerOnBottomBaseline => { rowNumber: ROPE ~ Convert.RopeFromInt[box.top*1000 + box.bottom]; rowY: LinearSolver.Unknown ~ LookUpUnknown[table.tableau, Rope.Concat["r", rowNumber]]; LinearSolver.AssertZero2[table.tableau, 1,rowY, -1,boxY]; LinearSolver.AssertGEZero2[table.tableau, 1,rowY, -1,gridBottom]; LinearSolver.AssertGEZero3[table.tableau, 1,rowY, -(extents[down].texPts),table.tableau.unity, -1,gridBottom]; LinearSolver.AssertGEZero3[table.tableau, 1,gridTop, -(extents[up].texPts),table.tableau.unity, -1,rowY]; }; ENDCASE => ERROR TableBase.UnimplementedCase; IF NOT LinearSolver.Satisfiable[table.tableau] THEN ERROR TableBase.ImplementationError["Unsatisifiable constraints"] }; rule: TableBase.RefTableRule => NULL; background: TableBase.RefTableBackground => NULL; ENDCASE => ERROR; }; GenerateColumnConstraints: TableBase.EnumeratedEntryProc = { WITH entry SELECT FROM box: TableBase.RefTableBox =>{ boxNumber: ROPE ~ Convert.RopeFromInt[box.left*1000 + box.top]; boxX: LinearSolver.Unknown ~ LookUpUnknown[table.tableau, Rope.Concat["x", boxNumber]]; gridLeft: LinearSolver.Unknown ~ LookUpUnknown[table.tableau, Rope.Concat["gx", Convert.RopeFromInt[box.left]]]; gridRight: LinearSolver.Unknown ~ LookUpUnknown[table.tableau, Rope.Concat["gx", Convert.RopeFromInt[box.right]]]; extents: TSTypes.Dimensions _ TableLayout.AlignExtents[table, box]; IF box.alignOnChar THEN { -- oh, what a crock colNumber: ROPE ~ Convert.RopeFromInt[box.left*1000 + box.right]; colX: LinearSolver.Unknown ~ LookUpUnknown[table.tableau, Rope.Concat["c", colNumber]]; LinearSolver.AssertZero2[table.tableau, 1,colX, -1,boxX]; LinearSolver.AssertGEZero2[table.tableau, 1,colX, -1,gridLeft]; LinearSolver.AssertGEZero3[table.tableau, 1,colX, -(extents[left].texPts),table.tableau.unity, -1,gridLeft]; LinearSolver.AssertGEZero2[table.tableau, 1,gridRight, -1,colX]; LinearSolver.AssertGEZero3[table.tableau, 1,gridRight, -(extents[right].texPts),table.tableau.unity, -1,colX]; } ELSE SELECT box.colAlignment FROM flushLeft => { LinearSolver.AssertZero3[table.tableau, 1,gridLeft, extents[left].texPts,table.tableau.unity, -1,boxX]; LinearSolver.AssertGEZero3[table.tableau, 1,gridRight, -(extents[right].texPts),table.tableau.unity, -1,boxX]; }; flushRight => { LinearSolver.AssertZero3[table.tableau, 1,boxX, extents[right].texPts,table.tableau.unity, -1,gridRight]; LinearSolver.AssertGEZero3[table.tableau, 1,boxX, -(extents[left].texPts),table.tableau.unity, -1,gridLeft]; }; center => { LinearSolver.AssertGEZero3[table.tableau, 1,gridRight, -(extents[left].texPts+extents[right].texPts),table.tableau.unity, -1,gridLeft]; LinearSolver.AssertZero[table.tableau, LIST[ LinearSolver.C[[1.0, gridLeft]], LinearSolver.C[[extents[left].texPts-extents[right].texPts, table.tableau.unity]], LinearSolver.C[[1.0, gridRight]], LinearSolver.C[[-2.0, boxX]]]]; }; ENDCASE => ERROR TableBase.UnimplementedCase; IF NOT LinearSolver.Satisfiable[table.tableau] THEN ERROR TableBase.ImplementationError["Unsatisifiable constraints"] }; rule: TableBase.RefTableRule => NULL; background: TableBase.RefTableBackground => NULL; ENDCASE => ERROR; }; LookUpUnknown: PROCEDURE [tableau: LinearSolver.Tableau, name: ROPE] RETURNS [v: LinearSolver.Unknown] = { found: BOOLEAN; val: REF; [found, val] _ SymTab.Fetch[constraintSymTab, name]; IF found THEN v _ NARROW[val, LinearSolver.Unknown] ELSE { v _ LinearSolver.NewUnknown[tableau, name]; LinearSolver.Restrict[tableau, v]; [] _ SymTab.Insert[constraintSymTab, name, v] }; }; END. <> <> <> <{>> <> <> <> <> <> <> < {>> <> <> <<};>> < {>> <> <> <<};>> <
{>> <> <> <> <<};>> < {>> <> <> <> <> <> <> <> <<};>> < ERROR TableBase.UnimplementedCase;>> <> <> <<};>> < NULL;>> < NULL;>> < ERROR;>> <<};>> <> <> <> <> <> < {>> <> < "L", flushRight => "R", center => "C", ENDCASE => "C", Convert.RopeFromInt[box.left*1000 + box.right]];>> <> <> <> <> <<[found, val] _ SymTab.Fetch[leftRightSymTab, column];>> <> <> <> <> <<}>> <> <<[] _ SymTab.Insert[leftRightSymTab, column, NEW[LeftRight _ [box.left, box.right, box.colAlignment, extents[left], extents[right]]]];>> <<};>> < NULL;>> <<};>> <> <> <> <> <> <> <