Einführung

Willkommen in der Dokumentation für den GTASA Navigator. Diese Anwendung demonstriert fortschrittliches Routing mittels Graphentheorie in einer Next.js Umgebung.

Das Ziel ist es, den effizientesten Weg zwischen Knotenpunkten zu berechnen, wobei verschiedene Transportmittel (Auto, Boot, Fußgänger) und Kriterien (z.B. Vermeidung von Autobahnen) berücksichtigt werden.

Technologie-Stack

  • Frontend: Next.js 16 (App Router), React, Tailwind CSS
  • Datenbank: Neo4j (Graph Database)
  • Visualisierung: HTML5 Canvas / Leaflet inkl. Custom Map Components
  • Icons: Lucide React

Datenmodell

Die Daten werden in Neo4j als Knoten (Nodes) und Kanten (Relationships) gespeichert.

Visualisierung des Routing Algorithmus
Node Structure
// Beispiel: Node
Node ID: 4:0a462e1b-8cda-4bcd-a3eb-faa4f7e1c95f:167935
{
        area_id: 41
        emergency_vehicle_only: false
        flood_fill: 1
        is_highway: false
        link_count: 2
        link_id: 713
        node_id: 337
        parking: false
        path_width: 40
        traffic_level: 2
        type: "Car"
        x: -1585.75
        y: 1172.0
        z: 6.0
      }
Edge Structure
// Beispiel: Edge
Edge ID: 5:0a462e1b-8cda-4bcd-a3eb-faa4f7e1c95f:113343

          is_highway: false
          length: 12

Routing Algorithmus

Die Routenberechnung erfolgt serverseitig direkt in der Datenbank. Wir nutzen Neo4j's shortestPath Funktion.

Logik-Ablauf:

  1. Klick-Koordinaten (Start/Ziel) erfassen.
  2. Nächste verfügbare Nodes in der DB finden (Nearest Neighbor).
  3. Filter anwenden (z.B. is_highway: false).
  4. Shortest Path Algorythmus.
  5. Pfad als Array von Koordinaten zurückgeben.

Use Cases

Ausgewählte Anwendungsfälle:

Fußgänger RoutingVermeidet Autobahnen, nutzt Gehwege.
Auto (Schnell)Bevorzugt Highways und Hauptstraßen.
Auto (Landschaft)Vermeidet Highways, nutzt Nebenstraßen.

Use Case 1

Fußgänger Routing
MATCH (startNode:PathNode {type: 'Ped'})
        WITH startNode,
            (startNode.x - ORIGIN_X)^2 + (startNode.y - ORIGIN_Y)^2 AS startDistanceSq
        ORDER BY startDistanceSq
        LIMIT 1
        MATCH (endNode:PathNode {type: 'Ped'})
        WITH startNode, endNode,
            (endNode.x - DESTINATION_X)^2 + (endNode.y - DESTINATION_Y)^2 AS endDistanceSq
        ORDER BY endDistanceSq
        LIMIT 1
        MATCH p=shortestPath((startNode)-[:CONNECTS_TO*1..1000]->(endNode))
        RETURN p

Use Case 2

Auto Schnell
MATCH (startNode:PathNode {type: 'Car'})
        WITH startNode,
          (startNode.x - ORIGIN_X)^2 + (startNode.y - ORIGIN_Y)^2 AS startDistanceSq
        ORDER BY startDistanceSq
        LIMIT 1
        MATCH (endNode:PathNode {type: 'Car'})
        WITH startNode, endNode,
          (endNode.x - DESTINATION_X)^2 + (endNode.y - DESTINATION_Y)^2 AS endDistanceSq
        ORDER BY endDistanceSq
        LIMIT 1
        MATCH p=shortestPath((startNode)-[:NOT_HIGHWAY*1..1000]->(endNode))
        RETURN p

Use Case 3

Auto Landschaft
MATCH (startNode:PathNode {type: 'Car', is_highway: false })
        WITH startNode,
          (startNode.x - ORIGIN_X)^2 + (startNode.y - ORIGIN_Y)^2 AS startDistanceSq
        ORDER BY startDistanceSq
        LIMIT 1
        MATCH (endNode:PathNode {type: 'Car', is_highway: false })
        WITH startNode, endNode,
          (endNode.x - DESTINATION_X)^2 + (endNode.y - DESTINATION_Y)^2 AS endDistanceSq
        ORDER BY endDistanceSq
        LIMIT 1
        MATCH p=shortestPath((startNode)-[:NOT_HIGHWAY*1..1000]->(endNode))
        RETURN p

Use Case 4

Punkte im Umkreis von 200x200
MATCH (n:PathNode)
    WHERE n.x >= ORIGIN_X AND n.x <= DESTINATION_X
      AND n.y >= ORIGIN_Y AND n.y <= DESTINATION_Y
    RETURN elementId(n) as id, n.area_id as area_id, n.node_id as node_id, n.x as x, n.y as y, n.z as z
 
      MATCH (n1:PathNode)-[r]->(n2:PathNode)
    WHERE elementId(n1) IN [NODE_IDS]
        AND elementId(n2) IN [NODE_IDS]
    RETURN elementId(n1) as from, elementId(n2) as to