@deltarobotics/uhd-viewer 0.0.0-stage → 0.2.1
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 +74 -0
- package/LICENSE +202 -0
- package/NOTICE +22 -0
- package/README.md +168 -2
- package/bin/serve.d.mts +62 -0
- package/bin/serve.mjs +257 -0
- package/bin/uhd-viewer.mjs +75 -0
- package/dist/app/assets/KodeMono-Bold-DdIivhPN.woff2 +0 -0
- package/dist/app/assets/KodeMono-Medium-CVnTuv5A.ttf +0 -0
- package/dist/app/assets/KodeMono-Regular-Bdr_-rJX.woff2 +0 -0
- package/dist/app/assets/KodeMono-SemiBold-JAfn5Dpm.ttf +0 -0
- package/dist/app/assets/index-CEJyT8hF.css +2 -0
- package/dist/app/assets/index-DWZ-48wc.js +3853 -0
- package/dist/app/index.html +16 -0
- package/dist/components/components.css +6372 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +26609 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/types/uhd-viewer/src/api.d.ts +286 -0
- package/dist/components/types/uhd-viewer/src/cad/CadView.d.ts +52 -0
- package/dist/components/types/uhd-viewer/src/cad/ModelView.d.ts +30 -0
- package/dist/components/types/uhd-viewer/src/cad/explode.d.ts +110 -0
- package/dist/components/types/uhd-viewer/src/cad/explodeSample.d.ts +25 -0
- package/dist/components/types/uhd-viewer/src/cad/findings.d.ts +41 -0
- package/dist/components/types/uhd-viewer/src/cad/labels.d.ts +76 -0
- package/dist/components/types/uhd-viewer/src/cad/model.d.ts +132 -0
- package/dist/components/types/uhd-viewer/src/cad/row.d.ts +15 -0
- package/dist/components/types/uhd-viewer/src/cad/scene.d.ts +95 -0
- package/dist/components/types/uhd-viewer/src/cad/scope.d.ts +89 -0
- package/dist/components/types/uhd-viewer/src/canvas/Canvas.d.ts +90 -0
- package/dist/components/types/uhd-viewer/src/canvas/Icon.d.ts +5 -0
- package/dist/components/types/uhd-viewer/src/canvas/LinkEdge.d.ts +40 -0
- package/dist/components/types/uhd-viewer/src/canvas/Port.d.ts +18 -0
- package/dist/components/types/uhd-viewer/src/canvas/actions.d.ts +5 -0
- package/dist/components/types/uhd-viewer/src/canvas/geometry.d.ts +72 -0
- package/dist/components/types/uhd-viewer/src/canvas/interaction.d.ts +162 -0
- package/dist/components/types/uhd-viewer/src/canvas/nodes.d.ts +43 -0
- package/dist/components/types/uhd-viewer/src/canvas/reveal.d.ts +55 -0
- package/dist/components/types/uhd-viewer/src/canvas/rightDrag.d.ts +51 -0
- package/dist/components/types/uhd-viewer/src/canvas/routing.d.ts +28 -0
- package/dist/components/types/uhd-viewer/src/chrome/ArtifactCards.d.ts +30 -0
- package/dist/components/types/uhd-viewer/src/chrome/Artifacts.d.ts +44 -0
- package/dist/components/types/uhd-viewer/src/chrome/BoardInspector.d.ts +53 -0
- package/dist/components/types/uhd-viewer/src/chrome/Chrome.d.ts +126 -0
- package/dist/components/types/uhd-viewer/src/chrome/Evidence.d.ts +20 -0
- package/dist/components/types/uhd-viewer/src/chrome/InterfaceCards.d.ts +66 -0
- package/dist/components/types/uhd-viewer/src/chrome/PairView.d.ts +37 -0
- package/dist/components/types/uhd-viewer/src/chrome/Sections.d.ts +128 -0
- package/dist/components/types/uhd-viewer/src/components.d.ts +60 -0
- package/dist/components/types/uhd-viewer/src/host/channel.d.ts +49 -0
- package/dist/components/types/uhd-viewer/src/host/context.d.ts +29 -0
- package/dist/components/types/uhd-viewer/src/host/protocol.d.ts +22 -0
- package/dist/components/types/uhd-viewer/src/host/targets.d.ts +101 -0
- package/dist/components/types/uhd-viewer/src/layout/board-layout.d.ts +69 -0
- package/dist/components/types/uhd-viewer/src/layout/card-body.d.ts +64 -0
- package/dist/components/types/uhd-viewer/src/layout/layout.d.ts +94 -0
- package/dist/components/types/uhd-viewer/src/layout/module-layout.d.ts +32 -0
- package/dist/components/types/uhd-viewer/src/layout/router.d.ts +55 -0
- package/dist/components/types/uhd-viewer/src/layout/taps.d.ts +20 -0
- package/dist/components/types/uhd-viewer/src/model/artifacts.d.ts +129 -0
- package/dist/components/types/uhd-viewer/src/model/classification.d.ts +41 -0
- package/dist/components/types/uhd-viewer/src/model/diagnostics.d.ts +27 -0
- package/dist/components/types/uhd-viewer/src/model/evidence.d.ts +63 -0
- package/dist/components/types/uhd-viewer/src/model/from-uhd.d.ts +58 -0
- package/dist/components/types/uhd-viewer/src/model/hierarchy.d.ts +173 -0
- package/dist/components/types/uhd-viewer/src/model/isolate.d.ts +33 -0
- package/dist/components/types/uhd-viewer/src/model/level.d.ts +7 -0
- package/dist/components/types/uhd-viewer/src/model/nets.d.ts +53 -0
- package/dist/components/types/uhd-viewer/src/model/outputs.d.ts +79 -0
- package/dist/components/types/uhd-viewer/src/model/slots.d.ts +184 -0
- package/dist/components/types/uhd-viewer/src/model/types.d.ts +213 -0
- package/dist/components/types/uhd-viewer/src/options.d.ts +27 -0
- package/dist/components/types/uhd-viewer/src/source/source.d.ts +109 -0
- package/dist/components/types/uhd-viewer/src/source/tolerant.d.ts +45 -0
- package/dist/components/types/uhd-viewer/src/theme/ThemeProvider.d.ts +33 -0
- package/dist/components/types/uhd-viewer/src/theme/adapters.d.ts +28 -0
- package/dist/components/types/uhd-viewer/src/theme/resolve.d.ts +19 -0
- package/dist/components/types/uhd-viewer/src/theme/themes.d.ts +67 -0
- package/dist/components/types/uhd-viewer/src/theme/tokens.d.ts +175 -0
- package/dist/components/types/uhd-viewer/src/ui/Inspector.d.ts +45 -0
- package/dist/components/types/uhd-viewer/src/ui/Legend.d.ts +59 -0
- package/dist/components/types/uhd-viewer/src/ui/ScrollArea.d.ts +16 -0
- package/dist/components/types/uhd-viewer/src/ui/Toolbar.d.ts +49 -0
- package/dist/components/types/uhd-viewer/src/ui/Tooltips.d.ts +3 -0
- package/dist/components/types/uhd-viewer/src/ui/cx.d.ts +2 -0
- package/dist/components/types/uhd-viewer/src/ui/legendFit.d.ts +55 -0
- package/dist/components/types/uhd-viewer/src/viewer/controller.d.ts +219 -0
- package/dist/components/types/uhd-viewer/src/viewer/details.d.ts +81 -0
- package/dist/components/types/uhd-viewer/src/viewer/hierarchy.d.ts +82 -0
- package/dist/components/types/uhd-viewer/src/viewer/mount.d.ts +12 -0
- package/dist/components/types/uhd-viewer/src/viewer/views.d.ts +187 -0
- package/dist/headless/index.d.ts +71 -0
- package/dist/headless/index.js +7425 -0
- package/dist/headless/index.js.map +1 -0
- package/dist/lib/api.d.ts +252 -0
- package/dist/lib/uhd-viewer.css +3 -0
- package/dist/lib/uhd-viewer.d.ts +4 -0
- package/dist/lib/uhd-viewer.js +97787 -0
- package/package.json +110 -4
- package/src/styles/fonts/OFL.txt +93 -0
- package/src/styles/tailwind-theme.css +48 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 3D view model (PB-775): what to load and where, derived from UHD alone.
|
|
3
|
+
*
|
|
4
|
+
* - Placements come from `assemble` (mechanical links with frames).
|
|
5
|
+
* - Each placement's body is the module's GLB artifact for that body.
|
|
6
|
+
* - Each interface reports how it is bound, per direction:
|
|
7
|
+
* feature D1 named sub-shape in the body artifact (+ signature)
|
|
8
|
+
* artifact D2 its own artifact file
|
|
9
|
+
* procedural D3 derived from its parameters at its frame
|
|
10
|
+
* plus whether it is logical, unmapped, or resolved through its children.
|
|
11
|
+
*/
|
|
12
|
+
import type { ArtifactDef, GeometryFrame, GeometryRef, InterfaceDef, ModuleDef } from "@deltarobotics/uhd";
|
|
13
|
+
import { type Assembly, type GeometryBindingIssue, type GeometryManifest, type Mat4 } from "@deltarobotics/uhd";
|
|
14
|
+
import type { ModuleLookup } from "@deltarobotics/uhd";
|
|
15
|
+
/** Artifact URL for a definition's (relative) file path: supplied by the viewer's source. */
|
|
16
|
+
import type { ArtifactResolver } from "../api";
|
|
17
|
+
export type { ArtifactResolver };
|
|
18
|
+
export type Direction = "feature" | "artifact" | "procedural";
|
|
19
|
+
export declare const DIRECTIONS: {
|
|
20
|
+
id: Direction;
|
|
21
|
+
label: string;
|
|
22
|
+
hint: string;
|
|
23
|
+
icon: string;
|
|
24
|
+
}[];
|
|
25
|
+
export interface CadBody {
|
|
26
|
+
key: string;
|
|
27
|
+
path: string[];
|
|
28
|
+
def: ModuleDef;
|
|
29
|
+
/** GLB to load, if the module has one for this body. */
|
|
30
|
+
glb?: ArtifactDef;
|
|
31
|
+
/** The body artifact id feature refs point at (STEP or vendor source). */
|
|
32
|
+
bodyArtifact?: string;
|
|
33
|
+
matrix: Mat4;
|
|
34
|
+
via?: string;
|
|
35
|
+
/** Placed by a hint, not by a link. */
|
|
36
|
+
hint?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Nothing places it: it is drawn beside the others in a row, laid out
|
|
39
|
+
* once its model is loaded (PB-1040), and the view says it is unplaced.
|
|
40
|
+
*/
|
|
41
|
+
row?: boolean;
|
|
42
|
+
}
|
|
43
|
+
export type BindingStatus = "bound" | "stale" | "missing" | "unchecked" | "none";
|
|
44
|
+
export interface InterfaceRow {
|
|
45
|
+
iface: InterfaceDef;
|
|
46
|
+
frame?: GeometryFrame;
|
|
47
|
+
/** Geometry comes from these interfaces (itself, or its children). */
|
|
48
|
+
sources: string[];
|
|
49
|
+
refs: {
|
|
50
|
+
interfaceId: string;
|
|
51
|
+
ref: GeometryRef;
|
|
52
|
+
}[];
|
|
53
|
+
logical: boolean;
|
|
54
|
+
/** No frame and no refs, on itself or any child. */
|
|
55
|
+
unmapped: boolean;
|
|
56
|
+
/** Per-direction resolution. */
|
|
57
|
+
byDirection: Record<Direction, {
|
|
58
|
+
interfaceId: string;
|
|
59
|
+
ref: GeometryRef;
|
|
60
|
+
status: BindingStatus;
|
|
61
|
+
note?: string;
|
|
62
|
+
}[]>;
|
|
63
|
+
issues: GeometryBindingIssue[];
|
|
64
|
+
}
|
|
65
|
+
export interface CadModel {
|
|
66
|
+
assembly: Assembly;
|
|
67
|
+
bodies: CadBody[];
|
|
68
|
+
/** module path key -> def, for every leaf instance */
|
|
69
|
+
defs: Map<string, ModuleDef>;
|
|
70
|
+
manifests: Map<string, GeometryManifest>;
|
|
71
|
+
/**
|
|
72
|
+
* Instances drawn inside another module's body rather than placed: the
|
|
73
|
+
* components of a board whose body (board.glb) shows them (PB-823). Path
|
|
74
|
+
* key → the body key that holds them.
|
|
75
|
+
*/
|
|
76
|
+
within: Map<string, string>;
|
|
77
|
+
/**
|
|
78
|
+
* Where the placements come from when not from the module's own assembly
|
|
79
|
+
* (PB-1040): an ancestor's assembly cut down to the module (`from` is the
|
|
80
|
+
* ancestor's path from the root, `""` the root), or nothing at all, the
|
|
81
|
+
* models side by side (`row`).
|
|
82
|
+
*/
|
|
83
|
+
placedBy?: {
|
|
84
|
+
kind: "ancestor";
|
|
85
|
+
from: string;
|
|
86
|
+
} | {
|
|
87
|
+
kind: "row";
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/** The definition at an instance path below `system` ([] is the system itself). */
|
|
91
|
+
export declare function defAt(system: ModuleDef, lookup: ModuleLookup, path: string[]): ModuleDef | undefined;
|
|
92
|
+
/** Artifact id of the GLB for a body: the one generated from `bodyArtifact`, or the module's first body GLB. */
|
|
93
|
+
export declare function glbFor(def: ModuleDef, bodyArtifact?: string): ArtifactDef | undefined;
|
|
94
|
+
/** Fetch every manifest JSON the modules declare (artifacts with format json generated from a body). */
|
|
95
|
+
export declare function loadManifests(defs: ModuleDef[], resolve: ArtifactResolver): Promise<Map<string, GeometryManifest>>;
|
|
96
|
+
export declare function buildCadModel(system: ModuleDef, lookup: ModuleLookup, manifests: Map<string, GeometryManifest>, hints?: {
|
|
97
|
+
path: string[];
|
|
98
|
+
matrix: Mat4;
|
|
99
|
+
note: string;
|
|
100
|
+
}[], rootPath?: string[]): CadModel;
|
|
101
|
+
/**
|
|
102
|
+
* The model with every part that nothing places, but that has a model of
|
|
103
|
+
* its own, added as a body in a row beside the rest (PB-1040): a module's
|
|
104
|
+
* 3D view never leaves out a part that has a model. The row is laid out by
|
|
105
|
+
* the view once the models are loaded (their sizes are known then). Undefined
|
|
106
|
+
* when there is no such part.
|
|
107
|
+
*/
|
|
108
|
+
export declare function withUnplacedInRow(model: CadModel, shown: ModuleDef, lookup: ModuleLookup): CadModel | undefined;
|
|
109
|
+
/**
|
|
110
|
+
* The named bodies a GLB comes apart into when exploded (D17): the largest
|
|
111
|
+
* stays, the rest move away from it. Only a cad standard output does this:
|
|
112
|
+
* `body.glb` with a `body.manifest.json` whose `bodies` lists two or more (an
|
|
113
|
+
* enclosure's back and lid), when the manifest was generated from the GLB, or
|
|
114
|
+
* when the module's print or cut exports make those bodies as separate pieces
|
|
115
|
+
* (`lid.stl` beside `base.stl`: both came from the same export). A vendor or
|
|
116
|
+
* library part's GLB stays rigid even when its manifest names several bodies
|
|
117
|
+
* (a motor's bell and stator, a prop's hub and blades).
|
|
118
|
+
*/
|
|
119
|
+
export declare function explodeParts(def: ModuleDef, glb: ArtifactDef | undefined, manifest: GeometryManifest | undefined): {
|
|
120
|
+
fixed: string;
|
|
121
|
+
moving: string[];
|
|
122
|
+
} | undefined;
|
|
123
|
+
export declare function interfaceRows(def: ModuleDef, manifests: Map<string, GeometryManifest>): InterfaceRow[];
|
|
124
|
+
/** Bolt-pattern / shaft parameters for procedural geometry (D3). */
|
|
125
|
+
export declare function param(iface: InterfaceDef, id: string): number | undefined;
|
|
126
|
+
export declare function traitParam<T>(iface: InterfaceDef, type: string, key: string): T | undefined;
|
|
127
|
+
/**
|
|
128
|
+
* The instance the assembly is placed from when the display hints don't say:
|
|
129
|
+
* the system itself when it has a body of its own, else the top-level module
|
|
130
|
+
* with the most interface frames (the structure the others mount to).
|
|
131
|
+
*/
|
|
132
|
+
export declare function defaultRoot(system: ModuleDef, lookup: (id: string) => ModuleDef | undefined): string[];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
/**
|
|
3
|
+
* Bodies that nothing places (PB-1040) in a row beside what is placed, once
|
|
4
|
+
* their models are loaded and their sizes known: along x, after the placed
|
|
5
|
+
* bodies, centred on them across and resting on their lowest point; from the
|
|
6
|
+
* origin when nothing is placed. Each one's `base` is where it now sits.
|
|
7
|
+
*/
|
|
8
|
+
export declare function layOutRow(recs: {
|
|
9
|
+
body: {
|
|
10
|
+
row?: boolean;
|
|
11
|
+
};
|
|
12
|
+
base: THREE.Matrix4;
|
|
13
|
+
obj: THREE.Object3D;
|
|
14
|
+
box: THREE.Box3;
|
|
15
|
+
}[]): void;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Imperative three.js scene for the 3D view (PB-775). Units: mm, Z up.
|
|
3
|
+
*
|
|
4
|
+
* GLB artifacts are glTF (metres, Y up); each is wrapped in a group that
|
|
5
|
+
* rotates +90° about X and scales ×1000, which returns it to the module's
|
|
6
|
+
* own CAD coordinates — the coordinates UHD frames are written in.
|
|
7
|
+
*/
|
|
8
|
+
import * as THREE from "three";
|
|
9
|
+
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
|
10
|
+
import { type GLTF } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
11
|
+
import type { GeometryFrame, InterfaceDef, ModuleDef } from "@deltarobotics/uhd";
|
|
12
|
+
import type { Mat4 } from "@deltarobotics/uhd";
|
|
13
|
+
import type { Appearance } from "../source/source";
|
|
14
|
+
/** The theme's colours for the scene, as `#rrggbb` (ThemeProvider's tokenColor). */
|
|
15
|
+
export interface SceneTheme {
|
|
16
|
+
background: string;
|
|
17
|
+
grid: string;
|
|
18
|
+
gridMinor: string;
|
|
19
|
+
accent: string;
|
|
20
|
+
highlight: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Highlight colours of one scene. The focus colours follow the theme's accent
|
|
24
|
+
* and highlight tokens; the rest are data colours. Each scene owns its set, so
|
|
25
|
+
* two viewers with different themes never share focus colours.
|
|
26
|
+
*/
|
|
27
|
+
export interface SceneColors {
|
|
28
|
+
focus: number;
|
|
29
|
+
counterpart: number;
|
|
30
|
+
normal: number;
|
|
31
|
+
xAxis: number;
|
|
32
|
+
phase: number[];
|
|
33
|
+
hint: number;
|
|
34
|
+
/** The selected body's emissive glow, and a stronger one for a picked interface's body. */
|
|
35
|
+
glow: number;
|
|
36
|
+
glowStrong: number;
|
|
37
|
+
}
|
|
38
|
+
/** The neutral default theme's accent and highlight (the stylesheet defaults), used until a theme is read. */
|
|
39
|
+
export declare const DEFAULT_SCENE_ACCENT = "#339fee";
|
|
40
|
+
export declare const DEFAULT_SCENE_HIGHLIGHT = "#22d3ee";
|
|
41
|
+
/** Fresh scene colours for a theme's accent and highlight (the selected body glows a dim accent). */
|
|
42
|
+
export declare function sceneColors(theme?: Pick<SceneTheme, "accent" | "highlight">): SceneColors;
|
|
43
|
+
/** WCAG relative luminance of a colour (0 black … 1 white). */
|
|
44
|
+
export declare function relativeLuminance(c: THREE.Color): number;
|
|
45
|
+
/** Load a GLB by URL (artifact URLs come from the viewer source's resolver). */
|
|
46
|
+
export declare function loadGlb(url: string): Promise<GLTF | null>;
|
|
47
|
+
/** glTF (m, Y-up) back to CAD coordinates (mm, Z-up). */
|
|
48
|
+
export declare function cadWrapper(obj: THREE.Object3D): THREE.Group;
|
|
49
|
+
export declare function toMatrix4(m: Mat4): THREE.Matrix4;
|
|
50
|
+
/**
|
|
51
|
+
* Surface for a module's body (or one named sub-body of its CAD), from, in
|
|
52
|
+
* order: display hints for the definition (and part), the part's declared
|
|
53
|
+
* material (UHD MaterialSpec), then neutral defaults by kind. Nothing here
|
|
54
|
+
* knows a particular project.
|
|
55
|
+
*/
|
|
56
|
+
export declare function materialFor(def: ModuleDef, bodyPart: string, appearance?: Appearance): THREE.MeshStandardMaterial;
|
|
57
|
+
export declare const focusMaterial: (color: number) => THREE.MeshStandardMaterial;
|
|
58
|
+
/** Group whose local X/Y/Z are the frame's xAxis / (normal × xAxis) / normal, origin at the frame origin. */
|
|
59
|
+
export declare function frameGroup(frame: GeometryFrame): THREE.Group;
|
|
60
|
+
export declare function frameGizmo(frame: GeometryFrame, colors: SceneColors, size?: number): THREE.Group;
|
|
61
|
+
/**
|
|
62
|
+
* D3: geometry derived from the interface's own parameters, placed at its
|
|
63
|
+
* frame. Returns null when the generator has nothing to work with. `notes`
|
|
64
|
+
* collects what the parameters could not say (e.g. pattern phase).
|
|
65
|
+
*/
|
|
66
|
+
export declare function proceduralGeometry(iface: InterfaceDef, generator: string, frame: GeometryFrame, color: number, notes: string[]): THREE.Object3D | null;
|
|
67
|
+
export interface SceneHandle {
|
|
68
|
+
scene: THREE.Scene;
|
|
69
|
+
camera: THREE.PerspectiveCamera;
|
|
70
|
+
controls: OrbitControls;
|
|
71
|
+
renderer: THREE.WebGLRenderer;
|
|
72
|
+
root: THREE.Group;
|
|
73
|
+
overlay: THREE.Group;
|
|
74
|
+
dispose: () => void;
|
|
75
|
+
frameAll: (box?: THREE.Box3) => void;
|
|
76
|
+
/**
|
|
77
|
+
* The model direction drawn up (default +z): the camera's up, the orbit
|
|
78
|
+
* axis, the ground grid and the lights follow it (a display hint, PB-873).
|
|
79
|
+
*/
|
|
80
|
+
setUp: (up: THREE.Vector3) => void;
|
|
81
|
+
/** Put the ground grid under a box (the assembled model), across the up direction. */
|
|
82
|
+
setGround: (box: THREE.Box3) => void;
|
|
83
|
+
/** This scene's highlight colours (follow `setTheme`). */
|
|
84
|
+
colors: SceneColors;
|
|
85
|
+
/** The theme's background, grid and focus colours. */
|
|
86
|
+
setTheme: (theme: SceneTheme) => void;
|
|
87
|
+
/** Called every frame before rendering, with the frame time in seconds. */
|
|
88
|
+
onFrame: Set<(dt: number) => void>;
|
|
89
|
+
/** When set, the render loop is driven externally (video capture). */
|
|
90
|
+
manual: {
|
|
91
|
+
on: boolean;
|
|
92
|
+
};
|
|
93
|
+
renderOnce: () => void;
|
|
94
|
+
}
|
|
95
|
+
export declare function createScene(container: HTMLElement): SceneHandle;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The 3D view of one module (PB-897): a system's view shows the whole
|
|
3
|
+
* assembly, a module's shows that module alone, in its own coordinates. The
|
|
4
|
+
* model is then built from the module's definition, so every path in it is
|
|
5
|
+
* relative to the module; a host's paths, the display hints and the findings
|
|
6
|
+
* are all written from the root. These functions translate between the two,
|
|
7
|
+
* and say what a view shows and what it leaves out.
|
|
8
|
+
*/
|
|
9
|
+
import type { ModuleDef } from "@deltarobotics/uhd";
|
|
10
|
+
import type { ModuleLookup } from "@deltarobotics/uhd";
|
|
11
|
+
import type { GeometryManifest, Mat4 } from "@deltarobotics/uhd";
|
|
12
|
+
import { type CadModel } from "./model";
|
|
13
|
+
/** A path from the root as a path inside `scope` ("" is the scope's own module); undefined when it is outside. */
|
|
14
|
+
export declare function intoScope(path: string, scope: string): string | undefined;
|
|
15
|
+
/** A path inside `scope` as a path from the root. */
|
|
16
|
+
export declare function outOfScope(path: string, scope: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* A finding's reference from the root (`board/u2:pin_14`, `board:sda`,
|
|
19
|
+
* `link:board/<id>`) as one inside `scope`; undefined when it names
|
|
20
|
+
* something outside.
|
|
21
|
+
*/
|
|
22
|
+
export declare function scopeRef(ref: string, scope: string): string | undefined;
|
|
23
|
+
/** The display hints' placements (keyed by path from the root, `#body` kept) that lie inside `scope`, re-keyed to it. */
|
|
24
|
+
export declare function scopedPlacements<T extends {
|
|
25
|
+
matrix: Mat4;
|
|
26
|
+
note?: string;
|
|
27
|
+
}>(placements: Record<string, T> | undefined, scope: string): {
|
|
28
|
+
path: string[];
|
|
29
|
+
matrix: Mat4;
|
|
30
|
+
note: string;
|
|
31
|
+
}[];
|
|
32
|
+
/** The display hints' assembly root (a path from the root) inside `scope`; undefined when it is not, or none is given. */
|
|
33
|
+
export declare function scopedRoot(root: string | undefined, scope: string): string[] | undefined;
|
|
34
|
+
/** The modules above `scope`, nearest first, as paths from the root (`""` is the root). */
|
|
35
|
+
export declare function ancestorsOf(scope: string): string[];
|
|
36
|
+
/**
|
|
37
|
+
* A model of an ancestor cut down to the module at `rel` (its path inside
|
|
38
|
+
* the ancestor) and re-keyed to it (PB-1040): what a module with no assembly
|
|
39
|
+
* of its own shows, its parts where the ancestor's assembly puts them. The
|
|
40
|
+
* matrices stay in the ancestor's coordinates (the view fits what is drawn);
|
|
41
|
+
* mates, routes and hardware are kept only when both of their ends lie in
|
|
42
|
+
* the module, and harnesses when they are in it.
|
|
43
|
+
*/
|
|
44
|
+
export declare function borrowModel(model: CadModel, rel: string[], from: string): CadModel;
|
|
45
|
+
export interface Unplaced {
|
|
46
|
+
/** Child id in the shown module. */
|
|
47
|
+
id: string;
|
|
48
|
+
name: string;
|
|
49
|
+
}
|
|
50
|
+
/** What a 3D view shows of a module, and what it does not. */
|
|
51
|
+
export interface ShownSummary {
|
|
52
|
+
/** The module has a body of its own (a board's `board.glb`): it is drawn as that body, its children in it. */
|
|
53
|
+
ownBody: boolean;
|
|
54
|
+
/** The module's direct children that are parts (harnesses are drawn as cables and hardware, not counted). */
|
|
55
|
+
parts: number;
|
|
56
|
+
/** Those of them that are drawn: placed, or inside the module's own body. */
|
|
57
|
+
placed: Unplaced[];
|
|
58
|
+
/** Those that are not: nothing says where they sit. */
|
|
59
|
+
unplaced: Unplaced[];
|
|
60
|
+
/** Those of `placed` that nothing places either, drawn beside the others (PB-1040). */
|
|
61
|
+
inRow: Unplaced[];
|
|
62
|
+
/**
|
|
63
|
+
* Nothing joins the module's parts: it has no body of its own, more than
|
|
64
|
+
* one part, and no mate or hint places a second one. What would be drawn
|
|
65
|
+
* is one part on its own, which is not a picture of the module.
|
|
66
|
+
*/
|
|
67
|
+
loose: boolean;
|
|
68
|
+
}
|
|
69
|
+
export declare function shownSummary(model: CadModel, shown: ModuleDef, lookup: ModuleLookup): ShownSummary;
|
|
70
|
+
/**
|
|
71
|
+
* The model a 3D view draws of the module at `at` (a path from the root;
|
|
72
|
+
* `""` is the root), PB-897 and PB-1040:
|
|
73
|
+
*
|
|
74
|
+
* 1. the module's own assembly: its mates and the display hints inside it;
|
|
75
|
+
* 2. when that leaves parts unplaced and the module has no body of its own,
|
|
76
|
+
* the nearest ancestor whose assembly places more of them: its assembly,
|
|
77
|
+
* cut down to the module (`borrowModel`);
|
|
78
|
+
* 3. what nothing places but has a model is drawn beside the rest, in a row
|
|
79
|
+
* (`withUnplacedInRow`), and the view says so.
|
|
80
|
+
*
|
|
81
|
+
* The root's view is its own assembly, as before.
|
|
82
|
+
*/
|
|
83
|
+
export declare function scopedModel(system: ModuleDef, lookup: ModuleLookup, manifests: Map<string, GeometryManifest>, display: {
|
|
84
|
+
placements?: Record<string, {
|
|
85
|
+
matrix: Mat4;
|
|
86
|
+
note?: string;
|
|
87
|
+
}>;
|
|
88
|
+
root?: string;
|
|
89
|
+
}, at: string): CadModel;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { ViewModel } from "../model/types";
|
|
2
|
+
import type { NodeMark } from "../api";
|
|
3
|
+
import { type Classification } from "../model/classification";
|
|
4
|
+
import type { ComputedLayout } from "../layout/layout";
|
|
5
|
+
import type { LevelLayout, LinkLayout } from "../layout/layout";
|
|
6
|
+
import { type Detail } from "./LinkEdge";
|
|
7
|
+
import type { Pt } from "./routing";
|
|
8
|
+
import type { Isolation } from "../model/isolate";
|
|
9
|
+
import type { Live } from "../viewer/controller";
|
|
10
|
+
import { type InteractionAction, type InteractionState, type Viewport } from "./interaction";
|
|
11
|
+
/** A view command from outside the canvas (a toolbar, a menu): fit, or a zoom step; `seq` tells repeats apart. */
|
|
12
|
+
export interface ViewCommand {
|
|
13
|
+
type: "fit" | "in" | "out" | "reset";
|
|
14
|
+
seq: number;
|
|
15
|
+
}
|
|
16
|
+
export type Selection = {
|
|
17
|
+
kind: "node" | "link";
|
|
18
|
+
id: string;
|
|
19
|
+
} | null;
|
|
20
|
+
/** Fit padding that keeps the diagram clear of the floating chrome: the header, the toolbar and, when open, the inspector. */
|
|
21
|
+
export declare const fitPadding: (inspector: boolean) => {
|
|
22
|
+
readonly top: "56px";
|
|
23
|
+
readonly bottom: "72px";
|
|
24
|
+
readonly left: "64px";
|
|
25
|
+
readonly right: "376px" | "64px";
|
|
26
|
+
};
|
|
27
|
+
export interface CanvasProps {
|
|
28
|
+
vm: ViewModel;
|
|
29
|
+
/** The inspector is open over the right of the canvas (fitting leaves room for it). */
|
|
30
|
+
inspector?: boolean;
|
|
31
|
+
layout: ComputedLayout;
|
|
32
|
+
hand?: LevelLayout;
|
|
33
|
+
mode: Classification;
|
|
34
|
+
detail: Detail;
|
|
35
|
+
showGrounds: boolean;
|
|
36
|
+
openLinks: Set<string>;
|
|
37
|
+
selection: Selection;
|
|
38
|
+
onSelect: (s: Selection) => void;
|
|
39
|
+
onToggleLink: (id: string) => void;
|
|
40
|
+
onLayout: (linkId: string, patch: LinkLayout) => void;
|
|
41
|
+
onPins: (linkId: string, pins: Pt[]) => void;
|
|
42
|
+
onToggleExpand: (id: string) => void;
|
|
43
|
+
/** Double-click on a node (default: expand it in place). */
|
|
44
|
+
onOpenNode?: (id: string) => void;
|
|
45
|
+
onMove: (id: string, x: number, y: number) => void;
|
|
46
|
+
/** A drag starts (what moves) or ends (null): the layout reroutes only what moves meanwhile. */
|
|
47
|
+
onLive: (live: Live | null) => void;
|
|
48
|
+
/**
|
|
49
|
+
* A node to bring into view (a host's focus, a row of the hierarchy), once it is drawn; `seq` tells repeats
|
|
50
|
+
* apart. With `lines`, a harness drawn along lines (no card of its own): those lines are framed.
|
|
51
|
+
*/
|
|
52
|
+
centre?: {
|
|
53
|
+
id: string;
|
|
54
|
+
seq: number;
|
|
55
|
+
lines?: readonly string[];
|
|
56
|
+
};
|
|
57
|
+
/** A selection to bring into view if it is not (a host's select): panned to, zoomed out only if it must; `seq` tells repeats apart. */
|
|
58
|
+
reveal?: {
|
|
59
|
+
selection: NonNullable<Selection>;
|
|
60
|
+
seq: number;
|
|
61
|
+
};
|
|
62
|
+
/** Right-click on a node: its context menu at the pointer (the browser's own when not given). */
|
|
63
|
+
onNodeContext?: (id: string, x: number, y: number) => void;
|
|
64
|
+
/** The host's marks by definition id (`ViewerOptions.nodeMarks`). */
|
|
65
|
+
marks?: Record<string, NodeMark>;
|
|
66
|
+
/** Legend entries are isolated: what stays at full strength (the rest fades). */
|
|
67
|
+
isolation?: Isolation | null;
|
|
68
|
+
/** Modules selected together (a selection box, clicks with Shift, Ctrl or Cmd, select all): two or more, else empty. */
|
|
69
|
+
group?: readonly string[];
|
|
70
|
+
/** React Flow selected or unselected modules (a box, a click with a key held, a press on a module): the changes, a rail's taps named as the rail. */
|
|
71
|
+
onSelectChanges?: (changes: {
|
|
72
|
+
id: string;
|
|
73
|
+
selected: boolean;
|
|
74
|
+
}[]) => void;
|
|
75
|
+
/** The tool chosen and whether Space is held (default: select). */
|
|
76
|
+
interaction?: InteractionState;
|
|
77
|
+
onInteraction?: (action: InteractionAction) => void;
|
|
78
|
+
/** Ctrl/Cmd+A, and Escape. */
|
|
79
|
+
onSelectAll?: () => void;
|
|
80
|
+
onEscape?: () => void;
|
|
81
|
+
/** Fit or zoom, asked for by a toolbar or a menu. */
|
|
82
|
+
command?: ViewCommand;
|
|
83
|
+
/** The viewport saved for this level: put back when the canvas opens (none: the diagram is fitted). */
|
|
84
|
+
viewport?: Viewport;
|
|
85
|
+
/** The user moved the view (its viewport), or asked for a fit (null: nothing is kept, the next opening fits). */
|
|
86
|
+
onViewport?: (viewport: Viewport | null) => void;
|
|
87
|
+
/** Right-click on the empty canvas: its menu at the pointer (the browser's own when not given). */
|
|
88
|
+
onPaneContext?: (x: number, y: number) => void;
|
|
89
|
+
}
|
|
90
|
+
export declare function Canvas(props: CanvasProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type Edge, type EdgeProps } from "@xyflow/react";
|
|
2
|
+
import type { ViewLink } from "../model/types";
|
|
3
|
+
import { type Classification } from "../model/classification";
|
|
4
|
+
import { type Pt } from "./routing";
|
|
5
|
+
import type { LinkLayout } from "../layout/layout";
|
|
6
|
+
import type { Live } from "../viewer/controller";
|
|
7
|
+
export type Detail = "basic" | "ribbon";
|
|
8
|
+
export interface LinkData extends Record<string, unknown> {
|
|
9
|
+
link: ViewLink;
|
|
10
|
+
points: Pt[];
|
|
11
|
+
color: string;
|
|
12
|
+
faded: boolean;
|
|
13
|
+
mode: Classification;
|
|
14
|
+
detail: Detail;
|
|
15
|
+
/** Expanded (lanes shown). */
|
|
16
|
+
open: boolean;
|
|
17
|
+
openLanes: Set<string>;
|
|
18
|
+
/** Harness span along the route (arc lengths). */
|
|
19
|
+
run?: [number, number];
|
|
20
|
+
/** Label + toggle position (arc length); absent: no label. */
|
|
21
|
+
labelAt?: number;
|
|
22
|
+
/** The label was placed by the user (or the display file): honour it even on a short stretch. */
|
|
23
|
+
labelFixed?: boolean;
|
|
24
|
+
pins: Pt[];
|
|
25
|
+
bends: Pt[];
|
|
26
|
+
onToggle: (id: string) => void;
|
|
27
|
+
onToggleLane: (id: string) => void;
|
|
28
|
+
/** Select the link (a click on its label: the label stops the edge's own click). */
|
|
29
|
+
onSelect?: (linkId: string) => void;
|
|
30
|
+
/** Where the user put the label and harness tab (and which side of the line). */
|
|
31
|
+
edit?: LinkLayout;
|
|
32
|
+
onLayout: (linkId: string, patch: LinkLayout) => void;
|
|
33
|
+
onPins: (linkId: string, pins: Pt[]) => void;
|
|
34
|
+
onLive: (live: Live | null) => void;
|
|
35
|
+
}
|
|
36
|
+
export type LinkEdgeType = Edge<LinkData, "link">;
|
|
37
|
+
export declare function LinkEdge({ id, data, selected }: EdgeProps<LinkEdgeType>): import("react").JSX.Element | null;
|
|
38
|
+
export declare const edgeTypes: {
|
|
39
|
+
link: typeof LinkEdge;
|
|
40
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PlacedPort } from "../layout/layout";
|
|
2
|
+
export interface PortProps {
|
|
3
|
+
placed: PlacedPort;
|
|
4
|
+
/** Position relative to the node's top-left corner. */
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
color: string;
|
|
8
|
+
faded: boolean;
|
|
9
|
+
exported?: boolean;
|
|
10
|
+
label?: boolean;
|
|
11
|
+
ground?: boolean;
|
|
12
|
+
selected?: boolean;
|
|
13
|
+
/** Draw the dot (off where a ribbon's pin handle already marks the port). */
|
|
14
|
+
dot?: boolean;
|
|
15
|
+
/** Max label width in px (from port spacing and card size). */
|
|
16
|
+
labelWidth?: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function Port({ placed, x, y, color, faded, exported, label, ground, selected, dot, labelWidth }: PortProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Geometry along a routed link (PB-803): positions by arc length, sub-paths,
|
|
3
|
+
* lanes that fan out of the centre line, and harness regions traced around
|
|
4
|
+
* whatever runs through them. Pure functions, no React.
|
|
5
|
+
*/
|
|
6
|
+
import { type Pt } from "./routing";
|
|
7
|
+
export declare const RUN = 24;
|
|
8
|
+
export declare const LANE_PITCH = 16;
|
|
9
|
+
export declare const RIBBON_PITCH = 6;
|
|
10
|
+
export declare function lengths(points: Pt[]): number[];
|
|
11
|
+
export declare const totalLength: (points: Pt[]) => number;
|
|
12
|
+
/** Point and unit direction at arc length `s`. */
|
|
13
|
+
export declare function at(points: Pt[], s: number): {
|
|
14
|
+
p: Pt;
|
|
15
|
+
d: Pt;
|
|
16
|
+
};
|
|
17
|
+
/** The polyline between arc lengths s0 and s1. */
|
|
18
|
+
export declare function subpath(points: Pt[], s0: number, s1: number): Pt[];
|
|
19
|
+
/** Arc length of the point on the polyline nearest to `q`. */
|
|
20
|
+
export declare function project(points: Pt[], q: Pt): number;
|
|
21
|
+
export declare function densify(points: Pt[], step?: number): Pt[];
|
|
22
|
+
/** Offsets for n lanes centred on the line. */
|
|
23
|
+
export declare const offsets: (n: number, pitch: number) => number[];
|
|
24
|
+
/** Fillet radius for the centre line of a ribbon `width` wide, so its inner conductor still turns round. */
|
|
25
|
+
export declare const ribbonRadius: (width: number) => number;
|
|
26
|
+
/** Stroke points of a ribbon (parallel conductors at a fixed pitch) along the whole route. */
|
|
27
|
+
export declare function ribbon(points: Pt[], n: number, radius?: number): {
|
|
28
|
+
d: string;
|
|
29
|
+
samples: Pt[];
|
|
30
|
+
}[];
|
|
31
|
+
/**
|
|
32
|
+
* The straight stretches of a route as arc-length intervals, each kept `clear`
|
|
33
|
+
* of the corners at its ends (and `end` of the route's own ends).
|
|
34
|
+
*/
|
|
35
|
+
export declare function straights(points: Pt[], clear: number, end?: number): [number, number][];
|
|
36
|
+
/**
|
|
37
|
+
* The nearest arc length to `s` that sits on a straight stretch, clear of the
|
|
38
|
+
* bends (handles and toggles never sit in a corner). Where no stretch is long
|
|
39
|
+
* enough, the middle of the longest segment.
|
|
40
|
+
*/
|
|
41
|
+
export declare function clearOfBends(points: Pt[], s: number, clear: number, end?: number): number;
|
|
42
|
+
/** The straight stretch (with `clear` at its corners) that contains arc length `s`. */
|
|
43
|
+
export declare function stretchAt(points: Pt[], s: number, clear: number, end?: number): [number, number];
|
|
44
|
+
/**
|
|
45
|
+
* Turn short S-jogs (a sidestep between two runs in the same direction,
|
|
46
|
+
* shorter than `min`) into a gentle diagonal: a wide ribbon cannot take two
|
|
47
|
+
* right angles in less than its own width without its conductors crossing.
|
|
48
|
+
*/
|
|
49
|
+
export declare function easeJogs(points: Pt[], min: number): Pt[];
|
|
50
|
+
/**
|
|
51
|
+
* A closed outline around every sample (dilated by `pad`), traced on a 2 px
|
|
52
|
+
* raster and smoothed: the harness region, tight to what runs through it.
|
|
53
|
+
*/
|
|
54
|
+
export declare function regionOutline(samples: Pt[], pad: number): string;
|
|
55
|
+
/** A stretch of a line at a constant offset from the centre line, between arc lengths a and b. */
|
|
56
|
+
export interface Plateau {
|
|
57
|
+
o: number;
|
|
58
|
+
a: number;
|
|
59
|
+
b: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A line that steps between offsets from the centre line: it runs each
|
|
63
|
+
* plateau parallel to the route and curves smoothly from one to the next over
|
|
64
|
+
* the gap between them (b of one to a of the next). Consecutive plateaus at
|
|
65
|
+
* the same offset join straight through. The building block of every
|
|
66
|
+
* breakout: a lane leaving its parent line, and a conductor stepping out
|
|
67
|
+
* level by level.
|
|
68
|
+
*/
|
|
69
|
+
export declare function stepped(points: Pt[], plateaus: Plateau[], radius?: number): {
|
|
70
|
+
d: string;
|
|
71
|
+
samples: Pt[];
|
|
72
|
+
};
|