@operato/scene-transport 10.0.0-beta.47 → 10.0.0-beta.48
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 +9 -0
- package/dist/amr.d.ts +1 -1
- package/dist/amr.js +3 -1
- package/dist/amr.js.map +1 -1
- package/dist/charging-station.d.ts +1 -1
- package/dist/charging-station.js +1 -1
- package/dist/charging-station.js.map +1 -1
- package/dist/forbidden-zone.d.ts +1 -1
- package/dist/forbidden-zone.js +1 -1
- package/dist/forbidden-zone.js.map +1 -1
- package/dist/intersection.d.ts +1 -1
- package/dist/intersection.js +1 -1
- package/dist/intersection.js.map +1 -1
- package/dist/lane.d.ts +1 -1
- package/dist/lane.js +1 -1
- package/dist/lane.js.map +1 -1
- package/dist/nav-zone.d.ts +1 -1
- package/dist/nav-zone.js +1 -1
- package/dist/nav-zone.js.map +1 -1
- package/dist/speed-zone.d.ts +1 -1
- package/dist/speed-zone.js +1 -1
- package/dist/speed-zone.js.map +1 -1
- package/dist/traffic-controller.d.ts +1 -1
- package/dist/traffic-controller.js +1 -1
- package/dist/traffic-controller.js.map +1 -1
- package/dist/waypoint.d.ts +1 -1
- package/dist/waypoint.js +1 -1
- package/dist/waypoint.js.map +1 -1
- package/package.json +3 -3
- package/src/amr.ts +3 -1
- package/src/charging-station.ts +1 -1
- package/src/forbidden-zone.ts +1 -1
- package/src/intersection.ts +1 -1
- package/src/lane.ts +1 -1
- package/src/nav-zone.ts +1 -1
- package/src/speed-zone.ts +1 -1
- package/src/traffic-controller.ts +1 -1
- package/src/waypoint.ts +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [10.0.0-beta.48](https://github.com/things-scene/operato-scene/compare/v10.0.0-beta.47...v10.0.0-beta.48) (2026-05-26)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### :bug: Bug Fix
|
|
10
|
+
|
|
11
|
+
* **scene-base/transport): nature getter 패턴 통일 + feat(facility:** Room alpha (투명도) ([9685bbe](https://github.com/things-scene/operato-scene/commit/9685bbe8efe588fc5b817116f76c73973b3ab063))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
6
15
|
## [10.0.0-beta.47](https://github.com/things-scene/operato-scene/compare/v10.0.0-beta.46...v10.0.0-beta.47) (2026-05-26)
|
|
7
16
|
|
|
8
17
|
|
package/dist/amr.d.ts
CHANGED
|
@@ -54,7 +54,7 @@ declare const Base: typeof Component & {
|
|
|
54
54
|
* 결정 + multi-mover coordination.
|
|
55
55
|
*/
|
|
56
56
|
export default class AMR extends Base implements Navigable {
|
|
57
|
-
|
|
57
|
+
get nature(): ComponentNature;
|
|
58
58
|
get state(): AMRState;
|
|
59
59
|
static legends: Record<string, LegendBinding>;
|
|
60
60
|
buildRealObject(): any;
|
package/dist/amr.js
CHANGED
|
@@ -82,7 +82,9 @@ const Base = FloorBound(Mover(CarrierHolder(ContainerCapacity(Legendable(Placeab
|
|
|
82
82
|
* 결정 + multi-mover coordination.
|
|
83
83
|
*/
|
|
84
84
|
let AMR = class AMR extends Base {
|
|
85
|
-
|
|
85
|
+
get nature() {
|
|
86
|
+
return NATURE;
|
|
87
|
+
}
|
|
86
88
|
get state() {
|
|
87
89
|
return super.state;
|
|
88
90
|
}
|
package/dist/amr.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"amr.js","sourceRoot":"","sources":["../src/amr.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * AMR — Autonomous Mobile Robot.\n *\n * AGV 의 *_자율 종_*. 고정 경로 (line/magnet/track) 대신 *_dynamic path planning +\n * obstacle avoidance + multi-mover coordination_*.\n *\n * 활용:\n * - things-scene Phase J — NavGraph + planPathAStar + ReservationTable\n * - things-scene Phase G — 6DOF Pose\n * - operato-scene Phase Z — Dispatcher (mission 자동 routing)\n * - operato-scene Phase A — Mover mixin (pickAndPlace 기반)\n *\n * AMR 가 새로 구현하는 것:\n * - `Navigable` 4 단계 (planPath / reservePath / followReservation / releaseReservation)\n * - battery state + drain (frameClock tick) — AMR-5\n * - 자동 charging mission (dispatcher 활용) — AMR-5\n * - idle policy (home / charging / stay / patrol) — AMR-6\n *\n * 이 파일 (AMR-2) 의 scope:\n * - AMR 컴포넌트 + state + nature\n * - Navigable 4 단계 minimal 구현 (NavGraph 없으면 null fallback)\n * - moveTo override → Navigable 4 단계 wiring\n * - canReach override → planPath dry-run\n *\n * 후속 PR:\n * - AMR-5: battery drain + 자동 charging mission\n * - AMR-6: idle policy\n * - AMR-7: NavGraph 자동 추론 (Facility 로부터)\n */\n\nimport {\n Component, ComponentNature, ContainerAbstract, ContainerCapacity, sceneComponent,\n NavGraph, ReservationTable, reservationTable, planPathAStar,\n frameClock\n} from '@hatiolab/things-scene'\nimport type {\n State, Material3D,\n PathPlan, PathPlanOptions, Reservation, SpeedProfile, Navigable\n} from '@hatiolab/things-scene'\n\n// Vec3 — things-scene 의 navigation/types 에서 정의. main index 노출 안 됐을 수 있어\n// 안전하게 local type 으로.\ntype Vec3 = { x: number; y: number; z: number }\nimport {\n CarrierHolder, FloorBound, Legendable, Mover, Placeable,\n findDispatcher,\n type Alignment, type CarrierAttachPoint, type Heights, type LegendBinding,\n type MoveOptions, type PlacementArchetype\n} from '@operato/scene-base'\n\nimport { AMR3D } from './amr-3d.js'\nimport {\n resolveNavGraph as helpResolveNavGraph,\n moverCurrentWorldPosition,\n resolveTargetWorldPosition,\n navigablePlanPath,\n navigableReservePath,\n navigableReleaseReservation,\n navigableFollowReservation,\n navigableCanReach,\n makeSegmentTarget,\n defaultSpeedProfile\n} from './navigable-helpers.js'\nimport { pointInPolygon } from './polygon-utils.js'\n\nexport type AMRStatus = 'idle' | 'planning' | 'moving' | 'charging' | 'returning' | 'error'\n\nexport interface AMRState extends State {\n // ── 운영 상태 ──\n status?: AMRStatus\n\n // ── 시뮬레이션 / 모니터링 ──\n /** 0~100. 100 = 만충. */\n battery?: number\n /** 운행 속도 (scene units / sim sec). default 200. */\n speed?: number\n\n // ── 자율 capability ──\n /** AMR 의 toolType — Navigable 검사용. lane.allowedToolTypes 매칭. default 'amr'. */\n toolType?: string\n /** SpeedProfile — Phase J 의 path planning 에 사용. 미명시 시 state.speed 로 단순 변환. */\n speedProfile?: SpeedProfile\n\n // ── Battery 정책 (AMR-5 에서 활용) ──\n /** 자동 충전 트리거 임계 (default 20). battery <= threshold 시 charging 임무 enqueue. */\n batteryThreshold?: number\n /** %/min drain (default 0.5). */\n batteryDrainRate?: number\n\n // ── Charging / home (AMR-5, AMR-6) ──\n /** 자동 충전 시 도착 station id. dispatcher.findHolderById 로 조회. */\n chargingStationId?: string\n /** 작업 없을 때 idle 위치. */\n homePosition?: { x: number; y: number; z?: number }\n /** Idle 정책 — AMR-6. */\n idlePolicy?: 'home' | 'charging' | 'stay' | 'patrol'\n\n // ── 자율 동작 flags ──\n /** Phase J path planning 사용. default true. false → AGV 같은 직선 (Mover.moveTo super). */\n autonomousPathPlanning?: boolean\n\n // ── 3D 재질 ──\n material3d?: Material3D\n}\n\nconst BODY_LEGEND: Record<string, string> = {\n idle: '#888',\n planning: '#88aabb',\n moving: '#aaccdd',\n charging: '#ffaa00',\n returning: '#88bb88',\n error: '#c66',\n default: '#888'\n}\n\nconst LAMP_EMISSIVE_LEGEND: Record<string, string> = {\n idle: '#222222',\n planning: '#4488ff', // blue — thinking\n moving: '#44ff44', // green — running\n charging: '#ffaa00', // amber — charging\n returning: '#44ff88',\n error: '#ff3333',\n default: '#222222'\n}\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n {\n type: 'select', label: 'status', name: 'status',\n property: { options: ['idle', 'planning', 'moving', 'charging', 'returning', 'error'] }\n },\n { type: 'number', label: 'battery', name: 'battery', placeholder: '0~100 (default 100)' },\n { type: 'number', label: 'speed', name: 'speed', placeholder: 'units/sec (default 200)' },\n { type: 'string', label: 'tool-type', name: 'toolType', placeholder: 'AMR class (default \"amr\")' },\n { type: 'string', label: 'charging-station-id', name: 'chargingStationId',\n placeholder: 'dispatcher 가 findHolderById 로 조회' },\n { type: 'select', label: 'idle-policy', name: 'idlePolicy',\n property: { options: ['home', 'charging', 'stay', 'patrol'] } },\n { type: 'checkbox', label: 'autonomous-path-planning', name: 'autonomousPathPlanning' }\n ],\n help: 'scene/component/amr'\n}\n\n// Composition — AGV/Forklift 와 동일 chain:\n// FloorBound → Mover → CarrierHolder → ContainerCapacity → Legendable → Placeable → ContainerAbstract\nconst Base = FloorBound(\n Mover(CarrierHolder(ContainerCapacity(Legendable(Placeable(ContainerAbstract)))))\n) as unknown as typeof Component & {\n new (...args: any[]): Component & {\n isCarrierHolder: boolean\n isMover: boolean\n attachPointFor(carrier: Component): CarrierAttachPoint | undefined\n pick(carrier: Component, options?: MoveOptions): Promise<void>\n place(carrier: Component, holder: Component, options?: MoveOptions): Promise<void>\n pickAndPlace(carrier: Component, holder: Component, options?: MoveOptions): Promise<void>\n moveTo(target: Component, options?: MoveOptions): Promise<void>\n canReach(target: any): boolean\n }\n}\n\n/**\n * AMR — Autonomous Mobile Robot.\n *\n * Mover + Navigable. Phase J 의 path planning + reservation 활용해 dynamic path\n * 결정 + multi-mover coordination.\n */\n@sceneComponent('amr')\nexport default class AMR extends Base implements Navigable {\n static nature = NATURE\n\n override get state(): AMRState {\n return super.state as AMRState\n }\n\n static legends: Record<string, LegendBinding> = {\n bodyColor: { from: 'status', legend: BODY_LEGEND },\n lampEmissive: { from: 'status', legend: LAMP_EMISSIVE_LEGEND }\n }\n\n buildRealObject() {\n return new AMR3D(this) as any\n }\n\n // ── Phase J: Navigable interface ──────────────────────────────────────\n\n get toolType(): string {\n return (this.state as AMRState).toolType ?? 'amr'\n }\n\n get speedProfile(): SpeedProfile {\n const s = this.state as AMRState\n if (s.speedProfile) return s.speedProfile\n return defaultSpeedProfile(s.speed ?? 200)\n }\n\n /**\n * 경로 계획. NavGraph 가 scene 안 있으면 A* 로 plan. 없으면 null (호출자가\n * Mover.moveTo super 의 직선 path 로 fallback).\n *\n * Phase J 의 planPathAStar 는 *_node id string_* 인자 — AMR 의 current world\n * position 과 target Vec3 를 가장 가까운 node 로 변환.\n *\n * @param target world coords\n * @param options PathPlanOptions\n */\n planPath(target: Vec3, options?: PathPlanOptions): PathPlan | null {\n return navigablePlanPath({\n mover: this,\n target,\n options,\n speedProfile: this.speedProfile,\n gridCellSize: (this.state as any)?.gridCellSize,\n toolType: this.toolType\n })\n }\n\n /**\n * 계획된 경로를 ReservationTable 에 commit. 충돌 시 null — caller (Mover.moveTo\n * override) 가 reroute / 대기 결정.\n */\n reservePath(plan: PathPlan, priority?: number): Reservation[] | null {\n return navigableReservePath(this, plan, priority)\n }\n\n /**\n * commit 된 reservation 따라 sim time 진행. 각 PathPlan segment 의 fromPos → toPos\n * 로 *_Mover.moveTo super_* 위임 (직선 lerp). segment 내부는 직선이므로 super 의\n * distance-based arrival 정확.\n *\n * Note: Reservation 자체 가 fromPos/toPos 없음 — PathPlan 의 PathSegment 가\n * 가짐. 그래서 followReservation 시 PathPlan 도 함께 알아야 — 여기선 last\n * planned PathPlan (this._lastPathPlan) 활용. moveTo override 가 한 번에 plan +\n * reserve + follow 호출하므로 race 없음.\n */\n async followReservation(reservations: Reservation[]): Promise<void> {\n const plan = this._lastPathPlan\n this.setState({ status: 'moving' as AMRStatus })\n if (!plan || plan.segments.length === 0) {\n // PathPlan 없으면 — sim time wait fallback (도착 의미 없는 stub)\n for (const r of reservations) {\n const duration = r.timeWindow.endSimMs - r.timeWindow.startSimMs\n if (duration > 0) await new Promise(resolve => setTimeout(resolve, duration))\n }\n this.releaseReservation(reservations)\n return\n }\n await navigableFollowReservation({\n mover: this,\n plan,\n reservations,\n superMoveTo: (target, options) => super.moveTo(target, options)\n })\n }\n\n /**\n * 점유 해제. 도착 완료 또는 cancel 시 호출.\n */\n releaseReservation(reservations: Reservation[]): void {\n // navigableFollowReservation 이 자동 release. 직접 cancel 시도 시 호출 가능.\n navigableReleaseReservation(reservations)\n }\n\n // ── Mover.moveTo override — Navigable 4 단계 wiring ────────────────────\n\n override async moveTo(target: Component, options?: MoveOptions): Promise<void> {\n const autonomous = (this.state as AMRState).autonomousPathPlanning !== false\n if (!autonomous) {\n // AGV 모드 — 직선\n return super.moveTo(target, options)\n }\n\n // target 의 world position 추출\n const targetPos = resolveTargetWorldPosition(target)\n if (!targetPos) {\n // fallback — super 의 직선\n return super.moveTo(target, options)\n }\n\n this.setState({ status: 'planning' as AMRStatus })\n const plan = this.planPath(targetPos, {\n priority: (options as any)?.priority ?? 0\n })\n if (!plan) {\n // path 발견 실패 — fallback 또는 throw. 현재는 super 의 직선 fallback.\n this._lastPathPlan = null\n this.setState({ status: 'moving' as AMRStatus })\n return super.moveTo(target, options)\n }\n\n // PathPlan 보관 — followReservation 이 segment.toPos 활용\n this._lastPathPlan = plan\n\n const reservations = this.reservePath(plan, (options as any)?.priority ?? 0)\n if (!reservations) {\n // 충돌 — 재시도 또는 대기. 현재는 짧은 대기 후 super fallback.\n this._lastPathPlan = null\n await new Promise(r => setTimeout(r, 500 + Math.random() * 500))\n this.setState({ status: 'moving' as AMRStatus })\n return super.moveTo(target, options)\n }\n\n try {\n await this.followReservation(reservations)\n } finally {\n this._lastPathPlan = null\n }\n this.setState({ status: 'idle' as AMRStatus })\n }\n\n /** moveTo override 가 planPath → followReservation 으로 plan 전달 — race-free. */\n private _lastPathPlan: PathPlan | null = null\n\n // ── AMR-5: Battery drain + 자동 charging ──────────────────────────────\n // ── AMR-6: Idle policy ───────────────────────────────────────────────\n //\n // frameClock subscribe — moving 중 battery drain, idle 시 idle policy 적용.\n // dispatcher.requestTransfer 위임으로 자동 mission (priority 250 charging /\n // 50 idle).\n\n private _tickUnsub?: () => void\n private _chargingMissionEnqueued = false // 한 cycle 만 enqueue\n private _idleMissionEnqueued = false\n private _lastTickSimTime = 0\n\n added(parent: any): void {\n super.added?.(parent)\n this._lastTickSimTime = frameClock.simTime\n this._tickUnsub = frameClock.subscribe((_dt, simTime) => {\n this._tick(simTime)\n }, {\n description: `amr[${(this.state as any).id ?? (this as any).refid}]`,\n component: this as unknown as Component\n })\n }\n\n removed(parent: any): void {\n this._tickUnsub?.()\n this._tickUnsub = undefined\n super.removed?.(parent)\n }\n\n dispose(): void {\n this._tickUnsub?.()\n this._tickUnsub = undefined\n super.dispose?.()\n }\n\n private _tick(simTime: number): void {\n if (!(this as any).app?.isViewMode) return\n\n const dtMs = simTime - this._lastTickSimTime\n this._lastTickSimTime = simTime\n if (dtMs <= 0) return\n\n const s = this.state as AMRState\n const status = s.status ?? 'idle'\n\n // 1. Battery drain — moving / planning / returning 일 때\n if (status === 'moving' || status === 'planning' || status === 'returning') {\n const drainPerMin = s.batteryDrainRate ?? 0.5 // %/min\n const drain = drainPerMin * dtMs / 60000\n const newBattery = Math.max(0, (s.battery ?? 100) - drain)\n if (newBattery !== s.battery) {\n this.setState({ battery: newBattery })\n }\n }\n\n // 2. 자동 charging mission — battery <= threshold + charging station 명시 + 충전 중 아님\n const threshold = s.batteryThreshold ?? 20\n if (\n (s.battery ?? 100) <= threshold &&\n s.chargingStationId &&\n status !== 'charging' && status !== 'returning' &&\n !this._chargingMissionEnqueued\n ) {\n this._chargingMissionEnqueued = true\n this._triggerChargingMission()\n }\n\n // 3. Idle policy — 작업 없을 때 자동 mission\n if (\n status === 'idle' &&\n (s.battery ?? 100) > threshold &&\n !this._idleMissionEnqueued\n ) {\n this._applyIdlePolicy()\n }\n\n // 4. AN-PR-6 — SpeedZone 통과 검사. 현재 위치 가 SpeedZone polygon 안이면\n // state.speed override. 영역 벗어나면 base speed 복원.\n this._applySpeedZoneOverride()\n }\n\n /**\n * AMR 의 현재 위치 가 SpeedZone polygon 안인지 검사 → speed 동적 override.\n *\n * 동작:\n * - scene 의 모든 SpeedZone 컴포넌트 sweep (root._speedZonesCache cache)\n * - AMR.world.position 에 대해 pointInPolygon 검사\n * - 통과 zone 의 *_가장 낮은 speedLimit_* 적용 (보수적)\n * - appliesTo csv 명시 시 — AMR.toolType 일치할 때만\n * - 벗어나면 state._baseSpeed 복원\n */\n private _applySpeedZoneOverride(): void {\n const root: any = (this as any).root\n if (!root) return\n\n // SpeedZone 들 cache\n if (!root._speedZonesCache) {\n const zones: any[] = []\n const visit = (c: any) => {\n if (!c) return\n if (c.state?.type === 'speed-zone' && typeof c.containsPoint === 'function') {\n zones.push(c)\n }\n const ch = c.components\n if (Array.isArray(ch)) for (const cc of ch) visit(cc)\n }\n visit(root)\n root._speedZonesCache = zones\n }\n const zones: any[] = root._speedZonesCache\n if (zones.length === 0) return\n\n // 현재 위치\n const pos = moverCurrentWorldPosition(this)\n if (!pos) return\n\n const myTool = this.toolType\n let minLimit: number | null = null\n for (const z of zones) {\n const zs = z.state\n // appliesTo filter\n const applies = (zs.appliesTo ?? '').trim()\n if (applies.length > 0) {\n const types = applies.split(',').map((t: string) => t.trim())\n if (!types.includes(myTool)) continue\n }\n if (typeof zs.speedLimit !== 'number') continue\n if (!z.containsPoint(pos.x, pos.z)) continue\n if (minLimit === null || zs.speedLimit < minLimit) minLimit = zs.speedLimit\n }\n\n // base speed 보관 (첫 호출 시 set)\n const s = this.state as AMRState\n const anyState = this.state as any\n if (typeof anyState._baseSpeed !== 'number') {\n anyState._baseSpeed = s.speed ?? 200\n }\n const baseSpeed = anyState._baseSpeed as number\n\n const targetSpeed = minLimit !== null ? Math.min(baseSpeed, minLimit) : baseSpeed\n if (s.speed !== targetSpeed) {\n this.setState({ speed: targetSpeed })\n }\n }\n\n private _triggerChargingMission(): void {\n const s = this.state as AMRState\n const stationId = s.chargingStationId\n if (!stationId) {\n this._chargingMissionEnqueued = false\n return\n }\n const dispatcher = findDispatcher(this as any)\n if (!dispatcher) {\n this._chargingMissionEnqueued = false\n return\n }\n\n this.setState({ status: 'returning' as AMRStatus })\n const ticket = dispatcher.requestTransfer({\n // from = AMR 자신 (carrier 처럼 mover 자체를 charging station 으로 이동)\n from: this as any,\n to: stationId,\n priority: 250, // 최고 우선 — 다른 작업 대기\n meta: { kind: 'charging', amrId: (s as any).id }\n })\n // ticket 완료 시점 — placement 가 ChargingStation 안으로 들어감.\n // AMR 의 status 는 charging-station 의 receiveAt 흐름에서 갱신됨.\n ticket.on('status', s2 => {\n if (s2 === 'completed' || s2 === 'failed' || s2 === 'canceled') {\n this._chargingMissionEnqueued = false\n }\n })\n }\n\n private _applyIdlePolicy(): void {\n const s = this.state as AMRState\n const policy = s.idlePolicy ?? 'stay'\n\n switch (policy) {\n case 'stay':\n return // 정지 — 아무것도 안 함\n\n case 'home': {\n if (!s.homePosition) return\n // 이미 home 근처면 skip — 단순 거리 검사\n const pos = moverCurrentWorldPosition(this)\n if (pos && Math.hypot(\n pos.x - s.homePosition.x,\n pos.z - (s.homePosition.z ?? 0)\n ) < 50) return\n this._idleMissionEnqueued = true\n this._enqueueIdleMission({\n x: s.homePosition.x,\n y: s.homePosition.y,\n z: s.homePosition.z ?? 0\n }, 'home')\n return\n }\n\n case 'charging': {\n const stationId = s.chargingStationId\n if (!stationId) return\n this._idleMissionEnqueued = true\n const dispatcher = findDispatcher(this as any)\n if (!dispatcher) {\n this._idleMissionEnqueued = false\n return\n }\n const ticket = dispatcher.requestTransfer({\n from: this as any,\n to: stationId,\n priority: 50, // 낮음 — 명시 작업 우선\n meta: { kind: 'idle-charging', amrId: (s as any).id }\n })\n ticket.on('status', st => {\n if (st === 'completed' || st === 'failed' || st === 'canceled') {\n this._idleMissionEnqueued = false\n }\n })\n return\n }\n\n case 'patrol': {\n // homePosition 또는 미리 등록된 patrol waypoint 사이 순회. 단순 구현 —\n // homePosition 만 활용. 향후 사용자 정책 (state.patrolWaypoints) 확장.\n if (!s.homePosition) return\n this._idleMissionEnqueued = true\n this._enqueueIdleMission({\n x: s.homePosition.x + (Math.random() * 200 - 100),\n y: s.homePosition.y,\n z: (s.homePosition.z ?? 0) + (Math.random() * 200 - 100)\n }, 'patrol')\n return\n }\n }\n }\n\n /** Idle / patrol 목적지로 self-mission. dispatcher 없으면 직접 moveTo. */\n private _enqueueIdleMission(target: Vec3, kind: string): void {\n // Proxy Component 만들어 dispatcher requestTransfer 보냄. dispatcher 의\n // findHolderById 가 없으므로 직접 moveTo proxy 도 OK — 단순.\n // 여기선 직접 moveTo — dispatcher 의 queue 안 거쳐서 자연 idle.\n const proxy = makeSegmentTarget(target)\n this.moveTo(proxy).finally(() => {\n this._idleMissionEnqueued = false\n })\n }\n\n // ── Mover.canReach override — planPath dry-run ────────────────────────\n //\n // `override` 키워드 미사용 — Base 캐스트가 super.canReach 의 generic type 만 노출\n // (TS4113 방지). runtime 위임은 정상.\n\n canReach(target: any): boolean {\n const autonomous = (this.state as AMRState).autonomousPathPlanning !== false\n if (!autonomous) {\n return super.canReach(target) // AGV 모드 — Mover default 위임\n }\n const result = navigableCanReach({\n mover: this,\n target,\n speedProfile: this.speedProfile,\n gridCellSize: (this.state as any)?.gridCellSize,\n toolType: this.toolType\n })\n if (result === null) return super.canReach(target) // NavGraph 없음 — fallback\n return result\n }\n\n // ── Helpers ───────────────────────────────────────────────────────────\n\n // _currentWorldPosition / _resolveComponentWorldPosition — navigable-helpers.ts 의\n // moverCurrentWorldPosition / resolveTargetWorldPosition 활용. 여기서 제거.\n\n /**\n * NavGraph resolve — helpers 의 4-layer fallback 활용.\n */\n private _resolveNavGraph(): NavGraph | null {\n return helpResolveNavGraph(this, this.speedProfile, (this.state as any)?.gridCellSize)\n }\n\n /**\n * 외부 (e.g. Facility / obstacle 변경 시) 명시 cache invalidate. grid + facility\n * 둘 다 무효화. scene event 자동 hook 은 향후 추가.\n */\n static invalidateAutoNavGraph(root: any): void {\n if (root) {\n delete root._autoNavGraph\n delete root._gridNavGraph\n delete root._componentsNavGraph\n delete root._speedZonesCache\n }\n }\n\n private _resolveReservationTable(): ReservationTable {\n // 글로벌 singleton — multi-mover coordination 자연.\n return reservationTable\n }\n\n /**\n * 단일 segment 이동 — fromPos → toPos. 실 visual lerp 는 Mover 의 표준 path\n * 활용 (Component proxy wrap). minimal 은 sim time wait.\n *\n * 향후 AMR-3 에서 정밀화 — segment 내부의 Component proxy + Mover.moveTo super.\n */\n private async _moveAlongSegment(r: Reservation): Promise<void> {\n const duration = r.timeWindow.endSimMs - r.timeWindow.startSimMs\n if (duration <= 0) return\n await new Promise(resolve => setTimeout(resolve, duration))\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"amr.js","sourceRoot":"","sources":["../src/amr.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * AMR — Autonomous Mobile Robot.\n *\n * AGV 의 *_자율 종_*. 고정 경로 (line/magnet/track) 대신 *_dynamic path planning +\n * obstacle avoidance + multi-mover coordination_*.\n *\n * 활용:\n * - things-scene Phase J — NavGraph + planPathAStar + ReservationTable\n * - things-scene Phase G — 6DOF Pose\n * - operato-scene Phase Z — Dispatcher (mission 자동 routing)\n * - operato-scene Phase A — Mover mixin (pickAndPlace 기반)\n *\n * AMR 가 새로 구현하는 것:\n * - `Navigable` 4 단계 (planPath / reservePath / followReservation / releaseReservation)\n * - battery state + drain (frameClock tick) — AMR-5\n * - 자동 charging mission (dispatcher 활용) — AMR-5\n * - idle policy (home / charging / stay / patrol) — AMR-6\n *\n * 이 파일 (AMR-2) 의 scope:\n * - AMR 컴포넌트 + state + nature\n * - Navigable 4 단계 minimal 구현 (NavGraph 없으면 null fallback)\n * - moveTo override → Navigable 4 단계 wiring\n * - canReach override → planPath dry-run\n *\n * 후속 PR:\n * - AMR-5: battery drain + 자동 charging mission\n * - AMR-6: idle policy\n * - AMR-7: NavGraph 자동 추론 (Facility 로부터)\n */\n\nimport {\n Component, ComponentNature, ContainerAbstract, ContainerCapacity, sceneComponent,\n NavGraph, ReservationTable, reservationTable, planPathAStar,\n frameClock\n} from '@hatiolab/things-scene'\nimport type {\n State, Material3D,\n PathPlan, PathPlanOptions, Reservation, SpeedProfile, Navigable\n} from '@hatiolab/things-scene'\n\n// Vec3 — things-scene 의 navigation/types 에서 정의. main index 노출 안 됐을 수 있어\n// 안전하게 local type 으로.\ntype Vec3 = { x: number; y: number; z: number }\nimport {\n CarrierHolder, FloorBound, Legendable, Mover, Placeable,\n findDispatcher,\n type Alignment, type CarrierAttachPoint, type Heights, type LegendBinding,\n type MoveOptions, type PlacementArchetype\n} from '@operato/scene-base'\n\nimport { AMR3D } from './amr-3d.js'\nimport {\n resolveNavGraph as helpResolveNavGraph,\n moverCurrentWorldPosition,\n resolveTargetWorldPosition,\n navigablePlanPath,\n navigableReservePath,\n navigableReleaseReservation,\n navigableFollowReservation,\n navigableCanReach,\n makeSegmentTarget,\n defaultSpeedProfile\n} from './navigable-helpers.js'\nimport { pointInPolygon } from './polygon-utils.js'\n\nexport type AMRStatus = 'idle' | 'planning' | 'moving' | 'charging' | 'returning' | 'error'\n\nexport interface AMRState extends State {\n // ── 운영 상태 ──\n status?: AMRStatus\n\n // ── 시뮬레이션 / 모니터링 ──\n /** 0~100. 100 = 만충. */\n battery?: number\n /** 운행 속도 (scene units / sim sec). default 200. */\n speed?: number\n\n // ── 자율 capability ──\n /** AMR 의 toolType — Navigable 검사용. lane.allowedToolTypes 매칭. default 'amr'. */\n toolType?: string\n /** SpeedProfile — Phase J 의 path planning 에 사용. 미명시 시 state.speed 로 단순 변환. */\n speedProfile?: SpeedProfile\n\n // ── Battery 정책 (AMR-5 에서 활용) ──\n /** 자동 충전 트리거 임계 (default 20). battery <= threshold 시 charging 임무 enqueue. */\n batteryThreshold?: number\n /** %/min drain (default 0.5). */\n batteryDrainRate?: number\n\n // ── Charging / home (AMR-5, AMR-6) ──\n /** 자동 충전 시 도착 station id. dispatcher.findHolderById 로 조회. */\n chargingStationId?: string\n /** 작업 없을 때 idle 위치. */\n homePosition?: { x: number; y: number; z?: number }\n /** Idle 정책 — AMR-6. */\n idlePolicy?: 'home' | 'charging' | 'stay' | 'patrol'\n\n // ── 자율 동작 flags ──\n /** Phase J path planning 사용. default true. false → AGV 같은 직선 (Mover.moveTo super). */\n autonomousPathPlanning?: boolean\n\n // ── 3D 재질 ──\n material3d?: Material3D\n}\n\nconst BODY_LEGEND: Record<string, string> = {\n idle: '#888',\n planning: '#88aabb',\n moving: '#aaccdd',\n charging: '#ffaa00',\n returning: '#88bb88',\n error: '#c66',\n default: '#888'\n}\n\nconst LAMP_EMISSIVE_LEGEND: Record<string, string> = {\n idle: '#222222',\n planning: '#4488ff', // blue — thinking\n moving: '#44ff44', // green — running\n charging: '#ffaa00', // amber — charging\n returning: '#44ff88',\n error: '#ff3333',\n default: '#222222'\n}\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n {\n type: 'select', label: 'status', name: 'status',\n property: { options: ['idle', 'planning', 'moving', 'charging', 'returning', 'error'] }\n },\n { type: 'number', label: 'battery', name: 'battery', placeholder: '0~100 (default 100)' },\n { type: 'number', label: 'speed', name: 'speed', placeholder: 'units/sec (default 200)' },\n { type: 'string', label: 'tool-type', name: 'toolType', placeholder: 'AMR class (default \"amr\")' },\n { type: 'string', label: 'charging-station-id', name: 'chargingStationId',\n placeholder: 'dispatcher 가 findHolderById 로 조회' },\n { type: 'select', label: 'idle-policy', name: 'idlePolicy',\n property: { options: ['home', 'charging', 'stay', 'patrol'] } },\n { type: 'checkbox', label: 'autonomous-path-planning', name: 'autonomousPathPlanning' }\n ],\n help: 'scene/component/amr'\n}\n\n// Composition — AGV/Forklift 와 동일 chain:\n// FloorBound → Mover → CarrierHolder → ContainerCapacity → Legendable → Placeable → ContainerAbstract\nconst Base = FloorBound(\n Mover(CarrierHolder(ContainerCapacity(Legendable(Placeable(ContainerAbstract)))))\n) as unknown as typeof Component & {\n new (...args: any[]): Component & {\n isCarrierHolder: boolean\n isMover: boolean\n attachPointFor(carrier: Component): CarrierAttachPoint | undefined\n pick(carrier: Component, options?: MoveOptions): Promise<void>\n place(carrier: Component, holder: Component, options?: MoveOptions): Promise<void>\n pickAndPlace(carrier: Component, holder: Component, options?: MoveOptions): Promise<void>\n moveTo(target: Component, options?: MoveOptions): Promise<void>\n canReach(target: any): boolean\n }\n}\n\n/**\n * AMR — Autonomous Mobile Robot.\n *\n * Mover + Navigable. Phase J 의 path planning + reservation 활용해 dynamic path\n * 결정 + multi-mover coordination.\n */\n@sceneComponent('amr')\nexport default class AMR extends Base implements Navigable {\n get nature(): ComponentNature {\n return NATURE\n }\n\n override get state(): AMRState {\n return super.state as AMRState\n }\n\n static legends: Record<string, LegendBinding> = {\n bodyColor: { from: 'status', legend: BODY_LEGEND },\n lampEmissive: { from: 'status', legend: LAMP_EMISSIVE_LEGEND }\n }\n\n buildRealObject() {\n return new AMR3D(this) as any\n }\n\n // ── Phase J: Navigable interface ──────────────────────────────────────\n\n get toolType(): string {\n return (this.state as AMRState).toolType ?? 'amr'\n }\n\n get speedProfile(): SpeedProfile {\n const s = this.state as AMRState\n if (s.speedProfile) return s.speedProfile\n return defaultSpeedProfile(s.speed ?? 200)\n }\n\n /**\n * 경로 계획. NavGraph 가 scene 안 있으면 A* 로 plan. 없으면 null (호출자가\n * Mover.moveTo super 의 직선 path 로 fallback).\n *\n * Phase J 의 planPathAStar 는 *_node id string_* 인자 — AMR 의 current world\n * position 과 target Vec3 를 가장 가까운 node 로 변환.\n *\n * @param target world coords\n * @param options PathPlanOptions\n */\n planPath(target: Vec3, options?: PathPlanOptions): PathPlan | null {\n return navigablePlanPath({\n mover: this,\n target,\n options,\n speedProfile: this.speedProfile,\n gridCellSize: (this.state as any)?.gridCellSize,\n toolType: this.toolType\n })\n }\n\n /**\n * 계획된 경로를 ReservationTable 에 commit. 충돌 시 null — caller (Mover.moveTo\n * override) 가 reroute / 대기 결정.\n */\n reservePath(plan: PathPlan, priority?: number): Reservation[] | null {\n return navigableReservePath(this, plan, priority)\n }\n\n /**\n * commit 된 reservation 따라 sim time 진행. 각 PathPlan segment 의 fromPos → toPos\n * 로 *_Mover.moveTo super_* 위임 (직선 lerp). segment 내부는 직선이므로 super 의\n * distance-based arrival 정확.\n *\n * Note: Reservation 자체 가 fromPos/toPos 없음 — PathPlan 의 PathSegment 가\n * 가짐. 그래서 followReservation 시 PathPlan 도 함께 알아야 — 여기선 last\n * planned PathPlan (this._lastPathPlan) 활용. moveTo override 가 한 번에 plan +\n * reserve + follow 호출하므로 race 없음.\n */\n async followReservation(reservations: Reservation[]): Promise<void> {\n const plan = this._lastPathPlan\n this.setState({ status: 'moving' as AMRStatus })\n if (!plan || plan.segments.length === 0) {\n // PathPlan 없으면 — sim time wait fallback (도착 의미 없는 stub)\n for (const r of reservations) {\n const duration = r.timeWindow.endSimMs - r.timeWindow.startSimMs\n if (duration > 0) await new Promise(resolve => setTimeout(resolve, duration))\n }\n this.releaseReservation(reservations)\n return\n }\n await navigableFollowReservation({\n mover: this,\n plan,\n reservations,\n superMoveTo: (target, options) => super.moveTo(target, options)\n })\n }\n\n /**\n * 점유 해제. 도착 완료 또는 cancel 시 호출.\n */\n releaseReservation(reservations: Reservation[]): void {\n // navigableFollowReservation 이 자동 release. 직접 cancel 시도 시 호출 가능.\n navigableReleaseReservation(reservations)\n }\n\n // ── Mover.moveTo override — Navigable 4 단계 wiring ────────────────────\n\n override async moveTo(target: Component, options?: MoveOptions): Promise<void> {\n const autonomous = (this.state as AMRState).autonomousPathPlanning !== false\n if (!autonomous) {\n // AGV 모드 — 직선\n return super.moveTo(target, options)\n }\n\n // target 의 world position 추출\n const targetPos = resolveTargetWorldPosition(target)\n if (!targetPos) {\n // fallback — super 의 직선\n return super.moveTo(target, options)\n }\n\n this.setState({ status: 'planning' as AMRStatus })\n const plan = this.planPath(targetPos, {\n priority: (options as any)?.priority ?? 0\n })\n if (!plan) {\n // path 발견 실패 — fallback 또는 throw. 현재는 super 의 직선 fallback.\n this._lastPathPlan = null\n this.setState({ status: 'moving' as AMRStatus })\n return super.moveTo(target, options)\n }\n\n // PathPlan 보관 — followReservation 이 segment.toPos 활용\n this._lastPathPlan = plan\n\n const reservations = this.reservePath(plan, (options as any)?.priority ?? 0)\n if (!reservations) {\n // 충돌 — 재시도 또는 대기. 현재는 짧은 대기 후 super fallback.\n this._lastPathPlan = null\n await new Promise(r => setTimeout(r, 500 + Math.random() * 500))\n this.setState({ status: 'moving' as AMRStatus })\n return super.moveTo(target, options)\n }\n\n try {\n await this.followReservation(reservations)\n } finally {\n this._lastPathPlan = null\n }\n this.setState({ status: 'idle' as AMRStatus })\n }\n\n /** moveTo override 가 planPath → followReservation 으로 plan 전달 — race-free. */\n private _lastPathPlan: PathPlan | null = null\n\n // ── AMR-5: Battery drain + 자동 charging ──────────────────────────────\n // ── AMR-6: Idle policy ───────────────────────────────────────────────\n //\n // frameClock subscribe — moving 중 battery drain, idle 시 idle policy 적용.\n // dispatcher.requestTransfer 위임으로 자동 mission (priority 250 charging /\n // 50 idle).\n\n private _tickUnsub?: () => void\n private _chargingMissionEnqueued = false // 한 cycle 만 enqueue\n private _idleMissionEnqueued = false\n private _lastTickSimTime = 0\n\n added(parent: any): void {\n super.added?.(parent)\n this._lastTickSimTime = frameClock.simTime\n this._tickUnsub = frameClock.subscribe((_dt, simTime) => {\n this._tick(simTime)\n }, {\n description: `amr[${(this.state as any).id ?? (this as any).refid}]`,\n component: this as unknown as Component\n })\n }\n\n removed(parent: any): void {\n this._tickUnsub?.()\n this._tickUnsub = undefined\n super.removed?.(parent)\n }\n\n dispose(): void {\n this._tickUnsub?.()\n this._tickUnsub = undefined\n super.dispose?.()\n }\n\n private _tick(simTime: number): void {\n if (!(this as any).app?.isViewMode) return\n\n const dtMs = simTime - this._lastTickSimTime\n this._lastTickSimTime = simTime\n if (dtMs <= 0) return\n\n const s = this.state as AMRState\n const status = s.status ?? 'idle'\n\n // 1. Battery drain — moving / planning / returning 일 때\n if (status === 'moving' || status === 'planning' || status === 'returning') {\n const drainPerMin = s.batteryDrainRate ?? 0.5 // %/min\n const drain = drainPerMin * dtMs / 60000\n const newBattery = Math.max(0, (s.battery ?? 100) - drain)\n if (newBattery !== s.battery) {\n this.setState({ battery: newBattery })\n }\n }\n\n // 2. 자동 charging mission — battery <= threshold + charging station 명시 + 충전 중 아님\n const threshold = s.batteryThreshold ?? 20\n if (\n (s.battery ?? 100) <= threshold &&\n s.chargingStationId &&\n status !== 'charging' && status !== 'returning' &&\n !this._chargingMissionEnqueued\n ) {\n this._chargingMissionEnqueued = true\n this._triggerChargingMission()\n }\n\n // 3. Idle policy — 작업 없을 때 자동 mission\n if (\n status === 'idle' &&\n (s.battery ?? 100) > threshold &&\n !this._idleMissionEnqueued\n ) {\n this._applyIdlePolicy()\n }\n\n // 4. AN-PR-6 — SpeedZone 통과 검사. 현재 위치 가 SpeedZone polygon 안이면\n // state.speed override. 영역 벗어나면 base speed 복원.\n this._applySpeedZoneOverride()\n }\n\n /**\n * AMR 의 현재 위치 가 SpeedZone polygon 안인지 검사 → speed 동적 override.\n *\n * 동작:\n * - scene 의 모든 SpeedZone 컴포넌트 sweep (root._speedZonesCache cache)\n * - AMR.world.position 에 대해 pointInPolygon 검사\n * - 통과 zone 의 *_가장 낮은 speedLimit_* 적용 (보수적)\n * - appliesTo csv 명시 시 — AMR.toolType 일치할 때만\n * - 벗어나면 state._baseSpeed 복원\n */\n private _applySpeedZoneOverride(): void {\n const root: any = (this as any).root\n if (!root) return\n\n // SpeedZone 들 cache\n if (!root._speedZonesCache) {\n const zones: any[] = []\n const visit = (c: any) => {\n if (!c) return\n if (c.state?.type === 'speed-zone' && typeof c.containsPoint === 'function') {\n zones.push(c)\n }\n const ch = c.components\n if (Array.isArray(ch)) for (const cc of ch) visit(cc)\n }\n visit(root)\n root._speedZonesCache = zones\n }\n const zones: any[] = root._speedZonesCache\n if (zones.length === 0) return\n\n // 현재 위치\n const pos = moverCurrentWorldPosition(this)\n if (!pos) return\n\n const myTool = this.toolType\n let minLimit: number | null = null\n for (const z of zones) {\n const zs = z.state\n // appliesTo filter\n const applies = (zs.appliesTo ?? '').trim()\n if (applies.length > 0) {\n const types = applies.split(',').map((t: string) => t.trim())\n if (!types.includes(myTool)) continue\n }\n if (typeof zs.speedLimit !== 'number') continue\n if (!z.containsPoint(pos.x, pos.z)) continue\n if (minLimit === null || zs.speedLimit < minLimit) minLimit = zs.speedLimit\n }\n\n // base speed 보관 (첫 호출 시 set)\n const s = this.state as AMRState\n const anyState = this.state as any\n if (typeof anyState._baseSpeed !== 'number') {\n anyState._baseSpeed = s.speed ?? 200\n }\n const baseSpeed = anyState._baseSpeed as number\n\n const targetSpeed = minLimit !== null ? Math.min(baseSpeed, minLimit) : baseSpeed\n if (s.speed !== targetSpeed) {\n this.setState({ speed: targetSpeed })\n }\n }\n\n private _triggerChargingMission(): void {\n const s = this.state as AMRState\n const stationId = s.chargingStationId\n if (!stationId) {\n this._chargingMissionEnqueued = false\n return\n }\n const dispatcher = findDispatcher(this as any)\n if (!dispatcher) {\n this._chargingMissionEnqueued = false\n return\n }\n\n this.setState({ status: 'returning' as AMRStatus })\n const ticket = dispatcher.requestTransfer({\n // from = AMR 자신 (carrier 처럼 mover 자체를 charging station 으로 이동)\n from: this as any,\n to: stationId,\n priority: 250, // 최고 우선 — 다른 작업 대기\n meta: { kind: 'charging', amrId: (s as any).id }\n })\n // ticket 완료 시점 — placement 가 ChargingStation 안으로 들어감.\n // AMR 의 status 는 charging-station 의 receiveAt 흐름에서 갱신됨.\n ticket.on('status', s2 => {\n if (s2 === 'completed' || s2 === 'failed' || s2 === 'canceled') {\n this._chargingMissionEnqueued = false\n }\n })\n }\n\n private _applyIdlePolicy(): void {\n const s = this.state as AMRState\n const policy = s.idlePolicy ?? 'stay'\n\n switch (policy) {\n case 'stay':\n return // 정지 — 아무것도 안 함\n\n case 'home': {\n if (!s.homePosition) return\n // 이미 home 근처면 skip — 단순 거리 검사\n const pos = moverCurrentWorldPosition(this)\n if (pos && Math.hypot(\n pos.x - s.homePosition.x,\n pos.z - (s.homePosition.z ?? 0)\n ) < 50) return\n this._idleMissionEnqueued = true\n this._enqueueIdleMission({\n x: s.homePosition.x,\n y: s.homePosition.y,\n z: s.homePosition.z ?? 0\n }, 'home')\n return\n }\n\n case 'charging': {\n const stationId = s.chargingStationId\n if (!stationId) return\n this._idleMissionEnqueued = true\n const dispatcher = findDispatcher(this as any)\n if (!dispatcher) {\n this._idleMissionEnqueued = false\n return\n }\n const ticket = dispatcher.requestTransfer({\n from: this as any,\n to: stationId,\n priority: 50, // 낮음 — 명시 작업 우선\n meta: { kind: 'idle-charging', amrId: (s as any).id }\n })\n ticket.on('status', st => {\n if (st === 'completed' || st === 'failed' || st === 'canceled') {\n this._idleMissionEnqueued = false\n }\n })\n return\n }\n\n case 'patrol': {\n // homePosition 또는 미리 등록된 patrol waypoint 사이 순회. 단순 구현 —\n // homePosition 만 활용. 향후 사용자 정책 (state.patrolWaypoints) 확장.\n if (!s.homePosition) return\n this._idleMissionEnqueued = true\n this._enqueueIdleMission({\n x: s.homePosition.x + (Math.random() * 200 - 100),\n y: s.homePosition.y,\n z: (s.homePosition.z ?? 0) + (Math.random() * 200 - 100)\n }, 'patrol')\n return\n }\n }\n }\n\n /** Idle / patrol 목적지로 self-mission. dispatcher 없으면 직접 moveTo. */\n private _enqueueIdleMission(target: Vec3, kind: string): void {\n // Proxy Component 만들어 dispatcher requestTransfer 보냄. dispatcher 의\n // findHolderById 가 없으므로 직접 moveTo proxy 도 OK — 단순.\n // 여기선 직접 moveTo — dispatcher 의 queue 안 거쳐서 자연 idle.\n const proxy = makeSegmentTarget(target)\n this.moveTo(proxy).finally(() => {\n this._idleMissionEnqueued = false\n })\n }\n\n // ── Mover.canReach override — planPath dry-run ────────────────────────\n //\n // `override` 키워드 미사용 — Base 캐스트가 super.canReach 의 generic type 만 노출\n // (TS4113 방지). runtime 위임은 정상.\n\n canReach(target: any): boolean {\n const autonomous = (this.state as AMRState).autonomousPathPlanning !== false\n if (!autonomous) {\n return super.canReach(target) // AGV 모드 — Mover default 위임\n }\n const result = navigableCanReach({\n mover: this,\n target,\n speedProfile: this.speedProfile,\n gridCellSize: (this.state as any)?.gridCellSize,\n toolType: this.toolType\n })\n if (result === null) return super.canReach(target) // NavGraph 없음 — fallback\n return result\n }\n\n // ── Helpers ───────────────────────────────────────────────────────────\n\n // _currentWorldPosition / _resolveComponentWorldPosition — navigable-helpers.ts 의\n // moverCurrentWorldPosition / resolveTargetWorldPosition 활용. 여기서 제거.\n\n /**\n * NavGraph resolve — helpers 의 4-layer fallback 활용.\n */\n private _resolveNavGraph(): NavGraph | null {\n return helpResolveNavGraph(this, this.speedProfile, (this.state as any)?.gridCellSize)\n }\n\n /**\n * 외부 (e.g. Facility / obstacle 변경 시) 명시 cache invalidate. grid + facility\n * 둘 다 무효화. scene event 자동 hook 은 향후 추가.\n */\n static invalidateAutoNavGraph(root: any): void {\n if (root) {\n delete root._autoNavGraph\n delete root._gridNavGraph\n delete root._componentsNavGraph\n delete root._speedZonesCache\n }\n }\n\n private _resolveReservationTable(): ReservationTable {\n // 글로벌 singleton — multi-mover coordination 자연.\n return reservationTable\n }\n\n /**\n * 단일 segment 이동 — fromPos → toPos. 실 visual lerp 는 Mover 의 표준 path\n * 활용 (Component proxy wrap). minimal 은 sim time wait.\n *\n * 향후 AMR-3 에서 정밀화 — segment 내부의 Component proxy + Mover.moveTo super.\n */\n private async _moveAlongSegment(r: Reservation): Promise<void> {\n const duration = r.timeWindow.endSimMs - r.timeWindow.startSimMs\n if (duration <= 0) return\n await new Promise(resolve => setTimeout(resolve, duration))\n }\n}\n"]}
|
|
@@ -16,7 +16,7 @@ export interface ChargingStationState extends State {
|
|
|
16
16
|
material3d?: Material3D;
|
|
17
17
|
}
|
|
18
18
|
export default class ChargingStation extends ContainerAbstract implements SlottedHolder {
|
|
19
|
-
|
|
19
|
+
get nature(): ComponentNature;
|
|
20
20
|
buildRealObject(): RealObject | undefined;
|
|
21
21
|
private _tickUnsub?;
|
|
22
22
|
added(parent: any): void;
|
package/dist/charging-station.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"charging-station.js","sourceRoot":"","sources":["../src/charging-station.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * ChargingStation — AMR / AGV 의 배터리 충전 인프라.\n *\n * 단일 slot SlottedHolder. AMR 이 도착 (place) → 자동 충전 시작. battery 100% 도달\n * 또는 외부 obtain 시 emit. dispatcher 가 충전 임무 자동 관리 (Phase Z).\n *\n * 모델링 의도:\n * - 사용자가 board 에 배치 + id 명시 ('charger-1' 등)\n * - AMR 의 state.chargingStationId 가 이 id 가리킴\n * - AMR 의 battery 부족 시 자동 dispatcher.requestTransfer 로 여기로 mission\n *\n * Charging 동작:\n * - place 시점에 _chargingStartedAt 기록\n * - frameClock tick 으로 battery 갱신 (sim time 기반)\n * - battery >= 100 시 status='ready'\n * - state.chargingRate (units/sec, default 충분히 빠름) 사용자 조정 가능\n */\n\nimport { Component, ComponentNature, ContainerAbstract, sceneComponent } from '@hatiolab/things-scene'\nimport type { State, Material3D } from '@hatiolab/things-scene'\nimport { frameClock } from '@hatiolab/things-scene'\nimport {\n putawayDefault, pickingDefault, putawayAutoDefault, pickingWhereDefault,\n SlotTarget,\n type SlotRecord,\n type SlottedHolder,\n type PutawayOptions, type PickingOptions\n} from '@operato/scene-base'\nimport type { TransferTicket } from '@operato/scene-base'\n\nimport { ChargingStation3D } from './charging-station-3d.js'\n\n/** 단일 slot id 상수. */\nconst SLOT_ID = 'dock'\n\nexport type ChargingStationStatus = 'available' | 'occupied' | 'charging' | 'ready' | 'error'\n\nexport interface ChargingStationState extends State {\n // ── 운영 상태 ──\n status?: ChargingStationStatus\n\n /** 현재 도착한 vehicle 의 record (snapshot). null = 비어있음. */\n occupant?: SlotRecord | null\n /** 충전 시작 시점 (frameClock simTime). */\n _chargingStartedAt?: number\n\n // ── 운영 정책 ──\n /** 충전 속도 — battery % / sim sec. default 1 (=100% 충전에 100 sec). */\n chargingRate?: number\n /** battery >= chargingThreshold 시 ready (default 100). */\n chargingThreshold?: number\n\n // ── 3D 재질 ──\n material3d?: Material3D\n}\n\nconst STATUS_LEGEND: Record<ChargingStationStatus, string> = {\n available: '#88aa88', // green — empty\n occupied: '#aaaa44', // yellow — vehicle 도착\n charging: '#44aa88', // teal — 충전 중\n ready: '#44ff44', // bright green — 완료\n error: '#c66' // red\n}\n\n@sceneComponent('charging-station')\nexport default class ChargingStation extends ContainerAbstract implements SlottedHolder {\n static get nature(): ComponentNature {\n return {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n {\n type: 'select',\n label: 'status',\n name: 'status',\n property: { options: ['available', 'occupied', 'charging', 'ready', 'error'] }\n },\n {\n type: 'number',\n label: 'charging-rate',\n name: 'chargingRate',\n placeholder: '% / sim sec (default 1.0)'\n },\n {\n type: 'number',\n label: 'charging-threshold',\n name: 'chargingThreshold',\n placeholder: 'battery % to mark ready (default 100)'\n }\n ]\n }\n }\n\n buildRealObject(): RealObject | undefined {\n return new ChargingStation3D(this)\n }\n\n // ── Lifecycle: frameClock tick — 충전 진행 ─────────────────────────────\n\n private _tickUnsub?: () => void\n\n added(parent: any): void {\n super.added?.(parent)\n this._tickUnsub = frameClock.subscribe((_dt, simTime) => {\n this._tickCharging(simTime)\n }, {\n description: `charging-station[${(this.state as any).id ?? (this as any).refid}]`,\n component: this\n })\n }\n\n removed(parent: any): void {\n this._tickUnsub?.()\n this._tickUnsub = undefined\n super.removed?.(parent)\n }\n\n dispose(): void {\n this._tickUnsub?.()\n this._tickUnsub = undefined\n super.dispose?.()\n }\n\n private _tickCharging(_simTime: number): void {\n const occupant = (this.state as any).occupant\n if (!occupant) return\n const startedAt = (this.state as any)._chargingStartedAt\n if (typeof startedAt !== 'number') return\n\n const rate = (this.state as any).chargingRate ?? 1.0\n const threshold = (this.state as any).chargingThreshold ?? 100\n const currentBattery = typeof occupant.battery === 'number' ? occupant.battery : 0\n if (currentBattery >= threshold) return // 이미 완료\n\n const elapsedSimSec = (_simTime - startedAt) / 1000\n const expectedBattery = Math.min(threshold, currentBattery + rate * elapsedSimSec)\n\n if (expectedBattery !== currentBattery) {\n const updated = { ...occupant, battery: expectedBattery }\n this.setState({\n occupant: updated,\n status: expectedBattery >= threshold ? 'ready' : 'charging'\n } as any)\n }\n }\n\n // ── SlottedHolder 구현 ─────────────────────────────────────────────────\n\n slotIds(): ReadonlyArray<string> {\n return [SLOT_ID]\n }\n\n hasCarrierAt(slotId: string): boolean {\n if (slotId !== SLOT_ID) return false\n return !!(this.state as any).occupant ||\n ((this as any).components ?? []).some((c: any) => c?.isCarriable || c?.isMover)\n }\n\n canReceiveAt(slotId: string, _carrier?: Component): boolean {\n if (slotId !== SLOT_ID) return false\n return !this.hasCarrierAt(slotId)\n }\n\n obtainCarrier(slotId: string): Component | null {\n if (slotId !== SLOT_ID) return null\n\n // 이미 자식 carrier/mover 있으면 그것 반환 (재진입)\n const existing = ((this as any).components ?? []).find(\n (c: any) => c?.isCarriable || c?.isMover\n )\n if (existing) return existing\n\n // record materialize\n const record = (this.state as any).occupant\n if (!record) return null\n\n const componentType = (record.type as string) || 'amr'\n const ComponentClass = (Component as any).register(componentType) as\n | (new (...args: any[]) => Component) | undefined\n if (!ComponentClass) {\n console.warn(`[charging-station] obtainCarrier: type \"${componentType}\" 미등록`)\n return null\n }\n\n const { id: _id, refid: _refid, transform: _tf, ...recordCopy } = record as any\n const componentState: any = {\n ...recordCopy,\n type: componentType,\n cellId: SLOT_ID,\n left: 0, top: 0,\n width: record.width ?? 100,\n height: record.height ?? 100,\n depth: record.depth ?? 100\n }\n const comp = new ComponentClass(componentState, (this as any)._app)\n ;(this as any).addComponent(comp, { silent: true })\n\n // 충전 종료 — record 제거 + status reset\n this.setState({\n occupant: null,\n status: 'available',\n _chargingStartedAt: undefined\n } as any)\n\n return comp\n }\n\n async receiveAt(slotId: string, vehicle: Component, _options?: any): Promise<void> {\n if (slotId !== SLOT_ID) {\n throw new Error(`ChargingStation.receiveAt: unknown slotId \"${slotId}\"`)\n }\n if (!this.canReceiveAt(slotId, vehicle)) {\n throw new Error('ChargingStation: already occupied')\n }\n const record = this.recordFromCarrier(vehicle, slotId)\n this.setState({\n occupant: record,\n status: 'charging',\n _chargingStartedAt: frameClock.simTime\n } as any)\n ;(vehicle as any).dispose?.()\n }\n\n recordFromCarrier(vehicle: Component, _slotId: string): SlotRecord {\n const s: any = (vehicle as any).state ?? {}\n const { id: _id, refid: _refid, transform: _tf, left: _l, top: _t, ...rest } = s\n return { cellId: SLOT_ID, ...rest }\n }\n\n getSlotAttachObject3d(_slotId: string): any /* THREE.Object3D | undefined */ {\n const ro: any = (this as any)._realObject\n return ro?.object3d\n }\n\n getSlotSize(_slotId: string): { width: number; height: number; depth: number } {\n const s: any = this.state\n return {\n width: s?.width ?? 200,\n height: s?.height ?? 200,\n depth: s?.depth ?? 50\n }\n }\n\n slotTargetAt(_slotId: string): SlotTarget {\n return new SlotTarget(this, SLOT_ID)\n }\n\n occupiedSlotIds(filter?: (slotId: string) => boolean): ReadonlyArray<string> {\n if (!this.hasCarrierAt(SLOT_ID)) return []\n if (filter && !filter(SLOT_ID)) return []\n return [SLOT_ID]\n }\n\n emptySlotIds(filter?: (slotId: string) => boolean): ReadonlyArray<string> {\n if (this.hasCarrierAt(SLOT_ID)) return []\n if (filter && !filter(SLOT_ID)) return []\n return [SLOT_ID]\n }\n\n // ── Phase Z: putaway / picking default 위임 ────────────────────────────\n\n putaway(slotId: string, opts: PutawayOptions): TransferTicket {\n return putawayDefault(this as any, slotId, opts)\n }\n\n picking(slotId: string, opts: PickingOptions): TransferTicket {\n return pickingDefault(this as any, slotId, opts)\n }\n\n putawayAuto(opts: PutawayOptions): TransferTicket {\n return putawayAutoDefault(this as any, opts)\n }\n\n pickingWhere(\n criteria: Record<string, any> | ((record: SlotRecord) => boolean),\n opts: PickingOptions\n ): TransferTicket {\n return pickingWhereDefault(this as any, criteria, opts)\n }\n\n // ── Utility — 현재 충전 진행률 (% / 0~1 normalized) ────────────────────\n\n get chargingProgress(): number | null {\n const occupant = (this.state as any).occupant\n if (!occupant) return null\n const threshold = (this.state as any).chargingThreshold ?? 100\n const current = typeof occupant.battery === 'number' ? occupant.battery : 0\n return Math.min(1, current / threshold)\n }\n}\n\n// RealObject — import at bottom to avoid cyclic. unused yet (just type).\nimport type { RealObject } from '@hatiolab/things-scene'\n"]}
|
|
1
|
+
{"version":3,"file":"charging-station.js","sourceRoot":"","sources":["../src/charging-station.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * ChargingStation — AMR / AGV 의 배터리 충전 인프라.\n *\n * 단일 slot SlottedHolder. AMR 이 도착 (place) → 자동 충전 시작. battery 100% 도달\n * 또는 외부 obtain 시 emit. dispatcher 가 충전 임무 자동 관리 (Phase Z).\n *\n * 모델링 의도:\n * - 사용자가 board 에 배치 + id 명시 ('charger-1' 등)\n * - AMR 의 state.chargingStationId 가 이 id 가리킴\n * - AMR 의 battery 부족 시 자동 dispatcher.requestTransfer 로 여기로 mission\n *\n * Charging 동작:\n * - place 시점에 _chargingStartedAt 기록\n * - frameClock tick 으로 battery 갱신 (sim time 기반)\n * - battery >= 100 시 status='ready'\n * - state.chargingRate (units/sec, default 충분히 빠름) 사용자 조정 가능\n */\n\nimport { Component, ComponentNature, ContainerAbstract, sceneComponent } from '@hatiolab/things-scene'\nimport type { State, Material3D } from '@hatiolab/things-scene'\nimport { frameClock } from '@hatiolab/things-scene'\nimport {\n putawayDefault, pickingDefault, putawayAutoDefault, pickingWhereDefault,\n SlotTarget,\n type SlotRecord,\n type SlottedHolder,\n type PutawayOptions, type PickingOptions\n} from '@operato/scene-base'\nimport type { TransferTicket } from '@operato/scene-base'\n\nimport { ChargingStation3D } from './charging-station-3d.js'\n\n/** 단일 slot id 상수. */\nconst SLOT_ID = 'dock'\n\nexport type ChargingStationStatus = 'available' | 'occupied' | 'charging' | 'ready' | 'error'\n\nexport interface ChargingStationState extends State {\n // ── 운영 상태 ──\n status?: ChargingStationStatus\n\n /** 현재 도착한 vehicle 의 record (snapshot). null = 비어있음. */\n occupant?: SlotRecord | null\n /** 충전 시작 시점 (frameClock simTime). */\n _chargingStartedAt?: number\n\n // ── 운영 정책 ──\n /** 충전 속도 — battery % / sim sec. default 1 (=100% 충전에 100 sec). */\n chargingRate?: number\n /** battery >= chargingThreshold 시 ready (default 100). */\n chargingThreshold?: number\n\n // ── 3D 재질 ──\n material3d?: Material3D\n}\n\nconst STATUS_LEGEND: Record<ChargingStationStatus, string> = {\n available: '#88aa88', // green — empty\n occupied: '#aaaa44', // yellow — vehicle 도착\n charging: '#44aa88', // teal — 충전 중\n ready: '#44ff44', // bright green — 완료\n error: '#c66' // red\n}\n\n@sceneComponent('charging-station')\nexport default class ChargingStation extends ContainerAbstract implements SlottedHolder {\n get nature(): ComponentNature {\n return {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n {\n type: 'select',\n label: 'status',\n name: 'status',\n property: { options: ['available', 'occupied', 'charging', 'ready', 'error'] }\n },\n {\n type: 'number',\n label: 'charging-rate',\n name: 'chargingRate',\n placeholder: '% / sim sec (default 1.0)'\n },\n {\n type: 'number',\n label: 'charging-threshold',\n name: 'chargingThreshold',\n placeholder: 'battery % to mark ready (default 100)'\n }\n ]\n }\n }\n\n buildRealObject(): RealObject | undefined {\n return new ChargingStation3D(this)\n }\n\n // ── Lifecycle: frameClock tick — 충전 진행 ─────────────────────────────\n\n private _tickUnsub?: () => void\n\n added(parent: any): void {\n super.added?.(parent)\n this._tickUnsub = frameClock.subscribe((_dt, simTime) => {\n this._tickCharging(simTime)\n }, {\n description: `charging-station[${(this.state as any).id ?? (this as any).refid}]`,\n component: this\n })\n }\n\n removed(parent: any): void {\n this._tickUnsub?.()\n this._tickUnsub = undefined\n super.removed?.(parent)\n }\n\n dispose(): void {\n this._tickUnsub?.()\n this._tickUnsub = undefined\n super.dispose?.()\n }\n\n private _tickCharging(_simTime: number): void {\n const occupant = (this.state as any).occupant\n if (!occupant) return\n const startedAt = (this.state as any)._chargingStartedAt\n if (typeof startedAt !== 'number') return\n\n const rate = (this.state as any).chargingRate ?? 1.0\n const threshold = (this.state as any).chargingThreshold ?? 100\n const currentBattery = typeof occupant.battery === 'number' ? occupant.battery : 0\n if (currentBattery >= threshold) return // 이미 완료\n\n const elapsedSimSec = (_simTime - startedAt) / 1000\n const expectedBattery = Math.min(threshold, currentBattery + rate * elapsedSimSec)\n\n if (expectedBattery !== currentBattery) {\n const updated = { ...occupant, battery: expectedBattery }\n this.setState({\n occupant: updated,\n status: expectedBattery >= threshold ? 'ready' : 'charging'\n } as any)\n }\n }\n\n // ── SlottedHolder 구현 ─────────────────────────────────────────────────\n\n slotIds(): ReadonlyArray<string> {\n return [SLOT_ID]\n }\n\n hasCarrierAt(slotId: string): boolean {\n if (slotId !== SLOT_ID) return false\n return !!(this.state as any).occupant ||\n ((this as any).components ?? []).some((c: any) => c?.isCarriable || c?.isMover)\n }\n\n canReceiveAt(slotId: string, _carrier?: Component): boolean {\n if (slotId !== SLOT_ID) return false\n return !this.hasCarrierAt(slotId)\n }\n\n obtainCarrier(slotId: string): Component | null {\n if (slotId !== SLOT_ID) return null\n\n // 이미 자식 carrier/mover 있으면 그것 반환 (재진입)\n const existing = ((this as any).components ?? []).find(\n (c: any) => c?.isCarriable || c?.isMover\n )\n if (existing) return existing\n\n // record materialize\n const record = (this.state as any).occupant\n if (!record) return null\n\n const componentType = (record.type as string) || 'amr'\n const ComponentClass = (Component as any).register(componentType) as\n | (new (...args: any[]) => Component) | undefined\n if (!ComponentClass) {\n console.warn(`[charging-station] obtainCarrier: type \"${componentType}\" 미등록`)\n return null\n }\n\n const { id: _id, refid: _refid, transform: _tf, ...recordCopy } = record as any\n const componentState: any = {\n ...recordCopy,\n type: componentType,\n cellId: SLOT_ID,\n left: 0, top: 0,\n width: record.width ?? 100,\n height: record.height ?? 100,\n depth: record.depth ?? 100\n }\n const comp = new ComponentClass(componentState, (this as any)._app)\n ;(this as any).addComponent(comp, { silent: true })\n\n // 충전 종료 — record 제거 + status reset\n this.setState({\n occupant: null,\n status: 'available',\n _chargingStartedAt: undefined\n } as any)\n\n return comp\n }\n\n async receiveAt(slotId: string, vehicle: Component, _options?: any): Promise<void> {\n if (slotId !== SLOT_ID) {\n throw new Error(`ChargingStation.receiveAt: unknown slotId \"${slotId}\"`)\n }\n if (!this.canReceiveAt(slotId, vehicle)) {\n throw new Error('ChargingStation: already occupied')\n }\n const record = this.recordFromCarrier(vehicle, slotId)\n this.setState({\n occupant: record,\n status: 'charging',\n _chargingStartedAt: frameClock.simTime\n } as any)\n ;(vehicle as any).dispose?.()\n }\n\n recordFromCarrier(vehicle: Component, _slotId: string): SlotRecord {\n const s: any = (vehicle as any).state ?? {}\n const { id: _id, refid: _refid, transform: _tf, left: _l, top: _t, ...rest } = s\n return { cellId: SLOT_ID, ...rest }\n }\n\n getSlotAttachObject3d(_slotId: string): any /* THREE.Object3D | undefined */ {\n const ro: any = (this as any)._realObject\n return ro?.object3d\n }\n\n getSlotSize(_slotId: string): { width: number; height: number; depth: number } {\n const s: any = this.state\n return {\n width: s?.width ?? 200,\n height: s?.height ?? 200,\n depth: s?.depth ?? 50\n }\n }\n\n slotTargetAt(_slotId: string): SlotTarget {\n return new SlotTarget(this, SLOT_ID)\n }\n\n occupiedSlotIds(filter?: (slotId: string) => boolean): ReadonlyArray<string> {\n if (!this.hasCarrierAt(SLOT_ID)) return []\n if (filter && !filter(SLOT_ID)) return []\n return [SLOT_ID]\n }\n\n emptySlotIds(filter?: (slotId: string) => boolean): ReadonlyArray<string> {\n if (this.hasCarrierAt(SLOT_ID)) return []\n if (filter && !filter(SLOT_ID)) return []\n return [SLOT_ID]\n }\n\n // ── Phase Z: putaway / picking default 위임 ────────────────────────────\n\n putaway(slotId: string, opts: PutawayOptions): TransferTicket {\n return putawayDefault(this as any, slotId, opts)\n }\n\n picking(slotId: string, opts: PickingOptions): TransferTicket {\n return pickingDefault(this as any, slotId, opts)\n }\n\n putawayAuto(opts: PutawayOptions): TransferTicket {\n return putawayAutoDefault(this as any, opts)\n }\n\n pickingWhere(\n criteria: Record<string, any> | ((record: SlotRecord) => boolean),\n opts: PickingOptions\n ): TransferTicket {\n return pickingWhereDefault(this as any, criteria, opts)\n }\n\n // ── Utility — 현재 충전 진행률 (% / 0~1 normalized) ────────────────────\n\n get chargingProgress(): number | null {\n const occupant = (this.state as any).occupant\n if (!occupant) return null\n const threshold = (this.state as any).chargingThreshold ?? 100\n const current = typeof occupant.battery === 'number' ? occupant.battery : 0\n return Math.min(1, current / threshold)\n }\n}\n\n// RealObject — import at bottom to avoid cyclic. unused yet (just type).\nimport type { RealObject } from '@hatiolab/things-scene'\n"]}
|
package/dist/forbidden-zone.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export interface ForbiddenZoneState extends State {
|
|
|
15
15
|
material3d?: Material3D;
|
|
16
16
|
}
|
|
17
17
|
export default class ForbiddenZone extends PolygonContainer implements Obstacle {
|
|
18
|
-
|
|
18
|
+
get nature(): ComponentNature;
|
|
19
19
|
buildRealObject(): any;
|
|
20
20
|
get isObstacle(): boolean;
|
|
21
21
|
obstaclePolygon(): ObstaclePolygon | null;
|
package/dist/forbidden-zone.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forbidden-zone.js","sourceRoot":"","sources":["../src/forbidden-zone.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;;AAEH,OAAO,EAAmB,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAExE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAGzD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAYpD,MAAM,MAAM,GAAoB;IAC9B,OAAO,EAAE,IAAI;IACb,SAAS,EAAE,KAAK;IAChB,SAAS,EAAE,KAAK;IAChB,UAAU,EAAE;QACV,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW;YACtD,WAAW,EAAE,uCAAuC,EAAE;QACxD,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,cAAc;YAC5D,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,EAAE;KACnD;IACD,IAAI,EAAE,gCAAgC;CACvC,CAAA;AAGc,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,gBAAgB;IACzD,
|
|
1
|
+
{"version":3,"file":"forbidden-zone.js","sourceRoot":"","sources":["../src/forbidden-zone.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;;AAEH,OAAO,EAAmB,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAExE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAGzD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAYpD,MAAM,MAAM,GAAoB;IAC9B,OAAO,EAAE,IAAI;IACb,SAAS,EAAE,KAAK;IAChB,SAAS,EAAE,KAAK;IAChB,UAAU,EAAE;QACV,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW;YACtD,WAAW,EAAE,uCAAuC,EAAE;QACxD,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,cAAc;YAC5D,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,EAAE;KACnD;IACD,IAAI,EAAE,gCAAgC;CACvC,CAAA;AAGc,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,gBAAgB;IACzD,IAAI,MAAM;QACR,OAAO,MAAM,CAAA;IACf,CAAC;IAED,eAAe;QACb,OAAO,IAAI,eAAe,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAQ,CAAA,CAAG,SAAS;IACpE,CAAC;IAED,qEAAqE;IAErE,IAAI,UAAU;QACZ,OAAQ,IAAI,CAAC,KAAa,EAAE,UAAU,KAAK,KAAK,CAAA;IAClD,CAAC;IAED,eAAe;QACb,MAAM,CAAC,GAAG,IAAI,CAAC,KAA2B,CAAA;QAC1C,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAA;QACrB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAA;QAC1D,MAAM,IAAI,GAAI,CAAS,EAAE,IAAI,IAAI,CAAC,CAAA;QAClC,MAAM,GAAG,GAAI,CAAS,EAAE,GAAG,IAAI,CAAC,CAAA;QAChC,MAAM,QAAQ,GAAG,KAAK;aACnB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,EAAE,CAAC,KAAK,QAAQ,CAAC;aACjE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAC9C,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAA;QACpC,OAAO;YACL,QAAQ;YACR,CAAC,EAAG,CAAS,EAAE,IAAI,IAAI,CAAC;YACxB,MAAM,EAAG,CAAS,EAAE,KAAK,IAAI,CAAC;SAC/B,CAAA;IACH,CAAC;IAED,IAAI,YAAY;QACd,OAAO,CAAE,IAAI,CAAC,KAA4B,CAAC,YAAY,IAAI,QAAQ,CAAiB,CAAA;IACtF,CAAC;IAED,IAAI,mBAAmB;QACrB,OAAO,SAAS,CAAA;IAClB,CAAC;CACF,CAAA;AAvCoB,aAAa;IADjC,cAAc,CAAC,gBAAgB,CAAC;GACZ,aAAa,CAuCjC;eAvCoB,aAAa","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * ForbiddenZone — 사용자 명시 *_통과 금지_* polygon 영역.\n *\n * Obstacle 컨트랙 (AN-PR-2) implement — 자동 NavGraph 추론 시 회피 대상. 도메인\n * 컴포넌트 (Rack 등) 가 인지하지 않는 *_가상 장애물_* (사람 통행 영역, 작업 공간\n * 보호 등) 표현.\n *\n * 차별점:\n * - 시각상 polygon (편집 가능)\n * - obstaclePolygon() 정확 반환 (bbox fallback X)\n * - 사용자가 board 에서 직접 그려 — *_grid 자동 추론보다 정밀_*\n */\n\nimport { ComponentNature, sceneComponent } from '@hatiolab/things-scene'\nimport type { State, Material3D } from '@hatiolab/things-scene'\nimport { PolygonContainer } from '@hatiolab/things-scene'\nimport type { Obstacle, ObstaclePolygon, ObstacleType, ObstaclePassability } from '@operato/scene-base'\n\nimport { ZonePlateMesh3D } from './zone-plate-3d.js'\n\nexport interface ForbiddenZoneState extends State {\n type: 'forbidden-zone'\n paths?: Array<{ x: number; y: number }>\n /** Zone 종류 — 향후 confined / safety / human-only 등. 정보 표시 용. */\n zoneClass?: string\n /** Obstacle type — 'static' (정적) / 'temporary'. default 'static'. */\n obstacleType?: ObstacleType\n material3d?: Material3D\n}\n\nconst NATURE: ComponentNature = {\n mutable: true,\n resizable: false,\n rotatable: false,\n properties: [\n { type: 'string', label: 'zone-class', name: 'zoneClass',\n placeholder: 'optional info — safety / human-only 등' },\n { type: 'select', label: 'obstacle-type', name: 'obstacleType',\n property: { options: ['static', 'temporary'] } }\n ],\n help: 'scene/component/forbidden-zone'\n}\n\n@sceneComponent('forbidden-zone')\nexport default class ForbiddenZone extends PolygonContainer implements Obstacle {\n get nature(): ComponentNature {\n return NATURE\n }\n\n buildRealObject() {\n return new ZonePlateMesh3D(this, 0xff4444, 0.3) as any // 빨강 반투명\n }\n\n // ── Obstacle 컨트랙 ──────────────────────────────────────────────────\n\n get isObstacle(): boolean {\n return (this.state as any)?.isObstacle !== false\n }\n\n obstaclePolygon(): ObstaclePolygon | null {\n const s = this.state as ForbiddenZoneState\n const paths = s.paths\n if (!Array.isArray(paths) || paths.length < 3) return null\n const left = (s as any)?.left ?? 0\n const top = (s as any)?.top ?? 0\n const vertices = paths\n .filter(p => typeof p?.x === 'number' && typeof p?.y === 'number')\n .map(p => ({ x: left + p.x, z: top + p.y }))\n if (vertices.length < 3) return null\n return {\n vertices,\n y: (s as any)?.zPos ?? 0,\n height: (s as any)?.depth ?? 0\n }\n }\n\n get obstacleType(): ObstacleType {\n return ((this.state as ForbiddenZoneState).obstacleType ?? 'static') as ObstacleType\n }\n\n get obstaclePassability(): ObstaclePassability {\n return 'blocked'\n }\n}\n"]}
|
package/dist/intersection.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export interface IntersectionState extends State {
|
|
|
13
13
|
material3d?: Material3D;
|
|
14
14
|
}
|
|
15
15
|
export default class Intersection extends ContainerAbstract {
|
|
16
|
-
|
|
16
|
+
get nature(): ComponentNature;
|
|
17
17
|
buildRealObject(): any;
|
|
18
18
|
/**
|
|
19
19
|
* Phase J 의 Intersection interface 로 변환.
|
package/dist/intersection.js
CHANGED
package/dist/intersection.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intersection.js","sourceRoot":"","sources":["../src/intersection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;;AAEH,OAAO,EAA8B,iBAAiB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAGtG,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAgBrD,MAAM,MAAM,GAAoB;IAC9B,OAAO,EAAE,KAAK;IACd,SAAS,EAAE,IAAI;IACf,SAAS,EAAE,KAAK;IAChB,UAAU,EAAE;QACV,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE;QACvF,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,gBAAgB,EAAE,WAAW,EAAE,sBAAsB,EAAE;QACvG;YACE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW;YACtD,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,YAAY,CAAC,EAAE;SAC1D;KACF;IACD,IAAI,EAAE,8BAA8B;CACrC,CAAA;AAGc,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,iBAAiB;IACzD,
|
|
1
|
+
{"version":3,"file":"intersection.js","sourceRoot":"","sources":["../src/intersection.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * Intersection — Lane 들의 분기점. Phase J 의 Intersection interface 매핑.\n *\n * 모델링:\n * - 사용자가 board 에 Intersection point 배치\n * - state.lanes: csv ('laneA,laneB,laneC') — 만나는 Lane id 목록\n * - state.crossingTimeMs: 통과 시간\n * - state.conflicts (선택): 충돌 pair + resolve policy\n *\n * 자동 conflict 추론:\n * - state.conflicts 미명시 시 — 모든 pair 가 fifo 로 충돌 (보수적 default)\n */\n\nimport { Component, ComponentNature, ContainerAbstract, sceneComponent } from '@hatiolab/things-scene'\nimport type { State, Material3D } from '@hatiolab/things-scene'\n\nimport { Intersection3D } from './intersection-3d.js'\n\nexport interface IntersectionState extends State {\n type: 'intersection'\n /** 만나는 Lane id 의 csv. */\n lanes?: string\n /** 통과 시간 (sim ms). default 500. */\n crossingTimeMs?: number\n /** Conflict spec — JSON 또는 csv. 향후 정밀 표현 시 확장. */\n conflicts?: any\n /** 우선순위 정책. */\n resolveBy?: 'fifo' | 'priority' | 'roundrobin'\n\n material3d?: Material3D\n}\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: false,\n properties: [\n { type: 'string', label: 'lanes-csv', name: 'lanes', placeholder: 'laneA,laneB,laneC' },\n { type: 'number', label: 'crossing-time', name: 'crossingTimeMs', placeholder: 'sim ms (default 500)' },\n {\n type: 'select', label: 'resolve-by', name: 'resolveBy',\n property: { options: ['fifo', 'priority', 'roundrobin'] }\n }\n ],\n help: 'scene/component/intersection'\n}\n\n@sceneComponent('intersection')\nexport default class Intersection extends ContainerAbstract {\n get nature(): ComponentNature {\n return NATURE\n }\n\n buildRealObject() {\n return new Intersection3D(this) as any\n }\n\n /**\n * Phase J 의 Intersection interface 로 변환.\n *\n * `state.conflicts` 미명시 시 — 모든 lane pair 가 conflict 로 간주\n * (보수적 default).\n */\n toIntersectionSpec(): {\n id: string\n lanes: string[]\n conflicts: Array<{ fromLane: string; toLane: string; resolveBy: 'fifo' | 'priority' | 'roundrobin' }>\n crossingTimeMs: number\n } | null {\n const s = this.state as IntersectionState\n const lanesCsv = (s.lanes ?? '').trim()\n if (lanesCsv.length === 0) return null\n const lanes = lanesCsv.split(',').map(t => t.trim()).filter(Boolean)\n if (lanes.length < 2) return null\n\n const resolveBy = s.resolveBy ?? 'fifo'\n // Default — 모든 pair conflict\n const conflicts: Array<{ fromLane: string; toLane: string; resolveBy: 'fifo' | 'priority' | 'roundrobin' }> = []\n if (Array.isArray(s.conflicts)) {\n for (const c of s.conflicts) {\n if (c?.fromLane && c?.toLane) {\n conflicts.push({\n fromLane: String(c.fromLane),\n toLane: String(c.toLane),\n resolveBy: c.resolveBy ?? resolveBy\n })\n }\n }\n } else {\n for (let i = 0; i < lanes.length; i++) {\n for (let j = 0; j < lanes.length; j++) {\n if (i === j) continue\n conflicts.push({ fromLane: lanes[i], toLane: lanes[j], resolveBy })\n }\n }\n }\n\n return {\n id: String((s as any).id ?? `int-${(this as any).refid ?? 'unknown'}`),\n lanes,\n conflicts,\n crossingTimeMs: s.crossingTimeMs ?? 500\n }\n }\n\n get isObstacle(): boolean {\n return false\n }\n}\n"]}
|
package/dist/lane.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export interface LaneState extends State {
|
|
|
22
22
|
material3d?: Material3D;
|
|
23
23
|
}
|
|
24
24
|
export default class Lane extends PolygonContainer {
|
|
25
|
-
|
|
25
|
+
get nature(): ComponentNature;
|
|
26
26
|
buildRealObject(): any;
|
|
27
27
|
/**
|
|
28
28
|
* Phase J 의 Lane interface 로 변환. nav-graph-from-components 가 호출.
|
package/dist/lane.js
CHANGED
package/dist/lane.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lane.js","sourceRoot":"","sources":["../src/lane.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;AAEH,OAAO,EAA8B,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAEnF,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAEzD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAqBrC,MAAM,MAAM,GAAoB;IAC9B,OAAO,EAAE,IAAI;IACb,SAAS,EAAE,KAAK;IAChB,SAAS,EAAE,KAAK;IAChB,UAAU,EAAE;QACV;YACE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW;YACtD,WAAW,EAAE,0BAA0B;SACxC;QACD;YACE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW;YACrD,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE;SAC5C;QACD;YACE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY;YACxD,WAAW,EAAE,gCAAgC;SAC9C;QACD;YACE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,kBAAkB;YAChE,WAAW,EAAE,yCAAyC;SACvD;QACD;YACE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU;YACnD,WAAW,EAAE,mCAAmC;SACjD;KACF;IACD,IAAI,EAAE,sBAAsB;CAC7B,CAAA;AAGc,IAAM,IAAI,GAAV,MAAM,IAAK,SAAQ,gBAAgB;IAChD,
|
|
1
|
+
{"version":3,"file":"lane.js","sourceRoot":"","sources":["../src/lane.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * Lane — 사용자가 board editor 에 *_명시 path_* 그리는 컴포넌트.\n *\n * polyline 형태 — paths 의 vertex 들이 lane 의 centerPoints. 사용자가 dragdrop\n * 또는 path edit 으로 그릴 수 있음. AN-PR-4 의 핵심.\n *\n * Phase J 의 `Lane` interface 와 직접 매핑:\n * - geometry.centerPoints = state.paths (2D → 3D 변환)\n * - geometry.width = state.laneWidth\n * - direction = state.direction ('oneway' | 'twoway')\n * - speedLimit = state.speedLimit\n * - allowedToolTypes = state.allowedToolTypes (csv)\n * - capacity = state.capacity\n *\n * NavGraph 통합 (nav-graph-from-components.ts):\n * scene 의 모든 Lane 컴포넌트 → Phase J 의 buildNavGraph(lanes, intersections)\n * 호출 → A* 가능한 NavGraph.\n */\n\nimport { Component, ComponentNature, sceneComponent } from '@hatiolab/things-scene'\nimport type { State, Material3D } from '@hatiolab/things-scene'\nimport { PolygonContainer } from '@hatiolab/things-scene'\n\nimport { Lane3D } from './lane-3d.js'\n\nexport interface LaneState extends State {\n type: 'lane'\n /** Polyline 좌표 — center points. */\n paths?: Array<{ x: number; y: number }>\n /** Lane 폭 (scene unit). vehicle 이 이 안에 들어가야 함. default 200. */\n laneWidth?: number\n /** Direction. */\n direction?: 'oneway' | 'twoway'\n /** Speed limit (units/sec). undefined = 무제한. */\n speedLimit?: number\n /** 허용 vehicle toolType. csv (e.g. 'amr,forklift'). 빈 string = 모두. */\n allowedToolTypes?: string\n /** 동시 capacity. 1 = single occupancy queue. default 1. */\n capacity?: number\n\n /** 3D 재질 */\n material3d?: Material3D\n}\n\nconst NATURE: ComponentNature = {\n mutable: true,\n resizable: false,\n rotatable: false,\n properties: [\n {\n type: 'number', label: 'lane-width', name: 'laneWidth',\n placeholder: 'scene unit (default 200)'\n },\n {\n type: 'select', label: 'direction', name: 'direction',\n property: { options: ['oneway', 'twoway'] }\n },\n {\n type: 'number', label: 'speed-limit', name: 'speedLimit',\n placeholder: 'units/sec (unspec = unlimited)'\n },\n {\n type: 'string', label: 'allowed-types', name: 'allowedToolTypes',\n placeholder: 'csv (e.g. \"amr,forklift\") — 빈 값 = 모두 허용'\n },\n {\n type: 'number', label: 'capacity', name: 'capacity',\n placeholder: 'simultaneous vehicles (default 1)'\n }\n ],\n help: 'scene/component/lane'\n}\n\n@sceneComponent('lane')\nexport default class Lane extends PolygonContainer {\n get nature(): ComponentNature {\n return NATURE\n }\n\n buildRealObject() {\n return new Lane3D(this) as any\n }\n\n // ── Phase J Lane interface 매핑 ───────────────────────────────────────\n\n /**\n * Phase J 의 Lane interface 로 변환. nav-graph-from-components 가 호출.\n */\n toLaneSpec(): {\n id: string\n geometry: { centerPoints: Array<{ x: number; y: number; z: number }>; width: number }\n direction: 'oneway' | 'twoway'\n speedLimit?: number\n allowedToolTypes?: string[]\n capacity: number\n } | null {\n const s = this.state as LaneState\n const paths = s.paths\n if (!Array.isArray(paths) || paths.length < 2) return null\n\n const left = (s as any).left ?? 0\n const top = (s as any).top ?? 0\n const y = (s as any).zPos ?? 0\n // 2D (x, y) → 3D (x, y, z) — 2D y axis = 3D z.\n const centerPoints = paths\n .filter(p => typeof p?.x === 'number' && typeof p?.y === 'number')\n .map(p => ({ x: left + p.x, y, z: top + p.y }))\n if (centerPoints.length < 2) return null\n\n const allowedRaw = (s.allowedToolTypes ?? '').trim()\n const allowedToolTypes = allowedRaw.length > 0\n ? allowedRaw.split(',').map(t => t.trim()).filter(Boolean)\n : undefined\n\n return {\n id: String((s as any).id ?? `lane-${(this as any).refid ?? 'unknown'}`),\n geometry: {\n centerPoints,\n width: s.laneWidth ?? 200\n },\n direction: s.direction ?? 'twoway',\n speedLimit: s.speedLimit,\n allowedToolTypes,\n capacity: s.capacity ?? 1\n }\n }\n\n /**\n * Lane 자체 는 obstacle 아님 — 통과 가능. isObstacle 명시 false. (default 가\n * obstacle 자격 없음 — getter 미존재. 명시 표기 위함.)\n */\n get isObstacle(): boolean {\n return false\n }\n}\n"]}
|
package/dist/nav-zone.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export interface NavZoneState extends State {
|
|
|
14
14
|
material3d?: Material3D;
|
|
15
15
|
}
|
|
16
16
|
export default class NavZone extends PolygonContainer {
|
|
17
|
-
|
|
17
|
+
get nature(): ComponentNature;
|
|
18
18
|
buildRealObject(): any;
|
|
19
19
|
/**
|
|
20
20
|
* Phase J 의 OpenZone interface 로 변환.
|
package/dist/nav-zone.js
CHANGED
package/dist/nav-zone.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nav-zone.js","sourceRoot":"","sources":["../src/nav-zone.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;AAEH,OAAO,EAAmB,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAExE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAEzD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAYpD,MAAM,MAAM,GAAoB;IAC9B,OAAO,EAAE,IAAI;IACb,SAAS,EAAE,KAAK;IAChB,SAAS,EAAE,KAAK;IAChB,UAAU,EAAE;QACV,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU;YACpD,WAAW,EAAE,0BAA0B,EAAE;QAC3C,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE,gBAAgB;YAChE,WAAW,EAAE,wCAAwC,EAAE;KAC1D;IACD,IAAI,EAAE,0BAA0B;CACjC,CAAA;AAGc,IAAM,OAAO,GAAb,MAAM,OAAQ,SAAQ,gBAAgB;IACnD,
|
|
1
|
+
{"version":3,"file":"nav-zone.js","sourceRoot":"","sources":["../src/nav-zone.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;AAEH,OAAO,EAAmB,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAExE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAEzD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAYpD,MAAM,MAAM,GAAoB;IAC9B,OAAO,EAAE,IAAI;IACb,SAAS,EAAE,KAAK;IAChB,SAAS,EAAE,KAAK;IAChB,UAAU,EAAE;QACV,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU;YACpD,WAAW,EAAE,0BAA0B,EAAE;QAC3C,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE,gBAAgB;YAChE,WAAW,EAAE,wCAAwC,EAAE;KAC1D;IACD,IAAI,EAAE,0BAA0B;CACjC,CAAA;AAGc,IAAM,OAAO,GAAb,MAAM,OAAQ,SAAQ,gBAAgB;IACnD,IAAI,MAAM;QACR,OAAO,MAAM,CAAA;IACf,CAAC;IAED,eAAe;QACb,OAAO,IAAI,eAAe,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAQ,CAAA,CAAG,SAAS;IACpE,CAAC;IAED;;OAEG;IACH,cAAc;QAKZ,MAAM,CAAC,GAAG,IAAI,CAAC,KAAqB,CAAA;QACpC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAA;QACrB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAA;QAC1D,MAAM,IAAI,GAAI,CAAS,EAAE,IAAI,IAAI,CAAC,CAAA;QAClC,MAAM,GAAG,GAAI,CAAS,EAAE,GAAG,IAAI,CAAC,CAAA;QAChC,MAAM,CAAC,GAAI,CAAS,EAAE,IAAI,IAAI,CAAC,CAAA;QAC/B,MAAM,QAAQ,GAAG,KAAK;aACnB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,EAAE,CAAC,KAAK,QAAQ,CAAC;aACjE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACjD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAA;QACpC,OAAO;YACL,EAAE,EAAE,MAAM,CAAE,CAAS,CAAC,EAAE,IAAI,WAAY,IAAY,CAAC,KAAK,IAAI,SAAS,EAAE,CAAC;YAC1E,QAAQ,EAAE,EAAE,QAAQ,EAAE;YACtB,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,GAAG;SAC5B,CAAA;IACH,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,KAAK,CAAA,CAAG,QAAQ;IACzB,CAAC;CACF,CAAA;AArCoB,OAAO;IAD3B,cAAc,CAAC,UAAU,CAAC;GACN,OAAO,CAqC3B;eArCoB,OAAO","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * NavZone — 사용자 명시 *_자유 이동 영역_* polygon.\n *\n * Phase J 의 OpenZone interface 매핑. lane / waypoint 로 표현 어려운 open\n * warehouse floor / dock plaza / cross-floor 영역. 시공간 격자로 점유권 관리.\n *\n * 사용 의도:\n * - 큰 open space 의 path 자동 추론 (grid 보다 정밀한 사용자 정의 영역)\n * - obstacle 아님 — Mover 가 자유 이동\n * - 향후: cell 단위 reservation (cellSize 명시)\n *\n * 자동 NavGraph 와의 통합:\n * - NavZone polygon 안 — *_grid cell 자동 free_* 표시 (obstacle scan 의 보조)\n * - 또는 NavZone 자체의 내부 grid → NavNode 자동 생성\n *\n * Layer:\n * - NavGraph cost 가중 (선택) — 사용자 선호 영역 cost 감소.\n */\n\nimport { ComponentNature, sceneComponent } from '@hatiolab/things-scene'\nimport type { State, Material3D } from '@hatiolab/things-scene'\nimport { PolygonContainer } from '@hatiolab/things-scene'\n\nimport { ZonePlateMesh3D } from './zone-plate-3d.js'\n\nexport interface NavZoneState extends State {\n type: 'nav-zone'\n paths?: Array<{ x: number; y: number }>\n /** Phase J OpenZone.cellSize — 점유 격자 cell 한 변. default 200. */\n cellSize?: number\n /** Cost 가중 — 1.0 = neutral, < 1.0 = 선호 (cost 감소), > 1.0 = 회피. default 1.0. */\n costMultiplier?: number\n material3d?: Material3D\n}\n\nconst NATURE: ComponentNature = {\n mutable: true,\n resizable: false,\n rotatable: false,\n properties: [\n { type: 'number', label: 'cell-size', name: 'cellSize',\n placeholder: 'scene unit (default 200)' },\n { type: 'number', label: 'cost-multiplier', name: 'costMultiplier',\n placeholder: '1.0 neutral / <1.0 prefer / >1.0 avoid' }\n ],\n help: 'scene/component/nav-zone'\n}\n\n@sceneComponent('nav-zone')\nexport default class NavZone extends PolygonContainer {\n get nature(): ComponentNature {\n return NATURE\n }\n\n buildRealObject() {\n return new ZonePlateMesh3D(this, 0x44ff88, 0.2) as any // 녹색 반투명\n }\n\n /**\n * Phase J 의 OpenZone interface 로 변환.\n */\n toOpenZoneSpec(): {\n id: string\n boundary: { vertices: Array<{ x: number; y: number; z: number }> }\n cellSize: number\n } | null {\n const s = this.state as NavZoneState\n const paths = s.paths\n if (!Array.isArray(paths) || paths.length < 3) return null\n const left = (s as any)?.left ?? 0\n const top = (s as any)?.top ?? 0\n const y = (s as any)?.zPos ?? 0\n const vertices = paths\n .filter(p => typeof p?.x === 'number' && typeof p?.y === 'number')\n .map(p => ({ x: left + p.x, y, z: top + p.y }))\n if (vertices.length < 3) return null\n return {\n id: String((s as any).id ?? `navzone-${(this as any).refid ?? 'unknown'}`),\n boundary: { vertices },\n cellSize: s.cellSize ?? 200\n }\n }\n\n get isObstacle(): boolean {\n return false // 통과 가능\n }\n}\n"]}
|
package/dist/speed-zone.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export interface SpeedZoneState extends State {
|
|
|
15
15
|
material3d?: Material3D;
|
|
16
16
|
}
|
|
17
17
|
export default class SpeedZone extends PolygonContainer {
|
|
18
|
-
|
|
18
|
+
get nature(): ComponentNature;
|
|
19
19
|
buildRealObject(): any;
|
|
20
20
|
/**
|
|
21
21
|
* 점 (x, z) 가 이 zone polygon 안인가. AMR 의 segment 통과 검사 helper.
|
package/dist/speed-zone.js
CHANGED
package/dist/speed-zone.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"speed-zone.js","sourceRoot":"","sources":["../src/speed-zone.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;AAEH,OAAO,EAAmB,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAExE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAEzD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEnD,gCAAgC;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAYnD,MAAM,MAAM,GAAoB;IAC9B,OAAO,EAAE,IAAI;IACb,SAAS,EAAE,KAAK;IAChB,SAAS,EAAE,KAAK;IAChB,UAAU,EAAE;QACV,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY;YACxD,WAAW,EAAE,kCAAkC,EAAE;QACnD,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW;YACtD,WAAW,EAAE,+CAA+C,EAAE;KACjE;IACD,IAAI,EAAE,4BAA4B;CACnC,CAAA;AAGc,IAAM,SAAS,GAAf,MAAM,SAAU,SAAQ,gBAAgB;IACrD,
|
|
1
|
+
{"version":3,"file":"speed-zone.js","sourceRoot":"","sources":["../src/speed-zone.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * SpeedZone — 사용자 명시 *_속도 제한 영역_* polygon.\n *\n * Mover (AMR / AGV) 가 polygon 안 통과 시 *_state.speed 또는 speedProfile.max_*\n * override. 안전 영역 (사람 통행), 정밀 조작 영역 (워크스테이션 근처), 교차로\n * approach 등.\n *\n * 통합 path (향후):\n * - AMR 의 _moveAlongSegment 가 segment 위치 → SpeedZone polygon 통과 검사 →\n * 해당 cell 의 duration 조정\n * - 또는 NavGraph edge 의 durationMs 가중 (SpeedZone 통과 cell 의 edge 가\n * speedLimit 따라 자동 길어짐)\n *\n * 현재 PR 의 scope:\n * - 컴포넌트 + 3D\n * - toSpeedZoneSpec() 변환\n * - mover 가 이 영역 안에 있는지 검사 helper (pointInPolygon)\n * - 실 mover 의 speed override 동작 wiring 은 향후 (AN-PR-6 의 일부)\n */\n\nimport { ComponentNature, sceneComponent } from '@hatiolab/things-scene'\nimport type { State, Material3D } from '@hatiolab/things-scene'\nimport { PolygonContainer } from '@hatiolab/things-scene'\n\nimport { ZonePlateMesh3D } from './zone-plate-3d.js'\nimport { pointInPolygon } from './polygon-utils.js'\n\n// Re-export for backward compat\nexport { pointInPolygon } from './polygon-utils.js'\n\nexport interface SpeedZoneState extends State {\n type: 'speed-zone'\n paths?: Array<{ x: number; y: number }>\n /** 속도 제한 (units/sec). undefined → 적용 안 함. */\n speedLimit?: number\n /** 적용 대상 mover toolType csv. 빈 string → 모두. */\n appliesTo?: string\n material3d?: Material3D\n}\n\nconst NATURE: ComponentNature = {\n mutable: true,\n resizable: false,\n rotatable: false,\n properties: [\n { type: 'number', label: 'speed-limit', name: 'speedLimit',\n placeholder: 'units/sec (mover speed override)' },\n { type: 'string', label: 'applies-to', name: 'appliesTo',\n placeholder: 'csv toolType (e.g. \"amr,forklift\") — 빈 값 = 모두' }\n ],\n help: 'scene/component/speed-zone'\n}\n\n@sceneComponent('speed-zone')\nexport default class SpeedZone extends PolygonContainer {\n get nature(): ComponentNature {\n return NATURE\n }\n\n buildRealObject() {\n return new ZonePlateMesh3D(this, 0xffaa22, 0.25) as any // 주황 반투명\n }\n\n /**\n * 점 (x, z) 가 이 zone polygon 안인가. AMR 의 segment 통과 검사 helper.\n * Ray casting algorithm.\n */\n containsPoint(x: number, z: number): boolean {\n const s = this.state as SpeedZoneState\n const paths = s.paths\n if (!Array.isArray(paths) || paths.length < 3) return false\n const left = (s as any)?.left ?? 0\n const top = (s as any)?.top ?? 0\n const vertices = paths\n .filter(p => typeof p?.x === 'number' && typeof p?.y === 'number')\n .map(p => ({ x: left + p.x, z: top + p.y }))\n return pointInPolygon(x, z, vertices)\n }\n\n toSpeedZoneSpec(): {\n id: string\n polygon: Array<{ x: number; z: number }>\n speedLimit?: number\n appliesTo?: string[]\n } | null {\n const s = this.state as SpeedZoneState\n const paths = s.paths\n if (!Array.isArray(paths) || paths.length < 3) return null\n const left = (s as any)?.left ?? 0\n const top = (s as any)?.top ?? 0\n const vertices = paths\n .filter(p => typeof p?.x === 'number' && typeof p?.y === 'number')\n .map(p => ({ x: left + p.x, z: top + p.y }))\n if (vertices.length < 3) return null\n\n const appliesRaw = (s.appliesTo ?? '').trim()\n const appliesTo = appliesRaw.length > 0\n ? appliesRaw.split(',').map(t => t.trim()).filter(Boolean)\n : undefined\n\n return {\n id: String((s as any).id ?? `speedzone-${(this as any).refid ?? 'unknown'}`),\n polygon: vertices,\n speedLimit: s.speedLimit,\n appliesTo\n }\n }\n\n get isObstacle(): boolean {\n return false // 통과 가능 — 단지 속도 제한\n }\n}\n\n// pointInPolygon 은 polygon-utils.ts 에서 정의 — pure logic 격리 (test 환경).\n// 위쪽 re-export 활용.\n"]}
|