@codexo/exojs-physics 0.15.2 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -23
- package/dist/esm/Aabb.d.ts +6 -10
- package/dist/esm/Aabb.d.ts.map +1 -0
- package/dist/esm/Aabb.js +9 -5
- package/dist/esm/Aabb.js.map +1 -1
- package/dist/esm/Collider.d.ts +62 -10
- package/dist/esm/Collider.d.ts.map +1 -0
- package/dist/esm/Collider.js +263 -157
- package/dist/esm/Collider.js.map +1 -1
- package/dist/esm/ContactGraph.d.ts +51 -5
- package/dist/esm/ContactGraph.d.ts.map +1 -0
- package/dist/esm/ContactGraph.js +282 -223
- package/dist/esm/ContactGraph.js.map +1 -1
- package/dist/esm/ContactModifier.d.ts +85 -0
- package/dist/esm/ContactModifier.d.ts.map +1 -0
- package/dist/esm/ContactModifier.js +49 -0
- package/dist/esm/ContactModifier.js.map +1 -0
- package/dist/esm/PhysicsBody.d.ts +56 -22
- package/dist/esm/PhysicsBody.d.ts.map +1 -0
- package/dist/esm/PhysicsBody.js +461 -443
- package/dist/esm/PhysicsBody.js.map +1 -1
- package/dist/esm/PhysicsWorld.d.ts +276 -43
- package/dist/esm/PhysicsWorld.d.ts.map +1 -0
- package/dist/esm/PhysicsWorld.js +890 -626
- package/dist/esm/PhysicsWorld.js.map +1 -1
- package/dist/esm/TimeStepper.d.ts +3 -2
- package/dist/esm/TimeStepper.d.ts.map +1 -0
- package/dist/esm/TimeStepper.js +56 -67
- package/dist/esm/TimeStepper.js.map +1 -1
- package/dist/esm/backend/NativePhysicsBackend.d.ts +8 -4
- package/dist/esm/backend/NativePhysicsBackend.d.ts.map +1 -0
- package/dist/esm/backend/NativePhysicsBackend.js +48 -41
- package/dist/esm/backend/NativePhysicsBackend.js.map +1 -1
- package/dist/esm/backend/PhysicsBackend.d.ts +9 -2
- package/dist/esm/backend/PhysicsBackend.d.ts.map +1 -0
- package/dist/esm/binding/BindingRegistry.d.ts +25 -4
- package/dist/esm/binding/BindingRegistry.d.ts.map +1 -0
- package/dist/esm/binding/BindingRegistry.js +70 -36
- package/dist/esm/binding/BindingRegistry.js.map +1 -1
- package/dist/esm/binding/PhysicsBinding.d.ts +22 -5
- package/dist/esm/binding/PhysicsBinding.d.ts.map +1 -0
- package/dist/esm/binding/PhysicsBinding.js +46 -21
- package/dist/esm/binding/PhysicsBinding.js.map +1 -1
- package/dist/esm/broadphase/AabbTreeBroadPhase.d.ts +68 -0
- package/dist/esm/broadphase/AabbTreeBroadPhase.d.ts.map +1 -0
- package/dist/esm/broadphase/AabbTreeBroadPhase.js +149 -0
- package/dist/esm/broadphase/AabbTreeBroadPhase.js.map +1 -0
- package/dist/esm/broadphase/BroadPhase.d.ts +7 -4
- package/dist/esm/broadphase/BroadPhase.d.ts.map +1 -0
- package/dist/esm/broadphase/index.d.ts +2 -1
- package/dist/esm/broadphase/index.d.ts.map +1 -0
- package/dist/esm/collision/CollisionProxy.d.ts +3 -2
- package/dist/esm/collision/CollisionProxy.d.ts.map +1 -0
- package/dist/esm/collision/Manifold.d.ts +5 -4
- package/dist/esm/collision/Manifold.d.ts.map +1 -0
- package/dist/esm/collision/Manifold.js +34 -25
- package/dist/esm/collision/Manifold.js.map +1 -1
- package/dist/esm/collision/chainAdjacency.d.ts +29 -0
- package/dist/esm/collision/chainAdjacency.d.ts.map +1 -0
- package/dist/esm/collision/chainAdjacency.js +44 -0
- package/dist/esm/collision/chainAdjacency.js.map +1 -0
- package/dist/esm/collision/dispatch.d.ts +35 -0
- package/dist/esm/collision/dispatch.d.ts.map +1 -0
- package/dist/esm/collision/dispatch.js +58 -0
- package/dist/esm/collision/dispatch.js.map +1 -0
- package/dist/esm/collision/index.d.ts +2 -0
- package/dist/esm/collision/index.d.ts.map +1 -0
- package/dist/esm/collision/narrowphase.d.ts +5 -2
- package/dist/esm/collision/narrowphase.d.ts.map +1 -0
- package/dist/esm/collision/narrowphase.js +524 -399
- package/dist/esm/collision/narrowphase.js.map +1 -1
- package/dist/esm/collision/segments.d.ts +19 -0
- package/dist/esm/collision/segments.d.ts.map +1 -0
- package/dist/esm/collision/segments.js +36 -0
- package/dist/esm/collision/segments.js.map +1 -0
- package/dist/esm/collision/sweep.d.ts +35 -0
- package/dist/esm/collision/sweep.d.ts.map +1 -0
- package/dist/esm/collision/sweep.js +437 -0
- package/dist/esm/collision/sweep.js.map +1 -0
- package/dist/esm/debug/PhysicsDebugDraw.d.ts +23 -4
- package/dist/esm/debug/PhysicsDebugDraw.d.ts.map +1 -0
- package/dist/esm/debug/PhysicsDebugDraw.js +230 -188
- package/dist/esm/debug/PhysicsDebugDraw.js.map +1 -1
- package/dist/esm/debug/index.d.ts +1 -0
- package/dist/esm/debug/index.d.ts.map +1 -0
- package/dist/esm/debug/index.js +3 -2
- package/dist/esm/events.d.ts +1 -0
- package/dist/esm/events.d.ts.map +1 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +24 -19
- package/dist/esm/joints/DistanceJoint.d.ts +4 -3
- package/dist/esm/joints/DistanceJoint.d.ts.map +1 -0
- package/dist/esm/joints/DistanceJoint.js +160 -172
- package/dist/esm/joints/DistanceJoint.js.map +1 -1
- package/dist/esm/joints/Joint.d.ts +5 -4
- package/dist/esm/joints/Joint.d.ts.map +1 -0
- package/dist/esm/joints/Joint.js +23 -21
- package/dist/esm/joints/Joint.js.map +1 -1
- package/dist/esm/joints/MouseJoint.d.ts +8 -7
- package/dist/esm/joints/MouseJoint.d.ts.map +1 -0
- package/dist/esm/joints/MouseJoint.js +132 -133
- package/dist/esm/joints/MouseJoint.js.map +1 -1
- package/dist/esm/joints/PrismaticJoint.d.ts +5 -4
- package/dist/esm/joints/PrismaticJoint.d.ts.map +1 -0
- package/dist/esm/joints/PrismaticJoint.js +211 -240
- package/dist/esm/joints/PrismaticJoint.js.map +1 -1
- package/dist/esm/joints/RevoluteJoint.d.ts +4 -3
- package/dist/esm/joints/RevoluteJoint.d.ts.map +1 -0
- package/dist/esm/joints/RevoluteJoint.js +191 -213
- package/dist/esm/joints/RevoluteJoint.js.map +1 -1
- package/dist/esm/joints/WeldJoint.d.ts +3 -2
- package/dist/esm/joints/WeldJoint.d.ts.map +1 -0
- package/dist/esm/joints/WeldJoint.js +156 -152
- package/dist/esm/joints/WeldJoint.js.map +1 -1
- package/dist/esm/joints/WheelJoint.d.ts +4 -3
- package/dist/esm/joints/WheelJoint.d.ts.map +1 -0
- package/dist/esm/joints/WheelJoint.js +228 -255
- package/dist/esm/joints/WheelJoint.js.map +1 -1
- package/dist/esm/math.d.ts +6 -9
- package/dist/esm/math.d.ts.map +1 -0
- package/dist/esm/math.js +37 -39
- package/dist/esm/math.js.map +1 -1
- package/dist/esm/physicsBuildInfo.d.ts +1 -0
- package/dist/esm/physicsBuildInfo.d.ts.map +1 -0
- package/dist/esm/physicsBuildInfo.js +6 -4
- package/dist/esm/physicsBuildInfo.js.map +1 -1
- package/dist/esm/public.d.ts +8 -3
- package/dist/esm/public.d.ts.map +1 -0
- package/dist/esm/query/QueryEngine.d.ts +56 -12
- package/dist/esm/query/QueryEngine.d.ts.map +1 -0
- package/dist/esm/query/QueryEngine.js +494 -237
- package/dist/esm/query/QueryEngine.js.map +1 -1
- package/dist/esm/query/SpatialIndex.d.ts +34 -0
- package/dist/esm/query/SpatialIndex.d.ts.map +1 -0
- package/dist/esm/shapes/AnyShape.d.ts +9 -4
- package/dist/esm/shapes/AnyShape.d.ts.map +1 -0
- package/dist/esm/shapes/BoxShape.d.ts +2 -1
- package/dist/esm/shapes/BoxShape.d.ts.map +1 -0
- package/dist/esm/shapes/BoxShape.js +37 -25
- package/dist/esm/shapes/BoxShape.js.map +1 -1
- package/dist/esm/shapes/CapsuleShape.d.ts +30 -0
- package/dist/esm/shapes/CapsuleShape.d.ts.map +1 -0
- package/dist/esm/shapes/CapsuleShape.js +88 -0
- package/dist/esm/shapes/CapsuleShape.js.map +1 -0
- package/dist/esm/shapes/ChainEdgeShape.d.ts +30 -0
- package/dist/esm/shapes/ChainEdgeShape.d.ts.map +1 -0
- package/dist/esm/shapes/ChainEdgeShape.js +66 -0
- package/dist/esm/shapes/ChainEdgeShape.js.map +1 -0
- package/dist/esm/shapes/ChainShape.d.ts +52 -0
- package/dist/esm/shapes/ChainShape.d.ts.map +1 -0
- package/dist/esm/shapes/ChainShape.js +85 -0
- package/dist/esm/shapes/ChainShape.js.map +1 -0
- package/dist/esm/shapes/CircleShape.d.ts +3 -4
- package/dist/esm/shapes/CircleShape.d.ts.map +1 -0
- package/dist/esm/shapes/CircleShape.js +27 -26
- package/dist/esm/shapes/CircleShape.js.map +1 -1
- package/dist/esm/shapes/PolygonShape.d.ts +7 -8
- package/dist/esm/shapes/PolygonShape.d.ts.map +1 -0
- package/dist/esm/shapes/PolygonShape.js +131 -162
- package/dist/esm/shapes/PolygonShape.js.map +1 -1
- package/dist/esm/shapes/SegmentShape.d.ts +31 -0
- package/dist/esm/shapes/SegmentShape.d.ts.map +1 -0
- package/dist/esm/shapes/SegmentShape.js +62 -0
- package/dist/esm/shapes/SegmentShape.js.map +1 -0
- package/dist/esm/shapes/Shape.d.ts +28 -17
- package/dist/esm/shapes/Shape.d.ts.map +1 -0
- package/dist/esm/shapes/Shape.js +12 -13
- package/dist/esm/shapes/Shape.js.map +1 -1
- package/dist/esm/shapes/convexParts.d.ts +21 -0
- package/dist/esm/shapes/convexParts.d.ts.map +1 -0
- package/dist/esm/shapes/convexParts.js +26 -0
- package/dist/esm/shapes/convexParts.js.map +1 -0
- package/dist/esm/shapes/decompose.d.ts +24 -0
- package/dist/esm/shapes/decompose.d.ts.map +1 -0
- package/dist/esm/shapes/decompose.js +272 -0
- package/dist/esm/shapes/decompose.js.map +1 -0
- package/dist/esm/shapes/index.d.ts +4 -0
- package/dist/esm/shapes/index.d.ts.map +1 -0
- package/dist/esm/solver/ContactSolver.d.ts +12 -5
- package/dist/esm/solver/ContactSolver.d.ts.map +1 -0
- package/dist/esm/solver/ContactSolver.js +425 -471
- package/dist/esm/solver/ContactSolver.js.map +1 -1
- package/dist/esm/solver/tolerances.d.ts +34 -0
- package/dist/esm/solver/tolerances.d.ts.map +1 -0
- package/dist/esm/solver/tolerances.js +38 -0
- package/dist/esm/solver/tolerances.js.map +1 -0
- package/dist/esm/sort.d.ts +5 -4
- package/dist/esm/sort.d.ts.map +1 -0
- package/dist/esm/sort.js +41 -51
- package/dist/esm/sort.js.map +1 -1
- package/dist/esm/types.d.ts +4 -8
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +15 -17
- package/dist/esm/types.js.map +1 -1
- package/package.json +6 -6
- package/dist/esm/broadphase/SweepAndPrune.d.ts +0 -15
- package/dist/esm/broadphase/SweepAndPrune.js +0 -77
- package/dist/esm/broadphase/SweepAndPrune.js.map +0 -1
- package/dist/esm/debug/index.js.map +0 -1
- package/dist/esm/index.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"narrowphase.js","sources":["../../../../src/collision/narrowphase.ts"],"sourcesContent":[null],"names":[],"mappings":"AAGA,MAAM,GAAG,GAAG,IAAI;AAEhB;;;;;AAKG;AACI,MAAM,OAAO,GAAG,CAAC,CAAiB,EAAE,CAAiB,EAAE,QAAkB,KAAa;IAC3F,QAAQ,CAAC,KAAK,EAAE;AAEhB,IAAA,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI;AACvB,IAAA,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI;AAEvB,IAAA,IAAI,EAAE,KAAK,QAAQ,EAAE;QACnB,OAAO,EAAE,KAAK,QAAQ,GAAG,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,GAAG,oBAAoB,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC;IACvG;IAEA,OAAO,EAAE,KAAK,QAAQ,GAAG,oBAAoB,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC;AACvG;AAEA;AACA;AACA;AACA,MAAM,QAAQ,GAAG,CAAC,QAAwB,MAAc,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;AACrH,MAAM,OAAO,GAAG,CAAC,QAAwB,MAAc,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;AAEpH,MAAM,cAAc,GAAG,CAAC,CAAiB,EAAE,CAAiB,EAAE,QAAkB,KAAa;AAC3F,IAAA,MAAM,EAAE,GAAG,CAAC,CAAC,WAAW;AACxB,IAAA,MAAM,EAAE,GAAG,CAAC,CAAC,WAAW;AACxB,IAAA,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC;AACtB,IAAA,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC;IAEtB,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IACpB,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;AACpB,IAAA,MAAM,IAAI,GAAG,EAAE,GAAG,EAAE;IACpB,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;AAEhC,IAAA,IAAI,MAAM,GAAG,IAAI,GAAG,IAAI,EAAE;AACxB,QAAA,OAAO,KAAK;IACd;IAEA,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AAE9B,IAAA,IAAI,IAAI,GAAG,GAAG,EAAE;QACd,EAAE,IAAI,IAAI;QACV,EAAE,IAAI,IAAI;IACZ;SAAO;QACL,EAAE,GAAG,CAAC;QACN,EAAE,GAAG,CAAC;IACR;AAEA,IAAA,QAAQ,CAAC,OAAO,GAAG,EAAE;AACrB,IAAA,QAAQ,CAAC,OAAO,GAAG,EAAE;IAErB,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;;IAEhC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,GAAG;IACjD,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,GAAG;AACjD,IAAA,KAAK,CAAC,WAAW,GAAG,IAAI,GAAG,IAAI;AAC/B,IAAA,KAAK,CAAC,EAAE,GAAG,CAAC;AACZ,IAAA,QAAQ,CAAC,UAAU,GAAG,CAAC;AAEvB,IAAA,OAAO,IAAI;AACb,CAAC;AAED;;;;AAIG;AACH,MAAM,oBAAoB,GAAG,CAAC,MAAsB,EAAE,OAAuB,EAAE,QAAkB,EAAE,IAAa,KAAa;AAC3H,IAAA,MAAM,CAAC,GAAG,MAAM,CAAC,WAAW;AAC5B,IAAA,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC;AAC1B,IAAA,MAAM,KAAK,GAAG,OAAO,CAAC,aAAa;AACnC,IAAA,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY;AACpC,IAAA,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC;AAE9B,IAAA,IAAI,MAAM,GAAG,CAAC,QAAQ;IACtB,IAAI,OAAO,GAAG,CAAC;AAEf,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE;;QAE9B,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAE;QAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE;QAC/B,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAE;QACzB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE;QAC7B,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;AAE/C,QAAA,IAAI,CAAC,GAAG,CAAC,EAAE;AACT,YAAA,OAAO,KAAK;QACd;AAEA,QAAA,IAAI,CAAC,GAAG,MAAM,EAAE;YACd,MAAM,GAAG,CAAC;YACV,OAAO,GAAG,CAAC;QACb;IACF;;IAGA,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,GAAG,CAAC,CAAE;IACnC,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,CAAE;AAEvC,IAAA,IAAI,EAAU;AACd,IAAA,IAAI,EAAU;AACd,IAAA,IAAI,WAAmB;AACvB,IAAA,IAAI,EAAU;AACd,IAAA,IAAI,EAAU;AACd,IAAA,IAAI,EAAU;AAEd,IAAA,IAAI,MAAM,GAAG,GAAG,EAAE;;QAEhB,EAAE,GAAG,CAAC,KAAK;QACX,EAAE,GAAG,CAAC,KAAK;AACX,QAAA,WAAW,GAAG,CAAC,GAAG,MAAM;QACxB,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC;QACjB,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC;QACjB,EAAE,GAAG,OAAO;IACd;SAAO;QACL,MAAM,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,IAAI,KAAK;QAC/B,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,GAAG,CAAC,CAAE;QAC/B,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,CAAE;QACnC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAE;QACzB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE;AAC7B,QAAA,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,CAAC;AAChE,QAAA,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,CAAC;AAEhE,QAAA,IAAI,EAAE,IAAI,CAAC,EAAE;;AAEX,YAAA,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG;AACpB,YAAA,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG;YACpB,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;AAE5B,YAAA,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE;AACd,gBAAA,OAAO,KAAK;YACd;YAEA,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAEvB,YAAA,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK;AAC/B,YAAA,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK;AAC/B,YAAA,WAAW,GAAG,CAAC,GAAG,CAAC;YACnB,EAAE,GAAG,GAAG;YACR,EAAE,GAAG,GAAG;YACR,EAAE,GAAG,OAAO;QACd;AAAO,aAAA,IAAI,EAAE,IAAI,CAAC,EAAE;AAClB,YAAA,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG;AACpB,YAAA,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG;YACpB,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;AAE5B,YAAA,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE;AACd,gBAAA,OAAO,KAAK;YACd;YAEA,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAEvB,YAAA,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK;AAC/B,YAAA,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK;AAC/B,YAAA,WAAW,GAAG,CAAC,GAAG,CAAC;YACnB,EAAE,GAAG,GAAG;YACR,EAAE,GAAG,GAAG;YACR,EAAE,GAAG,CAAC;QACR;aAAO;;YAEL,EAAE,GAAG,CAAC,KAAK;YACX,EAAE,GAAG,CAAC,KAAK;AACX,YAAA,WAAW,GAAG,CAAC,GAAG,MAAM;YACxB,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC;YACjB,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC;YACjB,EAAE,GAAG,OAAO;QACd;IACF;IAEA,IAAI,IAAI,EAAE;QACR,EAAE,GAAG,CAAC,EAAE;QACR,EAAE,GAAG,CAAC,EAAE;IACV;AAEA,IAAA,QAAQ,CAAC,OAAO,GAAG,EAAE;AACrB,IAAA,QAAQ,CAAC,OAAO,GAAG,EAAE;IAErB,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AAChC,IAAA,KAAK,CAAC,CAAC,GAAG,EAAE;AACZ,IAAA,KAAK,CAAC,CAAC,GAAG,EAAE;AACZ,IAAA,KAAK,CAAC,WAAW,GAAG,WAAW,GAAG,CAAC,GAAG,CAAC,GAAG,WAAW;AACrD,IAAA,KAAK,CAAC,EAAE,GAAG,EAAE;AACb,IAAA,QAAQ,CAAC,UAAU,GAAG,CAAC;AAEvB,IAAA,OAAO,IAAI;AACb,CAAC;AAQD,MAAM,WAAW,GAAG,MAAgC;IAClD,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE;IACrB,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE;CACtB;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,gBAAgB,GAAG,WAAW,EAAE;AACtC,MAAM,gBAAgB,GAAG,WAAW,EAAE;AACtC,MAAM,gBAAgB,GAAG,WAAW,EAAE;AAOtC;AACA,MAAM,KAAK,GAAe,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE;AACpD,MAAM,KAAK,GAAe,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE;AAEpD;AACA,MAAM,iBAAiB,GAAG,CAAC,CAAiB,EAAE,CAAiB,EAAE,GAAe,KAAgB;AAC9F,IAAA,MAAM,EAAE,GAAG,CAAC,CAAC,aAAa;AAC1B,IAAA,MAAM,EAAE,GAAG,CAAC,CAAC,YAAY;AACzB,IAAA,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC;AACrB,IAAA,MAAM,EAAE,GAAG,CAAC,CAAC,aAAa;AAC1B,IAAA,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC;AAErB,IAAA,IAAI,IAAI,GAAG,CAAC,QAAQ;IACpB,IAAI,QAAQ,GAAG,CAAC;AAEhB,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;;QAE3B,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAE;QACrB,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE;QACzB,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAE;QACrB,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE;;QAGzB,IAAI,MAAM,GAAG,QAAQ;QACrB,IAAI,EAAE,GAAG,CAAC;QACV,IAAI,EAAE,GAAG,CAAC;AAEV,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;YAC3B,MAAM,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAE;YACtB,MAAM,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE;YAC1B,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG;AAE7B,YAAA,IAAI,CAAC,GAAG,MAAM,EAAE;gBACd,MAAM,GAAG,CAAC;gBACV,EAAE,GAAG,GAAG;gBACR,EAAE,GAAG,GAAG;YACV;QACF;AAEA,QAAA,MAAM,UAAU,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;AAElD,QAAA,IAAI,UAAU,GAAG,IAAI,EAAE;YACrB,IAAI,GAAG,UAAU;YACjB,QAAQ,GAAG,CAAC;QACd;IACF;AAEA,IAAA,GAAG,CAAC,UAAU,GAAG,IAAI;AACrB,IAAA,GAAG,CAAC,IAAI,GAAG,QAAQ;AAEnB,IAAA,OAAO,GAAG;AACZ,CAAC;AAED;AACA,MAAM,gBAAgB,GAAG,CAAC,KAAa,EAAE,KAAa,EAAE,GAAmB,EAAE,GAA6B,KAAU;AAClH,IAAA,MAAM,EAAE,GAAG,GAAG,CAAC,aAAa;AAC5B,IAAA,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY;AAC7B,IAAA,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;IAEvB,IAAI,MAAM,GAAG,QAAQ;IACrB,IAAI,GAAG,GAAG,CAAC;AAEX,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;QAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAE;QACxB,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE;QAC5B,MAAM,CAAC,GAAG,KAAK,GAAG,GAAG,GAAG,KAAK,GAAG,GAAG;AAEnC,QAAA,IAAI,CAAC,GAAG,MAAM,EAAE;YACd,MAAM,GAAG,CAAC;YACV,GAAG,GAAG,CAAC;QACT;IACF;IAEA,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE;;AAGxB,IAAA,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,GAAG,CAAC,CAAE;AACvB,IAAA,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAE;AAC3B,IAAA,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG;AACf,IAAA,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAE;AACrB,IAAA,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE;AACzB,IAAA,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;AACf,CAAC;AAED;AACA,MAAM,WAAW,GAAG,CAClB,EAAU,EACV,EAAU,EACV,MAAc,EACd,KAAwC,EACxC,MAAgC,EAChC,WAAmB,KACT;;;;AAIV,IAAA,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC;AACpB,IAAA,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC;IACpB,IAAI,KAAK,GAAG,CAAC;AACb,IAAA,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,MAAM;AAC3C,IAAA,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,MAAM;AAE3C,IAAA,IAAI,EAAE,IAAI,CAAC,EAAE;QACX,QAAQ,CAAC,GAAG,EAAE,KAAK,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;AAClD,QAAA,KAAK,EAAE;IACT;AAEA,IAAA,IAAI,EAAE,IAAI,CAAC,EAAE;QACX,QAAQ,CAAC,GAAG,EAAE,KAAK,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;AAClD,QAAA,KAAK,EAAE;IACT;IAEA,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE;QAC5B,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;AAC5B,QAAA,MAAM,MAAM,GAAG,KAAK,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;AAElD,QAAA,MAAM,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AAC1C,QAAA,MAAM,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AAC1C,QAAA,MAAM,CAAC,EAAE,GAAG,WAAW;AACvB,QAAA,KAAK,EAAE;IACT;AAEA,IAAA,OAAO,KAAK;AACd,CAAC;AAED,MAAM,QAAQ,GAAG,CAAC,IAAgB,EAAE,EAAc,KAAU;AAC1D,IAAA,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AACb,IAAA,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AACb,IAAA,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE;AACjB,CAAC;AAED,MAAM,QAAQ,GAAG,CAAC,IAAa,EAAE,OAAe,EAAE,UAAkB,KAClE,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,KAAK,EAAE,CAAC,IAAI,UAAU,GAAG,KAAK,CAAC;AAExE;AACA,MAAM,eAAe,GAAG,CAAC,CAAiB,EAAE,CAAiB,EAAE,QAAkB,KAAa;IAC5F,MAAM,IAAI,GAAG,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC;AAE3C,IAAA,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,EAAE;AACxB,QAAA,OAAO,KAAK;IACd;IAEA,MAAM,IAAI,GAAG,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC;AAE3C,IAAA,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,EAAE;AACxB,QAAA,OAAO,KAAK;IACd;AAEA,IAAA,IAAI,GAAmB;AACvB,IAAA,IAAI,GAAmB;AACvB,IAAA,IAAI,OAAe;AACnB,IAAA,IAAI,IAAa;;;AAIjB,IAAA,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,GAAG,IAAI,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,EAAE;QACtE,GAAG,GAAG,CAAC;QACP,GAAG,GAAG,CAAC;AACP,QAAA,OAAO,GAAG,IAAI,CAAC,IAAI;QACnB,IAAI,GAAG,KAAK;IACd;SAAO;QACL,GAAG,GAAG,CAAC;QACP,GAAG,GAAG,CAAC;AACP,QAAA,OAAO,GAAG,IAAI,CAAC,IAAI;QACnB,IAAI,GAAG,IAAI;IACb;AAEA,IAAA,MAAM,EAAE,GAAG,GAAG,CAAC,aAAa;AAC5B,IAAA,MAAM,EAAE,GAAG,GAAG,CAAC,YAAY;AAC3B,IAAA,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;IACvB,MAAM,EAAE,GAAG,CAAC,OAAO,GAAG,CAAC,IAAI,EAAE;;IAE7B,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,GAAG,CAAC,CAAE;IAC5B,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,CAAE;IAChC,MAAM,GAAG,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,CAAE;IACvB,MAAM,GAAG,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAE;IAC3B,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,GAAG,CAAC,CAAE;IAC9B,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,CAAE;IAElC,MAAM,QAAQ,GAAG,gBAAgB;IACjC,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,CAAC;;AAG7C,IAAA,IAAI,EAAE,GAAG,GAAG,GAAG,GAAG;AAClB,IAAA,IAAI,EAAE,GAAG,GAAG,GAAG,GAAG;;;;AAIlB,IAAA,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IACvC,EAAE,IAAI,EAAE;IACR,EAAE,IAAI,EAAE;AAER,IAAA,MAAM,OAAO,GAAG,EAAE,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC;IACtC,MAAM,OAAO,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG;IAEnC,MAAM,QAAQ,GAAG,gBAAgB;IAEjC,IAAI,WAAW,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE;AAC1F,QAAA,OAAO,KAAK;IACd;IAEA,MAAM,QAAQ,GAAG,gBAAgB;IAEjC,IAAI,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE;AACxF,QAAA,OAAO,KAAK;IACd;AAEA,IAAA,QAAQ,CAAC,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,GAAG,KAAK;AACxC,IAAA,QAAQ,CAAC,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,GAAG,KAAK;IAExC,MAAM,IAAI,GAAG,KAAK,GAAG,GAAG,GAAG,KAAK,GAAG,GAAG;AACtC,IAAA,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM;IAC9B,IAAI,EAAE,GAAG,CAAC;AAEV,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;;AAE1B,QAAA,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;AAC9C,QAAA,MAAM,UAAU,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC,GAAG,IAAI;AAErD,QAAA,IAAI,UAAU,IAAI,CAAC,EAAE;;AAEnB,YAAA,MAAM,KAAK,GAAG,EAAE,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;AAC9C,YAAA,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;AACd,YAAA,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;AACd,YAAA,KAAK,CAAC,WAAW,GAAG,CAAC,UAAU;AAC/B,YAAA,KAAK,CAAC,EAAE,GAAG,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;AACzC,YAAA,EAAE,EAAE;QACN;IACF;AAEA,IAAA,QAAQ,CAAC,UAAU,GAAG,EAAE;IAExB,OAAO,EAAE,GAAG,CAAC;AACf,CAAC;AAED;;;AAGG;MACU,WAAW,GAAG,CAAC,CAAiB,EAAE,CAAiB,KAAa;AAC3E,IAAA,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI;AACvB,IAAA,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI;AAEvB,IAAA,IAAI,EAAE,KAAK,QAAQ,EAAE;AACnB,QAAA,IAAI,EAAE,KAAK,QAAQ,EAAE;AACnB,YAAA,MAAM,EAAE,GAAG,CAAC,CAAC,WAAW;AACxB,YAAA,MAAM,EAAE,GAAG,CAAC,CAAC,WAAW;YACxB,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;YACtC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACtB,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YAEtB,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,IAAI,GAAG,IAAI;QACzC;AAEA,QAAA,OAAO,oBAAoB,CAAC,CAAC,EAAE,CAAC,CAAC;IACnC;AAEA,IAAA,IAAI,EAAE,KAAK,QAAQ,EAAE;AACnB,QAAA,OAAO,oBAAoB,CAAC,CAAC,EAAE,CAAC,CAAC;IACnC;IAEA,OAAO,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,UAAU,GAAG,CAAC,IAAI,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,UAAU,GAAG,CAAC;AACvG;AAEA,MAAM,oBAAoB,GAAG,CAAC,MAAsB,EAAE,OAAuB,KAAa;AACxF,IAAA,MAAM,CAAC,GAAG,MAAM,CAAC,WAAW;AAC5B,IAAA,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC;AAC1B,IAAA,MAAM,KAAK,GAAG,OAAO,CAAC,aAAa;AACnC,IAAA,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY;AACpC,IAAA,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC;AAE9B,IAAA,IAAI,MAAM,GAAG,CAAC,QAAQ;IACtB,IAAI,OAAO,GAAG,CAAC;AAEf,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE;;QAE9B,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAE;QAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE;QAC/B,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAE;QACzB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE;QAC7B,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;AAE/C,QAAA,IAAI,CAAC,GAAG,CAAC,EAAE;AACT,YAAA,OAAO,KAAK;QACd;AAEA,QAAA,IAAI,CAAC,GAAG,MAAM,EAAE;YACd,MAAM,GAAG,CAAC;YACV,OAAO,GAAG,CAAC;QACb;IACF;AAEA,IAAA,IAAI,MAAM,GAAG,GAAG,EAAE;AAChB,QAAA,OAAO,IAAI;IACb;IAEA,MAAM,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,IAAI,KAAK;IAC/B,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,GAAG,CAAC,CAAE;IAC/B,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,CAAE;IACnC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAE;IACzB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE;AAC7B,IAAA,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,CAAC;AAChE,IAAA,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,CAAC;AAEhE,IAAA,IAAI,EAAE,IAAI,CAAC,EAAE;AACX,QAAA,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG;AACpB,QAAA,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG;QAEpB,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC;IACnC;AAEA,IAAA,IAAI,EAAE,IAAI,CAAC,EAAE;AACX,QAAA,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG;AACpB,QAAA,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG;QAEpB,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC;IACnC;IAEA,OAAO,MAAM,IAAI,CAAC;AACpB,CAAC;;;;"}
|
|
1
|
+
{"version":3,"file":"narrowphase.js","names":[],"sources":["../../../src/collision/narrowphase.ts"],"sourcesContent":["import type { PointLike } from '@codexo/exojs';\n\nimport { chainEdgeAdmits } from './chainAdjacency';\nimport type { CollisionProxy } from './CollisionProxy';\nimport type { PairTable } from './dispatch';\nimport { needsFlip, symmetricEntry, symmetricTable } from './dispatch';\nimport type { Manifold } from './Manifold';\nimport { closestPointOnSegment, pointSegmentDistanceSquared } from './segments';\n\nconst eps = 1e-9;\n\n/** Reused closest-point sink; the narrow phase is single-threaded and non-reentrant. */\nconst _segmentScratch: PointLike = { x: 0, y: 0 };\n\n/**\n * Solves one unordered shape pair. `a` is always the operand of the lower shape\n * kind; `flip` is `true` when the caller's operands were swapped to get there,\n * and the routine must reverse the manifold normal so it still points from the\n * caller's `a` toward its `b`.\n */\ntype CollidePair = (a: CollisionProxy, b: CollisionProxy, manifold: Manifold, flip: boolean) => boolean;\n\n/** Boolean form of {@link CollidePair}; no normal, so no flip to honour. */\ntype OverlapPair = (a: CollisionProxy, b: CollisionProxy) => boolean;\n\n/**\n * Generate the contact manifold for `a` vs `b`, writing into `manifold` and\n * returning `true` when the colliders touch. The manifold normal is oriented\n * from `a` toward `b`.\n *\n * A pair with no entry in the table is deliberately unsupported and reports no\n * contact rather than an approximation.\n */\nexport const collide = (a: CollisionProxy, b: CollisionProxy, manifold: Manifold): boolean => {\n manifold.reset();\n\n const ta = a.shape.type;\n const tb = b.shape.type;\n const solver = symmetricEntry(collideTable, ta, tb);\n\n if (solver === undefined) {\n return false;\n }\n\n const touching = needsFlip(ta, tb) ? solver(b, a, manifold, true) : solver(a, b, manifold, false);\n\n if (!touching) {\n return false;\n }\n\n // The manifold normal points a → b, so it is the direction `a` pushes `b`\n // away along; from b's side the outward direction is its negation.\n if (!chainEdgeAdmits(a, manifold.normalX, manifold.normalY) || !chainEdgeAdmits(b, -manifold.normalX, -manifold.normalY)) {\n manifold.reset();\n\n return false;\n }\n\n return true;\n};\n\n// Both helpers stay cast-free and allocation-free. A capsule is a two-vertex\n// ring with a radius, which is exactly why it shares the polygon routines: the\n// ring supplies `count` and `worldVertices`/`worldNormals`, the radius rounds\n// the result off.\nconst radiusOf = (collider: CollisionProxy): number => (collider.shape.type === 'circle' || collider.shape.type === 'capsule' ? collider.shape.radius : 0);\nconst countOf = (collider: CollisionProxy): number => {\n switch (collider.shape.type) {\n case 'polygon':\n return collider.shape.count;\n case 'capsule':\n case 'segment':\n return 2;\n case 'circle':\n case 'chain':\n // A chain is never an operand here - it is solved through its edge proxies.\n return 0;\n }\n};\n\nconst collideCircles: CollidePair = (a, b, manifold) => {\n const ca = a.worldCenter;\n const cb = b.worldCenter;\n const ra = radiusOf(a);\n const rb = radiusOf(b);\n\n let nx = cb.x - ca.x;\n let ny = cb.y - ca.y;\n const rsum = ra + rb;\n const distSq = nx * nx + ny * ny;\n\n if (distSq > rsum * rsum) {\n return false;\n }\n\n const dist = Math.sqrt(distSq);\n\n if (dist > eps) {\n nx /= dist;\n ny /= dist;\n } else {\n nx = 0;\n ny = 1;\n }\n\n manifold.normalX = nx;\n manifold.normalY = ny;\n\n const point = manifold.points[0];\n // Midpoint of the two surface contact points.\n point.x = (ca.x + nx * ra + cb.x - nx * rb) * 0.5;\n point.y = (ca.y + ny * ra + cb.y - ny * rb) * 0.5;\n point.penetration = rsum - dist;\n point.id = 0;\n manifold.pointCount = 1;\n\n return true;\n};\n\n/**\n * Circle (the `circle` collider) vs polygon. Produces the normal pointing from\n * the circle toward the polygon; when `flip` is set (the polygon is collider A),\n * the normal is negated so it stays `a → b`.\n */\nconst collideCirclePolygon: CollidePair = (circle, polygon, manifold, flip) => {\n const c = circle.worldCenter;\n const r = radiusOf(circle);\n const verts = polygon.worldVertices;\n const normals = polygon.worldNormals;\n const count = countOf(polygon);\n\n let maxSep = -Infinity;\n let refEdge = 0;\n\n for (let i = 0; i < count; i++) {\n // Loop indices are provably in-bounds (0..count-1); the `!` is zero-cost.\n const enx = normals[i * 2]!;\n const eny = normals[i * 2 + 1]!;\n const evx = verts[i * 2]!;\n const evy = verts[i * 2 + 1]!;\n const s = enx * (c.x - evx) + eny * (c.y - evy);\n\n if (s > r) {\n return false;\n }\n\n if (s > maxSep) {\n maxSep = s;\n refEdge = i;\n }\n }\n\n // refEdge/j stay in 0..count-1, so these reads are in-bounds too.\n const refNx = normals[refEdge * 2]!;\n const refNy = normals[refEdge * 2 + 1]!;\n\n let nx: number;\n let ny: number;\n let penetration: number;\n let px: number;\n let py: number;\n let id: number;\n\n if (maxSep < eps) {\n // Centre inside the polygon: push out along the least-penetrating face.\n nx = -refNx;\n ny = -refNy;\n penetration = r - maxSep;\n px = c.x + nx * r;\n py = c.y + ny * r;\n id = refEdge;\n } else {\n const j = (refEdge + 1) % count;\n const v1x = verts[refEdge * 2]!;\n const v1y = verts[refEdge * 2 + 1]!;\n const v2x = verts[j * 2]!;\n const v2y = verts[j * 2 + 1]!;\n const u1 = (c.x - v1x) * (v2x - v1x) + (c.y - v1y) * (v2y - v1y);\n const u2 = (c.x - v2x) * (v1x - v2x) + (c.y - v2y) * (v1y - v2y);\n\n if (u1 <= 0) {\n // Nearest feature is vertex v1 (Voronoi corner region).\n const dx = c.x - v1x;\n const dy = c.y - v1y;\n const d2 = dx * dx + dy * dy;\n\n if (d2 > r * r) {\n return false;\n }\n\n const d = Math.sqrt(d2);\n\n nx = d > eps ? -dx / d : -refNx;\n ny = d > eps ? -dy / d : -refNy;\n penetration = r - d;\n px = v1x;\n py = v1y;\n id = refEdge;\n } else if (u2 <= 0) {\n const dx = c.x - v2x;\n const dy = c.y - v2y;\n const d2 = dx * dx + dy * dy;\n\n if (d2 > r * r) {\n return false;\n }\n\n const d = Math.sqrt(d2);\n\n nx = d > eps ? -dx / d : -refNx;\n ny = d > eps ? -dy / d : -refNy;\n penetration = r - d;\n px = v2x;\n py = v2y;\n id = j;\n } else {\n // Face region.\n nx = -refNx;\n ny = -refNy;\n penetration = r - maxSep;\n px = c.x + nx * r;\n py = c.y + ny * r;\n id = refEdge;\n }\n }\n\n if (flip) {\n nx = -nx;\n ny = -ny;\n }\n\n manifold.normalX = nx;\n manifold.normalY = ny;\n\n const point = manifold.points[0];\n point.x = px;\n point.y = py;\n point.penetration = penetration < 0 ? 0 : penetration;\n point.id = id;\n manifold.pointCount = 1;\n\n return true;\n};\n\ninterface ClipVertex {\n x: number;\n y: number;\n id: number;\n}\n\nconst newClipPair = (): [ClipVertex, ClipVertex] => [\n { x: 0, y: 0, id: 0 },\n { x: 0, y: 0, id: 0 },\n];\n\n// Module-local clip scratch reused across collidePolygons calls instead of\n// allocating a fresh pair per contact. The narrow phase is single-threaded and\n// non-reentrant - a world step calls `collide` strictly sequentially per pair,\n// with no nested self-call or async - so module-global scratch is safe and may\n// be shared across worlds (world-isolation.test.ts guards the multi-world\n// invariant). The three pairs MUST stay separate: incident → clipped1 →\n// clipped2 are simultaneously live (each clip reads the previous clip's output).\nconst _incidentScratch = newClipPair();\nconst _clipped1Scratch = newClipPair();\nconst _clipped2Scratch = newClipPair();\n\ninterface Separation {\n separation: number;\n edge: number;\n}\n\n// Two separate scratches: collidePolygons holds sepA and sepB at the same time.\nconst _sepA: Separation = { separation: 0, edge: 0 };\nconst _sepB: Separation = { separation: 0, edge: 0 };\n\n/** Max separation of `b` from any face of `a`, with the supporting face index. Writes into and returns `out` (allocation-free). */\nconst findMaxSeparation = (a: CollisionProxy, b: CollisionProxy, out: Separation): Separation => {\n const av = a.worldVertices;\n const an = a.worldNormals;\n const ac = countOf(a);\n const bv = b.worldVertices;\n const bc = countOf(b);\n\n let best = -Infinity;\n let bestEdge = 0;\n\n for (let i = 0; i < ac; i++) {\n // i in 0..ac-1 and j in 0..bc-1, so every read below is in-bounds.\n const nx = an[i * 2]!;\n const ny = an[i * 2 + 1]!;\n const vx = av[i * 2]!;\n const vy = av[i * 2 + 1]!;\n\n // Support of b along -n = vertex of b minimising dot(n, vertex).\n let minDot = Infinity;\n let sx = 0;\n let sy = 0;\n\n for (let j = 0; j < bc; j++) {\n const bjx = bv[j * 2]!;\n const bjy = bv[j * 2 + 1]!;\n const d = nx * bjx + ny * bjy;\n\n if (d < minDot) {\n minDot = d;\n sx = bjx;\n sy = bjy;\n }\n }\n\n const separation = nx * (sx - vx) + ny * (sy - vy);\n\n if (separation > best) {\n best = separation;\n bestEdge = i;\n }\n }\n\n out.separation = best;\n out.edge = bestEdge;\n\n return out;\n};\n\n/** Incident face of `inc` = the face most anti-parallel to the reference normal. */\nconst findIncidentFace = (refNx: number, refNy: number, inc: CollisionProxy, out: [ClipVertex, ClipVertex]): void => {\n const iv = inc.worldVertices;\n const inrm = inc.worldNormals;\n const ic = countOf(inc);\n\n let minDot = Infinity;\n let idx = 0;\n\n for (let i = 0; i < ic; i++) {\n const inx = inrm[i * 2]!;\n const iny = inrm[i * 2 + 1]!;\n const d = refNx * inx + refNy * iny;\n\n if (d < minDot) {\n minDot = d;\n idx = i;\n }\n }\n\n const j = (idx + 1) % ic;\n\n // idx/j in 0..ic-1; reads in-bounds. out is a fixed 2-tuple.\n out[0].x = iv[idx * 2]!;\n out[0].y = iv[idx * 2 + 1]!;\n out[0].id = idx;\n out[1].x = iv[j * 2]!;\n out[1].y = iv[j * 2 + 1]!;\n out[1].id = j;\n};\n\n/** Clip the 2-vertex segment `input` to the half-plane `dot(n, p) ≤ offset`. */\nconst clipSegment = (\n nx: number,\n ny: number,\n offset: number,\n input: readonly [ClipVertex, ClipVertex],\n output: [ClipVertex, ClipVertex],\n syntheticId: number,\n): number => {\n // input/output are fixed 2-tuples; count never exceeds 2 (two boundary\n // copies, or one copy plus the guarded intersection), so output[0]/output[1]\n // are the only slots written and both always exist.\n const in0 = input[0];\n const in1 = input[1];\n let count = 0;\n const d1 = nx * in0.x + ny * in0.y - offset;\n const d2 = nx * in1.x + ny * in1.y - offset;\n\n if (d1 <= 0) {\n copyClip(in0, count === 0 ? output[0] : output[1]);\n count++;\n }\n\n if (d2 <= 0) {\n copyClip(in1, count === 0 ? output[0] : output[1]);\n count++;\n }\n\n if (d1 * d2 < 0 && count < 2) {\n const alpha = d1 / (d1 - d2);\n const target = count === 0 ? output[0] : output[1];\n\n target.x = in0.x + alpha * (in1.x - in0.x);\n target.y = in0.y + alpha * (in1.y - in0.y);\n target.id = syntheticId;\n count++;\n }\n\n return count;\n};\n\nconst copyClip = (from: ClipVertex, to: ClipVertex): void => {\n to.x = from.x;\n to.y = from.y;\n to.id = from.id;\n};\n\nconst encodeId = (flip: boolean, refEdge: number, incidentId: number): number => (flip ? 1 << 20 : 0) | ((refEdge & 0xff) << 12) | (incidentId & 0xfff);\n\n/**\n * Convex ring vs convex ring: SAT reference face + Sutherland-Hodgman clip, with\n * each operand allowed a radius that rounds its outline off.\n *\n * The separations the SAT computes are between the two **cores**; the radii only\n * move where touching begins, and since both candidate axes shift by the same\n * sum, the reference face the SAT picks is unaffected. A capsule is a two-vertex\n * core with a radius and a polygon a many-vertex core without one, so\n * polygon/polygon, capsule/polygon and capsule/capsule are all this one routine.\n */\nconst collideRoundedPolygons: CollidePair = (a, b, manifold, callerFlip) => {\n const totalRadius = radiusOf(a) + radiusOf(b);\n const sepA = findMaxSeparation(a, b, _sepA);\n\n if (sepA.separation >= totalRadius) {\n return false;\n }\n\n const sepB = findMaxSeparation(b, a, _sepB);\n\n if (sepB.separation >= totalRadius) {\n return false;\n }\n\n let ref: CollisionProxy;\n let inc: CollisionProxy;\n let refEdge: number;\n // Whether the REFERENCE role went to `b`. Distinct from `callerFlip`, which\n // records that the caller's own operands were swapped to reach the canonical\n // order; the final normal has to undo both.\n let refSwapped: boolean;\n\n // Bias toward keeping A as the reference for stability (reduces ref/incident\n // role flapping when a body rocks slightly).\n if (sepA.separation >= sepB.separation * 0.95 + sepA.separation * 0.01) {\n ref = a;\n inc = b;\n refEdge = sepA.edge;\n refSwapped = false;\n } else {\n ref = b;\n inc = a;\n refEdge = sepB.edge;\n refSwapped = true;\n }\n\n const rv = ref.worldVertices;\n const rn = ref.worldNormals;\n const rc = countOf(ref);\n const i2 = (refEdge + 1) % rc;\n // refEdge/i2 in 0..rc-1, so these reads are in-bounds.\n const v1x = rv[refEdge * 2]!;\n const v1y = rv[refEdge * 2 + 1]!;\n const v2x = rv[i2 * 2]!;\n const v2y = rv[i2 * 2 + 1]!;\n const refNx = rn[refEdge * 2]!;\n const refNy = rn[refEdge * 2 + 1]!;\n\n const incident = _incidentScratch;\n findIncidentFace(refNx, refNy, inc, incident);\n\n // Reference-face tangent (the side-plane direction).\n let tx = v2x - v1x;\n let ty = v2y - v1y;\n // sqrt(x²+y²) over Math.hypot - avoids hypot's variadic/internal-allocation\n // path on the narrow-phase hot path; the operands are bounded edge lengths,\n // so the overflow protection hypot adds is not needed here.\n const tl = Math.sqrt(tx * tx + ty * ty);\n tx /= tl;\n ty /= tl;\n\n const negSide = -(tx * v1x + ty * v1y);\n const posSide = tx * v2x + ty * v2y;\n\n const clipped1 = _clipped1Scratch;\n\n if (clipSegment(-tx, -ty, negSide, incident, clipped1, encodeId(refSwapped, refEdge, 0xffe)) < 2) {\n return false;\n }\n\n const clipped2 = _clipped2Scratch;\n\n if (clipSegment(tx, ty, posSide, clipped1, clipped2, encodeId(refSwapped, refEdge, 0xfff)) < 2) {\n return false;\n }\n\n const flipNormal = refSwapped !== callerFlip;\n\n manifold.normalX = flipNormal ? -refNx : refNx;\n manifold.normalY = flipNormal ? -refNy : refNy;\n\n const refC = refNx * v1x + refNy * v1y;\n const incidentRadius = radiusOf(inc);\n const points = manifold.points;\n let cp = 0;\n\n for (let k = 0; k < 2; k++) {\n // clipped2 is a fixed 2-tuple; k in {0,1} so the clip vertex always exists.\n const cv = k === 0 ? clipped2[0] : clipped2[1];\n const separation = refNx * cv.x + refNy * cv.y - refC;\n\n if (separation <= totalRadius) {\n // The clip vertex lies on the incident CORE; pulling it back along the\n // reference normal by the incident radius puts it on that shape's real\n // surface. A radius-free incident polygon shifts by zero, so the point is\n // the clip vertex exactly as it was before capsules existed.\n // cp reaches at most 2 (one per clip vertex); points[0]/points[1] exist.\n const point = cp === 0 ? points[0] : points[1];\n point.x = cv.x - refNx * incidentRadius;\n point.y = cv.y - refNy * incidentRadius;\n point.penetration = totalRadius - separation;\n point.id = encodeId(refSwapped, refEdge, cv.id);\n cp++;\n }\n }\n\n manifold.pointCount = cp;\n\n return cp > 0;\n};\n\n/**\n * Boolean overlap test (no manifold) used by sensors and shape-overlap queries.\n * Exact for the circle/circle, circle/polygon and polygon/polygon pairs.\n */\nexport const testOverlap = (a: CollisionProxy, b: CollisionProxy): boolean => {\n const ta = a.shape.type;\n const tb = b.shape.type;\n const test = symmetricEntry(overlapTable, ta, tb);\n\n if (test === undefined) {\n return false;\n }\n\n return needsFlip(ta, tb) ? test(b, a) : test(a, b);\n};\n\nconst circlesOverlap: OverlapPair = (a, b) => {\n const ca = a.worldCenter;\n const cb = b.worldCenter;\n const rsum = radiusOf(a) + radiusOf(b);\n const dx = cb.x - ca.x;\n const dy = cb.y - ca.y;\n\n return dx * dx + dy * dy <= rsum * rsum;\n};\n\nconst roundedPolygonsOverlap: OverlapPair = (a, b) => {\n const totalRadius = radiusOf(a) + radiusOf(b);\n\n return findMaxSeparation(a, b, _sepA).separation < totalRadius && findMaxSeparation(b, a, _sepB).separation < totalRadius;\n};\n\n/**\n * Circle vs capsule: a capsule is every point within its radius of the spine, so\n * this is a circle/circle test against the spine point nearest the circle centre.\n * One contact point - a circle meets a rounded surface in one place, and a second\n * would be invented noise for the solver.\n */\nconst collideCircleSpine: CollidePair = (circle, spineShape, manifold, flip) => {\n const spine = spineShape.worldVertices;\n const centre = circle.worldCenter;\n const circleRadius = radiusOf(circle);\n const radiusSum = circleRadius + radiusOf(spineShape);\n\n closestPointOnSegment(centre.x, centre.y, spine[0]!, spine[1]!, spine[2]!, spine[3]!, _segmentScratch);\n\n let nx = _segmentScratch.x - centre.x;\n let ny = _segmentScratch.y - centre.y;\n const distanceSquared = nx * nx + ny * ny;\n\n if (distanceSquared > radiusSum * radiusSum) {\n return false;\n }\n\n const distance = Math.sqrt(distanceSquared);\n\n if (distance > eps) {\n nx /= distance;\n ny /= distance;\n } else {\n // Centre exactly on the spine: the direction is undefined, so take the\n // capsule's own side normal. It is stable from frame to frame, which an\n // axis-aligned guess would not be.\n nx = spineShape.worldNormals[0]!;\n ny = spineShape.worldNormals[1]!;\n }\n\n manifold.normalX = flip ? -nx : nx;\n manifold.normalY = flip ? -ny : ny;\n\n const point = manifold.points[0];\n // Midway between the two surfaces along the contact normal.\n const along = circleRadius + (distance - radiusSum) * 0.5;\n\n point.x = centre.x + nx * along;\n point.y = centre.y + ny * along;\n point.penetration = radiusSum - distance;\n point.id = 0;\n manifold.pointCount = 1;\n\n return true;\n};\n\nconst circleSpineOverlap: OverlapPair = (circle, spineShape) => {\n const spine = spineShape.worldVertices;\n const centre = circle.worldCenter;\n const radiusSum = radiusOf(circle) + radiusOf(spineShape);\n\n return pointSegmentDistanceSquared(centre.x, centre.y, spine[0]!, spine[1]!, spine[2]!, spine[3]!, _segmentScratch) <= radiusSum * radiusSum;\n};\n\nconst circlePolygonOverlap: OverlapPair = (circle, polygon) => {\n const c = circle.worldCenter;\n const r = radiusOf(circle);\n const verts = polygon.worldVertices;\n const normals = polygon.worldNormals;\n const count = countOf(polygon);\n\n let maxSep = -Infinity;\n let refEdge = 0;\n\n for (let i = 0; i < count; i++) {\n // Loop indices are provably in-bounds (0..count-1); the `!` is zero-cost.\n const enx = normals[i * 2]!;\n const eny = normals[i * 2 + 1]!;\n const evx = verts[i * 2]!;\n const evy = verts[i * 2 + 1]!;\n const s = enx * (c.x - evx) + eny * (c.y - evy);\n\n if (s > r) {\n return false;\n }\n\n if (s > maxSep) {\n maxSep = s;\n refEdge = i;\n }\n }\n\n if (maxSep < eps) {\n return true;\n }\n\n const j = (refEdge + 1) % count;\n const v1x = verts[refEdge * 2]!;\n const v1y = verts[refEdge * 2 + 1]!;\n const v2x = verts[j * 2]!;\n const v2y = verts[j * 2 + 1]!;\n const u1 = (c.x - v1x) * (v2x - v1x) + (c.y - v1y) * (v2y - v1y);\n const u2 = (c.x - v2x) * (v1x - v2x) + (c.y - v2y) * (v1y - v2y);\n\n if (u1 <= 0) {\n const dx = c.x - v1x;\n const dy = c.y - v1y;\n\n return dx * dx + dy * dy <= r * r;\n }\n\n if (u2 <= 0) {\n const dx = c.x - v2x;\n const dy = c.y - v2y;\n\n return dx * dx + dy * dy <= r * r;\n }\n\n return maxSep <= r;\n};\n\n// Pair tables, built once at module init. Every unordered pair the engine\n// supports appears exactly once; anything absent reports no contact.\nconst collideTable: PairTable<CollidePair> = symmetricTable<CollidePair>([\n ['circle', 'circle', collideCircles],\n ['circle', 'capsule', collideCircleSpine],\n ['circle', 'segment', collideCircleSpine],\n ['circle', 'polygon', collideCirclePolygon],\n ['capsule', 'capsule', collideRoundedPolygons],\n ['capsule', 'segment', collideRoundedPolygons],\n ['capsule', 'polygon', collideRoundedPolygons],\n // segment/segment is deliberately absent - see `collide`.\n ['segment', 'polygon', collideRoundedPolygons],\n ['polygon', 'polygon', collideRoundedPolygons],\n]);\n\nconst overlapTable: PairTable<OverlapPair> = symmetricTable<OverlapPair>([\n ['circle', 'circle', circlesOverlap],\n ['circle', 'capsule', circleSpineOverlap],\n ['circle', 'segment', circleSpineOverlap],\n ['circle', 'polygon', circlePolygonOverlap],\n ['capsule', 'capsule', roundedPolygonsOverlap],\n ['capsule', 'segment', roundedPolygonsOverlap],\n ['capsule', 'polygon', roundedPolygonsOverlap],\n ['segment', 'polygon', roundedPolygonsOverlap],\n ['polygon', 'polygon', roundedPolygonsOverlap],\n]);\n"],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { PointLike } from '@codexo/exojs';
|
|
2
|
+
/**
|
|
3
|
+
* Closest point on the segment `a → b` to `(px, py)`, written into `out`.
|
|
4
|
+
* Returns the parameter along the segment, clamped to `[0, 1]`.
|
|
5
|
+
*/
|
|
6
|
+
export declare const closestPointOnSegment: (px: number, py: number, ax: number, ay: number, bx: number, by: number, out: PointLike) => number;
|
|
7
|
+
/** Squared distance from `(px, py)` to the segment `a → b`. */
|
|
8
|
+
export declare const pointSegmentDistanceSquared: (px: number, py: number, ax: number, ay: number, bx: number, by: number, scratch: PointLike) => number;
|
|
9
|
+
/**
|
|
10
|
+
* Closest points between the segments `a0 → a1` and `b0 → b1`, written into
|
|
11
|
+
* `outA` and `outB`. Returns the squared distance between them.
|
|
12
|
+
*
|
|
13
|
+
* Parallel and overlapping segments have a whole interval of closest pairs; this
|
|
14
|
+
* returns one of them, chosen deterministically. Callers that need a stable
|
|
15
|
+
* two-point manifold for such a case must derive it from the face geometry, not
|
|
16
|
+
* from this single pair.
|
|
17
|
+
*/
|
|
18
|
+
export declare const segmentSegmentDistanceSquared: (a0x: number, a0y: number, a1x: number, a1y: number, b0x: number, b0y: number, b1x: number, b1y: number, outA: PointLike, outB: PointLike) => number;
|
|
19
|
+
//# sourceMappingURL=segments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"segments.d.ts","sourceRoot":"","sources":["../../../src/collision/segments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAW/C;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAAI,IAAI,MAAM,EAAE,IAAI,MAAM,EAAE,IAAI,MAAM,EAAE,IAAI,MAAM,EAAE,IAAI,MAAM,EAAE,IAAI,MAAM,EAAE,KAAK,SAAS,KAAG,MAkB9H,CAAC;AAEF,+DAA+D;AAC/D,eAAO,MAAM,2BAA2B,GAAI,IAAI,MAAM,EAAE,IAAI,MAAM,EAAE,IAAI,MAAM,EAAE,IAAI,MAAM,EAAE,IAAI,MAAM,EAAE,IAAI,MAAM,EAAE,SAAS,SAAS,KAAG,MAOxI,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,GACxC,KAAK,MAAM,EACX,KAAK,MAAM,EACX,KAAK,MAAM,EACX,KAAK,MAAM,EACX,KAAK,MAAM,EACX,KAAK,MAAM,EACX,KAAK,MAAM,EACX,KAAK,MAAM,EACX,MAAM,SAAS,EACf,MAAM,SAAS,KACd,MA4DF,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/collision/segments.ts
|
|
2
|
+
/** Below this squared length a segment is treated as a single point. */
|
|
3
|
+
const degenerateLengthSquared = 1e-12;
|
|
4
|
+
/**
|
|
5
|
+
* Closest point on the segment `a → b` to `(px, py)`, written into `out`.
|
|
6
|
+
* Returns the parameter along the segment, clamped to `[0, 1]`.
|
|
7
|
+
*/
|
|
8
|
+
const closestPointOnSegment = (px, py, ax, ay, bx, by, out) => {
|
|
9
|
+
const ex = bx - ax;
|
|
10
|
+
const ey = by - ay;
|
|
11
|
+
const lengthSquared = ex * ex + ey * ey;
|
|
12
|
+
if (lengthSquared <= degenerateLengthSquared) {
|
|
13
|
+
out.x = ax;
|
|
14
|
+
out.y = ay;
|
|
15
|
+
return 0;
|
|
16
|
+
}
|
|
17
|
+
const t = clamp01(((px - ax) * ex + (py - ay) * ey) / lengthSquared);
|
|
18
|
+
out.x = ax + ex * t;
|
|
19
|
+
out.y = ay + ey * t;
|
|
20
|
+
return t;
|
|
21
|
+
};
|
|
22
|
+
/** Squared distance from `(px, py)` to the segment `a → b`. */
|
|
23
|
+
const pointSegmentDistanceSquared = (px, py, ax, ay, bx, by, scratch) => {
|
|
24
|
+
closestPointOnSegment(px, py, ax, ay, bx, by, scratch);
|
|
25
|
+
const dx = px - scratch.x;
|
|
26
|
+
const dy = py - scratch.y;
|
|
27
|
+
return dx * dx + dy * dy;
|
|
28
|
+
};
|
|
29
|
+
const clamp01 = (value) => {
|
|
30
|
+
if (value < 0) return 0;
|
|
31
|
+
return value > 1 ? 1 : value;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
export { closestPointOnSegment, pointSegmentDistanceSquared };
|
|
36
|
+
//# sourceMappingURL=segments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"segments.js","names":[],"sources":["../../../src/collision/segments.ts"],"sourcesContent":["import type { PointLike } from '@codexo/exojs';\n\n// Closest-feature primitives shared by every rounded shape. A capsule is a\n// segment with a radius and a chain edge is a segment without one, so all of\n// them reduce to these two questions - point-to-segment and segment-to-segment.\n// Kept as free functions taking output sinks, like the transform helpers, so the\n// narrow phase, the queries and the sweep can all use them allocation-free.\n\n/** Below this squared length a segment is treated as a single point. */\nconst degenerateLengthSquared = 1e-12;\n\n/**\n * Closest point on the segment `a → b` to `(px, py)`, written into `out`.\n * Returns the parameter along the segment, clamped to `[0, 1]`.\n */\nexport const closestPointOnSegment = (px: number, py: number, ax: number, ay: number, bx: number, by: number, out: PointLike): number => {\n const ex = bx - ax;\n const ey = by - ay;\n const lengthSquared = ex * ex + ey * ey;\n\n if (lengthSquared <= degenerateLengthSquared) {\n out.x = ax;\n out.y = ay;\n\n return 0;\n }\n\n const t = clamp01(((px - ax) * ex + (py - ay) * ey) / lengthSquared);\n\n out.x = ax + ex * t;\n out.y = ay + ey * t;\n\n return t;\n};\n\n/** Squared distance from `(px, py)` to the segment `a → b`. */\nexport const pointSegmentDistanceSquared = (px: number, py: number, ax: number, ay: number, bx: number, by: number, scratch: PointLike): number => {\n closestPointOnSegment(px, py, ax, ay, bx, by, scratch);\n\n const dx = px - scratch.x;\n const dy = py - scratch.y;\n\n return dx * dx + dy * dy;\n};\n\n/**\n * Closest points between the segments `a0 → a1` and `b0 → b1`, written into\n * `outA` and `outB`. Returns the squared distance between them.\n *\n * Parallel and overlapping segments have a whole interval of closest pairs; this\n * returns one of them, chosen deterministically. Callers that need a stable\n * two-point manifold for such a case must derive it from the face geometry, not\n * from this single pair.\n */\nexport const segmentSegmentDistanceSquared = (\n a0x: number,\n a0y: number,\n a1x: number,\n a1y: number,\n b0x: number,\n b0y: number,\n b1x: number,\n b1y: number,\n outA: PointLike,\n outB: PointLike,\n): number => {\n const dax = a1x - a0x;\n const day = a1y - a0y;\n const dbx = b1x - b0x;\n const dby = b1y - b0y;\n const rx = a0x - b0x;\n const ry = a0y - b0y;\n const aa = dax * dax + day * day;\n const bb = dbx * dbx + dby * dby;\n const f = dbx * rx + dby * ry;\n\n let s: number;\n let t: number;\n\n if (aa <= degenerateLengthSquared && bb <= degenerateLengthSquared) {\n outA.x = a0x;\n outA.y = a0y;\n outB.x = b0x;\n outB.y = b0y;\n\n return rx * rx + ry * ry;\n }\n\n if (aa <= degenerateLengthSquared) {\n s = 0;\n t = clamp01(f / bb);\n } else {\n const c = dax * rx + day * ry;\n\n if (bb <= degenerateLengthSquared) {\n t = 0;\n s = clamp01(-c / aa);\n } else {\n const b = dax * dbx + day * dby;\n const denom = aa * bb - b * b;\n\n // Parallel segments leave `denom` at zero; pinning s = 0 picks the pair at\n // a0, which is deterministic and as good as any other on the interval.\n s = denom > 0 ? clamp01((b * f - c * bb) / denom) : 0;\n t = (b * s + f) / bb;\n\n if (t < 0) {\n t = 0;\n s = clamp01(-c / aa);\n } else if (t > 1) {\n t = 1;\n s = clamp01((b - c) / aa);\n }\n }\n }\n\n outA.x = a0x + dax * s;\n outA.y = a0y + day * s;\n outB.x = b0x + dbx * t;\n outB.y = b0y + dby * t;\n\n const dx = outA.x - outB.x;\n const dy = outA.y - outB.y;\n\n return dx * dx + dy * dy;\n};\n\nconst clamp01 = (value: number): number => {\n if (value < 0) {\n return 0;\n }\n\n return value > 1 ? 1 : value;\n};\n"],"mappings":";;AASA,MAAM,0BAA0B;;;;;AAMhC,MAAa,yBAAyB,IAAY,IAAY,IAAY,IAAY,IAAY,IAAY,QAA2B;CACvI,MAAM,KAAK,KAAK;CAChB,MAAM,KAAK,KAAK;CAChB,MAAM,gBAAgB,KAAK,KAAK,KAAK;CAErC,IAAI,iBAAiB,yBAAyB;EAC5C,IAAI,IAAI;EACR,IAAI,IAAI;EAER,OAAO;CACT;CAEA,MAAM,IAAI,UAAU,KAAK,MAAM,MAAM,KAAK,MAAM,MAAM,aAAa;CAEnE,IAAI,IAAI,KAAK,KAAK;CAClB,IAAI,IAAI,KAAK,KAAK;CAElB,OAAO;AACT;;AAGA,MAAa,+BAA+B,IAAY,IAAY,IAAY,IAAY,IAAY,IAAY,YAA+B;CACjJ,sBAAsB,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,OAAO;CAErD,MAAM,KAAK,KAAK,QAAQ;CACxB,MAAM,KAAK,KAAK,QAAQ;CAExB,OAAO,KAAK,KAAK,KAAK;AACxB;AAoFA,MAAM,WAAW,UAA0B;CACzC,IAAI,QAAQ,GACV,OAAO;CAGT,OAAO,QAAQ,IAAI,IAAI;AACzB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ShapeType } from '../shapes/Shape';
|
|
2
|
+
import type { CollisionProxy } from './CollisionProxy';
|
|
3
|
+
/**
|
|
4
|
+
* First time of impact of a translation-only shape cast, written by
|
|
5
|
+
* {@link sweepProxies} (allocation-free: the caller owns the struct).
|
|
6
|
+
*/
|
|
7
|
+
export interface SweepHit {
|
|
8
|
+
/** Fraction of the motion at first contact, in `(0, 1]`. */
|
|
9
|
+
t: number;
|
|
10
|
+
/** Unit surface normal on the target at the hit, pointing back toward the moving shape (opposing the motion). */
|
|
11
|
+
normalX: number;
|
|
12
|
+
/** See {@link SweepHit.normalX}. */
|
|
13
|
+
normalY: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Translation-only shape cast of `moving` against a static `target`: `moving`
|
|
17
|
+
* is given at its **end-of-motion** pose (its cached world geometry) and is
|
|
18
|
+
* swept from `pose − (dx, dy)` to `pose`. Rotation over the motion is not swept
|
|
19
|
+
* - the moving shape keeps its end orientation for the whole cast, matching the
|
|
20
|
+
* bullet CCD model (the step's rotation is applied before the sweep).
|
|
21
|
+
*
|
|
22
|
+
* Returns `true` with the first time of impact and the target-surface normal
|
|
23
|
+
* written into `out`. Pairs already overlapping (or exactly touching) at the
|
|
24
|
+
* start of the motion return `false` - they cannot tunnel within this motion
|
|
25
|
+
* and the discrete solver owns them. Allocation-free.
|
|
26
|
+
*
|
|
27
|
+
* Boundary geometry (a segment, a chain edge) is a target, never the moving
|
|
28
|
+
* operand: a chain edge blocks a bullet under the same one-sided adjacency rule
|
|
29
|
+
* the discrete narrow phase applies, while a fast segment or chain is not swept
|
|
30
|
+
* at all.
|
|
31
|
+
*/
|
|
32
|
+
export declare const sweepProxies: (moving: CollisionProxy, dx: number, dy: number, target: CollisionProxy, out: SweepHit) => boolean;
|
|
33
|
+
/** `true` when {@link sweepProxies} has an implementation for this ordered pair. */
|
|
34
|
+
export declare const canSweep: (moving: ShapeType, target: ShapeType) => boolean;
|
|
35
|
+
//# sourceMappingURL=sweep.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sweep.d.ts","sourceRoot":"","sources":["../../../src/collision/sweep.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAKvD;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,4DAA4D;IAC5D,CAAC,EAAE,MAAM,CAAC;IACV,iHAAiH;IACjH,OAAO,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;CACjB;AASD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,YAAY,GAAI,QAAQ,cAAc,EAAE,IAAI,MAAM,EAAE,IAAI,MAAM,EAAE,QAAQ,cAAc,EAAE,KAAK,QAAQ,KAAG,OAiBpH,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,QAAQ,GAAI,QAAQ,SAAS,EAAE,QAAQ,SAAS,KAAG,OAAiE,CAAC"}
|
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
import { chainEdgeAdmits } from "./chainAdjacency.js";
|
|
2
|
+
import { orderedEntry, orderedTable } from "./dispatch.js";
|
|
3
|
+
import { pointSegmentDistanceSquared } from "./segments.js";
|
|
4
|
+
|
|
5
|
+
//#region src/collision/sweep.ts
|
|
6
|
+
const eps = 1e-9;
|
|
7
|
+
const _pointScratch = {
|
|
8
|
+
x: 0,
|
|
9
|
+
y: 0
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Translation-only shape cast of `moving` against a static `target`: `moving`
|
|
13
|
+
* is given at its **end-of-motion** pose (its cached world geometry) and is
|
|
14
|
+
* swept from `pose − (dx, dy)` to `pose`. Rotation over the motion is not swept
|
|
15
|
+
* - the moving shape keeps its end orientation for the whole cast, matching the
|
|
16
|
+
* bullet CCD model (the step's rotation is applied before the sweep).
|
|
17
|
+
*
|
|
18
|
+
* Returns `true` with the first time of impact and the target-surface normal
|
|
19
|
+
* written into `out`. Pairs already overlapping (or exactly touching) at the
|
|
20
|
+
* start of the motion return `false` - they cannot tunnel within this motion
|
|
21
|
+
* and the discrete solver owns them. Allocation-free.
|
|
22
|
+
*
|
|
23
|
+
* Boundary geometry (a segment, a chain edge) is a target, never the moving
|
|
24
|
+
* operand: a chain edge blocks a bullet under the same one-sided adjacency rule
|
|
25
|
+
* the discrete narrow phase applies, while a fast segment or chain is not swept
|
|
26
|
+
* at all.
|
|
27
|
+
*/
|
|
28
|
+
const sweepProxies = (moving, dx, dy, target, out) => {
|
|
29
|
+
const cast = orderedEntry(sweepTable, moving.shape.type, target.shape.type);
|
|
30
|
+
if (cast === void 0) return false;
|
|
31
|
+
if (!cast(moving, dx, dy, target, out)) return false;
|
|
32
|
+
return chainEdgeAdmits(target, out.normalX, out.normalY);
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Vertex count of a proxy's **core**: the geometry left once its radius is taken
|
|
36
|
+
* off. A circle is a point (no core ring), a capsule and a segment are both a
|
|
37
|
+
* two-vertex ring - with and without a radius - and a polygon is its own ring.
|
|
38
|
+
*/
|
|
39
|
+
const coreCount = (proxy) => {
|
|
40
|
+
switch (proxy.shape.type) {
|
|
41
|
+
case "polygon": return proxy.shape.count;
|
|
42
|
+
case "capsule":
|
|
43
|
+
case "segment": return 2;
|
|
44
|
+
case "circle":
|
|
45
|
+
case "chain": return 0;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const radiusOf = (proxy) => proxy.shape.type === "circle" || proxy.shape.type === "capsule" ? proxy.shape.radius : 0;
|
|
49
|
+
/** Moving circle vs static circle: a ray against the Minkowski-summed circle. */
|
|
50
|
+
const sweepCircleCircle = (moving, dx, dy, target, out) => {
|
|
51
|
+
const rsum = radiusOf(moving) + radiusOf(target);
|
|
52
|
+
const cx = target.worldCenter.x;
|
|
53
|
+
const cy = target.worldCenter.y;
|
|
54
|
+
const ox = moving.worldCenter.x - dx;
|
|
55
|
+
const oy = moving.worldCenter.y - dy;
|
|
56
|
+
const mx = ox - cx;
|
|
57
|
+
const my = oy - cy;
|
|
58
|
+
if (mx * mx + my * my <= rsum * rsum) return false;
|
|
59
|
+
const a = dx * dx + dy * dy;
|
|
60
|
+
const b = mx * dx + my * dy;
|
|
61
|
+
const c = mx * mx + my * my - rsum * rsum;
|
|
62
|
+
if (b >= 0) return false;
|
|
63
|
+
const disc = b * b - a * c;
|
|
64
|
+
if (disc < 0) return false;
|
|
65
|
+
const t = (-b - Math.sqrt(disc)) / a;
|
|
66
|
+
if (t < 0 || t > 1) return false;
|
|
67
|
+
out.t = t;
|
|
68
|
+
out.normalX = (ox + dx * t - cx) / rsum;
|
|
69
|
+
out.normalY = (oy + dy * t - cy) / rsum;
|
|
70
|
+
return true;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Moving circle vs a static core ring (polygon, capsule or segment): a ray
|
|
74
|
+
* against that ring inflated by both radii - offset faces plus vertex arcs, the
|
|
75
|
+
* exact swept geometry.
|
|
76
|
+
*/
|
|
77
|
+
const sweepCircleRing = (moving, dx, dy, target, out) => {
|
|
78
|
+
const rsum = radiusOf(moving) + radiusOf(target);
|
|
79
|
+
const ox = moving.worldCenter.x - dx;
|
|
80
|
+
const oy = moving.worldCenter.y - dy;
|
|
81
|
+
const verts = target.worldVertices;
|
|
82
|
+
const normals = target.worldNormals;
|
|
83
|
+
const count = coreCount(target);
|
|
84
|
+
if (pointRingDistanceSquared(ox, oy, verts, normals, count) <= rsum * rsum) return false;
|
|
85
|
+
return castPointAtRing(ox, oy, dx, dy, rsum, verts, normals, count, out);
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Moving core ring (polygon or capsule) vs static circle, solved in the moving
|
|
89
|
+
* shape's frame: the circle sweeps backward (`−d`) from a start displaced by
|
|
90
|
+
* `+d`, against the ring's end-pose geometry - the same relative motion, so the
|
|
91
|
+
* same time of impact.
|
|
92
|
+
*/
|
|
93
|
+
const sweepRingCircle = (moving, dx, dy, target, out) => {
|
|
94
|
+
const rsum = radiusOf(moving) + radiusOf(target);
|
|
95
|
+
const ox = target.worldCenter.x + dx;
|
|
96
|
+
const oy = target.worldCenter.y + dy;
|
|
97
|
+
const verts = moving.worldVertices;
|
|
98
|
+
const normals = moving.worldNormals;
|
|
99
|
+
const count = coreCount(moving);
|
|
100
|
+
if (pointRingDistanceSquared(ox, oy, verts, normals, count) <= rsum * rsum) return false;
|
|
101
|
+
if (!castPointAtRing(ox, oy, -dx, -dy, rsum, verts, normals, count, out)) return false;
|
|
102
|
+
out.normalX = -out.normalX;
|
|
103
|
+
out.normalY = -out.normalY;
|
|
104
|
+
return true;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Two core rings of which at least one carries a radius (any pair involving a
|
|
108
|
+
* capsule): built as one configuration-space ring and cast as a point, which is
|
|
109
|
+
* exact where a radius-inflated SAT would square off the rounded corners.
|
|
110
|
+
*/
|
|
111
|
+
const sweepRoundedRings = (moving, dx, dy, target, out) => {
|
|
112
|
+
const rsum = radiusOf(moving) + radiusOf(target);
|
|
113
|
+
if (!buildConfigurationRing(moving, dx, dy, target)) return false;
|
|
114
|
+
const verts = _configurationRing.vertices;
|
|
115
|
+
const normals = _configurationRing.normals;
|
|
116
|
+
const count = _configurationRing.count;
|
|
117
|
+
if (pointRingDistanceSquared(0, 0, verts, normals, count) <= rsum * rsum) return false;
|
|
118
|
+
return castPointAtRing(0, 0, dx, dy, rsum, verts, normals, count, out);
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Cast the point `(ox, oy)` along `(dx, dy)` (t ∈ [0, 1]) against `count`-vertex
|
|
122
|
+
* convex ring inflated by `r`: offset faces plus vertex arcs - the exact swept
|
|
123
|
+
* geometry. Writes the earliest hit into `out`; the normal points from the ring
|
|
124
|
+
* surface toward the point.
|
|
125
|
+
*/
|
|
126
|
+
const castPointAtRing = (ox, oy, dx, dy, r, verts, normals, count, out) => {
|
|
127
|
+
out.t = Infinity;
|
|
128
|
+
castAtOffsetFaces(ox, oy, dx, dy, r, verts, normals, count, out);
|
|
129
|
+
castAtVertexArcs(ox, oy, dx, dy, r, verts, count, out);
|
|
130
|
+
return out.t !== Infinity;
|
|
131
|
+
};
|
|
132
|
+
/** Offset-face pass of {@link castPointAtRing}: the face plane pushed out by `r`, hits valid within the edge span. */
|
|
133
|
+
const castAtOffsetFaces = (ox, oy, dx, dy, r, verts, normals, count, out) => {
|
|
134
|
+
for (let i = 0; i < count; i++) {
|
|
135
|
+
const nx = normals[i * 2];
|
|
136
|
+
const ny = normals[i * 2 + 1];
|
|
137
|
+
const denom = nx * dx + ny * dy;
|
|
138
|
+
if (denom >= 0) continue;
|
|
139
|
+
const v1x = verts[i * 2];
|
|
140
|
+
const v1y = verts[i * 2 + 1];
|
|
141
|
+
const t = (nx * (v1x - ox) + ny * (v1y - oy) + r) / denom;
|
|
142
|
+
if (t < 0 || t > 1 || t >= out.t) continue;
|
|
143
|
+
const j = (i + 1) % count;
|
|
144
|
+
const v2x = verts[j * 2];
|
|
145
|
+
const v2y = verts[j * 2 + 1];
|
|
146
|
+
const ex = v2x - v1x;
|
|
147
|
+
const ey = v2y - v1y;
|
|
148
|
+
const px = ox + dx * t;
|
|
149
|
+
const py = oy + dy * t;
|
|
150
|
+
const u = (px - v1x) * ex + (py - v1y) * ey;
|
|
151
|
+
if (u < 0 || u > ex * ex + ey * ey) continue;
|
|
152
|
+
out.t = t;
|
|
153
|
+
out.normalX = nx;
|
|
154
|
+
out.normalY = ny;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
/** Vertex-arc pass of {@link castPointAtRing}: a ray against the circle of radius `r` around each vertex. */
|
|
158
|
+
const castAtVertexArcs = (ox, oy, dx, dy, r, verts, count, out) => {
|
|
159
|
+
if (r <= 0) return;
|
|
160
|
+
const a = dx * dx + dy * dy;
|
|
161
|
+
for (let i = 0; i < count; i++) {
|
|
162
|
+
const vx = verts[i * 2];
|
|
163
|
+
const vy = verts[i * 2 + 1];
|
|
164
|
+
const mx = ox - vx;
|
|
165
|
+
const my = oy - vy;
|
|
166
|
+
const b = mx * dx + my * dy;
|
|
167
|
+
if (b >= 0) continue;
|
|
168
|
+
const c = mx * mx + my * my - r * r;
|
|
169
|
+
if (c < 0) continue;
|
|
170
|
+
const disc = b * b - a * c;
|
|
171
|
+
if (disc < 0) continue;
|
|
172
|
+
const t = (-b - Math.sqrt(disc)) / a;
|
|
173
|
+
if (t < 0 || t > 1 || t >= out.t) continue;
|
|
174
|
+
out.t = t;
|
|
175
|
+
out.normalX = (ox + dx * t - vx) / r;
|
|
176
|
+
out.normalY = (oy + dy * t - vy) / r;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* Squared distance from `(px, py)` to a convex core ring, `0` inside it. A
|
|
181
|
+
* two-vertex ring has no interior, so it is always the distance to the segment.
|
|
182
|
+
*/
|
|
183
|
+
const pointRingDistanceSquared = (px, py, verts, normals, count) => {
|
|
184
|
+
if (count >= 3) {
|
|
185
|
+
let inside = true;
|
|
186
|
+
for (let i = 0; i < count && inside; i++) inside = normals[i * 2] * (px - verts[i * 2]) + normals[i * 2 + 1] * (py - verts[i * 2 + 1]) <= 0;
|
|
187
|
+
if (inside) return 0;
|
|
188
|
+
}
|
|
189
|
+
let best = Infinity;
|
|
190
|
+
for (let i = 0; i < count; i++) {
|
|
191
|
+
const j = (i + 1) % count;
|
|
192
|
+
const distance = pointSegmentDistanceSquared(px, py, verts[i * 2], verts[i * 2 + 1], verts[j * 2], verts[j * 2 + 1], _pointScratch);
|
|
193
|
+
best = distance < best ? distance : best;
|
|
194
|
+
}
|
|
195
|
+
return best;
|
|
196
|
+
};
|
|
197
|
+
const _configurationRing = {
|
|
198
|
+
vertices: [],
|
|
199
|
+
normals: [],
|
|
200
|
+
count: 0
|
|
201
|
+
};
|
|
202
|
+
const _sumPoints = [];
|
|
203
|
+
const _sumOrder = [];
|
|
204
|
+
const _hull = [];
|
|
205
|
+
/**
|
|
206
|
+
* Build the pair's configuration-space obstacle into {@link _configurationRing}:
|
|
207
|
+
* the Minkowski sum of the target's core and the negated start-pose core of the
|
|
208
|
+
* moving shape. A translational cast of the pair is then a cast of the origin
|
|
209
|
+
* point against that single ring, inflated by the two radii - which is why every
|
|
210
|
+
* rounded pair reduces to {@link castPointAtRing} instead of its own algorithm.
|
|
211
|
+
*/
|
|
212
|
+
const buildConfigurationRing = (moving, dx, dy, target) => {
|
|
213
|
+
const movingCount = coreCount(moving);
|
|
214
|
+
const targetCount = coreCount(target);
|
|
215
|
+
if (movingCount < 2 || targetCount < 2) return false;
|
|
216
|
+
const movingVerts = moving.worldVertices;
|
|
217
|
+
const targetVerts = target.worldVertices;
|
|
218
|
+
const total = movingCount * targetCount;
|
|
219
|
+
grow(_sumPoints, total * 2);
|
|
220
|
+
grow(_sumOrder, total);
|
|
221
|
+
for (let j = 0, k = 0; j < targetCount; j++) for (let i = 0; i < movingCount; i++, k++) {
|
|
222
|
+
_sumPoints[k * 2] = targetVerts[j * 2] - (movingVerts[i * 2] - dx);
|
|
223
|
+
_sumPoints[k * 2 + 1] = targetVerts[j * 2 + 1] - (movingVerts[i * 2 + 1] - dy);
|
|
224
|
+
_sumOrder[k] = k;
|
|
225
|
+
}
|
|
226
|
+
const count = convexHull(total);
|
|
227
|
+
if (count < 2) return false;
|
|
228
|
+
grow(_configurationRing.vertices, count * 2);
|
|
229
|
+
grow(_configurationRing.normals, count * 2);
|
|
230
|
+
_configurationRing.count = count;
|
|
231
|
+
const verts = _configurationRing.vertices;
|
|
232
|
+
const normals = _configurationRing.normals;
|
|
233
|
+
for (let i = 0; i < count; i++) {
|
|
234
|
+
const point = _hull[i];
|
|
235
|
+
verts[i * 2] = _sumPoints[point * 2];
|
|
236
|
+
verts[i * 2 + 1] = _sumPoints[point * 2 + 1];
|
|
237
|
+
}
|
|
238
|
+
for (let i = 0; i < count; i++) {
|
|
239
|
+
const j = (i + 1) % count;
|
|
240
|
+
const ex = verts[j * 2] - verts[i * 2];
|
|
241
|
+
const ey = verts[j * 2 + 1] - verts[i * 2 + 1];
|
|
242
|
+
const length = Math.sqrt(ex * ex + ey * ey) || 1;
|
|
243
|
+
normals[i * 2] = ey / length;
|
|
244
|
+
normals[i * 2 + 1] = -ex / length;
|
|
245
|
+
}
|
|
246
|
+
return true;
|
|
247
|
+
};
|
|
248
|
+
/**
|
|
249
|
+
* Counter-clockwise convex hull of the first `total` points in
|
|
250
|
+
* {@link _sumPoints} (Andrew's monotone chain), written as point indices into
|
|
251
|
+
* {@link _hull}; returns the hull size. Collinear points are dropped, so a
|
|
252
|
+
* degenerate sum - two parallel spines - comes out as a two-vertex ring rather
|
|
253
|
+
* than a zero-area polygon.
|
|
254
|
+
*/
|
|
255
|
+
const convexHull = (total) => {
|
|
256
|
+
for (let i = 1; i < total; i++) {
|
|
257
|
+
const value = _sumOrder[i];
|
|
258
|
+
let j = i - 1;
|
|
259
|
+
while (j >= 0 && comparePoints(_sumOrder[j], value) > 0) {
|
|
260
|
+
_sumOrder[j + 1] = _sumOrder[j];
|
|
261
|
+
j--;
|
|
262
|
+
}
|
|
263
|
+
_sumOrder[j + 1] = value;
|
|
264
|
+
}
|
|
265
|
+
grow(_hull, total * 2 + 1);
|
|
266
|
+
let size = 0;
|
|
267
|
+
for (let i = 0; i < total; i++) size = pushHullPoint(_sumOrder[i], size, 2);
|
|
268
|
+
const upperFloor = size + 1;
|
|
269
|
+
for (let i = total - 2; i >= 0; i--) size = pushHullPoint(_sumOrder[i], size, upperFloor);
|
|
270
|
+
return size > 1 ? size - 1 : size;
|
|
271
|
+
};
|
|
272
|
+
/** One monotone-chain step: drop hull points that a left turn onto `point` makes interior. */
|
|
273
|
+
const pushHullPoint = (point, size, floor) => {
|
|
274
|
+
while (size >= floor && cross(_hull[size - 2], _hull[size - 1], point) <= 0) size--;
|
|
275
|
+
_hull[size] = point;
|
|
276
|
+
return size + 1;
|
|
277
|
+
};
|
|
278
|
+
const comparePoints = (a, b) => {
|
|
279
|
+
const ax = _sumPoints[a * 2];
|
|
280
|
+
const bx = _sumPoints[b * 2];
|
|
281
|
+
if (ax !== bx) return ax < bx ? -1 : 1;
|
|
282
|
+
const ay = _sumPoints[a * 2 + 1];
|
|
283
|
+
const by = _sumPoints[b * 2 + 1];
|
|
284
|
+
if (ay === by) return 0;
|
|
285
|
+
return ay < by ? -1 : 1;
|
|
286
|
+
};
|
|
287
|
+
/** Cross product of `o → a` and `o → b`; positive for a counter-clockwise turn. */
|
|
288
|
+
const cross = (o, a, b) => {
|
|
289
|
+
const ox = _sumPoints[o * 2];
|
|
290
|
+
const oy = _sumPoints[o * 2 + 1];
|
|
291
|
+
return (_sumPoints[a * 2] - ox) * (_sumPoints[b * 2 + 1] - oy) - (_sumPoints[a * 2 + 1] - oy) * (_sumPoints[b * 2] - ox);
|
|
292
|
+
};
|
|
293
|
+
/** Extend a scratch array to `length`, keeping it a plain packed number array. */
|
|
294
|
+
const grow = (array, length) => {
|
|
295
|
+
while (array.length < length) array.push(0);
|
|
296
|
+
};
|
|
297
|
+
const _satState = {
|
|
298
|
+
tEnter: 0,
|
|
299
|
+
tLeave: 0,
|
|
300
|
+
normalX: 0,
|
|
301
|
+
normalY: 0
|
|
302
|
+
};
|
|
303
|
+
/**
|
|
304
|
+
* Two radius-free core rings (polygon or segment) via swept SAT: for every
|
|
305
|
+
* candidate axis (both rings' face normals) intersect the moving projection
|
|
306
|
+
* interval with the static one over t ∈ [0, 1]; the latest entry over all axes
|
|
307
|
+
* is the time of impact, and its axis (oriented against the motion) the normal.
|
|
308
|
+
* Exact for linear motion of convex shapes.
|
|
309
|
+
*/
|
|
310
|
+
const sweepRings = (moving, dx, dy, target, out) => {
|
|
311
|
+
const state = _satState;
|
|
312
|
+
state.tEnter = -Infinity;
|
|
313
|
+
state.tLeave = Infinity;
|
|
314
|
+
if (!sweptSatAxes(target, moving, dx, dy, target, state) || !sweptSatAxes(moving, moving, dx, dy, target, state)) return false;
|
|
315
|
+
if (state.tEnter <= 0 || state.tEnter > 1) return false;
|
|
316
|
+
out.t = state.tEnter;
|
|
317
|
+
out.normalX = state.normalX;
|
|
318
|
+
out.normalY = state.normalY;
|
|
319
|
+
return true;
|
|
320
|
+
};
|
|
321
|
+
/**
|
|
322
|
+
* One swept-SAT axis pass over `axisOwner`'s face normals, tightening the
|
|
323
|
+
* `state` entry/exit window of `moving` (translated by `(dx, dy)`, given at its
|
|
324
|
+
* end pose) against the static `target`. Returns `false` as soon as an axis
|
|
325
|
+
* proves the shapes never meet within the motion.
|
|
326
|
+
*/
|
|
327
|
+
const sweptSatAxes = (axisOwner, moving, dx, dy, target, state) => {
|
|
328
|
+
const axes = axisOwner.worldNormals;
|
|
329
|
+
const axisCount = coreCount(axisOwner);
|
|
330
|
+
const mv = moving.worldVertices;
|
|
331
|
+
const mc = coreCount(moving);
|
|
332
|
+
const tv = target.worldVertices;
|
|
333
|
+
const tc = coreCount(target);
|
|
334
|
+
for (let i = 0; i < axisCount; i++) {
|
|
335
|
+
const nx = axes[i * 2];
|
|
336
|
+
const ny = axes[i * 2 + 1];
|
|
337
|
+
const dn = nx * dx + ny * dy;
|
|
338
|
+
let minA = Infinity;
|
|
339
|
+
let maxA = -Infinity;
|
|
340
|
+
for (let k = 0; k < mc; k++) {
|
|
341
|
+
const p = nx * mv[k * 2] + ny * mv[k * 2 + 1];
|
|
342
|
+
minA = p < minA ? p : minA;
|
|
343
|
+
maxA = p > maxA ? p : maxA;
|
|
344
|
+
}
|
|
345
|
+
minA -= dn;
|
|
346
|
+
maxA -= dn;
|
|
347
|
+
let minB = Infinity;
|
|
348
|
+
let maxB = -Infinity;
|
|
349
|
+
for (let k = 0; k < tc; k++) {
|
|
350
|
+
const p = nx * tv[k * 2] + ny * tv[k * 2 + 1];
|
|
351
|
+
minB = p < minB ? p : minB;
|
|
352
|
+
maxB = p > maxB ? p : maxB;
|
|
353
|
+
}
|
|
354
|
+
if (dn > -1e-9 && dn < eps) {
|
|
355
|
+
if (maxA <= minB || maxB <= minA) return false;
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
const t0 = (minB - maxA) / dn;
|
|
359
|
+
const t1 = (maxB - minA) / dn;
|
|
360
|
+
const entry = t0 < t1 ? t0 : t1;
|
|
361
|
+
const exit = t0 < t1 ? t1 : t0;
|
|
362
|
+
if (entry > state.tEnter) {
|
|
363
|
+
state.tEnter = entry;
|
|
364
|
+
state.normalX = dn < 0 ? nx : -nx;
|
|
365
|
+
state.normalY = dn < 0 ? ny : -ny;
|
|
366
|
+
}
|
|
367
|
+
if (exit < state.tLeave) state.tLeave = exit;
|
|
368
|
+
if (state.tEnter >= state.tLeave) return false;
|
|
369
|
+
}
|
|
370
|
+
return true;
|
|
371
|
+
};
|
|
372
|
+
const sweepTable = orderedTable([
|
|
373
|
+
[
|
|
374
|
+
"circle",
|
|
375
|
+
"circle",
|
|
376
|
+
sweepCircleCircle
|
|
377
|
+
],
|
|
378
|
+
[
|
|
379
|
+
"circle",
|
|
380
|
+
"capsule",
|
|
381
|
+
sweepCircleRing
|
|
382
|
+
],
|
|
383
|
+
[
|
|
384
|
+
"circle",
|
|
385
|
+
"segment",
|
|
386
|
+
sweepCircleRing
|
|
387
|
+
],
|
|
388
|
+
[
|
|
389
|
+
"circle",
|
|
390
|
+
"polygon",
|
|
391
|
+
sweepCircleRing
|
|
392
|
+
],
|
|
393
|
+
[
|
|
394
|
+
"capsule",
|
|
395
|
+
"circle",
|
|
396
|
+
sweepRingCircle
|
|
397
|
+
],
|
|
398
|
+
[
|
|
399
|
+
"capsule",
|
|
400
|
+
"capsule",
|
|
401
|
+
sweepRoundedRings
|
|
402
|
+
],
|
|
403
|
+
[
|
|
404
|
+
"capsule",
|
|
405
|
+
"segment",
|
|
406
|
+
sweepRoundedRings
|
|
407
|
+
],
|
|
408
|
+
[
|
|
409
|
+
"capsule",
|
|
410
|
+
"polygon",
|
|
411
|
+
sweepRoundedRings
|
|
412
|
+
],
|
|
413
|
+
[
|
|
414
|
+
"polygon",
|
|
415
|
+
"circle",
|
|
416
|
+
sweepRingCircle
|
|
417
|
+
],
|
|
418
|
+
[
|
|
419
|
+
"polygon",
|
|
420
|
+
"capsule",
|
|
421
|
+
sweepRoundedRings
|
|
422
|
+
],
|
|
423
|
+
[
|
|
424
|
+
"polygon",
|
|
425
|
+
"segment",
|
|
426
|
+
sweepRings
|
|
427
|
+
],
|
|
428
|
+
[
|
|
429
|
+
"polygon",
|
|
430
|
+
"polygon",
|
|
431
|
+
sweepRings
|
|
432
|
+
]
|
|
433
|
+
]);
|
|
434
|
+
|
|
435
|
+
//#endregion
|
|
436
|
+
export { sweepProxies };
|
|
437
|
+
//# sourceMappingURL=sweep.js.map
|