@world-engines/project-host 0.1.0-alpha.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/LICENSE +46 -0
- package/assets/gui/WELogo-title.svg +11 -0
- package/assets/gui/app.js +1326 -0
- package/assets/gui/index.html +118 -0
- package/assets/gui/local-preview-asset-urls.js +61 -0
- package/assets/gui/local-preview-bridge.js +393 -0
- package/assets/gui/spatial-template-panel.js +233 -0
- package/assets/gui/styles.css +115 -0
- package/assets/gui/terrain-render.js +120 -0
- package/assets/gui/workspace-status.css +17 -0
- package/assets/gui/workspace-status.js +255 -0
- package/assets/gui/world-map-globe.js +187 -0
- package/assets/gui/world-map-worker.js +62 -0
- package/assets/gui/world-map.css +30 -0
- package/assets/gui/world-map.js +2466 -0
- package/dist/account-model-proxy.d.ts +21 -0
- package/dist/account-model-proxy.js +470 -0
- package/dist/authoring-browser-runtime.d.ts +7 -0
- package/dist/authoring-browser-runtime.js +110 -0
- package/dist/authoring-ingestion.d.ts +38 -0
- package/dist/authoring-ingestion.js +410 -0
- package/dist/authoring-model-connection.d.ts +166 -0
- package/dist/authoring-model-connection.js +757 -0
- package/dist/chinese-lexical.d.ts +152 -0
- package/dist/chinese-lexical.js +555 -0
- package/dist/chromium-preview-browser-driver.d.ts +43 -0
- package/dist/chromium-preview-browser-driver.js +575 -0
- package/dist/cli/download.d.ts +12 -0
- package/dist/cli/download.js +50 -0
- package/dist/cli/dump.d.ts +32 -0
- package/dist/cli/dump.js +91 -0
- package/dist/cli/ingest.d.ts +49 -0
- package/dist/cli/ingest.js +225 -0
- package/dist/cli/review.d.ts +10 -0
- package/dist/cli/review.js +44 -0
- package/dist/cli/upload.d.ts +57 -0
- package/dist/cli/upload.js +112 -0
- package/dist/cli-command.d.ts +60 -0
- package/dist/cli-command.js +613 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +182 -0
- package/dist/desktop-authoring-runtime.d.ts +88 -0
- package/dist/desktop-authoring-runtime.js +1602 -0
- package/dist/desktop-sidecar.d.ts +11 -0
- package/dist/desktop-sidecar.js +143 -0
- package/dist/document-dump.d.ts +113 -0
- package/dist/document-dump.js +431 -0
- package/dist/document-graph-extractor.d.ts +125 -0
- package/dist/document-graph-extractor.js +588 -0
- package/dist/document-ingestion-journal.d.ts +68 -0
- package/dist/document-ingestion-journal.js +471 -0
- package/dist/document-ingestion.d.ts +183 -0
- package/dist/document-ingestion.js +976 -0
- package/dist/document-query-path-proof.d.ts +30 -0
- package/dist/document-query-path-proof.js +34 -0
- package/dist/document-query-path-renderer.d.ts +50 -0
- package/dist/document-query-path-renderer.js +75 -0
- package/dist/document-query-proof-paths.d.ts +22 -0
- package/dist/document-query-proof-paths.js +71 -0
- package/dist/document-query.d.ts +97 -0
- package/dist/document-query.js +1106 -0
- package/dist/document-relation-role.d.ts +14 -0
- package/dist/document-relation-role.js +86 -0
- package/dist/document-source.d.ts +107 -0
- package/dist/document-source.js +255 -0
- package/dist/embedding-cache.d.ts +35 -0
- package/dist/embedding-cache.js +317 -0
- package/dist/frozen-review-local-pipeline.d.ts +88 -0
- package/dist/frozen-review-local-pipeline.js +609 -0
- package/dist/frozen-review-source-capture.d.ts +15 -0
- package/dist/frozen-review-source-capture.js +551 -0
- package/dist/frozen-review-wasm-encryptor.d.ts +16 -0
- package/dist/frozen-review-wasm-encryptor.js +72 -0
- package/dist/frozen-review.d.ts +131 -0
- package/dist/frozen-review.js +802 -0
- package/dist/graph-traversal.d.ts +23 -0
- package/dist/graph-traversal.js +100 -0
- package/dist/gui/graph-layout-worker.js +1 -0
- package/dist/gui/graph-layout.wasm +0 -0
- package/dist/gui/graph.css +1 -0
- package/dist/gui/graph.js +76 -0
- package/dist/gui/plane-generation.js +112 -0
- package/dist/gui/plane-generator.js +310 -0
- package/dist/gui/plane-generator_bg.wasm +0 -0
- package/dist/gui/procedural-city.js +595 -0
- package/dist/gui/road-generation.js +129 -0
- package/dist/gui/road-parcels.js +1584 -0
- package/dist/gui/score.css +1 -0
- package/dist/gui/score.js +54 -0
- package/dist/gui/spatial-runtime.js +1231 -0
- package/dist/gui/spatial-templates.js +200 -0
- package/dist/gui/trigger.css +1 -0
- package/dist/gui/trigger.js +142 -0
- package/dist/harness-callback-transport.d.ts +17 -0
- package/dist/harness-callback-transport.js +128 -0
- package/dist/harness-document-ingestion.d.ts +77 -0
- package/dist/harness-document-ingestion.js +343 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +43 -0
- package/dist/ingestion-source-reconciliation.d.ts +88 -0
- package/dist/ingestion-source-reconciliation.js +253 -0
- package/dist/ladybug-runtime.d.ts +117 -0
- package/dist/ladybug-runtime.js +886 -0
- package/dist/local-account-embedding.d.ts +34 -0
- package/dist/local-account-embedding.js +294 -0
- package/dist/local-gallery.d.ts +35 -0
- package/dist/local-gallery.js +227 -0
- package/dist/local-gui-auth.d.ts +96 -0
- package/dist/local-gui-auth.js +703 -0
- package/dist/local-gui-contract.d.ts +53 -0
- package/dist/local-gui-contract.js +5 -0
- package/dist/local-gui-image-assets.d.ts +17 -0
- package/dist/local-gui-image-assets.js +96 -0
- package/dist/local-gui-preview-client.d.ts +3 -0
- package/dist/local-gui-preview-client.js +111 -0
- package/dist/local-gui-score.d.ts +72 -0
- package/dist/local-gui-score.js +184 -0
- package/dist/local-gui-server.d.ts +10 -0
- package/dist/local-gui-server.js +987 -0
- package/dist/local-gui-version.d.ts +17 -0
- package/dist/local-gui-version.js +147 -0
- package/dist/local-gui-workspace.d.ts +14 -0
- package/dist/local-gui-workspace.js +171 -0
- package/dist/local-model-settings.d.ts +28 -0
- package/dist/local-model-settings.js +124 -0
- package/dist/local-preview-assets.d.ts +28 -0
- package/dist/local-preview-assets.js +124 -0
- package/dist/local-preview-bound-resources.d.ts +12 -0
- package/dist/local-preview-bound-resources.js +80 -0
- package/dist/local-preview-message-store.d.ts +63 -0
- package/dist/local-preview-message-store.js +214 -0
- package/dist/local-preview-player-read-models.d.ts +47 -0
- package/dist/local-preview-player-read-models.js +90 -0
- package/dist/local-preview-projections.d.ts +61 -0
- package/dist/local-preview-projections.js +117 -0
- package/dist/local-preview-runtime.d.ts +105 -0
- package/dist/local-preview-runtime.js +553 -0
- package/dist/local-preview-session.d.ts +73 -0
- package/dist/local-preview-session.js +395 -0
- package/dist/local-preview-source.d.ts +40 -0
- package/dist/local-preview-source.js +192 -0
- package/dist/local-preview-view-events.d.ts +101 -0
- package/dist/local-preview-view-events.js +179 -0
- package/dist/local-preview-view-state-sqlite.d.ts +24 -0
- package/dist/local-preview-view-state-sqlite.js +263 -0
- package/dist/local-preview-view-state.d.ts +93 -0
- package/dist/local-preview-view-state.js +108 -0
- package/dist/local-preview-vite-config.d.ts +6 -0
- package/dist/local-preview-vite-config.js +122 -0
- package/dist/local-preview-world-effects.d.ts +9 -0
- package/dist/local-preview-world-effects.js +55 -0
- package/dist/local-preview-worldline-store.d.ts +47 -0
- package/dist/local-preview-worldline-store.js +282 -0
- package/dist/local-preview-worldlines.d.ts +95 -0
- package/dist/local-preview-worldlines.js +136 -0
- package/dist/mcp-async-dispatcher.d.ts +3 -0
- package/dist/mcp-async-dispatcher.js +129 -0
- package/dist/mcp-line-queue.d.ts +14 -0
- package/dist/mcp-line-queue.js +184 -0
- package/dist/mcp-pipe-internal.d.ts +6 -0
- package/dist/mcp-pipe-internal.js +151 -0
- package/dist/mcp-pipe-response.d.ts +14 -0
- package/dist/mcp-pipe-response.js +50 -0
- package/dist/mcp-stdio-response.d.ts +12 -0
- package/dist/mcp-stdio-response.js +27 -0
- package/dist/mcp.d.ts +27 -0
- package/dist/mcp.js +194 -0
- package/dist/prepared-embedding-cache.d.ts +38 -0
- package/dist/prepared-embedding-cache.js +238 -0
- package/dist/preview-browser-adapter.d.ts +53 -0
- package/dist/preview-browser-adapter.js +171 -0
- package/dist/preview-runtime.d.ts +67 -0
- package/dist/preview-runtime.js +460 -0
- package/dist/project-auth-transport.d.ts +27 -0
- package/dist/project-auth-transport.js +121 -0
- package/dist/project-auth.d.ts +51 -0
- package/dist/project-auth.js +108 -0
- package/dist/project-git-capture-recovery.d.ts +16 -0
- package/dist/project-git-capture-recovery.js +347 -0
- package/dist/project-git-cli.d.ts +5 -0
- package/dist/project-git-cli.js +40 -0
- package/dist/project-git-scenario-source.d.ts +10 -0
- package/dist/project-git-scenario-source.js +240 -0
- package/dist/project-git-view-source.d.ts +13 -0
- package/dist/project-git-view-source.js +134 -0
- package/dist/project-git.d.ts +97 -0
- package/dist/project-git.js +656 -0
- package/dist/project-host.d.ts +59 -0
- package/dist/project-host.js +471 -0
- package/dist/project-writer-lease.d.ts +18 -0
- package/dist/project-writer-lease.js +430 -0
- package/dist/public-error.d.ts +7 -0
- package/dist/public-error.js +61 -0
- package/dist/retrieval-benchmark.d.ts +46 -0
- package/dist/retrieval-benchmark.js +58 -0
- package/dist/safe-project-path.d.ts +8 -0
- package/dist/safe-project-path.js +93 -0
- package/dist/scenario-writer.d.ts +32 -0
- package/dist/scenario-writer.js +191 -0
- package/dist/transfer/download.d.ts +159 -0
- package/dist/transfer/download.js +598 -0
- package/dist/transfer/transport.d.ts +26 -0
- package/dist/transfer/transport.js +1 -0
- package/dist/transfer/upload.d.ts +162 -0
- package/dist/transfer/upload.js +354 -0
- package/dist/transfer-types.d.ts +95 -0
- package/dist/transfer-types.js +1 -0
- package/dist/transfer.d.ts +18 -0
- package/dist/transfer.js +273 -0
- package/dist/trigger-runtime.d.ts +121 -0
- package/dist/trigger-runtime.js +153 -0
- package/dist/vendor/wasm-core/asset-hashes.json +5 -0
- package/dist/vendor/wasm-core/wasm_core.d.ts +490 -0
- package/dist/vendor/wasm-core/wasm_core.js +1 -0
- package/dist/vendor/wasm-core/wasm_core_bg.wasm +0 -0
- package/dist/view-watcher.d.ts +9 -0
- package/dist/view-watcher.js +34 -0
- package/package.json +110 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
export const ROAD_GENERATION_PROFILE = "terrain-roads-v1";
|
|
2
|
+
/**
|
|
3
|
+
* 绑定路径搜索、桥隧门户、地形采样和地块图语义的 canonical 规则字节。
|
|
4
|
+
* 任一语义变更都必须更新这份 JSON 并发布新 identity。
|
|
5
|
+
*/
|
|
6
|
+
export const LEGACY_V6_ROAD_GENERATION_RULES_CANONICAL = '{"algorithm":"direction-state-a-star-v2;32-coprime-neighbors;stable-heap-tie-order;route-edge-cache-v1","anchor":"city-guide-anchor-once;whole-candidate-single-connectors;no-grid-exact-grid-pair-foldback-v3","bridge":"complete-dry-portal-water-span-v1;linear-deck-3d-length-at-most-maxBridgeLengthMeters;all-water-interior;no-shortcut-or-split-v2","cityAccess":"surface-street-node-short-connect-v1;radius-over-block-times-1.5-ceil-4to12;candidate-distance-0.75to3-block;target-1.7-block;stable-city-seed-node-pair-sort;surface-only-existing-nodes;actual-sampler-direct-or-bounded-astar;complete-portal-no-acute-boundary-containment;access-unreachable-domain-v1","cityBoundary":"radial-budget-v2;world-seed-city-seed-city-id-fnv1a-xor;24to128-rays;step-at-most10m;phase-smooth-three-harmonics-radius-0.85to1.15;actual-sampler-surface-or-complete-classify-edge-portal;surface-abs-grade-integral-ds-times-1-plus-0.6-normalized-grade-over-one-minus-normalized;normalized-grade-at-least-0.995-reject;bounded-ccw-nonclosed-3to128|unbuildable-empty;city-road-continuous-points-inside-boundary;intercity-unclipped","cityField":"seeded-radial-terrain-contour-guide-v1","direction":"heading-dot-at-least-zero;interior-angle-at-least90deg;all-assembled-route-final-gate-v2","elevation":"relative-height-times-elevationScaleMeters-v1","limits":"maxGrade-roadWidthMeters-maxBridgeLengthMeters-maxTunnelLengthMeters-v1","parcelFace":"road-parcels-v4-boundary-highway;cityId-exact-arterial-local-street-surface-only;quantized-strict-xy-intersection-split;dcel-left-turn;positive-inside-concave-boundary;oriented-length-weighted-second-moment-principal-axis;canonical-longest-edge-isotropic-fallback;projection-midline-clip;area22500-recursion-depth8;inset-half-widest-road-plus-setback;triangulated-max-square-safe-bounds-v4","parcelFrontage":"face-plus-uncovered-frontage-v1;cityId-exact-arterial-local-street-surface-elementary-run;polyline-slice-16to42m;two-sided-offset;depth-clamp-blockSize-times-0.18-10to20;source-and-road-corridor-clear;face-first-frontage-positive-area-nonoverlap-stable-id-greedy-v1","parcelGraph":"road-parcels-v4-boundary-highway","parcelIdentity":"boundary-token-sorted-hash-worldSeed-citySeed-cityId;oriented-split-normal-token;frontage-side-and-ordinal;weighted-land-use;id-sort-v3","parcelTerrain":"polygon-touching-cells-dry-finite;adjacent-touching-cell-slope-at-most-settings-maxSlope;grid-at-most257-v1","portalLookahead":"complete-portal-before-partial-surface-v1;exact-dry-grid-portal-preserved-v1;off-grid-origin-requires-validated-surface-connector-v1;connector-budget-cost-required-v1","repair":"same-core-segment-splice;10m-grid;at-most8-attempts;min-margin200m-v1","roadClass":"required-kind-intercity-arterial-local;required-class-street-motorway;intercity-motorway-else-street;all-intercity-motorway-and-city-nonbuildable-roads-forbidden-corridor;centerline-no-intersection-or-containment;clearance-half-width-plus-setback-v1","shortcut":"surface-run-control-edge-boundaries;candidates-i-to-j-j-at-most-i-plus24-or-last;actual-sampler-water-grade-step-at-most10m;reverse-sparse-dag-heading-compatible-dot-epsilon1e-12;no-accumulated-cost;farthest-reachable-stable-descending;retain-original-if-no-complete-chain;whole-road-stable-branch-unreachable-if-final-acute;bridge-tunnel-excluded-v3","terrain":"canonical-plane-hydrology-fixed-sampling;global-long-axis257;city-long-axis65to257;actual-finite-sampler-step10m;no-sub10m-obstacle-guarantee-v1","tunnel":"covered-dry-portal-bore;actual-cover-at-least1m;3d-length-at-most-maxTunnelLengthMeters;no-shortcut-or-split;no-water-interior;roadWidth-surface-abutment-v2","version":6}';
|
|
7
|
+
/**
|
|
8
|
+
* 该字符串绑定 profile、算法版本与上方 canonical 规则字节的 SHA-256。
|
|
9
|
+
* 道路语义变化时必须发布新 identity,禁止让旧世界静默重算为不同结果。
|
|
10
|
+
*/
|
|
11
|
+
export const LEGACY_V6_IDENTITY = "chat.worldengine.terrain-roads/v1;rules-sha256=9dc32e6e3f5e63fbf378d6b83dfa67c2e9d62dabfebe5b432956f7ff0fdb8443";
|
|
12
|
+
export const STRUCTURED_V8_ROAD_GENERATION_RULES_CANONICAL = '{"version":8,"algorithm":"direction-state-a-star-v2;32-coprime-neighbors;stable-heap-tie-order;route-edge-cache-v1","cityField":"structured-two-family-seeded-skeleton-v8;candidate-only-actual-terrain-router-required","cityCandidateBudget":"boundary-polygon-shoelace-abs-area-m2;ceil-sqrt-area-over-block-times-0.42-per-family;clamp6to15;not-nominal-radius-area;not-feasible-terrain-mask","cityCandidateFamilies":"six-arterial-rays-from-center-four-collinear-points;arterial-base-seeded-angle-plus-sixth-turn-plus-seeded-jitter;two-transverse-families-base-and-base-plus-pi-over-two-plus-seeded-0.18rad;collector-and-local;four-point-parabolic-sweeps;seeded-bend-block-times-0.32;actual-terrain-and-boundary-gates","cityBoundary":"radial-budget-v2;world-seed-city-seed-city-id-fnv1a-xor;24to128-rays;step-at-most10m;phase-smooth-three-harmonics-radius-0.85to1.15;actual-sampler-surface-or-complete-classify-edge-portal;surface-abs-grade-integral-ds-times-1-plus-0.6-normalized-grade-over-one-minus-normalized;normalized-grade-at-least-0.995-reject;bounded-ccw-nonclosed-3to128|unbuildable-empty;city-road-continuous-points-inside-boundary;intercity-unclipped","cityStructuredClip":"v8-nonarterial-all-exact-boundary-inside-runs;candidate-segment-boundary-intersections;boundary-inclusive;rooted-run-nearest-original-sweep-midpoint-else-inside-run-nearest-midpoint;arterial-uses-legacy-origin-first-exit-clip;final-route-sample-boundary-verify-at-most10m","cityStructuredRoot":"v8-transverse-same-city-surface-strict-internal-xy-intersection;parallel-collinear-endpoint-near-end-reject-epsilon1e-9;nearest-original-sweep-midpoint-then-stable-road-segment-point-pair-tie-order;root-z-actual-terrain-sample;both-old-surface-halves-revalidate-before-noding","cityRootArms":"root-left-right-independent-anchor-direct-or-bounded-astar-finish-and-boundary-check;both-concatenate|one-commit-valid-arm-and-record-other-unreachable|none-reject;assembled-root-route-no-acute-final-gate;preserve-root-xy","citySurfaceNoding":"v8-same-city-nonintercity-surface-only;strict-internal-xy-crossing-with-nonfinite-reject-and-dimensionless-interior-epsilon1e-9|positive-collinear-xy-overlap-line-distance-at-most1e-7;canonical-overlap-endpoints-xy-round-1e-7m-and-z-actual-terrain-sample;all-four-half-edges-or-local-endpoint-replacement-surface-revalidate;stable-road-segment-original-edge-index-descending-and-t-descending-insert-order;not-cross-city-bridge-tunnel-or-general-grade-separation","cityExactSurfaceReuse":"after-same-city-surface-noding-and-common-overlap-endpoint-rewrite;same-city-nonintercity-contiguous-all-surface-normalized-run-only-without-crossing-bridge-or-tunnel;undirected-exact-xyz-bit-elementary-key;arterial-then-local-then-lexical-road-id-owner;partial-overlap-reuse-removes-nonowner-exact-pieces-retains-continuous-chains;single-retained-chain-keeps-parent-id|multiple-retained-chains-child-id-parent-plus-retained-child-first-last-xy-IEEE-bits-and-reuse-purpose-no-ordinal;refresh-sorted-layout-ids;no-reuse-status-output;not-near-or-unvalidated-overlap-reuse","cityAccess":"legacy-v6-only:surface-street-node-short-connect-v1;radius-over-block-times-1.5-ceil-4to12;candidate-distance-0.75to3-block;target-1.7-block;stable-city-seed-node-pair-sort;surface-only-existing-nodes;actual-sampler-direct-or-bounded-astar;complete-portal-no-acute-boundary-containment;access-unreachable-domain-v1","parcelFace":"structured-v8-convex-closed-face-with-every-simplified-edge-matched-to-real-ordinary-street-elementary-frontage-only;per-edge-inward-half-plane-offset-before-split;clearance-max-matching-edge-half-width-plus-nonnegative-setback;mixed-width-collinear-match-uses-max-conservative-clearance;nonconvex-unmatched-or-invalid-offset-closed-face-reject-no-topology-guess","parcelSplit":"structured-v8-projection-midline-clip-area-settings-maxFaceAreaMeters-default22500-recursion-depth8;each-child-needs-longest-continuous-collinear-overlap-with-inset-real-street-frontage-at-least-max-10-min-20-widest-road;not-fragment-sum;on-failure-retain-parent-unsplit;cut-edge-is-not-frontage","parcelFrontage":"face-plus-uncovered-frontage-v1;open-area-only-real-surface-ordinary-street-segment-run;polyline-slice-min16-max42-except-unsplittable-first-edge-may-exceed42;two-sided-offset;inner-road-corridor-clearance-plus-0.01;source-run-clearance-recheck-at-least-clearance-minus0.2;depth-clamp-blockSize-times-0.18-10to20;source-and-road-corridor-clear;face-first-frontage-positive-area-nonoverlap-stable-id-greedy-v1;no-entrance-or-navigation-reachability-claim","legacyParcel":"legacy-v6-undefined-or-explicit-legacy-uses-prior-split-and-centroid-inset-path;v8-only-convex-offset-and-child-frontage-rule;shared-invalid-algorithm-fail-closed","parcelGraph":"road-parcels-v4-boundary-highway","parcelIdentity":"boundary-token-sorted-hash-worldSeed-citySeed-cityId;oriented-split-normal-token;frontage-side-and-ordinal;weighted-land-use;id-sort-v3","parcelTerrain":"polygon-touching-cells-dry-finite;adjacent-touching-cell-slope-at-most-settings-maxSlope;grid-at-most257-v1","roadClass":"required-kind-intercity-arterial-local;required-class-street-motorway;intercity-motorway-else-street;all-intercity-motorway-and-city-nonbuildable-roads-forbidden-corridor;centerline-no-intersection-or-containment;clearance-half-width-plus-setback-v1","direction":"heading-dot-at-least-zero;interior-angle-at-least90deg;all-assembled-route-final-gate-v2","limits":"maxGrade-roadWidthMeters-maxBridgeLengthMeters-maxTunnelLengthMeters-v1","elevation":"relative-height-times-elevationScaleMeters-v1","terrain":"canonical-plane-hydrology-fixed-sampling;global-long-axis257;city-long-axis65to257;actual-finite-sampler-step10m;no-sub10m-obstacle-guarantee-v1","portalLookahead":"complete-portal-before-partial-surface-v1;exact-dry-grid-portal-preserved-v1;off-grid-origin-requires-validated-surface-connector-v1;connector-budget-cost-required-v1","bridge":"complete-dry-portal-water-span-v1;linear-deck-3d-length-at-most-maxBridgeLengthMeters;all-water-interior;no-shortcut-or-split-v2","tunnel":"covered-dry-portal-bore;actual-cover-at-least1m;3d-length-at-most-maxTunnelLengthMeters;no-shortcut-or-split;no-water-interior;roadWidth-surface-abutment-v2","shortcut":"surface-run-control-edge-boundaries;candidates-i-to-j-j-at-most-i-plus24-or-last;actual-sampler-water-grade-step-at-most10m;reverse-sparse-dag-heading-compatible-dot-epsilon1e-12;no-accumulated-cost;farthest-reachable-stable-descending;retain-original-if-no-complete-chain;whole-road-stable-branch-unreachable-if-final-acute;bridge-tunnel-excluded-v3","repair":"same-core-segment-splice;10m-grid;at-most8-attempts;min-margin200m-v1"}';
|
|
13
|
+
export const STRUCTURED_V8_IDENTITY = "chat.worldengine.terrain-roads/v1;rules-sha256=03ab0544e8fdfc741045dccac18a946eb95b76bc10e9880012cba50060b29b4f";
|
|
14
|
+
export const FRONTAGE_BALANCED_V9_ROAD_GENERATION_RULES_CANONICAL = '{"version":9,"algorithm":"direction-state-a-star-v2;32-coprime-neighbors;stable-heap-tie-order;route-edge-cache-v1","cityField":"structured-two-family-seeded-skeleton-v8;candidate-only-actual-terrain-router-required","cityCandidateBudget":"boundary-polygon-shoelace-abs-area-m2;ceil-sqrt-area-over-block-times-0.42-per-family;clamp6to15;not-nominal-radius-area;not-feasible-terrain-mask","cityCandidateFamilies":"six-arterial-rays-from-center-four-collinear-points;arterial-base-seeded-angle-plus-sixth-turn-plus-seeded-jitter;two-transverse-families-base-and-base-plus-pi-over-two-plus-seeded-0.18rad;collector-and-local;four-point-parabolic-sweeps;seeded-bend-block-times-0.32;actual-terrain-and-boundary-gates","cityBoundary":"radial-budget-v2;world-seed-city-seed-city-id-fnv1a-xor;24to128-rays;step-at-most10m;phase-smooth-three-harmonics-radius-0.85to1.15;actual-sampler-surface-or-complete-classify-edge-portal;surface-abs-grade-integral-ds-times-1-plus-0.6-normalized-grade-over-one-minus-normalized;normalized-grade-at-least-0.995-reject;bounded-ccw-nonclosed-3to128|unbuildable-empty;city-road-continuous-points-inside-boundary;intercity-unclipped","cityStructuredClip":"v8-nonarterial-all-exact-boundary-inside-runs;candidate-segment-boundary-intersections;boundary-inclusive;rooted-run-nearest-original-sweep-midpoint-else-inside-run-nearest-midpoint;arterial-uses-legacy-origin-first-exit-clip;final-route-sample-boundary-verify-at-most10m","cityStructuredRoot":"v8-transverse-same-city-surface-strict-internal-xy-intersection;parallel-collinear-endpoint-near-end-reject-epsilon1e-9;nearest-original-sweep-midpoint-then-stable-road-segment-point-pair-tie-order;root-z-actual-terrain-sample;both-old-surface-halves-revalidate-before-noding","cityRootArms":"root-left-right-independent-anchor-direct-or-bounded-astar-finish-and-boundary-check;both-concatenate|one-commit-valid-arm-and-record-other-unreachable|none-reject;assembled-root-route-no-acute-final-gate;preserve-root-xy","citySurfaceNoding":"v8-same-city-nonintercity-surface-only;strict-internal-xy-crossing-with-nonfinite-reject-and-dimensionless-interior-epsilon1e-9|positive-collinear-xy-overlap-line-distance-at-most1e-7;canonical-overlap-endpoints-xy-round-1e-7m-and-z-actual-terrain-sample;all-four-half-edges-or-local-endpoint-replacement-surface-revalidate;stable-road-segment-original-edge-index-descending-and-t-descending-insert-order;not-cross-city-bridge-tunnel-or-general-grade-separation","cityExactSurfaceReuse":"after-same-city-surface-noding-and-common-overlap-endpoint-rewrite;same-city-nonintercity-contiguous-all-surface-normalized-run-only-without-crossing-bridge-or-tunnel;undirected-exact-xyz-bit-elementary-key;arterial-then-local-then-lexical-road-id-owner;partial-overlap-reuse-removes-nonowner-exact-pieces-retains-continuous-chains;single-retained-chain-keeps-parent-id|multiple-retained-chains-child-id-parent-plus-retained-child-first-last-xy-IEEE-bits-and-reuse-purpose-no-ordinal;refresh-sorted-layout-ids;no-reuse-status-output;not-near-or-unvalidated-overlap-reuse","cityAccess":"legacy-v6-only:surface-street-node-short-connect-v1;radius-over-block-times-1.5-ceil-4to12;candidate-distance-0.75to3-block;target-1.7-block;stable-city-seed-node-pair-sort;surface-only-existing-nodes;actual-sampler-direct-or-bounded-astar;complete-portal-no-acute-boundary-containment;access-unreachable-domain-v1","parcelAlgorithm":"identity-bound-v1;v6=legacy-v6-road-core-and-parcels;v8=structured-v8-road-core-and-parcels;v9=structured-v8-road-core-plus-frontage-balanced-v9-parcels;v9-vs-v8-selects-parcel-only;no-load-time-upgrade","parcelFace":"structured-v8-convex-closed-face-with-every-simplified-edge-matched-to-real-ordinary-street-elementary-frontage-only;per-edge-inward-half-plane-offset-before-split;clearance-max-matching-edge-half-width-plus-nonnegative-setback;mixed-width-collinear-match-uses-max-conservative-clearance;nonconvex-unmatched-or-invalid-offset-closed-face-reject-no-topology-guess","parcelSplit":"frontage-balanced-v9-primary-structured-v8-projection-midline-clip-area-settings-maxFaceAreaMeters-default22500;each-child-needs-longest-continuous-collinear-overlap-with-inset-real-street-frontage-at-least-max-10-min-20-widest-road;not-fragment-sum;when-primary-area-frontage-invalid-try-real-inset-frontage-overlap-cuts-length-desc-edge-id-normal-key;canonical-positive-frontage-tangent-normal;cut-overlap-midpoint-projection;dedup-normal-and-cut;first-area-frontage-valid-candidate;recursive-split-depth8;emitted-children-pass-existing-final-terrain-corridor-nonoverlap-gates;no-retry-after-final-rejection;on-all-area-frontage-failure-retain-parent-unsplit;cut-edge-is-not-frontage","parcelFrontage":"face-plus-uncovered-frontage-v1;open-area-only-real-surface-ordinary-street-segment-run;polyline-slice-min16-max42-except-unsplittable-first-edge-may-exceed42;two-sided-offset;inner-road-corridor-clearance-plus-0.01;source-run-clearance-recheck-at-least-clearance-minus0.2;depth-clamp-blockSize-times-0.18-10to20;source-and-road-corridor-clear;face-first-frontage-positive-area-nonoverlap-stable-id-greedy-v1;no-entrance-or-navigation-reachability-claim","legacyParcel":"legacy-v6-undefined-or-explicit-legacy-uses-prior-split-and-centroid-inset-path;structured-v8-uses-convex-offset-and-primary-child-frontage-rule;frontage-balanced-v9-keeps-v8-road-core-face-inset-and-primary-split-plus-stable-frontage-cut-fallback;shared-invalid-algorithm-fail-closed","parcelGraph":"road-parcels-v4-boundary-highway","parcelIdentity":"boundary-token-sorted-hash-worldSeed-citySeed-cityId;oriented-split-normal-token;frontage-side-and-ordinal;weighted-land-use;id-sort-v3","parcelTerrain":"polygon-touching-cells-dry-finite;adjacent-touching-cell-slope-at-most-settings-maxSlope;grid-at-most257-v1","roadClass":"required-kind-intercity-arterial-local;required-class-street-motorway;intercity-motorway-else-street;all-intercity-motorway-and-city-nonbuildable-roads-forbidden-corridor;centerline-no-intersection-or-containment;clearance-half-width-plus-setback-v1","direction":"heading-dot-at-least-zero;interior-angle-at-least90deg;all-assembled-route-final-gate-v2","limits":"maxGrade-roadWidthMeters-maxBridgeLengthMeters-maxTunnelLengthMeters-v1","elevation":"relative-height-times-elevationScaleMeters-v1","terrain":"canonical-plane-hydrology-fixed-sampling;global-long-axis257;city-long-axis65to257;actual-finite-sampler-step10m;no-sub10m-obstacle-guarantee-v1","portalLookahead":"complete-portal-before-partial-surface-v1;exact-dry-grid-portal-preserved-v1;off-grid-origin-requires-validated-surface-connector-v1;connector-budget-cost-required-v1","bridge":"complete-dry-portal-water-span-v1;linear-deck-3d-length-at-most-maxBridgeLengthMeters;all-water-interior;no-shortcut-or-split-v2","tunnel":"covered-dry-portal-bore;actual-cover-at-least1m;3d-length-at-most-maxTunnelLengthMeters;no-shortcut-or-split;no-water-interior;roadWidth-surface-abutment-v2","shortcut":"surface-run-control-edge-boundaries;candidates-i-to-j-j-at-most-i-plus24-or-last;actual-sampler-water-grade-step-at-most10m;reverse-sparse-dag-heading-compatible-dot-epsilon1e-12;no-accumulated-cost;farthest-reachable-stable-descending;retain-original-if-no-complete-chain;whole-road-stable-branch-unreachable-if-final-acute;bridge-tunnel-excluded-v3","repair":"same-core-segment-splice;10m-grid;at-most8-attempts;min-margin200m-v1"}';
|
|
15
|
+
export const FRONTAGE_BALANCED_V9_IDENTITY = "chat.worldengine.terrain-roads/v1;rules-sha256=671b01df50d378c85208f910ba10e63ff5b03d3787619898c8de60453329b38b";
|
|
16
|
+
export const ROAD_GENERATION_RULES_CANONICAL = '{"version":10,"algorithm":"direction-state-a-star-v2;32-coprime-neighbors;stable-heap-tie-order;route-edge-cache-v1","cityField":"structured-two-family-seeded-skeleton-v8;candidate-only-actual-terrain-router-required","cityCandidateBudget":"boundary-polygon-shoelace-abs-area-m2;ceil-sqrt-area-over-block-times-0.42-per-family;clamp6to15;not-nominal-radius-area;not-feasible-terrain-mask","cityCandidateFamilies":"six-arterial-rays-from-center-four-collinear-points;arterial-base-seeded-angle-plus-sixth-turn-plus-seeded-jitter;two-transverse-families-base-and-base-plus-pi-over-two-plus-seeded-0.18rad;collector-and-local;four-point-parabolic-sweeps;seeded-bend-block-times-0.32;actual-terrain-and-boundary-gates","cityBoundary":"radial-budget-v2;world-seed-city-seed-city-id-fnv1a-xor;24to128-rays;step-at-most10m;phase-smooth-three-harmonics-radius-0.85to1.15;actual-sampler-surface-or-complete-classify-edge-portal;surface-abs-grade-integral-ds-times-1-plus-0.6-normalized-grade-over-one-minus-normalized;normalized-grade-at-least-0.995-reject;bounded-ccw-nonclosed-3to128|unbuildable-empty;city-road-continuous-points-inside-boundary;intercity-unclipped","cityStructuredClip":"v8-nonarterial-all-exact-boundary-inside-runs;candidate-segment-boundary-intersections;boundary-inclusive;rooted-run-nearest-original-sweep-midpoint-else-inside-run-nearest-midpoint;arterial-uses-legacy-origin-first-exit-clip;final-route-sample-boundary-verify-at-most10m","cityStructuredRoot":"v8-transverse-same-city-surface-strict-internal-xy-intersection;parallel-collinear-endpoint-near-end-reject-epsilon1e-9;nearest-original-sweep-midpoint-then-stable-road-segment-point-pair-tie-order;root-z-actual-terrain-sample;both-old-surface-halves-revalidate-before-noding","cityRootArms":"root-left-right-independent-anchor-direct-or-bounded-astar-finish-and-boundary-check;both-concatenate|one-commit-valid-arm-and-record-other-unreachable|none-reject;assembled-root-route-no-acute-final-gate;preserve-root-xy","citySurfaceNoding":"v8-same-city-nonintercity-surface-only;strict-internal-xy-crossing-with-nonfinite-reject-and-dimensionless-interior-epsilon1e-9|positive-collinear-xy-overlap-line-distance-at-most1e-7;canonical-overlap-endpoints-xy-round-1e-7m-and-z-actual-terrain-sample;all-four-half-edges-or-local-endpoint-replacement-surface-revalidate;stable-road-segment-original-edge-index-descending-and-t-descending-insert-order;not-cross-city-bridge-tunnel-or-general-grade-separation","cityExactSurfaceReuse":"after-same-city-surface-noding-and-common-overlap-endpoint-rewrite;same-city-nonintercity-contiguous-all-surface-normalized-run-only-without-crossing-bridge-or-tunnel;undirected-exact-xyz-bit-elementary-key;arterial-then-local-then-lexical-road-id-owner;partial-overlap-reuse-removes-nonowner-exact-pieces-retains-continuous-chains;single-retained-chain-keeps-parent-id|multiple-retained-chains-child-id-parent-plus-retained-child-first-last-xy-IEEE-bits-and-reuse-purpose-no-ordinal;refresh-sorted-layout-ids;no-reuse-status-output;not-near-or-unvalidated-overlap-reuse","cityAccess":"legacy-v6-only:surface-street-node-short-connect-v1;radius-over-block-times-1.5-ceil-4to12;candidate-distance-0.75to3-block;target-1.7-block;stable-city-seed-node-pair-sort;surface-only-existing-nodes;actual-sampler-direct-or-bounded-astar;complete-portal-no-acute-boundary-containment;access-unreachable-domain-v1","parcelAlgorithm":"identity-bound-v1;v6=legacy-v6-road-core-and-parcels;v8=structured-v8-road-core-and-parcels;v9=structured-v8-road-core-plus-frontage-balanced-v9-parcels;v10=structured-v8-road-core-plus-shape-filled-v10-parcels;v10-vs-v9-selects-parcel-only;no-load-time-upgrade","parcelFace":"shape-filled-v10-simple-single-ring-closed-face;real-ordinary-street-elementary-frontage-only;collinear-ring-simplify;per-edge-inward-offset-max-matching-real-road-half-width-plus-nonnegative-setback-plus-4epsilon-quantization-guard;inset-must-stay-within-source-and-strict-road-clearance;self-cross-reject;concave-ear-clip-then-stable-convex-merge;internal-chords-have-no-offset-and-no-frontage;unsupported-complex-or-hole-face-reject-no-topology-guess","parcelSplit":"shape-filled-v10-long-axis-oriented-bounds-primary-then-stable-face-axis;projection-midline-clip-targets-settings-maxFaceAreaMeters-default22500-not-terminal-hard-limit;shape-context-cut-children-inset-by-4epsilon-per-side-leaving-8epsilon-artificial-nonroad-gap-to-prevent-quantized-shared-edge-positive-overlap;no-distance-or-overlap-gate-relaxation;both-children-area-at-least-settings-minParcelAreaMeters-default36;each-child-needs-longest-continuous-real-inset-street-frontage-at-least-max-10-min-20-widest-road;shape-node-and-recursive-output-hard-gates;pair-atomic-no-single-child-commit;frontage-balanced-real-inset-frontage-cut-fallback;recursive-depth8;at-depth-or-no-valid-cut-shape-valid-parent-may-remain-even-over-max-area;at-depth-or-no-valid-cut-invalid-shape-reject;cut-edge-is-not-frontage","parcelFrontage":"shape-filled-v10-face-first-then-uncovered-frontage-only;closed-valid-inset-faces-fill-before-open-street;real-surface-ordinary-street-run-resampled-at-at-most-min-10-maxSliceLength;two-sided-offset;depth-at-least-blockSize-times-0.18-and-at-least-minShortSide-times-sqrt2-plus1;maxSliceLength-max-requiredStripDimension-plus10-only-when-requiredStripDimension-over42-and-min-42-maxAspectRatio-times-depth-so-minShortSide-override-remains-sliceable;slice-at-least-minShortSide-times-sqrt2-plus1;shape-safe-bounds-and-ratio-hard-gates;source-and-all-road-corridor-boundary-terrain-clear;positive-area-nonoverlap-stable-id-greedy;no-entrance-or-navigation-reachability-claim","legacyParcel":"legacy-v6-undefined-or-explicit-legacy-uses-prior-split-and-centroid-inset-path;structured-v8-uses-convex-offset-and-primary-child-frontage-rule;frontage-balanced-v9-keeps-v8-road-core-face-inset-and-primary-split-plus-stable-frontage-cut-fallback;shape-filled-v10-keeps-v8-road-core-and-uses-simple-ring-inset-concave-decomposition-shape-hard-gates-and-uncovered-frontage-only;shared-invalid-algorithm-fail-closed","parcelGraph":"road-parcels-v4-boundary-highway","parcelIdentity":"boundary-token-sorted-hash-worldSeed-citySeed-cityId;oriented-split-normal-token;frontage-side-and-ordinal;weighted-land-use;id-sort-v3;shape-filled-v10-canonical-ring-ear-clip-first-valid-vertex-order-then-first-pair-convex-merge-loop;decomposed-piece-traversal-order-is-explicit-root-c-pieceIndex-and-affects-stable-id","parcelTerrain":"polygon-touching-cells-dry-finite;adjacent-touching-cell-slope-at-most-settings-maxSlope;grid-at-most257-v1","roadClass":"required-kind-intercity-arterial-local;required-class-street-motorway;intercity-motorway-else-street;all-intercity-motorway-and-city-nonbuildable-roads-forbidden-corridor;centerline-no-intersection-or-containment;clearance-half-width-plus-setback-v1","direction":"heading-dot-at-least-zero;interior-angle-at-least90deg;all-assembled-route-final-gate-v2","limits":"maxGrade-roadWidthMeters-maxBridgeLengthMeters-maxTunnelLengthMeters-v1","elevation":"relative-height-times-elevationScaleMeters-v1","terrain":"canonical-plane-hydrology-fixed-sampling;global-long-axis257;city-long-axis65to257;actual-finite-sampler-step10m;no-sub10m-obstacle-guarantee-v1","portalLookahead":"complete-portal-before-partial-surface-v1;exact-dry-grid-portal-preserved-v1;off-grid-origin-requires-validated-surface-connector-v1;connector-budget-cost-required-v1","bridge":"complete-dry-portal-water-span-v1;linear-deck-3d-length-at-most-maxBridgeLengthMeters;all-water-interior;no-shortcut-or-split-v2","tunnel":"covered-dry-portal-bore;actual-cover-at-least1m;3d-length-at-most-maxTunnelLengthMeters;no-shortcut-or-split;no-water-interior;roadWidth-surface-abutment-v2","shortcut":"surface-run-control-edge-boundaries;candidates-i-to-j-j-at-most-i-plus24-or-last;actual-sampler-water-grade-step-at-most10m;reverse-sparse-dag-heading-compatible-dot-epsilon1e-12;no-accumulated-cost;farthest-reachable-stable-descending;retain-original-if-no-complete-chain;whole-road-stable-branch-unreachable-if-final-acute;bridge-tunnel-excluded-v3","repair":"same-core-segment-splice;10m-grid;at-most8-attempts;min-margin200m-v1","parcelShape":"coordinates-round-decimal6-epsilon1e-6;minimum-oriented-convex-hull-edge-aligned-bounds;settings-maxAspectRatio-finite-at-least1-default4;settings-minShortSideMeters-finite-at-least26-default26;short-side-at-least-minShortSideMeters;long-side-at-most-short-side-times-maxAspectRatio;safe-axis-aligned-square-inside-polygon-width-and-height-at-least-minShortSideMeters;all-partition-nodes-and-emitted-parcels-terrain-boundary-corridor-clear"}';
|
|
17
|
+
export const ROAD_GENERATION_IDENTITY = "chat.worldengine.terrain-roads/v1;rules-sha256=58fc51cfe9986a8da0cc6931c8600cf4c1afbbcda80f58e00038b76f982aec5b";
|
|
18
|
+
/**
|
|
19
|
+
* 已发布 identity 的精确 allowlist。新算法必须先有冻结的 rules digest,才能加入这里;
|
|
20
|
+
* 不得以“当前默认值”替换已保存 source 的 identity。
|
|
21
|
+
*/
|
|
22
|
+
export const SUPPORTED_ROAD_GENERATION_IDENTITIES = Object.freeze([
|
|
23
|
+
LEGACY_V6_IDENTITY,
|
|
24
|
+
STRUCTURED_V8_IDENTITY,
|
|
25
|
+
FRONTAGE_BALANCED_V9_IDENTITY,
|
|
26
|
+
ROAD_GENERATION_IDENTITY,
|
|
27
|
+
]);
|
|
28
|
+
export function roadGenerationAlgorithm(identity) {
|
|
29
|
+
switch (identity) {
|
|
30
|
+
case LEGACY_V6_IDENTITY:
|
|
31
|
+
return "legacy-v6";
|
|
32
|
+
case STRUCTURED_V8_IDENTITY:
|
|
33
|
+
case FRONTAGE_BALANCED_V9_IDENTITY:
|
|
34
|
+
case ROAD_GENERATION_IDENTITY:
|
|
35
|
+
return "structured-v8";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** 已保存 identity 独立选择 parcel 语义;V9 仍复用已发布 V8 道路 core。 */
|
|
39
|
+
export function roadParcelAlgorithm(identity) {
|
|
40
|
+
switch (identity) {
|
|
41
|
+
case LEGACY_V6_IDENTITY:
|
|
42
|
+
return "legacy-v6";
|
|
43
|
+
case STRUCTURED_V8_IDENTITY:
|
|
44
|
+
return "structured-v8";
|
|
45
|
+
case FRONTAGE_BALANCED_V9_IDENTITY:
|
|
46
|
+
return "frontage-balanced-v9";
|
|
47
|
+
case ROAD_GENERATION_IDENTITY:
|
|
48
|
+
return "shape-filled-v10";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 只有已冻结的后继 identity 才能令旧 source 出现显式升级预览入口。
|
|
53
|
+
* 加载或保存绝不能据此静默升级。
|
|
54
|
+
*/
|
|
55
|
+
export function roadGenerationUpgradeTarget(identity) {
|
|
56
|
+
return identity === LEGACY_V6_IDENTITY
|
|
57
|
+
|| identity === STRUCTURED_V8_IDENTITY
|
|
58
|
+
|| identity === FRONTAGE_BALANCED_V9_IDENTITY
|
|
59
|
+
? ROAD_GENERATION_IDENTITY
|
|
60
|
+
: undefined;
|
|
61
|
+
}
|
|
62
|
+
export const DEFAULT_ROAD_GENERATION = Object.freeze({
|
|
63
|
+
profile: ROAD_GENERATION_PROFILE,
|
|
64
|
+
identity: ROAD_GENERATION_IDENTITY,
|
|
65
|
+
allowBridges: true,
|
|
66
|
+
allowTunnels: false,
|
|
67
|
+
maxBridgeLengthMeters: 300,
|
|
68
|
+
maxTunnelLengthMeters: 1_000,
|
|
69
|
+
maxGrade: 0.15,
|
|
70
|
+
roadWidthMeters: 8,
|
|
71
|
+
elevationScaleMeters: 3_000,
|
|
72
|
+
});
|
|
73
|
+
const ROAD_GENERATION_KEYS = new Set([
|
|
74
|
+
"profile",
|
|
75
|
+
"identity",
|
|
76
|
+
"allowBridges",
|
|
77
|
+
"allowTunnels",
|
|
78
|
+
"maxBridgeLengthMeters",
|
|
79
|
+
"maxTunnelLengthMeters",
|
|
80
|
+
"maxGrade",
|
|
81
|
+
"roadWidthMeters",
|
|
82
|
+
"elevationScaleMeters",
|
|
83
|
+
]);
|
|
84
|
+
function isRecord(value) {
|
|
85
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
86
|
+
}
|
|
87
|
+
function boundedNumber(value, field, minimum, maximum) {
|
|
88
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
89
|
+
throw new TypeError(`${field} 必须是有限数`);
|
|
90
|
+
if (value < minimum || value > maximum)
|
|
91
|
+
throw new RangeError(`${field} 必须位于 ${minimum}..${maximum}`);
|
|
92
|
+
return value;
|
|
93
|
+
}
|
|
94
|
+
function boolean(value, field) {
|
|
95
|
+
if (typeof value !== "boolean")
|
|
96
|
+
throw new TypeError(`${field} 必须是 boolean`);
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
function supportedIdentity(value) {
|
|
100
|
+
if (typeof value !== "string" || !SUPPORTED_ROAD_GENERATION_IDENTITIES.includes(value)) {
|
|
101
|
+
throw new TypeError(`identity 必须为 ${SUPPORTED_ROAD_GENERATION_IDENTITIES.join(" 或 ")}`);
|
|
102
|
+
}
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
/** 严格验证桥隧道路设置,拒绝未知字段并返回不可变 canonical 副本。 */
|
|
106
|
+
export function validateRoadGeneration(input) {
|
|
107
|
+
if (!isRecord(input))
|
|
108
|
+
throw new TypeError("RoadGenerationV1 必须是对象");
|
|
109
|
+
const unknown = Object.keys(input).filter((key) => !ROAD_GENERATION_KEYS.has(key));
|
|
110
|
+
if (unknown.length > 0)
|
|
111
|
+
throw new TypeError(`RoadGenerationV1 包含未知字段:${unknown.join(", ")}`);
|
|
112
|
+
const missing = [...ROAD_GENERATION_KEYS].filter((key) => !Object.hasOwn(input, key));
|
|
113
|
+
if (missing.length > 0)
|
|
114
|
+
throw new TypeError(`RoadGenerationV1 缺少字段:${missing.join(", ")}`);
|
|
115
|
+
if (input.profile !== ROAD_GENERATION_PROFILE)
|
|
116
|
+
throw new TypeError(`profile 必须为 ${ROAD_GENERATION_PROFILE}`);
|
|
117
|
+
const identity = supportedIdentity(input.identity);
|
|
118
|
+
return Object.freeze({
|
|
119
|
+
profile: ROAD_GENERATION_PROFILE,
|
|
120
|
+
identity,
|
|
121
|
+
allowBridges: boolean(input.allowBridges, "allowBridges"),
|
|
122
|
+
allowTunnels: boolean(input.allowTunnels, "allowTunnels"),
|
|
123
|
+
maxBridgeLengthMeters: boundedNumber(input.maxBridgeLengthMeters, "maxBridgeLengthMeters", 1, 1_000_000),
|
|
124
|
+
maxTunnelLengthMeters: boundedNumber(input.maxTunnelLengthMeters, "maxTunnelLengthMeters", 1, 1_000_000),
|
|
125
|
+
maxGrade: boundedNumber(input.maxGrade, "maxGrade", 0.01, 1),
|
|
126
|
+
roadWidthMeters: boundedNumber(input.roadWidthMeters, "roadWidthMeters", 3, 40),
|
|
127
|
+
elevationScaleMeters: boundedNumber(input.elevationScaleMeters, "elevationScaleMeters", 1, 100_000),
|
|
128
|
+
});
|
|
129
|
+
}
|