@mark1russell7/highways 0.9.2 → 0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -1
- package/build/index.d.ts +466 -5
- package/build/index.d.ts.map +1 -1
- package/build/index.js +8119 -5058
- package/build/index.js.map +1 -1
- package/package.json +1 -1
- package/src/bench/screen/exercise.ts +2 -0
- package/src/bench/screen/set.ts +58 -1
- package/src/families/cases.ts +17 -9
- package/src/families/coverage.ts +502 -0
- package/src/families/index.ts +4 -1
- package/src/highways/bronchial/index.ts +144 -0
- package/src/highways/index.ts +2 -0
- package/src/highways/knee/index.ts +154 -0
- package/src/highways/knee/root.ts +19 -0
- package/src/index.ts +4 -0
- package/src/levels/venation/index.ts +191 -0
- package/src/plugs/fix.ts +112 -0
- package/src/plugs/justify.ts +66 -0
- package/src/plugs/row-cards.ts +46 -0
- package/src/plugs/side.ts +23 -2
- package/src/plugs/spread/index.ts +217 -0
- package/src/routers/annealing/index.ts +260 -0
- package/src/routers/corners.ts +3 -39
- package/src/routers/frames.ts +80 -16
- package/src/routers/gutter.ts +545 -0
- package/src/routers/index.ts +5 -2
- package/src/routers/shared.ts +40 -2
- package/src/routers/tight/index.ts +122 -0
- package/src/strategies/builtins.ts +87 -2
- package/src/strategies/schemas.ts +76 -0
- package/src/whole/portfolio/index.ts +108 -0
package/README.md
CHANGED
|
@@ -49,6 +49,40 @@ const node = { id: "a", box: { x: 0, y: 0, w: 80, h: 40 }, ports: [{ id: "out",
|
|
|
49
49
|
// The plug "out" is at (80, 10). With h = 120, it is at (80, 30).
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
### Plug rules and fixed ports
|
|
53
|
+
|
|
54
|
+
A plug rule is a strategy of the step `plugs`. It places the free plugs of each edge. A fixed plug stays at its point.
|
|
55
|
+
|
|
56
|
+
| Rule | The place of each free plug |
|
|
57
|
+
|---|---|
|
|
58
|
+
| `facing` | The plug faces the other end of its edge. It is the default of the router `corners`. |
|
|
59
|
+
| `side` | The search of the route starts from the whole free side. The plug goes where the way leaves the side (WILD-001). |
|
|
60
|
+
| `justify` | The plugs of `facing`, then the plugs of each side keep their order and the gap `plugGap` (WILD-002). |
|
|
61
|
+
| `spread` | The plugs of each wall share the room of the wall, with the gap `plugGap`, in the order of their far ends. |
|
|
62
|
+
|
|
63
|
+
- `side` gives the plugs of `corners` with `plugs: "side"`. `justify` gives the plugs of `corners` with the same `plugGap`.
|
|
64
|
+
- `spread` keeps the room of a wall free of the corner insets (`inset`) and of the fixed plugs on the wall.
|
|
65
|
+
- When the room is too small for the gap, the gap shrinks evenly. No plug drops.
|
|
66
|
+
- The order on the wall keeps the order of the far ends, so the straight lines of two plugs do not cross at the wall.
|
|
67
|
+
- The ends of one port share one plug. The option `rounds` sorts each wall again by the new places of the far ends.
|
|
68
|
+
- The option `plug` of `corners` takes a plug rule. The other routers place the plugs as `facing` does.
|
|
69
|
+
|
|
70
|
+
`fixPorts(graph, rule, options?)` runs a plug rule, and gives each free port a fixed `at` and a `side` from the plugs of the rule. Then each router keeps those plugs.
|
|
71
|
+
|
|
72
|
+
- The rule is a plug strategy, or the name of one in `STRATEGIES` (or in the option `registry`). `plugOptions` gives its options.
|
|
73
|
+
- A fixed port keeps its values, and a port of no edge stays free. A port of several ends takes the plug of its first end.
|
|
74
|
+
- An end without a port stays free. With `newPorts: true`, it gets a new fixed port with the id `<edge id>:source` or `<edge id>:target`.
|
|
75
|
+
- The output is a new graph. The function does not change the input.
|
|
76
|
+
- The routes of `corners` on the output are the routes of `corners` with the option `plug` on the input.
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { fixPorts, sectionsRouter } from "@mark1russell7/highways";
|
|
80
|
+
|
|
81
|
+
// The rows of each card get plugs on the walls with at least 8 px between two plugs. Then `sections` routes between them.
|
|
82
|
+
const fixed = fixPorts(graph, "spread", { plugOptions: { plugGap: 8 } });
|
|
83
|
+
const result = sectionsRouter({ name: "sections" }).route(fixed);
|
|
84
|
+
```
|
|
85
|
+
|
|
52
86
|
### Frames
|
|
53
87
|
|
|
54
88
|
A node can name a frame node in `parent`. A frame is a node that holds other nodes, for example a card that holds rows.
|
|
@@ -65,6 +99,16 @@ A node can name a frame node in `parent`. A frame is a node that holds other nod
|
|
|
65
99
|
- `throw` (the default) throws a `RangeError`.
|
|
66
100
|
- `skip` gives no route to the edges of that node.
|
|
67
101
|
- `clamp` cuts the box to the bounds of the frame.
|
|
102
|
+
- The option `inner` sets the mode of the inner routes:
|
|
103
|
+
- `corners` (the default) finds each route in the corner graph, as above.
|
|
104
|
+
- `gutter` gives orthogonal routes in the gaps between the nodes and in the strips at the walls.
|
|
105
|
+
- In the mode `gutter`, a route uses the whole box of the frame. The mode does not use `frameInset`.
|
|
106
|
+
- A route of the mode `gutter` goes into its row at the port, or at the left or right end of the row.
|
|
107
|
+
- The plug stub stays perpendicular to the wall. A plug that is level with its row gives only the stub.
|
|
108
|
+
- The option `bendCost` is the cost of one bend in units of length. A larger cost gives fewer bends. The default is 16.
|
|
109
|
+
- Each gap that two or more routes share gets one lane for each route. The lanes are evenly spaced, in an order with few crossings.
|
|
110
|
+
- The space between two lanes is the margin of the router. In a narrow gap, the space becomes smaller.
|
|
111
|
+
- An edge with no way through the free room gets no route, as with `skip`. Rows that touch each other with gap 0 can block a way.
|
|
68
112
|
|
|
69
113
|
```ts
|
|
70
114
|
const nodes = [
|
|
@@ -73,6 +117,7 @@ const nodes = [
|
|
|
73
117
|
];
|
|
74
118
|
const edges = [{ id: "inner", source: { node: "row" }, target: { node: "card", port: "in" } }];
|
|
75
119
|
const inner = cornersRouter({ name: "corners" }).route({ nodes, edges }).routes; // inner[0].frame is "card"
|
|
120
|
+
const gutters = cornersRouter({ name: "corners", inner: "gutter", bendCost: 24 }).route({ nodes, edges }).routes; // only H and V legs
|
|
76
121
|
```
|
|
77
122
|
|
|
78
123
|
## Curve types
|
|
@@ -396,7 +441,7 @@ The steps of the pipeline that vary have strategies. Each step has one interface
|
|
|
396
441
|
| Step | Input | Output | Built-in strategies |
|
|
397
442
|
|---|---|---|---|
|
|
398
443
|
| `group` | `Graph` | `Section`: the tree of groups of the router `sections` | `quadtree`, `keys`, `kd`, `cut` |
|
|
399
|
-
| `plugs` | `PlugInput`: the graph, and optionally the ways of the router | `PlugPair[]`: the two plugs of each edge | `facing` |
|
|
444
|
+
| `plugs` | `PlugInput`: the graph, and optionally the ways of the router | `PlugPair[]`: the two plugs of each edge | `facing`, `side`, `justify`, `spread` |
|
|
400
445
|
| `router` | `Graph` | `Result` | `straight`, `plugs`, `corners`, `corners-smooth`, `trunks`, `shared`, `shared-all`, `sections`, `sections-tree` |
|
|
401
446
|
| `highway` | `HighwayInput`: the graph, optionally the first routes of a router, and optionally the plan before an edit | `HighwayPlan`: the highways as data | `keys`, `shared-ways`, `corridors`, `meet`, `weiszfeld`, `stubs`, `zipper`, `level-links`, `quickbundles`, `road-classes`, `flow-field`, `wspd`, `od-cells`, `select`, `mingle`, `spiral`, `flow-clusters`, `traclus`, `diffusion`, `nested`, `lanes`, `growth`, `edge-paths`, `soft-keys`, `hough`, `ridges`, `hdbscan`, `hub-arcs`, `divided`, `hierarchy`, `fdeb`, `mesh`, `kdeeb`, `cubu`, `mlseb`, `sbeb`, `areas`, `confluent`, `power`, `crossbars`, `frechet`, `spectral`, `resistance`, `link-communities`, `territories`, `consensus`, `p-hub`, `scale-space`, `corridors+breakeven`, `corridors+stretch`, `corridors+ambiguity`, `corridors+hysteresis`, `corridors+ids` |
|
|
402
447
|
| `levels` | `LevelInput`: the graph, the tree of groups and the routes | `Level[]`: the zoom levels of the router `sections` | `depths` |
|
|
@@ -429,6 +474,13 @@ Each of these steps has one default strategy. The default gives the output of th
|
|
|
429
474
|
The option `level` of `sections` takes a level strategy, and `levelOptions` gives its options. The strategy also gets the level options of the router.
|
|
430
475
|
- `pipeline` (the step `whole`) runs a room strategy, then a router or a highway plan, with the rules that the router reads (`runPipeline`).
|
|
431
476
|
Without options, it routes with `corners`. The demo of the site runs it. It does not draw the curves.
|
|
477
|
+
- `venation` (the step `levels`, NAT-016) keeps the levels of `depths`. Its level links take their ways on a closed backbone of the items.
|
|
478
|
+
The backbone is the relative neighbourhood graph (`rng`) or the Gabriel graph. A backbone link that a level link uses costs less for the next level links.
|
|
479
|
+
The routes do not change, so only the level links (Z3) change.
|
|
480
|
+
- `board-portfolio` (the step `whole`, WILD-045) runs a short list of settings on the board and keeps the best one.
|
|
481
|
+
The list `BOARD_PORTFOLIO_SETTINGS` holds 12 routers and highway plans. The option `settings` sets how many of them run.
|
|
482
|
+
A setting with a break of a hard rule does not count. The score adds the rank shares of the crossings, the median detour and the ink saved.
|
|
483
|
+
It reads no screen record and has no fit. With `budget: 0`, the default, the pick does not depend on the speed of the machine.
|
|
432
484
|
- `strategyKey(router, step)` gives the option of a router that takes a strategy of the step. `pipeline` uses it for the steps `group`, `plugs` and `levels`.
|
|
433
485
|
- `stepRouterStrategy(strategy)` runs a strategy of a step of `RoutedStep` as a router. `stepRouters(registry, step)` gives one router for each strategy of the step.
|
|
434
486
|
|
|
@@ -507,6 +559,8 @@ The step `highway` decides which edges share a way. It gives a plan, not routes.
|
|
|
507
559
|
| `streets` | The orthogonal streets of HWY-058. A greedy set cover picks the free horizontal and vertical lines that carry the most edge length. |
|
|
508
560
|
| `search` | The local search of HWY-059. It adds, drops and changes the highways of a start plan, and it keeps the plan with the best score. |
|
|
509
561
|
| `interchanges` | The interchanges of HWY-060. An edge can change from one highway to another at an interchange, where two spines come near. |
|
|
562
|
+
| `knee` | The knee tree of NAT-018. A sweep of the balancing factor gives trees from the least ink to the most direct paths, and the knee of that front is the pick. |
|
|
563
|
+
| `bronchial` | The bronchial tree of NAT-019. The tree grows toward the center of its targets, then splits them in two sectors, again and again. |
|
|
510
564
|
|
|
511
565
|
The strategy `corridors` joins two ways when they share a long length. The length is `BREAK_EVEN` times the lane width or more, and the share `rho` of the shorter way or more.
|
|
512
566
|
The strategies `meet`, `weiszfeld`, `stubs`, `zipper`, `level-links`, `lanes`, `divided` and `crossbars` change the plan of the option `from`: `shared-ways` (the default), `corridors` or `none`.
|
|
@@ -582,6 +636,17 @@ The router `attraction` is opt-in. It is not in `STRATEGIES`, so the default out
|
|
|
582
636
|
- A capacity term raises the cost of a link when its users are more than its width holds.
|
|
583
637
|
- With 1 pass, `attraction: 0` and `capacityWeight: 0`, the routes are the routes of `shared`.
|
|
584
638
|
|
|
639
|
+
### The routers `tight` and `annealing`
|
|
640
|
+
|
|
641
|
+
The routers `tight` and `annealing` are opt-in. They are not in `STRATEGIES`, so the default outputs do not change. Both put a hook on the router `shared`.
|
|
642
|
+
|
|
643
|
+
- `tightRouter(options)` gives the order of WILD-023: the edges whose second way costs much more than their first way go first.
|
|
644
|
+
Its options are `penalty` (2 to 10), `first` (`tight` or `loose`) and `ties` (`id` or `length`). `tightStrategy` is its router strategy.
|
|
645
|
+
- `annealingRouter(options)` gives the simulated annealing of RULE-021, with the candidate routes of WILD-028. Each edge picks one of a few ways.
|
|
646
|
+
The energy adds the ink, the path length and the crossings. The chance to keep a worse state is rational, so it uses no `Math.exp`.
|
|
647
|
+
Its options are `candidates` (3 to 8), `crossing` (0 to 20), `temperature` (0.1 to 10), `cooling` (0.9 to 0.99), `budget` (20 to 200) and `seed`.
|
|
648
|
+
The same seed gives the same routes. `annealingStrategy` is its router strategy.
|
|
649
|
+
|
|
585
650
|
### The portfolio router
|
|
586
651
|
|
|
587
652
|
The router `portfolio` is opt-in. It is not in `STRATEGIES`, so the default outputs do not change. [`PORTFOLIO.md`](../../docs/research/PORTFOLIO.md#the-portfolio-router-portfolio-api) gives its tables.
|
|
@@ -740,6 +805,24 @@ const { rows, front } = compareStep("curve", graph, { options: { arc: { radius:
|
|
|
740
805
|
const lanes = compareStep("curve", graph, { curveRouter: "shared", lanes: { width: 5, maxWidth: 30 }, options: { highway: { jog: "quintic" } } });
|
|
741
806
|
```
|
|
742
807
|
|
|
808
|
+
## The corpus families
|
|
809
|
+
|
|
810
|
+
`HIGHWAYS_FAMILIES` lists the 15 generators of the boards of the screen and the site. Each one is a family of `@mark1russell7/layout-contract`, with its dimensions as data. `highwaysRegistry()` makes a registry of them.
|
|
811
|
+
|
|
812
|
+
- The first 6 families make the boards of `screen-v1` and `screen-v2`.
|
|
813
|
+
- `COVERAGE_FAMILIES` adds 9 families: `frame-rows`, `pipeline`, `fan-out`, `two-hubs`, `uneven-sizes`, `thin-bars`, `sparse-long`, `local-mesh` and `bipartite`.
|
|
814
|
+
- The screen set `screen-v3` has the 15 families, each with 10 seeds.
|
|
815
|
+
- `signTestPower(n)` gives the least count of families out of `n` that passes a two-sided sign test at the level 0.05. For 15 families, the count is 12.
|
|
816
|
+
|
|
817
|
+
```ts
|
|
818
|
+
import { highwaysRegistry, signTestPower } from "@mark1russell7/highways";
|
|
819
|
+
|
|
820
|
+
const { graph } = highwaysRegistry().generate("fan-out", 4, { leaves: 40 });
|
|
821
|
+
console.log(graph.nodes.length, signTestPower(15)); // 41 12
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
[The corpus families](https://github.com/mark1russell7/highways/blob/main/docs/LAYOUT-RECORDS.md#the-corpus-families-corpus-gen) give the dimensions of each family.
|
|
825
|
+
|
|
743
826
|
## The same routes on each platform
|
|
744
827
|
|
|
745
828
|
A transcendental Math function, for example `Math.atan2` or `Math.hypot`, can give a different last bit on another platform or node version. A decision of a router must not depend on that bit.
|