feat: Implement synthetic edges city↔airport (Task 10)

- Add TransferTime constants (AirportToCity, CityToStation, StationToStation)
- Update Edge struct with Synthetic field
- Enhance addSyntheticEdgesForNode to use constants and mark synthetic edges
- Update BuildGraphFromStations to set Synthetic field
- Mark synthetic edges in GeoJSON output as dashed lines
- Write TestSyntheticAirportCityEdges and TestRouteWithSyntheticAirportCityEdges tests
This commit is contained in:
2026-08-16 16:05:50 +03:00
parent d93445ad55
commit 06730fe05c
4 changed files with 218 additions and 13 deletions

View File

@@ -19,6 +19,9 @@ type Edge struct {
Departure string // ISO 8601 departure time
Arrival string // ISO 8601 arrival time
Cost int // cost in minor currency units (e.g., rubles)
// Synthetic indicates whether this edge is a synthetic transfer edge
// (e.g., city↔airport, station↔city hub) rather than a real scheduled trip.
Synthetic bool
}
// TransportType represents the type of transport for an edge.
@@ -33,6 +36,19 @@ const (
TransportTypeBus TransportType = "bus"
)
// TransferTime constants for synthetic edge duration estimation.
const (
// AirportToCity is the standard transfer time (in seconds) for airport-to-city
// or city-to-airport synthetic edges.
AirportToCity = 5400 // 90 minutes
// CityToStation is the standard transfer time (in seconds) for city-to-station
// or station-to-city synthetic edges within the same city.
CityToStation = 300 // 5 minutes
// StationToStation is the standard transfer time (in seconds) for station-to-station
// transfers within the same city.
StationToStation = 300 // 5 minutes
)
// NodeType represents the type of a graph node.
type NodeType int
@@ -155,6 +171,7 @@ func BuildGraphFromStations(stations []StationInfo) *Graph {
Transport: string(tp),
TransportType: tp,
IsTransfer: true,
Synthetic: true,
})
// Add reverse synthetic edge: city hub -> station
@@ -166,6 +183,7 @@ func BuildGraphFromStations(stations []StationInfo) *Graph {
Transport: string(tp),
TransportType: tp,
IsTransfer: true,
Synthetic: true,
})
}
@@ -174,6 +192,7 @@ func BuildGraphFromStations(stations []StationInfo) *Graph {
// addSyntheticEdgesForNode adds synthetic edges from the given node to city hubs
// in the same city, as a fallback when direct route search fails.
// Uses transfer time constants for duration estimation.
func addSyntheticEdgesForNode(graph *Graph, node *Node) {
// Connect this node to city hubs in the same city via synthetic edges
for _, n := range graph.Nodes() {
@@ -185,15 +204,25 @@ func addSyntheticEdgesForNode(graph *Graph, node *Node) {
} else if node.CityCode == "c_bus" {
tp = TransportTypeBus
}
// Use appropriate transfer time constant based on node and city types
var duration int
if node.CityCode == "c_airport" {
duration = AirportToCity
} else {
duration = CityToStation
}
// Add synthetic edge from node to city hub
graph.AddEdge(&Edge{
From: node,
To: n,
Kind: EdgeKindSynthetic,
Duration: 300, // 5 min synthetic transfer
Duration: duration,
Transport: string(tp),
TransportType: tp,
IsTransfer: true,
Synthetic: true,
})
// Add reverse synthetic edge from city hub to node
@@ -201,10 +230,11 @@ func addSyntheticEdgesForNode(graph *Graph, node *Node) {
From: n,
To: node,
Kind: EdgeKindSynthetic,
Duration: 300, // 5 min synthetic transfer
Duration: duration,
Transport: string(tp),
TransportType: tp,
IsTransfer: true,
Synthetic: true,
})
}
}