vehicle-path2 2.2.0 → 2.3.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.
@@ -186,7 +186,12 @@ export type { VehicleMovementState as SegmentVehicleState };
186
186
  * Advance semua axle vehicle oleh `distance` sepanjang path.
187
187
  *
188
188
  * Ini adalah low-level tick primitive. Update semua axle menggunakan
189
- * arc-length parameterization. Arrival = axles[0] (terdepan) mencapai ujung path.
189
+ * arc-length parameterization. Arrival = axles[N-1] (rearmost) mencapai ujung path.
190
+ *
191
+ * Semantik: path dibuat dari posisi rear axle ke targetOffset. Sehingga
192
+ * `arrived=true` berarti rear axle telah mencapai targetOffset — bukan
193
+ * front axle mencapai ujung segmennya. Front axle tetap bisa "hang over"
194
+ * di luar batas path (di ujung line) via maxOffset.
190
195
  *
191
196
  * @param axleStates - Array AxleState saat ini, axles[0] = terdepan
192
197
  * @param axleExecutions - Array AxleExecutionState sesuai urutan axleStates
package/dist/core.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-DA33ne3M.cjs");function o(r,n,t){const a={lines:r,curves:n.map(i=>({id:i.id,fromLineId:i.fromLineId,toLineId:i.toLineId,fromOffset:i.fromOffset,fromIsPercentage:i.fromIsPercentage??!1,toOffset:i.toOffset,toIsPercentage:i.toIsPercentage??!1})),vehicles:t.map(i=>({id:i.id,lineId:i.axles[0].lineId,axles:i.axles.map(l=>({offset:l.offset})),axleSpacings:i.axleSpacings,isPercentage:i.isPercentage??!1}))};return JSON.stringify(a,null,2)}function s(r){let n;try{n=JSON.parse(r)}catch{throw new Error("deserializeScene: invalid JSON")}if(!n||typeof n!="object"||Array.isArray(n))throw new Error("deserializeScene: expected a JSON object");const t=n;if(!Array.isArray(t.lines))throw new Error('deserializeScene: missing "lines"');if(!Array.isArray(t.curves))throw new Error('deserializeScene: missing "curves"');if(!Array.isArray(t.vehicles))throw new Error('deserializeScene: missing "vehicles"');return{lines:t.lines,curves:t.curves,vehicles:t.vehicles}}exports.PathEngine=e.PathEngine;exports.arcLengthToSegmentPosition=e.arcLengthToSegmentPosition;exports.buildArcLengthTable=e.buildArcLengthTable;exports.buildGraph=e.buildGraph;exports.calculateBezierArcLength=e.calculateBezierArcLength;exports.calculateFrontAxlePosition=e.calculateFrontAxlePosition;exports.calculateInitialAxlePositions=e.calculateInitialAxlePositions;exports.calculatePositionOnCurve=e.calculatePositionOnCurve;exports.calculatePositionOnLine=e.calculatePositionOnLine;exports.calculateTangentLength=e.calculateTangentLength;exports.createBezierCurve=e.createBezierCurve;exports.createInitialMovementState=e.createInitialMovementState;exports.distance=e.distance;exports.distanceToT=e.distanceToT;exports.findPath=e.findPath;exports.getArcLength=e.getArcLength;exports.getCumulativeArcLength=e.getCumulativeArcLength;exports.getLineLength=e.getLineLength;exports.getPointOnBezier=e.getPointOnBezier;exports.getPointOnLine=e.getPointOnLine;exports.getPointOnLineByOffset=e.getPointOnLineByOffset;exports.getPositionFromOffset=e.getPositionFromOffset;exports.handleArrival=e.handleArrival;exports.initializeAllVehicles=e.initializeAllVehicles;exports.initializeMovingVehicle=e.initializeMovingVehicle;exports.isPointNearPoint=e.isPointNearPoint;exports.moveVehicle=e.moveVehicle;exports.normalize=e.normalize;exports.prepareCommandPath=e.prepareCommandPath;exports.resolveFromLineOffset=e.resolveFromLineOffset;exports.resolveToLineOffset=e.resolveToLineOffset;exports.updateAxlePosition=e.updateAxlePosition;exports.deserializeScene=s;exports.serializeScene=o;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-BUYdltrL.cjs");function o(r,n,t){const a={lines:r,curves:n.map(i=>({id:i.id,fromLineId:i.fromLineId,toLineId:i.toLineId,fromOffset:i.fromOffset,fromIsPercentage:i.fromIsPercentage??!1,toOffset:i.toOffset,toIsPercentage:i.toIsPercentage??!1})),vehicles:t.map(i=>({id:i.id,lineId:i.axles[0].lineId,axles:i.axles.map(l=>({offset:l.offset})),axleSpacings:i.axleSpacings,isPercentage:i.isPercentage??!1}))};return JSON.stringify(a,null,2)}function s(r){let n;try{n=JSON.parse(r)}catch{throw new Error("deserializeScene: invalid JSON")}if(!n||typeof n!="object"||Array.isArray(n))throw new Error("deserializeScene: expected a JSON object");const t=n;if(!Array.isArray(t.lines))throw new Error('deserializeScene: missing "lines"');if(!Array.isArray(t.curves))throw new Error('deserializeScene: missing "curves"');if(!Array.isArray(t.vehicles))throw new Error('deserializeScene: missing "vehicles"');return{lines:t.lines,curves:t.curves,vehicles:t.vehicles}}exports.PathEngine=e.PathEngine;exports.arcLengthToSegmentPosition=e.arcLengthToSegmentPosition;exports.buildArcLengthTable=e.buildArcLengthTable;exports.buildGraph=e.buildGraph;exports.calculateBezierArcLength=e.calculateBezierArcLength;exports.calculateFrontAxlePosition=e.calculateFrontAxlePosition;exports.calculateInitialAxlePositions=e.calculateInitialAxlePositions;exports.calculatePositionOnCurve=e.calculatePositionOnCurve;exports.calculatePositionOnLine=e.calculatePositionOnLine;exports.calculateTangentLength=e.calculateTangentLength;exports.createBezierCurve=e.createBezierCurve;exports.createInitialMovementState=e.createInitialMovementState;exports.distance=e.distance;exports.distanceToT=e.distanceToT;exports.findPath=e.findPath;exports.getArcLength=e.getArcLength;exports.getCumulativeArcLength=e.getCumulativeArcLength;exports.getLineLength=e.getLineLength;exports.getPointOnBezier=e.getPointOnBezier;exports.getPointOnLine=e.getPointOnLine;exports.getPointOnLineByOffset=e.getPointOnLineByOffset;exports.getPositionFromOffset=e.getPositionFromOffset;exports.handleArrival=e.handleArrival;exports.initializeAllVehicles=e.initializeAllVehicles;exports.initializeMovingVehicle=e.initializeMovingVehicle;exports.isPointNearPoint=e.isPointNearPoint;exports.moveVehicle=e.moveVehicle;exports.normalize=e.normalize;exports.prepareCommandPath=e.prepareCommandPath;exports.resolveFromLineOffset=e.resolveFromLineOffset;exports.resolveToLineOffset=e.resolveToLineOffset;exports.updateAxlePosition=e.updateAxlePosition;exports.deserializeScene=s;exports.serializeScene=o;
package/dist/core.js CHANGED
@@ -1,4 +1,4 @@
1
- import { P as f, a as g, b as h, c as d, d as u, e as m, f as P, g as A, h as v, i as L, j as O, k as p, l as S, m as z, n as y, o as w, p as x, q as I, r as b, s as E, t as T, u as B, v as C, w as N, x as j, y as J, z as F, A as V, B as M, C as k, D as q, E as D } from "./index-B3uagMdY.js";
1
+ import { P as f, a as g, b as h, c as d, d as u, e as m, f as P, g as A, h as v, i as L, j as O, k as p, l as S, m as z, n as y, o as w, p as x, q as I, r as b, s as E, t as T, u as B, v as C, w as N, x as j, y as J, z as F, A as V, B as M, C as k, D as q, E as D } from "./index-D-HctiIv.js";
2
2
  function n(s, a, i) {
3
3
  const r = {
4
4
  lines: s,
@@ -1 +1 @@
1
- "use strict";function L(t,e){const s=e.x-t.x,n=e.y-t.y;return Math.sqrt(s*s+n*n)}function D(t,e){const s=e.x-t.x,n=e.y-t.y,i=Math.sqrt(s*s+n*n);return i===0?{x:0,y:0}:{x:s/i,y:n/i}}function E(t,e){return e*(t==="proportional-40"?.4:.5522)}function V(t,e,s,n=!1,i){const{maxWheelbase:o,tangentMode:c}=s;let r;i?.fromOffset!==void 0?r=b(t,i.fromOffset,i.fromIsPercentage??!1):r=t.end;let a;i?.toOffset!==void 0?a=b(e,i.toOffset,i.toIsPercentage??!1):a=e.start;const l=D(t.start,t.end),u=n?{x:r.x-l.x*o,y:r.y-l.y*o}:r,g=D(t.start,t.end),d=D(e.start,e.end),h=L(u,a),p=E(c,h),f=n?{x:u.x-g.x*p,y:u.y-g.y*p}:{x:u.x+g.x*p,y:u.y+g.y*p},v={x:a.x-d.x*p,y:a.y-d.y*p};return{p0:u,p1:f,p2:v,p3:a}}function F(t,e){return{x:t.start.x+(t.end.x-t.start.x)*e,y:t.start.y+(t.end.y-t.start.y)*e}}function b(t,e,s){const n=L(t.start,t.end);let i;return s?i=e:i=n>0?e/n:0,i=Math.max(0,Math.min(1,i)),F(t,i)}function T(t,e){const{p0:s,p1:n,p2:i,p3:o}=t,c=1-e,r=c*c,a=r*c,l=e*e,u=l*e;return{x:a*s.x+3*r*e*n.x+3*c*l*i.x+u*o.x,y:a*s.y+3*r*e*n.y+3*c*l*i.y+u*o.y}}function ee(t,e,s=10){return L(t,e)<=s}function N(t,e=100){const s=[{t:0,distance:0}];let n=t.p0,i=0;for(let o=1;o<=e;o++){const c=o/e,r=T(t,c);i+=L(n,r),s.push({t:c,distance:i}),n=r}return s}function $(t,e){if(e<=0)return 0;const s=t[t.length-1].distance;if(e>=s)return 1;let n=0,i=t.length-1;for(;n<i-1;){const u=Math.floor((n+i)/2);t[u].distance<e?n=u:i=u}const o=t[n].distance,c=t[i].distance,r=t[n].t,a=t[i].t;if(c===o)return r;const l=(e-o)/(c-o);return r+l*(a-r)}function te(t){return t[t.length-1].distance}function j(t,e=100){let s=0,n=t.p0;for(let i=1;i<=e;i++){const o=i/e,c=T(t,o);s+=L(n,c),n=c}return s}function z(t,e,s,n,i){const o=L(t.start,t.end);return e===void 0?n*o:s?Math.max(0,Math.min(e,1))*o:Math.max(0,Math.min(e,o))}function W(t,e,s,n,i){const o=L(t.start,t.end);return e===void 0?n*o:s?Math.max(0,Math.min(e,1))*o:Math.max(0,Math.min(e,o))}function x(t,e,s){const n=new Map,i=new Map,o=new Map;for(const c of t)i.set(c.id,c),o.set(c.id,L(c.start,c.end)),n.set(c.id,[]);for(let c=0;c<e.length;c++){const r=e[c],a=i.get(r.fromLineId),l=i.get(r.toLineId);if(!a||!l)continue;const u=z(a,r.fromOffset,r.fromIsPercentage,1,s.maxWheelbase),g=W(l,r.toOffset,r.toIsPercentage,0,s.maxWheelbase),d=V(a,l,s,!1,{fromOffset:u,fromIsPercentage:!1,toOffset:g,toIsPercentage:!1}),h=j(d),p={curveIndex:c,fromLineId:r.fromLineId,toLineId:r.toLineId,fromOffset:u,toOffset:g,curveLength:h};n.get(r.fromLineId).push(p)}return{adjacency:n,lines:i,lineLengths:o}}function q(t,e){return t.curveCount!==e.curveCount?t.curveCount-e.curveCount:t.totalDistance-e.totalDistance}function K(t,e,s,n,i=!1){const{adjacency:o,lines:c,lineLengths:r}=t;if(!c.get(s))return null;const l=r.get(s),u=i?n/100*l:n,g=[],d=new Map,h=(f,v)=>`${f}:${Math.round(v)}`;if(e.lineId===s&&u>=e.offset){const f=u-e.offset;return{segments:[{type:"line",lineId:e.lineId,startOffset:e.offset,endOffset:u,length:f}],totalDistance:f,curveCount:0}}const p=o.get(e.lineId)||[];for(const f of p){if(f.fromOffset<e.offset)continue;const v=f.fromOffset-e.offset,I=v+f.curveLength,O={type:"line",lineId:e.lineId,startOffset:e.offset,endOffset:f.fromOffset,length:v},m={type:"curve",curveIndex:f.curveIndex,startOffset:0,endOffset:f.curveLength,length:f.curveLength};g.push({lineId:f.toLineId,entryOffset:f.toOffset,totalDistance:I,curveCount:1,path:[O,m]})}for(g.sort(q);g.length>0;){const f=g.shift(),v=h(f.lineId,f.entryOffset),I=d.get(v);if(I!==void 0&&(I.curveCount<f.curveCount||I.curveCount===f.curveCount&&I.distance<=f.totalDistance))continue;if(d.set(v,{curveCount:f.curveCount,distance:f.totalDistance}),f.lineId===s){const m=Math.abs(u-f.entryOffset);if(u>=f.entryOffset){const P={type:"line",lineId:s,startOffset:f.entryOffset,endOffset:u,length:m};return{segments:[...f.path,P],totalDistance:f.totalDistance+m,curveCount:f.curveCount}}}const O=o.get(f.lineId)||[];for(const m of O){if(m.fromOffset<f.entryOffset)continue;const P=m.fromOffset-f.entryOffset,B=f.totalDistance+P+m.curveLength,w=f.curveCount+1,X=h(m.toLineId,m.toOffset),C=d.get(X);if(C!==void 0&&(C.curveCount<w||C.curveCount===w&&C.distance<=B))continue;const Y={type:"line",lineId:f.lineId,startOffset:f.entryOffset,endOffset:m.fromOffset,length:P},Z={type:"curve",curveIndex:m.curveIndex,startOffset:0,endOffset:m.curveLength,length:m.curveLength};g.push({lineId:m.toLineId,entryOffset:m.toOffset,totalDistance:B,curveCount:w,path:[...f.path,Y,Z]})}g.sort(q)}return null}function S(t,e){const s=Math.sqrt(Math.pow(t.end.x-t.start.x,2)+Math.pow(t.end.y-t.start.y,2)),n=s>0?e/s:0;return{x:t.start.x+(t.end.x-t.start.x)*Math.min(1,Math.max(0,n)),y:t.start.y+(t.end.y-t.start.y)*Math.min(1,Math.max(0,n))}}function M(t){return Math.sqrt(Math.pow(t.end.x-t.start.x,2)+Math.pow(t.end.y-t.start.y,2))}function _(t,e,s){let n=0;for(let i=0;i<e;i++)n+=t.segments[i].length;return n+=s,n}function k(t,e){let s=0;for(let n=0;n<t.segments.length;n++){const i=t.segments[n],o=s+i.length;if(e<o)return{segmentIndex:n,segmentDistance:e-s};if(e===o)return n+1<t.segments.length?{segmentIndex:n+1,segmentDistance:0}:{segmentIndex:n,segmentDistance:i.length};s+=i.length}return null}function ne(t,e,s,n){const o=_(t,e,s)+n;return k(t,o)}function G(t,e,s,n){const i=M(n),o=s.length+1,c=new Array(o);c[o-1]={lineId:t,absoluteOffset:e,position:S(n,e)};let r=e;for(let a=o-2;a>=0;a--)r=Math.min(r+s[a],i),c[a]={lineId:t,absoluteOffset:r,position:S(n,r)};return c}function Q(t,e){return{...t,state:"idle"}}function R(t){return{vehicle:t,execution:null}}function se(t,e){const s=[],n=new Map;for(const i of t){if(!e.get(i.lineId))continue;const c=Q(i);s.push(c);const r=R(c);n.set(i.id,r)}return{movingVehicles:s,stateMap:n}}function y(t,e){return{position:S(t,e),lineId:t.id,absoluteOffset:e}}function A(t,e){const s=$(t.arcLengthTable,e);return{position:T(t.bezier,s)}}function H(t,e,s,n,i,o,c){const r=s.segments[e.currentSegmentIndex],a=e.segmentDistance+n;if(a>=r.length){const u=a-r.length,g=e.currentSegmentIndex+1;if(g>=s.segments.length){if(c!==void 0&&r.type==="line"){const f=i.get(r.lineId),v=r.startOffset+a;if(v<=c){const O=y(f,v);return{axleState:{...t,...O},execution:{...e,segmentDistance:a},completed:!1}}const I=y(f,c);return{axleState:{...t,...I},execution:{...e,segmentDistance:c-r.startOffset},completed:!0}}const p=r.type==="line"?y(i.get(r.lineId),r.endOffset):A(o.get(r.curveIndex),r.length);return{axleState:{...t,...p},execution:{...e,segmentDistance:r.length},completed:!0}}const d=s.segments[g],h=d.type==="line"?y(i.get(d.lineId),d.startOffset+u):A(o.get(d.curveIndex),u);return{axleState:{...t,...h},execution:{currentSegmentIndex:g,segmentDistance:u},completed:!1}}const l=r.type==="line"?y(i.get(r.lineId),r.startOffset+a):A(o.get(r.curveIndex),a);return{axleState:{...t,...l},execution:{...e,segmentDistance:a},completed:!1}}function ie(t,e,s,n){const i=new Map;for(const o of t.segments)if(o.type==="curve"&&o.curveIndex!==void 0){const c=e[o.curveIndex];if(c){const r=s.get(c.fromLineId),a=s.get(c.toLineId);if(r&&a){const l=z(r,c.fromOffset,c.fromIsPercentage,1,n.maxWheelbase),u=W(a,c.toOffset,c.toIsPercentage,0,n.maxWheelbase),g=V(r,a,n,!1,{fromOffset:l,fromIsPercentage:!1,toOffset:u,toIsPercentage:!1}),d=N(g);i.set(o.curveIndex,{bezier:g,arcLengthTable:d})}}}return i}function J(t,e,s){const{graph:n,linesMap:i,curves:o,config:c}=s,r=i.get(e.targetLineId);if(!r)return null;const a=t.axleSpacings.reduce((f,v)=>f+v,0),u=M(r)-a;if(u<=0)return null;const g=e.isPercentage?e.targetOffset*u:Math.min(e.targetOffset,u),d=t.axles[t.axles.length-1],h=K(n,{lineId:d.lineId,offset:d.absoluteOffset},e.targetLineId,g,!1);if(!h)return null;const p=ie(h,o,i,c);return{path:h,curveDataMap:p}}function re(t,e){const s=t.execution,i=e.vehicleQueues.get(t.vehicle.id)?.[s.currentCommandIndex];return i&&e.onCommandComplete&&e.onCommandComplete({vehicleId:t.vehicle.id,command:i,finalPosition:{lineId:t.vehicle.axles[t.vehicle.axles.length-1].lineId,absoluteOffset:t.vehicle.axles[t.vehicle.axles.length-1].absoluteOffset,position:t.vehicle.axles[t.vehicle.axles.length-1].position},payload:i.payload}),{handled:!0,vehicle:{...t.vehicle,state:"waiting"},newExecution:s,isWaiting:!0}}function U(t,e,s,n,i,o){let c;const r=e[0];if(r.currentSegmentIndex<s.segments.length){const l=s.segments[r.currentSegmentIndex];if(l.type==="line"){const u=i.get(l.lineId);u&&(c=M(u))}}const a=t.map((l,u)=>{const g=u===0?c:void 0;return H(l,e[u],s,n,i,o,g)});return{axles:a.map(l=>l.axleState),axleExecutions:a.map(l=>l.execution),arrived:a[0].completed}}class oe{graph=null;linesMap=new Map;curves=[];config;constructor(e){this.config={maxWheelbase:e.maxWheelbase,tangentMode:e.tangentMode}}get movementConfig(){return this.config}get lines(){return Array.from(this.linesMap.values())}getCurves(){return this.curves}setScene(e,s){this.linesMap.clear();for(const n of e)this.linesMap.set(n.id,n);this.curves=s,this.graph=x(e,s,this.config)}addLine(e){return this.linesMap.has(e.id)?!1:(this.linesMap.set(e.id,e),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0)}updateLine(e,s){const n=this.linesMap.get(e);return n?(s.start&&(n.start=s.start),s.end&&(n.end=s.end),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0):!1}updateLineEndpoint(e,s,n){return this.updateLine(e,{[s]:n})}renameLine(e,s){const n=s.trim();if(!n)return{success:!1,error:"Name cannot be empty"};if(n===e)return{success:!0};if(this.linesMap.has(n))return{success:!1,error:`"${n}" already exists`};const i=this.linesMap.get(e);if(!i)return{success:!1,error:`Line "${e}" not found`};i.id=n,this.linesMap.delete(e),this.linesMap.set(n,i);for(const o of this.curves)o.fromLineId===e&&(o.fromLineId=n),o.toLineId===e&&(o.toLineId=n);return this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),{success:!0}}removeLine(e){return this.linesMap.has(e)?(this.linesMap.delete(e),this.curves=this.curves.filter(s=>s.fromLineId!==e&&s.toLineId!==e),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0):!1}addCurve(e){this.curves.push(e),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config)}updateCurve(e,s){return e<0||e>=this.curves.length?!1:(this.curves[e]={...this.curves[e],...s},this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0)}removeCurve(e){return e<0||e>=this.curves.length?!1:(this.curves.splice(e,1),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0)}initializeVehicle(e,s,n){const i=this.linesMap.get(e);if(!i)return null;const o=n.reduce((l,u)=>l+u,0),c=M(i),r=Math.min(s,c-o);return{axles:G(e,r,n,i).map(l=>({lineId:l.lineId,offset:l.absoluteOffset,position:l.position})),axleSpacings:n}}preparePath(e,s,n,i=!1){if(!this.graph)return null;const o=e.axleSpacings.reduce((h,p)=>h+p,0),c=e.axles[e.axles.length-1],r={lineId:c.lineId,offset:c.offset,axles:e.axles.map(h=>({lineId:h.lineId,position:h.position,absoluteOffset:h.offset})),axleSpacings:e.axleSpacings},a=J(r,{targetLineId:s,targetOffset:n,isPercentage:i},{graph:this.graph,linesMap:this.linesMap,curves:this.curves,config:this.config});if(!a)return null;let l=n;const u=this.linesMap.get(s);if(u){const h=Math.max(0,M(u)-o);l=i?n*h:Math.min(n,h)}let g=0;const d=[{segmentIndex:0,segmentDistance:o}];for(let h=0;h<e.axleSpacings.length;h++)g+=e.axleSpacings[h],d.push({segmentIndex:0,segmentDistance:o-g});return{path:a.path,curveDataMap:a.curveDataMap,axleExecutions:d,targetLineId:s,targetOffset:l}}moveVehicle(e,s,n){const i=e.axles.map(r=>({lineId:r.lineId,position:r.position,absoluteOffset:r.offset})),o=s.axleExecutions.map(r=>({currentSegmentIndex:r.segmentIndex,segmentDistance:r.segmentDistance})),c=U(i,o,s.path,n,this.linesMap,s.curveDataMap);return{state:{axles:c.axles.map(r=>({lineId:r.lineId,offset:r.absoluteOffset,position:r.position})),axleSpacings:e.axleSpacings},execution:{...s,axleExecutions:c.axleExecutions.map(r=>({segmentIndex:r.currentSegmentIndex,segmentDistance:r.segmentDistance}))},arrived:c.arrived}}}exports.PathEngine=oe;exports.arcLengthToSegmentPosition=k;exports.buildArcLengthTable=N;exports.buildGraph=x;exports.calculateBezierArcLength=j;exports.calculateFrontAxlePosition=ne;exports.calculateInitialAxlePositions=G;exports.calculatePositionOnCurve=A;exports.calculatePositionOnLine=y;exports.calculateTangentLength=E;exports.createBezierCurve=V;exports.createInitialMovementState=R;exports.distance=L;exports.distanceToT=$;exports.findPath=K;exports.getArcLength=te;exports.getCumulativeArcLength=_;exports.getLineLength=M;exports.getPointOnBezier=T;exports.getPointOnLine=F;exports.getPointOnLineByOffset=b;exports.getPositionFromOffset=S;exports.handleArrival=re;exports.initializeAllVehicles=se;exports.initializeMovingVehicle=Q;exports.isPointNearPoint=ee;exports.moveVehicle=U;exports.normalize=D;exports.prepareCommandPath=J;exports.resolveFromLineOffset=z;exports.resolveToLineOffset=W;exports.updateAxlePosition=H;
1
+ "use strict";function L(t,e){const s=e.x-t.x,n=e.y-t.y;return Math.sqrt(s*s+n*n)}function D(t,e){const s=e.x-t.x,n=e.y-t.y,i=Math.sqrt(s*s+n*n);return i===0?{x:0,y:0}:{x:s/i,y:n/i}}function E(t,e){return e*(t==="proportional-40"?.4:.5522)}function V(t,e,s,n=!1,i){const{maxWheelbase:o,tangentMode:c}=s;let r;i?.fromOffset!==void 0?r=b(t,i.fromOffset,i.fromIsPercentage??!1):r=t.end;let a;i?.toOffset!==void 0?a=b(e,i.toOffset,i.toIsPercentage??!1):a=e.start;const l=D(t.start,t.end),u=n?{x:r.x-l.x*o,y:r.y-l.y*o}:r,g=D(t.start,t.end),d=D(e.start,e.end),h=L(u,a),p=E(c,h),f=n?{x:u.x-g.x*p,y:u.y-g.y*p}:{x:u.x+g.x*p,y:u.y+g.y*p},v={x:a.x-d.x*p,y:a.y-d.y*p};return{p0:u,p1:f,p2:v,p3:a}}function F(t,e){return{x:t.start.x+(t.end.x-t.start.x)*e,y:t.start.y+(t.end.y-t.start.y)*e}}function b(t,e,s){const n=L(t.start,t.end);let i;return s?i=e:i=n>0?e/n:0,i=Math.max(0,Math.min(1,i)),F(t,i)}function T(t,e){const{p0:s,p1:n,p2:i,p3:o}=t,c=1-e,r=c*c,a=r*c,l=e*e,u=l*e;return{x:a*s.x+3*r*e*n.x+3*c*l*i.x+u*o.x,y:a*s.y+3*r*e*n.y+3*c*l*i.y+u*o.y}}function ee(t,e,s=10){return L(t,e)<=s}function N(t,e=100){const s=[{t:0,distance:0}];let n=t.p0,i=0;for(let o=1;o<=e;o++){const c=o/e,r=T(t,c);i+=L(n,r),s.push({t:c,distance:i}),n=r}return s}function $(t,e){if(e<=0)return 0;const s=t[t.length-1].distance;if(e>=s)return 1;let n=0,i=t.length-1;for(;n<i-1;){const u=Math.floor((n+i)/2);t[u].distance<e?n=u:i=u}const o=t[n].distance,c=t[i].distance,r=t[n].t,a=t[i].t;if(c===o)return r;const l=(e-o)/(c-o);return r+l*(a-r)}function te(t){return t[t.length-1].distance}function j(t,e=100){let s=0,n=t.p0;for(let i=1;i<=e;i++){const o=i/e,c=T(t,o);s+=L(n,c),n=c}return s}function z(t,e,s,n,i){const o=L(t.start,t.end);return e===void 0?n*o:s?Math.max(0,Math.min(e,1))*o:Math.max(0,Math.min(e,o))}function W(t,e,s,n,i){const o=L(t.start,t.end);return e===void 0?n*o:s?Math.max(0,Math.min(e,1))*o:Math.max(0,Math.min(e,o))}function x(t,e,s){const n=new Map,i=new Map,o=new Map;for(const c of t)i.set(c.id,c),o.set(c.id,L(c.start,c.end)),n.set(c.id,[]);for(let c=0;c<e.length;c++){const r=e[c],a=i.get(r.fromLineId),l=i.get(r.toLineId);if(!a||!l)continue;const u=z(a,r.fromOffset,r.fromIsPercentage,1,s.maxWheelbase),g=W(l,r.toOffset,r.toIsPercentage,0,s.maxWheelbase),d=V(a,l,s,!1,{fromOffset:u,fromIsPercentage:!1,toOffset:g,toIsPercentage:!1}),h=j(d),p={curveIndex:c,fromLineId:r.fromLineId,toLineId:r.toLineId,fromOffset:u,toOffset:g,curveLength:h};n.get(r.fromLineId).push(p)}return{adjacency:n,lines:i,lineLengths:o}}function q(t,e){return t.curveCount!==e.curveCount?t.curveCount-e.curveCount:t.totalDistance-e.totalDistance}function K(t,e,s,n,i=!1){const{adjacency:o,lines:c,lineLengths:r}=t;if(!c.get(s))return null;const l=r.get(s),u=i?n/100*l:n,g=[],d=new Map,h=(f,v)=>`${f}:${Math.round(v)}`;if(e.lineId===s&&u>=e.offset){const f=u-e.offset;return{segments:[{type:"line",lineId:e.lineId,startOffset:e.offset,endOffset:u,length:f}],totalDistance:f,curveCount:0}}const p=o.get(e.lineId)||[];for(const f of p){if(f.fromOffset<e.offset)continue;const v=f.fromOffset-e.offset,I=v+f.curveLength,O={type:"line",lineId:e.lineId,startOffset:e.offset,endOffset:f.fromOffset,length:v},m={type:"curve",curveIndex:f.curveIndex,startOffset:0,endOffset:f.curveLength,length:f.curveLength};g.push({lineId:f.toLineId,entryOffset:f.toOffset,totalDistance:I,curveCount:1,path:[O,m]})}for(g.sort(q);g.length>0;){const f=g.shift(),v=h(f.lineId,f.entryOffset),I=d.get(v);if(I!==void 0&&(I.curveCount<f.curveCount||I.curveCount===f.curveCount&&I.distance<=f.totalDistance))continue;if(d.set(v,{curveCount:f.curveCount,distance:f.totalDistance}),f.lineId===s){const m=Math.abs(u-f.entryOffset);if(u>=f.entryOffset){const P={type:"line",lineId:s,startOffset:f.entryOffset,endOffset:u,length:m};return{segments:[...f.path,P],totalDistance:f.totalDistance+m,curveCount:f.curveCount}}}const O=o.get(f.lineId)||[];for(const m of O){if(m.fromOffset<f.entryOffset)continue;const P=m.fromOffset-f.entryOffset,B=f.totalDistance+P+m.curveLength,w=f.curveCount+1,X=h(m.toLineId,m.toOffset),C=d.get(X);if(C!==void 0&&(C.curveCount<w||C.curveCount===w&&C.distance<=B))continue;const Y={type:"line",lineId:f.lineId,startOffset:f.entryOffset,endOffset:m.fromOffset,length:P},Z={type:"curve",curveIndex:m.curveIndex,startOffset:0,endOffset:m.curveLength,length:m.curveLength};g.push({lineId:m.toLineId,entryOffset:m.toOffset,totalDistance:B,curveCount:w,path:[...f.path,Y,Z]})}g.sort(q)}return null}function S(t,e){const s=Math.sqrt(Math.pow(t.end.x-t.start.x,2)+Math.pow(t.end.y-t.start.y,2)),n=s>0?e/s:0;return{x:t.start.x+(t.end.x-t.start.x)*Math.min(1,Math.max(0,n)),y:t.start.y+(t.end.y-t.start.y)*Math.min(1,Math.max(0,n))}}function M(t){return Math.sqrt(Math.pow(t.end.x-t.start.x,2)+Math.pow(t.end.y-t.start.y,2))}function _(t,e,s){let n=0;for(let i=0;i<e;i++)n+=t.segments[i].length;return n+=s,n}function k(t,e){let s=0;for(let n=0;n<t.segments.length;n++){const i=t.segments[n],o=s+i.length;if(e<o)return{segmentIndex:n,segmentDistance:e-s};if(e===o)return n+1<t.segments.length?{segmentIndex:n+1,segmentDistance:0}:{segmentIndex:n,segmentDistance:i.length};s+=i.length}return null}function ne(t,e,s,n){const o=_(t,e,s)+n;return k(t,o)}function G(t,e,s,n){const i=M(n),o=s.length+1,c=new Array(o);c[o-1]={lineId:t,absoluteOffset:e,position:S(n,e)};let r=e;for(let a=o-2;a>=0;a--)r=Math.min(r+s[a],i),c[a]={lineId:t,absoluteOffset:r,position:S(n,r)};return c}function Q(t,e){return{...t,state:"idle"}}function R(t){return{vehicle:t,execution:null}}function se(t,e){const s=[],n=new Map;for(const i of t){if(!e.get(i.lineId))continue;const c=Q(i);s.push(c);const r=R(c);n.set(i.id,r)}return{movingVehicles:s,stateMap:n}}function y(t,e){return{position:S(t,e),lineId:t.id,absoluteOffset:e}}function A(t,e){const s=$(t.arcLengthTable,e);return{position:T(t.bezier,s)}}function H(t,e,s,n,i,o,c){const r=s.segments[e.currentSegmentIndex],a=e.segmentDistance+n;if(a>=r.length){const u=a-r.length,g=e.currentSegmentIndex+1;if(g>=s.segments.length){if(c!==void 0&&r.type==="line"){const f=i.get(r.lineId),v=r.startOffset+a;if(v<=c){const O=y(f,v);return{axleState:{...t,...O},execution:{...e,segmentDistance:a},completed:!1}}const I=y(f,c);return{axleState:{...t,...I},execution:{...e,segmentDistance:c-r.startOffset},completed:!0}}const p=r.type==="line"?y(i.get(r.lineId),r.endOffset):A(o.get(r.curveIndex),r.length);return{axleState:{...t,...p},execution:{...e,segmentDistance:r.length},completed:!0}}const d=s.segments[g],h=d.type==="line"?y(i.get(d.lineId),d.startOffset+u):A(o.get(d.curveIndex),u);return{axleState:{...t,...h},execution:{currentSegmentIndex:g,segmentDistance:u},completed:!1}}const l=r.type==="line"?y(i.get(r.lineId),r.startOffset+a):A(o.get(r.curveIndex),a);return{axleState:{...t,...l},execution:{...e,segmentDistance:a},completed:!1}}function ie(t,e,s,n){const i=new Map;for(const o of t.segments)if(o.type==="curve"&&o.curveIndex!==void 0){const c=e[o.curveIndex];if(c){const r=s.get(c.fromLineId),a=s.get(c.toLineId);if(r&&a){const l=z(r,c.fromOffset,c.fromIsPercentage,1,n.maxWheelbase),u=W(a,c.toOffset,c.toIsPercentage,0,n.maxWheelbase),g=V(r,a,n,!1,{fromOffset:l,fromIsPercentage:!1,toOffset:u,toIsPercentage:!1}),d=N(g);i.set(o.curveIndex,{bezier:g,arcLengthTable:d})}}}return i}function J(t,e,s){const{graph:n,linesMap:i,curves:o,config:c}=s,r=i.get(e.targetLineId);if(!r)return null;const a=t.axleSpacings.reduce((f,v)=>f+v,0),u=M(r)-a;if(u<=0)return null;const g=e.isPercentage?e.targetOffset*u:Math.min(e.targetOffset,u),d=t.axles[t.axles.length-1],h=K(n,{lineId:d.lineId,offset:d.absoluteOffset},e.targetLineId,g,!1);if(!h)return null;const p=ie(h,o,i,c);return{path:h,curveDataMap:p}}function re(t,e){const s=t.execution,i=e.vehicleQueues.get(t.vehicle.id)?.[s.currentCommandIndex];return i&&e.onCommandComplete&&e.onCommandComplete({vehicleId:t.vehicle.id,command:i,finalPosition:{lineId:t.vehicle.axles[t.vehicle.axles.length-1].lineId,absoluteOffset:t.vehicle.axles[t.vehicle.axles.length-1].absoluteOffset,position:t.vehicle.axles[t.vehicle.axles.length-1].position},payload:i.payload}),{handled:!0,vehicle:{...t.vehicle,state:"waiting"},newExecution:s,isWaiting:!0}}function U(t,e,s,n,i,o){let c;const r=e[0];if(r.currentSegmentIndex<s.segments.length){const l=s.segments[r.currentSegmentIndex];if(l.type==="line"){const u=i.get(l.lineId);u&&(c=M(u))}}const a=t.map((l,u)=>{const g=u===0?c:void 0;return H(l,e[u],s,n,i,o,g)});return{axles:a.map(l=>l.axleState),axleExecutions:a.map(l=>l.execution),arrived:a[a.length-1].completed}}class oe{graph=null;linesMap=new Map;curves=[];config;constructor(e){this.config={maxWheelbase:e.maxWheelbase,tangentMode:e.tangentMode}}get movementConfig(){return this.config}get lines(){return Array.from(this.linesMap.values())}getCurves(){return this.curves}setScene(e,s){this.linesMap.clear();for(const n of e)this.linesMap.set(n.id,n);this.curves=s,this.graph=x(e,s,this.config)}addLine(e){return this.linesMap.has(e.id)?!1:(this.linesMap.set(e.id,e),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0)}updateLine(e,s){const n=this.linesMap.get(e);return n?(s.start&&(n.start=s.start),s.end&&(n.end=s.end),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0):!1}updateLineEndpoint(e,s,n){return this.updateLine(e,{[s]:n})}renameLine(e,s){const n=s.trim();if(!n)return{success:!1,error:"Name cannot be empty"};if(n===e)return{success:!0};if(this.linesMap.has(n))return{success:!1,error:`"${n}" already exists`};const i=this.linesMap.get(e);if(!i)return{success:!1,error:`Line "${e}" not found`};i.id=n,this.linesMap.delete(e),this.linesMap.set(n,i);for(const o of this.curves)o.fromLineId===e&&(o.fromLineId=n),o.toLineId===e&&(o.toLineId=n);return this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),{success:!0}}removeLine(e){return this.linesMap.has(e)?(this.linesMap.delete(e),this.curves=this.curves.filter(s=>s.fromLineId!==e&&s.toLineId!==e),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0):!1}addCurve(e){this.curves.push(e),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config)}updateCurve(e,s){return e<0||e>=this.curves.length?!1:(this.curves[e]={...this.curves[e],...s},this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0)}removeCurve(e){return e<0||e>=this.curves.length?!1:(this.curves.splice(e,1),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0)}initializeVehicle(e,s,n){const i=this.linesMap.get(e);if(!i)return null;const o=n.reduce((l,u)=>l+u,0),c=M(i),r=Math.min(s,c-o);return{axles:G(e,r,n,i).map(l=>({lineId:l.lineId,offset:l.absoluteOffset,position:l.position})),axleSpacings:n}}preparePath(e,s,n,i=!1){if(!this.graph)return null;const o=e.axleSpacings.reduce((h,p)=>h+p,0),c=e.axles[e.axles.length-1],r={lineId:c.lineId,offset:c.offset,axles:e.axles.map(h=>({lineId:h.lineId,position:h.position,absoluteOffset:h.offset})),axleSpacings:e.axleSpacings},a=J(r,{targetLineId:s,targetOffset:n,isPercentage:i},{graph:this.graph,linesMap:this.linesMap,curves:this.curves,config:this.config});if(!a)return null;let l=n;const u=this.linesMap.get(s);if(u){const h=Math.max(0,M(u)-o);l=i?n*h:Math.min(n,h)}let g=0;const d=[{segmentIndex:0,segmentDistance:o}];for(let h=0;h<e.axleSpacings.length;h++)g+=e.axleSpacings[h],d.push({segmentIndex:0,segmentDistance:o-g});return{path:a.path,curveDataMap:a.curveDataMap,axleExecutions:d,targetLineId:s,targetOffset:l}}moveVehicle(e,s,n){const i=e.axles.map(r=>({lineId:r.lineId,position:r.position,absoluteOffset:r.offset})),o=s.axleExecutions.map(r=>({currentSegmentIndex:r.segmentIndex,segmentDistance:r.segmentDistance})),c=U(i,o,s.path,n,this.linesMap,s.curveDataMap);return{state:{axles:c.axles.map(r=>({lineId:r.lineId,offset:r.absoluteOffset,position:r.position})),axleSpacings:e.axleSpacings},execution:{...s,axleExecutions:c.axleExecutions.map(r=>({segmentIndex:r.currentSegmentIndex,segmentDistance:r.segmentDistance}))},arrived:c.arrived}}}exports.PathEngine=oe;exports.arcLengthToSegmentPosition=k;exports.buildArcLengthTable=N;exports.buildGraph=x;exports.calculateBezierArcLength=j;exports.calculateFrontAxlePosition=ne;exports.calculateInitialAxlePositions=G;exports.calculatePositionOnCurve=A;exports.calculatePositionOnLine=y;exports.calculateTangentLength=E;exports.createBezierCurve=V;exports.createInitialMovementState=R;exports.distance=L;exports.distanceToT=$;exports.findPath=K;exports.getArcLength=te;exports.getCumulativeArcLength=_;exports.getLineLength=M;exports.getPointOnBezier=T;exports.getPointOnLine=F;exports.getPointOnLineByOffset=b;exports.getPositionFromOffset=S;exports.handleArrival=re;exports.initializeAllVehicles=se;exports.initializeMovingVehicle=Q;exports.isPointNearPoint=ee;exports.moveVehicle=U;exports.normalize=D;exports.prepareCommandPath=J;exports.resolveFromLineOffset=z;exports.resolveToLineOffset=W;exports.updateAxlePosition=H;
@@ -471,8 +471,8 @@ function ee(t, e, s, n, r, o) {
471
471
  return {
472
472
  axles: c.map((l) => l.axleState),
473
473
  axleExecutions: c.map((l) => l.execution),
474
- arrived: c[0].completed
475
- // axles[0] = terdepan menentukan arrived
474
+ arrived: c[c.length - 1].completed
475
+ // axles[N-1] = rearmost menentukan arrived
476
476
  };
477
477
  }
