@sakibcoolz/core 0.1.1 → 0.2.0
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 +67 -7
- package/dist/acquisition.d.ts +29 -0
- package/dist/acquisition.d.ts.map +1 -0
- package/dist/acquisition.js +30 -0
- package/dist/acquisition.js.map +1 -0
- package/dist/assembly.d.ts +5 -2
- package/dist/assembly.d.ts.map +1 -1
- package/dist/assembly.js +7 -4
- package/dist/assembly.js.map +1 -1
- package/dist/attach.d.ts +4 -2
- package/dist/attach.d.ts.map +1 -1
- package/dist/attach.js +5 -3
- package/dist/attach.js.map +1 -1
- package/dist/clipboard.d.ts +6 -4
- package/dist/clipboard.d.ts.map +1 -1
- package/dist/clipboard.js +25 -4
- package/dist/clipboard.js.map +1 -1
- package/dist/collision.d.ts +2 -2
- package/dist/collision.js.map +1 -1
- package/dist/digest.d.ts +9 -0
- package/dist/digest.d.ts.map +1 -0
- package/dist/digest.js +68 -0
- package/dist/digest.js.map +1 -0
- package/dist/flow.d.ts +3 -2
- package/dist/flow.d.ts.map +1 -1
- package/dist/flow.js.map +1 -1
- package/dist/graph.d.ts +67 -7
- package/dist/graph.d.ts.map +1 -1
- package/dist/graph.js +195 -10
- package/dist/graph.js.map +1 -1
- package/dist/index.d.ts +13 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/observation.d.ts +1 -1
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +4 -1
- package/dist/observation.js.map +1 -1
- package/dist/routing.d.ts +6 -3
- package/dist/routing.d.ts.map +1 -1
- package/dist/routing.js +12 -2
- package/dist/routing.js.map +1 -1
- package/dist/scene.d.ts +245 -5
- package/dist/scene.d.ts.map +1 -1
- package/dist/scene.js +94 -3
- package/dist/scene.js.map +1 -1
- package/dist/serialization.d.ts +7 -7
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js +120 -8
- package/dist/serialization.js.map +1 -1
- package/dist/snapping.d.ts +2 -2
- package/dist/snapping.d.ts.map +1 -1
- package/dist/snapping.js +10 -7
- package/dist/snapping.js.map +1 -1
- package/dist/status.d.ts +56 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +114 -0
- package/dist/status.js.map +1 -0
- package/dist/tags.d.ts +52 -0
- package/dist/tags.d.ts.map +1 -0
- package/dist/tags.js +103 -0
- package/dist/tags.js.map +1 -0
- package/dist/telemetry.d.ts +42 -4
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +84 -8
- package/dist/telemetry.js.map +1 -1
- package/dist/touching.d.ts +2 -2
- package/dist/touching.d.ts.map +1 -1
- package/dist/touching.js +7 -4
- package/dist/touching.js.map +1 -1
- package/dist/units.js +1 -1
- package/dist/units.js.map +1 -1
- package/dist/upgrade.d.ts +2 -2
- package/dist/upgrade.js.map +1 -1
- package/dist/validation.d.ts +33 -6
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +806 -39
- package/dist/validation.js.map +1 -1
- package/package.json +4 -2
- package/schema/fixtures/invalid/association-without-relationship.scene.json +69 -0
- package/schema/fixtures/invalid/binding-kind.scene.json +14 -0
- package/schema/fixtures/invalid/command-zero-step.scene.json +105 -0
- package/schema/fixtures/invalid/empty-name.scene.json +30 -0
- package/schema/fixtures/invalid/expected.json +70 -0
- package/schema/fixtures/invalid/extension-not-namespaced.scene.json +10 -0
- package/schema/fixtures/invalid/extension-prototype-key.scene.json +12 -0
- package/schema/fixtures/invalid/missing-document-type.scene.json +6 -0
- package/schema/fixtures/invalid/non-string-label.scene.json +32 -0
- package/schema/fixtures/invalid/underlay-opacity.scene.json +17 -0
- package/schema/fixtures/invalid/unknown-component-kind.scene.json +29 -0
- package/schema/fixtures/invalid/unknown-relationship.scene.json +63 -0
- package/schema/fixtures/invalid/unknown-root-field.scene.json +8 -0
- package/schema/fixtures/invalid/unsupported-version.scene.json +7 -0
- package/schema/fixtures/invalid/view-rotation.scene.json +139 -0
- package/schema/fixtures/invalid/writable-string.scene.json +93 -0
- package/schema/fixtures/invalid/writable-without-limits.scene.json +100 -0
- package/schema/fixtures/invalid/zero-scale.scene.json +29 -0
- package/schema/fixtures/migration/README.md +18 -0
- package/schema/fixtures/migration/v1-demo.scene.json +160 -0
- package/schema/fixtures/migration/v1-demo.v4.json +198 -0
- package/schema/fixtures/migration/v2-demo.scene.json +244 -0
- package/schema/fixtures/migration/v2-demo.v4.json +245 -0
- package/schema/fixtures/migration/v2-generated-12.scene.json +473 -0
- package/schema/fixtures/migration/v2-generated-12.v4.json +474 -0
- package/schema/fixtures/migration/v3-demo.scene.json +244 -0
- package/schema/fixtures/migration/v3-demo.v4.json +245 -0
- package/schema/fixtures/migration/v3-generated-12.scene.json +473 -0
- package/schema/fixtures/migration/v3-generated-12.v4.json +474 -0
- package/schema/fixtures/migration/v3-mostly-connected-plant.scene.json +386 -0
- package/schema/fixtures/migration/v3-mostly-connected-plant.v4.json +387 -0
- package/schema/fixtures/migration/v3-open-joints-plant.scene.json +288 -0
- package/schema/fixtures/migration/v3-open-joints-plant.v4.json +289 -0
- package/schema/fixtures/migration/v3-unconnected-plant.scene.json +14 -0
- package/schema/fixtures/migration/v3-unconnected-plant.v4.json +276 -0
- package/schema/fixtures/projection/acquisition.plan.json +50 -0
- package/schema/fixtures/projection/control-line.plan.json +86 -0
- package/schema/fixtures/valid/acquisition.scene.json +117 -0
- package/schema/fixtures/valid/associations.scene.json +79 -0
- package/schema/fixtures/valid/commands.scene.json +155 -0
- package/schema/fixtures/valid/control-line.scene.json +210 -0
- package/schema/fixtures/valid/empty.scene.json +7 -0
- package/schema/fixtures/valid/identity-and-extensions.scene.json +96 -0
- package/schema/fixtures/valid/tank-valve-line.scene.json +89 -0
- package/schema/fixtures/valid/views.scene.json +139 -0
- package/schema/fixtures/validator-only/association-id-reuses-connection.scene.json +70 -0
- package/schema/fixtures/validator-only/association-unknown-component.scene.json +70 -0
- package/schema/fixtures/validator-only/command-max-below-min.scene.json +104 -0
- package/schema/fixtures/validator-only/command-out-of-type-range.scene.json +97 -0
- package/schema/fixtures/validator-only/connection-domain-mismatch.scene.json +63 -0
- package/schema/fixtures/validator-only/credential-in-connection.scene.json +66 -0
- package/schema/fixtures/validator-only/credential-in-extension.scene.json +14 -0
- package/schema/fixtures/validator-only/credential-label.scene.json +32 -0
- package/schema/fixtures/validator-only/duplicate-component-id.scene.json +50 -0
- package/schema/fixtures/validator-only/endpoint-with-credentials.scene.json +74 -0
- package/schema/fixtures/validator-only/expected.json +66 -0
- package/schema/fixtures/validator-only/modbus-coil-float.scene.json +100 -0
- package/schema/fixtures/validator-only/non-unit-rotation.scene.json +29 -0
- package/schema/fixtures/validator-only/unknown-data-source.scene.json +100 -0
- package/schema/fixtures/validator-only/unknown-port.scene.json +62 -0
- package/schema/fixtures/validator-only/unregistered-host-type.scene.json +29 -0
- package/schema/fixtures/validator-only/view-unknown-component.scene.json +143 -0
- package/schema/industrial-scene.v4.schema.json +365 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
|
-
export { SCENE_SCHEMA_VERSION, componentKinds, createEmptyScene, portsCompatible } from './scene.js';
|
|
2
|
-
export type { ComponentDefinition, ComponentInstance, ComponentKind, ConnectionPort, PortKind, QuaternionLike, QuaternionTuple, Quantity, ScadaScene, SceneConnection, SceneUnderlay, TagBinding, Vector3Like, Vector3Tuple, } from './scene.js';
|
|
1
|
+
export { SCENE_DOCUMENT_TYPE, SCENE_SCHEMA_VERSION, componentKinds, createEmptyScene, isBuiltInKind, isNamespacedType, isRelationship, relationshipKinds, dataTypes, modbusAreas, protocols, checkPorts, matesPhysically, portCapacity, portKinds, portsCompatible, powerKinds, signalTypes, viewKinds } from './scene.js';
|
|
2
|
+
export type { CommandLimits, ComponentDefinition, VariableTemplate, ComponentInstance, ComponentKind, ComponentType, ConnectionPort, JsonValue, PortCheck, PortFlow, PortKind, PowerKind, SignalType, QuaternionLike, QuaternionTuple, Relationship, Quantity, ScadaScene, DataType, ModbusAddress, OpcUaAddress, Protocol, RuntimeVariable, SceneAssociation, SceneDataSource, VariableAddress, SceneConnection, SceneExtensions, SceneProject, SceneUnderlay, SceneViews, SymbolPlacement, TagBinding, Vector3Like, Vector3Tuple, ViewKind, ViewLayout, ViewRoute, } from './scene.js';
|
|
3
3
|
export { canonicalUnits, isKnownUnit, toCanonical } from './units.js';
|
|
4
4
|
export { defaultSceneLimits, validateScene } from './validation.js';
|
|
5
5
|
export type { SceneLimits, SceneValidationError, SceneValidationErrorCode, SceneValidationOptions, SceneValidationResult } from './validation.js';
|
|
6
6
|
export { parseScene, serializeScene } from './serialization.js';
|
|
7
|
+
export { sceneDigest, sha256Hex } from './digest.js';
|
|
8
|
+
export { alarmSeverities, componentStatus } from './status.js';
|
|
9
|
+
export type { AlarmSeverity, AlarmState, ComponentStatus, ComponentStatusKind, StatusResult } from './status.js';
|
|
7
10
|
export type { ParseSceneOptions } from './serialization.js';
|
|
8
11
|
export { identityQuaternion, quaternionFromEuler, quaternionToEuler, rotateVector } from './rotation.js';
|
|
9
12
|
export { portToWorld } from './transforms.js';
|
|
10
13
|
export type { ComponentTransform, WorldPort } from './transforms.js';
|
|
11
14
|
export { findSnapCandidates, snapComponent } from './snapping.js';
|
|
12
15
|
export type { SnapCandidate, SnapOptions, SnapResult, SnapStatus } from './snapping.js';
|
|
13
|
-
export {
|
|
14
|
-
export
|
|
16
|
+
export { projectAcquisition } from './acquisition.js';
|
|
17
|
+
export { applyTagSuggestions, reviewTags, suggestVariables } from './tags.js';
|
|
18
|
+
export type { ApplyResult, SuggestOptions, TagFinding, TagFindingCode, TagSuggestions } from './tags.js';
|
|
19
|
+
export type { AcquisitionPlan, AcquisitionVariable } from './acquisition.js';
|
|
20
|
+
export { addAssociation, removeAssociation, connect, connectedGroups, connectionsOf, disconnect, neighbours, pathBetween, physicalDomains, reachableComponents, relatedComponents, removeComponent } from './graph.js';
|
|
21
|
+
export type { ConnectionFilter, GraphError, GraphErrorCode, GraphFilter, GraphOptions, GraphResult, GraphStep } from './graph.js';
|
|
15
22
|
export { routeConnection, routeScene, sampleRouteCenterline } from './routing.js';
|
|
16
23
|
export type { PipeRoute, RouteBend, RouteFailure, RouteKind, RoutingOptions } from './routing.js';
|
|
17
24
|
export { assemblyOf, lockConnectedAsChildren, moveAssembly, unlockFromParent } from './assembly.js';
|
|
@@ -31,8 +38,8 @@ export type { CollisionOptions, CollisionPair, CollisionResult } from './collisi
|
|
|
31
38
|
export { resolveFlow } from './flow.js';
|
|
32
39
|
export type { FlowDirection, FlowOptions, FlowReading, FlowResolution, FlowState, FlowUnknownReason, Quality, ValueSource } from './flow.js';
|
|
33
40
|
export type { FreshnessOptions } from './observation.js';
|
|
34
|
-
export { displayScene, resolveTelemetry } from './telemetry.js';
|
|
35
|
-
export type { Observation, PropertyState, TelemetryOptions, TelemetryResolution, TelemetryUnknownReason } from './telemetry.js';
|
|
41
|
+
export { displayScene, resolveTelemetry, resolveVariableValues, valueFitsDataType } from './telemetry.js';
|
|
42
|
+
export type { Observation, PropertyState, VariableState, TelemetryOptions, TelemetryResolution, TelemetryUnknownReason } from './telemetry.js';
|
|
36
43
|
export { connectProvider, createObservationStore } from './dataInput.js';
|
|
37
44
|
export type { DataProvider, ObservationStore } from './dataInput.js';
|
|
38
45
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
// Public API of @sakibcoolz/core. Everything not listed here is internal. See docs/API.md;
|
|
2
2
|
// `api.test.ts` fails when the runtime surface changes.
|
|
3
3
|
// Scene model and units
|
|
4
|
-
export { SCENE_SCHEMA_VERSION, componentKinds, createEmptyScene, portsCompatible } from './scene.js';
|
|
4
|
+
export { SCENE_DOCUMENT_TYPE, SCENE_SCHEMA_VERSION, componentKinds, createEmptyScene, isBuiltInKind, isNamespacedType, isRelationship, relationshipKinds, dataTypes, modbusAreas, protocols, checkPorts, matesPhysically, portCapacity, portKinds, portsCompatible, powerKinds, signalTypes, viewKinds } from './scene.js';
|
|
5
5
|
export { canonicalUnits, isKnownUnit, toCanonical } from './units.js';
|
|
6
6
|
// Validation, persistence and migration
|
|
7
7
|
export { defaultSceneLimits, validateScene } from './validation.js';
|
|
8
8
|
export { parseScene, serializeScene } from './serialization.js';
|
|
9
|
+
export { sceneDigest, sha256Hex } from './digest.js';
|
|
10
|
+
export { alarmSeverities, componentStatus } from './status.js';
|
|
9
11
|
// Transforms
|
|
10
12
|
export { identityQuaternion, quaternionFromEuler, quaternionToEuler, rotateVector } from './rotation.js';
|
|
11
13
|
export { portToWorld } from './transforms.js';
|
|
12
14
|
// Connections: snapping, graph, routing
|
|
13
15
|
export { findSnapCandidates, snapComponent } from './snapping.js';
|
|
14
|
-
export {
|
|
16
|
+
export { projectAcquisition } from './acquisition.js';
|
|
17
|
+
export { applyTagSuggestions, reviewTags, suggestVariables } from './tags.js';
|
|
18
|
+
export { addAssociation, removeAssociation, connect, connectedGroups, connectionsOf, disconnect, neighbours, pathBetween, physicalDomains, reachableComponents, relatedComponents, removeComponent } from './graph.js';
|
|
15
19
|
export { routeConnection, routeScene, sampleRouteCenterline } from './routing.js';
|
|
16
20
|
// Assemblies: parent/child locks for rigid editing (ADR-0008)
|
|
17
21
|
export { assemblyOf, lockConnectedAsChildren, moveAssembly, unlockFromParent } from './assembly.js';
|
|
@@ -29,6 +33,6 @@ export { findOpenJoints, seatOnConnection } from './joints.js';
|
|
|
29
33
|
export { findCollisions } from './collision.js';
|
|
30
34
|
// Read-only observations: flow, telemetry, host data input
|
|
31
35
|
export { resolveFlow } from './flow.js';
|
|
32
|
-
export { displayScene, resolveTelemetry } from './telemetry.js';
|
|
36
|
+
export { displayScene, resolveTelemetry, resolveVariableValues, valueFitsDataType } from './telemetry.js';
|
|
33
37
|
export { connectProvider, createObservationStore } from './dataInput.js';
|
|
34
38
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,wDAAwD;AAExD,wBAAwB;AACxB,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,wDAAwD;AAExD,wBAAwB;AACxB,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,cAAc,EAAE,gBAAgB,EAAE,aAAa,EAAE,gBAAgB,EAAE,cAAc,EAAE,iBAAiB,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAyC3T,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEtE,wCAAwC;AACxC,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAI/D,aAAa;AACb,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACzG,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9C,wCAAwC;AACxC,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAElE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAG9E,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEvN,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAGlF,8DAA8D;AAC9D,OAAO,EAAE,UAAU,EAAE,uBAAuB,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGpG,8CAA8C;AAC9C,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGjF,4EAA4E;AAC5E,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGxE,gFAAgF;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGjD,iFAAiF;AACjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,gFAAgF;AAChF,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/D,oCAAoC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGhD,2DAA2D;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAGxC,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAE1G,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC","sourcesContent":["// Public API of @sakibcoolz/core. Everything not listed here is internal. See docs/API.md;\n// `api.test.ts` fails when the runtime surface changes.\n\n// Scene model and units\nexport { SCENE_DOCUMENT_TYPE, SCENE_SCHEMA_VERSION, componentKinds, createEmptyScene, isBuiltInKind, isNamespacedType, isRelationship, relationshipKinds, dataTypes, modbusAreas, protocols, checkPorts, matesPhysically, portCapacity, portKinds, portsCompatible, powerKinds, signalTypes, viewKinds } from './scene.js';\nexport type {\n CommandLimits,\n ComponentDefinition,\n VariableTemplate,\n ComponentInstance,\n ComponentKind,\n ComponentType,\n ConnectionPort,\n JsonValue,\n PortCheck,\n PortFlow,\n PortKind,\n PowerKind,\n SignalType,\n QuaternionLike,\n QuaternionTuple,\n Relationship,\n Quantity,\n ScadaScene,\n DataType,\n ModbusAddress,\n OpcUaAddress,\n Protocol,\n RuntimeVariable,\n SceneAssociation,\n SceneDataSource,\n VariableAddress,\n SceneConnection,\n SceneExtensions,\n SceneProject,\n SceneUnderlay,\n SceneViews,\n SymbolPlacement,\n TagBinding,\n Vector3Like,\n Vector3Tuple,\n ViewKind,\n ViewLayout,\n ViewRoute,\n} from './scene.js';\nexport { canonicalUnits, isKnownUnit, toCanonical } from './units.js';\n\n// Validation, persistence and migration\nexport { defaultSceneLimits, validateScene } from './validation.js';\nexport type { SceneLimits, SceneValidationError, SceneValidationErrorCode, SceneValidationOptions, SceneValidationResult } from './validation.js';\nexport { parseScene, serializeScene } from './serialization.js';\nexport { sceneDigest, sha256Hex } from './digest.js';\nexport { alarmSeverities, componentStatus } from './status.js';\nexport type { AlarmSeverity, AlarmState, ComponentStatus, ComponentStatusKind, StatusResult } from './status.js';\nexport type { ParseSceneOptions } from './serialization.js';\n\n// Transforms\nexport { identityQuaternion, quaternionFromEuler, quaternionToEuler, rotateVector } from './rotation.js';\nexport { portToWorld } from './transforms.js';\nexport type { ComponentTransform, WorldPort } from './transforms.js';\n\n// Connections: snapping, graph, routing\nexport { findSnapCandidates, snapComponent } from './snapping.js';\nexport type { SnapCandidate, SnapOptions, SnapResult, SnapStatus } from './snapping.js';\nexport { projectAcquisition } from './acquisition.js';\nexport { applyTagSuggestions, reviewTags, suggestVariables } from './tags.js';\nexport type { ApplyResult, SuggestOptions, TagFinding, TagFindingCode, TagSuggestions } from './tags.js';\nexport type { AcquisitionPlan, AcquisitionVariable } from './acquisition.js';\nexport { addAssociation, removeAssociation, connect, connectedGroups, connectionsOf, disconnect, neighbours, pathBetween, physicalDomains, reachableComponents, relatedComponents, removeComponent } from './graph.js';\nexport type { ConnectionFilter, GraphError, GraphErrorCode, GraphFilter, GraphOptions, GraphResult, GraphStep } from './graph.js';\nexport { routeConnection, routeScene, sampleRouteCenterline } from './routing.js';\nexport type { PipeRoute, RouteBend, RouteFailure, RouteKind, RoutingOptions } from './routing.js';\n\n// Assemblies: parent/child locks for rigid editing (ADR-0008)\nexport { assemblyOf, lockConnectedAsChildren, moveAssembly, unlockFromParent } from './assembly.js';\nexport type { AssemblyResult } from './assembly.js';\n\n// Copy and paste of components and assemblies\nexport { clipboardWidth, copyComponents, pasteComponents } from './clipboard.js';\nexport type { ComponentClipboard } from './clipboard.js';\n\n// Turning exactly touching ports into explicit connections (user-triggered)\nexport { connectTouchingPorts, findTouchingPorts } from './touching.js';\nexport type { ConnectTouchingResult, TouchingMatch, TouchingOptions, TouchingRejection, TouchingResult } from './touching.js';\n\n// Bringing scenes written with older component dimensions up to date (ADR-0014)\nexport { upgradeDimensions } from './upgrade.js';\nexport type { UpgradeOptions, UpgradeResult } from './upgrade.js';\n\n// Attaching one part to another at their closest free ports (editor Shift+click)\nexport { attachComponents } from './attach.js';\nexport type { AttachOptions, AttachResult } from './attach.js';\n\n// Connections whose ports do not meet, and seating a part back onto its partner\nexport { findOpenJoints, seatOnConnection } from './joints.js';\nexport type { JointOptions, OpenJoint, SeatResult } from './joints.js';\n\n// Solid-body overlap (display only)\nexport { findCollisions } from './collision.js';\nexport type { CollisionOptions, CollisionPair, CollisionResult } from './collision.js';\n\n// Read-only observations: flow, telemetry, host data input\nexport { resolveFlow } from './flow.js';\nexport type { FlowDirection, FlowOptions, FlowReading, FlowResolution, FlowState, FlowUnknownReason, Quality, ValueSource } from './flow.js';\nexport type { FreshnessOptions } from './observation.js';\nexport { displayScene, resolveTelemetry, resolveVariableValues, valueFitsDataType } from './telemetry.js';\nexport type { Observation, PropertyState, VariableState, TelemetryOptions, TelemetryResolution, TelemetryUnknownReason } from './telemetry.js';\nexport { connectProvider, createObservationStore } from './dataInput.js';\nexport type { DataProvider, ObservationStore } from './dataInput.js';\n"]}
|
package/dist/observation.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface FreshnessOptions {
|
|
|
9
9
|
/** Timestamps further than this in the future are rejected. Default 5,000 ms. */
|
|
10
10
|
maxClockSkewMs?: number;
|
|
11
11
|
}
|
|
12
|
-
export type ObservationProblem = 'BAD_QUALITY' | 'STALE' | 'INVALID_TIMESTAMP' | 'INVALID_VALUE';
|
|
12
|
+
export type ObservationProblem = 'BAD_QUALITY' | 'DISCONNECTED' | 'STALE' | 'INVALID_TIMESTAMP' | 'INVALID_VALUE';
|
|
13
13
|
/** Why an observation cannot be trusted, or undefined if it can (UNCERTAIN is trusted but flagged). */
|
|
14
14
|
export declare function assessObservation(o: {
|
|
15
15
|
quality: Quality;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observation.d.ts","sourceRoot":"","sources":["../src/observation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,gFAAgF;AAChF,eAAO,MAAM,SAAS,EAAE,SAAS,OAAO,
|
|
1
|
+
{"version":3,"file":"observation.d.ts","sourceRoot":"","sources":["../src/observation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,gFAAgF;AAChF,eAAO,MAAM,SAAS,EAAE,SAAS,OAAO,EAA0D,CAAC;AAEnG,MAAM,WAAW,gBAAgB;IAC/B,0CAA0C;IAC1C,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAOD,MAAM,MAAM,kBAAkB,GAAG,aAAa,GAAG,cAAc,GAAG,OAAO,GAAG,mBAAmB,GAAG,eAAe,CAAC;AAElH,uGAAuG;AACvG,wBAAgB,iBAAiB,CAAC,CAAC,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,EAAE,OAAO,EAAE,gBAAgB,GAAG,kBAAkB,GAAG,SAAS,CAS7I;AAED,4FAA4F;AAC5F,wBAAgB,OAAO,CAAC,SAAS,EAAE;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,EAAE,OAAO,EAAE;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GAAG,OAAO,CAMzH"}
|
package/dist/observation.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Quality and timestamp rules shared by flow readings and tag observations. */
|
|
2
|
-
export const qualities = ['GOOD', 'BAD', 'UNCERTAIN', 'STALE'];
|
|
2
|
+
export const qualities = ['GOOD', 'BAD', 'UNCERTAIN', 'STALE', 'DISCONNECTED'];
|
|
3
3
|
/** Epoch ms of an ISO timestamp, or NaN for anything else (host data is untrusted: `Date.parse` throws on a Symbol). */
|
|
4
4
|
function parseTimestamp(value) {
|
|
5
5
|
return typeof value === 'string' ? Date.parse(value) : Number.NaN;
|
|
@@ -13,6 +13,9 @@ export function assessObservation(o, options) {
|
|
|
13
13
|
return 'INVALID_TIMESTAMP';
|
|
14
14
|
if (o.quality === 'BAD')
|
|
15
15
|
return 'BAD_QUALITY';
|
|
16
|
+
// Like BAD: the last value is never shown as current while the source link is down.
|
|
17
|
+
if (o.quality === 'DISCONNECTED')
|
|
18
|
+
return 'DISCONNECTED';
|
|
16
19
|
if (o.quality === 'STALE' || options.now - observedAt > (options.staleAfterMs ?? 10_000))
|
|
17
20
|
return 'STALE';
|
|
18
21
|
return undefined;
|
package/dist/observation.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observation.js","sourceRoot":"","sources":["../src/observation.ts"],"names":[],"mappings":"AAEA,gFAAgF;AAChF,MAAM,CAAC,MAAM,SAAS,GAAuB,CAAC,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"observation.js","sourceRoot":"","sources":["../src/observation.ts"],"names":[],"mappings":"AAEA,gFAAgF;AAChF,MAAM,CAAC,MAAM,SAAS,GAAuB,CAAC,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;AAWnG,wHAAwH;AACxH,SAAS,cAAc,CAAC,KAAc;IACpC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;AACpE,CAAC;AAID,uGAAuG;AACvG,MAAM,UAAU,iBAAiB,CAAC,CAAgD,EAAE,OAAyB;IAC3G,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;QAAE,OAAO,eAAe,CAAC;IAC3D,MAAM,UAAU,GAAG,cAAc,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;IACrD,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,OAAO,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,cAAc,IAAI,KAAK,CAAC;QAAE,OAAO,mBAAmB,CAAC;IACzH,IAAI,CAAC,CAAC,OAAO,KAAK,KAAK;QAAE,OAAO,aAAa,CAAC;IAC9C,oFAAoF;IACpF,IAAI,CAAC,CAAC,OAAO,KAAK,cAAc;QAAE,OAAO,cAAc,CAAC;IACxD,IAAI,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,OAAO,CAAC,GAAG,GAAG,UAAU,GAAG,CAAC,OAAO,CAAC,YAAY,IAAI,MAAM,CAAC;QAAE,OAAO,OAAO,CAAC;IACzG,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,OAAO,CAAC,SAAsC,EAAE,OAAgD;IAC9G,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,CAAC,GAAG,cAAc,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;IACpD,MAAM,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAClD,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5C,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC","sourcesContent":["import type { Quality } from './flow.js';\n\n/** Quality and timestamp rules shared by flow readings and tag observations. */\nexport const qualities: readonly Quality[] = ['GOOD', 'BAD', 'UNCERTAIN', 'STALE', 'DISCONNECTED'];\n\nexport interface FreshnessOptions {\n /** Current time in epoch milliseconds. */\n now: number;\n /** Older observations are STALE. Default 10,000 ms. */\n staleAfterMs?: number;\n /** Timestamps further than this in the future are rejected. Default 5,000 ms. */\n maxClockSkewMs?: number;\n}\n\n/** Epoch ms of an ISO timestamp, or NaN for anything else (host data is untrusted: `Date.parse` throws on a Symbol). */\nfunction parseTimestamp(value: unknown): number {\n return typeof value === 'string' ? Date.parse(value) : Number.NaN;\n}\n\nexport type ObservationProblem = 'BAD_QUALITY' | 'DISCONNECTED' | 'STALE' | 'INVALID_TIMESTAMP' | 'INVALID_VALUE';\n\n/** Why an observation cannot be trusted, or undefined if it can (UNCERTAIN is trusted but flagged). */\nexport function assessObservation(o: { quality: Quality; sourceTimestamp: string }, options: FreshnessOptions): ObservationProblem | undefined {\n if (!qualities.includes(o.quality)) return 'INVALID_VALUE';\n const observedAt = parseTimestamp(o.sourceTimestamp);\n if (Number.isNaN(observedAt) || observedAt - options.now > (options.maxClockSkewMs ?? 5_000)) return 'INVALID_TIMESTAMP';\n if (o.quality === 'BAD') return 'BAD_QUALITY';\n // Like BAD: the last value is never shown as current while the source link is down.\n if (o.quality === 'DISCONNECTED') return 'DISCONNECTED';\n if (o.quality === 'STALE' || options.now - observedAt > (options.staleAfterMs ?? 10_000)) return 'STALE';\n return undefined;\n}\n\n/** Newest wins; unparseable timestamps lose to any valid one; ties go to the later item. */\nexport function isNewer(candidate: { sourceTimestamp: string }, current: { sourceTimestamp: string } | undefined): boolean {\n if (!current) return true;\n const a = parseTimestamp(candidate.sourceTimestamp);\n const b = parseTimestamp(current.sourceTimestamp);\n if (Number.isNaN(a)) return Number.isNaN(b);\n return Number.isNaN(b) || a >= b;\n}\n"]}
|
package/dist/routing.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ComponentInstance,
|
|
1
|
+
import type { ComponentInstance, ComponentType, ConnectionPort, ScadaScene, SceneConnection, Vector3Tuple } from './scene.js';
|
|
2
2
|
export type RouteKind = 'direct' | 'straight' | 'orthogonal';
|
|
3
3
|
export type RouteFailure = 'UNRESOLVED' | 'UNSUPPORTED_ORIENTATION' | 'UNROUTABLE' | 'BEND_TOO_TIGHT';
|
|
4
4
|
export interface RouteBend {
|
|
@@ -32,7 +32,7 @@ export type PipeRoute = {
|
|
|
32
32
|
message: string;
|
|
33
33
|
};
|
|
34
34
|
export interface RoutingOptions {
|
|
35
|
-
resolvePorts: (type:
|
|
35
|
+
resolvePorts: (type: ComponentType, properties?: ComponentInstance['properties']) => readonly ConnectionPort[] | undefined;
|
|
36
36
|
/** Centreline bend radius, metres. Default 0.3. */
|
|
37
37
|
bendRadius?: number;
|
|
38
38
|
/**
|
|
@@ -47,7 +47,10 @@ export interface RoutingOptions {
|
|
|
47
47
|
* the first axis order x, y, z). Off-axis ports are only supported when a straight run fits.
|
|
48
48
|
*/
|
|
49
49
|
export declare function routeConnection(scene: ScadaScene, connection: SceneConnection, options: RoutingOptions): PipeRoute;
|
|
50
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* Routes every pipe connection, in connection order. Connections between power, signal or network
|
|
52
|
+
* ports are wired, not piped, and get no route (ADR-0023); unresolved endpoints still report `UNRESOLVED`.
|
|
53
|
+
*/
|
|
51
54
|
export declare function routeScene(scene: ScadaScene, options: RoutingOptions): PipeRoute[];
|
|
52
55
|
/**
|
|
53
56
|
* The pipe centreline as a polyline that follows each bend's arc (quarter circle of the bend
|
package/dist/routing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../src/routing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../src/routing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI9H,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,YAAY,CAAC;AAC7D,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,yBAAyB,GAAG,YAAY,GAAG,gBAAgB,CAAC;AAEtG,MAAM,WAAW,SAAS;IACxB,4FAA4F;IAC5F,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,6FAA6F;AAC7F,MAAM,MAAM,SAAS,GACjB;IACE,MAAM,EAAE,IAAI,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,YAAY,CAAC;IACnB,EAAE,EAAE,YAAY,CAAC;IACjB,kFAAkF;IAClF,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IACE,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IAC5C,IAAI,EAAE,YAAY,CAAC;IACnB,EAAE,EAAE,YAAY,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,GACD;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvF,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,UAAU,CAAC,EAAE,iBAAiB,CAAC,YAAY,CAAC,KAAK,SAAS,cAAc,EAAE,GAAG,SAAS,CAAC;IAC3H,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,KAAK,MAAM,CAAC;CAC7D;AAgFD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,OAAO,EAAE,cAAc,GAAG,SAAS,CAsDlH;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,cAAc,GAAG,SAAS,EAAE,CAQlF;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,EAAE;IAAE,MAAM,EAAE,IAAI,CAAA;CAAE,CAAC,EAAE,eAAe,SAAI,GAAG,YAAY,EAAE,CA0BtH"}
|
package/dist/routing.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { matesPhysically } from './scene.js';
|
|
1
2
|
import { portToWorld } from './transforms.js';
|
|
2
3
|
const EPS = 1e-9;
|
|
3
4
|
const AXIS_ORDERS = [
|
|
@@ -136,9 +137,18 @@ export function routeConnection(scene, connection, options) {
|
|
|
136
137
|
? invalid('BEND_TOO_TIGHT', `No route leaves room for bends of radius ${radius} m.`)
|
|
137
138
|
: invalid('UNROUTABLE', 'Every orthogonal route doubles back on itself.');
|
|
138
139
|
}
|
|
139
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* Routes every pipe connection, in connection order. Connections between power, signal or network
|
|
142
|
+
* ports are wired, not piped, and get no route (ADR-0023); unresolved endpoints still report `UNRESOLVED`.
|
|
143
|
+
*/
|
|
140
144
|
export function routeScene(scene, options) {
|
|
141
|
-
|
|
145
|
+
const byId = new Map(scene.components.map((c) => [c.id, c]));
|
|
146
|
+
const wired = (connection) => {
|
|
147
|
+
const owner = byId.get(connection.from.instanceId);
|
|
148
|
+
const port = owner && options.resolvePorts(owner.type, owner.properties)?.find((p) => p.id === connection.from.portId);
|
|
149
|
+
return port !== undefined && !matesPhysically(port);
|
|
150
|
+
};
|
|
151
|
+
return scene.connections.filter((connection) => !wired(connection)).map((connection) => routeConnection(scene, connection, options));
|
|
142
152
|
}
|
|
143
153
|
/**
|
|
144
154
|
* The pipe centreline as a polyline that follows each bend's arc (quarter circle of the bend
|
package/dist/routing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routing.js","sourceRoot":"","sources":["../src/routing.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ComponentInstance, ComponentKind, ConnectionPort, ScadaScene, SceneConnection, Vector3Tuple } from './scene.js';\nimport { portToWorld, type WorldPort } from './transforms.js';\n\nexport type RouteKind = 'direct' | 'straight' | 'orthogonal';\nexport type RouteFailure = 'UNRESOLVED' | 'UNSUPPORTED_ORIENTATION' | 'UNROUTABLE' | 'BEND_TOO_TIGHT';\n\nexport interface RouteBend {\n /** Where the two straight centrelines would meet; the fitting curves inside this corner. */\n corner: Vector3Tuple;\n radius: number;\n}\n\n/** Derived pipe centreline for one connection. Never persisted; recompute from the scene. */\nexport type PipeRoute =\n | {\n status: 'ok';\n connectionId: string;\n kind: RouteKind;\n from: Vector3Tuple;\n to: Vector3Tuple;\n /** Polyline from the `from` port to the `to` port through each corner, metres. */\n points: Vector3Tuple[];\n bends: RouteBend[];\n /** Polyline length through the corners, metres. */\n length: number;\n }\n | {\n status: 'invalid';\n connectionId: string;\n reason: Exclude<RouteFailure, 'UNRESOLVED'>;\n from: Vector3Tuple;\n to: Vector3Tuple;\n message: string;\n }\n | { status: 'invalid'; connectionId: string; reason: 'UNRESOLVED'; message: string };\n\nexport interface RoutingOptions {\n resolvePorts: (type: ComponentKind, properties?: ComponentInstance['properties']) => readonly ConnectionPort[] | undefined;\n /** Centreline bend radius, metres. Default 0.3. */\n bendRadius?: number;\n /**\n * Bend radius for a pipe size (port `nominalSize`), e.g. ASME long radius 1.5 × NPS (ADR-0015).\n * Takes precedence over `bendRadius` when given.\n */\n bendRadiusFor?: (nominalSize: number | undefined) => number;\n}\n\nconst EPS = 1e-9;\nconst AXIS_ORDERS = [\n [0, 1, 2],\n [0, 2, 1],\n [1, 0, 2],\n [1, 2, 0],\n [2, 0, 1],\n [2, 1, 0],\n];\n\nconst sub = (a: Vector3Tuple, b: Vector3Tuple): Vector3Tuple => [a[0] - b[0], a[1] - b[1], a[2] - b[2]];\nconst dot = (a: Vector3Tuple, b: Vector3Tuple) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\nconst along = (p: Vector3Tuple, d: Vector3Tuple, s: number): Vector3Tuple => [p[0] + d[0] * s, p[1] + d[1] * s, p[2] + d[2] * s];\nconst same = (a: Vector3Tuple, b: Vector3Tuple) => Math.hypot(...sub(a, b)) < EPS;\n\n/** The exact world axis a unit vector lies on, or undefined if it is off-axis. */\nfunction snapToAxis(v: Vector3Tuple): Vector3Tuple | undefined {\n const index = v.findIndex((n) => Math.abs(n) > 1 - EPS);\n if (index < 0) return undefined;\n const axis: Vector3Tuple = [0, 0, 0];\n axis[index] = Math.sign(v[index]);\n return axis;\n}\n\ntype Attempt = { points: Vector3Tuple[] } | { failure: 'reversal' | 'tight' };\n\n/**\n * One candidate route: leave `from` along its normal by the bend radius, move along each axis in\n * `order`, then enter `to` against its normal. Rejected if it doubles back or a bend lacks room.\n */\nfunction attempt(p0: Vector3Tuple, d0: Vector3Tuple, p1: Vector3Tuple, d1: Vector3Tuple, order: number[], radius: number): Attempt {\n const a = along(p0, d0, radius);\n const b = along(p1, d1, radius);\n const raw: Vector3Tuple[] = [p0, a];\n let current = a;\n for (const k of order) {\n if (Math.abs(b[k] - current[k]) > EPS) {\n current = [...current];\n current[k] = b[k];\n raw.push(current);\n }\n }\n raw.push(p1);\n\n // Drop zero-length steps and merge collinear runs; a 180° turn means the route doubles back.\n const points: Vector3Tuple[] = [raw[0]];\n let heading: Vector3Tuple | undefined;\n for (const p of raw.slice(1)) {\n const last = points[points.length - 1];\n if (same(p, last)) continue;\n const step = sub(p, last);\n const dir = step.map((n) => n / Math.hypot(...step)) as Vector3Tuple;\n if (heading && dot(heading, dir) < -1 + EPS) return { failure: 'reversal' };\n if (heading && dot(heading, dir) > 1 - EPS) points[points.length - 1] = p;\n else points.push(p);\n heading = dir;\n }\n\n // Each bend consumes one radius from both neighbouring straights.\n for (let i = 1; i < points.length; i++) {\n const bendsAtEnds = (i > 1 ? 1 : 0) + (i < points.length - 1 ? 1 : 0);\n if (Math.hypot(...sub(points[i], points[i - 1])) < bendsAtEnds * radius - EPS) return { failure: 'tight' };\n }\n return { points };\n}\n\nfunction polylineLength(points: Vector3Tuple[]): number {\n let length = 0;\n for (let i = 1; i < points.length; i++) length += Math.hypot(...sub(points[i], points[i - 1]));\n return length;\n}\n\nfunction resolve(scene: ScadaScene, endpoint: SceneConnection['from'], options: RoutingOptions): WorldPort | undefined {\n const owner = scene.components.find((c) => c.id === endpoint.instanceId);\n const port = owner && options.resolvePorts(owner.type, owner.properties)?.find((p) => p.id === endpoint.portId);\n return owner && port ? portToWorld(owner, port) : undefined;\n}\n\n/**\n * Routes one connection deterministically: `direct` for coincident ports, `straight` for opposed\n * collinear ports at any angle, otherwise an axis-aligned route with the fewest bends (ties go to\n * the first axis order x, y, z). Off-axis ports are only supported when a straight run fits.\n */\nexport function routeConnection(scene: ScadaScene, connection: SceneConnection, options: RoutingOptions): PipeRoute {\n const fromComponent = scene.components.find((c) => c.id === connection.from.instanceId);\n const fromPort = fromComponent && options.resolvePorts(fromComponent.type, fromComponent.properties)?.find((p) => p.id === connection.from.portId);\n const radius = options.bendRadiusFor ? options.bendRadiusFor(fromPort?.nominalSize) : options.bendRadius ?? 0.3;\n const connectionId = connection.id;\n const start = resolve(scene, connection.from, options);\n const end = resolve(scene, connection.to, options);\n if (!start || !end) {\n return { status: 'invalid', connectionId, reason: 'UNRESOLVED', message: 'An endpoint does not resolve to a declared port.' };\n }\n const from = start.position;\n const to = end.position;\n const ok = (kind: RouteKind, points: Vector3Tuple[]): PipeRoute => ({\n status: 'ok',\n connectionId,\n kind,\n from,\n to,\n points,\n bends: points.slice(1, -1).map((corner) => ({ corner, radius })),\n length: polylineLength(points),\n });\n const invalid = (reason: Exclude<RouteFailure, 'UNRESOLVED'>, message: string): PipeRoute => ({\n status: 'invalid',\n connectionId,\n reason,\n from,\n to,\n message,\n });\n\n const offset = sub(to, from);\n const distance = Math.hypot(...offset);\n if (distance < EPS) return ok('direct', [from]);\n\n const opposed = dot(start.direction, end.direction) < -1 + EPS;\n const ahead = dot(offset, start.direction) / distance;\n if (opposed && ahead > 1 - EPS) return ok('straight', [from, to]);\n\n const d0 = snapToAxis(start.direction);\n const d1 = snapToAxis(end.direction);\n if (!d0 || !d1) return invalid('UNSUPPORTED_ORIENTATION', 'Orthogonal routing needs both ports on world axes.');\n\n let best: Vector3Tuple[] | undefined;\n let tight = false;\n for (const order of AXIS_ORDERS) {\n const result = attempt(from, d0, to, d1, order, radius);\n if ('failure' in result) tight ||= result.failure === 'tight';\n else if (!best || result.points.length < best.length) best = result.points;\n }\n if (best) return ok('orthogonal', best);\n return tight\n ? invalid('BEND_TOO_TIGHT', `No route leaves room for bends of radius ${radius} m.`)\n : invalid('UNROUTABLE', 'Every orthogonal route doubles back on itself.');\n}\n\n/** Routes every connection, in connection order. */\nexport function routeScene(scene: ScadaScene, options: RoutingOptions): PipeRoute[] {\n return scene.connections.map((connection) => routeConnection(scene, connection, options));\n}\n\n/**\n * The pipe centreline as a polyline that follows each bend's arc (quarter circle of the bend\n * radius inside the corner) instead of the sharp corner, for placing things inside the pipe.\n * `segmentsPerBend` straight pieces approximate each arc. Consecutive duplicates are dropped.\n */\nexport function sampleRouteCenterline(route: Extract<PipeRoute, { status: 'ok' }>, segmentsPerBend = 8): Vector3Tuple[] {\n const { points, bends } = route;\n if (points.length < 3) return points.map((p) => [...p] as Vector3Tuple);\n const unit = (v: Vector3Tuple): Vector3Tuple => {\n const l = Math.hypot(...v);\n return [v[0] / l, v[1] / l, v[2] / l];\n };\n const out: Vector3Tuple[] = [];\n const push = (p: Vector3Tuple) => {\n if (out.length === 0 || !same(p, out[out.length - 1])) out.push(p);\n };\n push([...points[0]]);\n for (let i = 1; i < points.length - 1; i++) {\n const corner = points[i];\n const radius = bends[i - 1].radius;\n const incoming = unit(sub(corner, points[i - 1]));\n const outgoing = unit(sub(points[i + 1], corner));\n // Arc centre sits one radius back along the incoming run and one radius along the outgoing run.\n const centre = along(along(corner, incoming, -radius), outgoing, radius);\n for (let k = 0; k <= segmentsPerBend; k++) {\n const theta = (k / segmentsPerBend) * (Math.PI / 2);\n push(along(along(centre, outgoing, -radius * Math.cos(theta)), incoming, radius * Math.sin(theta)));\n }\n }\n push([...points[points.length - 1]]);\n return out;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"routing.js","sourceRoot":"","sources":["../src/routing.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ComponentInstance, ComponentType, ConnectionPort, ScadaScene, SceneConnection, Vector3Tuple } from './scene.js';\nimport { matesPhysically } from './scene.js';\nimport { portToWorld, type WorldPort } from './transforms.js';\n\nexport type RouteKind = 'direct' | 'straight' | 'orthogonal';\nexport type RouteFailure = 'UNRESOLVED' | 'UNSUPPORTED_ORIENTATION' | 'UNROUTABLE' | 'BEND_TOO_TIGHT';\n\nexport interface RouteBend {\n /** Where the two straight centrelines would meet; the fitting curves inside this corner. */\n corner: Vector3Tuple;\n radius: number;\n}\n\n/** Derived pipe centreline for one connection. Never persisted; recompute from the scene. */\nexport type PipeRoute =\n | {\n status: 'ok';\n connectionId: string;\n kind: RouteKind;\n from: Vector3Tuple;\n to: Vector3Tuple;\n /** Polyline from the `from` port to the `to` port through each corner, metres. */\n points: Vector3Tuple[];\n bends: RouteBend[];\n /** Polyline length through the corners, metres. */\n length: number;\n }\n | {\n status: 'invalid';\n connectionId: string;\n reason: Exclude<RouteFailure, 'UNRESOLVED'>;\n from: Vector3Tuple;\n to: Vector3Tuple;\n message: string;\n }\n | { status: 'invalid'; connectionId: string; reason: 'UNRESOLVED'; message: string };\n\nexport interface RoutingOptions {\n resolvePorts: (type: ComponentType, properties?: ComponentInstance['properties']) => readonly ConnectionPort[] | undefined;\n /** Centreline bend radius, metres. Default 0.3. */\n bendRadius?: number;\n /**\n * Bend radius for a pipe size (port `nominalSize`), e.g. ASME long radius 1.5 × NPS (ADR-0015).\n * Takes precedence over `bendRadius` when given.\n */\n bendRadiusFor?: (nominalSize: number | undefined) => number;\n}\n\nconst EPS = 1e-9;\nconst AXIS_ORDERS = [\n [0, 1, 2],\n [0, 2, 1],\n [1, 0, 2],\n [1, 2, 0],\n [2, 0, 1],\n [2, 1, 0],\n];\n\nconst sub = (a: Vector3Tuple, b: Vector3Tuple): Vector3Tuple => [a[0] - b[0], a[1] - b[1], a[2] - b[2]];\nconst dot = (a: Vector3Tuple, b: Vector3Tuple) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\nconst along = (p: Vector3Tuple, d: Vector3Tuple, s: number): Vector3Tuple => [p[0] + d[0] * s, p[1] + d[1] * s, p[2] + d[2] * s];\nconst same = (a: Vector3Tuple, b: Vector3Tuple) => Math.hypot(...sub(a, b)) < EPS;\n\n/** The exact world axis a unit vector lies on, or undefined if it is off-axis. */\nfunction snapToAxis(v: Vector3Tuple): Vector3Tuple | undefined {\n const index = v.findIndex((n) => Math.abs(n) > 1 - EPS);\n if (index < 0) return undefined;\n const axis: Vector3Tuple = [0, 0, 0];\n axis[index] = Math.sign(v[index]);\n return axis;\n}\n\ntype Attempt = { points: Vector3Tuple[] } | { failure: 'reversal' | 'tight' };\n\n/**\n * One candidate route: leave `from` along its normal by the bend radius, move along each axis in\n * `order`, then enter `to` against its normal. Rejected if it doubles back or a bend lacks room.\n */\nfunction attempt(p0: Vector3Tuple, d0: Vector3Tuple, p1: Vector3Tuple, d1: Vector3Tuple, order: number[], radius: number): Attempt {\n const a = along(p0, d0, radius);\n const b = along(p1, d1, radius);\n const raw: Vector3Tuple[] = [p0, a];\n let current = a;\n for (const k of order) {\n if (Math.abs(b[k] - current[k]) > EPS) {\n current = [...current];\n current[k] = b[k];\n raw.push(current);\n }\n }\n raw.push(p1);\n\n // Drop zero-length steps and merge collinear runs; a 180° turn means the route doubles back.\n const points: Vector3Tuple[] = [raw[0]];\n let heading: Vector3Tuple | undefined;\n for (const p of raw.slice(1)) {\n const last = points[points.length - 1];\n if (same(p, last)) continue;\n const step = sub(p, last);\n const dir = step.map((n) => n / Math.hypot(...step)) as Vector3Tuple;\n if (heading && dot(heading, dir) < -1 + EPS) return { failure: 'reversal' };\n if (heading && dot(heading, dir) > 1 - EPS) points[points.length - 1] = p;\n else points.push(p);\n heading = dir;\n }\n\n // Each bend consumes one radius from both neighbouring straights.\n for (let i = 1; i < points.length; i++) {\n const bendsAtEnds = (i > 1 ? 1 : 0) + (i < points.length - 1 ? 1 : 0);\n if (Math.hypot(...sub(points[i], points[i - 1])) < bendsAtEnds * radius - EPS) return { failure: 'tight' };\n }\n return { points };\n}\n\nfunction polylineLength(points: Vector3Tuple[]): number {\n let length = 0;\n for (let i = 1; i < points.length; i++) length += Math.hypot(...sub(points[i], points[i - 1]));\n return length;\n}\n\nfunction resolve(scene: ScadaScene, endpoint: SceneConnection['from'], options: RoutingOptions): WorldPort | undefined {\n const owner = scene.components.find((c) => c.id === endpoint.instanceId);\n const port = owner && options.resolvePorts(owner.type, owner.properties)?.find((p) => p.id === endpoint.portId);\n return owner && port ? portToWorld(owner, port) : undefined;\n}\n\n/**\n * Routes one connection deterministically: `direct` for coincident ports, `straight` for opposed\n * collinear ports at any angle, otherwise an axis-aligned route with the fewest bends (ties go to\n * the first axis order x, y, z). Off-axis ports are only supported when a straight run fits.\n */\nexport function routeConnection(scene: ScadaScene, connection: SceneConnection, options: RoutingOptions): PipeRoute {\n const fromComponent = scene.components.find((c) => c.id === connection.from.instanceId);\n const fromPort = fromComponent && options.resolvePorts(fromComponent.type, fromComponent.properties)?.find((p) => p.id === connection.from.portId);\n const radius = options.bendRadiusFor ? options.bendRadiusFor(fromPort?.nominalSize) : options.bendRadius ?? 0.3;\n const connectionId = connection.id;\n const start = resolve(scene, connection.from, options);\n const end = resolve(scene, connection.to, options);\n if (!start || !end) {\n return { status: 'invalid', connectionId, reason: 'UNRESOLVED', message: 'An endpoint does not resolve to a declared port.' };\n }\n const from = start.position;\n const to = end.position;\n const ok = (kind: RouteKind, points: Vector3Tuple[]): PipeRoute => ({\n status: 'ok',\n connectionId,\n kind,\n from,\n to,\n points,\n bends: points.slice(1, -1).map((corner) => ({ corner, radius })),\n length: polylineLength(points),\n });\n const invalid = (reason: Exclude<RouteFailure, 'UNRESOLVED'>, message: string): PipeRoute => ({\n status: 'invalid',\n connectionId,\n reason,\n from,\n to,\n message,\n });\n\n const offset = sub(to, from);\n const distance = Math.hypot(...offset);\n if (distance < EPS) return ok('direct', [from]);\n\n const opposed = dot(start.direction, end.direction) < -1 + EPS;\n const ahead = dot(offset, start.direction) / distance;\n if (opposed && ahead > 1 - EPS) return ok('straight', [from, to]);\n\n const d0 = snapToAxis(start.direction);\n const d1 = snapToAxis(end.direction);\n if (!d0 || !d1) return invalid('UNSUPPORTED_ORIENTATION', 'Orthogonal routing needs both ports on world axes.');\n\n let best: Vector3Tuple[] | undefined;\n let tight = false;\n for (const order of AXIS_ORDERS) {\n const result = attempt(from, d0, to, d1, order, radius);\n if ('failure' in result) tight ||= result.failure === 'tight';\n else if (!best || result.points.length < best.length) best = result.points;\n }\n if (best) return ok('orthogonal', best);\n return tight\n ? invalid('BEND_TOO_TIGHT', `No route leaves room for bends of radius ${radius} m.`)\n : invalid('UNROUTABLE', 'Every orthogonal route doubles back on itself.');\n}\n\n/**\n * Routes every pipe connection, in connection order. Connections between power, signal or network\n * ports are wired, not piped, and get no route (ADR-0023); unresolved endpoints still report `UNRESOLVED`.\n */\nexport function routeScene(scene: ScadaScene, options: RoutingOptions): PipeRoute[] {\n const byId = new Map(scene.components.map((c) => [c.id, c]));\n const wired = (connection: SceneConnection) => {\n const owner = byId.get(connection.from.instanceId);\n const port = owner && options.resolvePorts(owner.type, owner.properties)?.find((p) => p.id === connection.from.portId);\n return port !== undefined && !matesPhysically(port);\n };\n return scene.connections.filter((connection) => !wired(connection)).map((connection) => routeConnection(scene, connection, options));\n}\n\n/**\n * The pipe centreline as a polyline that follows each bend's arc (quarter circle of the bend\n * radius inside the corner) instead of the sharp corner, for placing things inside the pipe.\n * `segmentsPerBend` straight pieces approximate each arc. Consecutive duplicates are dropped.\n */\nexport function sampleRouteCenterline(route: Extract<PipeRoute, { status: 'ok' }>, segmentsPerBend = 8): Vector3Tuple[] {\n const { points, bends } = route;\n if (points.length < 3) return points.map((p) => [...p] as Vector3Tuple);\n const unit = (v: Vector3Tuple): Vector3Tuple => {\n const l = Math.hypot(...v);\n return [v[0] / l, v[1] / l, v[2] / l];\n };\n const out: Vector3Tuple[] = [];\n const push = (p: Vector3Tuple) => {\n if (out.length === 0 || !same(p, out[out.length - 1])) out.push(p);\n };\n push([...points[0]]);\n for (let i = 1; i < points.length - 1; i++) {\n const corner = points[i];\n const radius = bends[i - 1].radius;\n const incoming = unit(sub(corner, points[i - 1]));\n const outgoing = unit(sub(points[i + 1], corner));\n // Arc centre sits one radius back along the incoming run and one radius along the outgoing run.\n const centre = along(along(corner, incoming, -radius), outgoing, radius);\n for (let k = 0; k <= segmentsPerBend; k++) {\n const theta = (k / segmentsPerBend) * (Math.PI / 2);\n push(along(along(centre, outgoing, -radius * Math.cos(theta)), incoming, radius * Math.sin(theta)));\n }\n }\n push([...points[points.length - 1]]);\n return out;\n}\n"]}
|