@mark1russell7/layout-contract
v0.3.2
Published
The shared contract of the packing and highways layout engines: the input and record formats, the turn rule, margins, tolerances and hard rules.
Maintainers
Readme
@mark1russell7/layout-contract
The shared contract of two layout engines: packing places boxes, and highways routes the edges between them. Neither engine depends on the other. Both use this contract, so a placement and a routing compose.
The package has one runtime dependency: @mark1russell7/rigor-generators, the home of the seeded generator mulberry32.
The contents
| Part | Exports |
|---|---|
| Geometry | Point, Rect, Region, Side, Sides, Margin, marginSides, grow, boundsOf, regionArea, translate, overlapOf |
| The shape kinds | ShapeKind, SHAPE_KINDS, SHAPE_KIND_IDS, ShapeKindSpec, ShapeGeometry, DEFAULT_SHAPES, ShapeSupport, ShapeBound, RuleLevel, ShapeLevel, ShapeCheck, isShapeKind, shapeKindOf, shapeKindsOf, itemShapeOf, shapeKindProblem, shapesOf, ruleLevel, shapeLevel, shapeSupportProblems, boxArea, checkShapes |
| The input layout-input/1 | LayoutInput, LayoutBox (Item for the packer), Port, portPoint, LayoutEdge, LayoutContainer, Obstacle, LayoutCell, LayoutGenerator, PairGap, canonicalInput |
| The packer | PackInput, PackLink, toPackInput, packLinks, Placement, PackOutput, StageTrace, applyPack |
| The record layout-record/1 | LayoutRecord, Stage, Supports, RunFacts, RunEnv, toLayoutRecord, checkLayoutRecord, parseLayoutRecord |
| The strategies | StrategyInfo |
| The measures | MeasureSpec, Direction, JointMeasureId, JOINT_MEASURES, JOINT_MOVED_MIN, Verdict, compareMeasure, minEffectOf |
| The balance and stability measures | balanceOf, Balance, nearestGaps, procrustesOf, ProcrustesOptions, perChange, balanceMeasures, balanceMeasureSpecs, BALANCE_MEASURE_SUFFIXES, BalanceMeasureSuffix, BALANCE_SIDE_DEPTH, PlacedBox |
| Text layout, in the subpath /text | layoutText, TextLayout, TextLayoutOptions, createMeasurer, TextMeasurer, canvasAdvance, AdvanceFn, fontKey, graphemesOf, textMeasures, TEXT_MEASURES, TEXT_UNITS |
| The edges step | edgeStep, EdgeShape, EdgeStepParams, EDGE_DENSITY, EDGE_STEP_VERSION |
| The random numbers | mulberry32, fnv1a32, stepRandom, randomInt |
| The hashes | sha256Hex, canonicalJson, documentHash, outputHash, HashOptions |
| The promotion guards | outputGroups, OutputGroup, exercised, ExerciseEvidence |
| The portfolio | portfolio, Portfolio, PortfolioKey, PortfolioLevel, PortfolioOptions, PortfolioPick, PortfolioTrace, Member, MemberTrace, MemberStatus, pickMoves |
| The pick rule | selectBest, SelectCandidate, SelectLevel, Selection, PickSpec |
| The corpus checks | ClaimBreak, checkDeclared, declaredCounts, declaredClaimOf, DeclaredClaim, Declares, corpusHashOf, CorpusEntry |
| The families | familyOf, FamilyBy, FamilyCell, FAMILY_ANY_KIND |
| The verdict | verdict, VerdictOptions, VerdictResult, VerdictRecord, VerdictSide, VerdictInterval, FamilyVerdict, VerdictPermutation, VerdictSignTest, VerdictLabel, VerdictScope, VerdictBreadth, VERDICT_EXACT_MAX, VERDICT_EXACT_CAP, VERDICT_RUNS, VERDICT_DRAWS, VERDICT_SEED |
| The split files | checkSplit, splitFolds, leaveOneSeedOut, splitFileName, SPLIT_SCHEMA, CorpusSplit, SplitFold, SplitCorpus |
| The strategy space | StrategySpace, SpaceStage, StageOption, OptionSupports, ShapeFilter, SpaceParam, ParamWhen, MemberRule, SpaceConstraint, OptionRef, StrategyConfig, StageChoice, ParamKind, ParamValue, STRATEGY_SPACE_SCHEMA |
| The space functions | checkSpace, checkConfig, canonicalConfig, configId, spaceSize, spaceShapeKinds, paramLevels, enumerateSpace, productSpace, joinConfigs, splitConfig, SpaceSize, SpaceSizeOptions, EnumerateOptions, GridOptions, SampleOptions |
| The turn | turnBox, turnPort, turnMargin, turnRegion, turnSide, turnPoint |
| The tolerances | EPS, RECORD_EPS, RECORD_SCALE, Tolerance, DEFAULT_TOLERANCE |
| The hard rules | countOverlaps, countObstacleHits, regionHitsRect, rectInRegion, countOutside, ContainerTest, countPortsOffBorder, packHard, PackHard, PACK_HARD_RULES, placedRect, checkInput |
The rules
- The turn. A turn is 90 degrees clockwise, with the y axis down. A point (
px,py) of a box of heighthgoes to (h - py,px). Each side moves one step clockwise. The router gets the turned box and ports, and does not readturn. - The margin. A margin is a ring around a box. No other box and no route enters it. A route from a port of the box crosses the ring at a right angle.
- The gap. The gap is the free space between two boxes with their margins. Routes use it. Two boxes are
mA + gap + mBapart. - The pair gaps.
pairGapsgives a minimum distance to some pairs of boxes:{ a, b, gap, lanes? }. For its pair, thegapof an entry replacesmA + gap + mB.- The order of
aandbhas no meaning. A pair without an entry keeps its margins and the globalgap. lanesis the count of the channels that the gap has space for. It is information only.checkInputrefuses an unknown box, a pair of one box, a repeated pair in either order, a negative or infinitegapand badlanes.canonicalInputputsabeforebin each pair and sorts the list.documentHashuses this form, so an input withoutpairGapskeeps its hash.- The hard rule
no-overlapreadspairGaps. For a pair of the list, in either order, thegapreplaces the two margins. The pair breaks the rule only when the boxes are nearer than the gap. - The pairs that are not in the list keep their margins. Without
pairGaps, the verdicts and the hashes of the records do not change.
- The order of
- The ports. A port can have a side. Without a side, the router picks the side. A fixed port has
xandyon the border of the box, relative to its top-left corner.- A port with
sideandalongis fixed at a fraction of its side.alongis a number from 0 to 1, from the start of the side. - The start of
leftandrightis the top end. The start oftopandbottomis the left end.countPortsOffBorderuses the same start forxandy. checkInputrefusesalongwithout a side, a value that is not a finite number from 0 to 1, andalongwithxory.portPoint(box, port)gives the point of a port, relative to the top-left corner of the box. A port without a fixed point givesundefined, because the router picks the point.- A turn changes
alongofleftandrightto1 - along, because the start of the side moves to its other end.alongoftopandbottomstays. - An input without
alongkeeps its hash.
- A port with
- The hard rules of a pack.
no-overlapcounts the pairs of boxes and the pairs of a box and an obstacle. A pair ofpairGapsuses its gap in place of the margins. A locked box without a placement, or with a move of more thanRECORD_EPS, breakslocked-kept.checkInputrefuses a locked box without a position. Another box without a placement and not inoverflowbreakscomplete. - The container rule.
in-containercounts each box that goes out of the container made smaller byinset. The box counts with its margin. By default, a shaped container counts as its bounding box. - The exact container. Give
{ exactContainer: true }topackHardorcountOutside. Then a box of a shaped container with the sizefixedmust stay inside the shape. A cut corner, a notch and a hole count. A container with a free side keeps the bounding test. The default changes to the exact test at the next breaking version. - The shape kinds. An item is a
rect, apolygon, acircleor afreeshape. Each measure and rule declares its kinds.checkShapesrefuses the other kinds.docs/SHAPES.mdtells the rules.regionArea(region)gives the exact area of a region.boxArea(box)gives the exact area of a box, orundefinedfor afreebox. A box with an ellipse shape isfree.ShapeSupport.safelists the kinds with a safe count: an upper bound that does not miss a break.ruleLevel(rule, kind)givesexact,safeornone.no-overlapandin-containerare safe onpolygon,circleandfree.checkShapesaccepts a safe kind only with{ level: "safe" }.MeasureSpec.boundlists the kinds where the value of a measure is a bound of the true value, with its sideupperorlower.shapeLevel(use, kind)givesexact,safe,boundornone.checkShapesaccepts a bound kind only with{ level: "bound" }. The levelsaferefuses it.- A bound value proves only one side of a compare.
docs/SHAPES.mdtells what it proves for eachdirection. shapeSupportProblems(uses)refuses a kind in two of the listsshapes,safeandbound.shapes.MemberRule.view: "bounds"gives the members of a meta option the bounding box of each item. A shape filter then checks the members withrect.- A sample with a shape filter skips a meta option without a member list. It throws a
RangeErroronly when the space has no config for the kinds.
- The corpus dimensions.
CorpusDimension.precisionis the count of decimal places of a numeric value of a family. The registry rounds the value and the default to it before theinvalidatescompare.docs/CORPUS.mdtells the rules. - The output hash.
outputHashgives the first 16 hex characters of the SHA-256 of the canonical JSON of an output. Each number goes to the grid ofRECORD_EPSfirst. - The corpus checks.
checkDeclaredandcheckSplitgive a list ofClaimBreak. An empty list tells that each claim is true.corpusHashOfgives the corpus hash ofpacking. - The verdict.
verdictcompares two strategies on one measure, with the family as the unit. A verdict counts only when it holds for the mean of the family means and for the mean of the inputs. - The record. A run writes one
layout-record/1line of JSON Lines. The formats of the engines tell the fields. These rules are new in 0.3.0:deterministicistruewhen two runs with the same seed give the same output. A skipped record hasnull, because no run made a claim.- A record without
skippedhas a booleandeterministic.checkLayoutRecordrefusesnullon it. - An old skipped record has
deterministic: true.checkLayoutRecordaccepts it, andparseLayoutRecordgivesnullin its place. envgives the computer of the run:node,os,arch,runner,cpuandcpus. A timing record also givesmode, and it can givecontext.env.modeis the mode of the timing, for exampleprocessorfreshofpaired-time/1.env.contextisciorlocal, with the Node flags.checkLayoutRecord(value)gives the problems of one record.parseLayoutRecord(value)throws aTypeErrorwith them. Both accept fields that the format does not know.
- The tolerances.
EPS(1e-6) is for the float compares in an engine.RECORD_EPS(1e-3) is for the compares on a written file. A record writes the tolerance of each hard rule in its fieldtolerance. The defaults areoverlap0.001andthrough0.5.
An example
import { applyPack, packHard, toPackInput, type LayoutInput } from "@mark1russell7/layout-contract";
const input: LayoutInput = {
schema: "layout-input/1",
id: "example",
container: { w: 200, fixed: "width" },
gap: 4,
boxes: [{ id: "a", w: 40, h: 20, margin: 2 }],
};
const output = myPacker(toPackInput(input));
const placed = applyPack(input, output);
const hard = packHard(input, output);The docs
The comments of the source name each doc as docs/<NAME>.md. The docs are in the repository, not in the npm package:
| Doc | The subject |
|---|---|
| docs/BALANCE.md | The balance and stability measures of a pack and of a joint layout |
| docs/TEXT.md | The text layout of the subpath /text: the rules, the units and the measures |
| docs/CORPUS.md | The shared corpus registry, its dimensions and families |
| docs/CORPUS-CHECKS.md | The corpus checks and the split files |
| docs/JOINT-CORPUS.md | The joint corpus |
| docs/JOINT-MEASURES.md | The joint measures |
| docs/PORTFOLIO.md | The portfolio and its pick rule |
| docs/PROMOTION.md | The promotion guards |
| docs/SHAPES.md | The shape kinds, the levels of a rule and what a bound value proves |
| docs/STRATEGY-SPACE.md | The strategy space |
| docs/VERDICT.md | The verdict over families |
The formats are in docs/FORMAT.md of packing and docs/LAYOUT-RECORDS.md of highways. The TSDoc of ShapeBound also has the table of what a bound value proves.