478
478
  class ae {
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-DA33ne3M.cjs");exports.PathEngine=e.PathEngine;exports.arcLengthToSegmentPosition=e.arcLengthToSegmentPosition;exports.buildArcLengthTable=e.buildArcLengthTable;exports.buildGraph=e.buildGraph;exports.calculateBezierArcLength=e.calculateBezierArcLength;exports.calculateFrontAxlePosition=e.calculateFrontAxlePosition;exports.calculateInitialAxlePositions=e.calculateInitialAxlePositions;exports.calculatePositionOnCurve=e.calculatePositionOnCurve;exports.calculatePositionOnLine=e.calculatePositionOnLine;exports.createBezierCurve=e.createBezierCurve;exports.createInitialMovementState=e.createInitialMovementState;exports.distance=e.distance;exports.distanceToT=e.distanceToT;exports.findPath=e.findPath;exports.getArcLength=e.getArcLength;exports.getCumulativeArcLength=e.getCumulativeArcLength;exports.getLineLength=e.getLineLength;exports.getPointOnBezier=e.getPointOnBezier;exports.getPointOnLine=e.getPointOnLine;exports.getPointOnLineByOffset=e.getPointOnLineByOffset;exports.getPositionFromOffset=e.getPositionFromOffset;exports.handleArrival=e.handleArrival;exports.initializeAllVehicles=e.initializeAllVehicles;exports.initializeMovingVehicle=e.initializeMovingVehicle;exports.moveVehicle=e.moveVehicle;exports.normalize=e.normalize;exports.prepareCommandPath=e.prepareCommandPath;exports.resolveFromLineOffset=e.resolveFromLineOffset;exports.resolveToLineOffset=e.resolveToLineOffset;exports.updateAxlePosition=e.updateAxlePosition;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-BUYdltrL.cjs");exports.PathEngine=e.PathEngine;exports.arcLengthToSegmentPosition=e.arcLengthToSegmentPosition;exports.buildArcLengthTable=e.buildArcLengthTable;exports.buildGraph=e.buildGraph;exports.calculateBezierArcLength=e.calculateBezierArcLength;exports.calculateFrontAxlePosition=e.calculateFrontAxlePosition;exports.calculateInitialAxlePositions=e.calculateInitialAxlePositions;exports.calculatePositionOnCurve=e.calculatePositionOnCurve;exports.calculatePositionOnLine=e.calculatePositionOnLine;exports.createBezierCurve=e.createBezierCurve;exports.createInitialMovementState=e.createInitialMovementState;exports.distance=e.distance;exports.distanceToT=e.distanceToT;exports.findPath=e.findPath;exports.getArcLength=e.getArcLength;exports.getCumulativeArcLength=e.getCumulativeArcLength;exports.getLineLength=e.getLineLength;exports.getPointOnBezier=e.getPointOnBezier;exports.getPointOnLine=e.getPointOnLine;exports.getPointOnLineByOffset=e.getPointOnLineByOffset;exports.getPositionFromOffset=e.getPositionFromOffset;exports.handleArrival=e.handleArrival;exports.initializeAllVehicles=e.initializeAllVehicles;exports.initializeMovingVehicle=e.initializeMovingVehicle;exports.moveVehicle=e.moveVehicle;exports.normalize=e.normalize;exports.prepareCommandPath=e.prepareCommandPath;exports.resolveFromLineOffset=e.resolveFromLineOffset;exports.resolveToLineOffset=e.resolveToLineOffset;exports.updateAxlePosition=e.updateAxlePosition;
@@ -1,4 +1,4 @@
1
- import { P as t, a as i, b as s, c as n, d as o, e as l, f as r, g as c, h as g, j as h, k as P, l as u, m as L, n as f, o as m, p as v, q as A, r as d, s as O, t as z, u as p, v as x, w as B, x as C, z as T, A as b, B as F, C as V, D as E, E as I } from "./index-B3uagMdY.js";
1
+ import { P as t, a as i, b as s, c as n, d as o, e as l, f as r, g as c, h as g, j as h, k as P, l as u, m as L, n as f, o as m, p as v, q as A, r as d, s as O, t as z, u as p, v as x, w as B, x as C, z as T, A as b, B as F, C as V, D as E, E as I } from "./index-D-HctiIv.js";
2
2
  export {
3
3
  t as PathEngine,
4
4
  i as arcLengthToSegmentPosition,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vehicle-path2",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Vehicle motion simulator library for dual-axle vehicle movement along paths composed of lines and Bezier curves",
5
5
  "type": "module",
6
6
  "main": "./dist/vehicle-path.cjs",