@litfamily/litopencode 1.0.31 → 1.0.33
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/CHANGELOG.md +38 -0
- package/README-Ko-KR.md +6 -6
- package/README.md +6 -6
- package/TRADEMARK.md +12 -0
- package/dist/activation-primary-prompts.js +5 -1
- package/dist/activation-probe.js +1 -0
- package/dist/activation-prompt-utils.d.ts +1 -1
- package/dist/activation-reentry.d.ts +20 -0
- package/dist/activation-reentry.js +110 -1
- package/dist/activation-routing.d.ts +2 -1
- package/dist/activation-routing.js +100 -11
- package/dist/activation-workflow-prompts.d.ts +4 -0
- package/dist/activation-workflow-prompts.js +30 -0
- package/dist/activation.d.ts +1 -1
- package/dist/activation.js +44 -5
- package/dist/adhd-next.d.ts +51 -0
- package/dist/adhd-next.js +150 -0
- package/dist/agents/defaults.js +1 -1
- package/dist/cli/managed-skill-assets.d.ts +1 -1
- package/dist/cli/managed-skill-assets.js +7 -1
- package/dist/cli/native-skill-integrity.js +1 -1
- package/dist/cli.js +7 -1
- package/dist/commands.d.ts +28 -1
- package/dist/commands.js +58 -5
- package/dist/durable-plan.d.ts +5 -1
- package/dist/durable-plan.js +14 -2
- package/dist/features.d.ts +80 -1
- package/dist/features.js +105 -1
- package/dist/hooks.js +3 -0
- package/dist/ledger.js +12 -1
- package/dist/plan-scope-roots.d.ts +23 -0
- package/dist/plan-scope-roots.js +116 -0
- package/dist/restart-notice.d.ts +7 -0
- package/dist/restart-notice.js +40 -0
- package/dist/secret-shapes.js +5 -5
- package/dist/server.js +4 -0
- package/dist/session-liveness.d.ts +20 -0
- package/dist/session-liveness.js +99 -0
- package/dist/skills.d.ts +22 -1
- package/dist/skills.js +36 -0
- package/dist/start-work-typed.d.ts +34 -0
- package/dist/start-work-typed.js +167 -0
- package/dist/state.d.ts +3 -0
- package/dist/state.js +3 -0
- package/dist/tools.js +22 -2
- package/dist/tui/mission-band.d.ts +22 -1
- package/dist/tui/mission-band.js +75 -16
- package/dist/tui/mission-looks.d.ts +38 -0
- package/dist/tui/mission-looks.js +73 -0
- package/dist/tui/mission-model.d.ts +2 -0
- package/dist/tui/mission-model.js +3 -1
- package/dist/tui/mission-rainbow.d.ts +33 -0
- package/dist/tui/mission-rainbow.js +90 -0
- package/dist/tui/mission-source.d.ts +49 -0
- package/dist/tui/mission-source.js +217 -2
- package/dist/tui/mission-text.d.ts +2 -0
- package/dist/tui/mission-text.js +9 -1
- package/dist/tui/mission-threads.d.ts +58 -0
- package/dist/tui/mission-threads.js +128 -0
- package/dist/tui.js +112 -7
- package/dist/uiux-visual-catalog.js +8 -1
- package/dist/v2/events.js +3 -0
- package/dist/v2/session-hooks.js +38 -5
- package/dist/workflow-stack.d.ts +53 -0
- package/dist/workflow-stack.js +196 -0
- package/docs/assets/readme/badge-version.svg +1 -1
- package/docs/assets/skills/lit-schematic.webp +0 -0
- package/docs/reference-Ko-KR.md +48 -3
- package/docs/reference.md +54 -3
- package/package.json +1 -1
- package/skills/frontend-ui-ux/SKILL.md +3 -2
- package/skills/frontend-ui-ux/kit/components.css +414 -0
- package/skills/frontend-ui-ux/kit/fonts.json +22 -0
- package/skills/frontend-ui-ux/kit/layouts/landing.html +164 -0
- package/skills/frontend-ui-ux/kit/layouts/settings.html +114 -0
- package/skills/frontend-ui-ux/kit/layouts/workspace.html +115 -0
- package/skills/frontend-ui-ux/kit/styles/computational-brutalism.json +227 -0
- package/skills/frontend-ui-ux/kit/styles/field-notes.json +205 -0
- package/skills/frontend-ui-ux/kit/styles/graphite.json +200 -0
- package/skills/frontend-ui-ux/kit/styles/meadow.json +199 -0
- package/skills/frontend-ui-ux/kit/styles/neo-brutalism.json +222 -0
- package/skills/frontend-ui-ux/kit/ui.js +226 -0
- package/skills/frontend-ui-ux/references/brand-and-imagery.md +2 -2
- package/skills/frontend-ui-ux/references/complete-contract.md +2 -1
- package/skills/frontend-ui-ux/references/craft-floor.md +6 -2
- package/skills/frontend-ui-ux/references/default-editorial-pixel.json +3 -0
- package/skills/frontend-ui-ux/references/house-styles.md +236 -0
- package/skills/frontend-ui-ux/references/motion-guide.md +2 -2
- package/skills/frontend-ui-ux/references/production.md +3 -1
- package/skills/frontend-ui-ux/references/slop-register.md +4 -4
- package/skills/frontend-ui-ux/scripts/design-lock.mjs +400 -0
- package/skills/frontend-ui-ux/scripts/pixel-art.mjs +60 -0
- package/skills/frontend-ui-ux/scripts/probe-lock.mjs +235 -0
- package/skills/frontend-ui-ux/scripts/probe-page.mjs +34 -12
- package/skills/frontend-ui-ux/scripts/probe-static.mjs +16 -3
- package/skills/frontend-ui-ux/scripts/probe-thresholds.json +8 -2
- package/skills/frontend-ui-ux/scripts/probe.mjs +35 -7
- package/skills/lit-adhd/SKILL.md +209 -0
- package/skills/lit-adhd/references/brief-format.md +46 -0
- package/skills/lit-adhd/references/card-examples.md +103 -0
- package/skills/lit-adhd/references/status-taxonomy.md +34 -0
- package/skills/lit-adhd/scripts/rewind.mjs +933 -0
- package/skills/lit-diagram-drawer/SKILL.md +4 -3
- package/skills/lit-diagram-drawer/references/style-guide.md +20 -11
- package/skills/lit-diagram-drawer/references/type-architecture.md +3 -3
- package/skills/lit-diagram-drawer/references/type-dependency.md +1 -1
- package/skills/lit-diagram-drawer/references/type-tree.md +3 -3
- package/skills/lit-diagram-drawer/references/type-wardley.md +1 -1
- package/skills/lit-diagram-drawer/references/verifier-guide.md +1 -0
- package/skills/lit-diagram-drawer/scripts/craft-thresholds.json +1 -2
- package/skills/lit-diagram-drawer/scripts/visual-quality.mjs +1 -2
- package/skills/lit-docx/SKILL.md +2 -1
- package/skills/lit-handoff/SKILL.md +2 -0
- package/skills/lit-hijack/SKILL.md +422 -0
- package/skills/lit-hijack/references/capture-and-provenance.md +87 -0
- package/skills/lit-hijack/references/clean-room-build.md +111 -0
- package/skills/lit-hijack/references/distil-and-licence.md +100 -0
- package/skills/lit-hijack/references/gap-and-port-design.md +126 -0
- package/skills/lit-hijack/references/parity-and-report.md +110 -0
- package/skills/lit-hijack/scripts/hijack.mjs +993 -0
- package/skills/lit-plan/SKILL.md +8 -0
- package/skills/lit-pptx/SKILL.md +27 -11
- package/skills/lit-pptx/fonts/jetbrains-mono/JetBrainsMono-Bold.ttf +0 -0
- package/skills/lit-pptx/fonts/jetbrains-mono/JetBrainsMono-Regular.ttf +0 -0
- package/skills/lit-pptx/fonts/jetbrains-mono/OFL.txt +93 -0
- package/skills/lit-pptx/fonts/jetbrains-mono/SOURCE.md +17 -0
- package/skills/lit-pptx/references/density-and-fill.md +9 -3
- package/skills/lit-pptx/references/direction-step.md +21 -6
- package/skills/lit-pptx/references/examples/04-lecture-chalk-ko.md +3 -6
- package/skills/lit-pptx/references/examples/05-research-talk-paper-en.md +1 -5
- package/skills/lit-pptx/references/examples/08-reliability-keynote-night-en.md +0 -4
- package/skills/lit-pptx/references/examples/09-status-update-ledger-en.md +2 -2
- package/skills/lit-pptx/references/examples/11-forecast-review-night-ko.md +4 -7
- package/skills/lit-pptx/references/examples/13-engineering-review-computational-brutalism-ko.md +173 -0
- package/skills/lit-pptx/references/examples/14-launch-pitch-neo-brutalism-ko.md +154 -0
- package/skills/lit-pptx/references/examples/15-design-lecture-bauhaus-ko.md +139 -0
- package/skills/lit-pptx/references/examples/16-community-programme-riso-ko.md +158 -0
- package/skills/lit-pptx/references/examples/17-public-data-briefing-newsroom-ko.md +179 -0
- package/skills/lit-pptx/references/layout-families.md +65 -47
- package/skills/lit-pptx/references/title-treatments.md +83 -134
- package/skills/lit-pptx/references/tonalities/atlas.md +3 -3
- package/skills/lit-pptx/references/tonalities/bauhaus.md +140 -0
- package/skills/lit-pptx/references/tonalities/chalk.md +7 -6
- package/skills/lit-pptx/references/tonalities/computational-brutalism.md +150 -0
- package/skills/lit-pptx/references/tonalities/gazette.md +1 -1
- package/skills/lit-pptx/references/tonalities/ledger.md +1 -1
- package/skills/lit-pptx/references/tonalities/neo-brutalism.md +161 -0
- package/skills/lit-pptx/references/tonalities/newsroom.md +144 -0
- package/skills/lit-pptx/references/tonalities/night.md +1 -1
- package/skills/lit-pptx/references/tonalities/paper.md +2 -2
- package/skills/lit-pptx/references/tonalities/riso.md +137 -0
- package/skills/lit-pptx/references/tonalities/signal.md +3 -3
- package/skills/lit-pptx/references/tonalities/studio.md +7 -6
- package/skills/lit-pptx/run.mjs +2 -1
- package/skills/lit-pptx/scripts/compile-deck.js +1 -1
- package/skills/lit-pptx/scripts/craft-thresholds.json +4 -8
- package/skills/lit-pptx/scripts/craft_extras.py +56 -3
- package/skills/lit-pptx/scripts/deck_output.py +75 -90
- package/skills/lit-pptx/scripts/embed_fonts.py +13 -1
- package/skills/lit-pptx/scripts/layout_inventory.py +12 -5
- package/skills/lit-pptx/scripts/lib/grid-resolver.js +101 -110
- package/skills/lit-pptx/scripts/lib/layout-resolver.js +9 -15
- package/skills/lit-pptx/scripts/lib/render-pack.js +373 -566
- package/skills/lit-pptx/scripts/lib/slide-grid.js +104 -0
- package/skills/lit-pptx/scripts/lib/template-registry.js +57 -6
- package/skills/lit-pptx/scripts/qa_deck.py +10 -11
- package/skills/lit-pptx/scripts/render_pages.py +118 -0
- package/skills/lit-pptx/templates/tonalities/atlas/pack.yaml +1 -1
- package/skills/lit-pptx/templates/tonalities/bauhaus/pack.yaml +98 -0
- package/skills/lit-pptx/templates/tonalities/chalk/pack.yaml +1 -1
- package/skills/lit-pptx/templates/tonalities/computational-brutalism/pack.yaml +99 -0
- package/skills/lit-pptx/templates/tonalities/gazette/pack.yaml +1 -1
- package/skills/lit-pptx/templates/tonalities/ledger/pack.yaml +1 -1
- package/skills/lit-pptx/templates/tonalities/neo-brutalism/pack.yaml +107 -0
- package/skills/lit-pptx/templates/tonalities/newsroom/pack.yaml +99 -0
- package/skills/lit-pptx/templates/tonalities/night/pack.yaml +1 -1
- package/skills/lit-pptx/templates/tonalities/paper/pack.yaml +1 -1
- package/skills/lit-pptx/templates/tonalities/riso/pack.yaml +99 -0
- package/skills/lit-pptx/templates/tonalities/signal/pack.yaml +2 -2
- package/skills/lit-pptx/templates/tonalities/studio/pack.yaml +1 -1
- package/skills/lit-recap/SKILL.md +4 -0
- package/skills/lit-schematic/SKILL.md +118 -0
- package/skills/lit-schematic/examples/iso-heat-exchanger/build.mjs +38 -0
- package/skills/lit-schematic/examples/iso-heat-exchanger/scene.mjs +133 -0
- package/skills/lit-schematic/examples/journal-adsorption-rig/build.mjs +87 -0
- package/skills/lit-schematic/examples/pid-dosing-skid/build.mjs +85 -0
- package/skills/lit-schematic/references/cutaway-outputs.md +70 -0
- package/skills/lit-schematic/references/isometric-craft.md +101 -0
- package/skills/lit-schematic/references/journal-figures.md +72 -0
- package/skills/lit-schematic/references/kit-api.md +134 -0
- package/skills/lit-schematic/references/pfd-and-layout.md +53 -0
- package/skills/lit-schematic/references/pid-drafting.md +103 -0
- package/skills/lit-schematic/references/pid-symbols.md +163 -0
- package/skills/lit-schematic/references/verification.md +100 -0
- package/skills/lit-schematic/scripts/doctor.mjs +57 -0
- package/skills/lit-schematic/scripts/lib/figure.mjs +81 -0
- package/skills/lit-schematic/scripts/lib/fonts.mjs +25 -0
- package/skills/lit-schematic/scripts/lib/geom.mjs +113 -0
- package/skills/lit-schematic/scripts/lib/interactive.mjs +292 -0
- package/skills/lit-schematic/scripts/lib/isa.mjs +115 -0
- package/skills/lit-schematic/scripts/lib/iso.mjs +719 -0
- package/skills/lit-schematic/scripts/lib/legend-sheet.mjs +162 -0
- package/skills/lit-schematic/scripts/lib/pid.mjs +937 -0
- package/skills/lit-schematic/scripts/lib/png.mjs +132 -0
- package/skills/lit-schematic/scripts/lib/qa-core.mjs +658 -0
- package/skills/lit-schematic/scripts/lib/route.mjs +218 -0
- package/skills/lit-schematic/scripts/lib/sheet.mjs +890 -0
- package/skills/lit-schematic/scripts/lib/svg.mjs +82 -0
- package/skills/lit-schematic/scripts/lib/theme.mjs +115 -0
- package/skills/lit-schematic/scripts/motion.mjs +129 -0
- package/skills/lit-schematic/scripts/qa.mjs +92 -0
- package/skills/lit-schematic/scripts/render.mjs +233 -0
- package/skills/lit-schematic/scripts/scaffold.mjs +60 -0
- package/skills/lit-scientific-visualization/SKILL.md +27 -4
- package/skills/lit-typographic-motion/SKILL.md +19 -17
- package/skills/lit-typographic-motion/THIRD_PARTY_NOTICES +9 -0
- package/skills/lit-typographic-motion/engine/accents.mjs +6 -0
- package/skills/lit-typographic-motion/engine/assets.mjs +282 -0
- package/skills/lit-typographic-motion/engine/blender/runner.py +228 -0
- package/skills/lit-typographic-motion/engine/blender.mjs +126 -0
- package/skills/lit-typographic-motion/engine/board.mjs +138 -0
- package/skills/lit-typographic-motion/engine/cover/assets.mjs +11 -8
- package/skills/lit-typographic-motion/engine/cover/capture.mjs +6 -6
- package/skills/lit-typographic-motion/engine/cover/render.mjs +20 -7
- package/skills/lit-typographic-motion/engine/cover/treatment.mjs +30 -3
- package/skills/lit-typographic-motion/engine/fill.mjs +54 -0
- package/skills/lit-typographic-motion/engine/gallery.mjs +118 -0
- package/skills/lit-typographic-motion/engine/house.mjs +42 -0
- package/skills/lit-typographic-motion/engine/look.mjs +65 -8
- package/skills/lit-typographic-motion/engine/loudness.mjs +101 -0
- package/skills/lit-typographic-motion/engine/scaffold.mjs +219 -0
- package/skills/lit-typographic-motion/engine/score.mjs +594 -0
- package/skills/lit-typographic-motion/engine/sound.mjs +9 -57
- package/skills/lit-typographic-motion/engine/stage/capture.mjs +23 -9
- package/skills/lit-typographic-motion/engine/stage/clock.js +8 -2
- package/skills/lit-typographic-motion/engine/stage/cover-init.js +12 -1
- package/skills/lit-typographic-motion/engine/stage/frame-worker.mjs +15 -7
- package/skills/lit-typographic-motion/engine/stage/gate.mjs +48 -4
- package/skills/lit-typographic-motion/engine/stage/qa-page.js +16 -5
- package/skills/lit-typographic-motion/engine/stage/qa.mjs +148 -7
- package/skills/lit-typographic-motion/engine/stage/render.mjs +69 -7
- package/skills/lit-typographic-motion/engine/stage/scan.mjs +20 -1
- package/skills/lit-typographic-motion/engine/stage/stage-kit.js +85 -4
- package/skills/lit-typographic-motion/engine/stills.mjs +1 -1
- package/skills/lit-typographic-motion/engine/styles.mjs +221 -0
- package/skills/lit-typographic-motion/engine/text.mjs +1 -1
- package/skills/lit-typographic-motion/engine/treatment.mjs +190 -6
- package/skills/lit-typographic-motion/engine/vendor/three/LICENSE +21 -0
- package/skills/lit-typographic-motion/engine/vendor/three/addons/environments/RoomEnvironment.js +144 -0
- package/skills/lit-typographic-motion/engine/vendor/three/addons/geometries/RoundedBoxGeometry.js +155 -0
- package/skills/lit-typographic-motion/engine/vendor/three/three.module.js +54571 -0
- package/skills/lit-typographic-motion/gate.mjs +18 -2
- package/skills/lit-typographic-motion/probe.mjs +13 -1
- package/skills/lit-typographic-motion/recipes/hero-3d/expected.json +64 -0
- package/skills/lit-typographic-motion/recipes/hero-3d/index.html +132 -0
- package/skills/lit-typographic-motion/recipes/orbit-loop/expected.json +2 -0
- package/skills/lit-typographic-motion/recipes/painted-light/expected.json +2 -0
- package/skills/lit-typographic-motion/recipes/weight-tide/expected.json +2 -0
- package/skills/lit-typographic-motion/references/cover.md +56 -13
- package/skills/lit-typographic-motion/references/craft-loop.md +20 -7
- package/skills/lit-typographic-motion/references/depth.md +112 -0
- package/skills/lit-typographic-motion/references/runtime.md +21 -6
- package/skills/lit-typographic-motion/references/sound.md +76 -0
- package/skills/lit-typographic-motion/references/stage.md +50 -7
- package/skills/lit-typographic-motion/references/studio.md +162 -0
- package/skills/lit-typographic-motion/references/style-bibles.md +18 -0
- package/skills/lit-typographic-motion/references/treatment.md +108 -9
- package/skills/lit-typographic-motion/render.mjs +60 -3
- package/skills/lit-typographic-motion/styles/paper.json +185 -0
- package/skills/lit-typographic-motion/styles/swiss-signal.json +188 -0
- package/skills/lit-typographic-motion/styles/terminalcore.json +182 -0
- package/skills/lit-typographic-motion/styles/tidal.json +187 -0
- package/skills/litresearch/SKILL.md +2 -0
- package/skills/managed-skill-manifest.json +517 -88
- package/skills/readme-studio/SKILL.md +1 -1
- package/skills/review-work/SKILL.md +2 -0
- package/skills/start-work/SKILL.md +8 -0
- package/skills/workflow-loop/SKILL.md +4 -0
- package/tools/check-pack-payload.mjs +5 -2
- package/tools/payload-substance-parity.json +4 -3
- package/tools/qa-cover-recipes.mjs +4 -3
- package/tools/version-manifests.json +2 -2
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
// Orthogonal line routing for P&IDs, PFDs and 2D apparatus panels.
|
|
2
|
+
//
|
|
3
|
+
// Drafting rules it encodes: a line leaves its port straight out along the port's normal
|
|
4
|
+
// before it turns; it never enters a symbol other than at its own ports; it turns as little
|
|
5
|
+
// as possible; it may cross another line only at a right angle on a straight run, never turn
|
|
6
|
+
// on top of another line and never run along one. A failed search throws instead of drawing
|
|
7
|
+
// through a symbol, so the caller moves a symbol or gives waypoints.
|
|
8
|
+
|
|
9
|
+
import { EPS, dist, pointIn, simplify } from "./geom.mjs";
|
|
10
|
+
|
|
11
|
+
const DIRS = [[1, 0], [0, 1], [-1, 0], [0, -1]];
|
|
12
|
+
const dirIndex = ([dx, dy]) => DIRS.findIndex(([x, y]) => Math.abs(x - dx) < EPS && Math.abs(y - dy) < EPS);
|
|
13
|
+
|
|
14
|
+
class Heap {
|
|
15
|
+
constructor() { this.items = []; }
|
|
16
|
+
get size() { return this.items.length; }
|
|
17
|
+
push(item) {
|
|
18
|
+
const items = this.items;
|
|
19
|
+
items.push(item);
|
|
20
|
+
let i = items.length - 1;
|
|
21
|
+
while (i > 0) {
|
|
22
|
+
const parent = (i - 1) >> 1;
|
|
23
|
+
if (less(items[parent], items[i])) break;
|
|
24
|
+
[items[parent], items[i]] = [items[i], items[parent]];
|
|
25
|
+
i = parent;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
pop() {
|
|
29
|
+
const items = this.items;
|
|
30
|
+
const top = items[0];
|
|
31
|
+
const last = items.pop();
|
|
32
|
+
if (items.length) {
|
|
33
|
+
items[0] = last;
|
|
34
|
+
let i = 0;
|
|
35
|
+
for (;;) {
|
|
36
|
+
const l = 2 * i + 1;
|
|
37
|
+
const r = l + 1;
|
|
38
|
+
let m = i;
|
|
39
|
+
if (l < items.length && less(items[l], items[m])) m = l;
|
|
40
|
+
if (r < items.length && less(items[r], items[m])) m = r;
|
|
41
|
+
if (m === i) break;
|
|
42
|
+
[items[m], items[i]] = [items[i], items[m]];
|
|
43
|
+
i = m;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return top;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const less = (a, b) => (a.f !== b.f ? a.f < b.f : a.seq < b.seq);
|
|
50
|
+
|
|
51
|
+
function axisValues(lo, hi, step, extra) {
|
|
52
|
+
const values = new Set();
|
|
53
|
+
const first = Math.ceil(lo / step) * step;
|
|
54
|
+
for (let v = first; v <= hi + EPS; v += step) values.add(Math.round(v * 1000) / 1000);
|
|
55
|
+
for (const v of extra) if (v >= lo - EPS && v <= hi + EPS) values.add(Math.round(v * 1000) / 1000);
|
|
56
|
+
return [...values].sort((a, b) => a - b);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Existing lines as axis-aligned runs, so a candidate move can be classified as a clean
|
|
60
|
+
// crossing, an overlap or a turn on a line.
|
|
61
|
+
function occupancy(lines) {
|
|
62
|
+
const horizontal = [];
|
|
63
|
+
const vertical = [];
|
|
64
|
+
for (const points of lines) {
|
|
65
|
+
for (let i = 1; i < points.length; i++) {
|
|
66
|
+
const [a, b] = [points[i - 1], points[i]];
|
|
67
|
+
if (Math.abs(a[1] - b[1]) < EPS) horizontal.push({ y: a[1], x0: Math.min(a[0], b[0]), x1: Math.max(a[0], b[0]) });
|
|
68
|
+
else if (Math.abs(a[0] - b[0]) < EPS) vertical.push({ x: a[0], y0: Math.min(a[1], b[1]), y1: Math.max(a[1], b[1]) });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
onHorizontal: ([x, y], margin = 0) => horizontal.some((s) => Math.abs(s.y - y) < margin + EPS && x >= s.x0 - EPS && x <= s.x1 + EPS),
|
|
73
|
+
onVertical: ([x, y], margin = 0) => vertical.some((s) => Math.abs(s.x - x) < margin + EPS && y >= s.y0 - EPS && y <= s.y1 + EPS),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function routeOrthogonal({
|
|
78
|
+
from,
|
|
79
|
+
to,
|
|
80
|
+
obstacles = [],
|
|
81
|
+
lines = [],
|
|
82
|
+
bounds,
|
|
83
|
+
grid = 2.5,
|
|
84
|
+
clearance = 2,
|
|
85
|
+
stub = 5,
|
|
86
|
+
bendCost = 9,
|
|
87
|
+
crossCost = 4,
|
|
88
|
+
nearCost = 3,
|
|
89
|
+
exempt = [],
|
|
90
|
+
}) {
|
|
91
|
+
if (!bounds) throw new Error("routeOrthogonal: bounds are required");
|
|
92
|
+
const startDir = dirIndex(from.dir ?? [1, 0]);
|
|
93
|
+
const endDir = dirIndex(to.dir ?? [-1, 0]);
|
|
94
|
+
if (startDir < 0 || endDir < 0) throw new Error("routeOrthogonal: port directions must be axis-aligned unit vectors");
|
|
95
|
+
const inflated = obstacles.map((box) => [box[0] - clearance, box[1] - clearance, box[2] + clearance, box[3] + clearance]);
|
|
96
|
+
const blockedPoint = (p) => inflated.some((box) => pointIn(p, box, EPS));
|
|
97
|
+
// The stub runs out along the port normal until it clears every symbol's clearance zone,
|
|
98
|
+
// its own included: a nozzle on a curved head sits inside its vessel's bounding box.
|
|
99
|
+
const stubEnd = (port, d, label) => {
|
|
100
|
+
for (let k = stub; k <= stub + 80; k += 0.5) {
|
|
101
|
+
const p = [port.x + DIRS[d][0] * k, port.y + DIRS[d][1] * k];
|
|
102
|
+
if (!blockedPoint(p)) return p;
|
|
103
|
+
}
|
|
104
|
+
throw new Error(`routeOrthogonal: the ${label} port at (${port.x}, ${port.y}) faces into another symbol; turn the port or move the symbol`);
|
|
105
|
+
};
|
|
106
|
+
// Two ports that face each other on one axis with nothing between them join straight.
|
|
107
|
+
if ((startDir + 2) % 4 === endDir) {
|
|
108
|
+
const along = [to.x - from.x, to.y - from.y];
|
|
109
|
+
const straight = DIRS[startDir][0] === 0 ? Math.abs(along[0]) < EPS : Math.abs(along[1]) < EPS;
|
|
110
|
+
const ahead = along[0] * DIRS[startDir][0] + along[1] * DIRS[startDir][1] > 0;
|
|
111
|
+
if (straight && ahead) {
|
|
112
|
+
let clear = true;
|
|
113
|
+
const length = Math.hypot(along[0], along[1]);
|
|
114
|
+
for (let k = 0.5; k < length - 0.5 && clear; k += 0.5) {
|
|
115
|
+
const p = [from.x + DIRS[startDir][0] * k, from.y + DIRS[startDir][1] * k];
|
|
116
|
+
if (obstacles.some((box) => !exempt.includes(box) && pointIn(p, box, EPS))) clear = false;
|
|
117
|
+
}
|
|
118
|
+
if (clear) return [[from.x, from.y], [to.x, to.y]];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const s = stubEnd(from, startDir, "start");
|
|
122
|
+
const t = stubEnd(to, endDir, "end");
|
|
123
|
+
const xs = axisValues(bounds[0], bounds[2], grid, [s[0], t[0], from.x, to.x]);
|
|
124
|
+
const ys = axisValues(bounds[1], bounds[3], grid, [s[1], t[1], from.y, to.y]);
|
|
125
|
+
const xi = new Map(xs.map((v, i) => [v, i]));
|
|
126
|
+
const yi = new Map(ys.map((v, i) => [v, i]));
|
|
127
|
+
const key = (ix, iy) => iy * xs.length + ix;
|
|
128
|
+
const occ = occupancy(lines);
|
|
129
|
+
const sx = xi.get(Math.round(s[0] * 1000) / 1000);
|
|
130
|
+
const sy = yi.get(Math.round(s[1] * 1000) / 1000);
|
|
131
|
+
const tx = xi.get(Math.round(t[0] * 1000) / 1000);
|
|
132
|
+
const ty = yi.get(Math.round(t[1] * 1000) / 1000);
|
|
133
|
+
const arrive = (endDir + 2) % 4;
|
|
134
|
+
const heap = new Heap();
|
|
135
|
+
const best = new Map();
|
|
136
|
+
const came = new Map();
|
|
137
|
+
let seq = 0;
|
|
138
|
+
const h = (ix, iy) => Math.abs(xs[ix] - t[0]) + Math.abs(ys[iy] - t[1]);
|
|
139
|
+
heap.push({ ix: sx, iy: sy, d: startDir, g: 0, f: h(sx, sy), seq: seq++ });
|
|
140
|
+
best.set(`${key(sx, sy)}:${startDir}`, 0);
|
|
141
|
+
let goal = null;
|
|
142
|
+
while (heap.size) {
|
|
143
|
+
const cur = heap.pop();
|
|
144
|
+
const stateKey = `${key(cur.ix, cur.iy)}:${cur.d}`;
|
|
145
|
+
if (cur.g > (best.get(stateKey) ?? Infinity) + EPS) continue;
|
|
146
|
+
if (cur.ix === tx && cur.iy === ty) {
|
|
147
|
+
const finalCost = cur.g + (cur.d === arrive ? 0 : bendCost);
|
|
148
|
+
if (!goal || finalCost < goal.cost) goal = { state: stateKey, cost: finalCost };
|
|
149
|
+
if (cur.d === arrive) break;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const here = [xs[cur.ix], ys[cur.iy]];
|
|
153
|
+
for (let d = 0; d < 4; d++) {
|
|
154
|
+
if (d === (cur.d + 2) % 4) continue;
|
|
155
|
+
const nx = cur.ix + DIRS[d][0];
|
|
156
|
+
const ny = cur.iy + DIRS[d][1];
|
|
157
|
+
if (nx < 0 || ny < 0 || nx >= xs.length || ny >= ys.length) continue;
|
|
158
|
+
const next = [xs[nx], ys[ny]];
|
|
159
|
+
const mid = [(here[0] + next[0]) / 2, (here[1] + next[1]) / 2];
|
|
160
|
+
if (blockedPoint(next) || blockedPoint(mid)) continue;
|
|
161
|
+
const horizontalMove = d % 2 === 0;
|
|
162
|
+
// Running along an existing line, or turning on top of one, is never allowed.
|
|
163
|
+
if (horizontalMove ? occ.onHorizontal(mid) : occ.onVertical(mid)) continue;
|
|
164
|
+
const turning = d !== cur.d;
|
|
165
|
+
const isEndpoint = (cur.ix === sx && cur.iy === sy);
|
|
166
|
+
if (turning && !isEndpoint && (occ.onHorizontal(here) || occ.onVertical(here))) continue;
|
|
167
|
+
let step = dist(here, next);
|
|
168
|
+
if (horizontalMove ? occ.onVertical(next) : occ.onHorizontal(next)) {
|
|
169
|
+
const atGoal = nx === tx && ny === ty;
|
|
170
|
+
if (atGoal) continue;
|
|
171
|
+
step += crossCost;
|
|
172
|
+
}
|
|
173
|
+
if (horizontalMove ? occ.onHorizontal(mid, grid * 0.99) : occ.onVertical(mid, grid * 0.99)) step += nearCost;
|
|
174
|
+
const g = cur.g + step + (turning ? bendCost : 0);
|
|
175
|
+
const nextKey = `${key(nx, ny)}:${d}`;
|
|
176
|
+
if (g + EPS < (best.get(nextKey) ?? Infinity)) {
|
|
177
|
+
best.set(nextKey, g);
|
|
178
|
+
came.set(nextKey, stateKey);
|
|
179
|
+
heap.push({ ix: nx, iy: ny, d, g, f: g + h(nx, ny), seq: seq++ });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (!goal) {
|
|
184
|
+
throw new Error(`routeOrthogonal: no clear route from (${from.x}, ${from.y}) to (${to.x}, ${to.y}); move a symbol, widen the gap, or pass waypoints`);
|
|
185
|
+
}
|
|
186
|
+
const cells = [];
|
|
187
|
+
for (let k = goal.state; k; k = came.get(k)) {
|
|
188
|
+
const index = Number(k.split(":")[0]);
|
|
189
|
+
cells.push([xs[index % xs.length], ys[Math.floor(index / xs.length)]]);
|
|
190
|
+
if (!came.has(k)) break;
|
|
191
|
+
}
|
|
192
|
+
cells.reverse();
|
|
193
|
+
return simplify([[from.x, from.y], ...cells, [to.x, to.y]]);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Checks a hand-given polyline: every leg axis-aligned and the first and last legs on the
|
|
197
|
+
// port normals. Returns the simplified corners.
|
|
198
|
+
export function orthogonal(points, { from, to } = {}) {
|
|
199
|
+
const out = simplify(points);
|
|
200
|
+
for (let i = 1; i < out.length; i++) {
|
|
201
|
+
const [a, b] = [out[i - 1], out[i]];
|
|
202
|
+
if (Math.abs(a[0] - b[0]) > EPS && Math.abs(a[1] - b[1]) > EPS) {
|
|
203
|
+
throw new Error(`orthogonal: leg ${i} from (${a}) to (${b}) is diagonal; P&ID lines run horizontally or vertically`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const check = (port, a, b, label) => {
|
|
207
|
+
if (!port?.dir) return;
|
|
208
|
+
const d = [Math.sign(b[0] - a[0]), Math.sign(b[1] - a[1])];
|
|
209
|
+
if (d[0] !== Math.sign(port.dir[0]) || d[1] !== Math.sign(port.dir[1])) {
|
|
210
|
+
throw new Error(`orthogonal: the ${label} leg must leave its port along the port's normal`);
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
if (out.length >= 2) {
|
|
214
|
+
check(from, out[0], out[1], "first");
|
|
215
|
+
check(to, out.at(-1), out.at(-2), "last");
|
|
216
|
+
}
|
|
217
|
+
return out;
|
|
218
|
+
}
|