diff --git a/.gitattributes b/.gitattributes index f0bfce3..15d06a7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ -/Users/ryanlu/Downloads/Projects/mbus-backend-dev/src/assets/walkingCache.json filter=lfs diff=lfs merge=lfs -text -src/assets/walkingCache.json filter=lfs diff=lfs merge=lfs -text +src/assets/ann_arbor.ch.json filter=lfs diff=lfs merge=lfs -text +src/assets/walking-shortcuts.json filter=lfs diff=lfs merge=lfs -text diff --git a/docs/assets/hierarchy.js b/docs/assets/hierarchy.js index c11396f..5795d92 100644 --- a/docs/assets/hierarchy.js +++ b/docs/assets/hierarchy.js @@ -1 +1 @@ -window.hierarchyData = "eJyVjjEOgzAMRe/iOVAFVAbO0LFbhVAKpkQNCXLcoULcvU5VVYwwWfr28/sLUAgcob7pomwUEA4OO7bBS7aAhGl4MyHUcMEHKHha30NdnCsFL3ISW89Ig+kwnsjMHKjl94wxl/N85MkJ0zkT5SFw7LPEZ38mLUfrekL/LVEpXepmVaKuNuqrnZDN3eHBDltuR5nkLfXWS8bHAemQ88fs8a3rB573gTo=" \ No newline at end of file +window.hierarchyData = "eJyVjsEKgzAMht8l5+pQdILPsONuQ6TTOMtqK2l2GOK7Lx1jeNRT4E++fP8C5D0HqG9ZUTQKCAeLHRvvJFtAwjicnhBquOADFDyN66HOy7OCF1mJjWOkQXcYTqRn9tTye8aQynk68mSF6awO8hA49Enkkz8Tl6OxPaH7lqhUVubNqkRdbdRXMyHru8WDHbbcjjLRW+ZbL2kXBqRDzh+zx7euH7EegUw=" \ No newline at end of file diff --git a/docs/assets/navigation.js b/docs/assets/navigation.js index ee9438b..c0e8c52 100644 --- a/docs/assets/navigation.js +++ b/docs/assets/navigation.js @@ -1 +1 @@ -window.navigationData = "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" \ No newline at end of file +window.navigationData = "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" \ No newline at end of file diff --git a/docs/assets/search.js b/docs/assets/search.js index 474edbc..cc8204a 100644 --- a/docs/assets/search.js +++ b/docs/assets/search.js @@ -1 +1 @@ -window.searchData = "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"; \ No newline at end of file +window.searchData = "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"; \ No newline at end of file diff --git a/docs/classes/raptor_McRaptorAlgorithm.McRaptorAlgorithm.html b/docs/classes/raptor_McRaptorAlgorithm.McRaptorAlgorithm.html deleted file mode 100644 index 2ebb4a4..0000000 --- a/docs/classes/raptor_McRaptorAlgorithm.McRaptorAlgorithm.html +++ /dev/null @@ -1,30 +0,0 @@ -McRaptorAlgorithm | mbus-backend
mbus-backend
    Preparing search index...

    Implementation of the McRAPTOR (Multi-Criteria Round-Based Public Transit Routing) algorithm. -Optimizes for arrival time, walking distance, and number of transfers.

    -
    Index

    Constructors

    Methods

    • Calculates optimal journeys for a specific departure time.

      -

      Parameters

      • origin: string

        The starting Stop ID.

        -
      • destination: string

        The destination Stop ID.

        -
      • departureTime: number

        The exact departure time.

        -

      Returns Journey[]

      A list of optimal Journey objects.

      -
    • Finds the best journeys within a time window, filtering for Pareto optimality across all departures.

      -

      Parameters

      • origin: string

        The starting Stop ID.

        -
      • destination: string

        The destination Stop ID.

        -
      • startTime: number

        The start of the departure window.

        -
      • range: number

        The duration of the window to search (e.g. 3600s).

        -

      Returns Journey[]

      A deduplicated list of the best journeys found in the time range.

      -
    • Executes the McRAPTOR algorithm to find all non-dominated paths to the destination.

      -

      Parameters

      • origin: string

        The starting Stop ID.

        -
      • destination: string

        The destination Stop ID.

        -
      • departureTime: number

        The time of departure.

        -

      Returns Bag

      A Bag containing Pareto-optimal labels for the destination.

      -
    • Sets the penalty multiplier for walking (default is 1).

      -

      Parameters

      • penalty: number

        The multiplier for walking duration cost.

        -

      Returns void

    diff --git a/docs/classes/raptor_McRaptorAlgorithm.McRaptorIndex.html b/docs/classes/raptor_McRaptorAlgorithm.McRaptorIndex.html new file mode 100644 index 0000000..a880762 --- /dev/null +++ b/docs/classes/raptor_McRaptorAlgorithm.McRaptorIndex.html @@ -0,0 +1,6 @@ +McRaptorIndex | mbus-backend
    mbus-backend
      Preparing search index...

      Pre-built route indices for McRAPTOR. Rebuilt when the transit graph trips change.

      +
      Index

      Methods

      diff --git a/docs/classes/raptor_McStructs.Bag.html b/docs/classes/raptor_McStructs.Bag.html index 7463c61..0503392 100644 --- a/docs/classes/raptor_McStructs.Bag.html +++ b/docs/classes/raptor_McStructs.Bag.html @@ -1,13 +1,13 @@ Bag | mbus-backend
      mbus-backend
        Preparing search index...

        A container for Labels at a specific stop that maintains a Pareto frontier. Only keeps labels that are not dominated by any other label in the bag.

        -
        Index

        Constructors

        Index

        Constructors

        Properties

        Methods

        Constructors

        Properties

        labels: Label[] = []

        Methods

        • Attempts to add a label to the bag.

          +

        Constructors

        Properties

        labels: Label[] = []

        Methods

        • Attempts to add a label to the bag.

          Parameters

          Returns boolean

          True if the label was added (it was non-dominated), False otherwise.

          -
        • Merges another bag's labels into this one.

          Parameters

          Returns boolean

          True if the merge resulted in any changes to this bag.

          -
        +
        diff --git a/docs/classes/raptor_McStructs.Label.html b/docs/classes/raptor_McStructs.Label.html index ca4ff9f..d702653 100644 --- a/docs/classes/raptor_McStructs.Label.html +++ b/docs/classes/raptor_McStructs.Label.html @@ -1,6 +1,6 @@ Label | mbus-backend
        mbus-backend
          Preparing search index...

          Represents a state or arrival at a specific stop in the routing graph. Used to trace back the path and store performance metrics.

          -
          Index

          Constructors

          Index

          Constructors

          Properties

          arrivalTime enterTime parent @@ -21,16 +21,16 @@
        • stop: string | null = null

          The ID of the current stop.

        • enterTime: number = 0

          Time when the passenger boarded the vehicle.

        • stopIndex: number = -1

          Index of the current stop in the trip's sequence.

          -
        • Returns Label

          Properties

          arrivalTime: number

          Time of arrival at this stop.

          -
          enterTime: number = 0

          Time when the passenger boarded the vehicle.

          -
          parent: Label | null = null

          The previous label in the chain (used for backtracking).

          -
          stop: string | null = null

          The ID of the current stop.

          -
          stopIndex: number = -1

          Index of the current stop in the trip's sequence.

          -
          transfer: Transfer | null = null

          The transfer used to reach this state (if applicable).

          -
          transferCount: number

          Number of transfers taken so far.

          -
          trip: Trip | null = null

          The trip taken to reach this state (if applicable).

          -
          walkingDistance: number

          Cumulative walking distance in meters.

          -

          Methods

          • Determines if this label is strictly better than another label. +

          Returns Label

          Properties

          arrivalTime: number

          Time of arrival at this stop.

          +
          enterTime: number = 0

          Time when the passenger boarded the vehicle.

          +
          parent: Label | null = null

          The previous label in the chain (used for backtracking).

          +
          stop: string | null = null

          The ID of the current stop.

          +
          stopIndex: number = -1

          Index of the current stop in the trip's sequence.

          +
          transfer: Transfer | null = null

          The transfer used to reach this state (if applicable).

          +
          transferCount: number

          Number of transfers taken so far.

          +
          trip: Trip | null = null

          The trip taken to reach this state (if applicable).

          +
          walkingDistance: number

          Cumulative walking distance in meters.

          +

          Methods

          • Determines if this label is strictly better than another label. A label dominates if it is better or equal in all criteria and strictly better in at least one.

            -

            Parameters

            Returns boolean

          +

          Parameters

          Returns boolean

          diff --git a/docs/classes/walking_contractionHierarchy.ContractionHierarchyGraph.html b/docs/classes/walking_contractionHierarchy.ContractionHierarchyGraph.html new file mode 100644 index 0000000..18da5e6 --- /dev/null +++ b/docs/classes/walking_contractionHierarchy.ContractionHierarchyGraph.html @@ -0,0 +1,21 @@ +ContractionHierarchyGraph | mbus-backend
          mbus-backend
            Preparing search index...
            Index

            Constructors

            Properties

            _currentEdgeIndex: number = -1
            _currentNodeIndex: number = -1
            _edgeProperties: ChEdgeProperties[] = []
            _indexToNodeLookup: Record<number, string> = {}
            _locked: boolean = false
            _maxUncontractedEdgeIndex: number = 0
            _nodeToIndexLookup: Record<string, number> = {}
            adjacency_list: ChAdjEdge[][] = []
            contracted_nodes: number[] = []
            debugMode: boolean = false
            reverse_adjacency_list: ChAdjEdge[][] = []

            Accessors

            • get nodeCount(): number

              Returns number

            Methods

            • Parameters

              • start: string
              • end: string
              • properties: { _cost: number; _id: number }
              • isUndirected: boolean = true

              Returns void

            • Returns void

            • Parameters

              • Optionaloptions: PathfinderOptions

              Returns { queryContractionHierarchy: (start: string, end: string) => ChQueryResult }

            • Parameters

              • json: string | SerializedChGraph

              Returns void

            • PHAST: one upward Dijkstra + linear downward scan (one-to-many / one-to-all on CH).

              +

              Parameters

              • origin: number
              • Optionaltargets: Set<number>

              Returns Map<number, number>

            • Returns string

            diff --git a/docs/functions/jobs.startBackgroundJobs.html b/docs/functions/jobs.startBackgroundJobs.html index 2eed3bd..32b1e56 100644 --- a/docs/functions/jobs.startBackgroundJobs.html +++ b/docs/functions/jobs.startBackgroundJobs.html @@ -1,2 +1,2 @@ startBackgroundJobs | mbus-backend
            mbus-backend
              Preparing search index...

              Function startBackgroundJobs

              • Starts background jobs for updating bus positions, initializing routes, and rebuilding the graph.

                -

                Returns void

              +

              Returns void

              diff --git a/docs/functions/raptor_McRaptorAlgorithm.buildQueryOverlay.html b/docs/functions/raptor_McRaptorAlgorithm.buildQueryOverlay.html new file mode 100644 index 0000000..5b81aab --- /dev/null +++ b/docs/functions/raptor_McRaptorAlgorithm.buildQueryOverlay.html @@ -0,0 +1,2 @@ +buildQueryOverlay | mbus-backend
              mbus-backend
                Preparing search index...
                • Build per-query transfer overlay from walking access results.

                  +

                  Parameters

                  • walksFromOrigin: { duration: number; stopId: string }[]
                  • walksToDest: { duration: number; stopId: string }[]
                  • departureTime: number

                  Returns McRaptorQueryOverlay

                diff --git a/docs/functions/routes_api.activeRemindersForToken.html b/docs/functions/routes_api.activeRemindersForToken.html index af2db27..f0a3a67 100644 --- a/docs/functions/routes_api.activeRemindersForToken.html +++ b/docs/functions/routes_api.activeRemindersForToken.html @@ -1,3 +1,3 @@ activeRemindersForToken | mbus-backend
                mbus-backend
                  Preparing search index...

                  Function activeRemindersForToken

                  • Parameters

                    • req: Request

                      Express request, token is path encoded

                    • res: Response<{ reminders: ActiveReminderInfo[] }>

                      Express response

                      -

                    Returns void

                  +

                  Returns void

                  diff --git a/docs/functions/routes_api.getAllPredictions.html b/docs/functions/routes_api.getAllPredictions.html index 8b3990a..8a62539 100644 --- a/docs/functions/routes_api.getAllPredictions.html +++ b/docs/functions/routes_api.getAllPredictions.html @@ -2,4 +2,4 @@

                  Parameters

                  Returns void

                  JSON array of objects, each with vid and stops (predictions).

                  -
                  +
                  diff --git a/docs/functions/routes_api.getAllRideRoutes.html b/docs/functions/routes_api.getAllRideRoutes.html index 23cfae4..a83f533 100644 --- a/docs/functions/routes_api.getAllRideRoutes.html +++ b/docs/functions/routes_api.getAllRideRoutes.html @@ -2,4 +2,4 @@

                  Parameters

                  Returns void

                  JSON object with routes mapping route IDs to patterns.

                  -
                  +
                  diff --git a/docs/functions/routes_api.getAllRideStops.html b/docs/functions/routes_api.getAllRideStops.html index ba9acd2..c02b789 100644 --- a/docs/functions/routes_api.getAllRideStops.html +++ b/docs/functions/routes_api.getAllRideStops.html @@ -2,4 +2,4 @@

                  Parameters

                  Returns void

                  JSON array of stop objects.

                  -
                  +
                  diff --git a/docs/functions/routes_api.getAllRoutes.html b/docs/functions/routes_api.getAllRoutes.html index f764bd9..964b342 100644 --- a/docs/functions/routes_api.getAllRoutes.html +++ b/docs/functions/routes_api.getAllRoutes.html @@ -2,4 +2,4 @@

                  Parameters

                  Returns void

                  JSON object with routes mapping route IDs to patterns.

                  -
                  +
                  diff --git a/docs/functions/routes_api.getAllStops.html b/docs/functions/routes_api.getAllStops.html index c997411..1838911 100644 --- a/docs/functions/routes_api.getAllStops.html +++ b/docs/functions/routes_api.getAllStops.html @@ -2,4 +2,4 @@

                  Parameters

                  Returns void

                  JSON array of stop objects.

                  -
                  +
                  diff --git a/docs/functions/routes_api.getBuildingLocations.html b/docs/functions/routes_api.getBuildingLocations.html index bd10bd4..bf791d0 100644 --- a/docs/functions/routes_api.getBuildingLocations.html +++ b/docs/functions/routes_api.getBuildingLocations.html @@ -2,4 +2,4 @@

                  Parameters

                  Returns void

                  JSON file containing building data.

                  -
                  +
                  diff --git a/docs/functions/routes_api.getBusPositions.html b/docs/functions/routes_api.getBusPositions.html index 4f304a7..5f7cdd9 100644 --- a/docs/functions/routes_api.getBusPositions.html +++ b/docs/functions/routes_api.getBusPositions.html @@ -2,4 +2,4 @@

                  Parameters

                  Returns void

                  JSON object with buses array.

                  -
                  +
                  diff --git a/docs/functions/routes_api.getBusPredictions.html b/docs/functions/routes_api.getBusPredictions.html index 8e85c0b..7afa4b4 100644 --- a/docs/functions/routes_api.getBusPredictions.html +++ b/docs/functions/routes_api.getBusPredictions.html @@ -2,4 +2,4 @@

                  Parameters

                  Returns void

                  JSON object with bustime-response containing prd (predictions).

                  -
                  +
                  diff --git a/docs/functions/routes_api.getBusPredictionsLegacy.html b/docs/functions/routes_api.getBusPredictionsLegacy.html index bb8f4b8..64f5bc0 100644 --- a/docs/functions/routes_api.getBusPredictionsLegacy.html +++ b/docs/functions/routes_api.getBusPredictionsLegacy.html @@ -1,4 +1,4 @@ getBusPredictionsLegacy | mbus-backend
                  mbus-backend
                    Preparing search index...

                    Function getBusPredictionsLegacy

                    • Legacy/test endpoint for bus predictions.

                      Parameters

                      • req: Request

                        Express request

                      • res: Response

                        Express response

                        -

                      Returns void

                    +

                    Returns void

                    diff --git a/docs/functions/routes_api.getFrontendData.html b/docs/functions/routes_api.getFrontendData.html index cd99eab..f4083db 100644 --- a/docs/functions/routes_api.getFrontendData.html +++ b/docs/functions/routes_api.getFrontendData.html @@ -2,4 +2,4 @@

                    Parameters

                    Returns void

                    JSON object with routes (array of route details) and metadata.

                    -
                    +
                    diff --git a/docs/functions/routes_api.getKeyStops.html b/docs/functions/routes_api.getKeyStops.html index 0aaba13..c172724 100644 --- a/docs/functions/routes_api.getKeyStops.html +++ b/docs/functions/routes_api.getKeyStops.html @@ -2,4 +2,4 @@

                    Parameters

                    Returns void

                    JSON object with message details.

                    -
                    +
                    diff --git a/docs/functions/routes_api.getNearestStops.html b/docs/functions/routes_api.getNearestStops.html index e360e8b..aa1dde0 100644 --- a/docs/functions/routes_api.getNearestStops.html +++ b/docs/functions/routes_api.getNearestStops.html @@ -2,4 +2,4 @@

                    Parameters

                    Returns void

                    JSON object with nearestStops array.

                    -
                    +
                    diff --git a/docs/functions/routes_api.getRidePositions.html b/docs/functions/routes_api.getRidePositions.html index 9c4abad..04d7b37 100644 --- a/docs/functions/routes_api.getRidePositions.html +++ b/docs/functions/routes_api.getRidePositions.html @@ -2,4 +2,4 @@

                    Parameters

                    Returns void

                    JSON object with buses array.

                    -
                    +
                    diff --git a/docs/functions/routes_api.getRidePredictions.html b/docs/functions/routes_api.getRidePredictions.html index a91929a..07ef718 100644 --- a/docs/functions/routes_api.getRidePredictions.html +++ b/docs/functions/routes_api.getRidePredictions.html @@ -2,4 +2,4 @@

                    Parameters

                    Returns void

                    JSON object with bustime-response containing prd (predictions).

                    -
                    +
                    diff --git a/docs/functions/routes_api.getRideStopPredictions.html b/docs/functions/routes_api.getRideStopPredictions.html index ca779c0..af6408d 100644 --- a/docs/functions/routes_api.getRideStopPredictions.html +++ b/docs/functions/routes_api.getRideStopPredictions.html @@ -2,4 +2,4 @@

                    Parameters

                    Returns void

                    JSON object with bustime-response containing prd (predictions).

                    -
                    +
                    diff --git a/docs/functions/routes_api.getRouteCache.html b/docs/functions/routes_api.getRouteCache.html index 5e3222b..8027a97 100644 --- a/docs/functions/routes_api.getRouteCache.html +++ b/docs/functions/routes_api.getRouteCache.html @@ -2,4 +2,4 @@

                    Parameters

                    Returns void

                    JSON object with routes containing timing data.

                    -
                    +
                    diff --git a/docs/functions/routes_api.getRouteColor.html b/docs/functions/routes_api.getRouteColor.html index 2b49c96..f8eaeb0 100644 --- a/docs/functions/routes_api.getRouteColor.html +++ b/docs/functions/routes_api.getRouteColor.html @@ -2,4 +2,4 @@

                    Parameters

                    Returns void

                    JSON object with routeId, color, and image.

                    -
                    +
                    diff --git a/docs/functions/routes_api.getRouteColors.html b/docs/functions/routes_api.getRouteColors.html index 25a616d..eae1215 100644 --- a/docs/functions/routes_api.getRouteColors.html +++ b/docs/functions/routes_api.getRouteColors.html @@ -2,4 +2,4 @@

                    Parameters

                    Returns void

                    JSON object with a routes array containing route configs.

                    -
                    +
                    diff --git a/docs/functions/routes_api.getRouteInfoVersion.html b/docs/functions/routes_api.getRouteInfoVersion.html index 5623b6d..4b1028e 100644 --- a/docs/functions/routes_api.getRouteInfoVersion.html +++ b/docs/functions/routes_api.getRouteInfoVersion.html @@ -2,4 +2,4 @@

                    Parameters

                    Returns void

                    JSON object with the version string.

                    -
                    +
                    diff --git a/docs/functions/routes_api.getRouteInformation.html b/docs/functions/routes_api.getRouteInformation.html index a583c28..02911ab 100644 --- a/docs/functions/routes_api.getRouteInformation.html +++ b/docs/functions/routes_api.getRouteInformation.html @@ -2,4 +2,4 @@

                    Parameters

                    Returns void

                    JSON object containing routeIdToName, routeImages, metadata, and routeColors.

                    -
                    +
                    diff --git a/docs/functions/routes_api.getSelectableRoutes.html b/docs/functions/routes_api.getSelectableRoutes.html index 253334e..40f2d3c 100644 --- a/docs/functions/routes_api.getSelectableRoutes.html +++ b/docs/functions/routes_api.getSelectableRoutes.html @@ -2,4 +2,4 @@

                    Parameters

                    Returns void

                    JSON object with a bustime-response containing a list of routes.

                    -
                    +
                    diff --git a/docs/functions/routes_api.getStartupInfo.html b/docs/functions/routes_api.getStartupInfo.html index 5a12518..9a7efbc 100644 --- a/docs/functions/routes_api.getStartupInfo.html +++ b/docs/functions/routes_api.getStartupInfo.html @@ -2,4 +2,4 @@

                    Parameters

                    Returns void

                    JSON object with version info and messages.

                    -
                    +
                    diff --git a/docs/functions/routes_api.getStartupMessages.html b/docs/functions/routes_api.getStartupMessages.html index df88d25..90f7588 100644 --- a/docs/functions/routes_api.getStartupMessages.html +++ b/docs/functions/routes_api.getStartupMessages.html @@ -2,4 +2,4 @@

                    Parameters

                    Returns void

                    JSON object with message details.

                    -
                    +
                    diff --git a/docs/functions/routes_api.getStopPredictions.html b/docs/functions/routes_api.getStopPredictions.html index ff7f2ec..cd6ad90 100644 --- a/docs/functions/routes_api.getStopPredictions.html +++ b/docs/functions/routes_api.getStopPredictions.html @@ -2,4 +2,4 @@

                    Parameters

                    Returns void

                    JSON object with bustime-response containing prd (predictions).

                    -
                    +
                    diff --git a/docs/functions/routes_api.getVehicleImage.html b/docs/functions/routes_api.getVehicleImage.html index d7d2c1c..d0e1213 100644 --- a/docs/functions/routes_api.getVehicleImage.html +++ b/docs/functions/routes_api.getVehicleImage.html @@ -2,4 +2,4 @@

                    Parameters

                    Returns void

                    Image file (PNG).

                    -
                    +
                    diff --git a/docs/functions/routes_api.getVehiclePositions.html b/docs/functions/routes_api.getVehiclePositions.html index bb3d311..22751c1 100644 --- a/docs/functions/routes_api.getVehiclePositions.html +++ b/docs/functions/routes_api.getVehiclePositions.html @@ -2,4 +2,4 @@

                    Parameters

                    Returns void

                    JSON object with buses array.

                    -
                    +
                    diff --git a/docs/functions/routes_api.modifyReminders.html b/docs/functions/routes_api.modifyReminders.html index 7d03dcd..cdb20a5 100644 --- a/docs/functions/routes_api.modifyReminders.html +++ b/docs/functions/routes_api.modifyReminders.html @@ -1,4 +1,4 @@ modifyReminders | mbus-backend
                    mbus-backend
                      Preparing search index...

                      Function modifyReminders

                      • Lets you run the equivalent of several setReminder and unsetReminders in one call

                        Parameters

                        • req: Request

                          Express request expecting ModifyRemindersBody in body

                        • res: Response

                          Express response

                          -

                        Returns void

                      +

                      Returns void

                      diff --git a/docs/functions/routes_api.notifyMeLater.html b/docs/functions/routes_api.notifyMeLater.html index 7035476..b58e1f3 100644 --- a/docs/functions/routes_api.notifyMeLater.html +++ b/docs/functions/routes_api.notifyMeLater.html @@ -1 +1 @@ -notifyMeLater | mbus-backend
                      mbus-backend
                        Preparing search index...

                        Function notifyMeLater

                        • Parameters

                          • req: Request
                          • res: Response

                          Returns void

                        +notifyMeLater | mbus-backend
                        mbus-backend
                          Preparing search index...

                          Function notifyMeLater

                          • Parameters

                            • req: Request
                            • res: Response

                            Returns void

                          diff --git a/docs/functions/routes_api.planJourney.html b/docs/functions/routes_api.planJourney.html index 73be18d..844451f 100644 --- a/docs/functions/routes_api.planJourney.html +++ b/docs/functions/routes_api.planJourney.html @@ -2,4 +2,4 @@

                          Parameters

                          Returns Promise<void>

                          JSON object with journeys array containing possible routes.

                          -
                          +
                          diff --git a/docs/functions/routes_api.saveGraph.html b/docs/functions/routes_api.saveGraph.html index 2dbfb87..a98b6bc 100644 --- a/docs/functions/routes_api.saveGraph.html +++ b/docs/functions/routes_api.saveGraph.html @@ -2,4 +2,4 @@

                          Parameters

                          Returns Promise<void>

                          JSON message confirming the save path.

                          -
                          +
                          diff --git a/docs/functions/routes_api.setReminder.html b/docs/functions/routes_api.setReminder.html index 0903168..e02500d 100644 --- a/docs/functions/routes_api.setReminder.html +++ b/docs/functions/routes_api.setReminder.html @@ -1,3 +1,3 @@ setReminder | mbus-backend
                          mbus-backend
                            Preparing search index...

                            Function setReminder

                            • Parameters

                              • req: Request

                                Express request, expects SetReminderBody in the body

                              • res: Response

                                Express response, error message as string if error occurs

                                -

                              Returns void

                            +

                            Returns void

                            diff --git a/docs/functions/routes_api.swapToken.html b/docs/functions/routes_api.swapToken.html index d624bfc..0246980 100644 --- a/docs/functions/routes_api.swapToken.html +++ b/docs/functions/routes_api.swapToken.html @@ -2,4 +2,4 @@
                          • res: Response

                            Express response, error message as string if error occurs

                            Upon responding with 200, future calls to /setReminder, /unsetReminder, and /activeReminders will need the new token

                            -
                          • Returns void

                            +

                            Returns void

                            diff --git a/docs/functions/routes_api.unsetReminder.html b/docs/functions/routes_api.unsetReminder.html index 64bb8e6..670c70d 100644 --- a/docs/functions/routes_api.unsetReminder.html +++ b/docs/functions/routes_api.unsetReminder.html @@ -1,3 +1,3 @@ unsetReminder | mbus-backend
                            mbus-backend
                              Preparing search index...

                              Function unsetReminder

                              • Parameters

                                • req: Request

                                  Express request, UnsetReminderBody in the body

                                • res: Response

                                  Express response, error message as string if error occurs

                                  -

                                Returns void

                              +

                              Returns void

                              diff --git a/docs/functions/services_graphBuilder.findNearestStops.html b/docs/functions/services_graphBuilder.findNearestStops.html index 845e914..86317de 100644 --- a/docs/functions/services_graphBuilder.findNearestStops.html +++ b/docs/functions/services_graphBuilder.findNearestStops.html @@ -1,2 +1,2 @@ findNearestStops | mbus-backend
                              mbus-backend
                                Preparing search index...

                                Function findNearestStops

                                • Finds the nearest k stops to a given coordinate.

                                  -

                                  Parameters

                                  • lat: number
                                  • lon: number
                                  • k: number = 2

                                  Returns { distance: number; lat: number; lon: number; name: string; stpid: string }[]

                                +

                                Parameters

                                Returns { distance: number; lat: number; lon: number; name: string; stpid: string }[]

                                diff --git a/docs/functions/services_graphBuilder.initializeRoutes.html b/docs/functions/services_graphBuilder.initializeRoutes.html index 0be282b..d858dc3 100644 --- a/docs/functions/services_graphBuilder.initializeRoutes.html +++ b/docs/functions/services_graphBuilder.initializeRoutes.html @@ -1,2 +1,2 @@ initializeRoutes | mbus-backend
                                mbus-backend
                                  Preparing search index...

                                  Function initializeRoutes

                                  • Initializes route data, caching patterns and stop locations.

                                    -

                                    Returns Promise<void>

                                  +

                                  Returns Promise<void>

                                  diff --git a/docs/functions/services_graphBuilder.rebuildGraph.html b/docs/functions/services_graphBuilder.rebuildGraph.html index eef8bcb..a1e8502 100644 --- a/docs/functions/services_graphBuilder.rebuildGraph.html +++ b/docs/functions/services_graphBuilder.rebuildGraph.html @@ -1,2 +1,2 @@ rebuildGraph | mbus-backend
                                  mbus-backend
                                    Preparing search index...
                                    • Rebuilds the routing graph based on current predictions and static data.

                                      -

                                      Returns Promise<void>

                                    +

                                    Returns Promise<void>

                                    diff --git a/docs/functions/services_graphBuilder.saveGraphState.html b/docs/functions/services_graphBuilder.saveGraphState.html index 36d84c0..b2cb8f7 100644 --- a/docs/functions/services_graphBuilder.saveGraphState.html +++ b/docs/functions/services_graphBuilder.saveGraphState.html @@ -1,2 +1,2 @@ saveGraphState | mbus-backend
                                    mbus-backend
                                      Preparing search index...
                                      • Saves the current graph and state to a JSON file (DEV mode only).

                                        -

                                        Returns string

                                      +

                                      Returns string

                                      diff --git a/docs/functions/services_graphBuilder.sortPreds.html b/docs/functions/services_graphBuilder.sortPreds.html index d9e28f5..c667dee 100644 --- a/docs/functions/services_graphBuilder.sortPreds.html +++ b/docs/functions/services_graphBuilder.sortPreds.html @@ -1,2 +1,2 @@ sortPreds | mbus-backend
                                      mbus-backend
                                        Preparing search index...
                                        +

                                        Parameters

                                        Returns void

                                        diff --git a/docs/functions/services_graphBuilder.updateBusPositions.html b/docs/functions/services_graphBuilder.updateBusPositions.html index 914fac7..14f3286 100644 --- a/docs/functions/services_graphBuilder.updateBusPositions.html +++ b/docs/functions/services_graphBuilder.updateBusPositions.html @@ -1,2 +1,2 @@ updateBusPositions | mbus-backend
                                        mbus-backend
                                          Preparing search index...

                                          Function updateBusPositions

                                          • Fetches and updates current bus positions in state.

                                            -

                                            Returns Promise<void>

                                          +

                                          Returns Promise<void>

                                          diff --git a/docs/functions/services_journey.planJourney.html b/docs/functions/services_journey.planJourney.html index c3c51ec..f2ffc87 100644 --- a/docs/functions/services_journey.planJourney.html +++ b/docs/functions/services_journey.planJourney.html @@ -1,8 +1,2 @@ planJourney | mbus-backend
                                          mbus-backend
                                            Preparing search index...

                                            Function planJourney

                                            • Plans a journey between two coordinates using the McRaptor algorithm.

                                              -

                                              Parameters

                                              • oLat: number

                                                Origin latitude

                                                -
                                              • oLon: number

                                                Origin longitude

                                                -
                                              • dLat: number

                                                Destination latitude

                                                -
                                              • dLon: number

                                                Destination longitude

                                                -
                                              • time: number

                                                Start time in seconds since midnight

                                                -
                                              • options: { range?: number; walkingPenalty?: number }

                                                Optional parameters for walking penalty and search range

                                                -

                                              Returns Promise<
                                                  (
                                                      | {
                                                          arrivalTime: number;
                                                          criteria: {
                                                              arrivalTime: number;
                                                              transferCount: number;
                                                              walkingDistance: number;
                                                          };
                                                          departureTime: number;
                                                          legs: any[];
                                                      }
                                                      | null
                                                  )[],
                                              >

                                            +

                                            Parameters

                                            Returns Promise<
                                                (
                                                    | {
                                                        arrivalTime: number;
                                                        criteria: {
                                                            arrivalTime: number;
                                                            transferCount: number;
                                                            walkingDistance: number;
                                                        };
                                                        departureTime: number;
                                                        legs: any[];
                                                    }
                                                    | null
                                                )[],
                                            >

                                            diff --git a/docs/functions/services_mbus.fetchPatterns.html b/docs/functions/services_mbus.fetchPatterns.html index 3d27eac..18ff102 100644 --- a/docs/functions/services_mbus.fetchPatterns.html +++ b/docs/functions/services_mbus.fetchPatterns.html @@ -1,2 +1,2 @@ fetchPatterns | mbus-backend
                                            mbus-backend
                                              Preparing search index...

                                              Function fetchPatterns

                                              • Fetches route patterns (path points) for a specific route.

                                                -

                                                Parameters

                                                • rt: string

                                                Returns Promise<any>

                                              +

                                              Parameters

                                              Returns Promise<any>

                                              diff --git a/docs/functions/services_mbus.fetchPredictions.html b/docs/functions/services_mbus.fetchPredictions.html index b8b7d84..8df6a9f 100644 --- a/docs/functions/services_mbus.fetchPredictions.html +++ b/docs/functions/services_mbus.fetchPredictions.html @@ -1,2 +1,2 @@ fetchPredictions | mbus-backend
                                              mbus-backend
                                                Preparing search index...

                                                Function fetchPredictions

                                                • Fetches predictions for multiple stop IDs.

                                                  -

                                                  Parameters

                                                  • stopIds: string[]
                                                  • routes: string[]

                                                  Returns Promise<any[]>

                                                +

                                                Parameters

                                                Returns Promise<any[]>

                                                diff --git a/docs/functions/services_mbus.fetchRoutes.html b/docs/functions/services_mbus.fetchRoutes.html index 3a62cea..127e8c6 100644 --- a/docs/functions/services_mbus.fetchRoutes.html +++ b/docs/functions/services_mbus.fetchRoutes.html @@ -1,2 +1,2 @@ fetchRoutes | mbus-backend
                                                mbus-backend
                                                  Preparing search index...

                                                  Function fetchRoutes

                                                  • Fetches all available routes.

                                                    -

                                                    Returns Promise<any>

                                                  +

                                                  Returns Promise<any>

                                                  diff --git a/docs/functions/services_mbus.fetchVehicles.html b/docs/functions/services_mbus.fetchVehicles.html index 9bd7543..c3b2d90 100644 --- a/docs/functions/services_mbus.fetchVehicles.html +++ b/docs/functions/services_mbus.fetchVehicles.html @@ -1,2 +1,2 @@ fetchVehicles | mbus-backend
                                                  mbus-backend
                                                    Preparing search index...

                                                    Function fetchVehicles

                                                    • Fetches vehicle positions for the given routes.

                                                      -

                                                      Parameters

                                                      • routes: string[]

                                                      Returns Promise<any[]>

                                                    +

                                                    Parameters

                                                    Returns Promise<any[]>

                                                    diff --git a/docs/functions/services_metadata.getAllRouteConfig.html b/docs/functions/services_metadata.getAllRouteConfig.html index 68c8d0c..3ab4af0 100644 --- a/docs/functions/services_metadata.getAllRouteConfig.html +++ b/docs/functions/services_metadata.getAllRouteConfig.html @@ -1,2 +1,2 @@ getAllRouteConfig | mbus-backend
                                                    mbus-backend
                                                      Preparing search index...

                                                      Function getAllRouteConfig

                                                      • Returns configuration for all routes.

                                                        -

                                                        Returns { color: string; image: string; routeId: string }[]

                                                      +

                                                      Returns { color: string; image: string; routeId: string }[]

                                                      diff --git a/docs/functions/services_metadata.getRouteColor.html b/docs/functions/services_metadata.getRouteColor.html index 4a6765a..2c68d36 100644 --- a/docs/functions/services_metadata.getRouteColor.html +++ b/docs/functions/services_metadata.getRouteColor.html @@ -1,2 +1,2 @@ getRouteColor | mbus-backend
                                                      mbus-backend
                                                        Preparing search index...

                                                        Function getRouteColor

                                                        • Gets the color for a specific route ID.

                                                          -

                                                          Parameters

                                                          • routeId: string

                                                          Returns string | null

                                                        +

                                                        Parameters

                                                        Returns string | null

                                                        diff --git a/docs/functions/services_metadata.getRouteImage.html b/docs/functions/services_metadata.getRouteImage.html index 1bfc935..8b8d093 100644 --- a/docs/functions/services_metadata.getRouteImage.html +++ b/docs/functions/services_metadata.getRouteImage.html @@ -1,2 +1,2 @@ getRouteImage | mbus-backend
                                                        mbus-backend
                                                          Preparing search index...

                                                          Function getRouteImage

                                                          • Gets the image filename for a specific route ID.

                                                            -

                                                            Parameters

                                                            • routeId: string

                                                            Returns string | null

                                                          +

                                                          Parameters

                                                          Returns string | null

                                                          diff --git a/docs/functions/services_reminder.eventsEqual.html b/docs/functions/services_reminder.eventsEqual.html index 0f538f6..7e58aa4 100644 --- a/docs/functions/services_reminder.eventsEqual.html +++ b/docs/functions/services_reminder.eventsEqual.html @@ -1 +1 @@ -eventsEqual | mbus-backend
                                                          mbus-backend
                                                            Preparing search index...

                                                            Function eventsEqual

                                                            +eventsEqual | mbus-backend
                                                            mbus-backend
                                                              Preparing search index...

                                                              Function eventsEqual

                                                              diff --git a/docs/functions/services_reminder.infoToUseForRoute.html b/docs/functions/services_reminder.infoToUseForRoute.html index 6677cfb..96fa10b 100644 --- a/docs/functions/services_reminder.infoToUseForRoute.html +++ b/docs/functions/services_reminder.infoToUseForRoute.html @@ -1 +1 @@ -infoToUseForRoute | mbus-backend
                                                              mbus-backend
                                                                Preparing search index...

                                                                Function infoToUseForRoute

                                                                • Parameters

                                                                  • rtid: string

                                                                  Returns
                                                                      | {
                                                                          predsByStopId: Record<string, Prediction[]>;
                                                                          predsByVid: Record<string, Prediction[]>;
                                                                          reminderSubscriptions: ReminderSubscriptions;
                                                                      }
                                                                      | null

                                                                +infoToUseForRoute | mbus-backend
                                                                mbus-backend
                                                                  Preparing search index...

                                                                  Function infoToUseForRoute

                                                                  • Parameters

                                                                    • rtid: string

                                                                    Returns
                                                                        | {
                                                                            predsByStopId: Record<string, Prediction[]>;
                                                                            predsByVid: Record<string, Prediction[]>;
                                                                            reminderSubscriptions: ReminderSubscriptions;
                                                                        }
                                                                        | null

                                                                  diff --git a/docs/functions/services_reminder.processRideReminders.html b/docs/functions/services_reminder.processRideReminders.html index 562319d..88d26a7 100644 --- a/docs/functions/services_reminder.processRideReminders.html +++ b/docs/functions/services_reminder.processRideReminders.html @@ -1 +1 @@ -processRideReminders | mbus-backend
                                                                  mbus-backend
                                                                    Preparing search index...

                                                                    Function processRideReminders

                                                                    +processRideReminders | mbus-backend
                                                                    mbus-backend
                                                                      Preparing search index...

                                                                      Function processRideReminders

                                                                      diff --git a/docs/functions/services_reminder.processUniversityReminders.html b/docs/functions/services_reminder.processUniversityReminders.html index 01b0549..e038a72 100644 --- a/docs/functions/services_reminder.processUniversityReminders.html +++ b/docs/functions/services_reminder.processUniversityReminders.html @@ -1 +1 @@ -processUniversityReminders | mbus-backend
                                                                      mbus-backend
                                                                        Preparing search index...

                                                                        Function processUniversityReminders

                                                                        +processUniversityReminders | mbus-backend
                                                                        mbus-backend
                                                                          Preparing search index...

                                                                          Function processUniversityReminders

                                                                          diff --git a/docs/functions/services_reminder.sendNotifToAll.html b/docs/functions/services_reminder.sendNotifToAll.html index 6b6f2e0..a6898ee 100644 --- a/docs/functions/services_reminder.sendNotifToAll.html +++ b/docs/functions/services_reminder.sendNotifToAll.html @@ -1 +1 @@ -sendNotifToAll | mbus-backend
                                                                          mbus-backend
                                                                            Preparing search index...

                                                                            Function sendNotifToAll

                                                                            • Parameters

                                                                              • notif: { body: string; title: string }
                                                                              • tokens: Set<string>

                                                                              Returns void

                                                                            +sendNotifToAll | mbus-backend
                                                                            mbus-backend
                                                                              Preparing search index...

                                                                              Function sendNotifToAll

                                                                              • Parameters

                                                                                • notif: { body: string; title: string }
                                                                                • tokens: Set<string>

                                                                                Returns void

                                                                              diff --git a/docs/functions/services_reminderTypes.baseEvent.html b/docs/functions/services_reminderTypes.baseEvent.html index ad93406..006ffd1 100644 --- a/docs/functions/services_reminderTypes.baseEvent.html +++ b/docs/functions/services_reminderTypes.baseEvent.html @@ -1,2 +1,2 @@ baseEvent | mbus-backend
                                                                              mbus-backend
                                                                                Preparing search index...
                                                                                +

                                                                                Parameters

                                                                                Returns BaseEvent

                                                                                diff --git a/docs/functions/services_reminderTypes.delayEvent.html b/docs/functions/services_reminderTypes.delayEvent.html index 1207c39..204c214 100644 --- a/docs/functions/services_reminderTypes.delayEvent.html +++ b/docs/functions/services_reminderTypes.delayEvent.html @@ -1,2 +1,2 @@ delayEvent | mbus-backend
                                                                                mbus-backend
                                                                                  Preparing search index...
                                                                                  • factory

                                                                                    -

                                                                                    Parameters

                                                                                    • x: { currPred: number; prevPred: number; rtid: string; stpid: string }

                                                                                    Returns DelayEvent

                                                                                  +

                                                                                  Parameters

                                                                                  Returns DelayEvent

                                                                                  diff --git a/docs/functions/services_reminderTypes.eventsEqual.html b/docs/functions/services_reminderTypes.eventsEqual.html index 83d0898..171ba8e 100644 --- a/docs/functions/services_reminderTypes.eventsEqual.html +++ b/docs/functions/services_reminderTypes.eventsEqual.html @@ -1 +1 @@ -eventsEqual | mbus-backend
                                                                                  mbus-backend
                                                                                    Preparing search index...
                                                                                    +eventsEqual | mbus-backend
                                                                                    mbus-backend
                                                                                      Preparing search index...
                                                                                      diff --git a/docs/functions/services_reminderTypes.fromKey.html b/docs/functions/services_reminderTypes.fromKey.html index 426b120..fe759d3 100644 --- a/docs/functions/services_reminderTypes.fromKey.html +++ b/docs/functions/services_reminderTypes.fromKey.html @@ -1 +1 @@ -fromKey | mbus-backend
                                                                                      mbus-backend
                                                                                        Preparing search index...
                                                                                        +fromKey | mbus-backend
                                                                                        mbus-backend
                                                                                          Preparing search index...
                                                                                          diff --git a/docs/functions/services_reminderTypes.registrationToken.html b/docs/functions/services_reminderTypes.registrationToken.html index a884ca7..d1dc4d6 100644 --- a/docs/functions/services_reminderTypes.registrationToken.html +++ b/docs/functions/services_reminderTypes.registrationToken.html @@ -1 +1 @@ -registrationToken | mbus-backend
                                                                                          mbus-backend
                                                                                            Preparing search index...

                                                                                            Function registrationToken

                                                                                            +registrationToken | mbus-backend
                                                                                            mbus-backend
                                                                                              Preparing search index...

                                                                                              Function registrationToken

                                                                                              diff --git a/docs/functions/services_reminderTypes.sameBaseEvent.html b/docs/functions/services_reminderTypes.sameBaseEvent.html index b6a0765..e723324 100644 --- a/docs/functions/services_reminderTypes.sameBaseEvent.html +++ b/docs/functions/services_reminderTypes.sameBaseEvent.html @@ -1 +1 @@ -sameBaseEvent | mbus-backend
                                                                                              mbus-backend
                                                                                                Preparing search index...
                                                                                                • Parameters

                                                                                                  • e1: CoreEvent
                                                                                                  • e2: CoreEvent

                                                                                                  Returns boolean

                                                                                                +sameBaseEvent | mbus-backend
                                                                                                mbus-backend
                                                                                                  Preparing search index...
                                                                                                  • Parameters

                                                                                                    • e1: CoreEvent
                                                                                                    • e2: CoreEvent

                                                                                                    Returns boolean

                                                                                                  diff --git a/docs/functions/services_reminderTypes.thresholdEvent.html b/docs/functions/services_reminderTypes.thresholdEvent.html index af4ff72..6242d76 100644 --- a/docs/functions/services_reminderTypes.thresholdEvent.html +++ b/docs/functions/services_reminderTypes.thresholdEvent.html @@ -1,2 +1,2 @@ -thresholdEvent | mbus-backend
                                                                                                  mbus-backend
                                                                                                    Preparing search index...
                                                                                                    +thresholdEvent | mbus-backend
                                                                                                    mbus-backend
                                                                                                      Preparing search index...
                                                                                                      diff --git a/docs/functions/services_reminderTypes.toKey.html b/docs/functions/services_reminderTypes.toKey.html index bcbf4ea..492247b 100644 --- a/docs/functions/services_reminderTypes.toKey.html +++ b/docs/functions/services_reminderTypes.toKey.html @@ -1,2 +1,2 @@ toKey | mbus-backend
                                                                                                      mbus-backend
                                                                                                        Preparing search index...
                                                                                                        +

                                                                                                        Type Parameters

                                                                                                        Parameters

                                                                                                        Returns Key<T>

                                                                                                        diff --git a/docs/functions/services_ride.fetchPatterns.html b/docs/functions/services_ride.fetchPatterns.html index 6850074..c67d7fd 100644 --- a/docs/functions/services_ride.fetchPatterns.html +++ b/docs/functions/services_ride.fetchPatterns.html @@ -1,2 +1,2 @@ fetchPatterns | mbus-backend
                                                                                                        mbus-backend
                                                                                                          Preparing search index...

                                                                                                          Function fetchPatterns

                                                                                                          • Fetches route patterns (path points) for a specific route.

                                                                                                            -

                                                                                                            Parameters

                                                                                                            • rt: string

                                                                                                            Returns Promise<any>

                                                                                                          +

                                                                                                          Parameters

                                                                                                          Returns Promise<any>

                                                                                                          diff --git a/docs/functions/services_ride.fetchPredictions.html b/docs/functions/services_ride.fetchPredictions.html index 32d4c42..c86c5ee 100644 --- a/docs/functions/services_ride.fetchPredictions.html +++ b/docs/functions/services_ride.fetchPredictions.html @@ -1,2 +1,2 @@ fetchPredictions | mbus-backend
                                                                                                          mbus-backend
                                                                                                            Preparing search index...

                                                                                                            Function fetchPredictions

                                                                                                            • Fetches predictions for multiple stop IDs.

                                                                                                              -

                                                                                                              Parameters

                                                                                                              • stopIds: string[]
                                                                                                              • routes: string[]

                                                                                                              Returns Promise<any[]>

                                                                                                            +

                                                                                                            Parameters

                                                                                                            Returns Promise<any[]>

                                                                                                            diff --git a/docs/functions/services_ride.fetchRoutes.html b/docs/functions/services_ride.fetchRoutes.html index 21a65e6..75016e3 100644 --- a/docs/functions/services_ride.fetchRoutes.html +++ b/docs/functions/services_ride.fetchRoutes.html @@ -1,2 +1,2 @@ fetchRoutes | mbus-backend
                                                                                                            mbus-backend
                                                                                                              Preparing search index...

                                                                                                              Function fetchRoutes

                                                                                                              • Fetches all available routes.

                                                                                                                -

                                                                                                                Returns Promise<any>

                                                                                                              +

                                                                                                              Returns Promise<any>

                                                                                                              diff --git a/docs/functions/services_ride.fetchVehicles.html b/docs/functions/services_ride.fetchVehicles.html index 3dd3a95..0a5050b 100644 --- a/docs/functions/services_ride.fetchVehicles.html +++ b/docs/functions/services_ride.fetchVehicles.html @@ -1,2 +1,2 @@ fetchVehicles | mbus-backend
                                                                                                              mbus-backend
                                                                                                                Preparing search index...

                                                                                                                Function fetchVehicles

                                                                                                                • Fetches vehicle positions for the given routes.

                                                                                                                  -

                                                                                                                  Parameters

                                                                                                                  • routes: string[]

                                                                                                                  Returns Promise<any[]>

                                                                                                                +

                                                                                                                Parameters

                                                                                                                Returns Promise<any[]>

                                                                                                                diff --git a/docs/functions/state_transitState.setCachedGraph.html b/docs/functions/state_transitState.setCachedGraph.html index 63000ff..030ef8a 100644 --- a/docs/functions/state_transitState.setCachedGraph.html +++ b/docs/functions/state_transitState.setCachedGraph.html @@ -1,2 +1,2 @@ setCachedGraph | mbus-backend
                                                                                                                mbus-backend
                                                                                                                  Preparing search index...

                                                                                                                  Function setCachedGraph

                                                                                                                  +

                                                                                                                  Parameters

                                                                                                                  Returns void

                                                                                                                  diff --git a/docs/functions/state_transitState.setCachedRideStopLocations.html b/docs/functions/state_transitState.setCachedRideStopLocations.html index 7331229..11761f2 100644 --- a/docs/functions/state_transitState.setCachedRideStopLocations.html +++ b/docs/functions/state_transitState.setCachedRideStopLocations.html @@ -1,2 +1,2 @@ setCachedRideStopLocations | mbus-backend
                                                                                                                  mbus-backend
                                                                                                                    Preparing search index...

                                                                                                                    Function setCachedRideStopLocations

                                                                                                                    • Updates the cached ride stop locations.

                                                                                                                      -

                                                                                                                      Parameters

                                                                                                                      • newLocs: Record<string, { lat: number; lon: number; name: string }>

                                                                                                                      Returns void

                                                                                                                    +

                                                                                                                    Parameters

                                                                                                                    Returns void

                                                                                                                    diff --git a/docs/functions/state_transitState.setCachedStopLocations.html b/docs/functions/state_transitState.setCachedStopLocations.html index 9bbf317..a545f1e 100644 --- a/docs/functions/state_transitState.setCachedStopLocations.html +++ b/docs/functions/state_transitState.setCachedStopLocations.html @@ -1,2 +1,2 @@ setCachedStopLocations | mbus-backend
                                                                                                                    mbus-backend
                                                                                                                      Preparing search index...

                                                                                                                      Function setCachedStopLocations

                                                                                                                      • Updates the cached stop locations.

                                                                                                                        -

                                                                                                                        Parameters

                                                                                                                        • newLocs: Record<string, { lat: number; lon: number; name: string }>

                                                                                                                        Returns void

                                                                                                                      +

                                                                                                                      Parameters

                                                                                                                      Returns void

                                                                                                                      diff --git a/docs/functions/walking_contractionHierarchy.buildGraphFromAdjacency.html b/docs/functions/walking_contractionHierarchy.buildGraphFromAdjacency.html new file mode 100644 index 0000000..43cbec6 --- /dev/null +++ b/docs/functions/walking_contractionHierarchy.buildGraphFromAdjacency.html @@ -0,0 +1,2 @@ +buildGraphFromAdjacency | mbus-backend
                                                                                                                      mbus-backend
                                                                                                                        Preparing search index...
                                                                                                                        • Build an uncontracted CH graph from a walking adjacency list (GraphML node string ids).

                                                                                                                          +

                                                                                                                          Parameters

                                                                                                                          • adjacency: Map<string, GraphMLEdge[]>
                                                                                                                          • Optionaloptions: { debugMode?: boolean }

                                                                                                                          Returns ContractionHierarchyGraph

                                                                                                                        diff --git a/docs/functions/walking_contractionHierarchy.buildNearestNodeIndex.html b/docs/functions/walking_contractionHierarchy.buildNearestNodeIndex.html new file mode 100644 index 0000000..cab561d --- /dev/null +++ b/docs/functions/walking_contractionHierarchy.buildNearestNodeIndex.html @@ -0,0 +1,2 @@ +buildNearestNodeIndex | mbus-backend
                                                                                                                        mbus-backend
                                                                                                                          Preparing search index...
                                                                                                                          • Build spatial grid index for nearestGraphNode. Call when graph nodes change.

                                                                                                                            +

                                                                                                                            Parameters

                                                                                                                            Returns void

                                                                                                                          diff --git a/docs/functions/walking_contractionHierarchy.buildWalkingChAssets.html b/docs/functions/walking_contractionHierarchy.buildWalkingChAssets.html new file mode 100644 index 0000000..db7c9be --- /dev/null +++ b/docs/functions/walking_contractionHierarchy.buildWalkingChAssets.html @@ -0,0 +1,3 @@ +buildWalkingChAssets | mbus-backend
                                                                                                                          mbus-backend
                                                                                                                            Preparing search index...
                                                                                                                            • Build CH from ann_arbor.graphml and write ann_arbor.ch.json + ch-metadata.json. +Invoked by npm run build:walking-ch (~minutes, high memory).

                                                                                                                              +

                                                                                                                              Returns Promise<void>

                                                                                                                            diff --git a/docs/functions/walking_contractionHierarchy.getChFilePath.html b/docs/functions/walking_contractionHierarchy.getChFilePath.html new file mode 100644 index 0000000..74bc9cb --- /dev/null +++ b/docs/functions/walking_contractionHierarchy.getChFilePath.html @@ -0,0 +1 @@ +getChFilePath | mbus-backend
                                                                                                                            mbus-backend
                                                                                                                              Preparing search index...
                                                                                                                              • Returns string

                                                                                                                              diff --git a/docs/functions/walking_contractionHierarchy.isChLoaded.html b/docs/functions/walking_contractionHierarchy.isChLoaded.html new file mode 100644 index 0000000..47f19b0 --- /dev/null +++ b/docs/functions/walking_contractionHierarchy.isChLoaded.html @@ -0,0 +1,2 @@ +isChLoaded | mbus-backend
                                                                                                                              mbus-backend
                                                                                                                                Preparing search index...
                                                                                                                                • True after a successful loadContractionHierarchy.

                                                                                                                                  +

                                                                                                                                  Returns boolean

                                                                                                                                diff --git a/docs/functions/walking_contractionHierarchy.loadContractionHierarchy.html b/docs/functions/walking_contractionHierarchy.loadContractionHierarchy.html new file mode 100644 index 0000000..3dd8035 --- /dev/null +++ b/docs/functions/walking_contractionHierarchy.loadContractionHierarchy.html @@ -0,0 +1,3 @@ +loadContractionHierarchy | mbus-backend
                                                                                                                                mbus-backend
                                                                                                                                  Preparing search index...
                                                                                                                                  • Load src/assets/ann_arbor.ch.json into memory. Call once at startup.

                                                                                                                                    +

                                                                                                                                    Returns void

                                                                                                                                    If the CH file is missing (run npm run build:walking-ch or pull Git LFS).

                                                                                                                                    +
                                                                                                                                  diff --git a/docs/functions/walking_contractionHierarchy.nearestGraphNode.html b/docs/functions/walking_contractionHierarchy.nearestGraphNode.html new file mode 100644 index 0000000..e1a5e36 --- /dev/null +++ b/docs/functions/walking_contractionHierarchy.nearestGraphNode.html @@ -0,0 +1,2 @@ +nearestGraphNode | mbus-backend
                                                                                                                                  mbus-backend
                                                                                                                                    Preparing search index...
                                                                                                                                    • Snap coordinates to the nearest walking-graph node (haversine distance to node center).

                                                                                                                                      +

                                                                                                                                      Parameters

                                                                                                                                      Returns { dist: number; id: string } | null

                                                                                                                                    diff --git a/docs/functions/walking_contractionHierarchy.queryDistance.html b/docs/functions/walking_contractionHierarchy.queryDistance.html new file mode 100644 index 0000000..64647c3 --- /dev/null +++ b/docs/functions/walking_contractionHierarchy.queryDistance.html @@ -0,0 +1,2 @@ +queryDistance | mbus-backend
                                                                                                                                    mbus-backend
                                                                                                                                      Preparing search index...
                                                                                                                                      • Shortest-path distance in meters between two graph node IDs, or null if unreachable.

                                                                                                                                        +

                                                                                                                                        Parameters

                                                                                                                                        • startNodeId: string
                                                                                                                                        • endNodeId: string

                                                                                                                                        Returns number | null

                                                                                                                                      diff --git a/docs/functions/walking_contractionHierarchy.queryDistancesFromOrigin.html b/docs/functions/walking_contractionHierarchy.queryDistancesFromOrigin.html new file mode 100644 index 0000000..a4488c3 --- /dev/null +++ b/docs/functions/walking_contractionHierarchy.queryDistancesFromOrigin.html @@ -0,0 +1,2 @@ +queryDistancesFromOrigin | mbus-backend
                                                                                                                                      mbus-backend
                                                                                                                                        Preparing search index...
                                                                                                                                        • PHAST: one origin graph node → many targets (used for McRaptor walk-access batches).

                                                                                                                                          +

                                                                                                                                          Parameters

                                                                                                                                          • startNodeId: string
                                                                                                                                          • targetNodeIds: Iterable<string>

                                                                                                                                          Returns Map<string, number> | null

                                                                                                                                        diff --git a/docs/functions/walking_contractionHierarchy.queryPath.html b/docs/functions/walking_contractionHierarchy.queryPath.html new file mode 100644 index 0000000..7351869 --- /dev/null +++ b/docs/functions/walking_contractionHierarchy.queryPath.html @@ -0,0 +1,2 @@ +queryPath | mbus-backend
                                                                                                                                        mbus-backend
                                                                                                                                          Preparing search index...
                                                                                                                                          • Shortest path between two graph nodes (distance + contracted node sequence).

                                                                                                                                            +

                                                                                                                                            Parameters

                                                                                                                                            • startNodeId: string
                                                                                                                                            • endNodeId: string

                                                                                                                                            Returns { distance: number; nodeIds: string[] } | null

                                                                                                                                          diff --git a/docs/functions/walking_contractionHierarchy.stitchPathCoords.html b/docs/functions/walking_contractionHierarchy.stitchPathCoords.html new file mode 100644 index 0000000..4dc4738 --- /dev/null +++ b/docs/functions/walking_contractionHierarchy.stitchPathCoords.html @@ -0,0 +1 @@ +stitchPathCoords | mbus-backend
                                                                                                                                          mbus-backend
                                                                                                                                            Preparing search index...
                                                                                                                                            • Parameters

                                                                                                                                              • pathIds: string[]
                                                                                                                                              • graphNodes: Map<string, GraphMLNode>
                                                                                                                                              • graphAdjacency: Map<string, GraphMLEdge[]>
                                                                                                                                              • originLat: number
                                                                                                                                              • originLon: number
                                                                                                                                              • destLat: number
                                                                                                                                              • destLon: number

                                                                                                                                              Returns { lat: number; lon: number }[]

                                                                                                                                            diff --git a/docs/functions/walking_loadMap.haversine.html b/docs/functions/walking_loadMap.haversine.html index 79efb48..c60a2b0 100644 --- a/docs/functions/walking_loadMap.haversine.html +++ b/docs/functions/walking_loadMap.haversine.html @@ -4,4 +4,4 @@
                                                                                                                                          • bLat: number

                                                                                                                                            Latitude of point B.

                                                                                                                                          • bLon: number

                                                                                                                                            Longitude of point B.

                                                                                                                                          • Returns number

                                                                                                                                            Distance in meters.

                                                                                                                                            -
                                                                                                                                            +
                                                                                                                                            diff --git a/docs/functions/walking_loadMap.loadMap.html b/docs/functions/walking_loadMap.loadMap.html index 6618d45..c7c8619 100644 --- a/docs/functions/walking_loadMap.loadMap.html +++ b/docs/functions/walking_loadMap.loadMap.html @@ -13,4 +13,4 @@
                                                                                                                                          • Returns { graph: Map<string, GraphMLEdge[]>; nodes: Map<string, GraphMLNode> }

                                                                                                                                            An object containing the map of Nodes and the Adjacency List (graph).

                                                                                                                                            -
                                                                                                                                            +
                                                                                                                                            diff --git a/docs/functions/walking_walkingMap.__computeDijkstraAll.html b/docs/functions/walking_walkingMap.__computeDijkstraAll.html new file mode 100644 index 0000000..c8a52be --- /dev/null +++ b/docs/functions/walking_walkingMap.__computeDijkstraAll.html @@ -0,0 +1,2 @@ +__computeDijkstraAll | mbus-backend
                                                                                                                                            mbus-backend
                                                                                                                                              Preparing search index...

                                                                                                                                              Function __computeDijkstraAll

                                                                                                                                              • Internal

                                                                                                                                                Exposed for tests comparing CH vs Dijkstra.

                                                                                                                                                +

                                                                                                                                                Parameters

                                                                                                                                                • startId: string
                                                                                                                                                • Optionaltargets: Set<string>

                                                                                                                                                Returns Map<string, number>

                                                                                                                                              diff --git a/docs/functions/walking_walkingMap.buildSparseWalkingTransfers.html b/docs/functions/walking_walkingMap.buildSparseWalkingTransfers.html new file mode 100644 index 0000000..bd4fb2b --- /dev/null +++ b/docs/functions/walking_walkingMap.buildSparseWalkingTransfers.html @@ -0,0 +1,4 @@ +buildSparseWalkingTransfers | mbus-backend
                                                                                                                                              mbus-backend
                                                                                                                                                Preparing search index...

                                                                                                                                                Function buildSparseWalkingTransfers

                                                                                                                                                • ULTRA-style sparse walking transfers: full walk matrix + transitive reduction. +Preserves optimal walking distances; McRAPTOR only relaxes non-redundant shortcut edges. +Loaded shortcuts stay in memory; disk is cold-start only. New stops extend incrementally.

                                                                                                                                                  +

                                                                                                                                                  Parameters

                                                                                                                                                  • stopIds: string[]

                                                                                                                                                  Returns SparseWalkingTransferResult

                                                                                                                                                diff --git a/docs/functions/walking_walkingMap.buildStopNodeMap.html b/docs/functions/walking_walkingMap.buildStopNodeMap.html index 10e668b..35c9fcd 100644 --- a/docs/functions/walking_walkingMap.buildStopNodeMap.html +++ b/docs/functions/walking_walkingMap.buildStopNodeMap.html @@ -1,4 +1 @@ -buildStopNodeMap | mbus-backend
                                                                                                                                                mbus-backend
                                                                                                                                                  Preparing search index...

                                                                                                                                                  Function buildStopNodeMap

                                                                                                                                                  • Maps a list of bus stops to their nearest nodes on the street graph. -This optimizes future lookups by caching the StopID -> NodeID relationship.

                                                                                                                                                    -

                                                                                                                                                    Parameters

                                                                                                                                                    • locations: Record<string, { lat: number; lon: number }>

                                                                                                                                                      A map of StopID to {lat, lon}.

                                                                                                                                                      -

                                                                                                                                                    Returns void

                                                                                                                                                  +buildStopNodeMap | mbus-backend
                                                                                                                                                  mbus-backend
                                                                                                                                                    Preparing search index...

                                                                                                                                                    Function buildStopNodeMap

                                                                                                                                                    • Parameters

                                                                                                                                                      • locations: Record<string, { lat: number; lon: number }>

                                                                                                                                                      Returns void

                                                                                                                                                    diff --git a/docs/functions/walking_walkingMap.ensureCacheForStops.html b/docs/functions/walking_walkingMap.ensureCacheForStops.html deleted file mode 100644 index e90fe83..0000000 --- a/docs/functions/walking_walkingMap.ensureCacheForStops.html +++ /dev/null @@ -1,5 +0,0 @@ -ensureCacheForStops | mbus-backend
                                                                                                                                                    mbus-backend
                                                                                                                                                      Preparing search index...

                                                                                                                                                      Function ensureCacheForStops

                                                                                                                                                      • Ensures walking paths between all provided stops are calculated and cached. -Fetches missing paths in parallel and updates the disk cache.

                                                                                                                                                        -

                                                                                                                                                        Parameters

                                                                                                                                                        • stopIds: Set<string>

                                                                                                                                                          Set of stop IDs to verify.

                                                                                                                                                          -
                                                                                                                                                        • stopLocations: Record<string, { lat: number; lon: number }>

                                                                                                                                                          Map of Stop ID to coordinates.

                                                                                                                                                          -

                                                                                                                                                        Returns Promise<void>

                                                                                                                                                      diff --git a/docs/functions/walking_walkingMap.getCachedWalk.html b/docs/functions/walking_walkingMap.getCachedWalk.html deleted file mode 100644 index 65d8590..0000000 --- a/docs/functions/walking_walkingMap.getCachedWalk.html +++ /dev/null @@ -1,5 +0,0 @@ -getCachedWalk | mbus-backend
                                                                                                                                                      mbus-backend
                                                                                                                                                        Preparing search index...

                                                                                                                                                        Function getCachedWalk

                                                                                                                                                        • Retrieves a cached walking path between two stops.

                                                                                                                                                          -

                                                                                                                                                          Parameters

                                                                                                                                                          • originId: string

                                                                                                                                                            Origin Stop ID.

                                                                                                                                                            -
                                                                                                                                                          • destId: string

                                                                                                                                                            Destination Stop ID.

                                                                                                                                                            -

                                                                                                                                                          Returns WalkingResponse | undefined

                                                                                                                                                          Cached walking data or undefined.

                                                                                                                                                          -
                                                                                                                                                        diff --git a/docs/functions/walking_walkingMap.getWalkingDistancesFrom.html b/docs/functions/walking_walkingMap.getWalkingDistancesFrom.html index 916cc29..937626f 100644 --- a/docs/functions/walking_walkingMap.getWalkingDistancesFrom.html +++ b/docs/functions/walking_walkingMap.getWalkingDistancesFrom.html @@ -1,8 +1 @@ -getWalkingDistancesFrom | mbus-backend
                                                                                                                                                        mbus-backend
                                                                                                                                                          Preparing search index...

                                                                                                                                                          Function getWalkingDistancesFrom

                                                                                                                                                          • Optimized method to get walking distances from an origin to ALL known bus stops. -Optionally includes a direct walk to a specific destination point. -Uses a single Dijkstra pass with early termination and LRU Cache.

                                                                                                                                                            -

                                                                                                                                                            Parameters

                                                                                                                                                            • lat: number

                                                                                                                                                              Origin latitude.

                                                                                                                                                              -
                                                                                                                                                            • lon: number

                                                                                                                                                              Origin longitude.

                                                                                                                                                              -
                                                                                                                                                            • OptionaldestLat: number

                                                                                                                                                              (Optional) Destination latitude for direct walk.

                                                                                                                                                              -
                                                                                                                                                            • OptionaldestLon: number

                                                                                                                                                              (Optional) Destination longitude for direct walk.

                                                                                                                                                              -

                                                                                                                                                            Returns { duration: number; stopId: string }[]

                                                                                                                                                          +getWalkingDistancesFrom | mbus-backend
                                                                                                                                                          mbus-backend
                                                                                                                                                            Preparing search index...

                                                                                                                                                            Function getWalkingDistancesFrom

                                                                                                                                                            • Parameters

                                                                                                                                                              • lat: number
                                                                                                                                                              • lon: number
                                                                                                                                                              • OptionaldestLat: number
                                                                                                                                                              • OptionaldestLon: number

                                                                                                                                                              Returns { duration: number; stopId: string }[]

                                                                                                                                                            diff --git a/docs/functions/walking_walkingMap.getWalkingResponse.html b/docs/functions/walking_walkingMap.getWalkingResponse.html index cd96549..6398427 100644 --- a/docs/functions/walking_walkingMap.getWalkingResponse.html +++ b/docs/functions/walking_walkingMap.getWalkingResponse.html @@ -1,7 +1 @@ -getWalkingResponse | mbus-backend
                                                                                                                                                            mbus-backend
                                                                                                                                                              Preparing search index...

                                                                                                                                                              Function getWalkingResponse

                                                                                                                                                              • Calculates a detailed walking path between two coordinates using A*. -Includes path geometry for rendering.

                                                                                                                                                                -

                                                                                                                                                                Parameters

                                                                                                                                                                • originLat: number

                                                                                                                                                                  Latitude of origin.

                                                                                                                                                                  -
                                                                                                                                                                • originLon: number

                                                                                                                                                                  Longitude of origin.

                                                                                                                                                                  -
                                                                                                                                                                • destLat: number

                                                                                                                                                                  Latitude of destination.

                                                                                                                                                                  -
                                                                                                                                                                • destLon: number

                                                                                                                                                                  Longitude of destination.

                                                                                                                                                                  -

                                                                                                                                                                Returns Promise<WalkingResponse>

                                                                                                                                                              +getWalkingResponse | mbus-backend
                                                                                                                                                              mbus-backend
                                                                                                                                                                Preparing search index...

                                                                                                                                                                Function getWalkingResponse

                                                                                                                                                                • Parameters

                                                                                                                                                                  • originLat: number
                                                                                                                                                                  • originLon: number
                                                                                                                                                                  • destLat: number
                                                                                                                                                                  • destLon: number

                                                                                                                                                                  Returns Promise<WalkingResponse>

                                                                                                                                                                diff --git a/docs/functions/walking_walkingShortcuts.countStopWalkEdges.html b/docs/functions/walking_walkingShortcuts.countStopWalkEdges.html new file mode 100644 index 0000000..2a9b386 --- /dev/null +++ b/docs/functions/walking_walkingShortcuts.countStopWalkEdges.html @@ -0,0 +1 @@ +countStopWalkEdges | mbus-backend
                                                                                                                                                                mbus-backend
                                                                                                                                                                  Preparing search index...
                                                                                                                                                                  diff --git a/docs/functions/walking_walkingShortcuts.shortcutsToTransfers.html b/docs/functions/walking_walkingShortcuts.shortcutsToTransfers.html new file mode 100644 index 0000000..495c57c --- /dev/null +++ b/docs/functions/walking_walkingShortcuts.shortcutsToTransfers.html @@ -0,0 +1 @@ +shortcutsToTransfers | mbus-backend
                                                                                                                                                                  mbus-backend
                                                                                                                                                                    Preparing search index...
                                                                                                                                                                    diff --git a/docs/functions/walking_walkingShortcuts.transitiveReductionShortcuts.html b/docs/functions/walking_walkingShortcuts.transitiveReductionShortcuts.html new file mode 100644 index 0000000..fcbc67c --- /dev/null +++ b/docs/functions/walking_walkingShortcuts.transitiveReductionShortcuts.html @@ -0,0 +1,4 @@ +transitiveReductionShortcuts | mbus-backend
                                                                                                                                                                    mbus-backend
                                                                                                                                                                      Preparing search index...

                                                                                                                                                                      Function transitiveReductionShortcuts

                                                                                                                                                                      • ULTRA-style shortcut graph: transitive reduction on walking times. +Removes origin→dest when some intermediate stop yields an equal-or-better path. +Preserves all shortest-path walking distances (no quality loss for time-based walks).

                                                                                                                                                                        +

                                                                                                                                                                        Parameters

                                                                                                                                                                        • stops: string[]
                                                                                                                                                                        • durations: StopWalkMeters
                                                                                                                                                                        • toleranceMeters: number = METER_TOLERANCE

                                                                                                                                                                        Returns StopWalkMeters

                                                                                                                                                                      diff --git a/docs/hierarchy.html b/docs/hierarchy.html index e83590c..3f656c3 100644 --- a/docs/hierarchy.html +++ b/docs/hierarchy.html @@ -1 +1 @@ -mbus-backend
                                                                                                                                                                      mbus-backend
                                                                                                                                                                        Preparing search index...

                                                                                                                                                                        mbus-backend

                                                                                                                                                                        Hierarchy Summary

                                                                                                                                                                        +mbus-backend
                                                                                                                                                                        mbus-backend
                                                                                                                                                                          Preparing search index...

                                                                                                                                                                          mbus-backend

                                                                                                                                                                          Hierarchy Summary

                                                                                                                                                                          diff --git a/docs/interfaces/raptor_McRaptorAlgorithm.Journey.html b/docs/interfaces/raptor_McRaptorAlgorithm.Journey.html index b0210ca..4c25218 100644 --- a/docs/interfaces/raptor_McRaptorAlgorithm.Journey.html +++ b/docs/interfaces/raptor_McRaptorAlgorithm.Journey.html @@ -1,6 +1,4 @@ Journey | mbus-backend
                                                                                                                                                                          mbus-backend
                                                                                                                                                                            Preparing search index...

                                                                                                                                                                            Represents a complete transit journey consisting of multiple legs.

                                                                                                                                                                            -
                                                                                                                                                                            interface Journey {
                                                                                                                                                                                criteria: {
                                                                                                                                                                                    arrivalTime: number;
                                                                                                                                                                                    transferCount: number;
                                                                                                                                                                                    walkingDistance: number;
                                                                                                                                                                                };
                                                                                                                                                                                legs: JourneyLeg[];
                                                                                                                                                                            }
                                                                                                                                                                            Index

                                                                                                                                                                            Properties

                                                                                                                                                                            interface Journey {
                                                                                                                                                                                criteria: {
                                                                                                                                                                                    arrivalTime: number;
                                                                                                                                                                                    transferCount: number;
                                                                                                                                                                                    walkingDistance: number;
                                                                                                                                                                                };
                                                                                                                                                                                legs: JourneyLeg[];
                                                                                                                                                                            }
                                                                                                                                                                            Index

                                                                                                                                                                            Properties

                                                                                                                                                                            Properties

                                                                                                                                                                            criteria: {
                                                                                                                                                                                arrivalTime: number;
                                                                                                                                                                                transferCount: number;
                                                                                                                                                                                walkingDistance: number;
                                                                                                                                                                            }

                                                                                                                                                                            The performance metrics for this journey.

                                                                                                                                                                            -
                                                                                                                                                                            legs: JourneyLeg[]

                                                                                                                                                                            The sequence of legs (trips or walking transfers) in the journey.

                                                                                                                                                                            -
                                                                                                                                                                            +

                                                                                                                                                                            Properties

                                                                                                                                                                            criteria: {
                                                                                                                                                                                arrivalTime: number;
                                                                                                                                                                                transferCount: number;
                                                                                                                                                                                walkingDistance: number;
                                                                                                                                                                            }
                                                                                                                                                                            legs: JourneyLeg[]
                                                                                                                                                                            diff --git a/docs/interfaces/raptor_McRaptorAlgorithm.JourneyLeg.html b/docs/interfaces/raptor_McRaptorAlgorithm.JourneyLeg.html index b6da33e..b50b445 100644 --- a/docs/interfaces/raptor_McRaptorAlgorithm.JourneyLeg.html +++ b/docs/interfaces/raptor_McRaptorAlgorithm.JourneyLeg.html @@ -1,5 +1,5 @@ JourneyLeg | mbus-backend
                                                                                                                                                                            mbus-backend
                                                                                                                                                                              Preparing search index...

                                                                                                                                                                              Represents a single segment of a journey, either a transit trip or a walking transfer.

                                                                                                                                                                              -
                                                                                                                                                                              interface JourneyLeg {
                                                                                                                                                                                  destination: string;
                                                                                                                                                                                  destinationID: string;
                                                                                                                                                                                  duration: number;
                                                                                                                                                                                  endTime: number;
                                                                                                                                                                                  origin: string;
                                                                                                                                                                                  originID: string;
                                                                                                                                                                                  rt?: string;
                                                                                                                                                                                  startTime: number;
                                                                                                                                                                                  stopTimes?: StopTime[];
                                                                                                                                                                                  transfer?: Transfer;
                                                                                                                                                                                  trip?: Trip;
                                                                                                                                                                                  type: "Trip" | "Transfer";
                                                                                                                                                                              }
                                                                                                                                                                              Index

                                                                                                                                                                              Properties

                                                                                                                                                                              interface JourneyLeg {
                                                                                                                                                                                  destination: string;
                                                                                                                                                                                  destinationID: string;
                                                                                                                                                                                  duration: number;
                                                                                                                                                                                  endTime: number;
                                                                                                                                                                                  origin: string;
                                                                                                                                                                                  originID: string;
                                                                                                                                                                                  rt?: string;
                                                                                                                                                                                  startTime: number;
                                                                                                                                                                                  stopTimes?: StopTime[];
                                                                                                                                                                                  transfer?: Transfer;
                                                                                                                                                                                  trip?: Trip;
                                                                                                                                                                                  type: "Trip" | "Transfer";
                                                                                                                                                                              }
                                                                                                                                                                              Index

                                                                                                                                                                              Properties

                                                                                                                                                                              destination: string
                                                                                                                                                                              destinationID: string
                                                                                                                                                                              duration: number
                                                                                                                                                                              endTime: number
                                                                                                                                                                              origin: string
                                                                                                                                                                              originID: string
                                                                                                                                                                              rt?: string
                                                                                                                                                                              startTime: number
                                                                                                                                                                              stopTimes?: StopTime[]
                                                                                                                                                                              transfer?: Transfer
                                                                                                                                                                              trip?: Trip
                                                                                                                                                                              type: "Trip" | "Transfer"
                                                                                                                                                                              +

                                                                                                                                                                              Properties

                                                                                                                                                                              destination: string
                                                                                                                                                                              destinationID: string
                                                                                                                                                                              duration: number
                                                                                                                                                                              endTime: number
                                                                                                                                                                              origin: string
                                                                                                                                                                              originID: string
                                                                                                                                                                              rt?: string
                                                                                                                                                                              startTime: number
                                                                                                                                                                              stopTimes?: StopTime[]
                                                                                                                                                                              transfer?: Transfer
                                                                                                                                                                              trip?: Trip
                                                                                                                                                                              type: "Trip" | "Transfer"
                                                                                                                                                                              diff --git a/docs/interfaces/raptor_McRaptorAlgorithm.McRaptorQueryOverlay.html b/docs/interfaces/raptor_McRaptorAlgorithm.McRaptorQueryOverlay.html new file mode 100644 index 0000000..1b1c5d8 --- /dev/null +++ b/docs/interfaces/raptor_McRaptorAlgorithm.McRaptorQueryOverlay.html @@ -0,0 +1,5 @@ +McRaptorQueryOverlay | mbus-backend
                                                                                                                                                                              mbus-backend
                                                                                                                                                                                Preparing search index...

                                                                                                                                                                                Interface McRaptorQueryOverlay

                                                                                                                                                                                Per-query walking overlay — avoids cloning the full transfer graph. +Origin walks replace VIRTUAL_ORIGIN transfers; destination walks append to each stop.

                                                                                                                                                                                +
                                                                                                                                                                                interface McRaptorQueryOverlay {
                                                                                                                                                                                    destinationWalks: Map<string, Transfer>;
                                                                                                                                                                                    originWalks: Transfer[];
                                                                                                                                                                                }
                                                                                                                                                                                Index

                                                                                                                                                                                Properties

                                                                                                                                                                                destinationWalks: Map<string, Transfer>
                                                                                                                                                                                originWalks: Transfer[]
                                                                                                                                                                                diff --git a/docs/interfaces/raptor_types.Leg.html b/docs/interfaces/raptor_types.Leg.html index e209caf..df25d32 100644 --- a/docs/interfaces/raptor_types.Leg.html +++ b/docs/interfaces/raptor_types.Leg.html @@ -1,4 +1,4 @@ Leg | mbus-backend
                                                                                                                                                                                mbus-backend
                                                                                                                                                                                  Preparing search index...

                                                                                                                                                                                  Interface Leg

                                                                                                                                                                                  Abstract representation of a connection between two stops.

                                                                                                                                                                                  -
                                                                                                                                                                                  interface Leg {
                                                                                                                                                                                      destination: string;
                                                                                                                                                                                      origin: string;
                                                                                                                                                                                  }

                                                                                                                                                                                  Hierarchy (View Summary)

                                                                                                                                                                                  Index

                                                                                                                                                                                  Properties

                                                                                                                                                                                  interface Leg {
                                                                                                                                                                                      destination: string;
                                                                                                                                                                                      origin: string;
                                                                                                                                                                                  }

                                                                                                                                                                                  Hierarchy (View Summary)

                                                                                                                                                                                  Index

                                                                                                                                                                                  Properties

                                                                                                                                                                                  Properties

                                                                                                                                                                                  destination: string
                                                                                                                                                                                  origin: string
                                                                                                                                                                                  +

                                                                                                                                                                                  Properties

                                                                                                                                                                                  destination: string
                                                                                                                                                                                  origin: string
                                                                                                                                                                                  diff --git a/docs/interfaces/raptor_types.StopTime.html b/docs/interfaces/raptor_types.StopTime.html index eafc571..03ddbd9 100644 --- a/docs/interfaces/raptor_types.StopTime.html +++ b/docs/interfaces/raptor_types.StopTime.html @@ -1,5 +1,5 @@ StopTime | mbus-backend
                                                                                                                                                                                  mbus-backend
                                                                                                                                                                                    Preparing search index...

                                                                                                                                                                                    Interface StopTime

                                                                                                                                                                                    Represents a scheduled stop event within a trip (GTFS StopTime).

                                                                                                                                                                                    -
                                                                                                                                                                                    interface StopTime {
                                                                                                                                                                                        arrivalTime: number;
                                                                                                                                                                                        departureTime: number;
                                                                                                                                                                                        dropOff: boolean;
                                                                                                                                                                                        heursticCost?: number;
                                                                                                                                                                                        isExtrapolated?: boolean;
                                                                                                                                                                                        pickUp: boolean;
                                                                                                                                                                                        rt?: string;
                                                                                                                                                                                        stop: string;
                                                                                                                                                                                    }
                                                                                                                                                                                    Index

                                                                                                                                                                                    Properties

                                                                                                                                                                                    interface StopTime {
                                                                                                                                                                                        arrivalTime: number;
                                                                                                                                                                                        departureTime: number;
                                                                                                                                                                                        dropOff: boolean;
                                                                                                                                                                                        heursticCost?: number;
                                                                                                                                                                                        isExtrapolated?: boolean;
                                                                                                                                                                                        pickUp: boolean;
                                                                                                                                                                                        rt?: string;
                                                                                                                                                                                        stop: string;
                                                                                                                                                                                    }
                                                                                                                                                                                    Index

                                                                                                                                                                                    Properties

                                                                                                                                                                                    arrivalTime: number
                                                                                                                                                                                    departureTime: number
                                                                                                                                                                                    dropOff: boolean

                                                                                                                                                                                    Whether passengers can alight from the vehicle here.

                                                                                                                                                                                    -
                                                                                                                                                                                    heursticCost?: number

                                                                                                                                                                                    Optional pre-calculated cost for routing heuristics.

                                                                                                                                                                                    -
                                                                                                                                                                                    isExtrapolated?: boolean

                                                                                                                                                                                    If the stop is predicted or not.

                                                                                                                                                                                    -
                                                                                                                                                                                    pickUp: boolean

                                                                                                                                                                                    Whether passengers can board the vehicle here.

                                                                                                                                                                                    -
                                                                                                                                                                                    rt?: string

                                                                                                                                                                                    Real-time status string (if available).

                                                                                                                                                                                    -
                                                                                                                                                                                    stop: string

                                                                                                                                                                                    The ID of the stop.

                                                                                                                                                                                    -
                                                                                                                                                                                    +

                                                                                                                                                                                    Properties

                                                                                                                                                                                    arrivalTime: number
                                                                                                                                                                                    departureTime: number
                                                                                                                                                                                    dropOff: boolean

                                                                                                                                                                                    Whether passengers can alight from the vehicle here.

                                                                                                                                                                                    +
                                                                                                                                                                                    heursticCost?: number

                                                                                                                                                                                    Optional pre-calculated cost for routing heuristics.

                                                                                                                                                                                    +
                                                                                                                                                                                    isExtrapolated?: boolean

                                                                                                                                                                                    If the stop is predicted or not.

                                                                                                                                                                                    +
                                                                                                                                                                                    pickUp: boolean

                                                                                                                                                                                    Whether passengers can board the vehicle here.

                                                                                                                                                                                    +
                                                                                                                                                                                    rt?: string

                                                                                                                                                                                    Real-time status string (if available).

                                                                                                                                                                                    +
                                                                                                                                                                                    stop: string

                                                                                                                                                                                    The ID of the stop.

                                                                                                                                                                                    +
                                                                                                                                                                                    diff --git a/docs/interfaces/raptor_types.TimetableLeg.html b/docs/interfaces/raptor_types.TimetableLeg.html index 347f2af..1172e44 100644 --- a/docs/interfaces/raptor_types.TimetableLeg.html +++ b/docs/interfaces/raptor_types.TimetableLeg.html @@ -1,6 +1,6 @@ TimetableLeg | mbus-backend
                                                                                                                                                                                    mbus-backend
                                                                                                                                                                                      Preparing search index...

                                                                                                                                                                                      Interface TimetableLeg

                                                                                                                                                                                      A specific segment of a scheduled trip with fixed times.

                                                                                                                                                                                      -
                                                                                                                                                                                      interface TimetableLeg {
                                                                                                                                                                                          destination: string;
                                                                                                                                                                                          origin: string;
                                                                                                                                                                                          stopTimes: StopTime[];
                                                                                                                                                                                          trip: Trip;
                                                                                                                                                                                      }

                                                                                                                                                                                      Hierarchy (View Summary)

                                                                                                                                                                                      • Leg
                                                                                                                                                                                        • TimetableLeg
                                                                                                                                                                                      Index

                                                                                                                                                                                      Properties

                                                                                                                                                                                      interface TimetableLeg {
                                                                                                                                                                                          destination: string;
                                                                                                                                                                                          origin: string;
                                                                                                                                                                                          stopTimes: StopTime[];
                                                                                                                                                                                          trip: Trip;
                                                                                                                                                                                      }

                                                                                                                                                                                      Hierarchy (View Summary)

                                                                                                                                                                                      • Leg
                                                                                                                                                                                        • TimetableLeg
                                                                                                                                                                                      Index

                                                                                                                                                                                      Properties

                                                                                                                                                                                      destination: string
                                                                                                                                                                                      origin: string
                                                                                                                                                                                      stopTimes: StopTime[]
                                                                                                                                                                                      trip: Trip
                                                                                                                                                                                      +

                                                                                                                                                                                      Properties

                                                                                                                                                                                      destination: string
                                                                                                                                                                                      origin: string
                                                                                                                                                                                      stopTimes: StopTime[]
                                                                                                                                                                                      trip: Trip
                                                                                                                                                                                      diff --git a/docs/interfaces/raptor_types.Transfer.html b/docs/interfaces/raptor_types.Transfer.html index 5249ef0..be9ec6c 100644 --- a/docs/interfaces/raptor_types.Transfer.html +++ b/docs/interfaces/raptor_types.Transfer.html @@ -1,9 +1,9 @@ Transfer | mbus-backend
                                                                                                                                                                                      mbus-backend
                                                                                                                                                                                        Preparing search index...

                                                                                                                                                                                        Interface Transfer

                                                                                                                                                                                        A walking connection between two stops with a defined duration.

                                                                                                                                                                                        -
                                                                                                                                                                                        interface Transfer {
                                                                                                                                                                                            destination: string;
                                                                                                                                                                                            duration: number;
                                                                                                                                                                                            endTime: number;
                                                                                                                                                                                            origin: string;
                                                                                                                                                                                            startTime: number;
                                                                                                                                                                                        }

                                                                                                                                                                                        Hierarchy (View Summary)

                                                                                                                                                                                        Index

                                                                                                                                                                                        Properties

                                                                                                                                                                                        interface Transfer {
                                                                                                                                                                                            destination: string;
                                                                                                                                                                                            duration: number;
                                                                                                                                                                                            endTime: number;
                                                                                                                                                                                            origin: string;
                                                                                                                                                                                            startTime: number;
                                                                                                                                                                                        }

                                                                                                                                                                                        Hierarchy (View Summary)

                                                                                                                                                                                        Index

                                                                                                                                                                                        Properties

                                                                                                                                                                                        destination: string
                                                                                                                                                                                        duration: number
                                                                                                                                                                                        endTime: number

                                                                                                                                                                                        Valid end time for this transfer window.

                                                                                                                                                                                        -
                                                                                                                                                                                        origin: string
                                                                                                                                                                                        startTime: number

                                                                                                                                                                                        Valid start time for this transfer window.

                                                                                                                                                                                        -
                                                                                                                                                                                        +

                                                                                                                                                                                        Properties

                                                                                                                                                                                        destination: string
                                                                                                                                                                                        duration: number
                                                                                                                                                                                        endTime: number

                                                                                                                                                                                        Valid end time for this transfer window.

                                                                                                                                                                                        +
                                                                                                                                                                                        origin: string
                                                                                                                                                                                        startTime: number

                                                                                                                                                                                        Valid start time for this transfer window.

                                                                                                                                                                                        +
                                                                                                                                                                                        diff --git a/docs/interfaces/raptor_types.Trip.html b/docs/interfaces/raptor_types.Trip.html index 946cd62..cb09ba4 100644 --- a/docs/interfaces/raptor_types.Trip.html +++ b/docs/interfaces/raptor_types.Trip.html @@ -1,7 +1,7 @@ Trip | mbus-backend
                                                                                                                                                                                        mbus-backend
                                                                                                                                                                                          Preparing search index...

                                                                                                                                                                                          Interface Trip

                                                                                                                                                                                          Represents a transit vehicle run (GTFS Trip).

                                                                                                                                                                                          -
                                                                                                                                                                                          interface Trip {
                                                                                                                                                                                              stopTimes: StopTime[];
                                                                                                                                                                                              tripId: string;
                                                                                                                                                                                              vid: string | null;
                                                                                                                                                                                          }
                                                                                                                                                                                          Index

                                                                                                                                                                                          Properties

                                                                                                                                                                                          interface Trip {
                                                                                                                                                                                              stopTimes: StopTime[];
                                                                                                                                                                                              tripId: string;
                                                                                                                                                                                              vid: string | null;
                                                                                                                                                                                          }
                                                                                                                                                                                          Index

                                                                                                                                                                                          Properties

                                                                                                                                                                                          Properties

                                                                                                                                                                                          stopTimes: StopTime[]

                                                                                                                                                                                          Ordered list of stops made by this trip.

                                                                                                                                                                                          -
                                                                                                                                                                                          tripId: string
                                                                                                                                                                                          vid: string | null

                                                                                                                                                                                          Vehicle ID, if available.

                                                                                                                                                                                          -
                                                                                                                                                                                          +
                                                                                                                                                                                          tripId: string
                                                                                                                                                                                          vid: string | null

                                                                                                                                                                                          Vehicle ID, if available.

                                                                                                                                                                                          +
                                                                                                                                                                                          diff --git a/docs/interfaces/walking_contractionHierarchy.ChQueryResult.html b/docs/interfaces/walking_contractionHierarchy.ChQueryResult.html new file mode 100644 index 0000000..7a00b5f --- /dev/null +++ b/docs/interfaces/walking_contractionHierarchy.ChQueryResult.html @@ -0,0 +1,3 @@ +ChQueryResult | mbus-backend
                                                                                                                                                                                          mbus-backend
                                                                                                                                                                                            Preparing search index...
                                                                                                                                                                                            interface ChQueryResult {
                                                                                                                                                                                                nodes?: string[];
                                                                                                                                                                                                total_cost: number;
                                                                                                                                                                                            }
                                                                                                                                                                                            Index

                                                                                                                                                                                            Properties

                                                                                                                                                                                            Properties

                                                                                                                                                                                            nodes?: string[]
                                                                                                                                                                                            total_cost: number
                                                                                                                                                                                            diff --git a/docs/interfaces/walking_walkingMap.BatchWalkingResult.html b/docs/interfaces/walking_walkingMap.BatchWalkingResult.html deleted file mode 100644 index 7995faa..0000000 --- a/docs/interfaces/walking_walkingMap.BatchWalkingResult.html +++ /dev/null @@ -1,8 +0,0 @@ -BatchWalkingResult | mbus-backend
                                                                                                                                                                                            mbus-backend
                                                                                                                                                                                              Preparing search index...

                                                                                                                                                                                              Interface BatchWalkingResult

                                                                                                                                                                                              Result of a batch query from a single origin node to multiple destinations.

                                                                                                                                                                                              -
                                                                                                                                                                                              interface BatchWalkingResult {
                                                                                                                                                                                                  distanceToNode: number;
                                                                                                                                                                                                  nearestNodeId: string;
                                                                                                                                                                                                  nodeDistances: Map<string, number>;
                                                                                                                                                                                              }
                                                                                                                                                                                              Index

                                                                                                                                                                                              Properties

                                                                                                                                                                                              distanceToNode: number

                                                                                                                                                                                              The straight-line distance from the origin coordinates to the street node.

                                                                                                                                                                                              -
                                                                                                                                                                                              nearestNodeId: string

                                                                                                                                                                                              The ID of the street node closest to the origin coordinates.

                                                                                                                                                                                              -
                                                                                                                                                                                              nodeDistances: Map<string, number>

                                                                                                                                                                                              A map of NodeID -> Distance (in meters) for all reachable nodes.

                                                                                                                                                                                              -
                                                                                                                                                                                              diff --git a/docs/interfaces/walking_walkingMap.WalkingResponse.html b/docs/interfaces/walking_walkingMap.WalkingResponse.html index 2889134..d7d5acd 100644 --- a/docs/interfaces/walking_walkingMap.WalkingResponse.html +++ b/docs/interfaces/walking_walkingMap.WalkingResponse.html @@ -1,8 +1,5 @@ WalkingResponse | mbus-backend
                                                                                                                                                                                              mbus-backend
                                                                                                                                                                                                Preparing search index...

                                                                                                                                                                                                Interface WalkingResponse

                                                                                                                                                                                                Standard response for a single point-to-point walking query.

                                                                                                                                                                                                -
                                                                                                                                                                                                interface WalkingResponse {
                                                                                                                                                                                                    distance: number;
                                                                                                                                                                                                    duration: number;
                                                                                                                                                                                                    path_coords: { lat: number; lon: number }[];
                                                                                                                                                                                                }
                                                                                                                                                                                                Index

                                                                                                                                                                                                Properties

                                                                                                                                                                                                interface WalkingResponse {
                                                                                                                                                                                                    distance: number;
                                                                                                                                                                                                    duration: number;
                                                                                                                                                                                                    path_coords: { lat: number; lon: number }[];
                                                                                                                                                                                                }
                                                                                                                                                                                                Index

                                                                                                                                                                                                Properties

                                                                                                                                                                                                distance: number

                                                                                                                                                                                                Walking distance in meters.

                                                                                                                                                                                                -
                                                                                                                                                                                                duration: number

                                                                                                                                                                                                Walking duration in seconds.

                                                                                                                                                                                                -
                                                                                                                                                                                                path_coords: { lat: number; lon: number }[]

                                                                                                                                                                                                Ordered list of coordinates representing the walking path geometry.

                                                                                                                                                                                                -
                                                                                                                                                                                                +

                                                                                                                                                                                                Properties

                                                                                                                                                                                                distance: number
                                                                                                                                                                                                duration: number
                                                                                                                                                                                                path_coords: { lat: number; lon: number }[]
                                                                                                                                                                                                diff --git a/docs/media/test_example.png b/docs/media/test_example.png index 41667bd..498b3e5 100644 Binary files a/docs/media/test_example.png and b/docs/media/test_example.png differ diff --git a/docs/modules.html b/docs/modules.html index 9561e10..d8c99d6 100644 --- a/docs/modules.html +++ b/docs/modules.html @@ -1 +1 @@ -mbus-backend
                                                                                                                                                                                                mbus-backend
                                                                                                                                                                                                  Preparing search index...

                                                                                                                                                                                                    mbus-backend

                                                                                                                                                                                                    Modules

                                                                                                                                                                                                    app
                                                                                                                                                                                                    jobs
                                                                                                                                                                                                    raptor/McRaptorAlgorithm
                                                                                                                                                                                                    raptor/McStructs
                                                                                                                                                                                                    raptor/types
                                                                                                                                                                                                    routes/api
                                                                                                                                                                                                    services/graphBuilder
                                                                                                                                                                                                    services/journey
                                                                                                                                                                                                    services/mbus
                                                                                                                                                                                                    services/metadata
                                                                                                                                                                                                    services/reminder
                                                                                                                                                                                                    services/reminderTypes
                                                                                                                                                                                                    services/ride
                                                                                                                                                                                                    state/transitState
                                                                                                                                                                                                    types
                                                                                                                                                                                                    walking/loadMap
                                                                                                                                                                                                    walking/types
                                                                                                                                                                                                    walking/walkingMap
                                                                                                                                                                                                    +mbus-backend
                                                                                                                                                                                                    mbus-backend
                                                                                                                                                                                                      Preparing search index...

                                                                                                                                                                                                        mbus-backend

                                                                                                                                                                                                        Modules

                                                                                                                                                                                                        app
                                                                                                                                                                                                        jobs
                                                                                                                                                                                                        raptor/McRaptorAlgorithm
                                                                                                                                                                                                        raptor/McStructs
                                                                                                                                                                                                        raptor/types
                                                                                                                                                                                                        routes/api
                                                                                                                                                                                                        services/graphBuilder
                                                                                                                                                                                                        services/journey
                                                                                                                                                                                                        services/mbus
                                                                                                                                                                                                        services/metadata
                                                                                                                                                                                                        services/reminder
                                                                                                                                                                                                        services/reminderTypes
                                                                                                                                                                                                        services/ride
                                                                                                                                                                                                        state/transitState
                                                                                                                                                                                                        types
                                                                                                                                                                                                        walking/contractionHierarchy
                                                                                                                                                                                                        walking/loadMap
                                                                                                                                                                                                        walking/types
                                                                                                                                                                                                        walking/walkingMap
                                                                                                                                                                                                        walking/walkingShortcuts
                                                                                                                                                                                                        diff --git a/docs/modules/raptor_McRaptorAlgorithm.html b/docs/modules/raptor_McRaptorAlgorithm.html index b3e9157..fe69a8f 100644 --- a/docs/modules/raptor_McRaptorAlgorithm.html +++ b/docs/modules/raptor_McRaptorAlgorithm.html @@ -1 +1 @@ -raptor/McRaptorAlgorithm | mbus-backend
                                                                                                                                                                                                        mbus-backend
                                                                                                                                                                                                          Preparing search index...

                                                                                                                                                                                                          Module raptor/McRaptorAlgorithm

                                                                                                                                                                                                          Classes

                                                                                                                                                                                                          McRaptorAlgorithm

                                                                                                                                                                                                          Interfaces

                                                                                                                                                                                                          Journey
                                                                                                                                                                                                          JourneyLeg
                                                                                                                                                                                                          +raptor/McRaptorAlgorithm | mbus-backend
                                                                                                                                                                                                          mbus-backend
                                                                                                                                                                                                            Preparing search index...

                                                                                                                                                                                                            Module raptor/McRaptorAlgorithm

                                                                                                                                                                                                            Classes

                                                                                                                                                                                                            McRaptorIndex

                                                                                                                                                                                                            Interfaces

                                                                                                                                                                                                            Journey
                                                                                                                                                                                                            JourneyLeg
                                                                                                                                                                                                            McRaptorQueryOverlay

                                                                                                                                                                                                            Variables

                                                                                                                                                                                                            VIRTUAL_DESTINATION
                                                                                                                                                                                                            VIRTUAL_ORIGIN

                                                                                                                                                                                                            Functions

                                                                                                                                                                                                            buildQueryOverlay
                                                                                                                                                                                                            diff --git a/docs/modules/state_transitState.html b/docs/modules/state_transitState.html index b09cede..cf1223f 100644 --- a/docs/modules/state_transitState.html +++ b/docs/modules/state_transitState.html @@ -1 +1 @@ -state/transitState | mbus-backend
                                                                                                                                                                                                            mbus-backend
                                                                                                                                                                                                              Preparing search index...

                                                                                                                                                                                                              Module state/transitState

                                                                                                                                                                                                              Type Aliases

                                                                                                                                                                                                              Prediction

                                                                                                                                                                                                              Variables

                                                                                                                                                                                                              cachedGraph
                                                                                                                                                                                                              cachedPredsByStopId
                                                                                                                                                                                                              cachedPredsByVid
                                                                                                                                                                                                              cachedRidePredsByStopId
                                                                                                                                                                                                              cachedRidePredsByVid
                                                                                                                                                                                                              cachedRideRoutes
                                                                                                                                                                                                              cachedRideStopLocations
                                                                                                                                                                                                              cachedRoutes
                                                                                                                                                                                                              cachedStopLocations
                                                                                                                                                                                                              curBusPositions
                                                                                                                                                                                                              curRidePositions
                                                                                                                                                                                                              rideStopIdToName
                                                                                                                                                                                                              routeTimingCache
                                                                                                                                                                                                              stopIdToName
                                                                                                                                                                                                              tatripidToRt
                                                                                                                                                                                                              validRideRoutes
                                                                                                                                                                                                              validRoutes

                                                                                                                                                                                                              Functions

                                                                                                                                                                                                              setCachedGraph
                                                                                                                                                                                                              setCachedRideStopLocations
                                                                                                                                                                                                              setCachedStopLocations
                                                                                                                                                                                                              +state/transitState | mbus-backend
                                                                                                                                                                                                              mbus-backend
                                                                                                                                                                                                                Preparing search index...

                                                                                                                                                                                                                Module state/transitState

                                                                                                                                                                                                                Type Aliases

                                                                                                                                                                                                                Prediction

                                                                                                                                                                                                                Variables

                                                                                                                                                                                                                cachedGraph
                                                                                                                                                                                                                cachedPredsByStopId
                                                                                                                                                                                                                cachedPredsByVid
                                                                                                                                                                                                                cachedRidePredsByStopId
                                                                                                                                                                                                                cachedRidePredsByVid
                                                                                                                                                                                                                cachedRideRoutes
                                                                                                                                                                                                                cachedRideStopLocations
                                                                                                                                                                                                                cachedRoutes
                                                                                                                                                                                                                cachedStopLocations
                                                                                                                                                                                                                curBusPositions
                                                                                                                                                                                                                curRidePositions
                                                                                                                                                                                                                mcRaptorIndex
                                                                                                                                                                                                                rideStopIdToName
                                                                                                                                                                                                                routeTimingCache
                                                                                                                                                                                                                stopIdToName
                                                                                                                                                                                                                tatripidToRt
                                                                                                                                                                                                                validRideRoutes
                                                                                                                                                                                                                validRoutes

                                                                                                                                                                                                                Functions

                                                                                                                                                                                                                setCachedGraph
                                                                                                                                                                                                                setCachedRideStopLocations
                                                                                                                                                                                                                setCachedStopLocations
                                                                                                                                                                                                                diff --git a/docs/modules/walking_contractionHierarchy.html b/docs/modules/walking_contractionHierarchy.html new file mode 100644 index 0000000..c94f4a5 --- /dev/null +++ b/docs/modules/walking_contractionHierarchy.html @@ -0,0 +1 @@ +walking/contractionHierarchy | mbus-backend
                                                                                                                                                                                                                mbus-backend
                                                                                                                                                                                                                  Preparing search index...

                                                                                                                                                                                                                  Module walking/contractionHierarchy

                                                                                                                                                                                                                  Classes

                                                                                                                                                                                                                  ContractionHierarchyGraph

                                                                                                                                                                                                                  Interfaces

                                                                                                                                                                                                                  ChQueryResult

                                                                                                                                                                                                                  Functions

                                                                                                                                                                                                                  buildGraphFromAdjacency
                                                                                                                                                                                                                  buildNearestNodeIndex
                                                                                                                                                                                                                  buildWalkingChAssets
                                                                                                                                                                                                                  getChFilePath
                                                                                                                                                                                                                  isChLoaded
                                                                                                                                                                                                                  loadContractionHierarchy
                                                                                                                                                                                                                  nearestGraphNode
                                                                                                                                                                                                                  queryDistance
                                                                                                                                                                                                                  queryDistancesFromOrigin
                                                                                                                                                                                                                  queryPath
                                                                                                                                                                                                                  stitchPathCoords
                                                                                                                                                                                                                  diff --git a/docs/modules/walking_types.html b/docs/modules/walking_types.html index 247a6fb..698d63b 100644 --- a/docs/modules/walking_types.html +++ b/docs/modules/walking_types.html @@ -1 +1 @@ -walking/types | mbus-backend
                                                                                                                                                                                                                  mbus-backend
                                                                                                                                                                                                                    Preparing search index...

                                                                                                                                                                                                                    Module walking/types

                                                                                                                                                                                                                    Type Aliases

                                                                                                                                                                                                                    GraphMLEdge
                                                                                                                                                                                                                    GraphMLNode
                                                                                                                                                                                                                    LandmarkDef
                                                                                                                                                                                                                    +walking/types | mbus-backend
                                                                                                                                                                                                                    mbus-backend
                                                                                                                                                                                                                      Preparing search index...

                                                                                                                                                                                                                      Module walking/types

                                                                                                                                                                                                                      Type Aliases

                                                                                                                                                                                                                      GraphMLEdge
                                                                                                                                                                                                                      GraphMLNode
                                                                                                                                                                                                                      diff --git a/docs/modules/walking_walkingMap.html b/docs/modules/walking_walkingMap.html index bbb0db7..785a1d9 100644 --- a/docs/modules/walking_walkingMap.html +++ b/docs/modules/walking_walkingMap.html @@ -1 +1 @@ -walking/walkingMap | mbus-backend
                                                                                                                                                                                                                      mbus-backend
                                                                                                                                                                                                                        Preparing search index...

                                                                                                                                                                                                                        Module walking/walkingMap

                                                                                                                                                                                                                        Interfaces

                                                                                                                                                                                                                        BatchWalkingResult
                                                                                                                                                                                                                        WalkingResponse

                                                                                                                                                                                                                        Functions

                                                                                                                                                                                                                        buildStopNodeMap
                                                                                                                                                                                                                        ensureCacheForStops
                                                                                                                                                                                                                        getCachedWalk
                                                                                                                                                                                                                        getWalkingDistancesFrom
                                                                                                                                                                                                                        getWalkingResponse
                                                                                                                                                                                                                        +walking/walkingMap | mbus-backend
                                                                                                                                                                                                                        mbus-backend
                                                                                                                                                                                                                          Preparing search index...

                                                                                                                                                                                                                          Module walking/walkingMap

                                                                                                                                                                                                                          Interfaces

                                                                                                                                                                                                                          WalkingResponse

                                                                                                                                                                                                                          Functions

                                                                                                                                                                                                                          __computeDijkstraAll
                                                                                                                                                                                                                          buildSparseWalkingTransfers
                                                                                                                                                                                                                          buildStopNodeMap
                                                                                                                                                                                                                          getWalkingDistancesFrom
                                                                                                                                                                                                                          getWalkingResponse
                                                                                                                                                                                                                          diff --git a/docs/modules/walking_walkingShortcuts.html b/docs/modules/walking_walkingShortcuts.html new file mode 100644 index 0000000..7d807cf --- /dev/null +++ b/docs/modules/walking_walkingShortcuts.html @@ -0,0 +1 @@ +walking/walkingShortcuts | mbus-backend
                                                                                                                                                                                                                          mbus-backend
                                                                                                                                                                                                                            Preparing search index...

                                                                                                                                                                                                                            Module walking/walkingShortcuts

                                                                                                                                                                                                                            Type Aliases

                                                                                                                                                                                                                            StopWalkMeters

                                                                                                                                                                                                                            Functions

                                                                                                                                                                                                                            countStopWalkEdges
                                                                                                                                                                                                                            shortcutsToTransfers
                                                                                                                                                                                                                            transitiveReductionShortcuts
                                                                                                                                                                                                                            diff --git a/docs/types/raptor_McStructs.Criteria.html b/docs/types/raptor_McStructs.Criteria.html index f731f5d..517fc86 100644 --- a/docs/types/raptor_McStructs.Criteria.html +++ b/docs/types/raptor_McStructs.Criteria.html @@ -1,5 +1,5 @@ Criteria | mbus-backend
                                                                                                                                                                                                                            mbus-backend
                                                                                                                                                                                                                              Preparing search index...

                                                                                                                                                                                                                              Type Alias Criteria

                                                                                                                                                                                                                              Defines the optimization metrics used to compare different journey options.

                                                                                                                                                                                                                              -
                                                                                                                                                                                                                              type Criteria = {
                                                                                                                                                                                                                                  arrivalTime: number;
                                                                                                                                                                                                                                  transferCount: number;
                                                                                                                                                                                                                                  walkingDistance: number;
                                                                                                                                                                                                                              }
                                                                                                                                                                                                                              Index

                                                                                                                                                                                                                              Properties

                                                                                                                                                                                                                              type Criteria = {
                                                                                                                                                                                                                                  arrivalTime: number;
                                                                                                                                                                                                                                  transferCount: number;
                                                                                                                                                                                                                                  walkingDistance: number;
                                                                                                                                                                                                                              }
                                                                                                                                                                                                                              Index

                                                                                                                                                                                                                              Properties

                                                                                                                                                                                                                              arrivalTime: number
                                                                                                                                                                                                                              transferCount: number
                                                                                                                                                                                                                              walkingDistance: number
                                                                                                                                                                                                                              +

                                                                                                                                                                                                                              Properties

                                                                                                                                                                                                                              arrivalTime: number
                                                                                                                                                                                                                              transferCount: number
                                                                                                                                                                                                                              walkingDistance: number
                                                                                                                                                                                                                              diff --git a/docs/types/raptor_types.Duration.html b/docs/types/raptor_types.Duration.html index bd2ff41..86559f0 100644 --- a/docs/types/raptor_types.Duration.html +++ b/docs/types/raptor_types.Duration.html @@ -1,2 +1,2 @@ Duration | mbus-backend
                                                                                                                                                                                                                              mbus-backend
                                                                                                                                                                                                                                Preparing search index...

                                                                                                                                                                                                                                Type Alias Duration

                                                                                                                                                                                                                                Duration: number

                                                                                                                                                                                                                                A span of time measured in seconds.

                                                                                                                                                                                                                                -
                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                diff --git a/docs/types/raptor_types.Interchange.html b/docs/types/raptor_types.Interchange.html index 018d219..6a83bb6 100644 --- a/docs/types/raptor_types.Interchange.html +++ b/docs/types/raptor_types.Interchange.html @@ -1,2 +1,2 @@ Interchange | mbus-backend
                                                                                                                                                                                                                                mbus-backend
                                                                                                                                                                                                                                  Preparing search index...

                                                                                                                                                                                                                                  Type Alias Interchange

                                                                                                                                                                                                                                  Interchange: Record<StopID, Time>

                                                                                                                                                                                                                                  Map defining the minimum time required to switch vehicles at each stop.

                                                                                                                                                                                                                                  -
                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                  diff --git a/docs/types/raptor_types.StopID.html b/docs/types/raptor_types.StopID.html index eec8b94..aa89958 100644 --- a/docs/types/raptor_types.StopID.html +++ b/docs/types/raptor_types.StopID.html @@ -1,2 +1,2 @@ StopID | mbus-backend
                                                                                                                                                                                                                                  mbus-backend
                                                                                                                                                                                                                                    Preparing search index...

                                                                                                                                                                                                                                    Type Alias StopID

                                                                                                                                                                                                                                    StopID: string

                                                                                                                                                                                                                                    Unique identifier for a transit stop (e.g., "NRW").

                                                                                                                                                                                                                                    -
                                                                                                                                                                                                                                    +
                                                                                                                                                                                                                                    diff --git a/docs/types/raptor_types.Time.html b/docs/types/raptor_types.Time.html index bdf5077..15e864a 100644 --- a/docs/types/raptor_types.Time.html +++ b/docs/types/raptor_types.Time.html @@ -1,3 +1,3 @@ Time | mbus-backend
                                                                                                                                                                                                                                    mbus-backend
                                                                                                                                                                                                                                      Preparing search index...

                                                                                                                                                                                                                                      Type Alias Time

                                                                                                                                                                                                                                      Time: number

                                                                                                                                                                                                                                      Time represented as seconds since midnight. Values may exceed 86400 (24 hours) for trips extending into the next day.

                                                                                                                                                                                                                                      -
                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      diff --git a/docs/types/raptor_types.TransfersByOrigin.html b/docs/types/raptor_types.TransfersByOrigin.html index b24eb74..aea9e57 100644 --- a/docs/types/raptor_types.TransfersByOrigin.html +++ b/docs/types/raptor_types.TransfersByOrigin.html @@ -1,2 +1,2 @@ TransfersByOrigin | mbus-backend
                                                                                                                                                                                                                                      mbus-backend
                                                                                                                                                                                                                                        Preparing search index...

                                                                                                                                                                                                                                        Type Alias TransfersByOrigin

                                                                                                                                                                                                                                        TransfersByOrigin: Record<StopID, Transfer[]>

                                                                                                                                                                                                                                        Lookup map for walking transfers, indexed by the origin Stop ID.

                                                                                                                                                                                                                                        -
                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                        diff --git a/docs/types/raptor_types.TripID.html b/docs/types/raptor_types.TripID.html index ae31e00..928a2a3 100644 --- a/docs/types/raptor_types.TripID.html +++ b/docs/types/raptor_types.TripID.html @@ -1,2 +1,2 @@ TripID | mbus-backend
                                                                                                                                                                                                                                        mbus-backend
                                                                                                                                                                                                                                          Preparing search index...

                                                                                                                                                                                                                                          Type Alias TripID

                                                                                                                                                                                                                                          TripID: string

                                                                                                                                                                                                                                          Unique identifier for a GTFS trip.

                                                                                                                                                                                                                                          -
                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                          diff --git a/docs/types/services_reminder.PostThreshold.html b/docs/types/services_reminder.PostThreshold.html index 2eca7ea..86ed1e0 100644 --- a/docs/types/services_reminder.PostThreshold.html +++ b/docs/types/services_reminder.PostThreshold.html @@ -1,7 +1,7 @@ PostThreshold | mbus-backend
                                                                                                                                                                                                                                          mbus-backend
                                                                                                                                                                                                                                            Preparing search index...

                                                                                                                                                                                                                                            Type Alias PostThreshold

                                                                                                                                                                                                                                            Waiting for the bus indicated by vid to be at the stop indicated by stpid. Logic for what notification to send is complicated by arrival times sometimes skipping DUE, see ReminderSubscriptons.process for details.

                                                                                                                                                                                                                                            -
                                                                                                                                                                                                                                            type PostThreshold = {
                                                                                                                                                                                                                                                event: BaseEvent;
                                                                                                                                                                                                                                                stage: 1;
                                                                                                                                                                                                                                                vid: string;
                                                                                                                                                                                                                                                vidPredPrev: number | null;
                                                                                                                                                                                                                                            }
                                                                                                                                                                                                                                            Index

                                                                                                                                                                                                                                            Properties

                                                                                                                                                                                                                                            type PostThreshold = {
                                                                                                                                                                                                                                                event: BaseEvent;
                                                                                                                                                                                                                                                stage: 1;
                                                                                                                                                                                                                                                vid: string;
                                                                                                                                                                                                                                                vidPredPrev: number | null;
                                                                                                                                                                                                                                            }
                                                                                                                                                                                                                                            Index

                                                                                                                                                                                                                                            Properties

                                                                                                                                                                                                                                            event: BaseEvent
                                                                                                                                                                                                                                            stage: 1
                                                                                                                                                                                                                                            vid: string
                                                                                                                                                                                                                                            vidPredPrev: number | null
                                                                                                                                                                                                                                            +

                                                                                                                                                                                                                                            Properties

                                                                                                                                                                                                                                            event: BaseEvent
                                                                                                                                                                                                                                            stage: 1
                                                                                                                                                                                                                                            vid: string
                                                                                                                                                                                                                                            vidPredPrev: number | null
                                                                                                                                                                                                                                            diff --git a/docs/types/services_reminder.PreThreshold.html b/docs/types/services_reminder.PreThreshold.html index 041f7fe..cc0131b 100644 --- a/docs/types/services_reminder.PreThreshold.html +++ b/docs/types/services_reminder.PreThreshold.html @@ -1,7 +1,7 @@ PreThreshold | mbus-backend
                                                                                                                                                                                                                                            mbus-backend
                                                                                                                                                                                                                                              Preparing search index...

                                                                                                                                                                                                                                              Type Alias PreThreshold

                                                                                                                                                                                                                                              Waiting for a prediction of the right event to have a arrival timestamp that is at or after mustBeAfter and an arrival time less than thresh. A bus is xx minutes from the stop notification is then sent. To handle delayed and disappeared notifications, a candidateVid is set to the soonest arriving bus that arrives after mustbeAfter.

                                                                                                                                                                                                                                              -
                                                                                                                                                                                                                                              type PreThreshold = {
                                                                                                                                                                                                                                                  candidateVid: string | null;
                                                                                                                                                                                                                                                  candidateVidPredPrev: number | null;
                                                                                                                                                                                                                                                  event: BaseEvent;
                                                                                                                                                                                                                                                  mustBeAfter: number;
                                                                                                                                                                                                                                                  stage: 0;
                                                                                                                                                                                                                                                  thresh: number;
                                                                                                                                                                                                                                              }
                                                                                                                                                                                                                                              Index

                                                                                                                                                                                                                                              Properties

                                                                                                                                                                                                                                              type PreThreshold = {
                                                                                                                                                                                                                                                  candidateVid: string | null;
                                                                                                                                                                                                                                                  candidateVidPredPrev: number | null;
                                                                                                                                                                                                                                                  event: BaseEvent;
                                                                                                                                                                                                                                                  mustBeAfter: number;
                                                                                                                                                                                                                                                  stage: 0;
                                                                                                                                                                                                                                                  thresh: number;
                                                                                                                                                                                                                                              }
                                                                                                                                                                                                                                              Index

                                                                                                                                                                                                                                              Properties

                                                                                                                                                                                                                                              candidateVid: string | null

                                                                                                                                                                                                                                              stores the bus that'll likely trigger the threshold notification, being only a candidate this can change as things are updated and such a change won't trigger a disappeared notification

                                                                                                                                                                                                                                              -
                                                                                                                                                                                                                                              candidateVidPredPrev: number | null

                                                                                                                                                                                                                                              minutes

                                                                                                                                                                                                                                              -
                                                                                                                                                                                                                                              event: BaseEvent
                                                                                                                                                                                                                                              mustBeAfter: number

                                                                                                                                                                                                                                              unix epoch milliseconds

                                                                                                                                                                                                                                              -
                                                                                                                                                                                                                                              stage: 0
                                                                                                                                                                                                                                              thresh: number

                                                                                                                                                                                                                                              minutes

                                                                                                                                                                                                                                              -
                                                                                                                                                                                                                                              +
                                                                                                                                                                                                                                              candidateVidPredPrev: number | null

                                                                                                                                                                                                                                              minutes

                                                                                                                                                                                                                                              +
                                                                                                                                                                                                                                              event: BaseEvent
                                                                                                                                                                                                                                              mustBeAfter: number

                                                                                                                                                                                                                                              unix epoch milliseconds

                                                                                                                                                                                                                                              +
                                                                                                                                                                                                                                              stage: 0
                                                                                                                                                                                                                                              thresh: number

                                                                                                                                                                                                                                              minutes

                                                                                                                                                                                                                                              +
                                                                                                                                                                                                                                              diff --git a/docs/types/services_reminderTypes.BaseEvent.html b/docs/types/services_reminderTypes.BaseEvent.html index 1dcbcc2..967ab34 100644 --- a/docs/types/services_reminderTypes.BaseEvent.html +++ b/docs/types/services_reminderTypes.BaseEvent.html @@ -1 +1 @@ -BaseEvent | mbus-backend
                                                                                                                                                                                                                                              mbus-backend
                                                                                                                                                                                                                                                Preparing search index...
                                                                                                                                                                                                                                                BaseEvent: CoreEvent & { __brand: "event" }
                                                                                                                                                                                                                                                +BaseEvent | mbus-backend
                                                                                                                                                                                                                                                mbus-backend
                                                                                                                                                                                                                                                  Preparing search index...
                                                                                                                                                                                                                                                  BaseEvent: CoreEvent & { __brand: "event" }
                                                                                                                                                                                                                                                  diff --git a/docs/types/services_reminderTypes.DelayEvent.html b/docs/types/services_reminderTypes.DelayEvent.html index 44c549c..0ad3ba2 100644 --- a/docs/types/services_reminderTypes.DelayEvent.html +++ b/docs/types/services_reminderTypes.DelayEvent.html @@ -1 +1 @@ -DelayEvent | mbus-backend
                                                                                                                                                                                                                                                  mbus-backend
                                                                                                                                                                                                                                                    Preparing search index...
                                                                                                                                                                                                                                                    DelayEvent: CoreEvent & {
                                                                                                                                                                                                                                                        __brand: "delayEvent";
                                                                                                                                                                                                                                                        currPred: number;
                                                                                                                                                                                                                                                        prevPred: number;
                                                                                                                                                                                                                                                    }
                                                                                                                                                                                                                                                    +DelayEvent | mbus-backend
                                                                                                                                                                                                                                                    mbus-backend
                                                                                                                                                                                                                                                      Preparing search index...
                                                                                                                                                                                                                                                      DelayEvent: CoreEvent & {
                                                                                                                                                                                                                                                          __brand: "delayEvent";
                                                                                                                                                                                                                                                          currPred: number;
                                                                                                                                                                                                                                                          prevPred: number;
                                                                                                                                                                                                                                                      }
                                                                                                                                                                                                                                                      diff --git a/docs/types/services_reminderTypes.Key.html b/docs/types/services_reminderTypes.Key.html index f07b39c..5aea4b6 100644 --- a/docs/types/services_reminderTypes.Key.html +++ b/docs/types/services_reminderTypes.Key.html @@ -1 +1 @@ -Key | mbus-backend
                                                                                                                                                                                                                                                      mbus-backend
                                                                                                                                                                                                                                                        Preparing search index...

                                                                                                                                                                                                                                                        Type Alias Key<T>

                                                                                                                                                                                                                                                        Key: string & { __brand: "key"; __phantomData: T }

                                                                                                                                                                                                                                                        Type Parameters

                                                                                                                                                                                                                                                        • T
                                                                                                                                                                                                                                                        +Key | mbus-backend
                                                                                                                                                                                                                                                        mbus-backend
                                                                                                                                                                                                                                                          Preparing search index...

                                                                                                                                                                                                                                                          Type Alias Key<T>

                                                                                                                                                                                                                                                          Key: string & { __brand: "key"; __phantomData: T }

                                                                                                                                                                                                                                                          Type Parameters

                                                                                                                                                                                                                                                          • T
                                                                                                                                                                                                                                                          diff --git a/docs/types/services_reminderTypes.RegistrationToken.html b/docs/types/services_reminderTypes.RegistrationToken.html index a46cd40..8277c3e 100644 --- a/docs/types/services_reminderTypes.RegistrationToken.html +++ b/docs/types/services_reminderTypes.RegistrationToken.html @@ -1 +1 @@ -RegistrationToken | mbus-backend
                                                                                                                                                                                                                                                          mbus-backend
                                                                                                                                                                                                                                                            Preparing search index...

                                                                                                                                                                                                                                                            Type Alias RegistrationToken

                                                                                                                                                                                                                                                            RegistrationToken: string & { __brand: "registrationToken" }
                                                                                                                                                                                                                                                            +RegistrationToken | mbus-backend
                                                                                                                                                                                                                                                            mbus-backend
                                                                                                                                                                                                                                                              Preparing search index...

                                                                                                                                                                                                                                                              Type Alias RegistrationToken

                                                                                                                                                                                                                                                              RegistrationToken: string & { __brand: "registrationToken" }
                                                                                                                                                                                                                                                              diff --git a/docs/types/services_reminderTypes.ThresholdEvent.html b/docs/types/services_reminderTypes.ThresholdEvent.html index 453a64b..6f4cf75 100644 --- a/docs/types/services_reminderTypes.ThresholdEvent.html +++ b/docs/types/services_reminderTypes.ThresholdEvent.html @@ -1 +1 @@ -ThresholdEvent | mbus-backend
                                                                                                                                                                                                                                                              mbus-backend
                                                                                                                                                                                                                                                                Preparing search index...

                                                                                                                                                                                                                                                                Type Alias ThresholdEvent

                                                                                                                                                                                                                                                                ThresholdEvent: CoreEvent & { __brand: "thresholdEvent"; threshold: number }
                                                                                                                                                                                                                                                                +ThresholdEvent | mbus-backend
                                                                                                                                                                                                                                                                mbus-backend
                                                                                                                                                                                                                                                                  Preparing search index...

                                                                                                                                                                                                                                                                  Type Alias ThresholdEvent

                                                                                                                                                                                                                                                                  ThresholdEvent: CoreEvent & {
                                                                                                                                                                                                                                                                      __brand: "thresholdEvent";
                                                                                                                                                                                                                                                                      exactly: boolean;
                                                                                                                                                                                                                                                                      threshold: number;
                                                                                                                                                                                                                                                                  }
                                                                                                                                                                                                                                                                  diff --git a/docs/types/state_transitState.Prediction.html b/docs/types/state_transitState.Prediction.html index 9d40436..3a121b1 100644 --- a/docs/types/state_transitState.Prediction.html +++ b/docs/types/state_transitState.Prediction.html @@ -1,2 +1,7 @@ Prediction | mbus-backend
                                                                                                                                                                                                                                                                  mbus-backend
                                                                                                                                                                                                                                                                    Preparing search index...

                                                                                                                                                                                                                                                                    Type Alias Prediction

                                                                                                                                                                                                                                                                    Prediction: {
                                                                                                                                                                                                                                                                        prdctdn: string;
                                                                                                                                                                                                                                                                        prdtm: number;
                                                                                                                                                                                                                                                                        rt: string;
                                                                                                                                                                                                                                                                        stpid: string;
                                                                                                                                                                                                                                                                        vid: string;
                                                                                                                                                                                                                                                                    } & Record<string, any>

                                                                                                                                                                                                                                                                    Represents a bus prediction.

                                                                                                                                                                                                                                                                    -
                                                                                                                                                                                                                                                                    +

                                                                                                                                                                                                                                                                    Type Declaration

                                                                                                                                                                                                                                                                    diff --git a/docs/types/types.Route.html b/docs/types/types.Route.html index c373f72..1a2e40c 100644 --- a/docs/types/types.Route.html +++ b/docs/types/types.Route.html @@ -1,2 +1,2 @@ -Route | mbus-backend
                                                                                                                                                                                                                                                                    mbus-backend
                                                                                                                                                                                                                                                                      Preparing search index...

                                                                                                                                                                                                                                                                      Type Alias Route

                                                                                                                                                                                                                                                                      type Route = {
                                                                                                                                                                                                                                                                          rt: string;
                                                                                                                                                                                                                                                                      }
                                                                                                                                                                                                                                                                      Index

                                                                                                                                                                                                                                                                      Properties

                                                                                                                                                                                                                                                                      rt -

                                                                                                                                                                                                                                                                      Properties

                                                                                                                                                                                                                                                                      rt: string
                                                                                                                                                                                                                                                                      +Route | mbus-backend
                                                                                                                                                                                                                                                                      mbus-backend
                                                                                                                                                                                                                                                                        Preparing search index...

                                                                                                                                                                                                                                                                        Type Alias Route

                                                                                                                                                                                                                                                                        type Route = {
                                                                                                                                                                                                                                                                            rt: string;
                                                                                                                                                                                                                                                                        }
                                                                                                                                                                                                                                                                        Index

                                                                                                                                                                                                                                                                        Properties

                                                                                                                                                                                                                                                                        rt +

                                                                                                                                                                                                                                                                        Properties

                                                                                                                                                                                                                                                                        rt: string
                                                                                                                                                                                                                                                                        diff --git a/docs/types/walking_types.GraphMLEdge.html b/docs/types/walking_types.GraphMLEdge.html index 1ed522b..d7a0483 100644 --- a/docs/types/walking_types.GraphMLEdge.html +++ b/docs/types/walking_types.GraphMLEdge.html @@ -1,8 +1,8 @@ GraphMLEdge | mbus-backend
                                                                                                                                                                                                                                                                        mbus-backend
                                                                                                                                                                                                                                                                          Preparing search index...

                                                                                                                                                                                                                                                                          Type Alias GraphMLEdge

                                                                                                                                                                                                                                                                          Represents a directed edge (street segment) connecting two nodes.

                                                                                                                                                                                                                                                                          -
                                                                                                                                                                                                                                                                          type GraphMLEdge = {
                                                                                                                                                                                                                                                                              dist: number;
                                                                                                                                                                                                                                                                              geometry?: { lat: number; lon: number }[];
                                                                                                                                                                                                                                                                              to: string;
                                                                                                                                                                                                                                                                          }
                                                                                                                                                                                                                                                                          Index

                                                                                                                                                                                                                                                                          Properties

                                                                                                                                                                                                                                                                          type GraphMLEdge = {
                                                                                                                                                                                                                                                                              dist: number;
                                                                                                                                                                                                                                                                              geometry?: { lat: number; lon: number }[];
                                                                                                                                                                                                                                                                              to: string;
                                                                                                                                                                                                                                                                          }
                                                                                                                                                                                                                                                                          Index

                                                                                                                                                                                                                                                                          Properties

                                                                                                                                                                                                                                                                          Properties

                                                                                                                                                                                                                                                                          dist: number

                                                                                                                                                                                                                                                                          Length of the edge in meters.

                                                                                                                                                                                                                                                                          -
                                                                                                                                                                                                                                                                          geometry?: { lat: number; lon: number }[]

                                                                                                                                                                                                                                                                          Detailed geometry points (WKT) for rendering curved paths.

                                                                                                                                                                                                                                                                          -
                                                                                                                                                                                                                                                                          to: string

                                                                                                                                                                                                                                                                          The ID of the target node this edge leads to.

                                                                                                                                                                                                                                                                          -
                                                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                                                          geometry?: { lat: number; lon: number }[]

                                                                                                                                                                                                                                                                          Detailed geometry points (WKT) for rendering curved paths.

                                                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                                                          to: string

                                                                                                                                                                                                                                                                          The ID of the target node this edge leads to.

                                                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                                                          diff --git a/docs/types/walking_types.GraphMLNode.html b/docs/types/walking_types.GraphMLNode.html index f225f2c..d07feda 100644 --- a/docs/types/walking_types.GraphMLNode.html +++ b/docs/types/walking_types.GraphMLNode.html @@ -1,8 +1,8 @@ GraphMLNode | mbus-backend
                                                                                                                                                                                                                                                                          mbus-backend
                                                                                                                                                                                                                                                                            Preparing search index...

                                                                                                                                                                                                                                                                            Type Alias GraphMLNode

                                                                                                                                                                                                                                                                            Represents a node in the street graph derived from GraphML.

                                                                                                                                                                                                                                                                            -
                                                                                                                                                                                                                                                                            type GraphMLNode = {
                                                                                                                                                                                                                                                                                id: string;
                                                                                                                                                                                                                                                                                lat: number;
                                                                                                                                                                                                                                                                                lon: number;
                                                                                                                                                                                                                                                                            }
                                                                                                                                                                                                                                                                            Index

                                                                                                                                                                                                                                                                            Properties

                                                                                                                                                                                                                                                                            id +
                                                                                                                                                                                                                                                                            type GraphMLNode = {
                                                                                                                                                                                                                                                                                id: string;
                                                                                                                                                                                                                                                                                lat: number;
                                                                                                                                                                                                                                                                                lon: number;
                                                                                                                                                                                                                                                                            }
                                                                                                                                                                                                                                                                            Index

                                                                                                                                                                                                                                                                            Properties

                                                                                                                                                                                                                                                                            Properties

                                                                                                                                                                                                                                                                            id: string

                                                                                                                                                                                                                                                                            Unique identifier for the node (from OSM/GraphML).

                                                                                                                                                                                                                                                                            -
                                                                                                                                                                                                                                                                            lat: number

                                                                                                                                                                                                                                                                            Latitude coordinate.

                                                                                                                                                                                                                                                                            -
                                                                                                                                                                                                                                                                            lon: number

                                                                                                                                                                                                                                                                            Longitude coordinate.

                                                                                                                                                                                                                                                                            -
                                                                                                                                                                                                                                                                            +
                                                                                                                                                                                                                                                                            lat: number

                                                                                                                                                                                                                                                                            Latitude coordinate.

                                                                                                                                                                                                                                                                            +
                                                                                                                                                                                                                                                                            lon: number

                                                                                                                                                                                                                                                                            Longitude coordinate.

                                                                                                                                                                                                                                                                            +
                                                                                                                                                                                                                                                                            diff --git a/docs/types/walking_types.LandmarkDef.html b/docs/types/walking_types.LandmarkDef.html deleted file mode 100644 index 915b411..0000000 --- a/docs/types/walking_types.LandmarkDef.html +++ /dev/null @@ -1,10 +0,0 @@ -LandmarkDef | mbus-backend
                                                                                                                                                                                                                                                                            mbus-backend
                                                                                                                                                                                                                                                                              Preparing search index...

                                                                                                                                                                                                                                                                              Type Alias LandmarkDef

                                                                                                                                                                                                                                                                              Definition for a navigation landmark used in the ALT heuristic algorithm.

                                                                                                                                                                                                                                                                              -
                                                                                                                                                                                                                                                                              type LandmarkDef = {
                                                                                                                                                                                                                                                                                  lat: number;
                                                                                                                                                                                                                                                                                  lon: number;
                                                                                                                                                                                                                                                                                  name: string;
                                                                                                                                                                                                                                                                                  nodeId?: string;
                                                                                                                                                                                                                                                                              }
                                                                                                                                                                                                                                                                              Index

                                                                                                                                                                                                                                                                              Properties

                                                                                                                                                                                                                                                                              Properties

                                                                                                                                                                                                                                                                              lat: number

                                                                                                                                                                                                                                                                              Latitude coordinate.

                                                                                                                                                                                                                                                                              -
                                                                                                                                                                                                                                                                              lon: number

                                                                                                                                                                                                                                                                              Longitude coordinate.

                                                                                                                                                                                                                                                                              -
                                                                                                                                                                                                                                                                              name: string

                                                                                                                                                                                                                                                                              Display name of the landmark.

                                                                                                                                                                                                                                                                              -
                                                                                                                                                                                                                                                                              nodeId?: string

                                                                                                                                                                                                                                                                              The Graph Node ID nearest to this landmark (computed at runtime).

                                                                                                                                                                                                                                                                              -
                                                                                                                                                                                                                                                                              diff --git a/docs/types/walking_walkingShortcuts.StopWalkMeters.html b/docs/types/walking_walkingShortcuts.StopWalkMeters.html new file mode 100644 index 0000000..d5ddfcc --- /dev/null +++ b/docs/types/walking_walkingShortcuts.StopWalkMeters.html @@ -0,0 +1,2 @@ +StopWalkMeters | mbus-backend
                                                                                                                                                                                                                                                                              mbus-backend
                                                                                                                                                                                                                                                                                Preparing search index...
                                                                                                                                                                                                                                                                                StopWalkMeters: Map<string, Map<string, number>>

                                                                                                                                                                                                                                                                                Directed stop-to-stop walking distances in meters (only reachable pairs).

                                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                                diff --git a/docs/variables/raptor_McRaptorAlgorithm.VIRTUAL_DESTINATION.html b/docs/variables/raptor_McRaptorAlgorithm.VIRTUAL_DESTINATION.html new file mode 100644 index 0000000..c81067f --- /dev/null +++ b/docs/variables/raptor_McRaptorAlgorithm.VIRTUAL_DESTINATION.html @@ -0,0 +1 @@ +VIRTUAL_DESTINATION | mbus-backend
                                                                                                                                                                                                                                                                                mbus-backend
                                                                                                                                                                                                                                                                                  Preparing search index...

                                                                                                                                                                                                                                                                                  Variable VIRTUAL_DESTINATIONConst

                                                                                                                                                                                                                                                                                  VIRTUAL_DESTINATION: "VIRTUAL_DESTINATION" = 'VIRTUAL_DESTINATION'
                                                                                                                                                                                                                                                                                  diff --git a/docs/variables/raptor_McRaptorAlgorithm.VIRTUAL_ORIGIN.html b/docs/variables/raptor_McRaptorAlgorithm.VIRTUAL_ORIGIN.html new file mode 100644 index 0000000..ae0c68b --- /dev/null +++ b/docs/variables/raptor_McRaptorAlgorithm.VIRTUAL_ORIGIN.html @@ -0,0 +1 @@ +VIRTUAL_ORIGIN | mbus-backend
                                                                                                                                                                                                                                                                                  mbus-backend
                                                                                                                                                                                                                                                                                    Preparing search index...

                                                                                                                                                                                                                                                                                    Variable VIRTUAL_ORIGINConst

                                                                                                                                                                                                                                                                                    VIRTUAL_ORIGIN: "VIRTUAL_ORIGIN" = 'VIRTUAL_ORIGIN'
                                                                                                                                                                                                                                                                                    diff --git a/docs/variables/routes_api.default.html b/docs/variables/routes_api.default.html index b90e1b3..2c3be2f 100644 --- a/docs/variables/routes_api.default.html +++ b/docs/variables/routes_api.default.html @@ -1,3 +1,3 @@ default | mbus-backend
                                                                                                                                                                                                                                                                                    mbus-backend
                                                                                                                                                                                                                                                                                      Preparing search index...

                                                                                                                                                                                                                                                                                      Variable defaultConst

                                                                                                                                                                                                                                                                                      default: Router = ...

                                                                                                                                                                                                                                                                                      Express router for the MBus API v3. Handles routes for static data, state debugging, journey planning, and startup info.

                                                                                                                                                                                                                                                                                      -
                                                                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                                                                      diff --git a/docs/variables/services_metadata.staticData.html b/docs/variables/services_metadata.staticData.html index 02a705b..9afa7eb 100644 --- a/docs/variables/services_metadata.staticData.html +++ b/docs/variables/services_metadata.staticData.html @@ -1,2 +1,2 @@ staticData | mbus-backend
                                                                                                                                                                                                                                                                                      mbus-backend
                                                                                                                                                                                                                                                                                        Preparing search index...

                                                                                                                                                                                                                                                                                        Variable staticDataConst

                                                                                                                                                                                                                                                                                        staticData: any = metadata

                                                                                                                                                                                                                                                                                        Raw static metadata from JSON.

                                                                                                                                                                                                                                                                                        -
                                                                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                                                                        diff --git a/docs/variables/services_reminder.rideReminderSubscriptions.html b/docs/variables/services_reminder.rideReminderSubscriptions.html index f0c65df..22538cd 100644 --- a/docs/variables/services_reminder.rideReminderSubscriptions.html +++ b/docs/variables/services_reminder.rideReminderSubscriptions.html @@ -1 +1 @@ -rideReminderSubscriptions | mbus-backend
                                                                                                                                                                                                                                                                                        mbus-backend
                                                                                                                                                                                                                                                                                          Preparing search index...

                                                                                                                                                                                                                                                                                          Variable rideReminderSubscriptionsConst

                                                                                                                                                                                                                                                                                          rideReminderSubscriptions: ReminderSubscriptions = ...
                                                                                                                                                                                                                                                                                          +rideReminderSubscriptions | mbus-backend
                                                                                                                                                                                                                                                                                          mbus-backend
                                                                                                                                                                                                                                                                                            Preparing search index...

                                                                                                                                                                                                                                                                                            Variable rideReminderSubscriptionsConst

                                                                                                                                                                                                                                                                                            rideReminderSubscriptions: ReminderSubscriptions = ...
                                                                                                                                                                                                                                                                                            diff --git a/docs/variables/services_reminder.testing.html b/docs/variables/services_reminder.testing.html index 2f9349e..151d448 100644 --- a/docs/variables/services_reminder.testing.html +++ b/docs/variables/services_reminder.testing.html @@ -1,2 +1,2 @@ testing | mbus-backend
                                                                                                                                                                                                                                                                                            mbus-backend
                                                                                                                                                                                                                                                                                              Preparing search index...

                                                                                                                                                                                                                                                                                              Variable testingConst

                                                                                                                                                                                                                                                                                              testing: {
                                                                                                                                                                                                                                                                                                  eventsEqual: (e1: BaseEvent, e2: BaseEvent) => boolean;
                                                                                                                                                                                                                                                                                                  ReminderSubscriptions: typeof ReminderSubscriptions;
                                                                                                                                                                                                                                                                                              } = ...

                                                                                                                                                                                                                                                                                              exported for tests

                                                                                                                                                                                                                                                                                              -

                                                                                                                                                                                                                                                                                              Type Declaration

                                                                                                                                                                                                                                                                                              • eventsEqual: (e1: BaseEvent, e2: BaseEvent) => boolean
                                                                                                                                                                                                                                                                                              • ReminderSubscriptions: typeof ReminderSubscriptions
                                                                                                                                                                                                                                                                                              +

                                                                                                                                                                                                                                                                                              Type Declaration

                                                                                                                                                                                                                                                                                              diff --git a/docs/variables/services_reminder.universityReminderSubscriptions.html b/docs/variables/services_reminder.universityReminderSubscriptions.html index b19565d..0ecc6b2 100644 --- a/docs/variables/services_reminder.universityReminderSubscriptions.html +++ b/docs/variables/services_reminder.universityReminderSubscriptions.html @@ -1 +1 @@ -universityReminderSubscriptions | mbus-backend
                                                                                                                                                                                                                                                                                              mbus-backend
                                                                                                                                                                                                                                                                                                Preparing search index...

                                                                                                                                                                                                                                                                                                Variable universityReminderSubscriptionsConst

                                                                                                                                                                                                                                                                                                universityReminderSubscriptions: ReminderSubscriptions = ...
                                                                                                                                                                                                                                                                                                +universityReminderSubscriptions | mbus-backend
                                                                                                                                                                                                                                                                                                mbus-backend
                                                                                                                                                                                                                                                                                                  Preparing search index...

                                                                                                                                                                                                                                                                                                  Variable universityReminderSubscriptionsConst

                                                                                                                                                                                                                                                                                                  universityReminderSubscriptions: ReminderSubscriptions = ...
                                                                                                                                                                                                                                                                                                  diff --git a/docs/variables/state_transitState.cachedGraph.html b/docs/variables/state_transitState.cachedGraph.html index 9b2a870..9877a07 100644 --- a/docs/variables/state_transitState.cachedGraph.html +++ b/docs/variables/state_transitState.cachedGraph.html @@ -1,2 +1,2 @@ cachedGraph | mbus-backend
                                                                                                                                                                                                                                                                                                  mbus-backend
                                                                                                                                                                                                                                                                                                    Preparing search index...

                                                                                                                                                                                                                                                                                                    Variable cachedGraph

                                                                                                                                                                                                                                                                                                    cachedGraph: {
                                                                                                                                                                                                                                                                                                        interchange: Interchange;
                                                                                                                                                                                                                                                                                                        transfers: TransfersByOrigin;
                                                                                                                                                                                                                                                                                                        trips: Trip[];
                                                                                                                                                                                                                                                                                                    } = ...

                                                                                                                                                                                                                                                                                                    The current transit graph used for routing.

                                                                                                                                                                                                                                                                                                    -

                                                                                                                                                                                                                                                                                                    Type Declaration

                                                                                                                                                                                                                                                                                                    +

                                                                                                                                                                                                                                                                                                    Type Declaration

                                                                                                                                                                                                                                                                                                    diff --git a/docs/variables/state_transitState.cachedPredsByStopId.html b/docs/variables/state_transitState.cachedPredsByStopId.html index 14a287b..8b86e84 100644 --- a/docs/variables/state_transitState.cachedPredsByStopId.html +++ b/docs/variables/state_transitState.cachedPredsByStopId.html @@ -1,2 +1,2 @@ cachedPredsByStopId | mbus-backend
                                                                                                                                                                                                                                                                                                    mbus-backend
                                                                                                                                                                                                                                                                                                      Preparing search index...

                                                                                                                                                                                                                                                                                                      Variable cachedPredsByStopIdConst

                                                                                                                                                                                                                                                                                                      cachedPredsByStopId: Record<string, Prediction[]> = {}

                                                                                                                                                                                                                                                                                                      Predictions indexed by stop ID.

                                                                                                                                                                                                                                                                                                      -
                                                                                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                                                                                      diff --git a/docs/variables/state_transitState.cachedPredsByVid.html b/docs/variables/state_transitState.cachedPredsByVid.html index e2f14ae..0e8a3a1 100644 --- a/docs/variables/state_transitState.cachedPredsByVid.html +++ b/docs/variables/state_transitState.cachedPredsByVid.html @@ -1,2 +1,2 @@ cachedPredsByVid | mbus-backend
                                                                                                                                                                                                                                                                                                      mbus-backend
                                                                                                                                                                                                                                                                                                        Preparing search index...

                                                                                                                                                                                                                                                                                                        Variable cachedPredsByVidConst

                                                                                                                                                                                                                                                                                                        cachedPredsByVid: Record<string, Prediction[]> = {}

                                                                                                                                                                                                                                                                                                        Predictions indexed by vehicle ID.

                                                                                                                                                                                                                                                                                                        -
                                                                                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                                                                                        diff --git a/docs/variables/state_transitState.cachedRidePredsByStopId.html b/docs/variables/state_transitState.cachedRidePredsByStopId.html index a2d90a8..a11a5fe 100644 --- a/docs/variables/state_transitState.cachedRidePredsByStopId.html +++ b/docs/variables/state_transitState.cachedRidePredsByStopId.html @@ -1,2 +1,2 @@ cachedRidePredsByStopId | mbus-backend
                                                                                                                                                                                                                                                                                                        mbus-backend
                                                                                                                                                                                                                                                                                                          Preparing search index...

                                                                                                                                                                                                                                                                                                          Variable cachedRidePredsByStopIdConst

                                                                                                                                                                                                                                                                                                          cachedRidePredsByStopId: Record<string, Prediction[]> = {}

                                                                                                                                                                                                                                                                                                          Predictions indexed by ride stop ID.

                                                                                                                                                                                                                                                                                                          -
                                                                                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                                                                                          diff --git a/docs/variables/state_transitState.cachedRidePredsByVid.html b/docs/variables/state_transitState.cachedRidePredsByVid.html index 67a79b1..80879d4 100644 --- a/docs/variables/state_transitState.cachedRidePredsByVid.html +++ b/docs/variables/state_transitState.cachedRidePredsByVid.html @@ -1,2 +1,2 @@ cachedRidePredsByVid | mbus-backend
                                                                                                                                                                                                                                                                                                          mbus-backend
                                                                                                                                                                                                                                                                                                            Preparing search index...

                                                                                                                                                                                                                                                                                                            Variable cachedRidePredsByVidConst

                                                                                                                                                                                                                                                                                                            cachedRidePredsByVid: Record<string, Prediction[]> = {}

                                                                                                                                                                                                                                                                                                            Predictions indexed by ride vehicle ID.

                                                                                                                                                                                                                                                                                                            -
                                                                                                                                                                                                                                                                                                            +
                                                                                                                                                                                                                                                                                                            diff --git a/docs/variables/state_transitState.cachedRideRoutes.html b/docs/variables/state_transitState.cachedRideRoutes.html index a85f23b..0c0edf9 100644 --- a/docs/variables/state_transitState.cachedRideRoutes.html +++ b/docs/variables/state_transitState.cachedRideRoutes.html @@ -1,2 +1,2 @@ cachedRideRoutes | mbus-backend
                                                                                                                                                                                                                                                                                                            mbus-backend
                                                                                                                                                                                                                                                                                                              Preparing search index...

                                                                                                                                                                                                                                                                                                              Variable cachedRideRoutesConst

                                                                                                                                                                                                                                                                                                              cachedRideRoutes: Record<string, any> = {}

                                                                                                                                                                                                                                                                                                              Cache of route patterns and static data for the ride.

                                                                                                                                                                                                                                                                                                              -
                                                                                                                                                                                                                                                                                                              +
                                                                                                                                                                                                                                                                                                              diff --git a/docs/variables/state_transitState.cachedRideStopLocations.html b/docs/variables/state_transitState.cachedRideStopLocations.html index 8eaa636..06e4a70 100644 --- a/docs/variables/state_transitState.cachedRideStopLocations.html +++ b/docs/variables/state_transitState.cachedRideStopLocations.html @@ -1 +1 @@ -cachedRideStopLocations | mbus-backend
                                                                                                                                                                                                                                                                                                              mbus-backend
                                                                                                                                                                                                                                                                                                                Preparing search index...

                                                                                                                                                                                                                                                                                                                Variable cachedRideStopLocations

                                                                                                                                                                                                                                                                                                                cachedRideStopLocations: Record<
                                                                                                                                                                                                                                                                                                                    string,
                                                                                                                                                                                                                                                                                                                    { lat: number; lon: number; name: string },
                                                                                                                                                                                                                                                                                                                > = {}
                                                                                                                                                                                                                                                                                                                +cachedRideStopLocations | mbus-backend
                                                                                                                                                                                                                                                                                                                mbus-backend
                                                                                                                                                                                                                                                                                                                  Preparing search index...

                                                                                                                                                                                                                                                                                                                  Variable cachedRideStopLocations

                                                                                                                                                                                                                                                                                                                  cachedRideStopLocations: Record<
                                                                                                                                                                                                                                                                                                                      string,
                                                                                                                                                                                                                                                                                                                      { lat: number; lon: number; name: string },
                                                                                                                                                                                                                                                                                                                  > = {}
                                                                                                                                                                                                                                                                                                                  diff --git a/docs/variables/state_transitState.cachedRoutes.html b/docs/variables/state_transitState.cachedRoutes.html index 4c54c10..d05546a 100644 --- a/docs/variables/state_transitState.cachedRoutes.html +++ b/docs/variables/state_transitState.cachedRoutes.html @@ -1,2 +1,2 @@ cachedRoutes | mbus-backend
                                                                                                                                                                                                                                                                                                                  mbus-backend
                                                                                                                                                                                                                                                                                                                    Preparing search index...

                                                                                                                                                                                                                                                                                                                    Variable cachedRoutesConst

                                                                                                                                                                                                                                                                                                                    cachedRoutes: Record<string, any> = {}

                                                                                                                                                                                                                                                                                                                    Cache of route patterns and static data.

                                                                                                                                                                                                                                                                                                                    -
                                                                                                                                                                                                                                                                                                                    +
                                                                                                                                                                                                                                                                                                                    diff --git a/docs/variables/state_transitState.cachedStopLocations.html b/docs/variables/state_transitState.cachedStopLocations.html index d89fc66..d982917 100644 --- a/docs/variables/state_transitState.cachedStopLocations.html +++ b/docs/variables/state_transitState.cachedStopLocations.html @@ -1,2 +1,2 @@ cachedStopLocations | mbus-backend
                                                                                                                                                                                                                                                                                                                    mbus-backend
                                                                                                                                                                                                                                                                                                                      Preparing search index...

                                                                                                                                                                                                                                                                                                                      Variable cachedStopLocations

                                                                                                                                                                                                                                                                                                                      cachedStopLocations: Record<string, { lat: number; lon: number; name: string }> = {}

                                                                                                                                                                                                                                                                                                                      Cache of stop locations (lat/lon).

                                                                                                                                                                                                                                                                                                                      -
                                                                                                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                                                                                                      diff --git a/docs/variables/state_transitState.curBusPositions.html b/docs/variables/state_transitState.curBusPositions.html index 7bc30bd..8659a07 100644 --- a/docs/variables/state_transitState.curBusPositions.html +++ b/docs/variables/state_transitState.curBusPositions.html @@ -1,2 +1,2 @@ curBusPositions | mbus-backend
                                                                                                                                                                                                                                                                                                                      mbus-backend
                                                                                                                                                                                                                                                                                                                        Preparing search index...

                                                                                                                                                                                                                                                                                                                        Variable curBusPositionsConst

                                                                                                                                                                                                                                                                                                                        curBusPositions: { buses: any[] } = ...

                                                                                                                                                                                                                                                                                                                        Current positions of all buses.

                                                                                                                                                                                                                                                                                                                        -

                                                                                                                                                                                                                                                                                                                        Type Declaration

                                                                                                                                                                                                                                                                                                                        • buses: any[]
                                                                                                                                                                                                                                                                                                                        +

                                                                                                                                                                                                                                                                                                                        Type Declaration

                                                                                                                                                                                                                                                                                                                        diff --git a/docs/variables/state_transitState.curRidePositions.html b/docs/variables/state_transitState.curRidePositions.html index 96ca1c9..9169047 100644 --- a/docs/variables/state_transitState.curRidePositions.html +++ b/docs/variables/state_transitState.curRidePositions.html @@ -1,2 +1,2 @@ curRidePositions | mbus-backend
                                                                                                                                                                                                                                                                                                                        mbus-backend
                                                                                                                                                                                                                                                                                                                          Preparing search index...

                                                                                                                                                                                                                                                                                                                          Variable curRidePositionsConst

                                                                                                                                                                                                                                                                                                                          curRidePositions: { buses: any[] } = ...

                                                                                                                                                                                                                                                                                                                          Current positions of all ride buses.

                                                                                                                                                                                                                                                                                                                          -

                                                                                                                                                                                                                                                                                                                          Type Declaration

                                                                                                                                                                                                                                                                                                                          • buses: any[]
                                                                                                                                                                                                                                                                                                                          +

                                                                                                                                                                                                                                                                                                                          Type Declaration

                                                                                                                                                                                                                                                                                                                          diff --git a/docs/variables/state_transitState.mcRaptorIndex.html b/docs/variables/state_transitState.mcRaptorIndex.html new file mode 100644 index 0000000..d1039b7 --- /dev/null +++ b/docs/variables/state_transitState.mcRaptorIndex.html @@ -0,0 +1,2 @@ +mcRaptorIndex | mbus-backend
                                                                                                                                                                                                                                                                                                                          mbus-backend
                                                                                                                                                                                                                                                                                                                            Preparing search index...

                                                                                                                                                                                                                                                                                                                            Variable mcRaptorIndex

                                                                                                                                                                                                                                                                                                                            mcRaptorIndex: McRaptorIndex | null = null

                                                                                                                                                                                                                                                                                                                            Pre-built McRAPTOR route indices; rebuilt when trips change.

                                                                                                                                                                                                                                                                                                                            +
                                                                                                                                                                                                                                                                                                                            diff --git a/docs/variables/state_transitState.rideStopIdToName.html b/docs/variables/state_transitState.rideStopIdToName.html index b36e20b..888f47f 100644 --- a/docs/variables/state_transitState.rideStopIdToName.html +++ b/docs/variables/state_transitState.rideStopIdToName.html @@ -1,2 +1,2 @@ rideStopIdToName | mbus-backend
                                                                                                                                                                                                                                                                                                                            mbus-backend
                                                                                                                                                                                                                                                                                                                              Preparing search index...

                                                                                                                                                                                                                                                                                                                              Variable rideStopIdToNameConst

                                                                                                                                                                                                                                                                                                                              rideStopIdToName: Record<string, string> = {}

                                                                                                                                                                                                                                                                                                                              Map of ride stop IDs to their human-readable names.

                                                                                                                                                                                                                                                                                                                              -
                                                                                                                                                                                                                                                                                                                              +
                                                                                                                                                                                                                                                                                                                              diff --git a/docs/variables/state_transitState.routeTimingCache.html b/docs/variables/state_transitState.routeTimingCache.html index 3a6c458..724cc2b 100644 --- a/docs/variables/state_transitState.routeTimingCache.html +++ b/docs/variables/state_transitState.routeTimingCache.html @@ -1,2 +1,2 @@ routeTimingCache | mbus-backend
                                                                                                                                                                                                                                                                                                                              mbus-backend
                                                                                                                                                                                                                                                                                                                                Preparing search index...

                                                                                                                                                                                                                                                                                                                                Variable routeTimingCacheConst

                                                                                                                                                                                                                                                                                                                                routeTimingCache: Record<
                                                                                                                                                                                                                                                                                                                                    string,
                                                                                                                                                                                                                                                                                                                                    Record<
                                                                                                                                                                                                                                                                                                                                        string,
                                                                                                                                                                                                                                                                                                                                        Record<string, { diff: number; rtdir: string; rtNext: string }>,
                                                                                                                                                                                                                                                                                                                                    >,
                                                                                                                                                                                                                                                                                                                                > = ...

                                                                                                                                                                                                                                                                                                                                Cache of timing differences between stops for extrapolation.

                                                                                                                                                                                                                                                                                                                                -
                                                                                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                                                                                diff --git a/docs/variables/state_transitState.stopIdToName.html b/docs/variables/state_transitState.stopIdToName.html index 567074d..0af8bc2 100644 --- a/docs/variables/state_transitState.stopIdToName.html +++ b/docs/variables/state_transitState.stopIdToName.html @@ -1,2 +1,2 @@ stopIdToName | mbus-backend
                                                                                                                                                                                                                                                                                                                                mbus-backend
                                                                                                                                                                                                                                                                                                                                  Preparing search index...

                                                                                                                                                                                                                                                                                                                                  Variable stopIdToNameConst

                                                                                                                                                                                                                                                                                                                                  stopIdToName: Record<string, string> = {}

                                                                                                                                                                                                                                                                                                                                  Map of stop IDs to their human-readable names.

                                                                                                                                                                                                                                                                                                                                  -
                                                                                                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                                                                                                  diff --git a/docs/variables/state_transitState.tatripidToRt.html b/docs/variables/state_transitState.tatripidToRt.html index f36d203..456f0b0 100644 --- a/docs/variables/state_transitState.tatripidToRt.html +++ b/docs/variables/state_transitState.tatripidToRt.html @@ -1,2 +1,2 @@ tatripidToRt | mbus-backend
                                                                                                                                                                                                                                                                                                                                  mbus-backend
                                                                                                                                                                                                                                                                                                                                    Preparing search index...

                                                                                                                                                                                                                                                                                                                                    Variable tatripidToRtConst

                                                                                                                                                                                                                                                                                                                                    tatripidToRt: Record<string, string> = {}

                                                                                                                                                                                                                                                                                                                                    Map of trip IDs to route names.

                                                                                                                                                                                                                                                                                                                                    -
                                                                                                                                                                                                                                                                                                                                    +
                                                                                                                                                                                                                                                                                                                                    diff --git a/docs/variables/state_transitState.validRideRoutes.html b/docs/variables/state_transitState.validRideRoutes.html index dcd6c7d..c5d98fd 100644 --- a/docs/variables/state_transitState.validRideRoutes.html +++ b/docs/variables/state_transitState.validRideRoutes.html @@ -1,2 +1,2 @@ validRideRoutes | mbus-backend
                                                                                                                                                                                                                                                                                                                                    mbus-backend
                                                                                                                                                                                                                                                                                                                                      Preparing search index...

                                                                                                                                                                                                                                                                                                                                      Variable validRideRoutesConst

                                                                                                                                                                                                                                                                                                                                      validRideRoutes: Set<string> = ...

                                                                                                                                                                                                                                                                                                                                      Set of currently valid ride route IDs.

                                                                                                                                                                                                                                                                                                                                      -
                                                                                                                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                                                                                                                      diff --git a/docs/variables/state_transitState.validRoutes.html b/docs/variables/state_transitState.validRoutes.html index dd1e43a..65e1e0f 100644 --- a/docs/variables/state_transitState.validRoutes.html +++ b/docs/variables/state_transitState.validRoutes.html @@ -1,2 +1,2 @@ validRoutes | mbus-backend
                                                                                                                                                                                                                                                                                                                                      mbus-backend
                                                                                                                                                                                                                                                                                                                                        Preparing search index...

                                                                                                                                                                                                                                                                                                                                        Variable validRoutesConst

                                                                                                                                                                                                                                                                                                                                        validRoutes: Set<string> = ...

                                                                                                                                                                                                                                                                                                                                        Set of currently valid route IDs.

                                                                                                                                                                                                                                                                                                                                        -
                                                                                                                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                                                                                                                        diff --git a/package.json b/package.json index 64c5d38..1d51d01 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "main": "src/app.ts", "scripts": { "start": "tsx src/app.ts", + "build:walking-ch": "node --max-old-space-size=8192 --import tsx src/walking/contractionHierarchy.ts", "test": "vitest run test", "stress-test": "vitest run test/search-stress.test.ts", "docs": "typedoc --entryPointStrategy expand ./src --exclude \"**/legacy/**\"" diff --git a/src/assets/ann_arbor.ch.json b/src/assets/ann_arbor.ch.json new file mode 100644 index 0000000..e5d4f0b --- /dev/null +++ b/src/assets/ann_arbor.ch.json @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:22cf7244ea81888ea9836d30377d802b5affac2526494cf802cc09c8797f8128 +size 45768451 diff --git a/src/assets/ch-metadata.json b/src/assets/ch-metadata.json new file mode 100644 index 0000000..66657f3 --- /dev/null +++ b/src/assets/ch-metadata.json @@ -0,0 +1,7 @@ +{ + "graphmlPath": "src/assets/ann_arbor.graphml", + "graphmlSha256": "e4488a8aece92b0c0a1a4c72dc2d4c90314ef68993b42ceea0f20c67404efac2", + "nodeCount": 51680, + "builtAt": "2026-06-12T19:09:21.061Z", + "chImplementation": "src/walking/ch (ported from contraction-hierarchy-js MIT)" +} \ No newline at end of file diff --git a/src/assets/walking-shortcuts.json b/src/assets/walking-shortcuts.json new file mode 100644 index 0000000..c159410 --- /dev/null +++ b/src/assets/walking-shortcuts.json @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c9ad493874877018675675234e9c98b823c8b790dd7a93b9d79a881ae8083290 +size 191750355 diff --git a/src/legacy/busService-reminders.ts b/src/legacy/busService-reminders.ts deleted file mode 100644 index 1ead44c..0000000 --- a/src/legacy/busService-reminders.ts +++ /dev/null @@ -1,683 +0,0 @@ -import * as process from "node:process"; - -import axios from 'axios'; -import dotenv from "dotenv"; -import { Route } from "@/types"; -import { - Trip, - StopTime, - Transfer, - StopID, - TransfersByOrigin, - Interchange -} from "./raptor/types"; - -dotenv.config(); - -const API_KEY = process.env.MBUS_API_KEY; -if (API_KEY === undefined) { - throw new Error("MBus API key not set."); -} - -const curBusPositions: { - buses: any[] -} = { - "buses": [] -} - -const cachedRoutes: {[k: string]: any} = {}; -type Prediction = { vid: string; stpid: string } & Record; - -let cachedPredsByVid: Record = {}; -let cachedPredsByStopId: Record = {}; -// routeTimingCache: route -> fromStop -> toStop -> latest diff (minutes) -const routeTimingCache: Record>> = -{ - "CN": { - "N434NORTHBOUND": { - "N500": { - "diff": 5, - "rtdir": "SOUTHBOUND", - "rtNext": "CS" - } - }, - }, - "CS":{ - "S002SOUTHBOUND": { - "S001": { - "diff": 5, - "rtdir": "NORTHBOUND", - "rtNext": "CN" - } - } - } -}; - -const validRoutes = new Set(); -let curRouteSelections = {}; -const routes = ["BB", "CN", "CS", "CSX", "DD", "MX", "NE", "NW", "NX", "OS", "NES", "WS", "WX"]; -let cachedStopLocations: { [stopId: string]: {name : string, lat: number, lon: number } } = { - -}; - -const message = {id: "gradamatation", title: "Congrats Grads 🥳", message: "Congrats to everyone who is gradamatating! Enjoy some grad hats on the buses, and don't forget to celebrate!", buildVersion: '99'} - -let cachedGraph: { - trips: Trip[]; - transfers: TransfersByOrigin; - interchange: Interchange; -} - -let stopIdToName: Record = {}; -let tatripidToRt: Record = {}; - -const sortStopTimesByRouteSequence = (stopTimes: StopTime[]): StopTime[] => { - if (stopTimes.length <= 1) return stopTimes; - - // Sort by arrival time - return stopTimes.sort((a, b) => a.arrivalTime - b.arrivalTime); -}; - -const rebuildGraph = async () => { - try { - const predictions = await getAllBusPredictions(); - if (!predictions || predictions.length === 0) { - return; - } - - // Build stopIdToName and tatripidToRt maps - stopIdToName = {}; - tatripidToRt = {}; - predictions.forEach((trip: any) => { - if (trip.tatripid && trip.stops && trip.stops.length > 0) { - // Find first stop with rt - const firstStopWithRt = trip.stops.find((stop: any) => stop.rt); - if (firstStopWithRt && firstStopWithRt.rt) { - tatripidToRt[trip.tatripid] = firstStopWithRt.rt; - } - } - trip.stops.forEach((stop: any) => { - if (stop.stpid && stop.stpnm) { - stopIdToName[stop.stpid] = stop.stpnm; - } - }); - }); - - const now = new Date(); - const currentTime = now.getUTCHours() * 3600 + now.getUTCMinutes() * 60 + now.getUTCSeconds(); - - const transfers = cachedGraph?.transfers || {}; - const interchange = cachedGraph?.interchange || {}; - - const allStops = new Set(); - predictions.forEach((trip: any) => { - trip.stops.forEach((stop: any) => { - allStops.add(stop.stpid); - }); - }); - - allStops.forEach(stopId => { - if (!transfers[stopId]) { - transfers[stopId] = []; - } - if (!interchange[stopId]) { - interchange[stopId] = 60; // 1 minute interchange time - } - }); - - const stopPredictions: Record = {}; - predictions.forEach((trip: any) => { - trip.stops.forEach((stop: any) => { - if (!stopPredictions[stop.stpid]) { - stopPredictions[stop.stpid] = []; - } - stopPredictions[stop.stpid].push({ - stpid: stop.stpid, - prdctdn: stop.prdctdn, - tatripid: trip.tatripid - }); - }); - }); - - const trips: Trip[] = []; - interface TripPrediction { - vid: string; - stops: { - stpid: string; - prdctdn: string; - rt: string; - }[]; - } - - const tripPredictions: Record = {}; - - predictions.forEach((trip: any) => { - if (!tripPredictions[trip.tatripid]) { - tripPredictions[trip.tatripid] = { - vid: trip.vid, - stops: [] - }; - } - trip.stops.forEach((stop: any) => { - tripPredictions[trip.tatripid].stops.push({ - stpid: stop.stpid, - prdctdn: stop.prdctdn, - rt: stop.rt - }); - }); - }); - - Object.entries(tripPredictions).forEach(([tripId, preds]) => { - // Create stop times with prediction times - const stopTimes: StopTime[] = preds.stops.map(pred => ({ - stop: pred.stpid, - arrivalTime: currentTime + (parseInt(pred.prdctdn) * 60), - departureTime: currentTime + (parseInt(pred.prdctdn) * 60), - pickUp: true, - dropOff: true, - rt: pred.rt - })); - - // Sort stop times by their sequence in the route - const sortedStopTimes = sortStopTimesByRouteSequence(stopTimes); - - trips.push({ - tripId, - vid: preds.vid, - stopTimes: sortedStopTimes - }); - }); - - - cachedGraph = { - trips, - transfers, - interchange - }; - - // Add virtual stops and their interchange - const originStopId = 'VIRTUAL_ORIGIN'; - const destStopId = 'VIRTUAL_DESTINATION'; - cachedGraph.transfers[originStopId] = []; - cachedGraph.transfers[destStopId] = []; - cachedGraph.interchange[originStopId] = 60; - cachedGraph.interchange[destStopId] = 60; - const virtualOriginTrip = { - tripId: 'VIRTUAL_ORIGIN_TRIP', - vid: null, - stopTimes: [{ - stop: originStopId, - arrivalTime: 0, - departureTime: 0, - pickUp: true, - dropOff: true - }] - }; - const virtualDestTrip = { - tripId: 'VIRTUAL_DESTINATION_TRIP', - vid: null, - stopTimes: [{ - stop: destStopId, - arrivalTime: 0, - departureTime: 0, - pickUp: true, - dropOff: true - }] - }; - cachedGraph.trips.push(virtualOriginTrip); - cachedGraph.trips.push(virtualDestTrip); - - } catch (error) { - console.error('Error rebuilding graph:', error); - } -}; - -const getAllBusPredictions = async () => { - try { - // Get all unique stop IDs from cached routes - const allStopIds = new Set(); - Object.values(cachedRoutes).forEach((routePatterns: any) => { - if (Array.isArray(routePatterns)) { - routePatterns.forEach((pattern: any) => { - if (pattern.pt && Array.isArray(pattern.pt)) { - pattern.pt.forEach((point: any) => { - if (point.stpid) { - allStopIds.add(point.stpid); - } - }); - } - }); - } - }); - - const stopIdsArray = Array.from(allStopIds); - const chunks = []; - - for (let i = 0; i < stopIdsArray.length; i += 10) { - chunks.push(stopIdsArray.slice(i, i + 10)); - } - - const predictions = await Promise.all( - chunks.map(async (chunk) => { - const stopIds = chunk.join(','); - const response = await axios.get(`https://mbus.ltp.umich.edu/bustime/api/v3/getpredictions`, { - params: { - requestType: 'getpredictions', - locale: 'en', - stpid: stopIds, - rt: routes.join(','), - tmres: 's', - rtpidatafeed: 'bustime', - key: API_KEY, - format: 'json' - } - }); - return response.data; - }) - ); - - const formattedPredictions = predictions.flat().reduce((acc, predictionChunk) => { - if (predictionChunk['bustime-response'] && predictionChunk['bustime-response']['prd']) { - predictionChunk['bustime-response']['prd'].forEach((prd: any) => { - const tatripid = prd.tatripid; - const stopName = prd.stpnm; - const stopId = prd.stpid; - const rt = prd.rt; - const rtdir = prd.rtdir; - const vid = prd.vid; - let prdctdn = prd.prdctdn; - prdctdn = prdctdn === "DUE" ? "1" : prdctdn; - - let trip = acc.find((t: any) => t.tatripid === tatripid); - - if (!trip) { - if (vid) { // if no trip, go by vid - trip = acc.find((t: any) => t.vid === vid); - } - } - - if (!trip) { // if no trip, create one - trip = { tatripid, vid, stops: [] }; - acc.push(trip); - } else { // merge with existing trip - if (!trip.tatripid) { - trip.tatripid = tatripid; - } - if (!trip.vid && vid) { - trip.vid = vid; - } - } - - let stop = trip.stops.find((s: any) => s.stpnm === stopName && s.stpid === stopId); - if (!stop) { - stop = { stpnm: stopName, stpid: stopId, prdctdn: null, rt: null, rtdir : null }; - trip.stops.push(stop); - } - stop.rtdir = rtdir; - stop.rt = rt; - stop.prdctdn = prdctdn; - }); - } - return acc; - }, []); - - // Cache predictions by vid and stopId - cachedPredsByVid = {}; - cachedPredsByStopId = {}; - predictions.flat().forEach((predictionChunk) => { - const prds = predictionChunk['bustime-response']?.['prd']; - if (!prds) return; - - prds.forEach((prd: Prediction) => { - const { vid, stpid } = prd; - // stpid -> [pred, pred...] - if (!cachedPredsByStopId[stpid]) { - cachedPredsByStopId[stpid] = []; - } - cachedPredsByStopId[stpid].push(prd); // store reference - - if (!vid) return; - // vid -> [pred, pred...] - if (!cachedPredsByVid[vid]) { - cachedPredsByVid[vid] = []; - } - cachedPredsByVid[vid].push(prd); - - }); - }); - - // Cache predictions per route in routeTimingCache for extrapolation - - // Record of stop ids in order using routes - const routeInfoFilter: Record = {}; - for (const [routeName, routeList] of Object.entries(cachedRoutes as Record)) { - for (const route of routeList) { - const rtdir = route.rtdir; - const routeKey = routeName + rtdir; - if (!routeInfoFilter[routeKey]) { - routeInfoFilter[routeKey] = []; - } - for (const point of route.pt) { - if (point.typ !== "W" && point.stpid) { - routeInfoFilter[routeKey].push({ stpid: point.stpid, rtdir }); - } - } - } - } - - const stopIdToName: Record = {}; - formattedPredictions.forEach((trip: any) => { - trip.stops.forEach((stop: any) => { - if (stop.stpid && stop.stpnm) stopIdToName[stop.stpid] = stop.stpnm; - }); - }); - - // Create indices for route -> stop order - const routeStopIndexMaps = new Map>(); - for (const [routeId, stopOrder] of Object.entries(routeInfoFilter)) { - const stopIndexMap = new Map(stopOrder.map(({ stpid }, i) => [stpid, i])); - routeStopIndexMaps.set(routeId, stopIndexMap); - } - - formattedPredictions.forEach((trip: any) => { - if(trip.stops.length == 0) return; - const minPrdctdn = Math.min(...trip.stops.map((s : any) => parseInt(s.prdctdn, 10))); - const firstRoute = trip.stops.find((s: any) => parseInt(s.prdctdn, 10) === minPrdctdn)?.rt; - - if (!firstRoute) return; - // Sort by predicted time - trip.stops.sort((a: any, b: any) => { - const diffTime = parseInt(a.prdctdn, 10) - parseInt(b.prdctdn, 10); - if (diffTime !== 0) return diffTime; // primary sort - - // If not same route, put first route in front - if (a.rt + a.rtdir !== b.rt + b.rtdir) { - if (a.rt === firstRoute) return -1; - if (b.rt === firstRoute) return 1; - - return a.rt.localeCompare(b.rt); - } - // If same route, sort by stop order - const aMap = routeStopIndexMaps.get(a.rt + a.rtdir); - const bMap = routeStopIndexMaps.get(b.rt + b.rtdir); - - const aIdx = aMap?.get(a.stpid) ?? Number.MAX_SAFE_INTEGER; - const bIdx = bMap?.get(b.stpid) ?? Number.MAX_SAFE_INTEGER; - return aIdx - bIdx; - }); - // Create edges based on sorted order - for (let i = 0; i < trip.stops.length - 1; i++) { - const from = trip.stops[i]; - const to = trip.stops[i + 1]; - const diff = parseInt(to.prdctdn, 10) - parseInt(from.prdctdn, 10); - const rt = from.rt; - - const stopIndexMap = routeStopIndexMaps.get(from.rt + from.rtdir); - if (!stopIndexMap) continue; - - const fromIdx = stopIndexMap.get(from.stpid); - const toIdx = stopIndexMap.get(to.stpid); - // Ensure valid follow up stop by idx or end of idx - const isValidFollowUp = ( - fromIdx !== undefined && - toIdx !== undefined && - (toIdx === fromIdx + 1 || fromIdx === stopIndexMap.size - 1) - ); - if (!isValidFollowUp) continue; - - if (!routeTimingCache[rt]) routeTimingCache[rt] = {}; - const fromKey = from.stpid + (from.rtdir || ""); - if (!routeTimingCache[rt][fromKey]) routeTimingCache[rt][fromKey] = {}; - routeTimingCache[rt][fromKey][to.stpid] = { - diff : diff, - rtdir: to.rtdir, - rtNext: to.rt - }; - } - }); - - // Extrapolate future stops based on routeTimingCache - formattedPredictions.forEach((trip: any) => { - let stopsAdded = 0; - while (stopsAdded < 20 && trip.stops.length > 0) { - const lastStop = trip.stops[trip.stops.length - 1]; - const rt = lastStop.rt; - if (!rt) break; - - const fromKey = lastStop.stpid + (lastStop.rtdir || ""); - const nextStops = routeTimingCache[rt]?.[fromKey]; - if (!nextStops) break; - - const nextEntries = Object.entries(nextStops); - if (nextEntries.length === 0) break; - - const [nextStopId, { diff, rtdir, rtNext}] = nextEntries[0]; - const nextPrdctdn = (parseInt(lastStop.prdctdn, 10) + diff).toString(); - - trip.stops.push({ - stpnm: stopIdToName[nextStopId] || nextStopId, - stpid: nextStopId, - prdctdn: nextPrdctdn, - rt : rtNext, - rtdir : rtdir - }); - stopsAdded++; - } - }); - - return formattedPredictions; - } catch (err: unknown) { - const message = err instanceof Error ? err.message : String(err); - console.error("Error in getAllBusPredictions:", message); - return []; - } -}; - -const client = axios.create({ - baseURL: 'https://mbus.ltp.umich.edu/bustime/api/v3/', - params: { - key: API_KEY, - format: 'json' - } -}); - -const getBuses = async () => { - const getChunk = async (routesChunk: string[]) => { - try { - const res = await client.get('/getvehicles', { - params: { requestType: 'getvehicles', rt: routesChunk.join(',') }, - }); - - if ( - 'bustime-response' in res.data && - 'vehicle' in res.data['bustime-response'] - ) { - return res.data['bustime-response']['vehicle']; - } - - return []; - } catch (error) { - console.warn('getChunk failed for routes', routesChunk, error instanceof Error ? error.message : error); - return []; - } - }; - - const chunks = [] - for (let i = 0; i < routes.length; i += 10) { - chunks.push(routes.slice(i, i + 10)); - } - - let buses = await Promise.all(chunks.map(getChunk)); - buses = buses.flat(); - - return buses; -} - -const updateBusPositions = async () => { - curBusPositions.buses = await getBuses(); -} - -const addToCachedRoutes = async (rt: string) => { - try { - const res = await client.get('/getpatterns', { - params: { - requestType: 'getpatterns', - rtpidatafeed: 'bustime', - rt: rt - } - }); - - if (res.data['bustime-response'] && res.data['bustime-response']['ptr']) { - cachedRoutes[rt] = res.data['bustime-response']['ptr']; - } - } catch (e) { - console.log(`Error while getting routes: ${e}`); - } -} - -const getSelectableRoutes = () => { - axios.get(`https://mbus.ltp.umich.edu/bustime/api/v3/getroutes?requestType=getroutes&locale=en&key=${API_KEY}&format=json`).then(res => { - curRouteSelections = res.data; - validRoutes.clear(); - try { - res.data['bustime-response']['routes'].forEach((e: Route) => { - validRoutes.add(e['rt']); - addToCachedRoutes(e['rt']); - }); - } catch (e) { - if (res.data['bustime-response'].error !== undefined) { - console.log(res.data['bustime-response'].error); - } - console.log(`Failed to parse valid routes: ${e}`); - } - }) - .catch((err) => console.log(`Error while getting selectable routes: ${err}`)) - .finally(async () => { - // Update transfers - try { - if (!cachedGraph) { - cachedGraph = { - trips: [], - transfers: {}, - interchange: {} - }; - } - // Rebuild stop locations cache from cached routes - cachedStopLocations = {}; - console.log("Caching Transfers..") - Object.values(cachedRoutes).forEach((routePatterns: any) => { - if (Array.isArray(routePatterns)) { - routePatterns.forEach((pattern: any) => { - if (pattern.pt && Array.isArray(pattern.pt)) { - pattern.pt.forEach((point: any) => { - if (point.stpid && point.lat && point.lon) { - cachedStopLocations[point.stpid] = { - name: point.stpnm, - lat: parseFloat(point.lat), - lon: parseFloat(point.lon) - }; - } - }); - } - }); - } - }); - - console.log(`Number of stop locations: ${Object.keys(cachedStopLocations).length}`); - - const WALKING_SPEED_KMH = 4; - const WALKING_SPEED_MS = WALKING_SPEED_KMH * 1000 / 3600; // Convert to m/s - - const routeStops = new Set(); - Object.values(cachedRoutes).forEach((routePatterns: any) => { - if (Array.isArray(routePatterns)) { - routePatterns.forEach((pattern: any) => { - if (pattern.pt && Array.isArray(pattern.pt)) { - pattern.pt.forEach((point: any) => { - if (point.stpid) { - routeStops.add(point.stpid); - } - }); - } - }); - } - }); - - routeStops.forEach(stopId => { - cachedGraph.transfers[stopId] = []; - }); - - routeStops.forEach(stopId => { - if (!cachedGraph.interchange[stopId]) { - cachedGraph.interchange[stopId] = 60; // 1 minute interchange time - } - }); - - // Create transfers between all stops - routeStops.forEach(stopId => { - routeStops.forEach(otherStopId => { - if (stopId !== otherStopId) { - const stop1 = cachedStopLocations[stopId]; - const stop2 = cachedStopLocations[otherStopId]; - - let transferDuration: number; - - if (stop1 && stop2) { - // Compute diff with lat and lon - const latDiff = (stop2.lat - stop1.lat) * 111320; - const lonDiff = (stop2.lon - stop1.lon) * 111320 * Math.cos(stop1.lat * Math.PI / 180); - const distance = Math.sqrt(latDiff * latDiff + lonDiff * lonDiff); - let walkingTimeSeconds = distance / WALKING_SPEED_MS; - // if (distance > 1200) { - // walkingTimeSeconds *= 1.5; // penatly for too big distances - // } - transferDuration = Math.round(walkingTimeSeconds); - } else { - console.log('Invalid stop'); - transferDuration = 60000; - } - const existingTransfer = cachedGraph.transfers[stopId].find(t => t.destination === otherStopId); - - if (existingTransfer) { - existingTransfer.duration = transferDuration; - } else { - const transfer: Transfer = { - origin: stopId, - destination: otherStopId, - duration: transferDuration, - startTime: 0, - endTime: Number.MAX_SAFE_INTEGER - }; - cachedGraph.transfers[stopId].push(transfer); - } - } - }); - }); - - const totalTransfers = Object.values(cachedGraph.transfers).reduce((total, transfers) => total + transfers.length, 0); - console.log(`Total transfers in cachedGraph: ${totalTransfers}`); - } catch (error) { - console.error('Error updating transfers:', error); - } - }); -} - -export { - curBusPositions, - cachedRoutes, - cachedPredsByVid, - cachedPredsByStopId, - validRoutes, - curRouteSelections, - routes, - cachedStopLocations, - routeTimingCache, - cachedGraph, - stopIdToName, - tatripidToRt, - getAllBusPredictions, - updateBusPositions, - getSelectableRoutes, - rebuildGraph -}; - diff --git a/src/legacy/busService.ts b/src/legacy/busService.ts deleted file mode 100644 index bccae67..0000000 --- a/src/legacy/busService.ts +++ /dev/null @@ -1,751 +0,0 @@ -import * as process from "node:process"; -import * as fs from 'fs'; -import * as path from 'path'; -import * as walking from '../walking/walkingMap'; - -import axios from 'axios'; -import dotenv from "dotenv"; -import { Route } from "@/types"; -import { - Trip, - StopTime, - Transfer, - StopID, - TransfersByOrigin, - Interchange -} from "../raptor/types"; - -import { writeFileSync, readFileSync, existsSync } from "fs"; - -dotenv.config(); - -const API_KEY = process.env.MBUS_API_KEY; -if (API_KEY === undefined) { - throw new Error("MBus API key not set."); -} - -const curBusPositions: { - buses: any[] -} = { - "buses": [] -} - -const cachedRoutes: { [k: string]: any } = {}; -type Prediction = { vid: string; stpid: string } & Record; - -let cachedPredsByVid: Record = {}; -let cachedPredsByStopId: Record = {}; -// routeTimingCache: route -> fromStop -> toStop -> latest diff (minutes) -const routeTimingCache: Record>> = -{ - "CN": { - "N434NORTHBOUND": { - "N500": { - "diff": 5, - "rtdir": "SOUTHBOUND", - "rtNext": "CS" - } - }, - }, - "CS": { - "S002SOUTHBOUND": { - "S001": { - "diff": 5, - "rtdir": "NORTHBOUND", - "rtNext": "CN" - } - } - } -}; - -const validRoutes = new Set(); -let curRouteSelections = {}; -const routes = ["BB", "CN", "CS", "CSX", "DD", "MX", "NE", "NW", "NX", "OS", "NES", "WS", "WX"]; -let cachedStopLocations: { [stopId: string]: { name: string, lat: number, lon: number } } = { - -}; - -const message = { id: "gradamatation", title: "Congrats Grads 🥳", message: "Congrats to everyone who is gradamatating! Enjoy some grad hats on the buses, and don't forget to celebrate!", buildVersion: '99' } - -let cachedGraph: { - trips: Trip[]; - transfers: TransfersByOrigin; - interchange: Interchange; -} - -let stopIdToName: Record = {}; -let tatripidToRt: Record = {}; - -const sortStopTimesByRouteSequence = (stopTimes: StopTime[]): StopTime[] => { - if (stopTimes.length <= 1) return stopTimes; - - // Sort by arrival time - return stopTimes.sort((a, b) => a.arrivalTime - b.arrivalTime); -}; - -const rebuildGraph = async () => { - if (process.env.DEV_CACHE === 'true') { - if (cachedGraph && cachedGraph.trips && cachedGraph.trips.length > 0) return; - try { - const filePath = path.resolve(process.cwd(), 'saved_graph.json'); - if (fs.existsSync(filePath)) { - const data = JSON.parse(fs.readFileSync(filePath, 'utf8')); - cachedGraph = data.graph; - cachedStopLocations = data.stopLocations; - stopIdToName = data.stopNames; - cachedPredsByVid = data.predsByVid || {}; - cachedPredsByStopId = data.predsByStopId || {}; - console.log('Loaded graph and state from saved_graph.json'); - } else { - console.warn('DEV_CACHE set but saved_graph.json not found'); - } - } catch (err) { - console.error('Error loading cached graph:', err); - } - return; - } - try { - const predictions = await getAllBusPredictions(); - if (!predictions || predictions.length === 0) { - return; - } - - // Build stopIdToName and tatripidToRt maps - stopIdToName = {}; - tatripidToRt = {}; - predictions.forEach((trip: any) => { - if (trip.tatripid && trip.stops && trip.stops.length > 0) { - // Find first stop with rt - const firstStopWithRt = trip.stops.find((stop: any) => stop.rt); - if (firstStopWithRt && firstStopWithRt.rt) { - tatripidToRt[trip.tatripid] = firstStopWithRt.rt; - } - } - trip.stops.forEach((stop: any) => { - if (stop.stpid && stop.stpnm) { - stopIdToName[stop.stpid] = stop.stpnm; - } - }); - }); - - const now = new Date(); - const currentTime = now.getUTCHours() * 3600 + now.getUTCMinutes() * 60 + now.getUTCSeconds(); - - const transfers = cachedGraph?.transfers || {}; - const interchange = cachedGraph?.interchange || {}; - - const allStops = new Set(); - predictions.forEach((trip: any) => { - trip.stops.forEach((stop: any) => { - allStops.add(stop.stpid); - }); - }); - - allStops.forEach(stopId => { - if (!transfers[stopId]) { - transfers[stopId] = []; - } - if (!interchange[stopId]) { - interchange[stopId] = 30; // 30 seconds interchange time - } - }); - - const stopPredictions: Record = {}; - predictions.forEach((trip: any) => { - trip.stops.forEach((stop: any) => { - if (!stopPredictions[stop.stpid]) { - stopPredictions[stop.stpid] = []; - } - stopPredictions[stop.stpid].push({ - stpid: stop.stpid, - prdctdn: stop.prdctdn, - tatripid: trip.tatripid - }); - }); - }); - - const trips: Trip[] = []; - interface TripPrediction { - vid: string; - stops: { - stpid: string; - prdctdn: string; - rt: string; - }[]; - } - - const tripPredictions: Record = {}; - - predictions.forEach((trip: any) => { - if (!tripPredictions[trip.tatripid]) { - tripPredictions[trip.tatripid] = { - vid: trip.vid, - stops: [] - }; - } - trip.stops.forEach((stop: any) => { - tripPredictions[trip.tatripid].stops.push({ - stpid: stop.stpid, - prdctdn: stop.prdctdn, - rt: stop.rt - }); - }); - }); - - Object.entries(tripPredictions).forEach(([tripId, preds]) => { - // Create stop times with prediction times - const stopTimes: StopTime[] = preds.stops.map(pred => ({ - stop: pred.stpid, - arrivalTime: currentTime + (parseInt(pred.prdctdn) * 60), - departureTime: currentTime + (parseInt(pred.prdctdn) * 60), - pickUp: true, - dropOff: true, - rt: pred.rt - })); - - // Sort stop times by their sequence in the route - const sortedStopTimes = sortStopTimesByRouteSequence(stopTimes); - - trips.push({ - tripId, - vid: preds.vid, - stopTimes: sortedStopTimes - }); - }); - - - cachedGraph = { - trips, - transfers, - interchange - }; - - // Add virtual stops and their interchange - const originStopId = 'VIRTUAL_ORIGIN'; - const destStopId = 'VIRTUAL_DESTINATION'; - cachedGraph.transfers[originStopId] = []; - cachedGraph.transfers[destStopId] = []; - cachedGraph.interchange[originStopId] = 30; - cachedGraph.interchange[destStopId] = 30; - const virtualOriginTrip = { - tripId: 'VIRTUAL_ORIGIN_TRIP', - vid: null, - stopTimes: [{ - stop: originStopId, - arrivalTime: 0, - departureTime: 0, - pickUp: true, - dropOff: true - }] - }; - const virtualDestTrip = { - tripId: 'VIRTUAL_DESTINATION_TRIP', - vid: null, - stopTimes: [{ - stop: destStopId, - arrivalTime: 0, - departureTime: 0, - pickUp: true, - dropOff: true - }] - }; - cachedGraph.trips.push(virtualOriginTrip); - cachedGraph.trips.push(virtualDestTrip); - - } catch (error) { - console.error('Error rebuilding graph:', error); - } -}; - -const getAllBusPredictions = async () => { - try { - // Get all unique stop IDs from cached routes - const allStopIds = new Set(); - Object.values(cachedRoutes).forEach((routePatterns: any) => { - if (Array.isArray(routePatterns)) { - routePatterns.forEach((pattern: any) => { - if (pattern.pt && Array.isArray(pattern.pt)) { - pattern.pt.forEach((point: any) => { - if (point.stpid) { - allStopIds.add(point.stpid); - } - }); - } - }); - } - }); - - const stopIdsArray = Array.from(allStopIds); - const chunks = []; - - if (process.env.DEV_CACHE === 'true') { - return []; - } - - for (let i = 0; i < stopIdsArray.length; i += 10) { - chunks.push(stopIdsArray.slice(i, i + 10)); - } - - let formattedPredictions = []; - - - cachedPredsByVid = {}; - cachedPredsByStopId = {}; - - if (process.env.DEV === 'true') { - // In DEV mode, load static dummy data instead of fetching from the live API - try { - const dummyDataPath = path.resolve(process.cwd(), 'dummy_bus_data.json'); - const dummyData = fs.readFileSync(dummyDataPath, 'utf8'); - formattedPredictions = JSON.parse(dummyData); - - // Populate internal caches from the loaded dummy data - formattedPredictions.forEach((trip: any) => { - const vid = trip.vid; - trip.stops.forEach((stop: any) => { - const stpid = stop.stpid; - const prd: Prediction = { - tmstmp: new Date().toISOString(), - typ: "A", - stpnm: stop.stpnm, - stpid: stop.stpid, - vid: vid, - dstp: 0, - rt: stop.rt, - rtdd: stop.rt, - rtdir: stop.rtdir, - des: "", - prdctdn: stop.prdctdn, - tablockid: "", - tatripid: trip.tatripid, - dly: false, - prdctm: "", - zone: "" - }; - - if (!cachedPredsByStopId[stpid]) { - cachedPredsByStopId[stpid] = []; - } - cachedPredsByStopId[stpid].push(prd); - - if (vid) { - if (!cachedPredsByVid[vid]) { - cachedPredsByVid[vid] = []; - } - cachedPredsByVid[vid].push(prd); - } - }); - }); - - } catch (err) { - console.error('Error loading dummy bus data:', err); - formattedPredictions = []; - } - } else { - const predictions = await Promise.all( - chunks.map(async (chunk) => { - const stopIds = chunk.join(','); - const response = await axios.get(`https://mbus.ltp.umich.edu/bustime/api/v3/getpredictions`, { - params: { - requestType: 'getpredictions', - locale: 'en', - stpid: stopIds, - rt: routes.join(','), - tmres: 's', - rtpidatafeed: 'bustime', - key: API_KEY, - format: 'json' - } - }); - return response.data; - }) - ); - - formattedPredictions = predictions.flat().reduce((acc, predictionChunk) => { - if (predictionChunk['bustime-response'] && predictionChunk['bustime-response']['prd']) { - predictionChunk['bustime-response']['prd'].forEach((prd: any) => { - const tatripid = prd.tatripid; - const stopName = prd.stpnm; - const stopId = prd.stpid; - const rt = prd.rt; - const rtdir = prd.rtdir; - const vid = prd.vid; - let prdctdn = prd.prdctdn; - prdctdn = prdctdn === "DUE" ? "1" : prdctdn; - - let trip = acc.find((t: any) => t.tatripid === tatripid); - - if (!trip) { - if (vid) { - trip = acc.find((t: any) => t.vid === vid); - } - } - - if (!trip) { - trip = { tatripid, vid, stops: [] }; - acc.push(trip); - } else { - if (!trip.tatripid) { - trip.tatripid = tatripid; - } - if (!trip.vid && vid) { - trip.vid = vid; - } - } - - let stop = trip.stops.find((s: any) => s.stpnm === stopName && s.stpid === stopId); - if (!stop) { - stop = { stpnm: stopName, stpid: stopId, prdctdn: null, rt: null, rtdir: null }; - trip.stops.push(stop); - } - stop.rtdir = rtdir; - stop.rt = rt; - stop.prdctdn = prdctdn; - }); - } - return acc; - }, []); - - predictions.flat().forEach((predictionChunk) => { - const prds = predictionChunk['bustime-response']?.['prd']; - if (!prds) return; - - prds.forEach((prd: Prediction) => { - const { vid, stpid } = prd; - if (!cachedPredsByStopId[stpid]) { - cachedPredsByStopId[stpid] = []; - } - cachedPredsByStopId[stpid].push(prd); - - if (!vid) return; - if (!cachedPredsByVid[vid]) { - cachedPredsByVid[vid] = []; - } - cachedPredsByVid[vid].push(prd); - - }); - }); - } - - - // Cache predictions per route in routeTimingCache for extrapolation - - // Record of stop ids in order using routes - const routeInfoFilter: Record = {}; - for (const [routeName, routeList] of Object.entries(cachedRoutes as Record)) { - for (const route of routeList) { - const rtdir = route.rtdir; - const routeKey = routeName + rtdir; - if (!routeInfoFilter[routeKey]) { - routeInfoFilter[routeKey] = []; - } - for (const point of route.pt) { - if (point.typ !== "W" && point.stpid) { - routeInfoFilter[routeKey].push({ stpid: point.stpid, rtdir }); - } - } - } - } - - const stopIdToName: Record = {}; - formattedPredictions.forEach((trip: any) => { - trip.stops.forEach((stop: any) => { - if (stop.stpid && stop.stpnm) stopIdToName[stop.stpid] = stop.stpnm; - }); - }); - - // Create indices for route -> stop order - const routeStopIndexMaps = new Map>(); - for (const [routeId, stopOrder] of Object.entries(routeInfoFilter)) { - const stopIndexMap = new Map(stopOrder.map(({ stpid }, i) => [stpid, i])); - routeStopIndexMaps.set(routeId, stopIndexMap); - } - - formattedPredictions.forEach((trip: any) => { - if (trip.stops.length == 0) return; - const minPrdctdn = Math.min(...trip.stops.map((s: any) => parseInt(s.prdctdn, 10))); - const firstRoute = trip.stops.find((s: any) => parseInt(s.prdctdn, 10) === minPrdctdn)?.rt; - - if (!firstRoute) return; - // Sort by predicted time - trip.stops.sort((a: any, b: any) => { - const diffTime = parseInt(a.prdctdn, 10) - parseInt(b.prdctdn, 10); - if (diffTime !== 0) return diffTime; // primary sort - - // If not same route, put first route in front - if (a.rt + a.rtdir !== b.rt + b.rtdir) { - if (a.rt === firstRoute) return -1; - if (b.rt === firstRoute) return 1; - - return a.rt.localeCompare(b.rt); - } - // If same route, sort by stop order - const aMap = routeStopIndexMaps.get(a.rt + a.rtdir); - const bMap = routeStopIndexMaps.get(b.rt + b.rtdir); - - const aIdx = aMap?.get(a.stpid) ?? Number.MAX_SAFE_INTEGER; - const bIdx = bMap?.get(b.stpid) ?? Number.MAX_SAFE_INTEGER; - return aIdx - bIdx; - }); - // Create edges based on sorted order - for (let i = 0; i < trip.stops.length - 1; i++) { - const from = trip.stops[i]; - const to = trip.stops[i + 1]; - const diff = parseInt(to.prdctdn, 10) - parseInt(from.prdctdn, 10); - const rt = from.rt; - - const stopIndexMap = routeStopIndexMaps.get(from.rt + from.rtdir); - if (!stopIndexMap) continue; - - const fromIdx = stopIndexMap.get(from.stpid); - const toIdx = stopIndexMap.get(to.stpid); - // Ensure valid follow up stop by idx or end of idx - const isValidFollowUp = ( - fromIdx !== undefined && - toIdx !== undefined && - (toIdx === fromIdx + 1 || fromIdx === stopIndexMap.size - 1) - ); - if (!isValidFollowUp) continue; - - if (!routeTimingCache[rt]) routeTimingCache[rt] = {}; - const fromKey = from.stpid + (from.rtdir || ""); - if (!routeTimingCache[rt][fromKey]) routeTimingCache[rt][fromKey] = {}; - routeTimingCache[rt][fromKey][to.stpid] = { - diff: diff, - rtdir: to.rtdir, - rtNext: to.rt - }; - } - }); - - // Extrapolate future stops based on routeTimingCache - formattedPredictions.forEach((trip: any) => { - let stopsAdded = 0; - while (stopsAdded < 20 && trip.stops.length > 0) { - const lastStop = trip.stops[trip.stops.length - 1]; - const rt = lastStop.rt; - if (!rt) break; - - const fromKey = lastStop.stpid + (lastStop.rtdir || ""); - const nextStops = routeTimingCache[rt]?.[fromKey]; - if (!nextStops) break; - - const nextEntries = Object.entries(nextStops); - if (nextEntries.length === 0) break; - - const [nextStopId, { diff, rtdir, rtNext }] = nextEntries[0]; - const nextPrdctdn = (parseInt(lastStop.prdctdn, 10) + diff).toString(); - - trip.stops.push({ - stpnm: stopIdToName[nextStopId] || nextStopId, - stpid: nextStopId, - prdctdn: nextPrdctdn, - rt: rtNext, - rtdir: rtdir - }); - stopsAdded++; - } - }); - - return formattedPredictions; - } catch (err: unknown) { - const message = err instanceof Error ? err.message : String(err); - console.error("Error in getAllBusPredictions:", message); - return []; - } -}; - -const client = axios.create({ - baseURL: 'https://mbus.ltp.umich.edu/bustime/api/v3/', - params: { - key: API_KEY, - format: 'json' - } -}); - -const getBuses = async () => { - const getChunk = async (routesChunk: string[]) => { - try { - const res = await client.get('/getvehicles', { - params: { requestType: 'getvehicles', rt: routesChunk.join(',') }, - }); - - if ( - 'bustime-response' in res.data && - 'vehicle' in res.data['bustime-response'] - ) { - return res.data['bustime-response']['vehicle']; - } - - return []; - } catch (error) { - console.warn('getChunk failed for routes', routesChunk, error instanceof Error ? error.message : error); - return []; - } - }; - - const chunks = [] - for (let i = 0; i < routes.length; i += 10) { - chunks.push(routes.slice(i, i + 10)); - } - - let buses = await Promise.all(chunks.map(getChunk)); - buses = buses.flat(); - - return buses; -} - -const updateBusPositions = async () => { - curBusPositions.buses = await getBuses(); -} - -const addToCachedRoutes = async (rt: string) => { - try { - const res = await client.get('/getpatterns', { - params: { - requestType: 'getpatterns', - rtpidatafeed: 'bustime', - rt: rt - } - }); - - - if (res.data['bustime-response'] && res.data['bustime-response']['ptr']) { - cachedRoutes[rt] = res.data['bustime-response']['ptr']; - } - } catch (e) { - console.log(`Error while getting routes: ${e}`); - } -} - -const getSelectableRoutes = () => { - if (process.env.DEV_CACHE === 'true') return; - - axios.get(`https://mbus.ltp.umich.edu/bustime/api/v3/getroutes?requestType=getroutes&locale=en&key=${API_KEY}&format=json`).then(async res => { - curRouteSelections = res.data; - validRoutes.clear(); - try { - const promises: Promise[] = []; - res.data['bustime-response']['routes'].forEach((e: Route) => { - validRoutes.add(e['rt']); - promises.push(addToCachedRoutes(e['rt'])); - }); - await Promise.all(promises); - } catch (e) { - if (res.data['bustime-response'].error !== undefined) { - console.log(res.data['bustime-response'].error); - } - console.log(`Failed to parse valid routes: ${e}`); - } - }) - .catch((err) => console.log(`Error while getting selectable routes: ${err}`)) - .finally(async () => { - // Update transfers - try { - if (!cachedGraph) { - cachedGraph = { - trips: [], - transfers: {}, - interchange: {} - }; - } - // Rebuild stop locations cache from cached routes - cachedStopLocations = {}; - console.log("Caching Transfers..") - Object.values(cachedRoutes).forEach((routePatterns: any) => { - if (Array.isArray(routePatterns)) { - routePatterns.forEach((pattern: any) => { - if (pattern.pt && Array.isArray(pattern.pt)) { - pattern.pt.forEach((point: any) => { - if (point.stpid && point.lat && point.lon) { - cachedStopLocations[point.stpid] = { - name: point.stpnm, - lat: parseFloat(point.lat), - lon: parseFloat(point.lon) - }; - } - }); - } - }); - } - }); - - console.log(`Number of stop locations: ${Object.keys(cachedStopLocations).length}`); - walking.buildStopNodeMap(cachedStopLocations); - - const routeStops = new Set(); - Object.values(cachedRoutes).forEach((routePatterns: any) => { - if (Array.isArray(routePatterns)) { - routePatterns.forEach((pattern: any) => { - if (pattern.pt && Array.isArray(pattern.pt)) { - pattern.pt.forEach((point: any) => { - if (point.stpid) { - routeStops.add(point.stpid); - } - }); - } - }); - } - }); - - routeStops.forEach(stopId => { - cachedGraph.transfers[stopId] = []; - }); - - routeStops.forEach(stopId => { - if (!cachedGraph.interchange[stopId]) { - cachedGraph.interchange[stopId] = 30; // 30 seconds interchange time - } - }); - - // Create transfers between all stops - await walking.ensureCacheForStops(routeStops, cachedStopLocations); - - routeStops.forEach(stopId => { - routeStops.forEach(otherStopId => { - if (stopId !== otherStopId) { - - const cachedData = walking.getCachedWalk(stopId, otherStopId); - - if (cachedData) { - cachedGraph.transfers[stopId].push({ - origin: stopId, - destination: otherStopId, - duration: cachedData.duration, - startTime: 0, - endTime: Number.MAX_SAFE_INTEGER - }); - } else { - console.warn(`Unexpected missing walk data: ${stopId} -> ${otherStopId}`); - } - } - }); - }); - - const totalTransfers = Object.values(cachedGraph.transfers).reduce((total, t) => total + t.length, 0); - console.log(`Total transfers in cachedGraph: ${totalTransfers}`); - - } catch (error) { - console.error('Error updating transfers:', error); - } - }); -} - -export { - curBusPositions, - cachedRoutes, - cachedPredsByVid, - cachedPredsByStopId, - validRoutes, - curRouteSelections, - routes, - cachedStopLocations, - routeTimingCache, - cachedGraph, - stopIdToName, - tatripidToRt, - getAllBusPredictions, - updateBusPositions, - getSelectableRoutes, - rebuildGraph -}; diff --git a/src/legacy/reminderService-reminders.ts b/src/legacy/reminderService-reminders.ts deleted file mode 100644 index b997fcd..0000000 --- a/src/legacy/reminderService-reminders.ts +++ /dev/null @@ -1,240 +0,0 @@ -import dotenv from "dotenv"; -import { cachedPredsByStopId, stopIdToName } from "./busService"; -import { getMessaging } from "firebase-admin/messaging"; -import { applicationDefault, initializeApp } from "firebase-admin/app"; - -dotenv.config() - -// Initialize Firebase -initializeApp({ credential: applicationDefault() }); - -type Event = { - stpid: string, - rtid: string, - readonly __brand: "event" -} - -type RegistrationToken = string & { readonly __brand: "registration_token" } -type EventKey = string & { readonly __brand: "event_key" } - -function encodeEvent(e: Event): EventKey { - return `${e.stpid}|${e.rtid}` as EventKey; -} - -function decodeEvent(e: EventKey): Event { - const split = e.split('|'); - return { stpid: split[0], rtid: split[1] } as Event; -} - -// Subscriptions go through a pipeline, starting in the waiting for reminder -// stage. After the bus in x minutes notification is set they move to the -// waiting for bus stage, where they stay until the bus is arriving notification -// is sent. Being in the second stage is repsented by having a threshold of null. -class ReminderSubscriptions { - // a thresh of null means being in the second stage - subscriptions: Array<{ event: Event, thresh: number | null, token: RegistrationToken }> - - constructor() { - this.subscriptions = []; - } - - // addition is done to the start of the pipeline - add(event: Event, thresh: number, token: RegistrationToken) { - console.log("Adding a reminder subscription"); - this.subscriptions.push({ event, thresh, token }); - } - - // removes all subscriptions involving both `event` and `token` - remove(event: Event, token: RegistrationToken) { - console.log("Removing a reminder subscription"); - this.subscriptions = this.subscriptions - .filter((s) => s.event.rtid !== event.rtid || s.event.stpid !== event.stpid || s.token !== token); - } - - // updates the status of all registrations, returning an object representing the - // notifications that should be sent - process(arrivalTimes: Map): { - reminder: Map>, - atTheStop: Map>, - disappeared: Map>, - delayed: Map> - } { - const addHelper = (map: Map>, key: EventKey, token: RegistrationToken) => { - let tokens = map.get(key); - if (tokens === undefined) { - map.set(key, new Set()); - tokens = map.get(key)!; - } - tokens.add(token); - }; - const notifications = { - reminder: new Map(), atTheStop: new Map(), disappeared: new Map(), delayed: new Map() - }; - const newSubscriptions: typeof this.subscriptions = []; - for (const subscription of this.subscriptions) { - const key = encodeEvent(subscription.event); - const arrivalTime = arrivalTimes.get(key); - if (arrivalTime === undefined || arrivalTime.curr === null) { - addHelper(notifications.disappeared, key, subscription.token); - } else if (subscription.thresh === null && arrivalTime.curr === 0) { - addHelper(notifications.atTheStop, key, subscription.token); - } else if (arrivalTime.prev !== null && arrivalTime.curr > arrivalTime.prev) { - addHelper(notifications.delayed, key, subscription.token); - newSubscriptions.push(subscription); // keep subscription if delayed - } else if (subscription.thresh !== null && arrivalTime.prev !== null - && arrivalTime.curr <= subscription.thresh && arrivalTime.curr < arrivalTime.prev) { - addHelper(notifications.reminder, key, subscription.token); - // replace with next in pipeline, a subscription to bus at stop - newSubscriptions.push({ event: subscription.event, thresh: null, token: subscription.token }); - } else { - newSubscriptions.push(subscription); // keep subscription by default - } - } - this.subscriptions = newSubscriptions; - console.log(`Process completed with ${notifications.reminder.size}, ${notifications.atTheStop.size}, ${notifications.delayed.size}, ${notifications.disappeared.size}`); - return notifications; - } - - // removes all subscriptions involving `event` - removeAllFor(event: Event) { - this.subscriptions = this.subscriptions - .filter((s) => s.event.rtid !== event.rtid || s.event.stpid !== event.stpid); - } - - swapToken(from: RegistrationToken, to: RegistrationToken) { - this.subscriptions = this.subscriptions.map((s) => { - if (s.token === from) { - return { ...s, token: to }; - } else { - return s; - } - }); - } - - activeRemindersFor(id: RegistrationToken): Array<{ stpid: string, rtid: string, thresh: number | null }> { - return this.subscriptions - .filter((s) => s.token === id) - .map((s) => { - return {stpid: s.event.stpid, rtid: s.event.rtid, thresh: s.thresh }; - }); - } - - describe() { - console.log(`There are ${this.subscriptions.length} reminder subscriptions`); - } -} - -const reminderSubscriptions = new ReminderSubscriptions(); -const arrivalTimes: Map = new Map(); - -function processReminders() { - // move current arrival times to prev - for (const [_k, v] of arrivalTimes) { - v.prev = v.curr; - v.curr = null; - } - - const stpids = Object.keys(cachedPredsByStopId); - // determine arrival time updates for each stop - for (const stpid of stpids) { - for (const vehicle of cachedPredsByStopId[stpid]) { - const rtid = vehicle.rt; - const prediction = vehicle.prdctdn === 'DUE' ? 0 : parseInt(vehicle.prdctdn); - const key = encodeEvent({ stpid: stpid, rtid: rtid } as Event); - let time = arrivalTimes.get(key); - if (time === undefined) { - arrivalTimes.set(key, { curr: null, prev: null }); - time = arrivalTimes.get(key)!; - } - if (time.curr === null || prediction < time.curr) - time.curr = prediction; - } - } - - // send push notifications as needed - const notifications = reminderSubscriptions.process(arrivalTimes); - for (const [eventKey, tokens] of notifications.reminder) { - const event = decodeEvent(eventKey); - const stopName = stopIdToName[event.stpid] ?? event.stpid; - sendToAll( - { - notification: { - title: 'Bus Arrival Reminder', - body: `${event.rtid} is ${arrivalTimes.get(eventKey)?.curr} minute(s) away from ${stopName}` - } - }, - tokens - ); - } - for (const [eventKey, tokens] of notifications.atTheStop) { - const event = decodeEvent(eventKey); - const stopName = stopIdToName[event.stpid] ?? event.stpid; - sendToAll( - { - notification: { title: 'Bus Arriving', body: `${event.rtid} is almost at ${stopName}` }, - }, - tokens - ); - } - for (const [eventKey, tokens] of notifications.delayed) { - const event = decodeEvent(eventKey); - const stopName = stopIdToName[event.stpid] ?? event.stpid; - const arrivalTime = arrivalTimes.get(eventKey); - const delay = arrivalTime?.curr !== null && arrivalTime?.prev ? `${arrivalTime.curr - arrivalTime.prev}` : `some`; - sendToAll( - { - notification: { - title: `Bus Delayed`, - body: `The ${event.rtid} bus en route to ${stopName} got delayed by ${delay} minute(s).` - } - }, - tokens - ); - } - for (const [eventKey, tokens] of notifications.disappeared) { - const event = decodeEvent(eventKey); - const stopName = stopIdToName[event.stpid] ?? event.stpid; - sendToAll( - { - notification: { - title: `Bus Disappeared`, - body: `The ${event.rtid} bus en route to ${stopName} disappeared! Set a new reminder if desired.` - } - }, - tokens - ); - } - -} - -function sendToAll(msg: any, tokens: Set) { - console.log(`sending a message to ${tokens.size} devices`); - const group = new Set(); - for (const token of tokens) { - if (group.size === 500) { - sendToAllHelper(msg, group); - group.clear(); - } - group.add(token); - } - sendToAllHelper(msg, group); -} - -// REQUIRES: tokens.size <= 500 -function sendToAllHelper(msg: any, tokens: Set) { - const payload = { tokens: Array.from(tokens), ...msg }; - getMessaging().sendEachForMulticast(payload) - .then((res) => { - if (res.failureCount > 0) { - console.log(`${res.failureCount} messages failed to send!`); - res.responses.forEach((res, idx) => { - if (!res.success) { - console.log(`message send ${idx} failed`); - console.log(res.error); - } - }) - } - }); -} - -export { processReminders, reminderSubscriptions, Event, RegistrationToken }; diff --git a/src/legacy/v3-reminders.ts b/src/legacy/v3-reminders.ts deleted file mode 100644 index b01d078..0000000 --- a/src/legacy/v3-reminders.ts +++ /dev/null @@ -1,660 +0,0 @@ -import express from "express"; -import dotenv from "dotenv"; -import { - Transfer, - StopID, - TimetableLeg -} from "./raptor/types"; -import { RaptorAlgorithm } from "./raptor/RaptorAlgorithm"; -import { RaptorAlgorithmFactory } from "./raptor/RaptorAlgorithmFactory"; -import { DepartAfterQuery } from "./query/DepartAfterQuery"; -import { JourneyFactory } from "./results/JourneyFactory"; -import { earliestArrival, leastChanges, leastWalking } from "./results/filter/MultipleCriteriaFilter"; - -import * as metadata from "./assets/route-data.json"; -import * as valid_assets from "./assets/valid_assets.json"; -import * as path from "node:path"; -import { MaxPriorityQueue } from '@datastructures-js/priority-queue'; - - -import { - curBusPositions, - cachedPredsByStopId, - cachedRoutes, - cachedPredsByVid, - cachedStopLocations, - curRouteSelections, - stopIdToName, - tatripidToRt, - getAllBusPredictions, - routeTimingCache, - cachedGraph, - updateBusPositions, - getSelectableRoutes, - rebuildGraph -} from './busService'; -import axios from "axios"; - -// Simple Bus Color System -interface BusRoute { - routeId: string; - color: string; - image: string; -} - -class BusColorManager { - private readonly routes: BusRoute[] = [ - { routeId: "BB", color: "#2F773F", image: "bus_BB.png" }, - { routeId: "CN", color: "#643076", image: "bus_CN.png" }, - { routeId: "CS", color: "#3559B8", image: "bus_CS.png" }, - { routeId: "CSX", color: "#1C2256", image: "bus_CSX.png" }, - { routeId: "DD", color: "#A9C534", image: "bus_DD.png" }, - { routeId: "MX", color: "#5EC7DE", image: "bus_MX.png" }, - { routeId: "NE", color: "#C55188", image: "bus_NE.png" }, - { routeId: "NW", color: "#AE3636", image: "bus_NW.png" }, - { routeId: "NX", color: "#DA4343", image: "bus_NX.png" }, - { routeId: "OS", color: "#E8A43C", image: "bus_OS.png" }, - { routeId: "NES", color: "#C55188", image: "bus_NES.png" }, - { routeId: "WS", color: "#BA5231", image: "bus_WS.png" }, - { routeId: "WX", color: "#E8663E", image: "bus_WX.png" } - ]; - - public getRouteColor(routeId: string): string | null { - const route = this.routes.find(r => r.routeId === routeId); - return route ? route.color : null; - } - - public getRouteImage(routeId: string): string | null { - const route = this.routes.find(r => r.routeId === routeId); - return route ? route.image : null; - } - - public getAllRoutes(): BusRoute[] { - return [...this.routes]; - } - - public getRouteInfo(routeId: string): BusRoute | null { - return this.routes.find(r => r.routeId === routeId) || null; - } -} - -// Initialize bus color manager -const busColorManager = new BusColorManager(); - -dotenv.config(); -const router = express.Router(); -const routeImages: { [k: string]: string } = metadata.routeImages; - -setInterval(updateBusPositions, 7500); -setInterval(getSelectableRoutes, 60000); -setInterval(rebuildGraph, 10 * 1000); -setInterval(processReminders, 10 * 1000); -setInterval(() => reminderSubscriptions.describe(), 60000); -getSelectableRoutes(); -rebuildGraph(); - -import * as process from "node:process"; -import { getMessaging } from "firebase-admin/messaging"; -import { processReminders, reminderSubscriptions, Event, RegistrationToken } from "./reminderService"; - - -dotenv.config(); - -const API_KEY = process.env.MBUS_API_KEY; -router.get('/getBusPredictions1/:busId', (req, res) => { - axios.get(`https://mbus.ltp.umich.edu/bustime/api/v3/getpredictions?requestType=getpredictions&locale=en&vid=${req.params.busId}&top=4&tmres=s&rtpidatafeed=bustime&key=${API_KEY}&format=json&xtime=1626028950462`).then(apiRes => { - res.send(apiRes.data); - }).catch(err => { - console.log(err); - res.sendStatus(500); - - }); -}); - -router.get('/getBusPositions', (req, res) => { - res.send(curBusPositions); -}); - -router.get('/getVehiclePositions', (req, res) => { - res.send(curBusPositions); -}); - -router.get('/getSelectableRoutes', (req, res) => { - res.send(curRouteSelections); -}); - -router.get('/getAllRoutes', (req, res) => { - res.send({ routes: cachedRoutes }); -}); - -router.get('/getrouteCache', (req, res) => { - res.send({ routes: routeTimingCache }); -}); - -router.get('/getVehicleImage/:route', (req, res) => { - const { route } = req.params; - - const dirname = import.meta.dirname; - const assetPath = path.join(dirname, 'assets'); - const imagePath = path.join(assetPath, 'main2025'); - - if (!route || !(route in routeImages)) { - res.sendFile(path.join(assetPath, 'bus_CN.png')); - return res.sendStatus(400); - } - - res.sendFile(path.join(imagePath, routeImages[route])); -}); - -router.get('/getRouteInfoVersion', (req, res) => { - res.send(JSON.stringify({ version: metadata.metadata.version })); -}); - -router.get('/getRouteInformation', (req, res) => { - const infoToSend = { - routeIdToName: metadata.routeIdToName, - routeImages: metadata.routeImages, - metadata: metadata.metadata, - routeColors: busColorManager.getAllRoutes().map(route => ({ - routeId: route.routeId, - color: route.color, - image: route.image - })) - } - res.send(infoToSend); -}); - -router.get('/getStartupInfo', (req, res) => { - res.json({ - // updating this will disable older versions of the app - min_supported_version: "1.0.0", - why_update_message: { - title: "New Update Available", - subtitle: "Please update to the latest version for the best experience." - }, - // adding data here will show a persistant message on launch - persistant_message: { - title: "Update on missing bus predictions", - subtitle: "2/9 9:03 PM: The university has confirmed to us that they're actively working on fixing the issue with missing bus predictions. Thank you for your patience." - }, - // adding data here will show a one-time message on launch (not yet implemented) - one_time_message: { - title: "", - subtitle: "" - }, - // updating this will make bus images redownload on frontend - bus_image_version: "1", - }); -});; - -router.get('/getBusPredictions/:busId', (req, res) => { - const busId = req.params.busId; - const preds = cachedPredsByVid[busId]; - - if (!preds) { - return res.json({ - "bustime-response": { "prd": [] } - }); - } - res.json({ - "bustime-response": { "prd": preds } - }); -}); - -router.get('/getStopPredictions/:stopId', (req, res) => { - const stopId = req.params.stopId; - const preds = cachedPredsByStopId[stopId]; - - if (!preds) { - return res.json({ - "bustime-response": { "prd": [] } - }); - } - - res.json({ - "bustime-response": { "prd": preds } - }); -}); - -router.get('/getAllPredictions', async (req, res) => { - try { - const predictions = await getAllBusPredictions(); - res.send(predictions); - } catch (err) { - console.log(err); - res.sendStatus(500); - } -}); - -router.get('/getAllStops', (req, res) => { - const stopsList = Object.entries(cachedStopLocations).map(([stpid, stopInfo]) => ({ - stpid, - ...stopInfo, - })); - res.json(Object.values(stopsList)); -}); - -router.get('/getBuildingLocations', (req, res) => { - res.sendFile(path.join(import.meta.dirname, 'assets', 'building-data.json')); -}); - -router.get('/get-startup-messages', (req, res) => { - res.send(JSON.stringify(message)); -}); - -// Simple bus color endpoints -router.get('/getRouteColors', (req, res) => { - const routes = busColorManager.getAllRoutes(); - res.json({ - routes: routes.map(route => ({ - routeId: route.routeId, - color: route.color, - image: route.image - })) - }); -}); - -router.get('/getRouteColor/:routeId', (req, res) => { - const { routeId } = req.params; - const routeInfo = busColorManager.getRouteInfo(routeId); - - if (!routeInfo) { - return res.status(404).json({ error: `Route '${routeId}' not found` }); - } - - res.json({ - routeId: routeInfo.routeId, - color: routeInfo.color, - image: routeInfo.image - }); -}); - -// Simple endpoint for frontend, gets everything needed for UI -router.get('/getFrontendData', (req, res) => { - try { - const routes = busColorManager.getAllRoutes(); - - const response = { - routes: routes.map(route => ({ - routeId: route.routeId, - name: (metadata.routeIdToName as any)[route.routeId] || route.routeId, - image: route.image, - color: route.color, - imageUrl: `/mbus/api/v3/getVehicleImage/${route.routeId}` - })), - metadata: { - ...metadata.metadata, - lastUpdated: new Date().toISOString() - } - }; - - res.json(response); - } catch (error) { - res.status(500).json({ error: 'Failed to get frontend data' }); - } -}); - - -router.get('/nearest-stops', (req, res) => { - try { - const { lat, lon, k = '2' } = req.query; - - const originLat = parseFloat(lat as string); - const originLon = parseFloat(lon as string); - const numStops = parseInt(k as string); - - if (isNaN(originLat) || isNaN(originLon)) { - return res.status(400).json({ error: 'Invalid or missing lat/lon' }); - } - if (isNaN(numStops) || numStops <= 0) { - return res.status(400).json({ error: 'Parameter k must be a positive integer' }); - } - - const heap = new MaxPriorityQueue<{ stpid: string; name: string; lat: number; lon: number; distance: number }>({ - compare: (a, b) => a.distance - b.distance - }); - - for (const [stpid, stop] of Object.entries(cachedStopLocations)) { - const latDiff = (stop.lat - originLat) * 111320; - const lonDiff = (stop.lon - originLon) * 111320 * Math.cos(originLat * Math.PI / 180); - const distance = Math.sqrt(latDiff ** 2 + lonDiff ** 2); - - const stopWithDist = { - stpid, - name: stop.name, - lat: stop.lat, - lon: stop.lon, - distance - }; - - if (heap.size() < numStops) { - heap.enqueue(stopWithDist); - } else if (distance < heap.front().distance) { - heap.dequeue(); - heap.enqueue(stopWithDist); - } - } - - const nearestStops = heap.toArray().sort((a, b) => a.distance - b.distance); - res.json({ nearestStops }); - } catch (error) { - console.error('Error in /nearest-stops:', error); - res.status(500).json({ error: 'Internal server error' }); - } -}); - -function optimizeWalkingFastest(journey: any, cachedGraph: any): any { - if (!journey) return journey; - - const optimizedLegs: any[] = []; - const WALKING_SPEED_KMH = 4; - const WALKING_SPEED_MS = WALKING_SPEED_KMH * 1000 / 3600; - - function distanceMeters(lat1: number, lon1: number, lat2: number, lon2: number): number { - const dx = (lat2 - lat1) * 111320; - const dy = (lon2 - lon1) * 111320 * Math.cos(lat1 * Math.PI / 180); - return Math.sqrt(dx * dx + dy * dy); - } - - for (let i = 0; i < journey.legs.length; i++) { - const leg = journey.legs[i]; - - // Look for a transfer followed by a bus trip - if (leg.trip && i > 0 && "duration" in journey.legs[i - 1]) { - const transfer = journey.legs[i - 1] as Transfer; - const tripLeg = leg as TimetableLeg; - const trip = tripLeg.trip; - - const originalBoardStop = tripLeg.stopTimes[0].stop; - const boardIdx = trip.stopTimes.findIndex(st => st.stop === originalBoardStop); - const walkStartTime = transfer.startTime; - - let bestStop = originalBoardStop; - let bestIdx = boardIdx; - let bestDistance = Number.MAX_SAFE_INTEGER; - - const originLoc = cachedStopLocations[transfer.origin]; - if (!originLoc) { - optimizedLegs.push(leg); - continue; - } - - for (let j = boardIdx; j < trip.stopTimes.length; j++) { - const candidate = trip.stopTimes[j]; - const stopLoc = cachedStopLocations[candidate.stop]; - if (!stopLoc) continue; - - const dist = distanceMeters(originLoc.lat, originLoc.lon, stopLoc.lat, stopLoc.lon); - const walkArrival = walkStartTime + dist / WALKING_SPEED_MS; - const busArrival = candidate.arrivalTime - (cachedGraph.interchange[candidate.stop] ?? 0); - - if (walkArrival <= busArrival && dist < bestDistance) { - bestStop = candidate.stop; - bestIdx = j; - bestDistance = dist; - } - } - - if (bestStop !== originalBoardStop) { - console.log(`Optimized walking to ${bestStop} instead of ${originalBoardStop}, saving ${Math.round(bestDistance)} meters`); - // Update transfer - transfer.destination = bestStop; - transfer.duration = Math.round(bestDistance / WALKING_SPEED_MS); - - // Trim trip leg to start from bestStop - tripLeg.stopTimes = trip.stopTimes.slice(bestIdx); - - // Refresh trip leg duration - if (tripLeg.stopTimes.length > 1) { - const firstStop = tripLeg.stopTimes[0]; - const lastStop = tripLeg.stopTimes[tripLeg.stopTimes.length - 1]; - (tripLeg as any).duration = lastStop.arrivalTime - firstStop.departureTime; - } - } - } - - optimizedLegs.push(leg); - } - - return { ...journey, legs: optimizedLegs }; -} - -router.get('/plan-journey', async (req, res) => { - try { - const originStopId = 'VIRTUAL_ORIGIN'; - const destStopId = 'VIRTUAL_DESTINATION'; - - const { originLat, originLon, destLat, destLon, walkingPenalty: walkingPenaltyParam } = req.query; - if (!originLat || !originLon || !destLat || !destLon) { - return res.status(400).json({ error: 'Origin and destination coordinates are required' }); - } - - const now = new Date(); - const currentTime = now.getUTCHours() * 3600 + now.getUTCMinutes() * 60 + now.getUTCSeconds(); - - if (!cachedGraph || !cachedGraph.trips || cachedGraph.trips.length === 0) { - await rebuildGraph(); // try to build - if (!cachedGraph) { - return res.status(404).json({ error: 'No routes available at this time' }); - } - } - - // Clear all transfers from the virtual origin - cachedGraph.transfers[originStopId] = []; - cachedGraph.transfers[destStopId] = []; - // Clear all transfers to virtual destination - Object.keys(cachedGraph.transfers).forEach(stopId => { - cachedGraph.transfers[stopId] = cachedGraph.transfers[stopId].filter( - t => t.destination !== destStopId - ); - }); - - // Update the times for the virtual trips - const vOriginTrip = cachedGraph.trips.find(t => t.tripId === 'VIRTUAL_ORIGIN_TRIP'); - if (vOriginTrip) { - vOriginTrip.stopTimes[0].arrivalTime = currentTime; - vOriginTrip.stopTimes[0].departureTime = currentTime; - } - const vDestTrip = cachedGraph.trips.find(t => t.tripId === 'VIRTUAL_DESTINATION_TRIP'); - if (vDestTrip) { - vDestTrip.stopTimes[0].arrivalTime = currentTime; - vDestTrip.stopTimes[0].departureTime = currentTime; - } - - // Calculate transfers from origin to all real stops - const originLatNum = parseFloat(originLat as string); - const originLonNum = parseFloat(originLon as string); - const destLatNum = parseFloat(destLat as string); - const destLonNum = parseFloat(destLon as string); - - const WALKING_SPEED_KMH = 4; - const WALKING_SPEED_MS = WALKING_SPEED_KMH * 1000 / 3600; - - // Add transfers from origin to all real stops - Object.keys(cachedStopLocations).forEach(stopId => { - const stopLocation = cachedStopLocations[stopId]; - if (stopLocation) { - const latDiff = (stopLocation.lat - originLatNum) * 111320; - const lonDiff = (stopLocation.lon - originLonNum) * 111320 * Math.cos(originLatNum * Math.PI / 180); - const distance = Math.sqrt(latDiff * latDiff + lonDiff * lonDiff); - - let walkingTimeSeconds = distance / WALKING_SPEED_MS; - const transferDuration = Math.round(walkingTimeSeconds); - - const transfer: Transfer = { - origin: originStopId, - destination: stopId, - duration: transferDuration, - startTime: currentTime, - endTime: Number.MAX_SAFE_INTEGER - }; - cachedGraph.transfers[originStopId].push(transfer); - } - }); - - // Add transfers from all real stops to destination - Object.keys(cachedStopLocations).forEach(stopId => { - const stopLocation = cachedStopLocations[stopId]; - if (stopLocation) { - const latDiff = (destLatNum - stopLocation.lat) * 111320; - const lonDiff = (destLonNum - stopLocation.lon) * 111320 * Math.cos(stopLocation.lat * Math.PI / 180); - const distance = Math.sqrt(latDiff * latDiff + lonDiff * lonDiff); - - let walkingTimeSeconds = distance / WALKING_SPEED_MS; - const transferDuration = Math.round(walkingTimeSeconds); - - const transfer: Transfer = { - origin: stopId, - destination: destStopId, - duration: transferDuration, - startTime: currentTime, - endTime: Number.MAX_SAFE_INTEGER - }; - cachedGraph.transfers[stopId].push(transfer); - } - }); - - // Direct transfer from VIRTUAL_ORIGIN to VIRTUAL_DESTINATION - const directLatDiff = (destLatNum - originLatNum) * 111320; - const directLonDiff = (destLonNum - originLonNum) * 111320 * Math.cos(originLatNum * Math.PI / 180); - const directDistance = Math.sqrt(directLatDiff * directLatDiff + directLonDiff * directLonDiff); - - let directWalkingTimeSeconds = directDistance / WALKING_SPEED_MS; - - const directTransferDuration = Math.round(directWalkingTimeSeconds); - //console.log(`Walking Distance: ${directTransferDuration}`); - - const directTransfer: Transfer = { - origin: originStopId, - destination: destStopId, - duration: directTransferDuration, - startTime: currentTime, - endTime: Number.MAX_SAFE_INTEGER - }; - cachedGraph.transfers[originStopId].push(directTransfer); - - RaptorAlgorithm.setDebug(false); - const raptor = RaptorAlgorithmFactory.create(cachedGraph.trips, cachedGraph.transfers, cachedGraph.interchange); - let walkingPenalty = 1; // default no penalty - if (walkingPenaltyParam !== undefined) { - const parsed = parseFloat(walkingPenaltyParam as string); - if (!isNaN(parsed) && parsed > 0) { - walkingPenalty = parsed; - } - } - raptor.setWalkingPenalty(walkingPenalty); - - const resultsFactory = new JourneyFactory(); - const journeyPlanner = new DepartAfterQuery(raptor, resultsFactory); - const journeys = journeyPlanner.plan( - originStopId as StopID, - destStopId as StopID, - currentTime - ); - - const formatJourney = (journey: any) => { - if (!journey) return null; - return { - ...journey, - legs: journey.legs.map((leg: any) => { - const formattedLeg: any = { - ...leg, - origin_id: leg.origin, - origin: leg.origin === 'VIRTUAL_ORIGIN' ? 'Start' : (leg.origin === 'VIRTUAL_DESTINATION' ? 'End' : (stopIdToName[leg.origin] || leg.origin)), - destination_id: leg.destination, - destination: leg.destination === 'VIRTUAL_ORIGIN' ? 'Start' : (leg.destination === 'VIRTUAL_DESTINATION' ? 'End' : (stopIdToName[leg.destination] || leg.destination)) - }; - if (leg.trip && leg.trip.tripId) { - // Add duration for bus legs - if (leg.stopTimes && leg.stopTimes.length > 0) { - const firstStop = leg.stopTimes[0]; - const lastStop = leg.stopTimes[leg.stopTimes.length - 1]; - formattedLeg.duration = lastStop.arrivalTime - firstStop.departureTime; - formattedLeg.rt = firstStop.rt; - formattedLeg.vid = leg.vid; - - } - } else if (typeof leg.duration === 'number') { - // Add duration for transfer legs - formattedLeg.duration = leg.duration; - } - return formattedLeg; - }) - }; - }; - - let fastest = journeys.length > 0 ? journeys.reduce((best, j) => earliestArrival(best, j) ? j : best, journeys[0]) : null; - // if (fastest) { - // fastest = optimizeWalkingFastest(fastest, cachedGraph); - // } - const leastTransfers = journeys.length > 0 ? journeys.reduce((best, j) => leastChanges(best, j) ? j : best, journeys[0]) : null; - const leastWalk = journeys.length > 0 ? journeys.reduce((best, j) => leastWalking(best, j) ? j : best, journeys[0]) : null; - const uniqueJourneys = [fastest, leastTransfers, leastWalk] - .filter((j, i, arr) => j && arr.findIndex(x => x === j) === i) - .map(formatJourney); - res.json({ journeys: uniqueJourneys.slice(0, 3) }); - } catch (error) { - console.error('Error planning journey:', error); - res.status(500).json({ error: 'Failed to plan journey' }); - } -}); - -// Notifications / Reminders - -// Expects {token: string, stpid: string, rtid: string, thresh: number} in the body -router.post('/setReminder', (req, res) => { - const token = req.body.token as RegistrationToken; - const stpid: string = req.body.stpid; - const rtid: string = req.body.rtid; - const thresh: number = req.body.thresh; - reminderSubscriptions.add({ stpid, rtid } as Event, thresh, token); - res.sendStatus(200); -}); - -// Expects {token: string, stpid: string, rtid: string} in the body -router.post('/unsetReminder', (req, res) => { - const token = req.body.token as RegistrationToken; - const stpid: string = req.body.stpid; - const rtid: string = req.body.rtid; - reminderSubscriptions.remove({ stpid, rtid } as Event, token); - res.sendStatus(200); -}); - -// Expects {oldTok: string, newTok: string} in the body -// Upon responding with 200, future calls to /setReminder, /unsetReminder, and /activeReminders -// will need the new token -router.post('/swapToken', (req, res) => { - const oldTok = req.body.oldTok as RegistrationToken; - const newTok = req.body.newTok as RegistrationToken; - reminderSubscriptions.swapToken(oldTok, newTok); - res.sendStatus(200); -}); - -// Responds with { reminders: Array<{ stpid: string, rtid: string, thresh: number | null }> } -router.get('/activeReminders/:registrationToken', (req, res) => { - const token = req.params.registrationToken as RegistrationToken; - res.send({ reminders: reminderSubscriptions.activeRemindersFor(token) }); - res.status(200); -}); - -// testing purposes -router.post('/notifyMeLater', (req, res) => { - console.log("got request"); - const registrationToken = req.body.token; - if (registrationToken === undefined) { - console.log("got request with no token"); - console.log(req.body); - res.send("registration token missing"); - res.status(400); - return; - } - setTimeout(() => { - console.log("sending push notification.."); - getMessaging() - .send({ notification: { title: "hi", body: "hello world!" }, token: registrationToken }) - .catch((e) => console.log("Failed to send message: ", e)); - }, 10000); - res.sendStatus(200); -}); - -export default router; diff --git a/src/legacy/v3.ts b/src/legacy/v3.ts deleted file mode 100644 index 8de143a..0000000 --- a/src/legacy/v3.ts +++ /dev/null @@ -1,561 +0,0 @@ - -import * as walking from '../walking/walkingMap'; -import * as metadata from "../assets/route-data.json"; -import * as path from "node:path"; -import * as fs from 'fs'; - -import express from "express"; -import dotenv from "dotenv"; -import axios from "axios"; - -import { McRaptorAlgorithm, Journey, JourneyLeg } from "../raptor/McRaptorAlgorithm"; -import { MaxPriorityQueue } from '@datastructures-js/priority-queue'; - -import { - curBusPositions, - cachedPredsByStopId, - cachedRoutes, - cachedPredsByVid, - cachedStopLocations, - curRouteSelections, - stopIdToName, - tatripidToRt, - getAllBusPredictions, - routeTimingCache, - cachedGraph, - updateBusPositions, - getSelectableRoutes, - rebuildGraph, -} from './busService'; - -// Simple Bus Color System -interface BusRoute { - routeId: string; - color: string; - image: string; -} - -class BusColorManager { - private readonly routes: BusRoute[] = [ - { routeId: "BB", color: "#2F773F", image: "bus_BB.png" }, - { routeId: "CN", color: "#643076", image: "bus_CN.png" }, - { routeId: "CS", color: "#3559B8", image: "bus_CS.png" }, - { routeId: "CSX", color: "#1C2256", image: "bus_CSX.png" }, - { routeId: "DD", color: "#A9C534", image: "bus_DD.png" }, - { routeId: "MX", color: "#5EC7DE", image: "bus_MX.png" }, - { routeId: "NE", color: "#C55188", image: "bus_NE.png" }, - { routeId: "NW", color: "#AE3636", image: "bus_NW.png" }, - { routeId: "NX", color: "#DA4343", image: "bus_NX.png" }, - { routeId: "OS", color: "#E8A43C", image: "bus_OS.png" }, - { routeId: "NES", color: "#C55188", image: "bus_NES.png" }, - { routeId: "WS", color: "#BA5231", image: "bus_WS.png" }, - { routeId: "WX", color: "#E8663E", image: "bus_WX.png" } - ]; - - public getRouteColor(routeId: string): string | null { - const route = this.routes.find(r => r.routeId === routeId); - return route ? route.color : null; - } - - public getRouteImage(routeId: string): string | null { - const route = this.routes.find(r => r.routeId === routeId); - return route ? route.image : null; - } - - public getAllRoutes(): BusRoute[] { - return [...this.routes]; - } - - public getRouteInfo(routeId: string): BusRoute | null { - return this.routes.find(r => r.routeId === routeId) || null; - } -} - - -// Initialize bus color manager -const busColorManager = new BusColorManager(); - -dotenv.config(); -const router = express.Router(); -const routeImages: { [k: string]: string } = metadata.routeImages; - -setInterval(updateBusPositions, 7500); -setInterval(getSelectableRoutes, 60000); -setInterval(rebuildGraph, 10 * 1000); -getSelectableRoutes(); -rebuildGraph(); - -import * as process from "node:process"; - -const message = { - id: "gradamatation", - title: "Congrats Grads 🥳", - message: - "Congrats to everyone who is gradamatating! Enjoy some grad hats on the buses, and don't forget to celebrate!", - buildVersion: "99", -}; - -dotenv.config(); - -const API_KEY = process.env.MBUS_API_KEY; -router.get('/getBusPredictions1/:busId', (req, res) => { - axios.get(`https://mbus.ltp.umich.edu/bustime/api/v3/getpredictions?requestType=getpredictions&locale=en&vid=${req.params.busId}&top=4&tmres=s&rtpidatafeed=bustime&key=${API_KEY}&format=json&xtime=1626028950462`).then(apiRes => { - res.send(apiRes.data); - }).catch(err => { - console.log(err); - res.sendStatus(500); - - }); -}); - -router.get('/getBusPositions', (req, res) => { - res.send(curBusPositions); -}); - -router.get('/getVehiclePositions', (req, res) => { - res.send(curBusPositions); -}); - -router.get('/getSelectableRoutes', (req, res) => { - res.send(curRouteSelections); -}); - -router.get('/getAllRoutes', (req, res) => { - res.send({ routes: cachedRoutes }); -}); - -router.get('/getrouteCache', (req, res) => { - res.send({ routes: routeTimingCache }); -}); - -router.get('/getVehicleImage/:route', (req, res) => { - const { route } = req.params; - - const dirname = import.meta.dirname; - const assetPath = path.join(dirname, 'assets'); - const imagePath = path.join(assetPath, 'main2025'); - - if (!route || !(route in routeImages)) { - res.status(400).sendFile(path.join(imagePath, 'bus_CN.png')); - return; - } - res.sendFile(path.join(imagePath, routeImages[route]), (err) => { - if (err) { - console.error(`Error sending requested image for route ${route}: ${err.message}`); - if (!res.headersSent) res.status(404).send('Image file not found on server.'); - } - }); -}); - -router.get('/getRouteInfoVersion', (req, res) => { - res.send(JSON.stringify({ version: metadata.metadata.version })); -}); - -router.get('/getRouteInformation', (req, res) => { - const infoToSend = { - routeIdToName: metadata.routeIdToName, - routeImages: metadata.routeImages, - metadata: metadata.metadata, - routeColors: busColorManager.getAllRoutes().map(route => ({ - routeId: route.routeId, - color: route.color, - image: route.image - })) - } - res.send(infoToSend); -}); - -router.get('/getStartupInfo', (req, res) => { - res.json({ - // updating this will disable older versions of the app - min_supported_version: "1.0.0", - why_update_message: { - title: "New Update Available", - subtitle: "Please update to the latest version for the best experience." - }, - // adding data here will show a persistant message on launch - persistant_message: { - title: "", - subtitle: "" - }, - // adding data here will show a one-time message on launch (not yet implemented) - one_time_message: { - title: "", - subtitle: "" - }, - // updating this will make bus images redownload on frontend - bus_image_version: "1", - }); -});; - -router.get('/getBusPredictions/:busId', (req, res) => { - const busId = req.params.busId; - const preds = cachedPredsByVid[busId]; - - if (!preds) { - return res.json({ - "bustime-response": { "prd": [] } - }); - } - res.json({ - "bustime-response": { "prd": preds } - }); -}); - -router.get('/getStopPredictions/:stopId', (req, res) => { - const stopId = req.params.stopId; - const preds = cachedPredsByStopId[stopId]; - - if (!preds) { - return res.json({ - "bustime-response": { "prd": [] } - }); - } - - res.json({ - "bustime-response": { "prd": preds } - }); -}); - -router.get('/getAllPredictions', async (req, res) => { - try { - const predictions = await getAllBusPredictions(); - res.send(predictions); - } catch (err) { - console.log(err); - res.sendStatus(500); - } -}); - -router.get('/getAllStops', (req, res) => { - const stopsList = Object.entries(cachedStopLocations).map(([stpid, stopInfo]) => ({ - stpid, - ...stopInfo, - })); - res.json(Object.values(stopsList)); -}); - -router.get('/getBuildingLocations', (req, res) => { - res.sendFile(path.join(import.meta.dirname, 'assets', 'building-data.json')); -}); - -router.get('/get-startup-messages', (req, res) => { - res.send(JSON.stringify(message)); -}); - -// Simple bus color endpoints -router.get('/getRouteColors', (req, res) => { - const routes = busColorManager.getAllRoutes(); - res.json({ - routes: routes.map(route => ({ - routeId: route.routeId, - color: route.color, - image: route.image - })) - }); -}); - -router.get('/getRouteColor/:routeId', (req, res) => { - const { routeId } = req.params; - const routeInfo = busColorManager.getRouteInfo(routeId); - - if (!routeInfo) { - return res.status(404).json({ error: `Route '${routeId}' not found` }); - } - - res.json({ - routeId: routeInfo.routeId, - color: routeInfo.color, - image: routeInfo.image - }); -}); - -// Simple endpoint for frontend, gets everything needed for UI -router.get('/getFrontendData', (req, res) => { - try { - const routes = busColorManager.getAllRoutes(); - - const response = { - routes: routes.map(route => ({ - routeId: route.routeId, - name: (metadata.routeIdToName as any)[route.routeId] || route.routeId, - image: route.image, - color: route.color, - imageUrl: `/mbus/api/v3/getVehicleImage/${route.routeId}` - })), - metadata: { - ...metadata.metadata, - lastUpdated: new Date().toISOString() - } - }; - - res.json(response); - } catch (error) { - res.status(500).json({ error: 'Failed to get frontend data' }); - } -}); - - -router.get('/nearest-stops', (req, res) => { - try { - const { lat, lon, k = '2' } = req.query; - - const originLat = parseFloat(lat as string); - const originLon = parseFloat(lon as string); - const numStops = parseInt(k as string); - - if (isNaN(originLat) || isNaN(originLon)) { - return res.status(400).json({ error: 'Invalid or missing lat/lon' }); - } - if (isNaN(numStops) || numStops <= 0) { - return res.status(400).json({ error: 'Parameter k must be a positive integer' }); - } - - const heap = new MaxPriorityQueue<{ stpid: string; name: string; lat: number; lon: number; distance: number }>({ - compare: (a, b) => a.distance - b.distance - }); - - for (const [stpid, stop] of Object.entries(cachedStopLocations)) { - const latDiff = (stop.lat - originLat) * 111320; - const lonDiff = (stop.lon - originLon) * 111320 * Math.cos(originLat * Math.PI / 180); - const distance = Math.sqrt(latDiff ** 2 + lonDiff ** 2); - - const stopWithDist = { - stpid, - name: stop.name, - lat: stop.lat, - lon: stop.lon, - distance - }; - - if (heap.size() < numStops) { - heap.enqueue(stopWithDist); - } else if (distance < heap.front()!.distance) { - heap.dequeue(); - heap.enqueue(stopWithDist); - } - } - - const nearestStops = heap.toArray().sort((a, b) => a.distance - b.distance); - res.json({ nearestStops }); - } catch (error) { - console.error('Error in /nearest-stops:', error); - res.status(500).json({ error: 'Internal server error' }); - } -}); - -router.get('/plan-journey', async (req, res) => { - try { - const originStopId = 'VIRTUAL_ORIGIN'; - const destStopId = 'VIRTUAL_DESTINATION'; - - const { originLat, originLon, destLat, destLon, walkingPenalty: walkingPenaltyParam} = req.query; - if (!originLat || !originLon || !destLat || !destLon) { - return res.status(400).json({ error: 'Origin and destination coordinates are required' }); - } - - const oLat = parseFloat(originLat as string); - const oLon = parseFloat(originLon as string); - const dLat = parseFloat(destLat as string); - const dLon = parseFloat(destLon as string); - - const now = new Date(); - const currentTime = now.getUTCHours() * 3600 + now.getUTCMinutes() * 60 + now.getUTCSeconds(); - - if (!cachedGraph || !cachedGraph.trips || cachedGraph.trips.length === 0) { - await rebuildGraph(); - if (!cachedGraph) { - return res.status(404).json({ error: 'No routes available at this time' }); - } - } - - // Clear all transfers for virtual stops - cachedGraph.transfers[originStopId] = []; - cachedGraph.transfers[destStopId] = []; - Object.keys(cachedGraph.transfers).forEach(stopId => { - cachedGraph.transfers[stopId] = cachedGraph.transfers[stopId].filter( - t => t.destination !== destStopId - ); - }); - - const vOriginTrip = cachedGraph.trips.find(t => t.tripId === 'VIRTUAL_ORIGIN_TRIP'); - if (vOriginTrip) { - vOriginTrip.stopTimes[0].arrivalTime = currentTime; - vOriginTrip.stopTimes[0].departureTime = currentTime; - } - const vDestTrip = cachedGraph.trips.find(t => t.tripId === 'VIRTUAL_DESTINATION_TRIP'); - if (vDestTrip) { - vDestTrip.stopTimes[0].arrivalTime = currentTime; - vDestTrip.stopTimes[0].departureTime = currentTime; - } - - // Get walking times from origin to all stops - // Get walking times from all stops to dest - const walksFromOrigin = walking.getWalkingDistancesFrom(oLat, oLon, dLat, dLon); - const walksToDest = walking.getWalkingDistancesFrom(dLat, dLon); - - walksFromOrigin.forEach(walk => { - if (walk.stopId === "DIRECT_WALK") { - cachedGraph.transfers[originStopId].push({ - origin: originStopId, - destination: destStopId, - duration: walk.duration, - startTime: currentTime, - endTime: Number.MAX_SAFE_INTEGER - }); - } else { - cachedGraph.transfers[originStopId].push({ - origin: originStopId, - destination: walk.stopId, - duration: walk.duration, - startTime: currentTime, - endTime: Number.MAX_SAFE_INTEGER - }); - } - }); - - walksToDest.forEach(walk => { - cachedGraph.transfers[walk.stopId].push({ - origin: walk.stopId, - destination: destStopId, - duration: walk.duration, - startTime: currentTime, - endTime: Number.MAX_SAFE_INTEGER - }); - }); - - const mcRaptor = new McRaptorAlgorithm(cachedGraph.trips, cachedGraph.transfers, cachedGraph.interchange); - - let walkingPenalty = 1; - if (walkingPenaltyParam !== undefined) { - const parsed = parseFloat(walkingPenaltyParam as string); - if (!isNaN(parsed) && parsed > 0) { - walkingPenalty = parsed; - } - } - mcRaptor.setWalkingPenalty(walkingPenalty); - - let rangeInSeconds = 60*45; - const { range } = req.query; - if (range !== undefined) { - const parsedRange = parseInt(range as string); - if (!isNaN(parsedRange) && parsedRange > 0) { - rangeInSeconds = parsedRange * 60; - } - } - - let journeys: Journey[]; - if(range !== undefined) { - journeys = mcRaptor.getOptimizedJourneysInRange(originStopId, destStopId, currentTime, rangeInSeconds); - } else { - journeys = mcRaptor.getOptimizedJourneys(originStopId, destStopId, currentTime); - } - const processLeg = async (leg: JourneyLeg) => { - const isWalk = !leg.trip; - - const formattedLeg: any = { - origin_id: leg.origin, - origin: leg.origin === 'VIRTUAL_ORIGIN' ? 'Start' : (leg.origin === 'VIRTUAL_DESTINATION' ? 'End' : (stopIdToName[leg.origin] || leg.origin)), - destination_id: leg.destination, - destination: leg.destination === 'VIRTUAL_DESTINATION' ? 'End' : (stopIdToName[leg.destination] || leg.destination), - destinationName: leg.destination === 'VIRTUAL_DESTINATION' ? 'End' : (stopIdToName[leg.destination] || leg.destination), - startTime: Math.round(leg.startTime), - endTime: Math.round(leg.endTime), - duration: Math.round(leg.duration), - mode: isWalk ? 'walk' : 'bus', - originID: leg.originID, - destinationID: leg.destinationID, - stopTimes: leg.stopTimes, - trip: leg.trip, - rt: leg.rt - }; - - if (leg.trip) { - formattedLeg.tripId = leg.trip.tripId; - formattedLeg.vid = leg.trip.vid; - if (!formattedLeg.rt) { - const firstStop = leg.trip.stopTimes[0]; - formattedLeg.rt = firstStop.rt || tatripidToRt[leg.trip.tripId] || 'UNKNOWN'; - } - } - - if (isWalk) { - const cached = walking.getCachedWalk(leg.origin, leg.destination); - - if (cached) { - Object.assign(formattedLeg, cached); - } else { - const l1 = leg.origin === 'VIRTUAL_ORIGIN' ? { lat: oLat, lon: oLon } : cachedStopLocations[leg.origin]; - const l2 = leg.destination === 'VIRTUAL_DESTINATION' ? { lat: dLat, lon: dLon } : cachedStopLocations[leg.destination]; - - if (l1 && l2) { - try { - const data = await walking.getWalkingResponse(l1.lat, l1.lon, l2.lat, l2.lon); - data.duration = Math.round(data.duration); - Object.assign(formattedLeg, data); - } catch (e) { - formattedLeg.path_coords = []; - } - } - } - } - - return formattedLeg; - }; - - const processJourneys = async (journeys: Journey[]) => { - return Promise.all(journeys.map(async (journey: Journey) => { - if (!journey) return null; - - const legs = await Promise.all(journey.legs.map(processLeg)); - - return { - legs, - departureTime: journey.criteria.arrivalTime - (legs.reduce((acc, leg) => acc + leg.duration, 0)), - arrivalTime: journey.criteria.arrivalTime, - criteria: journey.criteria - }; - })); - }; - const processedList = await processJourneys(journeys); - const sortedJourneys = processedList - .filter((j: any) => j !== null) - .sort((a: any, b: any) => - a.arrivalTime - b.arrivalTime || - a.criteria.walkingDistance - b.criteria.walkingDistance - ); - res.json({ - journeys: sortedJourneys - }); - - } catch (error) { - console.error('Error planning journey:', error); - res.status(500).json({ error: 'Failed to plan journey' }); - } -}); - - -router.get('/save-graph', async (req, res) => { - if (process.env.DEV_SAVE !== 'true') { - return res.status(403).json({ error: 'Endpoint only available in DEV mode' }); - } - - try { - const filePath = path.resolve(process.cwd(), 'saved_graph.json'); - const fullState = { - graph: cachedGraph, - stopLocations: cachedStopLocations, - stopNames: stopIdToName, - predsByVid: cachedPredsByVid, - predsByStopId: cachedPredsByStopId - }; - const data = JSON.stringify(fullState, null, 2); - fs.writeFileSync(filePath, data); - res.json({ message: `Graph and state saved to ${filePath}` }); - } catch (error) { - console.error('Error saving graph:', error); - res.status(500).json({ error: 'Failed to save graph' }); - } -}); - -export default router; diff --git a/src/raptor/McRaptorAlgorithm.ts b/src/raptor/McRaptorAlgorithm.ts index 164b1f8..477afc4 100644 --- a/src/raptor/McRaptorAlgorithm.ts +++ b/src/raptor/McRaptorAlgorithm.ts @@ -1,13 +1,23 @@ -import { Trip, Transfer, StopID, Time, Interchange, StopTime } from "./types"; +import { Trip, Transfer, StopID, Time, Interchange, StopTime, TransfersByOrigin } from "./types"; import { Bag, Label } from "./McStructs"; +export const VIRTUAL_ORIGIN = 'VIRTUAL_ORIGIN'; +export const VIRTUAL_DESTINATION = 'VIRTUAL_DESTINATION'; + +/** + * Per-query walking overlay — avoids cloning the full transfer graph. + * Origin walks replace VIRTUAL_ORIGIN transfers; destination walks append to each stop. + */ +export interface McRaptorQueryOverlay { + originWalks: Transfer[]; + destinationWalks: Map; +} + /** * Represents a complete transit journey consisting of multiple legs. */ export interface Journey { - /** The sequence of legs (trips or walking transfers) in the journey. */ legs: JourneyLeg[]; - /** The performance metrics for this journey. */ criteria: { arrivalTime: number; walkingDistance: number; @@ -33,82 +43,123 @@ export interface JourneyLeg { stopTimes?: StopTime[]; } +function buildRouteIndices(trips: Trip[]) { + const routes: Record = {}; + const routeStops: Record = {}; + const stopToRoutes: Record = {}; + + for (const trip of trips) { + const stopSeq = trip.stopTimes.map(st => st.stop).join(','); + if (!routes[stopSeq]) { + routes[stopSeq] = []; + routeStops[stopSeq] = trip.stopTimes.map(st => st.stop); + } + routes[stopSeq].push(trip); + } + + for (const routeId in routes) { + routes[routeId].sort((a, b) => a.stopTimes[0].departureTime - b.stopTimes[0].departureTime); + for (const stop of routeStops[routeId]) { + if (!stopToRoutes[stop]) stopToRoutes[stop] = []; + stopToRoutes[stop].push(routeId); + } + } + + return { routes, routeStops, stopToRoutes }; +} + +/** Merge per-query walking overlay into base transfers once (avoids per-round .concat allocations). */ +function mergeTransfersWithOverlay( + baseTransfers: TransfersByOrigin, + overlay?: McRaptorQueryOverlay +): TransfersByOrigin { + if (!overlay) return baseTransfers; + + const merged: TransfersByOrigin = { ...baseTransfers }; + merged[VIRTUAL_ORIGIN] = overlay.originWalks; + + for (const [stop, extra] of overlay.destinationWalks) { + const base = baseTransfers[stop]; + merged[stop] = base ? [...base, extra] : [extra]; + } + + return merged; +} + +function resolveTransfers( + stop: StopID, + transfers: TransfersByOrigin +): Transfer[] { + if (stop === VIRTUAL_DESTINATION) return []; + return transfers[stop] || []; +} + +function findEarliestTrip(trips: Trip[], stopIndex: number, minTime: number): Trip | null { + let lo = 0; + let hi = trips.length - 1; + let result: Trip | null = null; + + while (lo <= hi) { + const mid = (lo + hi) >> 1; + const dep = trips[mid].stopTimes[stopIndex].departureTime; + if (dep >= minTime) { + result = trips[mid]; + hi = mid - 1; + } else { + lo = mid + 1; + } + } + return result; +} + /** - * Implementation of the McRAPTOR (Multi-Criteria Round-Based Public Transit Routing) algorithm. - * Optimizes for arrival time, walking distance, and number of transfers. + * Pre-built route indices for McRAPTOR. Rebuilt when the transit graph trips change. */ -export class McRaptorAlgorithm { - private trips: Trip[]; - private transfers: Record; - private interchange: Interchange; - private stops: StopID[]; - private routes: Record; - private routeStops: Record; - - private walkingPenalty: number = 1; - - /** - * Initializes the routing engine with transit data. - * @param trips - List of all transit trips. - * @param transfers - Graph of walking connections between stops. - * @param interchange - Minimum transfer times for each stop. - */ - constructor( +export class McRaptorIndex { + private readonly trips: Trip[]; + private readonly interchange: Interchange; + private readonly routes: Record; + private readonly routeStops: Record; + private readonly stopToRoutes: Record; + + private constructor( trips: Trip[], - transfers: Record, - interchange: Interchange + interchange: Interchange, + routes: Record, + routeStops: Record, + stopToRoutes: Record ) { this.trips = trips; - this.transfers = transfers; this.interchange = interchange; - this.stops = Object.keys(interchange); - - this.routes = {}; - this.routeStops = {}; - - for (const trip of trips) { - const stopSeq = trip.stopTimes.map(st => st.stop).join(','); - if (!this.routes[stopSeq]) { - this.routes[stopSeq] = []; - this.routeStops[stopSeq] = trip.stopTimes.map(st => st.stop); - } - this.routes[stopSeq].push(trip); - } - - for (const routeId in this.routes) { - this.routes[routeId].sort((a, b) => a.stopTimes[0].departureTime - b.stopTimes[0].departureTime); - } + this.routes = routes; + this.routeStops = routeStops; + this.stopToRoutes = stopToRoutes; } - /** - * Sets the penalty multiplier for walking (default is 1). - * @param penalty - The multiplier for walking duration cost. - */ - public setWalkingPenalty(penalty: number) { - this.walkingPenalty = penalty; + static build(trips: Trip[], interchange: Interchange): McRaptorIndex { + const { routes, routeStops, stopToRoutes } = buildRouteIndices(trips); + return new McRaptorIndex(trips, interchange, routes, routeStops, stopToRoutes); } - /** - * Executes the McRAPTOR algorithm to find all non-dominated paths to the destination. - * @param origin - The starting Stop ID. - * @param destination - The destination Stop ID. - * @param departureTime - The time of departure. - * @returns A Bag containing Pareto-optimal labels for the destination. - */ - public run(origin: StopID, destination: StopID, departureTime: Time): Bag { + run( + origin: StopID, + destination: StopID, + departureTime: Time, + baseTransfers: TransfersByOrigin, + overlay?: McRaptorQueryOverlay, + walkingPenalty = 1 + ): Bag { const rounds = 8; const bags: Record[] = []; + const transfers = mergeTransfersWithOverlay(baseTransfers, overlay); + const getTransfers = (stop: StopID) => resolveTransfers(stop, transfers); bags[0] = {}; - for (const stop of this.stops) bags[0][stop] = new Bag(); - if (!bags[0][destination]) bags[0][destination] = new Bag(); - if (!bags[0][origin]) bags[0][origin] = new Bag(); const startLabel = new Label(departureTime, 0, 0, null, null, null, origin, departureTime, -1); bags[0][origin].add(startLabel); - let markedStops = new Set(); markedStops.add(origin); @@ -117,11 +168,10 @@ export class McRaptorAlgorithm { const stop = origin; const stopBag = bags[0][stop]; if (stopBag && !stopBag.isEmpty()) { - const transfers = this.transfers[stop] || []; - for (const transfer of transfers) { + for (const transfer of getTransfers(stop)) { const dest = transfer.destination; const walkTime = transfer.duration; - const walkCost = walkTime * this.walkingPenalty; + const walkCost = walkTime * walkingPenalty; if (!bags[0][dest]) bags[0][dest] = new Bag(); @@ -156,17 +206,15 @@ export class McRaptorAlgorithm { const routesToVisit = new Set(); for (const stop of markedStops) { - for (const [routeId, stops] of Object.entries(this.routeStops)) { - if (stops.includes(stop)) { - routesToVisit.add(routeId); - } + const routeIds = this.stopToRoutes[stop]; + if (!routeIds) continue; + for (const routeId of routeIds) { + routesToVisit.add(routeId); } } const newMarkedStops = new Set(); - if (!bags[k][destination]) bags[k][destination] = new Bag(); - for (const routeId of routesToVisit) { const stops = this.routeStops[routeId]; const trips = this.routes[routeId]; @@ -203,21 +251,21 @@ export class McRaptorAlgorithm { if (prevBag) { for (const label of prevBag.labels) { const buffer = this.interchange[stop] || 0; - const catchTrip = this.findEarliestTrip(trips, i, label.arrivalTime + buffer); + const catchTrip = findEarliestTrip(trips, i, label.arrivalTime + buffer); if (catchTrip) { if (catchTrip.stopTimes[i].pickUp === false) continue; - const departureTime = catchTrip.stopTimes[i].departureTime; + const tripDepartureTime = catchTrip.stopTimes[i].departureTime; const onBoardLabel = new Label( - departureTime, + tripDepartureTime, label.walkingDistance, label.transferCount + 1, label, catchTrip, null, stop, - departureTime, + tripDepartureTime, i ); routeBag.add(onBoardLabel); @@ -233,12 +281,10 @@ export class McRaptorAlgorithm { const stopBag = bags[k][stop]; if (!stopBag || stopBag.isEmpty()) continue; - const transfers = this.transfers[stop] || []; - - for (const transfer of transfers) { + for (const transfer of getTransfers(stop)) { const dest = transfer.destination; const walkTime = transfer.duration; - const walkCost = walkTime * this.walkingPenalty; + const walkCost = walkTime * walkingPenalty; if (!bags[k][dest]) bags[k][dest] = new Bag(); @@ -280,24 +326,15 @@ export class McRaptorAlgorithm { return resultBag; } - private findEarliestTrip(trips: Trip[], stopIndex: number, minTime: number): Trip | null { - for (const trip of trips) { - if (trip.stopTimes[stopIndex].departureTime >= minTime) { - return trip; - } - } - return null; - } - - /** - * Calculates optimal journeys for a specific departure time. - * @param origin - The starting Stop ID. - * @param destination - The destination Stop ID. - * @param departureTime - The exact departure time. - * @returns A list of optimal Journey objects. - */ - public getOptimizedJourneys(origin: StopID, destination: StopID, departureTime: Time): Journey[] { - const resultBag = this.run(origin, destination, departureTime); + getOptimizedJourneys( + origin: StopID, + destination: StopID, + departureTime: Time, + baseTransfers: TransfersByOrigin, + overlay?: McRaptorQueryOverlay, + walkingPenalty = 1 + ): Journey[] { + const resultBag = this.run(origin, destination, departureTime, baseTransfers, overlay, walkingPenalty); const journeys: Journey[] = []; @@ -315,32 +352,33 @@ export class McRaptorAlgorithm { return journeys; } - /** - * Finds the best journeys within a time window, filtering for Pareto optimality across all departures. - * @param origin - The starting Stop ID. - * @param destination - The destination Stop ID. - * @param startTime - The start of the departure window. - * @param range - The duration of the window to search (e.g. 3600s). - * @returns A deduplicated list of the best journeys found in the time range. - */ - public getOptimizedJourneysInRange(origin: StopID, destination: StopID, startTime: Time, range: number): Journey[] { + getOptimizedJourneysInRange( + origin: StopID, + destination: StopID, + startTime: Time, + range: number, + baseTransfers: TransfersByOrigin, + overlay?: McRaptorQueryOverlay, + walkingPenalty = 1 + ): Journey[] { const allJourneys: Journey[] = []; const endTime = startTime + range; const significantTimes = new Set(); significantTimes.add(startTime); - const startStops = [origin, ...(this.transfers[origin] || []).map(t => t.destination)]; + const mergedTransfers = mergeTransfersWithOverlay(baseTransfers, overlay); + const startStops = [origin, ...(mergedTransfers[origin] || []).map(t => t.destination)]; for (const stop of startStops) { - for (const routeId in this.routeStops) { - if (this.routeStops[routeId].includes(stop)) { - const params = this.routes[routeId]; - for (const trip of params) { - const stopTime = trip.stopTimes.find(st => st.stop === stop); - if (stopTime && stopTime.departureTime >= startTime && stopTime.departureTime <= endTime) { - significantTimes.add(stopTime.departureTime); - } + const routeIds = this.stopToRoutes[stop]; + if (!routeIds) continue; + for (const routeId of routeIds) { + const params = this.routes[routeId]; + for (const trip of params) { + const stopTime = trip.stopTimes.find(st => st.stop === stop); + if (stopTime && stopTime.departureTime >= startTime && stopTime.departureTime <= endTime) { + significantTimes.add(stopTime.departureTime); } } } @@ -349,7 +387,9 @@ export class McRaptorAlgorithm { const sortedTimes = Array.from(significantTimes).sort((a, b) => b - a); for (const depTime of sortedTimes) { - const journeys = this.getOptimizedJourneys(origin, destination, depTime); + const journeys = this.getOptimizedJourneys( + origin, destination, depTime, baseTransfers, overlay, walkingPenalty + ); for (const j of journeys) { if (j.legs.length === 0) continue; allJourneys.push(j); @@ -417,7 +457,6 @@ export class McRaptorAlgorithm { const trip = current.trip; const boardStop = parent.stop!; const alightStop = current.stop!; - if (!parent.trip) { current = parent; @@ -464,4 +503,32 @@ export class McRaptorAlgorithm { return path; } -} \ No newline at end of file +} + +/** Build per-query transfer overlay from walking access results. */ +export function buildQueryOverlay( + walksFromOrigin: { stopId: string; duration: number }[], + walksToDest: { stopId: string; duration: number }[], + departureTime: Time +): McRaptorQueryOverlay { + const originWalks: Transfer[] = walksFromOrigin.map(walk => ({ + origin: VIRTUAL_ORIGIN, + destination: walk.stopId === 'DIRECT_WALK' ? VIRTUAL_DESTINATION : walk.stopId, + duration: walk.duration, + startTime: departureTime, + endTime: Number.MAX_SAFE_INTEGER, + })); + + const destinationWalks = new Map(); + for (const walk of walksToDest) { + destinationWalks.set(walk.stopId, { + origin: walk.stopId, + destination: VIRTUAL_DESTINATION, + duration: walk.duration, + startTime: departureTime, + endTime: Number.MAX_SAFE_INTEGER, + }); + } + + return { originWalks, destinationWalks }; +} diff --git a/src/services/graphBuilder.ts b/src/services/graphBuilder.ts index 68ac957..f6c748c 100644 --- a/src/services/graphBuilder.ts +++ b/src/services/graphBuilder.ts @@ -11,6 +11,12 @@ import * as path from 'path'; const DEFAULT_ROUTES = ["BB", "CN", "CS", "CSX", "DD", "MX", "NE", "NW", "NX", "OS", "NES", "WS", "WX"]; const DEFAULT_RIDE_ROUTES = ["3", "4", "5", "6", "22", "23", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "42", "43", "44", "45", "46", "47", "61", "62", "63", "64", "65", "66", "67", "68", "104"]; +/** Normalize bustime API stop ids to strings (The Ride uses numeric ids; Maps and === must stay consistent). */ +function stopIdKey(stpid: unknown): string | null { + if (stpid === null || stpid === undefined || stpid === '') return null; + return String(stpid); +} + /** Fetches and updates current bus positions in state. */ export async function updateBusPositions() { const buses = await mbus.fetchVehicles(DEFAULT_ROUTES); @@ -43,7 +49,7 @@ export async function initializeRoutes() { buildStopLocationMap(); buildRideStops(); - await buildWalkingTransfers(); + buildWalkingTransfers(); } catch (e) { console.error("Init Routes Failed", e); @@ -59,7 +65,8 @@ export async function rebuildGraph() { const allStopIds = new Set(); Object.values(state.cachedRoutes).forEach((patterns: any) => { patterns?.forEach((p: any) => p.pt?.forEach((pt: any) => { - if (pt.stpid) allStopIds.add(pt.stpid); + const id = stopIdKey(pt.stpid); + if (id) allStopIds.add(id); })); }); @@ -70,20 +77,23 @@ export async function rebuildGraph() { populateLookupMaps(formattedPreds); updatePredictionLookups(formattedPreds); - const trips = convertToTrips(formattedPreds); // extra stuff to update the busses for the ride const rideStopIds = new Set(); Object.values(state.cachedRideRoutes).forEach((patterns: any) => { patterns?.forEach((p: any) => p.pt?.forEach((pt: any) => { - if (pt.stpid) rideStopIds.add(pt.stpid); + const id = stopIdKey(pt.stpid); + if (id) rideStopIds.add(id); })); }); + const rawRidePreds = await rideBus.fetchPredictions(Array.from(rideStopIds), DEFAULT_RIDE_ROUTES); const formattedRidePreds = processRidePredictions(rawRidePreds); populateRideLookupMaps(formattedRidePreds); updateRideLookups(formattedRidePreds); + const trips = convertToTrips([...formattedPreds, ...formattedRidePreds]); + state.setCachedGraph({ trips, transfers: state.cachedGraph.transfers, @@ -102,15 +112,17 @@ export async function rebuildGraph() { function populateLookupMaps(preds: any[]) { Object.values(state.cachedRoutes).forEach((patterns: any) => { patterns?.forEach((p: any) => p.pt?.forEach((pt: any) => { - if (pt.stpid && pt.stpnm) { - state.stopIdToName[pt.stpid] = pt.stpnm; + const id = stopIdKey(pt.stpid); + if (id && pt.stpnm) { + state.stopIdToName[id] = pt.stpnm; } })); }); preds.forEach((trip: any) => { trip.stops.forEach((stop: any) => { - if (stop.stpid && stop.stpnm) { - state.stopIdToName[stop.stpid] = stop.stpnm; + const id = stopIdKey(stop.stpid); + if (id && stop.stpnm) { + state.stopIdToName[id] = stop.stpnm; } }); }); @@ -132,18 +144,29 @@ function populateLookupMaps(preds: any[]) { function populateRideLookupMaps(preds: any[]) { Object.values(state.cachedRideRoutes).forEach((patterns: any) => { patterns?.forEach((p: any) => p.pt?.forEach((pt: any) => { - if (pt.stpid && pt.stpnm) { - state.rideStopIdToName[pt.stpid] = pt.stpnm; + const id = stopIdKey(pt.stpid); + if (id && pt.stpnm) { + state.rideStopIdToName[id] = pt.stpnm; } })); }); preds.forEach((trip: any) => { trip.stops.forEach((stop: any) => { - if (stop.stpid && stop.stpnm) { - state.rideStopIdToName[stop.stpid] = stop.stpnm; + const id = stopIdKey(stop.stpid); + if (id && stop.stpnm) { + state.rideStopIdToName[id] = stop.stpnm; } }); }); + + preds.forEach((trip: any) => { + if (trip.tatripid && trip.stops.length > 0) { + const firstStopWithRt = trip.stops.find((s: any) => s.rt); + if (firstStopWithRt) { + state.tatripidToRt[trip.tatripid] = firstStopWithRt.rt; + } + } + }); } /** @@ -154,8 +177,9 @@ function buildStopLocationMap() { const locs: Record = {}; Object.values(state.cachedRoutes).forEach((patterns: any) => { patterns?.forEach((p: any) => p.pt?.forEach((pt: any) => { - if (pt.stpid && pt.lat) { - locs[pt.stpid] = { name: pt.stpnm, lat: parseFloat(pt.lat), lon: parseFloat(pt.lon) }; + const id = stopIdKey(pt.stpid); + if (id && pt.lat) { + locs[id] = { name: pt.stpnm, lat: parseFloat(pt.lat), lon: parseFloat(pt.lon) }; } })); }); @@ -168,41 +192,38 @@ function buildStopLocationMap() { */ function buildRideStops() { const locs: Record = {}; + const globalLocs = { ...state.cachedStopLocations }; // Clone existing mbus stops + Object.values(state.cachedRideRoutes).forEach((patterns: any) => { patterns?.forEach((p: any) => p.pt?.forEach((pt: any) => { - if (pt.stpid && pt.lat) { - locs[pt.stpid] = { name: pt.stpnm, lat: parseFloat(pt.lat), lon: parseFloat(pt.lon) }; + const id = stopIdKey(pt.stpid); + if (id && pt.lat) { + const stopData = { name: pt.stpnm, lat: parseFloat(pt.lat), lon: parseFloat(pt.lon) }; + locs[id] = stopData; + globalLocs[id] = stopData; } })); }); + state.setCachedStopLocations(globalLocs); state.setCachedRideStopLocations(locs); + // Walking first-hop queries only know stops in stopNodeMap; rebuild after merging Ride stops (numeric ids e.g. "363"). + walking.buildStopNodeMap(globalLocs); } /** - * Generates walking transfers between all stops. - * Uses the walking service to calculate durations. + * Generates sparse ULTRA-style walking transfers between stops. + * Reuses in-memory shortcuts; extends incrementally when new stops appear. */ -async function buildWalkingTransfers() { +function buildWalkingTransfers() { const stops = Object.keys(state.cachedStopLocations); stops.forEach(s => { - state.cachedGraph.transfers[s] = []; state.cachedGraph.interchange[s] = 30; }); - await walking.ensureCacheForStops(new Set(stops), state.cachedStopLocations); - - stops.forEach(origin => { - stops.forEach(dest => { - if (origin === dest) return; - const walk = walking.getCachedWalk(origin, dest); - if (walk) { - state.cachedGraph.transfers[origin].push({ - origin, destination: dest, duration: walk.duration, - startTime: 0, endTime: Number.MAX_SAFE_INTEGER - }); - } - }); - }); + if (stops.length === 0) return; + + const { transfers } = walking.buildSparseWalkingTransfers(stops); + state.cachedGraph.transfers = transfers; } /** @@ -225,14 +246,15 @@ function processPredictions(rawChunks: any[]) { if (!trip.tatripid) trip.tatripid = prd.tatripid; if (!trip.vid && prd.vid) trip.vid = prd.vid; } - // If no stop, create new stop - let stop = trip.stops.find((s: any) => s.stpid === prd.stpid); + const stpid = stopIdKey(prd.stpid); + if (!stpid) return; + let stop = trip.stops.find((s: any) => s.stpid === stpid); if (!stop) { - stop = { stpnm: prd.stpnm, stpid: prd.stpid, prdctdn: null, rt: null, rtdir: null }; + stop = { stpnm: prd.stpnm, stpid, prdctdn: null, rt: null, rtdir: null }; trip.stops.push(stop); } stop.rtdir = prd.rtdir; - stop.rt = prd.rt; + stop.rt = prd.rt != null ? String(prd.rt) : prd.rt; stop.prdctdn = prd.prdctdn === "DUE" ? "1" : prd.prdctdn; stop.prdtm = parseInt(prd.prdtm); }); @@ -248,8 +270,9 @@ function processPredictions(rawChunks: any[]) { const routeKey = routeName + rtdir; if (!routeInfoFilter[routeKey]) routeInfoFilter[routeKey] = []; for (const point of route.pt) { - if (point.typ !== "W" && point.stpid) { - routeInfoFilter[routeKey].push({ stpid: point.stpid, rtdir }); + const pid = stopIdKey(point.stpid); + if (point.typ !== "W" && pid) { + routeInfoFilter[routeKey].push({ stpid: pid, rtdir }); } } } @@ -331,7 +354,8 @@ function processPredictions(rawChunks: any[]) { const nextEntries = Object.entries(nextStops); if (nextEntries.length === 0) break; - const [nextStopId, { diff, rtdir, rtNext }] = nextEntries[0]; + const [nextStopIdRaw, { diff, rtdir, rtNext }] = nextEntries[0]; + const nextStopId = stopIdKey(nextStopIdRaw) ?? String(nextStopIdRaw); const nextPrdctdn = (parseInt(lastStop.prdctdn, 10) + diff).toString(); trip.stops.push({ @@ -351,17 +375,15 @@ function processPredictions(rawChunks: any[]) { /** - * COPIED FROM PROCESS PREDICTIONS AND MODIFIED TO WORK WITH THE RIDE - * @param rawChunks Raw API response chunks + * Same pipeline as {@link processPredictions}, but indexes and extrapolation use {@link state.cachedRideRoutes}. + * Coerces `stpid` / `rt` to strings so pattern maps match The Ride API (numeric ids). */ function processRidePredictions(rawChunks: any[]) { const formattedPredictions = rawChunks.flat().reduce((acc: any[], chunk: any) => { if (chunk['bustime-response']?.['prd']) { chunk['bustime-response']['prd'].forEach((prd: any) => { let trip = acc.find((t: any) => t.tatripid === prd.tatripid); - // If no tatripid, try to match by vid (mbus API specifics) if (!trip && prd.vid) trip = acc.find((t: any) => t.vid === prd.vid); - // If no match, create new trip if (!trip) { trip = { tatripid: prd.tatripid, vid: prd.vid, des: prd.des, stops: [] }; acc.push(trip); @@ -369,25 +391,125 @@ function processRidePredictions(rawChunks: any[]) { if (!trip.tatripid) trip.tatripid = prd.tatripid; if (!trip.vid && prd.vid) trip.vid = prd.vid; } - // If no stop, create new stop - let stop = trip.stops.find((s: any) => s.stpid === prd.stpid); + const stpid = stopIdKey(prd.stpid); + if (!stpid) return; + let stop = trip.stops.find((s: any) => s.stpid === stpid); if (!stop) { - stop = { stpnm: prd.stpnm, stpid: prd.stpid, prdctdn: null, rt: null, rtdir: null }; + stop = { stpnm: prd.stpnm, stpid, prdctdn: null, rt: null, rtdir: null }; trip.stops.push(stop); } - stop.rtdir = prd.rtdir; - stop.rt = prd.rt; + stop.rtdir = prd.rtdir != null ? String(prd.rtdir) : null; + stop.rt = prd.rt != null ? String(prd.rt) : null; stop.prdctdn = prd.prdctdn === "DUE" ? "1" : prd.prdctdn; - // console.log(prd.prdtm); - // prdtm is in format YYYYMMDD HH:MM:SS - // stop.prdtm = parseInt(prd.prdtm); - // TODO: use actual timestamp - stop.prdtm = Date.now() + (parseInt(stop.prdctdn) + 0.5) * 60 * 1000; + stop.prdtm = parseInt(prd.prdtm, 10); }); } return acc; }, []); + const routeInfoFilter: Record = {}; + for (const [routeName, routeList] of Object.entries(state.cachedRideRoutes as Record)) { + for (const route of routeList) { + const rtdir = route.rtdir; + const routeKey = routeName + rtdir; + if (!routeInfoFilter[routeKey]) routeInfoFilter[routeKey] = []; + for (const point of route.pt) { + const pid = stopIdKey(point.stpid); + if (point.typ !== "W" && pid) { + routeInfoFilter[routeKey].push({ stpid: pid, rtdir }); + } + } + } + } + + const routeStopIndexMaps = new Map>(); + for (const [routeId, stopOrder] of Object.entries(routeInfoFilter)) { + const stopIndexMap = new Map(stopOrder.map(({ stpid }, i) => [stpid, i])); + routeStopIndexMaps.set(routeId, stopIndexMap); + } + + formattedPredictions.forEach((trip: any) => { + if (trip.stops.length == 0) return; + const minPrdctdn = Math.min(...trip.stops.map((s: any) => parseInt(s.prdctdn, 10))); + const firstRoute = trip.stops.find((s: any) => parseInt(s.prdctdn, 10) === minPrdctdn)?.rt; + + if (!firstRoute) return; + + trip.stops.sort((a: any, b: any) => { + const diffTime = parseInt(a.prdctdn, 10) - parseInt(b.prdctdn, 10); + if (diffTime !== 0) return diffTime; + if (a.rt + a.rtdir !== b.rt + b.rtdir) { + if (a.rt === firstRoute) return -1; + if (b.rt === firstRoute) return 1; + return a.rt.localeCompare(b.rt); + } + const aMap = routeStopIndexMaps.get(a.rt + a.rtdir); + const bMap = routeStopIndexMaps.get(b.rt + b.rtdir); + const aIdx = aMap?.get(a.stpid) ?? Number.MAX_SAFE_INTEGER; + const bIdx = bMap?.get(b.stpid) ?? Number.MAX_SAFE_INTEGER; + return aIdx - bIdx; + }); + + for (let i = 0; i < trip.stops.length - 1; i++) { + const from = trip.stops[i]; + const to = trip.stops[i + 1]; + const diff = parseInt(to.prdctdn, 10) - parseInt(from.prdctdn, 10); + const rt = from.rt; + + const stopIndexMap = routeStopIndexMaps.get(from.rt + from.rtdir); + if (!stopIndexMap) continue; + + const fromIdx = stopIndexMap.get(from.stpid); + const toIdx = stopIndexMap.get(to.stpid); + const isValidFollowUp = ( + fromIdx !== undefined && toIdx !== undefined && + (toIdx === fromIdx + 1 || fromIdx === stopIndexMap.size - 1) + ); + if (!isValidFollowUp) continue; + + if (!state.routeTimingCache[rt]) state.routeTimingCache[rt] = {}; + const fromKey = from.stpid + (from.rtdir || ""); + if (!state.routeTimingCache[rt][fromKey]) state.routeTimingCache[rt][fromKey] = {}; + state.routeTimingCache[rt][fromKey] = { + [to.stpid]: { + diff: diff, + rtdir: to.rtdir, + rtNext: to.rt + } + }; + } + }); + + formattedPredictions.forEach((trip: any) => { + let stopsAdded = 0; + while (stopsAdded < 20 && trip.stops.length > 0) { + const lastStop = trip.stops[trip.stops.length - 1]; + const rt = lastStop.rt; + if (!rt) break; + + const fromKey = lastStop.stpid + (lastStop.rtdir || ""); + const nextStops = state.routeTimingCache[rt]?.[fromKey]; + if (!nextStops) break; + + const nextEntries = Object.entries(nextStops); + if (nextEntries.length === 0) break; + + const [nextStopIdRaw, { diff, rtdir, rtNext }] = nextEntries[0]; + const nextStopId = stopIdKey(nextStopIdRaw) ?? String(nextStopIdRaw); + const nextPrdctdn = (parseInt(lastStop.prdctdn, 10) + diff).toString(); + + trip.stops.push({ + stpnm: state.cachedStopLocations[nextStopId]?.name || nextStopId, + stpid: nextStopId, + prdctdn: nextPrdctdn, + rt: rtNext, + rtdir: rtdir, + isExtrapolated: true + }); + stopsAdded++; + } + }); + return formattedPredictions; } @@ -431,6 +553,8 @@ function updateRideLookups(preds: any[]) { preds.forEach((trip: any) => { trip.stops.forEach((stop: any) => { + if (stop.isExtrapolated) return; + const predObj = { ...stop, vid: trip.vid, tatripid: trip.tatripid, des: trip.des }; if (!state.cachedRidePredsByStopId[stop.stpid]) state.cachedRidePredsByStopId[stop.stpid] = []; @@ -465,7 +589,7 @@ function convertToTrips(preds: any[]): Trip[] { preds.forEach((p: any) => { const stopTimes: StopTime[] = p.stops.map((s: any) => ({ - stop: s.stpid, + stop: stopIdKey(s.stpid) ?? String(s.stpid), arrivalTime: currentTime + (parseInt(s.prdctdn) * 60), departureTime: currentTime + (parseInt(s.prdctdn) * 60), pickUp: true, diff --git a/src/services/journey.ts b/src/services/journey.ts index f5a0776..196c92f 100644 --- a/src/services/journey.ts +++ b/src/services/journey.ts @@ -1,15 +1,48 @@ import * as state from '../state/transitState'; import * as walking from '../walking/walkingMap'; -import { McRaptorAlgorithm, Journey, JourneyLeg } from "../raptor/McRaptorAlgorithm"; +import { + McRaptorIndex, + Journey, + JourneyLeg, + VIRTUAL_ORIGIN, + VIRTUAL_DESTINATION, + buildQueryOverlay, +} from "../raptor/McRaptorAlgorithm"; + +const MAX_JOURNEYS_RETURNED = 5; + +function queryJourneys( + walksFromOrigin: { stopId: string; duration: number }[], + walksToDest: { stopId: string; duration: number }[], + time: number, + options: { walkingPenalty?: number; range?: number } = {} +): Journey[] { + const overlay = buildQueryOverlay(walksFromOrigin, walksToDest, time); + const index = state.mcRaptorIndex + ?? McRaptorIndex.build(state.cachedGraph.trips, state.cachedGraph.interchange); + const penalty = options.walkingPenalty ?? 1; + + const journeys = options.range === undefined + ? index.getOptimizedJourneys( + VIRTUAL_ORIGIN, VIRTUAL_DESTINATION, time, + state.cachedGraph.transfers, overlay, penalty + ) + : index.getOptimizedJourneysInRange( + VIRTUAL_ORIGIN, VIRTUAL_DESTINATION, time, options.range, + state.cachedGraph.transfers, overlay, penalty + ); + + return [...journeys] + .sort((a, b) => + a.criteria.arrivalTime - b.criteria.arrivalTime || + a.criteria.walkingDistance - b.criteria.walkingDistance || + a.criteria.transferCount - b.criteria.transferCount + ) + .slice(0, MAX_JOURNEYS_RETURNED); +} /** * Plans a journey between two coordinates using the McRaptor algorithm. - * @param oLat Origin latitude - * @param oLon Origin longitude - * @param dLat Destination latitude - * @param dLon Destination longitude - * @param time Start time in seconds since midnight - * @param options Optional parameters for walking penalty and search range */ export async function planJourney( oLat: number, oLon: number, @@ -17,61 +50,9 @@ export async function planJourney( time: number, options: { walkingPenalty?: number, range?: number } ) { - const V_ORIGIN = 'VIRTUAL_ORIGIN'; - const V_DEST = 'VIRTUAL_DESTINATION'; - const walksFromOrigin = walking.getWalkingDistancesFrom(oLat, oLon, dLat, dLon); const walksToDest = walking.getWalkingDistancesFrom(dLat, dLon); - - const transferData = { ...state.cachedGraph.transfers }; - transferData[V_ORIGIN] = []; - transferData[V_DEST] = []; - - walksFromOrigin.forEach(walk => { - const dest = walk.stopId === "DIRECT_WALK" ? V_DEST : walk.stopId; - transferData[V_ORIGIN].push({ - origin: V_ORIGIN, destination: dest, - duration: walk.duration, startTime: time, endTime: Number.MAX_SAFE_INTEGER - }); - }); - - walksToDest.forEach(walk => { - transferData[walk.stopId] = [...(transferData[walk.stopId] || [])]; - transferData[walk.stopId].push({ - origin: walk.stopId, destination: V_DEST, - duration: walk.duration, startTime: time, endTime: Number.MAX_SAFE_INTEGER - }); - }); - - const requestTrips = state.cachedGraph.trips.map(trip => { - if (trip.tripId === 'VIRTUAL_ORIGIN_TRIP') { - return { - ...trip, - stopTimes: [{ stop: V_ORIGIN, arrivalTime: time, departureTime: time, pickUp: true, dropOff: true }] - }; - } - if (trip.tripId === 'VIRTUAL_DESTINATION_TRIP') { - return { - ...trip, - stopTimes: [{ stop: V_DEST, arrivalTime: time, departureTime: time, pickUp: true, dropOff: true }] - }; - } - return trip; - }); - - const mcRaptor = new McRaptorAlgorithm(requestTrips, transferData, state.cachedGraph.interchange); - mcRaptor.setWalkingPenalty(options.walkingPenalty || 1); - - const range = options.range; - const journeys = range === undefined - ? mcRaptor.getOptimizedJourneys(V_ORIGIN, V_DEST, time) - : mcRaptor.getOptimizedJourneysInRange( - V_ORIGIN, - V_DEST, - time, - range ?? 45 * 60 - ); - + const journeys = queryJourneys(walksFromOrigin, walksToDest, time, options); return processJourneys(journeys, oLat, oLon, dLat, dLon); } @@ -107,23 +88,20 @@ async function processJourneys(journeys: Journey[], oLat: number, oLon: number, } if (isWalk) { - const cached = walking.getCachedWalk(leg.origin, leg.destination); - - if (cached) { - Object.assign(formattedLeg, cached); - } else { - const l1 = leg.origin === 'VIRTUAL_ORIGIN' ? { lat: oLat, lon: oLon } : state.cachedStopLocations[leg.origin]; - const l2 = leg.destination === 'VIRTUAL_DESTINATION' ? { lat: dLat, lon: dLon } : state.cachedStopLocations[leg.destination]; - - if (l1 && l2) { - try { - const data = await walking.getWalkingResponse(l1.lat, l1.lon, l2.lat, l2.lon); - data.duration = Math.round(data.duration); - Object.assign(formattedLeg, data); - } catch (e) { - formattedLeg.path_coords = []; - } + const l1 = leg.origin === 'VIRTUAL_ORIGIN' ? { lat: oLat, lon: oLon } : state.cachedStopLocations[leg.origin]; + const l2 = leg.destination === 'VIRTUAL_DESTINATION' ? { lat: dLat, lon: dLon } : state.cachedStopLocations[leg.destination]; + + if (l1 && l2) { + try { + const data = await walking.getWalkingResponse(l1.lat, l1.lon, l2.lat, l2.lon); + data.duration = Math.round(data.duration); + Object.assign(formattedLeg, data); + } catch (e) { + console.error("Failed to generate walking path", e); + formattedLeg.path_coords = []; } + } else { + formattedLeg.path_coords = []; } } @@ -149,4 +127,4 @@ async function processJourneys(journeys: Journey[], oLat: number, oLon: number, a.arrivalTime - b.arrivalTime || a.criteria.walkingDistance - b.criteria.walkingDistance ); -} \ No newline at end of file +} diff --git a/src/state/transitState.ts b/src/state/transitState.ts index 6686a27..94ffdfd 100644 --- a/src/state/transitState.ts +++ b/src/state/transitState.ts @@ -1,4 +1,5 @@ import { Trip, TransfersByOrigin, Interchange } from "../raptor/types"; +import { McRaptorIndex } from "../raptor/McRaptorAlgorithm"; /** Current positions of all buses. */ export const curBusPositions = { buses: [] as any[] }; @@ -46,6 +47,9 @@ export let cachedGraph: { interchange: Interchange; } = { trips: [], transfers: {}, interchange: {} }; +/** Pre-built McRAPTOR route indices; rebuilt when trips change. */ +export let mcRaptorIndex: McRaptorIndex | null = null; + /** Cache of stop locations (lat/lon). */ export let cachedStopLocations: Record = {}; export let cachedRideStopLocations: Record = {}; @@ -72,6 +76,9 @@ export const validRideRoutes = new Set(); /** Updates the cached graph. */ export function setCachedGraph(newGraph: typeof cachedGraph) { cachedGraph = newGraph; + mcRaptorIndex = newGraph.trips.length > 0 + ? McRaptorIndex.build(newGraph.trips, newGraph.interchange) + : null; } /** Updates the cached stop locations. */ export function setCachedStopLocations(newLocs: typeof cachedStopLocations) { diff --git a/src/walking/contractionHierarchy.ts b/src/walking/contractionHierarchy.ts new file mode 100644 index 0000000..445a13c --- /dev/null +++ b/src/walking/contractionHierarchy.ts @@ -0,0 +1,1178 @@ +/** + * Contraction hierarchy (CH) walking router for Ann Arbor. + * + * Ported from [contraction-hierarchy-js](https://github.com/royhobbstn/contraction-hierarchy-js) (MIT). + * Used by `walkingMap.ts` for fast street-network distances and polylines when + * `src/assets/ann_arbor.ch.json` is present. + * + * ## Runtime (server) + * + * 1. `walkingMap` calls {@link loadContractionHierarchy} at startup if the CH file exists. + * 2. Coordinate queries snap to the graph via {@link nearestGraphNode} (spatial grid index). + * 3. **Batch** stop access legs use {@link queryDistancesFromOrigin} (PHAST, one-to-many). + * 4. **Point-to-point** polylines use {@link queryPath} / {@link queryDistance}. + * + * If the CH file is missing or `WALKING_USE_DIJKSTRA=true`, `walkingMap` falls back to full-graph Dijkstra. + * + * ## Offline build + * + * Regenerate the asset after `ann_arbor.graphml` changes: + * + * ```bash + * npm run build:walking-ch + * ``` + * + * Writes `src/assets/ann_arbor.ch.json` (~45MB) and `src/assets/ch-metadata.json`. + * Commit the CH file via **Git LFS** (see `.gitattributes`) so clones get fast routing without rebuilding. + * + * ## Public API + * + * | Function | Purpose | + * |----------|---------| + * | {@link loadContractionHierarchy} | Load prebuilt CH from disk | + * | {@link queryDistancesFromOrigin} | PHAST batch distances from one graph node | + * | {@link queryDistance} | Point-to-point distance | + * | {@link queryPath} | Point-to-point distance + node path | + * | {@link nearestGraphNode} | Snap lat/lon to nearest street node | + * | {@link buildWalkingChAssets} | Offline preprocessor (also invoked by `build:walking-ch`) | + */ + +import fs from 'fs'; +import path from 'path'; +import crypto from 'crypto'; +import { pathToFileURL } from 'url'; +import type { GraphMLNode, GraphMLEdge } from './types'; +import { haversine, loadMap } from './loadMap'; + +// --- min-heap (tinyqueue-style) --- + +type HeapCompare = (a: T, b: T) => number; + +interface HeapNode { + heapIndex: number; +} + +class NodeHeap { + data: T[] = []; + length = 0; + private compare: HeapCompare; + + constructor(options: { compare: HeapCompare }) { + this.compare = options.compare; + } + + push(item: T) { + this.data.push(item); + item.heapIndex = this.length; + this.length++; + this._up(this.length - 1); + } + + pop(): T | undefined { + if (this.length === 0) return undefined; + const top = this.data[0]; + this.length--; + if (this.length > 0) { + this.data[0] = this.data[this.length]; + this.data[0].heapIndex = 0; + this._down(0); + } + this.data.pop(); + return top; + } + + peek(): T | undefined { + return this.data[0]; + } + + updateItem(pos: number) { + this._down(pos); + this._up(pos); + } + + private _up(pos: number) { + const { data, compare } = this; + const item = data[pos]; + while (pos > 0) { + const parent = (pos - 1) >> 1; + const current = data[parent]; + if (compare(item, current) >= 0) break; + data[pos] = current; + current.heapIndex = pos; + pos = parent; + } + data[pos] = item; + item.heapIndex = pos; + } + + private _down(pos: number) { + const { data, compare, length } = this; + const halfLength = length >> 1; + const item = data[pos]; + while (pos < halfLength) { + let left = (pos << 1) + 1; + const right = left + 1; + let best = data[left]; + if (right < length && compare(data[right], best) < 0) { + left = right; + best = data[right]; + } + if (compare(best, item) >= 0) break; + data[pos] = best; + best.heapIndex = pos; + pos = left; + } + data[pos] = item; + item.heapIndex = pos; + } +} + +// --- search state pool --- + +interface SearchState extends HeapNode { + id: number; + dist: number; + prev?: number; + visited?: boolean; + opened: boolean; + attrs?: number; +} + +function createNodePool() { + let currentInCache = 0; + const nodeCache: SearchState[] = []; + + return { + reset() { + currentInCache = 0; + }, + createNewState(node: { id: number; dist?: number }): SearchState { + let cached = nodeCache[currentInCache]; + if (cached) { + cached.id = node.id; + cached.dist = node.dist !== undefined ? node.dist : Infinity; + cached.prev = undefined; + cached.visited = undefined; + cached.opened = false; + cached.heapIndex = -1; + cached.attrs = undefined; + } else { + cached = { + id: node.id, + dist: node.dist !== undefined ? node.dist : Infinity, + opened: false, + heapIndex: -1, + }; + nodeCache[currentInCache] = cached; + } + currentInCache++; + return cached; + }, + }; +} + +// --- contraction hierarchy graph --- + +interface ChAdjEdge { + end: number; + cost: number; + attrs: number; +} + +interface ChEdgeProperties { + _id: number | number[]; + _cost: number; + _start_index: number; + _end_index: number; + _ordered?: number[]; + [key: string]: unknown; +} + +interface PathfinderOptions { + nodes?: boolean; +} + +export interface ChQueryResult { + total_cost: number; + nodes?: string[]; +} + +interface SerializedChGraph { + _locked: boolean; + adjacency_list: ChAdjEdge[][]; + reverse_adjacency_list: ChAdjEdge[][]; + contracted_nodes?: number[]; + _nodeToIndexLookup: Record; + _edgeProperties: ChEdgeProperties[]; + _maxUncontractedEdgeIndex: number; +} + +interface PhastIncomingEdge { + from: number; + cost: number; +} + +class OrderNode implements SearchState { + score: number; + id: number; + dist = Infinity; + opened = false; + heapIndex = -1; + constructor(score: number, id: number) { + this.score = score; + this.id = id; + } +} + +export class ContractionHierarchyGraph { + debugMode = false; + adjacency_list: ChAdjEdge[][] = []; + reverse_adjacency_list: ChAdjEdge[][] = []; + contracted_nodes: number[] = []; + + _currentNodeIndex = -1; + _nodeToIndexLookup: Record = {}; + _indexToNodeLookup: Record = {}; + _currentEdgeIndex = -1; + _edgeProperties: ChEdgeProperties[] = []; + _maxUncontractedEdgeIndex = 0; + _locked = false; + + private _phastUpIncoming: PhastIncomingEdge[][] | null = null; + private _phastOrderDesc: number[] | null = null; + + private _createNodePool = createNodePool; + + addEdge( + start: string, + end: string, + properties: { _id: number; _cost: number }, + isUndirected = true + ) { + if (this._locked) throw new Error('Graph has been contracted.'); + this._addEdge(start, end, properties, isUndirected); + } + + private _addEdge( + start: string, + end: string, + edgeProperties: { _id: number; _cost: number }, + isUndirected: boolean + ) { + const startNode = String(start); + const endNode = String(end); + if (startNode === endNode) return; + + if (this._nodeToIndexLookup[startNode] == null) { + this._currentNodeIndex++; + this._nodeToIndexLookup[startNode] = this._currentNodeIndex; + this._indexToNodeLookup[this._currentNodeIndex] = startNode; + } + if (this._nodeToIndexLookup[endNode] == null) { + this._currentNodeIndex++; + this._nodeToIndexLookup[endNode] = this._currentNodeIndex; + this._indexToNodeLookup[this._currentNodeIndex] = endNode; + } + + const startNodeIndex = this._nodeToIndexLookup[startNode]; + const endNodeIndex = this._nodeToIndexLookup[endNode]; + + this._currentEdgeIndex++; + const props: ChEdgeProperties = { + ...edgeProperties, + _start_index: startNodeIndex, + _end_index: endNodeIndex, + }; + this._edgeProperties[this._currentEdgeIndex] = props; + + const obj: ChAdjEdge = { end: endNodeIndex, cost: edgeProperties._cost, attrs: this._currentEdgeIndex }; + const reverseObj: ChAdjEdge = { end: startNodeIndex, cost: edgeProperties._cost, attrs: this._currentEdgeIndex }; + + if (!this.adjacency_list[startNodeIndex]) this.adjacency_list[startNodeIndex] = []; + this.adjacency_list[startNodeIndex].push(obj); + + if (!this.reverse_adjacency_list[endNodeIndex]) this.reverse_adjacency_list[endNodeIndex] = []; + this.reverse_adjacency_list[endNodeIndex].push(reverseObj); + + if (isUndirected) { + if (!this.adjacency_list[endNodeIndex]) this.adjacency_list[endNodeIndex] = []; + this.adjacency_list[endNodeIndex].push(reverseObj); + if (!this.reverse_adjacency_list[startNodeIndex]) this.reverse_adjacency_list[startNodeIndex] = []; + this.reverse_adjacency_list[startNodeIndex].push(obj); + } + } + + private _addContractedEdge(startIndex: number, endIndex: number, properties: ChEdgeProperties) { + this._currentEdgeIndex++; + properties._start_index = startIndex; + properties._end_index = endIndex; + this._edgeProperties[this._currentEdgeIndex] = properties; + + const obj: ChAdjEdge = { end: endIndex, cost: properties._cost, attrs: this._currentEdgeIndex }; + const reverseObj: ChAdjEdge = { end: startIndex, cost: properties._cost, attrs: this._currentEdgeIndex }; + + if (!this.adjacency_list[startIndex]) this.adjacency_list[startIndex] = []; + this.adjacency_list[startIndex].push(obj); + if (!this.reverse_adjacency_list[endIndex]) this.reverse_adjacency_list[endIndex] = []; + this.reverse_adjacency_list[endIndex].push(reverseObj); + } + + contractGraph() { + if (this._locked) throw new Error('Network has already been contracted'); + this._locked = true; + this._maxUncontractedEdgeIndex = this._currentEdgeIndex; + + const finder = this._createChShortcutter(); + + const getContractedNeighborCount = (v: number) => + (this.adjacency_list[v] || []).reduce((acc, node) => { + const isContracted = this.contracted_nodes[node.end] != null ? 1 : 0; + return acc + isContracted; + }, 0); + + const getVertexScore = (v: number) => { + const shortcutCount = this._contract(v, true, finder); + const edgeCount = (this.adjacency_list[v] || []).length; + const edgeDifference = shortcutCount - edgeCount; + return edgeDifference + getContractedNeighborCount(v); + }; + + const nh = new NodeHeap({ + compare: (a, b) => a.score - b.score, + }); + + this.contracted_nodes = []; + Object.keys(this._nodeToIndexLookup).forEach(key => { + const index = this._nodeToIndexLookup[key]; + nh.push(new OrderNode(getVertexScore(index), index)); + }); + + let contractionLevel = 1; + const len = nh.length; + + while (nh.length > 0) { + if (nh.length % 50 === 0) { + if (this.debugMode) console.log(`${nh.length} / ${len}`); + this._cleanAdjList(this.adjacency_list); + this._cleanAdjList(this.reverse_adjacency_list); + } + + let foundLowest = false; + let nodeObj = nh.peek()!; + const oldScore = nodeObj.score; + + do { + const firstVertex = nodeObj.id; + const newScore = getVertexScore(firstVertex); + if (newScore > oldScore) { + nodeObj.score = newScore; + nh.updateItem(nodeObj.heapIndex); + } + nodeObj = nh.peek()!; + if (nodeObj.id === firstVertex) foundLowest = true; + } while (!foundLowest); + + const v = nh.pop()!; + this._contract(v.id, false, finder); + this.contracted_nodes[v.id] = contractionLevel; + contractionLevel++; + } + + this._cleanAdjList(this.adjacency_list); + this._cleanAdjList(this.reverse_adjacency_list); + this._arrangeContractedPaths(this.adjacency_list); + this._arrangeContractedPaths(this.reverse_adjacency_list); + + if (this.debugMode) console.log('Contraction complete'); + } + + private _arrangeContractedPaths(adjList: ChAdjEdge[][]) { + adjList.forEach((node, index) => { + node.forEach(edge => { + const startNode = index; + const simpleIds: number[] = []; + const ids: number[] = [edge.attrs]; + + while (ids.length) { + const id = ids.pop()!; + if (id <= this._maxUncontractedEdgeIndex) { + simpleIds.push(id); + } else { + const edgeId = this._edgeProperties[id]._id; + if (Array.isArray(edgeId)) ids.push(...edgeId); + } + } + + const links: Record = {}; + simpleIds.forEach(id => { + const properties = this._edgeProperties[id]; + const si = String(properties._start_index); + const ei = String(properties._end_index); + if (!links[si]) links[si] = [id]; + else links[si].push(id); + if (!links[ei]) links[ei] = [id]; + else links[ei].push(id); + }); + + const ordered: number[] = []; + let lastNode = String(startNode); + let currentEdgeId: number | null = links[lastNode]?.[0] ?? null; + + while (currentEdgeId != null) { + ordered.push(currentEdgeId); + const edgeProps: ChEdgeProperties = this._edgeProperties[currentEdgeId]; + const c1: string = String(edgeProps._start_index); + const c2: string = String(edgeProps._end_index); + const nextNode: string = c1 === lastNode ? c2 : c1; + lastNode = nextNode; + const arr: number[] | undefined = links[nextNode]; + if (!arr || arr.length === 1) break; + if (arr.length > 2) throw new Error('Too many edges at node during CH arrange'); + currentEdgeId = arr[0] === currentEdgeId ? arr[1] : arr[0]; + } + + this._edgeProperties[edge.attrs]._ordered = ordered; + }); + }); + } + + private _cleanAdjList(adjList: ChAdjEdge[][]) { + adjList.forEach((node, nodeId) => { + const fromRank = this.contracted_nodes[nodeId]; + if (fromRank == null) return; + adjList[nodeId] = node.filter(edge => { + const toRank = this.contracted_nodes[edge.end]; + if (toRank == null) return true; + return fromRank < toRank; + }); + }); + } + + private _contract( + v: number, + getCountOnly: boolean, + finder: ReturnType + ): number { + const fromConnections = (this.reverse_adjacency_list[v] || []).filter(c => !this.contracted_nodes[c.end]); + const toConnections = (this.adjacency_list[v] || []).filter(c => !this.contracted_nodes[c.end]); + let shortcutCount = 0; + + fromConnections.forEach(u => { + const dist1 = u.cost; + let maxTotal = 0; + toConnections.forEach(w => { + if (u.end === w.end) return; + const total = dist1 + w.cost; + if (total > maxTotal) maxTotal = total; + }); + if (!toConnections.length) return; + + const path = finder.runDijkstra(u.end, null, v, maxTotal); + + toConnections.forEach(w => { + if (u.end === w.end) return; + const dist2 = w.cost; + const total = dist1 + dist2; + const dijkstra = path.distances[w.end] ?? Infinity; + if (total < dijkstra) { + shortcutCount++; + if (!getCountOnly) { + this._addContractedEdge(u.end, w.end, { + _cost: total, + _id: [u.attrs, w.attrs], + _start_index: u.end, + _end_index: w.end, + }); + } + } + }); + }); + + return shortcutCount; + } + + private _createChShortcutter() { + const pool = this._createNodePool(); + const adjacencyList = this.adjacency_list; + + return { + runDijkstra: ( + startIndex: number, + endIndex: number | null, + vertex: number, + total: number + ) => { + pool.reset(); + const nodeState: (SearchState | undefined)[] = []; + const distances: Record = {}; + const openSet = new NodeHeap({ compare: (a, b) => a.dist - b.dist }); + + let current: SearchState | undefined = pool.createNewState({ id: startIndex, dist: 0 }); + nodeState[startIndex] = current; + current.opened = true; + distances[current.id] = 0; + + if (startIndex === endIndex) current = undefined; + + while (current) { + (adjacencyList[current.id] || []) + .filter(edge => edge.end !== vertex) + .forEach(edge => { + let node = nodeState[edge.end]; + if (!node) { + node = pool.createNewState({ id: edge.end }); + nodeState[edge.end] = node; + } + if (node.visited) return; + if (!node.opened) { + openSet.push(node); + node.opened = true; + } + const proposed = current!.dist + edge.cost; + if (proposed >= node.dist) return; + node.dist = proposed; + distances[node.id] = proposed; + node.prev = current!.id; + openSet.updateItem(node.heapIndex); + }); + + current.visited = true; + const settledAmt = current.dist; + current = openSet.pop(); + if (current && endIndex != null && current.id === endIndex) break; + if (settledAmt > total) break; + } + + return { distances, nodeState }; + }, + }; + } + + createPathfinder(options?: PathfinderOptions) { + const adjacencyList = this.adjacency_list; + const reverseAdjacencyList = this.reverse_adjacency_list; + const edgeProperties = this._edgeProperties; + const pool = this._createNodePool(); + const nodeToIndexLookup = this._nodeToIndexLookup; + const indexToNodeLookup = this._indexToNodeLookup; + const opts = options ?? {}; + + const queryContractionHierarchy = (start: string, end: string): ChQueryResult => { + pool.reset(); + const startIndex = nodeToIndexLookup[String(start)]; + const endIndex = nodeToIndexLookup[String(end)]; + if (startIndex == null || endIndex == null) { + return { total_cost: Infinity }; + } + + const forwardNodeState: (SearchState | undefined)[] = []; + const backwardNodeState: (SearchState | undefined)[] = []; + const forwardDistances: Record = {}; + const backwardDistances: Record = {}; + + let currentStart = pool.createNewState({ id: startIndex, dist: 0 }); + forwardNodeState[startIndex] = currentStart; + currentStart.opened = true; + forwardDistances[currentStart.id] = 0; + + let currentEnd = pool.createNewState({ id: endIndex, dist: 0 }); + backwardNodeState[endIndex] = currentEnd; + currentEnd.opened = true; + backwardDistances[currentEnd.id] = 0; + + let tentativeShortest = Infinity; + let tentativeShortestNode: number | null = null; + + function* doDijkstra( + adj: ChAdjEdge[][], + initial: SearchState, + nodeState: (SearchState | undefined)[], + distances: Record, + reverseDistances: Record + ) { + const openSet = new NodeHeap({ compare: (a, b) => a.dist - b.dist }); + let current: SearchState | undefined = initial; + + while (current) { + (adj[current.id] || []).forEach(edge => { + let node = nodeState[edge.end]; + if (!node) { + node = pool.createNewState({ id: edge.end }); + node.attrs = edge.attrs; + nodeState[edge.end] = node; + } + if (node.visited) return; + if (!node.opened) { + openSet.push(node); + node.opened = true; + } + const proposed = current!.dist + edge.cost; + if (proposed >= node.dist) return; + node.dist = proposed; + distances[node.id] = proposed; + node.attrs = edge.attrs; + node.prev = current!.id; + openSet.updateItem(node.heapIndex); + + const reverseDist = reverseDistances[edge.end]; + if (reverseDist >= 0) { + const pathLen = proposed + reverseDist; + if (tentativeShortest > pathLen) { + tentativeShortest = pathLen; + tentativeShortestNode = edge.end; + } + } + }); + current.visited = true; + current = openSet.pop(); + if (current) yield current; + } + } + + if (startIndex !== endIndex) { + const searchForward = doDijkstra( + adjacencyList, currentStart, forwardNodeState, forwardDistances, backwardDistances + ); + const searchBackward = doDijkstra( + reverseAdjacencyList, currentEnd, backwardNodeState, backwardDistances, forwardDistances + ); + let forwardDone = false; + let backwardDone = false; + let sf = searchForward.next(); + let sb = searchBackward.next(); + + do { + if (!forwardDone) { + sf = searchForward.next(); + if (sf.done) forwardDone = true; + } + if (!backwardDone) { + sb = searchBackward.next(); + if (sb.done) backwardDone = true; + } + } while ( + (sf.value && forwardDistances[sf.value.id] < tentativeShortest) || + (sb.value && backwardDistances[sb.value.id] < tentativeShortest) + ); + } else { + tentativeShortest = 0; + tentativeShortestNode = startIndex; + } + + const result: ChQueryResult = { + total_cost: tentativeShortest !== Infinity ? tentativeShortest : Infinity, + }; + + if (opts.nodes && tentativeShortestNode != null && tentativeShortest !== Infinity) { + result.nodes = this._buildNodeList( + edgeProperties, forwardNodeState, backwardNodeState, + tentativeShortestNode, startIndex, indexToNodeLookup + ); + } + + return result; + }; + + return { queryContractionHierarchy: queryContractionHierarchy.bind(this) }; + } + + private _buildNodeList( + edgeProperties: ChEdgeProperties[], + forwardNodeState: (SearchState | undefined)[], + backwardNodeState: (SearchState | undefined)[], + meetingNode: number, + startNode: number, + indexToNodeLookup: Record + ): string[] { + const pathway: { id: number; direction: 'f' | 'b' }[] = []; + const nodeList: number[] = [meetingNode]; + + let currentForward = forwardNodeState[meetingNode]; + let currentBackward = backwardNodeState[meetingNode]; + + while (currentForward && currentForward.attrs != null) { + pathway.push({ id: currentForward.attrs, direction: 'f' }); + nodeList.push(currentForward.prev!); + currentForward = forwardNodeState[currentForward.prev!]; + } + pathway.reverse(); + nodeList.reverse(); + + while (currentBackward && currentBackward.attrs != null) { + pathway.push({ id: currentBackward.attrs, direction: 'b' }); + nodeList.push(currentBackward.prev!); + currentBackward = backwardNodeState[currentBackward.prev!]; + } + + let node = startNode; + const ordered = pathway.map(p => { + const start = p.direction === 'f' + ? edgeProperties[p.id]._start_index + : edgeProperties[p.id]._end_index; + const end = p.direction === 'f' + ? edgeProperties[p.id]._end_index + : edgeProperties[p.id]._start_index; + const props = [...(edgeProperties[p.id]._ordered ?? [])]; + if (node !== start) { + props.reverse(); + node = start; + } else { + node = end; + } + return props; + }); + + const flattened = ordered.flat(); + const nodes: string[] = []; + let currentNode = startNode; + nodes.push(indexToNodeLookup[currentNode]); + + for (const edgeIndex of flattened) { + const edge = edgeProperties[edgeIndex]; + if (currentNode === edge._start_index) currentNode = edge._end_index; + else if (currentNode === edge._end_index) currentNode = edge._start_index; + else currentNode = edge._end_index; + nodes.push(indexToNodeLookup[currentNode]); + } + + return nodes; + } + + /** PHAST: one upward Dijkstra + linear downward scan (one-to-many / one-to-all on CH). */ + queryPhastFromIndex(origin: number, targets?: Set): Map { + this._ensurePhastIndex(); + const n = this._currentNodeIndex + 1; + const upAdj = this.adjacency_list; + const upIncoming = this._phastUpIncoming!; + const orderDesc = this._phastOrderDesc!; + + const dist = new Float64Array(n); + dist.fill(Infinity); + dist[origin] = 0; + + const openSet = new NodeHeap({ compare: (a, b) => a.dist - b.dist }); + const pool = createNodePool(); + pool.reset(); + const nodeState: (SearchState | undefined)[] = []; + + let current: SearchState | undefined = pool.createNewState({ id: origin, dist: 0 }); + nodeState[origin] = current; + current.opened = true; + openSet.push(current); + + while (current) { + const settled = current.dist; + if (settled > dist[current.id]) { + current = openSet.pop(); + continue; + } + for (const edge of upAdj[current.id] || []) { + const proposed = settled + edge.cost; + if (proposed >= dist[edge.end]) continue; + dist[edge.end] = proposed; + + let node = nodeState[edge.end]; + if (!node) { + node = pool.createNewState({ id: edge.end, dist: proposed }); + nodeState[edge.end] = node; + node.opened = true; + openSet.push(node); + } else { + node.dist = proposed; + openSet.updateItem(node.heapIndex); + } + } + current = openSet.pop(); + } + + for (const v of orderDesc) { + const dv = dist[v]; + if (!Number.isFinite(dv)) continue; + for (const { from: w, cost } of upIncoming[v]) { + const proposed = dv + cost; + if (proposed < dist[w]) dist[w] = proposed; + } + } + + const out = new Map(); + if (targets && targets.size > 0) { + for (const t of targets) { + const d = dist[t]; + if (Number.isFinite(d)) out.set(t, d); + } + } else { + for (let i = 0; i < n; i++) { + const d = dist[i]; + if (Number.isFinite(d)) out.set(i, d); + } + } + return out; + } + + private _ensurePhastIndex() { + if (this._phastUpIncoming && this._phastOrderDesc) return; + + const n = this._currentNodeIndex + 1; + const upAdj = this.adjacency_list; + const ranks = this._nodeRanks(n, upAdj); + + const upIncoming: PhastIncomingEdge[][] = Array.from({ length: n }, () => []); + for (let u = 0; u < n; u++) { + for (const edge of upAdj[u] || []) { + upIncoming[edge.end].push({ from: u, cost: edge.cost }); + } + } + + const orderDesc = Array.from({ length: n }, (_, i) => i).sort((a, b) => ranks[b] - ranks[a]); + + this._phastUpIncoming = upIncoming; + this._phastOrderDesc = orderDesc; + } + + private _nodeRanks(n: number, upAdj: ChAdjEdge[][]): Uint32Array { + if (this.contracted_nodes.length > 0) { + const ranks = new Uint32Array(n); + for (let i = 0; i < n; i++) { + ranks[i] = this.contracted_nodes[i] ?? 0; + } + return ranks; + } + + const inDeg = new Uint32Array(n); + for (let u = 0; u < n; u++) { + for (const edge of upAdj[u] || []) { + inDeg[edge.end]++; + } + } + + const ranks = new Uint32Array(n); + const queue: number[] = []; + for (let i = 0; i < n; i++) { + if (inDeg[i] === 0) queue.push(i); + } + + let r = 0; + let seen = 0; + while (queue.length > 0) { + const u = queue.shift()!; + ranks[u] = r++; + seen++; + for (const edge of upAdj[u] || []) { + if (--inDeg[edge.end] === 0) queue.push(edge.end); + } + } + + if (seen !== n) { + for (let i = 0; i < n; i++) ranks[i] = i; + } + return ranks; + } + + saveCH(): string { + if (!this._locked) throw new Error('Save CH only after contraction'); + const data: SerializedChGraph = { + _locked: this._locked, + adjacency_list: this.adjacency_list, + reverse_adjacency_list: this.reverse_adjacency_list, + contracted_nodes: this.contracted_nodes, + _nodeToIndexLookup: this._nodeToIndexLookup, + _edgeProperties: this._edgeProperties, + _maxUncontractedEdgeIndex: this._maxUncontractedEdgeIndex, + }; + return JSON.stringify(data); + } + + loadCH(json: string | SerializedChGraph) { + const parsed: SerializedChGraph = typeof json === 'string' ? JSON.parse(json) : json; + this._locked = parsed._locked; + this.adjacency_list = parsed.adjacency_list; + this.reverse_adjacency_list = parsed.reverse_adjacency_list; + this.contracted_nodes = parsed.contracted_nodes ?? []; + this._nodeToIndexLookup = parsed._nodeToIndexLookup; + this._edgeProperties = parsed._edgeProperties; + this._maxUncontractedEdgeIndex = parsed._maxUncontractedEdgeIndex; + this._indexToNodeLookup = {}; + for (const [node, index] of Object.entries(this._nodeToIndexLookup)) { + this._indexToNodeLookup[Number(index)] = node; + } + this._currentEdgeIndex = this._edgeProperties.length - 1; + this._currentNodeIndex = Object.keys(this._indexToNodeLookup).length - 1; + this._phastUpIncoming = null; + this._phastOrderDesc = null; + } + + get nodeCount() { + return Object.keys(this._nodeToIndexLookup).length; + } +} + +/** Build an uncontracted CH graph from a walking adjacency list (GraphML node string ids). */ +export function buildGraphFromAdjacency( + adjacency: Map, + options?: { debugMode?: boolean } +): ContractionHierarchyGraph { + const graph = new ContractionHierarchyGraph(); + graph.debugMode = options?.debugMode ?? false; + + const directedMin = new Map(); + for (const [from, edges] of adjacency) { + for (const edge of edges) { + const key = `${from}|${edge.to}`; + const prev = directedMin.get(key); + if (prev == null || edge.dist < prev) { + directedMin.set(key, edge.dist); + } + } + } + + const undirectedMin = new Map(); + for (const [key, cost] of directedMin) { + const [a, b] = key.split('|'); + const pairKey = a < b ? `${a}|${b}` : `${b}|${a}`; + const prev = undirectedMin.get(pairKey); + if (prev == null || cost < prev.cost) { + undirectedMin.set(pairKey, { a, b, cost }); + } + } + + let edgeId = 1; + for (const { a, b, cost } of undirectedMin.values()) { + graph.addEdge(a, b, { _id: edgeId++, _cost: cost }, true); + } + + return graph; +} + +// --- runtime loader / query API --- + +const CH_FILE = path.resolve(process.cwd(), 'src/assets/ann_arbor.ch.json'); +const CH_META_FILE = path.resolve(process.cwd(), 'src/assets/ch-metadata.json'); +const GRAPHML_FILE = path.resolve(process.cwd(), 'src/assets/ann_arbor.graphml'); + +let chGraph: ContractionHierarchyGraph | null = null; +let pathfinder: ReturnType | null = null; + +export function getChFilePath() { + return CH_FILE; +} + +/** True after a successful {@link loadContractionHierarchy}. */ +export function isChLoaded() { + return chGraph != null && pathfinder != null; +} + +/** + * Load `src/assets/ann_arbor.ch.json` into memory. Call once at startup. + * @throws If the CH file is missing (run `npm run build:walking-ch` or pull Git LFS). + */ +export function loadContractionHierarchy(): void { + if (!fs.existsSync(CH_FILE)) { + throw new Error( + `Missing contraction hierarchy at ${CH_FILE}. Run: npm run build:walking-ch` + ); + } + + const graph = new ContractionHierarchyGraph(); + graph.loadCH(fs.readFileSync(CH_FILE, 'utf8')); + chGraph = graph; + pathfinder = graph.createPathfinder({ nodes: true }); + + if (fs.existsSync(CH_META_FILE) && fs.existsSync(GRAPHML_FILE)) { + try { + const meta = JSON.parse(fs.readFileSync(CH_META_FILE, 'utf8')); + const hash = crypto.createHash('sha256').update(fs.readFileSync(GRAPHML_FILE)).digest('hex'); + if (meta.graphmlSha256 && meta.graphmlSha256 !== hash) { + console.warn( + '[CH] ann_arbor.ch.json may be stale — graphml hash differs from ch-metadata.json. Re-run npm run build:walking-ch' + ); + } + } catch { + /* ignore metadata read errors */ + } + } + + console.log(`[CH] Loaded contraction hierarchy (${graph.nodeCount} nodes)`); +} + +/** PHAST: one origin graph node → many targets (used for McRaptor walk-access batches). */ +export function queryDistancesFromOrigin( + startNodeId: string, + targetNodeIds: Iterable +): Map | null { + if (!chGraph) return null; + const startIdx = chGraph._nodeToIndexLookup[String(startNodeId)]; + if (startIdx == null) return null; + + const targetIdx = new Set(); + for (const tid of targetNodeIds) { + const idx = chGraph._nodeToIndexLookup[String(tid)]; + if (idx != null) targetIdx.add(idx); + } + + const byIdx = chGraph.queryPhastFromIndex(startIdx, targetIdx); + const out = new Map(); + for (const [idx, d] of byIdx) { + const nodeId = chGraph._indexToNodeLookup[idx]; + if (nodeId) out.set(nodeId, d); + } + return out; +} + +/** Shortest-path distance in meters between two graph node IDs, or null if unreachable. */ +export function queryDistance(startNodeId: string, endNodeId: string): number | null { + if (!pathfinder) return null; + const result = pathfinder.queryContractionHierarchy(startNodeId, endNodeId); + if (!Number.isFinite(result.total_cost) || result.total_cost === Infinity) return null; + return result.total_cost; +} + +/** Shortest path between two graph nodes (distance + contracted node sequence). */ +export function queryPath( + startNodeId: string, + endNodeId: string +): { distance: number; nodeIds: string[] } | null { + if (!pathfinder) return null; + const result = pathfinder.queryContractionHierarchy(startNodeId, endNodeId); + if (!Number.isFinite(result.total_cost) || result.total_cost === Infinity || !result.nodes?.length) { + return null; + } + return { distance: result.total_cost, nodeIds: result.nodes }; +} + +/** ~200m grid cells for fast nearest-node lookup (full 51k scan was ~20ms per call). */ +const NEAREST_GRID_DEG = 0.002; +let nearestNodeGrid: Map | null = null; +let nearestNodeGridSize = 0; + +/** Build spatial grid index for {@link nearestGraphNode}. Call when graph nodes change. */ +export function buildNearestNodeIndex(nodes: Map) { + const grid = new Map(); + for (const n of nodes.values()) { + const key = `${Math.floor(n.lat / NEAREST_GRID_DEG)}|${Math.floor(n.lon / NEAREST_GRID_DEG)}`; + const bucket = grid.get(key); + if (bucket) bucket.push(n); + else grid.set(key, [n]); + } + nearestNodeGrid = grid; + nearestNodeGridSize = nodes.size; +} + +/** Snap coordinates to the nearest walking-graph node (haversine distance to node center). */ +export function nearestGraphNode( + nodes: Map, + lat: number, + lon: number +): { id: string; dist: number } | null { + if (!nearestNodeGrid || nearestNodeGridSize !== nodes.size) { + buildNearestNodeIndex(nodes); + } + + const grid = nearestNodeGrid!; + const cx = Math.floor(lat / NEAREST_GRID_DEG); + const cy = Math.floor(lon / NEAREST_GRID_DEG); + const cellMeters = NEAREST_GRID_DEG * 111_000; + + let bestId: string | null = null; + let bestDist = Infinity; + + for (let ring = 0; ring < 40; ring++) { + for (let dx = -ring; dx <= ring; dx++) { + for (let dy = -ring; dy <= ring; dy++) { + if (ring > 0 && Math.abs(dx) !== ring && Math.abs(dy) !== ring) continue; + const bucket = grid.get(`${cx + dx}|${cy + dy}`); + if (!bucket) continue; + for (const n of bucket) { + const d = haversine(lat, lon, n.lat, n.lon); + if (d < bestDist) { + bestDist = d; + bestId = n.id; + } + } + } + } + if (bestId != null && bestDist <= ring * cellMeters) break; + } + + return bestId ? { id: bestId, dist: bestDist } : null; +} + +export function stitchPathCoords( + pathIds: string[], + graphNodes: Map, + graphAdjacency: Map, + originLat: number, + originLon: number, + destLat: number, + destLon: number +): { lat: number; lon: number }[] { + const pathCoords: { lat: number; lon: number }[] = [{ lat: originLat, lon: originLon }]; + + if (pathIds.length > 0) { + const startNode = graphNodes.get(pathIds[0]); + if (startNode) pathCoords.push({ lat: startNode.lat, lon: startNode.lon }); + + for (let i = 0; i < pathIds.length - 1; i++) { + const currId = pathIds[i]; + const nextId = pathIds[i + 1]; + const edge = graphAdjacency.get(currId)?.find(e => e.to === nextId); + + if (edge?.geometry && edge.geometry.length > 0) { + for (let k = 1; k < edge.geometry.length; k++) { + pathCoords.push(edge.geometry[k]); + } + } else { + const nextNode = graphNodes.get(nextId); + if (nextNode) pathCoords.push({ lat: nextNode.lat, lon: nextNode.lon }); + } + } + } + + pathCoords.push({ lat: destLat, lon: destLon }); + return pathCoords; +} + +// --- offline preprocessor --- + +/** + * Build CH from `ann_arbor.graphml` and write `ann_arbor.ch.json` + `ch-metadata.json`. + * Invoked by `npm run build:walking-ch` (~minutes, high memory). + */ +export async function buildWalkingChAssets(): Promise { + if (!fs.existsSync(GRAPHML_FILE)) { + console.error(`GraphML not found: ${GRAPHML_FILE}`); + process.exit(1); + } + + console.log('Loading GraphML...'); + const { nodes, graph } = loadMap(); + console.log(`Nodes: ${nodes.size}, building CH graph...`); + + const chGraphBuilt = buildGraphFromAdjacency(graph, { debugMode: true }); + console.log(`CH graph nodes: ${chGraphBuilt.nodeCount}`); + console.log('Contracting — this may take several minutes...'); + const t0 = performance.now(); + chGraphBuilt.contractGraph(); + console.log(`Contraction finished in ${((performance.now() - t0) / 1000).toFixed(1)}s`); + + const serialized = chGraphBuilt.saveCH(); + fs.writeFileSync(CH_FILE, serialized); + console.log(`Wrote ${CH_FILE} (${(serialized.length / 1e6).toFixed(1)} MB)`); + + const graphmlSha256 = crypto.createHash('sha256').update(fs.readFileSync(GRAPHML_FILE)).digest('hex'); + const meta = { + graphmlPath: 'src/assets/ann_arbor.graphml', + graphmlSha256, + nodeCount: nodes.size, + builtAt: new Date().toISOString(), + chImplementation: 'src/walking/contractionHierarchy.ts', + }; + fs.writeFileSync(CH_META_FILE, JSON.stringify(meta, null, 2)); + console.log(`Wrote ${CH_META_FILE}`); +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + buildWalkingChAssets().catch(err => { + console.error(err); + process.exit(1); + }); +} diff --git a/src/walking/types.ts b/src/walking/types.ts index dfffdbd..35c2306 100644 --- a/src/walking/types.ts +++ b/src/walking/types.ts @@ -21,17 +21,3 @@ export type GraphMLEdge = { /** Detailed geometry points (WKT) for rendering curved paths. */ geometry?: { lat: number, lon: number }[] }; - -/** - * Definition for a navigation landmark used in the ALT heuristic algorithm. - */ -export type LandmarkDef = { - /** Display name of the landmark. */ - name: string; - /** Latitude coordinate. */ - lat: number; - /** Longitude coordinate. */ - lon: number; - /** The Graph Node ID nearest to this landmark (computed at runtime). */ - nodeId?: string; -}; \ No newline at end of file diff --git a/src/walking/walkingMap.ts b/src/walking/walkingMap.ts index b105667..9a7fd24 100644 --- a/src/walking/walkingMap.ts +++ b/src/walking/walkingMap.ts @@ -1,94 +1,120 @@ -import fs from 'fs'; -import path from 'path'; -import { writeFileSync, readFileSync, existsSync } from "fs"; -import { GraphMLNode, GraphMLEdge, LandmarkDef } from './types'; +import crypto from 'crypto'; +import { existsSync, readFileSync, writeFileSync } from 'fs'; +import { GraphMLNode, GraphMLEdge } from './types'; +import { TransfersByOrigin } from '../raptor/types'; import { haversine, loadMap } from './loadMap'; -import { LRUCache } from 'lru-cache'; +import { LRUCache } from 'lru-cache'; +import * as chRouter from './contractionHierarchy'; +import { + StopWalkMeters, + transitiveReductionShortcuts, + shortcutsToTransfers, + countStopWalkEdges, +} from './walkingShortcuts'; /** * Standard response for a single point-to-point walking query. */ export interface WalkingResponse { - /** Walking duration in seconds. */ duration: number; - /** Walking distance in meters. */ distance: number; - /** Ordered list of coordinates representing the walking path geometry. */ path_coords: { lat: number, lon: number }[]; } -/** - * Result of a batch query from a single origin node to multiple destinations. - */ -export interface BatchWalkingResult { - /** The ID of the street node closest to the origin coordinates. */ - nearestNodeId: string; - /** The straight-line distance from the origin coordinates to the street node. */ - distanceToNode: number; - /** A map of NodeID -> Distance (in meters) for all reachable nodes. */ - nodeDistances: Map; -} - -const CACHE_FILE = path.resolve(process.cwd(), 'src/assets/landmark_dist.json'); const WALKING_SPEED_M_S = 5000 / 3600; -const WALKING_CACHE_PATH = "src/assets/walkingCache.json"; -const DEBUG = false; -const LANDMARK_DISTANCES = new Map>(); -const LANDMARKS: LandmarkDef[] = [ - { name: "Hayward/Hubbard", lat: 42.295877, lon: -83.707688999999 }, - { name: "Crisler Center", lat: 42.264356, lon: -83.744353999999 }, - { name: "Dominos Farms", lat: 42.321140000001, lon: -83.682196000001 }, - { name: "Wall St Structure", lat: 42.288482999999, lon: -83.735965 }, - { name: "Plymouth Park-and-Ride", lat: 42.30597, lon: -83.68852 }, - { name: "Oxford Housing", lat: 42.274684999999, lon: -83.726024999999 } -]; +const SHORTCUTS_CACHE_PATH = "src/assets/walking-shortcuts.json"; +/** Placeholder duration for stop pairs with no street route (legacy walkingCache behavior). */ +const UNREACHABLE_WALK_SECONDS = 60000; +const USE_DIJKSTRA = process.env.WALKING_USE_DIJKSTRA === 'true'; let graphNodes: Map = new Map(); let graphAdjacency: Map = new Map(); let stopNodeMap: Record = {}; let relevantStopNodes = new Set(); - -let walkingCache: { [key: string]: WalkingResponse } = {}; +let useChRouting = false; const networkDistanceCache = new LRUCache>({ max: 5000, }); -/** - * Finds the nearest street graph node to a given lat/lon. - * @param nodes - The map of all graph nodes. - * @param lat - Query latitude. - * @param lon - Query longitude. - * @returns Object containing the best Node ID and the distance to it. - */ -function nearestNode(nodes: Map, lat: number, lon: number) { - let bestId: string | null = null; - let bestDist = Infinity; - for (const [id, n] of nodes) { - const d = haversine(lat, lon, n.lat, n.lon); - if (d < bestDist) { - bestDist = d; - bestId = id; - } +/** Cached street path between two graph nodes (snap coords applied per request). */ +interface NodePolylineCacheEntry { + streetMeters: number; + nodeIds: string[]; + /** No street route between these nodes — use haversine on request coordinates. */ + unreachable?: boolean; +} + +const polylineCache = new LRUCache({ + max: 5000, +}); + +function nodePolylineCacheKey(startId: string, goalId: string): string { + return `${startId}::${goalId}`; +} + +function buildWalkingResponseFromNodePath( + entry: NodePolylineCacheEntry, + nearestStart: { id: string; dist: number }, + nearestGoal: { id: string; dist: number }, + originLat: number, + originLon: number, + destLat: number, + destLon: number +): WalkingResponse { + if (entry.unreachable) { + const meters = haversine(originLat, originLon, destLat, destLon); + return { + distance: meters, + duration: meters / WALKING_SPEED_M_S, + path_coords: [{ lat: originLat, lon: originLon }, { lat: destLat, lon: destLon }], + }; } - return { id: bestId, dist: bestDist }; + + const meters = entry.streetMeters + nearestStart.dist + nearestGoal.dist; + const pathCoords = chRouter.stitchPathCoords( + entry.nodeIds, graphNodes, graphAdjacency, + originLat, originLon, destLat, destLon + ); + return { + distance: meters, + duration: meters / WALKING_SPEED_M_S, + path_coords: pathCoords, + }; } -/** - * Reconstructs the path from the A* 'cameFrom' map. - */ -function reconstructPath(cameFrom: Map, current: string) { - const total = [current]; - while (cameFrom.has(current)) { - current = cameFrom.get(current)!; - total.push(current); +function resolveNodePolylinePath( + startId: string, + goalId: string +): NodePolylineCacheEntry { + const cacheKey = nodePolylineCacheKey(startId, goalId); + const cached = polylineCache.get(cacheKey); + if (cached) return cached; + + let entry: NodePolylineCacheEntry; + + const chPath = useChRouting ? chRouter.queryPath(startId, goalId) : null; + if (chPath) { + entry = { streetMeters: chPath.distance, nodeIds: chPath.nodeIds }; + } else { + const distOnStreet = queryNetworkDistance(startId, goalId); + if (distOnStreet === undefined) { + entry = { streetMeters: 0, nodeIds: [], unreachable: true }; + } else if (startId === goalId) { + entry = { streetMeters: 0, nodeIds: [startId] }; + } else { + entry = { streetMeters: distOnStreet, nodeIds: [startId, goalId] }; + } } - return total.reverse(); + + polylineCache.set(cacheKey, entry); + return entry; +} + +function nearestNode(nodes: Map, lat: number, lon: number) { + return chRouter.nearestGraphNode(nodes, lat, lon) ?? { id: null as unknown as string, dist: Infinity }; } -/** - * Minimal MinHeap implementation for priority queueing in A* and Dijkstra. - */ class MinHeap { private arr: { id: string; f: number }[] = []; push(item: { id: string; f: number }) { this.arr.push(item); this._siftUp(); } @@ -98,17 +124,10 @@ class MinHeap { private _siftDown() { let i = 0; const n = this.arr.length; while (true) { const l = 2 * i + 1; const r = 2 * i + 2; let smallest = i; if (l < n && this.arr[l].f < this.arr[smallest].f) smallest = l; if (r < n && this.arr[r].f < this.arr[smallest].f) smallest = r; if (smallest === i) break;[this.arr[i], this.arr[smallest]] = [this.arr[smallest], this.arr[i]]; i = smallest; } } } -/** - * Runs Dijkstra's algorithm from a start node to finding a specific set of targets. - * Optimized to early-exit once all targets in the optional set are found. - * @param startId - The starting Node ID. - * @param targets - (Optional) Set of Node IDs to stop searching after finding. - * @returns Map of Node ID to walking distance in meters. - */ +/** Legacy full-graph Dijkstra (WALKING_USE_DIJKSTRA=true or CH missing). */ function computeDijkstraAll(startId: string, targets?: Set): Map { const distances = new Map(); const minHeap = new MinHeap(); - let targetsFound = 0; const totalTargets = targets ? targets.size : 0; @@ -116,16 +135,14 @@ function computeDijkstraAll(startId: string, targets?: Set): Map 0) { - const { id: u, f: d } = minHeap.pop()!; + const popped = minHeap.pop()!; + const { id: u, f: d } = popped; if (d > (distances.get(u) ?? Infinity)) continue; if (targets && targets.has(u)) { targetsFound++; - if (targetsFound >= totalTargets) { - break; - } + if (targetsFound >= totalTargets) break; } - const neighbors = graphAdjacency.get(u) ?? []; - for (const edge of neighbors) { + for (const edge of graphAdjacency.get(u) ?? []) { const newDist = d + edge.dist; if (newDist < (distances.get(edge.to) ?? Infinity)) { distances.set(edge.to, newDist); @@ -136,187 +153,66 @@ function computeDijkstraAll(startId: string, targets?: Set): Map(); - const fScore = new Map(); - const inOpen = new Set(); - const cameFrom = new Map(); - let explored = 0; - - gScore.set(startId, 0); - const goalNode = graphNodes.get(goalId)!; - - const getHeuristic = (currId: string): number => { - const hHaversine = haversine( - graphNodes.get(currId)!.lat, graphNodes.get(currId)!.lon, - goalNode.lat, goalNode.lon - ); - let maxLandmarkDiff = 0; - for (const [landmarkId, distMap] of LANDMARK_DISTANCES) { - const dToNode = distMap.get(currId); - const dToGoal = distMap.get(goalId); - if (dToNode !== undefined && dToGoal !== undefined) { - const diff = Math.abs(dToNode - dToGoal); - if (diff > maxLandmarkDiff) maxLandmarkDiff = diff; - } - } - return Math.max(hHaversine, maxLandmarkDiff); - }; - - const initialH = getHeuristic(startId); - fScore.set(startId, initialH); - openHeap.push({ id: startId, f: initialH }); - inOpen.add(startId); - - while (openHeap.size() > 0) { - explored++; - const cur = openHeap.pop()!; - const current = cur.id; - - if (current === goalId) { - const pathIds = reconstructPath(cameFrom, current); - let totalDist = 0; - for (let i = 1; i < pathIds.length; i++) { - const from = pathIds[i - 1]; - const to = pathIds[i]; - const e = graphAdjacency.get(from)!.find(ed => ed.to === to); - if (e) totalDist += e.dist; - } - return { pathIds, totalDist, explored }; - } - - inOpen.delete(current); - const neighbors = graphAdjacency.get(current) ?? []; - for (const edge of neighbors) { - const tentative_g = (gScore.get(current) ?? Infinity) + edge.dist; - if (tentative_g < (gScore.get(edge.to) ?? Infinity)) { - cameFrom.set(edge.to, current); - gScore.set(edge.to, tentative_g); - - const h = getHeuristic(edge.to); - const f = tentative_g + h; - - fScore.set(edge.to, f); - if (!inOpen.has(edge.to)) { - openHeap.push({ id: edge.to, f }); - inOpen.add(edge.to); - } - } - } - } - return null; -} - -/** - * Saves precomputed landmark distances to a JSON cache file. - */ -function saveLandmarkDistances(data: Map>) { - const output: Record> = {}; - for (const [landmarkId, distances] of data) { - const distObj: Record = {}; - for (const [targetNode, dist] of distances) { - distObj[targetNode] = Number(dist.toFixed(2)); - } - output[landmarkId] = distObj; +function queryNetworkDistance(startId: string, endId: string): number | undefined { + if (useChRouting && chRouter.isChLoaded()) { + return chRouter.queryDistance(startId, endId) ?? undefined; } - fs.writeFileSync(CACHE_FILE, JSON.stringify(output)); - console.log(`Saved cache to ${CACHE_FILE}`); + const dists = computeDijkstraAll(startId, new Set([endId])); + return dists.get(endId); } -/** - * Loads precomputed landmark distances from the JSON cache file. - */ -function loadLandmarkDistances() { - const raw = fs.readFileSync(CACHE_FILE, 'utf8'); - const json = JSON.parse(raw); - for (const landmarkId in json) { - const distObj = json[landmarkId]; - const distMap = new Map(); - for (const targetNode in distObj) { - distMap.set(targetNode, distObj[targetNode]); - } - LANDMARK_DISTANCES.set(landmarkId, distMap); +function batchDistancesFromOrigin(originId: string, targetNodeIds: Iterable): Map { + const targets = new Set(targetNodeIds); + if (useChRouting && chRouter.isChLoaded()) { + const phast = chRouter.queryDistancesFromOrigin(originId, targets); + if (phast && phast.size > 0) return phast; } - console.log(`Loaded distances for ${LANDMARK_DISTANCES.size} landmarks from cache`); + return computeDijkstraAll(originId, targets); } -/** - * Initializes the graph nodes and adjacency list. - * Computes landmark distances if cache is missing. - */ function initializeGraph() { const { nodes, graph } = loadMap(); graphNodes = nodes; graphAdjacency = graph; + chRouter.buildNearestNodeIndex(nodes); console.log(`Graph initialized with ${graphNodes.size} nodes.`); - if (fs.existsSync(CACHE_FILE)) { - console.log('--- Cache Found: Loading Precomputed Distances ---'); - loadLandmarkDistances(); - } else { - console.log('--- No Cache Found: Starting Computation ---'); - const t0 = performance.now(); - - for (const lm of LANDMARKS) { - const nearest = nearestNode(graphNodes, lm.lat, lm.lon); - if (!nearest.id) continue; - - lm.nodeId = nearest.id; - console.log(`Computing Dijkstra for landmark: ${lm.name} (${lm.nodeId})`); - - const distMap = computeDijkstraAll(lm.nodeId); - LANDMARK_DISTANCES.set(lm.nodeId, distMap); + useChRouting = false; + if (!USE_DIJKSTRA && existsSync(chRouter.getChFilePath())) { + try { + chRouter.loadContractionHierarchy(); + useChRouting = true; + console.log('Walking routing: contraction hierarchy'); + } catch (e) { + console.warn('CH load failed, falling back to Dijkstra:', e); } - const t1 = performance.now(); - console.log(`Computation finished in ${(t1 - t0).toFixed(0)}ms`); - saveLandmarkDistances(LANDMARK_DISTANCES); + } else if (USE_DIJKSTRA) { + console.log('Walking routing: Dijkstra (WALKING_USE_DIJKSTRA=true)'); + } else { + console.warn( + 'Walking routing: Dijkstra (no CH file). Run npm run build:walking-ch to generate src/assets/ann_arbor.ch.json' + ); } } -/** - * Maps a list of bus stops to their nearest nodes on the street graph. - * This optimizes future lookups by caching the StopID -> NodeID relationship. - * @param locations - A map of StopID to {lat, lon}. - */ export function buildStopNodeMap(locations: Record) { if (graphNodes.size === 0) initializeGraph(); stopNodeMap = {}; relevantStopNodes.clear(); - let mappedCount = 0; Object.entries(locations).forEach(([stopId, loc]) => { const nearest = nearestNode(graphNodes, loc.lat, loc.lon); - if (nearest && nearest.id) { - stopNodeMap[stopId] = { - nodeId: nearest.id, - distToNode: nearest.dist - }; + if (nearest?.id) { + stopNodeMap[stopId] = { nodeId: nearest.id, distToNode: nearest.dist }; relevantStopNodes.add(nearest.id); - mappedCount++; } }); } -/** - * Calculates a detailed walking path between two coordinates using A*. - * Includes path geometry for rendering. - * @param originLat - Latitude of origin. - * @param originLon - Longitude of origin. - * @param destLat - Latitude of destination. - * @param destLon - Longitude of destination. - */ -export async function getWalkingResponse(originLat: number, originLon: number, destLat: number, destLon: number): Promise { - if (graphNodes.size === 0) { - console.warn("Graph not loaded. Calling initializeGraph() now."); - initializeGraph(); - } +export async function getWalkingResponse( + originLat: number, originLon: number, destLat: number, destLon: number +): Promise { + if (graphNodes.size === 0) initializeGraph(); const nearestStart = nearestNode(graphNodes, originLat, originLon); const nearestGoal = nearestNode(graphNodes, destLat, destLon); @@ -325,72 +221,13 @@ export async function getWalkingResponse(originLat: number, originLon: number, d throw new Error('No nearest graph nodes found for one or both coordinates.'); } - const result = await aStar(nearestStart.id, nearestGoal.id); - - let pathCoords: { lat: number, lon: number }[] = []; - let meters: number; - let seconds: number; - - if (!result) { - // Fallback if no path found - const directDist = haversine(originLat, originLon, destLat, destLon); - meters = directDist; - seconds = meters / WALKING_SPEED_M_S; - console.warn(`A* failed for path. Falling back to direct Haversine distance.`); - pathCoords = [{ lat: originLat, lon: originLon }, { lat: destLat, lon: destLon }]; - } else { - meters = result.totalDist + nearestStart.dist + nearestGoal.dist; - seconds = meters / WALKING_SPEED_M_S; - - if (DEBUG) { - console.log(`Path found: ${meters.toFixed(2)}m. Explored ${result.explored} nodes.`); - } - - pathCoords.push({ lat: originLat, lon: originLon }); - - if (result.pathIds.length > 0) { - // Add start node - const startNode = graphNodes.get(result.pathIds[0])!; - pathCoords.push({ lat: startNode.lat, lon: startNode.lon }); - - for (let i = 0; i < result.pathIds.length - 1; i++) { - const currId = result.pathIds[i]; - const nextId = result.pathIds[i + 1]; - - // find edge used to get to nextId - const edge = graphAdjacency.get(currId)?.find(e => e.to === nextId); - - if (edge && edge.geometry && edge.geometry.length > 0) { - for (let k = 1; k < edge.geometry.length; k++) { - pathCoords.push(edge.geometry[k]); - } - } else { - // draw line to next node - const nextNode = graphNodes.get(nextId)!; - pathCoords.push({ lat: nextNode.lat, lon: nextNode.lon }); - } - } - } - - pathCoords.push({ lat: destLat, lon: destLon }); - } - - return { - distance: meters, - duration: seconds, - path_coords: pathCoords, - }; + const entry = resolveNodePolylinePath(nearestStart.id, nearestGoal.id); + return buildWalkingResponseFromNodePath( + entry, nearestStart, nearestGoal, + originLat, originLon, destLat, destLon + ); } -/** - * Optimized method to get walking distances from an origin to ALL known bus stops. - * Optionally includes a direct walk to a specific destination point. - * Uses a single Dijkstra pass with early termination and LRU Cache. - * @param lat - Origin latitude. - * @param lon - Origin longitude. - * @param destLat - (Optional) Destination latitude for direct walk. - * @param destLon - (Optional) Destination longitude for direct walk. - */ export function getWalkingDistancesFrom( lat: number, lon: number, destLat?: number, destLon?: number @@ -403,8 +240,7 @@ export function getWalkingDistancesFrom( let destNodeId: string | undefined; let destNodeDist = 0; - - // Resolve destination node if provided + if (destLat !== undefined && destLon !== undefined) { const dNode = nearestNode(graphNodes, destLat, destLon); if (dNode.id) { @@ -413,38 +249,21 @@ export function getWalkingDistancesFrom( } } - // 2. Create the Cache Key using IDs - const cacheKey = `${nearest.id}::${destNodeId || ''}`; - - let nodeDistances = networkDistanceCache.get(cacheKey); + const cacheKey = `${nearest.id}::${destNodeId || ''}`; + let nodeDistances = networkDistanceCache.get(cacheKey); if (!nodeDistances) { - - let addedToSet = false; - if (destNodeId && !relevantStopNodes.has(destNodeId)) { - relevantStopNodes.add(destNodeId); - addedToSet = true; - } - - // Run Dijkstra - nodeDistances = computeDijkstraAll(nearest.id, relevantStopNodes); - - // Cleanup set - if (addedToSet && destNodeId) { - relevantStopNodes.delete(destNodeId); - } - + const targetIds = new Set(relevantStopNodes); + if (destNodeId) targetIds.add(destNodeId); + nodeDistances = batchDistancesFromOrigin(nearest.id, targetIds); networkDistanceCache.set(cacheKey, nodeDistances); } const results: { stopId: string, duration: number }[] = []; - // Process Bus Stops for (const [stopId, mapData] of Object.entries(stopNodeMap)) { const distOnStreet = nodeDistances.get(mapData.nodeId); - if (distOnStreet !== undefined) { - // (User->StartNode) + (StartNode->EndNode [CACHED]) + (EndNode->BusStop) const totalDist = nearest.dist + distOnStreet + mapData.distToNode; results.push({ stopId, @@ -466,80 +285,394 @@ export function getWalkingDistancesFrom( return results; } -/** - * Ensures walking paths between all provided stops are calculated and cached. - * Fetches missing paths in parallel and updates the disk cache. - * @param stopIds - Set of stop IDs to verify. - * @param stopLocations - Map of Stop ID to coordinates. - */ -export async function ensureCacheForStops( - stopIds: Set, - stopLocations: Record -): Promise { +function buildStopToStopWalkMatrix(stopIds: string[]): StopWalkMeters { + if (graphNodes.size === 0) initializeGraph(); + + const targetNodeIds = new Set(); + for (const stopId of stopIds) { + const nodeId = stopNodeMap[stopId]?.nodeId; + if (nodeId) targetNodeIds.add(nodeId); + } + + const matrix: StopWalkMeters = new Map(); + const total = stopIds.length; + + console.log(`Computing stop-to-stop walk matrix (${total} PHAST/Dijkstra origins)...`); - const fetchPromises: Promise[] = []; - let cacheWasUpdated = false; + for (let i = 0; i < stopIds.length; i++) { + const originId = stopIds[i]; + const startData = stopNodeMap[originId]; + if (!startData) continue; - console.log(`Verifying cache for ${stopIds.size} stops...`); + if (i % 10 === 0 || i === total - 1) { + const pct = ((i + 1) / total * 100).toFixed(1); + process.stdout.write(`\r Walk matrix: ${i + 1} / ${total} (${pct}%)`); + } + + const nodeDists = batchDistancesFromOrigin(startData.nodeId, targetNodeIds); + const outgoing = new Map(); + + for (const destId of stopIds) { + if (destId === originId) continue; + const endData = stopNodeMap[destId]; + if (!endData) continue; + const distOnStreet = nodeDists.get(endData.nodeId); + if (distOnStreet === undefined) continue; + const totalMeters = startData.distToNode + distOnStreet + endData.distToNode; + outgoing.set(destId, totalMeters); + } + + if (outgoing.size > 0) matrix.set(originId, outgoing); + } + + process.stdout.write('\n'); + return matrix; +} + +interface SparseWalkingTransferResult { + transfers: TransfersByOrigin; + fullEdgeCount: number; + shortcutEdgeCount: number; +} + +/** Process-lifetime cache — avoids re-reading/parsing ~180MB JSON on every initializeRoutes tick. */ +let inMemoryShortcuts: { stopIds: string[]; result: SparseWalkingTransferResult } | null = null; + +function sortedStopIds(stopIds: string[]): string[] { + return [...stopIds].sort(); +} + +function stopSetHash(stopIds: string[]): string { + return crypto.createHash('sha256').update(sortedStopIds(stopIds).join(',')).digest('hex').slice(0, 16); +} + +function stopSetsEqual(a: string[], b: string[]): boolean { + if (a.length !== b.length) return false; + for (let i = 0; i < a.length; i++) { + if (a[i] !== b[i]) return false; + } + return true; +} + +function isStopSuperset(superset: string[], subset: string[]): boolean { + const set = new Set(superset); + return subset.every(s => set.has(s)); +} + +function addedStopIds(cached: string[], current: string[]): string[] { + const set = new Set(cached); + return current.filter(s => !set.has(s)); +} + +function inferStopIdsFromTransfers(transfers: TransfersByOrigin): string[] { + const ids = new Set(); + for (const [origin, list] of Object.entries(transfers)) { + ids.add(origin); + for (const t of list) ids.add(t.destination); + } + return sortedStopIds([...ids]); +} + +function metersToWalkDuration(meters: number): number { + return Math.ceil(meters / WALKING_SPEED_M_S); +} + +function countTransferEdges(transfers: TransfersByOrigin): number { + let n = 0; + for (const list of Object.values(transfers)) { + if (list) n += list.length; + } + return n; +} + +function appendWalkTransfer( + transfers: TransfersByOrigin, + origin: string, + dest: string, + meters: number +): void { + if (!transfers[origin]) transfers[origin] = []; + transfers[origin].push({ + origin, + destination: dest, + duration: metersToWalkDuration(meters), + startTime: 0, + endTime: Number.MAX_SAFE_INTEGER, + }); +} + +function hasTransferTo(transfers: TransfersByOrigin, origin: string, dest: string): boolean { + return transfers[origin]?.some(t => t.destination === dest) ?? false; +} + +function appendUnreachableTransfer(transfers: TransfersByOrigin, origin: string, dest: string): void { + if (!transfers[origin]) transfers[origin] = []; + transfers[origin].push({ + origin, + destination: dest, + duration: UNREACHABLE_WALK_SECONDS, + startTime: 0, + endTime: Number.MAX_SAFE_INTEGER, + }); +} - for (const id1 of stopIds) { - for (const id2 of stopIds) { - if (id1 === id2) continue; +/** Add 60000s transfers for every stop pair lacking a street route (matches old walkingCache.json). */ +function fillUnreachableTransfers(transfers: TransfersByOrigin, stopIds: string[]): number { + let added = 0; + for (const originId of stopIds) { + const startData = stopNodeMap[originId]; + if (!startData) continue; + if (!transfers[originId]) transfers[originId] = []; + + for (const destId of stopIds) { + if (originId === destId) continue; + if (!stopNodeMap[destId]) continue; + if (hasTransferTo(transfers, originId, destId)) continue; + appendUnreachableTransfer(transfers, originId, destId); + added++; + } + } + return added; +} - const cacheKey = `${id1}_TO_${id2}`; +function finalizeTransferGraph(transfers: TransfersByOrigin, stopIds: string[]): number { + fillUnreachableTransfers(transfers, stopIds); + for (const stopId of stopIds) { + if (!transfers[stopId]) transfers[stopId] = []; + } + return countTransferEdges(transfers); +} - if (!walkingCache[cacheKey]) { - const loc1 = stopLocations[id1]; - const loc2 = stopLocations[id2]; +/** + * Add walking edges for newly seen stops only (PHAST rows for new origins, CH pairs existing→new). + * Preserves all direct shortest walks — no quality loss vs a full matrix rebuild. + */ +function extendWalkingTransfers( + transfers: TransfersByOrigin, + allStopIds: string[], + newStopIds: string[] +): number { + if (graphNodes.size === 0) initializeGraph(); - if (loc1 && loc2) { - cacheWasUpdated = true; + const newStopSet = new Set(newStopIds); + const targetNodeIds = new Set(); + for (const stopId of allStopIds) { + const nodeId = stopNodeMap[stopId]?.nodeId; + if (nodeId) targetNodeIds.add(nodeId); + } - const p = (async () => { - try { - const data = await getWalkingResponse(loc1.lat, loc1.lon, loc2.lat, loc2.lon); - walkingCache[cacheKey] = data; - } catch (err) { - walkingCache[cacheKey] = { duration: 60000, distance: 0, path_coords: [] }; - } - })(); + let newEdges = 0; + + for (const originId of newStopIds) { + if (!transfers[originId]) transfers[originId] = []; + const startData = stopNodeMap[originId]; + if (!startData) continue; + + const nodeDists = batchDistancesFromOrigin(startData.nodeId, targetNodeIds); + for (const destId of allStopIds) { + if (destId === originId) continue; + const endData = stopNodeMap[destId]; + if (!endData) continue; + const distOnStreet = nodeDists.get(endData.nodeId); + if (distOnStreet === undefined) { + if (!hasTransferTo(transfers, originId, destId)) { + appendUnreachableTransfer(transfers, originId, destId); + newEdges++; + } + continue; + } + appendWalkTransfer( + transfers, originId, destId, + startData.distToNode + distOnStreet + endData.distToNode + ); + newEdges++; + } + } - fetchPromises.push(p); + for (const originId of allStopIds) { + if (newStopSet.has(originId)) continue; + const startData = stopNodeMap[originId]; + if (!startData) continue; + if (!transfers[originId]) transfers[originId] = []; + + for (const destId of newStopIds) { + if (destId === originId) continue; + const endData = stopNodeMap[destId]; + if (!endData) continue; + const distOnStreet = queryNetworkDistance(startData.nodeId, endData.nodeId); + if (distOnStreet === undefined) { + if (!hasTransferTo(transfers, originId, destId)) { + appendUnreachableTransfer(transfers, originId, destId); + newEdges++; } + continue; } + appendWalkTransfer( + transfers, originId, destId, + startData.distToNode + distOnStreet + endData.distToNode + ); + newEdges++; } } - if (fetchPromises.length > 0) { - console.log(`Computing ${fetchPromises.length} new paths...`); - await Promise.all(fetchPromises); + for (const stopId of allStopIds) { + if (!transfers[stopId]) transfers[stopId] = []; } - if (cacheWasUpdated) { - try { - writeFileSync(WALKING_CACHE_PATH, JSON.stringify(walkingCache, null, 2)); - console.log(`WalkingManager: Cache updated on disk. Total entries: ${Object.keys(walkingCache).length}`); - } catch (err) { - console.error("WalkingManager: Failed to write cache to disk", err); - } + return newEdges; +} + +interface ShortcutsCacheFile { + stopIds?: string[]; + stopHash?: string; + transfers: TransfersByOrigin; + fullEdgeCount?: number; + shortcutEdgeCount: number; + builtAt?: string; +} + +function persistShortcutsCache(stopIds: string[], result: SparseWalkingTransferResult): void { + try { + writeFileSync(SHORTCUTS_CACHE_PATH, JSON.stringify({ + stopIds, + stopHash: stopSetHash(stopIds), + transfers: result.transfers, + fullEdgeCount: result.fullEdgeCount, + shortcutEdgeCount: result.shortcutEdgeCount, + builtAt: new Date().toISOString(), + }, null, 2)); + console.log(`Wrote ${SHORTCUTS_CACHE_PATH}`); + } catch (err) { + console.warn('Failed to write walking shortcuts cache:', err); + } +} + +function loadShortcutsFromDisk(): { stopIds: string[]; result: SparseWalkingTransferResult } | null { + if (!existsSync(SHORTCUTS_CACHE_PATH)) return null; + try { + const cached = JSON.parse(readFileSync(SHORTCUTS_CACHE_PATH, 'utf8')) as ShortcutsCacheFile; + if (!cached.transfers) return null; + const stopIds = cached.stopIds?.length + ? sortedStopIds(cached.stopIds) + : inferStopIdsFromTransfers(cached.transfers); + const result: SparseWalkingTransferResult = { + transfers: cached.transfers, + fullEdgeCount: cached.fullEdgeCount ?? countTransferEdges(cached.transfers), + shortcutEdgeCount: cached.shortcutEdgeCount, + }; + return { stopIds, result }; + } catch { + return null; } } +function commitShortcuts(stopIds: string[], result: SparseWalkingTransferResult): SparseWalkingTransferResult { + inMemoryShortcuts = { stopIds, result }; + return result; +} + /** - * Retrieves a cached walking path between two stops. - * @param originId - Origin Stop ID. - * @param destId - Destination Stop ID. - * @returns Cached walking data or undefined. + * ULTRA-style sparse walking transfers: full walk matrix + transitive reduction. + * Preserves optimal walking distances; McRAPTOR only relaxes non-redundant shortcut edges. + * Loaded shortcuts stay in memory; disk is cold-start only. New stops extend incrementally. */ -export function getCachedWalk(originId: string, destId: string): WalkingResponse | undefined { - return walkingCache[`${originId}_TO_${destId}`] ?? null; +export function buildSparseWalkingTransfers(stopIds: string[]): SparseWalkingTransferResult { + const sorted = sortedStopIds(stopIds); + + if (inMemoryShortcuts && stopSetsEqual(inMemoryShortcuts.stopIds, sorted)) { + return inMemoryShortcuts.result; + } + + let cachedStopIds = inMemoryShortcuts?.stopIds ?? null; + let cachedResult = inMemoryShortcuts?.result ?? null; + + if (!cachedResult) { + const fromDisk = loadShortcutsFromDisk(); + if (fromDisk) { + cachedStopIds = fromDisk.stopIds; + cachedResult = fromDisk.result; + console.log( + `Loaded walking shortcuts from disk into memory (${fromDisk.result.shortcutEdgeCount} edges, ${cachedStopIds.length} stops)` + ); + } + } + + if (cachedResult && cachedStopIds) { + const newStops = addedStopIds(cachedStopIds, sorted); + + if (newStops.length === 0 && isStopSuperset(cachedStopIds, sorted)) { + const edgeCount = finalizeTransferGraph(cachedResult.transfers, sorted); + const result: SparseWalkingTransferResult = { + transfers: cachedResult.transfers, + fullEdgeCount: edgeCount, + shortcutEdgeCount: edgeCount, + }; + return commitShortcuts(cachedStopIds, result); + } + + if (newStops.length > 0) { + if (!isStopSuperset(sorted, cachedStopIds)) { + console.warn( + `Walking shortcuts: extending ${newStops.length} new stop(s) on partial cache ` + + `(${cachedStopIds.length} cached → ${sorted.length} current).` + ); + } else { + console.log( + `Extending walking shortcuts for ${newStops.length} new stop(s) ` + + `(${cachedStopIds.length} → ${sorted.length})...` + ); + } + const transfers = cachedResult.transfers; + const addedEdges = extendWalkingTransfers(transfers, sorted, newStops); + const edgeCount = finalizeTransferGraph(transfers, sorted); + const result: SparseWalkingTransferResult = { + transfers, + fullEdgeCount: edgeCount, + shortcutEdgeCount: edgeCount, + }; + console.log(`Walking shortcuts extended: +${addedEdges} edges (${edgeCount} total)`); + persistShortcutsCache(sorted, result); + return commitShortcuts(sorted, result); + } + } + + if (cachedResult && process.env.WALKING_REBUILD_SHORTCUTS !== 'true') { + console.warn( + 'Walking shortcuts: cache present but stop set changed unexpectedly; ' + + 'using cached graph. Set WALKING_REBUILD_SHORTCUTS=true to force full rebuild.' + ); + const edgeCount = finalizeTransferGraph(cachedResult.transfers, sorted); + return commitShortcuts(sorted, { + transfers: cachedResult.transfers, + fullEdgeCount: edgeCount, + shortcutEdgeCount: edgeCount, + }); + } + + console.log(`Walking shortcuts: full rebuild for ${sorted.length} stops...`); + const full = buildStopToStopWalkMatrix(sorted); + const fullEdgeCount = countStopWalkEdges(full); + + console.log(`Applying transitive reduction (${fullEdgeCount} directed walk edges)...`); + const shortcuts = transitiveReductionShortcuts(sorted, full); + const shortcutEdgeCount = countStopWalkEdges(shortcuts); + + const transfers = shortcutsToTransfers(shortcuts, metersToWalkDuration); + const edgeCount = finalizeTransferGraph(transfers, sorted); + + console.log( + `Walking shortcuts: ${fullEdgeCount} reachable → ${shortcutEdgeCount} after reduction, ` + + `${edgeCount} total with unreachable pairs` + ); + + const result: SparseWalkingTransferResult = { transfers, fullEdgeCount, shortcutEdgeCount: edgeCount }; + persistShortcutsCache(sorted, result); + return commitShortcuts(sorted, result); +} + +/** @internal Exposed for tests comparing CH vs Dijkstra. */ +export function __computeDijkstraAll(startId: string, targets?: Set) { + return computeDijkstraAll(startId, targets); } initializeGraph(); -if (existsSync(WALKING_CACHE_PATH)) { - const file = readFileSync(WALKING_CACHE_PATH, "utf8"); - Object.assign(walkingCache, JSON.parse(file)); - console.log("Loaded walkingCache.json"); -} else { - console.log("walkingCache.json does not exist — using empty cache"); -} \ No newline at end of file diff --git a/src/walking/walkingShortcuts.ts b/src/walking/walkingShortcuts.ts new file mode 100644 index 0000000..c42030d --- /dev/null +++ b/src/walking/walkingShortcuts.ts @@ -0,0 +1,77 @@ +import { Transfer, TransfersByOrigin } from '../raptor/types'; + +/** Directed stop-to-stop walking distances in meters (only reachable pairs). */ +export type StopWalkMeters = Map>; + +const METER_TOLERANCE = 1; + +/** + * ULTRA-style shortcut graph: transitive reduction on walking times. + * Removes origin→dest when some intermediate stop yields an equal-or-better path. + * Preserves all shortest-path walking distances (no quality loss for time-based walks). + */ +export function transitiveReductionShortcuts( + stops: string[], + durations: StopWalkMeters, + toleranceMeters = METER_TOLERANCE +): StopWalkMeters { + const shortcuts = new Map>(); + + for (const origin of stops) { + const outgoing = durations.get(origin); + if (!outgoing) continue; + + for (const [dest, directMeters] of outgoing) { + if (origin === dest) continue; + + let redundant = false; + for (const mid of stops) { + if (mid === origin || mid === dest) continue; + const leg1 = durations.get(origin)?.get(mid); + const leg2 = durations.get(mid)?.get(dest); + if (leg1 == null || leg2 == null) continue; + if (leg1 >= directMeters || leg2 >= directMeters) continue; + if (leg1 + leg2 <= directMeters + toleranceMeters) { + redundant = true; + break; + } + } + + if (!redundant) { + if (!shortcuts.has(origin)) shortcuts.set(origin, new Map()); + shortcuts.get(origin)!.set(dest, directMeters); + } + } + } + + return shortcuts; +} + +export function shortcutsToTransfers( + shortcuts: StopWalkMeters, + metersToDuration: (meters: number) => number +): TransfersByOrigin { + const transfers: TransfersByOrigin = {}; + + for (const [origin, outgoing] of shortcuts) { + const list: Transfer[] = []; + for (const [destination, meters] of outgoing) { + list.push({ + origin, + destination, + duration: metersToDuration(meters), + startTime: 0, + endTime: Number.MAX_SAFE_INTEGER, + }); + } + if (list.length > 0) transfers[origin] = list; + } + + return transfers; +} + +export function countStopWalkEdges(graph: StopWalkMeters): number { + let n = 0; + for (const outgoing of graph.values()) n += outgoing.size; + return n; +} diff --git a/static/test_example.png b/static/test_example.png index 57c8f00..498b3e5 100644 Binary files a/static/test_example.png and b/static/test_example.png differ diff --git a/test/api.test.ts b/test/api.test.ts index fc586fc..013cc36 100644 --- a/test/api.test.ts +++ b/test/api.test.ts @@ -167,13 +167,13 @@ describe('API Endpoints', () => { // --- Journey Planning --- it('should get path between main stops', async () => { try { - const response = await axios.get(`${BASE_URL}/plan-journey?originLat=42.264356&originLon=-83.744353999999&destLat=42.268067999999&destLon=-83.747307000001`); + const response = await axios.get(`${BASE_URL}/plan-journey?originLat=42.264356&originLon=-83.744353999999&destLat=42.268067999999&destLon=-83.747307000001`, { timeout: 30_000 }); expect(response.status).toBe(200); expect(response.data).toHaveProperty('journeys'); expect(Array.isArray(response.data.journeys)).toBe(true); console.log('GET /plan-journey (test 1):', JSON.stringify(response.data.journeys, null, 2)); - const response2 = await axios.get(`${BASE_URL}/plan-journey?originLat=42.27389558&originLon=-83.73739576&destLat=42.29303061&destLon=-83.7163671`); + const response2 = await axios.get(`${BASE_URL}/plan-journey?originLat=42.27389558&originLon=-83.73739576&destLat=42.29303061&destLon=-83.7163671`, { timeout: 30_000 }); expect(response2.status).toBe(200); expect(response2.data).toHaveProperty('journeys'); expect(Array.isArray(response2.data.journeys)).toBe(true); @@ -188,7 +188,7 @@ describe('API Endpoints', () => { } throw error; } - }); + }, 60_000); it('should return 400 for missing coordinates in plan-journey', async () => { try { @@ -204,5 +204,5 @@ describe('API Endpoints', () => { throw error; } } - }); + }, 20000); }); \ No newline at end of file diff --git a/test/path.test.ts b/test/path.test.ts deleted file mode 100644 index eb0a602..0000000 --- a/test/path.test.ts +++ /dev/null @@ -1,75 +0,0 @@ -import axios from 'axios'; -import { describe, it, expect, beforeAll } from 'vitest'; - -const SERVER_PORT = 3000; -const BASE_URL = `http://localhost:${SERVER_PORT}/mbus/api/v3`; - -describe('API Endpoints', () => { - beforeAll(async () => { - try { - await axios.get(`${BASE_URL}/getAllPredictions`); - } catch (error) { - console.error('Server is not running! Please start the server with: npm start'); - process.exit(1); - } - }); - - it('should get bus predictions and log stop IDs', async () => { - try { - const response = await axios.get(`${BASE_URL}/getAllPredictions`); - expect(response.status).toBe(200); - expect(Array.isArray(response.data)).toBe(true); - - // Extract and log unique stop IDs - const stopIds = new Set(); - response.data.forEach((bus: any) => { - if (bus.stops && Array.isArray(bus.stops)) { - bus.stops.forEach((stop: any) => { - if (stop.stpid) { - stopIds.add(stop.stpid); - } - }); - } - }); - - const stopIdsArray = Array.from(stopIds); - console.log('Available stop IDs:', stopIdsArray); - expect(stopIdsArray.length).toBeGreaterThan(0); - } catch (error) { - if (axios.isAxiosError(error)) { - console.error('Error fetching predictions:', error.message); - if (error.response) { - console.error('Response status:', error.response.status); - console.error('Response data:', error.response.data); - } - } - throw error; - } - }); - - it('should get path between main stops', async () => { - try { - // Test path from one location to another using coordinates - const response = await axios.get(`${BASE_URL}/plan-journey?originLat=42.264356&originLon=-83.744353999999&destLat=42.268067999999&destLon=-83.747307000001`); - expect(response.status).toBe(200); - console.log('Path test 1:', JSON.stringify(response.data, null, 2)); - - // Test another path with different coordinates - // const response2 = await axios.get(`${BASE_URL}/plan-journey?originLat=42.277682&originLon=-83.734936&destLat=42.290425&destLon=-83.718150999999`); - const response2 = await axios.get(`${BASE_URL}/plan-journey?originLat=42.27389558&originLon=-83.73739576&destLat=42.29303061&destLon=-83.7163671?walkingPenalty=8`); - - expect(response2.status).toBe(200); - console.log('Path test 2:', JSON.stringify(response2.data, null, 2)); - } catch (error) { - if (axios.isAxiosError(error)) { - console.error('Error fetching path:', error.message); - if (error.response) { - console.error('Response status:', error.response.status); - console.error('Response data:', error.response.data); - } - } - throw error; - } - }); - -}); \ No newline at end of file diff --git a/test/search-stress.test.ts b/test/search-stress.test.ts index 6b9ea92..b43c9ee 100644 --- a/test/search-stress.test.ts +++ b/test/search-stress.test.ts @@ -4,10 +4,21 @@ import { describe, it, expect, beforeAll } from 'vitest'; const SERVER_PORT = 3000; const BASE_URL = `http://localhost:${SERVER_PORT}/mbus/api/v3`; +/** Axios errors embed functions (e.g. transformRequest) that Vitest cannot clone over RPC. */ +function toPlainError(error: unknown, label: string): Error { + if (axios.isAxiosError(error)) { + const status = error.response?.status; + const detail = status != null ? ` (HTTP ${status})` : ''; + return new Error(`${label}: ${error.message}${detail}`); + } + if (error instanceof Error) return new Error(`${label}: ${error.message}`); + return new Error(`${label}: ${String(error)}`); +} + describe('Stress Test Pathing Endpoint', () => { beforeAll(async () => { try { - await axios.get(`${BASE_URL}/getAllPredictions`); + await axios.get(`${BASE_URL}/getAllPredictions`, { timeout: 10_000 }); } catch (error) { console.error('Server is not running! Please start the server with: npm start'); process.exit(1); @@ -15,11 +26,13 @@ describe('Stress Test Pathing Endpoint', () => { }); it('should handle many concurrent /plan-journey requests', async () => { - const numRequests = 50; // adjust for desired stress level + const numRequests = 50; const origin = { lat: 42.264356, lon: -83.744354 }; const destination = { lat: 42.268068, lon: -83.747307 }; - // Generate multiple unique request URLs (could vary coordinates slightly) + // Requests queue on single-threaded Node; allow enough time for the full batch. + const requestTimeoutMs = 180_000; + const requests = Array.from({ length: numRequests }, (_, i) => { const offset = i * 0.0001; const originLat = origin.lat + offset; @@ -28,28 +41,32 @@ describe('Stress Test Pathing Endpoint', () => { const destLon = destination.lon + offset; const url = `${BASE_URL}/plan-journey?originLat=${originLat}&originLon=${originLon}&destLat=${destLat}&destLon=${destLon}`; - return axios.get(url) + return axios.get(url, { timeout: requestTimeoutMs }) .then(response => { expect(response.status).toBe(200); - return response.data; + return { index: i + 1, ok: true as const }; }) .catch(error => { - console.error(`Request ${i + 1} failed:`, error.message); - if (error.response) { - console.error('Response status:', error.response.status); - } - throw error; + throw toPlainError(error, `Request ${i + 1}`); }); }); const start = Date.now(); - try { - const responses = await Promise.all(requests); - const duration = Date.now() - start; - console.log(`✅ All ${numRequests} requests completed in ${duration}ms`); - } catch (error) { - console.error('❌ Some requests failed during stress test.'); - throw error; + const results = await Promise.allSettled(requests); + const duration = Date.now() - start; + + const failures = results + .map((r, i) => (r.status === 'rejected' ? { index: i + 1, reason: r.reason } : null)) + .filter((f): f is { index: number; reason: unknown } => f != null); + + if (failures.length > 0) { + for (const f of failures) { + const msg = f.reason instanceof Error ? f.reason.message : String(f.reason); + console.error(`Request ${f.index} failed:`, msg); + } + throw new Error(`${failures.length}/${numRequests} stress requests failed after ${duration}ms`); } - }, 40000); // Optional: increase timeout for stress test + + console.log(`✅ All ${numRequests} requests completed in ${duration}ms`); + }, 300_000); }); diff --git a/test/walking-ch.test.ts b/test/walking-ch.test.ts new file mode 100644 index 0000000..e22144d --- /dev/null +++ b/test/walking-ch.test.ts @@ -0,0 +1,89 @@ +import fs from 'fs'; +import path from 'path'; +import { describe, it, expect, beforeAll } from 'vitest'; +import { loadMap } from '../src/walking/loadMap'; +import * as chRouter from '../src/walking/contractionHierarchy'; +import { __computeDijkstraAll } from '../src/walking/walkingMap'; + +const CH_FILE = path.resolve(process.cwd(), 'src/assets/ann_arbor.ch.json'); +const chAvailable = fs.existsSync(CH_FILE); + +/** Sample node pairs spread across the Ann Arbor walking graph. */ +function sampleNodePairs(graph: Map, count = 12): [string, string][] { + const ids = [...graph.keys()]; + const pairs: [string, string][] = []; + const step = Math.max(1, Math.floor(ids.length / count)); + for (let i = 0; i < ids.length - step && pairs.length < count; i += step) { + pairs.push([ids[i], ids[i + step]]); + } + if (pairs.length < 2 && ids.length >= 2) { + pairs.push([ids[0], ids[ids.length - 1]]); + } + return pairs; +} + +describe.skipIf(!chAvailable)('Contraction hierarchy walking', () => { + beforeAll(() => { + chRouter.loadContractionHierarchy(); + }); + + it('loads CH and reports routing mode', () => { + expect(chRouter.isChLoaded()).toBe(true); + }); + + it('CH distances match Dijkstra within 1m on sample pairs', () => { + const { graph } = loadMap(); + const pairs = sampleNodePairs(graph); + + for (const [start, end] of pairs) { + const dijkstra = __computeDijkstraAll(start, new Set([end])).get(end); + const ch = chRouter.queryDistance(start, end); + + expect(dijkstra, `missing Dijkstra for ${start} -> ${end}`).toBeDefined(); + expect(ch, `missing CH for ${start} -> ${end}`).not.toBeNull(); + + if (dijkstra === undefined || ch == null) continue; + expect(Math.abs(dijkstra - ch)).toBeLessThanOrEqual(1); + } + }); + + it('returns null for disconnected or unknown nodes', () => { + expect(chRouter.queryDistance('nonexistent-node-a', 'nonexistent-node-b')).toBeNull(); + }); + + it('PHAST batch distances match Dijkstra within 1m', () => { + const { graph } = loadMap(); + const ids = [...graph.keys()]; + const step = Math.max(1, Math.floor(ids.length / 80)); + const targets = new Set(); + for (let i = step; i < ids.length && targets.size < 40; i += step) { + targets.add(ids[i]); + } + const origin = ids[0]; + + const dijkstra = __computeDijkstraAll(origin, targets); + const phast = chRouter.queryDistancesFromOrigin(origin, targets); + expect(phast).not.toBeNull(); + + for (const t of targets) { + const d = dijkstra.get(t); + const p = phast!.get(t); + expect(d, `missing Dijkstra for ${origin} -> ${t}`).toBeDefined(); + expect(p, `missing PHAST for ${origin} -> ${t}`).toBeDefined(); + if (d === undefined || p === undefined) continue; + expect(Math.abs(d - p)).toBeLessThanOrEqual(1); + } + }); +}); + +describe('Contraction hierarchy asset', () => { + it('documents how to build CH when asset is missing', () => { + if (chAvailable) { + expect(fs.statSync(CH_FILE).size).toBeGreaterThan(0); + return; + } + console.warn( + 'Skipping CH validation — run npm run build:walking-ch to generate src/assets/ann_arbor.ch.json' + ); + }); +}); diff --git a/test/walking-shortcuts.test.ts b/test/walking-shortcuts.test.ts new file mode 100644 index 0000000..0c52790 --- /dev/null +++ b/test/walking-shortcuts.test.ts @@ -0,0 +1,111 @@ +import { describe, it, expect } from 'vitest'; +import { + transitiveReductionShortcuts, + countStopWalkEdges, + StopWalkMeters, +} from '../src/walking/walkingShortcuts'; + +function shortestWalkMeters( + origin: string, + dest: string, + stops: string[], + graph: StopWalkMeters +): number | undefined { + if (origin === dest) return 0; + + const idx = new Map(stops.map((s, i) => [s, i])); + const n = stops.length; + const dist: number[][] = Array.from({ length: n }, () => Array(n).fill(Infinity)); + + for (let i = 0; i < n; i++) dist[i][i] = 0; + + for (const [from, outgoing] of graph) { + const i = idx.get(from); + if (i == null) continue; + for (const [to, meters] of outgoing) { + const j = idx.get(to); + if (j == null) continue; + dist[i][j] = Math.min(dist[i][j], meters); + } + } + + for (let k = 0; k < n; k++) { + for (let i = 0; i < n; i++) { + if (!Number.isFinite(dist[i][k])) continue; + for (let j = 0; j < n; j++) { + if (!Number.isFinite(dist[k][j])) continue; + const via = dist[i][k] + dist[k][j]; + if (via < dist[i][j]) dist[i][j] = via; + } + } + } + + const oi = idx.get(origin); + const di = idx.get(dest); + if (oi == null || di == null) return undefined; + const d = dist[oi][di]; + return Number.isFinite(d) ? d : undefined; +} + +function shortcutsPreserveDistances( + stops: string[], + full: StopWalkMeters, + shortcuts: StopWalkMeters, + toleranceMeters = 1 +): boolean { + for (const origin of stops) { + for (const dest of stops) { + if (origin === dest) continue; + const fullDist = shortestWalkMeters(origin, dest, stops, full); + const shortDist = shortestWalkMeters(origin, dest, stops, shortcuts); + if (fullDist == null && shortDist == null) continue; + if (fullDist == null || shortDist == null) return false; + if (Math.abs(fullDist - shortDist) > toleranceMeters) return false; + } + } + return true; +} + +function buildSampleGraph(): { stops: string[]; full: StopWalkMeters } { + const stops = ['A', 'B', 'C', 'D']; + const full: StopWalkMeters = new Map([ + ['A', new Map([['B', 100], ['C', 200]])], + ['B', new Map([['A', 100], ['C', 100], ['D', 50]])], + ['C', new Map([['A', 200], ['B', 100]])], + ['D', new Map([['B', 50]])], + ]); + return { stops, full }; +} + +describe('walkingShortcuts', () => { + it('removes transitively redundant edges while preserving shortest paths', () => { + const { stops, full } = buildSampleGraph(); + const shortcuts = transitiveReductionShortcuts(stops, full); + + expect(shortcuts.get('A')?.has('C')).toBe(false); + expect(shortcuts.get('A')?.get('B')).toBe(100); + expect(shortcuts.get('B')?.get('C')).toBe(100); + expect(shortcuts.get('D')?.get('B')).toBe(50); + + expect(shortcutsPreserveDistances(stops, full, shortcuts)).toBe(true); + }); + + it('reduces edge count on a hub graph', () => { + const { stops, full } = buildSampleGraph(); + const shortcuts = transitiveReductionShortcuts(stops, full); + expect(countStopWalkEdges(shortcuts)).toBeLessThan(countStopWalkEdges(full)); + expect(shortestWalkMeters('A', 'C', stops, shortcuts)).toBe(200); + }); + + it('keeps all edges when no hub shortcuts exist', () => { + const stops = ['X', 'Y', 'Z']; + const full: StopWalkMeters = new Map([ + ['X', new Map([['Y', 100]])], + ['Y', new Map([['X', 100], ['Z', 100]])], + ['Z', new Map([['Y', 100]])], + ]); + const shortcuts = transitiveReductionShortcuts(stops, full); + expect(countStopWalkEdges(shortcuts)).toBe(countStopWalkEdges(full)); + expect(shortcutsPreserveDistances(stops, full, shortcuts)).toBe(true); + }); +});