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. ψTableConstraintsImpl.Mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Rick Beach, February 19, 1985 10:51:39 am PST Solve row constraints first Determine the box positions Solve column constraints next Determine the box positions GenerateRowConstraints: PROC [table: TableBase.RefTable] ~ { GenerateRowConstraint: 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[[0.5, gridBottom]], LinearSolver.C[[0.5*(extents[down].texPts-extents[up].texPts), table.tableau.unity]], LinearSolver.C[[0.5, gridTop]], LinearSolver.C[[-1, 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; }; IF doItTheLongWay THEN TableBase.EnumerateByRows[table, GenerateRowConstraint] ELSE { DetermineTheMaxs; Enumerate the grid equations... }; }; GenerateColumnConstraints: PROC [table: TableBase.RefTable] ~ { GenerateColumnConstraint: 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]]; colNumber: ROPE ~ Convert.RopeFromInt[box.left*1000 + box.right]; colX: LinearSolver.Unknown ~ LookUpUnknown[table.tableau, Rope.Concat["c", colNumber]]; 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]; SELECT box.colAlignment FROM flushLeft => { LinearSolver.AssertZero3[table.tableau, 1,gridLeft, extents[left].texPts,table.tableau.unity, -1,colX]; LinearSolver.AssertGEZero3[table.tableau, 1,gridRight, -(extents[right].texPts),table.tableau.unity, -1,colX]; }; flushRight => { LinearSolver.AssertZero3[table.tableau, 1,colX, extents[right].texPts,table.tableau.unity, -1,gridRight]; LinearSolver.AssertGEZero3[table.tableau, 1,colX, -(extents[left].texPts),table.tableau.unity, -1,gridLeft]; }; center => { LinearSolver.AssertGEZero3[table.tableau, 1,colX, -(extents[left].texPts),table.tableau.unity, -1,gridLeft]; LinearSolver.AssertGEZero3[table.tableau, 1,gridRight, -(extents[right].texPts),table.tableau.unity, -1,colX]; LinearSolver.AssertZero3[table.tableau, 1.0,gridLeft, 1.0,gridRight, -2,colX]; }; charAlign => { 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]; }; 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; }; IF doItTheLongWay THEN TableBase.EnumerateByRows[table, GenerateColumnConstraint] ELSE { LeftRight: TYPE ~ RECORD[left, right: TableBase.GridNumber, alignment: TableBase.HorizontalAlignment, leftExtent, rightExtent: TSTypes.Dimn]; MaxLeftRight: TableBase.EnumeratedEntryProc ~ { WITH entry SELECT FROM box: TableBase.RefTableBox => { column: ROPE ~ Rope.Concat[SELECT box.colAlignment FROM flushLeft => "L", flushRight => "R", center => "C", ENDCASE => "C", Convert.RopeFromInt[box.left*1000 + box.right]]; extents: TSTypes.Dimensions _ TableLayout.AlignExtents[table, box]; val: SymTab.Val; max: REF LeftRight; found: BOOLEAN; [found, val] _ SymTab.Fetch[leftRightSymTab, column]; IF found THEN { max _ NARROW[val]; max.leftExtent _ max.leftExtent.MaxDimn[extents[left]]; max.rightExtent _ max.rightExtent.MaxDimn[extents[right]]; } ELSE [] _ SymTab.Insert[leftRightSymTab, column, NEW[LeftRight _ [box.left, box.right, box.colAlignment, extents[left], extents[right]]]]; }; ENDCASE => NULL; }; GenerateNewColumnConstraint: SymTab.EachPairAction ~ { PROC [key: SymTab.Key, val: SymTab.Val] RETURNS [quit: BOOL]; max: REF LeftRight ~ NARROW[val]; gridColumn: LinearSolver.Unknown ~ LookUpUnknown[table.tableau, Rope.Concat["c", Convert.RopeFromInt[max.left*1000 + max.right]]]; gridLeft: LinearSolver.Unknown ~ LookUpUnknown[table.tableau, Rope.Concat["gx", Convert.RopeFromInt[max.left]]]; gridRight: LinearSolver.Unknown ~ LookUpUnknown[table.tableau, Rope.Concat["gx", Convert.RopeFromInt[max.right]]]; SELECT max.alignment FROM flushLeft => { LinearSolver.AssertZero3[table.tableau, 1,gridLeft, max.leftExtent.texPts,table.tableau.unity, -1,gridColumn]; LinearSolver.AssertGEZero3[table.tableau, 1,gridRight, -(max.rightExtent.texPts),table.tableau.unity, -1,gridColumn]; }; flushRight => { LinearSolver.AssertZero3[table.tableau, 1,gridColumn, max.rightExtent.texPts,table.tableau.unity, -1,gridRight]; LinearSolver.AssertGEZero3[table.tableau, 1,gridColumn, -(max.leftExtent.texPts),table.tableau.unity, -1,gridLeft]; }; center => { LinearSolver.AssertGEZero3[table.tableau, 1,gridRight, -(max.leftExtent.texPts+max.rightExtent.texPts),table.tableau.unity, -1,gridLeft]; LinearSolver.AssertZero[table.tableau, LIST[ LinearSolver.C[[1, gridLeft]], LinearSolver.C[[max.leftExtent.texPts-max.rightExtent.texPts, table.tableau.unity]], LinearSolver.C[[1, gridRight]], LinearSolver.C[[-2, gridColumn]]]]; }; ENDCASE => ERROR TableBase.UnimplementedCase; }; leftRightSymTab: SymTab.Ref _ SymTab.Create[101]; TableBase.EnumerateByRows[table, MaxLeftRight]; [] _ SymTab.Pairs[leftRightSymTab, GenerateNewColumnConstraint] }; }; doItTheLongWay: BOOLEAN _ TRUE; Κ w˜™Jšœ Οmœ1™