@jetta/axle-load-calculator 0.3.2 → 0.3.3
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 +71 -0
- package/README.md +2 -0
- package/build/core/orchestration/CollisionChecker.d.ts +8 -0
- package/build/core/orchestration/CollisionChecker.d.ts.map +1 -0
- package/build/core/orchestration/CollisionChecker.js +60 -0
- package/build/core/orchestration/ItemOverlapError.d.ts +7 -0
- package/build/core/orchestration/ItemOverlapError.d.ts.map +1 -0
- package/build/core/orchestration/ItemOverlapError.js +9 -0
- package/build/core/orchestration/WeightByAxisTask.d.ts +1 -0
- package/build/core/orchestration/WeightByAxisTask.d.ts.map +1 -1
- package/build/core/orchestration/WeightByAxisTask.js +3 -0
- package/build/index.d.ts +3 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -1
- package/package.json +2 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@jetta/axle-load-calculator` are documented in this file.
|
|
4
|
+
|
|
5
|
+
Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Cargo collision check after axle loads are written (`CollisionChecker`), using `lt` from `@jetta/number-compare` (default epsilon `1e-9`).
|
|
12
|
+
- Public `ItemOverlapError` thrown by `calculate_weight_on_axles_physics` when two allocated items share volume.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Face-touching boxes (IEEE ULP on edges such as `4.075 + 0.815` vs `4.89`) are no longer treated as overlap, so callers can keep axle kg instead of skipping the gate.
|
|
17
|
+
|
|
18
|
+
## [0.3.2] - 2026-07-23
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- Same-grouper container loads are merged for mass-center so results match MS.
|
|
23
|
+
|
|
24
|
+
## [0.3.0] - 2026-06-02
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- Public API accepts objects only, returns objects, and throws domain errors instead of mixed string/object I/O.
|
|
29
|
+
|
|
30
|
+
### Removed
|
|
31
|
+
|
|
32
|
+
- Collision test artifacts and unused overlap error after `CollisionChecker` removal.
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- npm coverage script with 80% line, function, branch, and statement thresholds.
|
|
37
|
+
|
|
38
|
+
## [0.2.1] - 2026-06-02
|
|
39
|
+
|
|
40
|
+
### Removed
|
|
41
|
+
|
|
42
|
+
- `CollisionChecker` and its call from the weight-by-axis task.
|
|
43
|
+
|
|
44
|
+
## [0.2.0] - 2026-06-02
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
|
|
48
|
+
- First published library surface: `calculate_weight_on_axles_physics`, domain exceptions, Zod request validation, and in-process physics plus orchestration.
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
|
|
52
|
+
- Package entry points use lowercase `index`.
|
|
53
|
+
- Weight calculation accepted both JSON strings and objects (superseded in 0.3.0).
|
|
54
|
+
|
|
55
|
+
## [0.1.3] - 2026-06-02
|
|
56
|
+
|
|
57
|
+
### Changed
|
|
58
|
+
|
|
59
|
+
- Package is public (`private: false`) for npm publish.
|
|
60
|
+
|
|
61
|
+
## [0.1.2] - 2026-06-02
|
|
62
|
+
|
|
63
|
+
### Added
|
|
64
|
+
|
|
65
|
+
- Bitbucket Pipelines for CI/CD.
|
|
66
|
+
|
|
67
|
+
## [0.1.0] - 2026-06-02
|
|
68
|
+
|
|
69
|
+
### Added
|
|
70
|
+
|
|
71
|
+
- Project scaffolding, transport and vehicle models, deflection and tare, axle-weight services, weight-by-axis orchestration, and golden deflection fixtures.
|
package/README.md
CHANGED
|
@@ -55,6 +55,7 @@ try {
|
|
|
55
55
|
| `UnsupportedVehicleTypeError` | Unknown `tipoVeiculo` |
|
|
56
56
|
| `UnrecognizedSuspensionTypeError` | Invalid vanderleia suspension type |
|
|
57
57
|
| `GrouperNotFoundError` | Merged-container grouper not found |
|
|
58
|
+
| `ItemOverlapError` | Two allocated items occupy the same volume |
|
|
58
59
|
|
|
59
60
|
Import `ZodError` directly from [`zod`](https://github.com/colinhacks/zod).
|
|
60
61
|
|
|
@@ -72,6 +73,7 @@ Also exported from `@jetta/axle-load-calculator` for `instanceof` checks when us
|
|
|
72
73
|
## Dependencies
|
|
73
74
|
|
|
74
75
|
- [zod](https://github.com/colinhacks/zod) — request validation at the public boundary
|
|
76
|
+
- [`@jetta/number-compare`](https://www.npmjs.com/package/@jetta/number-compare) — float-safe interval tests in cargo collision
|
|
75
77
|
|
|
76
78
|
## Scripts
|
|
77
79
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rejects an env whose allocated items occupy the same volume.
|
|
3
|
+
* Face-touching boxes are allowed; comparison uses `@jetta/number-compare`.
|
|
4
|
+
* @param env - Env vehicle with containers and items.
|
|
5
|
+
* @throws {ItemOverlapError} When two items share volume on all three axes.
|
|
6
|
+
*/
|
|
7
|
+
export declare function check_cargo_collision(env: Record<string, unknown>): void;
|
|
8
|
+
//# sourceMappingURL=CollisionChecker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CollisionChecker.d.ts","sourceRoot":"","sources":["../../../src/core/orchestration/CollisionChecker.ts"],"names":[],"mappings":"AAWA;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAWxE"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { lt } from '@jetta/number-compare';
|
|
2
|
+
import { ItemOverlapError } from './ItemOverlapError.js';
|
|
3
|
+
/**
|
|
4
|
+
* Rejects an env whose allocated items occupy the same volume.
|
|
5
|
+
* Face-touching boxes are allowed; comparison uses `@jetta/number-compare`.
|
|
6
|
+
* @param env - Env vehicle with containers and items.
|
|
7
|
+
* @throws {ItemOverlapError} When two items share volume on all three axes.
|
|
8
|
+
*/
|
|
9
|
+
export function check_cargo_collision(env) {
|
|
10
|
+
const containers = env.containers;
|
|
11
|
+
if (!containers) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
for (const container of containers) {
|
|
15
|
+
check_container_items(container);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function check_container_items(container) {
|
|
19
|
+
const items = container.items;
|
|
20
|
+
if (!items || items.length <= 1) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
throw_if_any_pair_overlaps(items);
|
|
24
|
+
}
|
|
25
|
+
function throw_if_any_pair_overlaps(items) {
|
|
26
|
+
for (let index = 0; index < items.length - 1; index++) {
|
|
27
|
+
for (let other = index + 1; other < items.length; other++) {
|
|
28
|
+
if (items_overlap(items[index], items[other])) {
|
|
29
|
+
throw new ItemOverlapError();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function items_overlap(left, right) {
|
|
35
|
+
const left_box = item_box(left);
|
|
36
|
+
const right_box = item_box(right);
|
|
37
|
+
return intervals_overlap(left_box.x, right_box.x)
|
|
38
|
+
&& intervals_overlap(left_box.y, right_box.y)
|
|
39
|
+
&& intervals_overlap(left_box.z, right_box.z);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Maps CM / Java item JSON onto axis intervals.
|
|
43
|
+
* Height lives on JSON `z`; length on JSON `y` + `comprimento`.
|
|
44
|
+
*/
|
|
45
|
+
function item_box(item) {
|
|
46
|
+
const origin_x = Number(item.x ?? 0);
|
|
47
|
+
const origin_y = Number(item.y ?? 0);
|
|
48
|
+
const origin_z = Number(item.z ?? 0);
|
|
49
|
+
const width = Number(item.largura ?? item.width ?? 0);
|
|
50
|
+
const height = Number(item.altura ?? item.height ?? 0);
|
|
51
|
+
const length = Number(item.comprimento ?? item.length ?? 0);
|
|
52
|
+
return {
|
|
53
|
+
x: { min: origin_x, max: origin_x + width },
|
|
54
|
+
y: { min: origin_z, max: origin_z + height },
|
|
55
|
+
z: { min: origin_y, max: origin_y + length }
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function intervals_overlap(left, right) {
|
|
59
|
+
return lt(left.min, right.max) && lt(right.min, left.max);
|
|
60
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ItemOverlapError.d.ts","sourceRoot":"","sources":["../../../src/core/orchestration/ItemOverlapError.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;;CAO1C"}
|
|
@@ -12,6 +12,7 @@ import type { WeightByAxisSuccessOutput } from './WeightByAxisResponse.js';
|
|
|
12
12
|
* @throws {import('../physics/transports/MissingContainerError.js').MissingContainerError} When a container lookup fails.
|
|
13
13
|
* @throws {import('../physics/items/UnknownItemIdError.js').UnknownItemIdError} When an item template id is unknown.
|
|
14
14
|
* @throws {import('../physics/models/deflection/DeflectionModelNotImplementedError.js').DeflectionModelNotImplementedError} When no deflection model exists.
|
|
15
|
+
* @throws {import('./ItemOverlapError.js').ItemOverlapError} When two allocated items occupy the same volume.
|
|
15
16
|
*/
|
|
16
17
|
export declare function run_weight_by_axis_task(request_data: WeightByAxisRequestInput): WeightByAxisSuccessOutput;
|
|
17
18
|
//# sourceMappingURL=WeightByAxisTask.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WeightByAxisTask.d.ts","sourceRoot":"","sources":["../../../src/core/orchestration/WeightByAxisTask.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"WeightByAxisTask.d.ts","sourceRoot":"","sources":["../../../src/core/orchestration/WeightByAxisTask.ts"],"names":[],"mappings":"AAGA,OAAO,EAEH,KAAK,wBAAwB,EAChC,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAA;AAE1E;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CACnC,YAAY,EAAE,wBAAwB,GACvC,yBAAyB,CAa3B"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { calculate_loaded_weights_for_env } from './AxleWeightPhysics.js';
|
|
2
|
+
import { check_cargo_collision } from './CollisionChecker.js';
|
|
2
3
|
import { build_success_output } from './OutputBuilder.js';
|
|
3
4
|
import { parse_weight_by_axis_request_data } from './RequestSchema.js';
|
|
4
5
|
/**
|
|
@@ -13,6 +14,7 @@ import { parse_weight_by_axis_request_data } from './RequestSchema.js';
|
|
|
13
14
|
* @throws {import('../physics/transports/MissingContainerError.js').MissingContainerError} When a container lookup fails.
|
|
14
15
|
* @throws {import('../physics/items/UnknownItemIdError.js').UnknownItemIdError} When an item template id is unknown.
|
|
15
16
|
* @throws {import('../physics/models/deflection/DeflectionModelNotImplementedError.js').DeflectionModelNotImplementedError} When no deflection model exists.
|
|
17
|
+
* @throws {import('./ItemOverlapError.js').ItemOverlapError} When two allocated items occupy the same volume.
|
|
16
18
|
*/
|
|
17
19
|
export function run_weight_by_axis_task(request_data) {
|
|
18
20
|
const request = parse_weight_by_axis_request_data(request_data);
|
|
@@ -21,6 +23,7 @@ export function run_weight_by_axis_task(request_data) {
|
|
|
21
23
|
for (const env of envs) {
|
|
22
24
|
const loaded_weights = calculate_loaded_weights_for_env(env);
|
|
23
25
|
apply_loaded_weights_to_env(env, loaded_weights);
|
|
26
|
+
check_cargo_collision(env);
|
|
24
27
|
output_envs.push(strip_items_and_bands(env));
|
|
25
28
|
}
|
|
26
29
|
return build_success_output(output_envs);
|
package/build/index.d.ts
CHANGED
|
@@ -7,8 +7,9 @@ import { UnsupportedVehicleTypeError } from './core/physics/models/UnsupportedVe
|
|
|
7
7
|
import { ContainerSequenceNotFoundError } from './core/physics/transports/ContainerSequenceNotFoundError.js';
|
|
8
8
|
import { GrouperNotFoundError } from './core/physics/transports/GrouperNotFoundError.js';
|
|
9
9
|
import { MissingContainerError } from './core/physics/transports/MissingContainerError.js';
|
|
10
|
+
import { ItemOverlapError } from './core/orchestration/ItemOverlapError.js';
|
|
10
11
|
export type { WeightByAxisRequest, WeightByAxisRequestInput, WeightByAxisResponse, WeightByAxisSuccessOutput };
|
|
11
|
-
export { ContainerSequenceNotFoundError, DeflectionModelNotImplementedError, GrouperNotFoundError, MissingContainerError, UnrecognizedSuspensionTypeError, UnknownItemIdError, UnsupportedVehicleTypeError };
|
|
12
|
+
export { ContainerSequenceNotFoundError, DeflectionModelNotImplementedError, GrouperNotFoundError, ItemOverlapError, MissingContainerError, UnrecognizedSuspensionTypeError, UnknownItemIdError, UnsupportedVehicleTypeError };
|
|
12
13
|
/**
|
|
13
14
|
* Calculates loaded cargo weight per axle for each transport in the payload.
|
|
14
15
|
* @param request - Request with `{ envs, config? }`.
|
|
@@ -17,6 +18,7 @@ export { ContainerSequenceNotFoundError, DeflectionModelNotImplementedError, Gro
|
|
|
17
18
|
* @throws {UnsupportedVehicleTypeError} When physics rejects the vehicle type.
|
|
18
19
|
* @throws {UnrecognizedSuspensionTypeError} When vanderleia suspension type is invalid.
|
|
19
20
|
* @throws {GrouperNotFoundError} When a merged-container grouper is missing.
|
|
21
|
+
* @throws {ItemOverlapError} When two allocated items occupy the same volume.
|
|
20
22
|
* Other exported error classes are for lower-level physics modules, not thrown here.
|
|
21
23
|
*/
|
|
22
24
|
export declare function calculate_weight_on_axles_physics(request: WeightByAxisRequestInput): WeightByAxisSuccessOutput;
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACR,mBAAmB,EACnB,wBAAwB,EAC3B,MAAM,uCAAuC,CAAA;AAC9C,OAAO,KAAK,EACR,oBAAoB,EACpB,yBAAyB,EAC5B,MAAM,8CAA8C,CAAA;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4CAA4C,CAAA;AAC/E,OAAO,EAAE,kCAAkC,EAAE,MAAM,wEAAwE,CAAA;AAC3H,OAAO,EAAE,+BAA+B,EAAE,MAAM,0DAA0D,CAAA;AAC1G,OAAO,EAAE,2BAA2B,EAAE,MAAM,sDAAsD,CAAA;AAClG,OAAO,EAAE,8BAA8B,EAAE,MAAM,6DAA6D,CAAA;AAC5G,OAAO,EAAE,oBAAoB,EAAE,MAAM,mDAAmD,CAAA;AACxF,OAAO,EAAE,qBAAqB,EAAE,MAAM,oDAAoD,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACR,mBAAmB,EACnB,wBAAwB,EAC3B,MAAM,uCAAuC,CAAA;AAC9C,OAAO,KAAK,EACR,oBAAoB,EACpB,yBAAyB,EAC5B,MAAM,8CAA8C,CAAA;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4CAA4C,CAAA;AAC/E,OAAO,EAAE,kCAAkC,EAAE,MAAM,wEAAwE,CAAA;AAC3H,OAAO,EAAE,+BAA+B,EAAE,MAAM,0DAA0D,CAAA;AAC1G,OAAO,EAAE,2BAA2B,EAAE,MAAM,sDAAsD,CAAA;AAClG,OAAO,EAAE,8BAA8B,EAAE,MAAM,6DAA6D,CAAA;AAC5G,OAAO,EAAE,oBAAoB,EAAE,MAAM,mDAAmD,CAAA;AACxF,OAAO,EAAE,qBAAqB,EAAE,MAAM,oDAAoD,CAAA;AAC1F,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAA;AAE3E,YAAY,EACR,mBAAmB,EACnB,wBAAwB,EACxB,oBAAoB,EACpB,yBAAyB,EAC5B,CAAA;AAED,OAAO,EACH,8BAA8B,EAC9B,kCAAkC,EAClC,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,+BAA+B,EAC/B,kBAAkB,EAClB,2BAA2B,EAC9B,CAAA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iCAAiC,CAC7C,OAAO,EAAE,wBAAwB,GAClC,yBAAyB,CAG3B"}
|
package/build/index.js
CHANGED
|
@@ -6,7 +6,8 @@ import { UnsupportedVehicleTypeError } from './core/physics/models/UnsupportedVe
|
|
|
6
6
|
import { ContainerSequenceNotFoundError } from './core/physics/transports/ContainerSequenceNotFoundError.js';
|
|
7
7
|
import { GrouperNotFoundError } from './core/physics/transports/GrouperNotFoundError.js';
|
|
8
8
|
import { MissingContainerError } from './core/physics/transports/MissingContainerError.js';
|
|
9
|
-
|
|
9
|
+
import { ItemOverlapError } from './core/orchestration/ItemOverlapError.js';
|
|
10
|
+
export { ContainerSequenceNotFoundError, DeflectionModelNotImplementedError, GrouperNotFoundError, ItemOverlapError, MissingContainerError, UnrecognizedSuspensionTypeError, UnknownItemIdError, UnsupportedVehicleTypeError };
|
|
10
11
|
/**
|
|
11
12
|
* Calculates loaded cargo weight per axle for each transport in the payload.
|
|
12
13
|
* @param request - Request with `{ envs, config? }`.
|
|
@@ -15,6 +16,7 @@ export { ContainerSequenceNotFoundError, DeflectionModelNotImplementedError, Gro
|
|
|
15
16
|
* @throws {UnsupportedVehicleTypeError} When physics rejects the vehicle type.
|
|
16
17
|
* @throws {UnrecognizedSuspensionTypeError} When vanderleia suspension type is invalid.
|
|
17
18
|
* @throws {GrouperNotFoundError} When a merged-container grouper is missing.
|
|
19
|
+
* @throws {ItemOverlapError} When two allocated items occupy the same volume.
|
|
18
20
|
* Other exported error classes are for lower-level physics modules, not thrown here.
|
|
19
21
|
*/
|
|
20
22
|
export function calculate_weight_on_axles_physics(request) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jetta/axle-load-calculator",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Merged weight_by_axis physics and orchestration library",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"coverage": "c8 --check-coverage --lines 80 --functions 80 --branches 80 --statements 80 --reporter=html --reporter=text npm run test"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
+
"@jetta/number-compare": "^3.0.3",
|
|
25
26
|
"zod": "^3.24.0"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|