mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
186 lines
6.0 KiB
Go
186 lines
6.0 KiB
Go
package service
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
"sort"
|
|
|
|
"bugulma/backend/internal/domain"
|
|
"bugulma/backend/internal/geospatial"
|
|
)
|
|
|
|
// TransportationService handles transportation cost calculations and route optimization
|
|
type TransportationService struct {
|
|
geoCalc geospatial.Calculator
|
|
}
|
|
|
|
// NewTransportationService creates a new transportation service
|
|
func NewTransportationService(geoCalc geospatial.Calculator) *TransportationService {
|
|
return &TransportationService{
|
|
geoCalc: geoCalc,
|
|
}
|
|
}
|
|
|
|
// Default transport profiles (simplified for Bugulma region)
|
|
var transportProfiles = map[domain.TransportMode]domain.TransportProfile{
|
|
domain.TransportModeTruck: {
|
|
CostPerKm: 0.12, // €0.12 per km for truck transport
|
|
SpeedKmH: 60.0, // 60 km/h average speed
|
|
MaxCapacity: 25.0, // 25 tons
|
|
EnvironmentalFactor: 1.0, // Baseline
|
|
},
|
|
domain.TransportModeRail: {
|
|
CostPerKm: 0.08, // €0.08 per km (more efficient)
|
|
SpeedKmH: 40.0, // 40 km/h average speed
|
|
MaxCapacity: 200.0, // 200 tons (updated to better reflect rail capacity)
|
|
EnvironmentalFactor: 0.7, // Better for environment
|
|
},
|
|
domain.TransportModePipe: {
|
|
CostPerKm: 0.05, // €0.05 per km (fixed infrastructure)
|
|
SpeedKmH: 100.0, // 100 km/h (fluid transport)
|
|
MaxCapacity: 1000.0, // 1000 tons (continuous flow)
|
|
EnvironmentalFactor: 0.5, // Excellent for environment
|
|
},
|
|
}
|
|
|
|
// CalculateTransportCost calculates transportation cost between two points
|
|
func (t *TransportationService) CalculateTransportCost(
|
|
fromLat, fromLng, toLat, toLng float64,
|
|
mode domain.TransportMode,
|
|
volume float64,
|
|
) (*TransportCost, error) {
|
|
|
|
// Calculate distances
|
|
straightResult, err := t.geoCalc.CalculateDistance(
|
|
geospatial.Point{Latitude: fromLat, Longitude: fromLng},
|
|
geospatial.Point{Latitude: toLat, Longitude: toLng},
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Estimate road distance (1.3x straight-line as approximation)
|
|
roadDistance := straightResult.DistanceKm * 1.3
|
|
|
|
profile, exists := transportProfiles[mode]
|
|
if !exists {
|
|
return nil, ErrInvalidTransportMode
|
|
}
|
|
|
|
// Check capacity
|
|
if volume > profile.MaxCapacity {
|
|
return nil, ErrVolumeExceedsCapacity
|
|
}
|
|
|
|
// Calculate costs
|
|
transportCost := roadDistance * profile.CostPerKm
|
|
timeToDeliver := (roadDistance / profile.SpeedKmH)
|
|
|
|
cost := &TransportCost{
|
|
TransportMode: mode,
|
|
StraightDistanceKm: straightResult.DistanceKm,
|
|
RoadDistanceKm: roadDistance,
|
|
CostEur: transportCost,
|
|
TimeHours: timeToDeliver,
|
|
EnvironmentalFactor: profile.EnvironmentalFactor,
|
|
CapacityUtilization: (volume / profile.MaxCapacity) * 100,
|
|
}
|
|
|
|
return cost, nil
|
|
}
|
|
|
|
// FindOptimalTransportRoutes finds the most cost-effective transportation routes
|
|
func (t *TransportationService) FindOptimalTransportRoutes(
|
|
fromLat, fromLng, toLat, toLng float64,
|
|
volume float64,
|
|
) ([]*domain.TransportOption, error) {
|
|
|
|
var options []*domain.TransportOption
|
|
|
|
for mode, profile := range transportProfiles {
|
|
// Check if the transport mode is feasible for this volume
|
|
if volume > profile.MaxCapacity {
|
|
continue
|
|
}
|
|
|
|
// Calculate distances
|
|
result, err := t.geoCalc.CalculateDistance(
|
|
geospatial.Point{Latitude: fromLat, Longitude: fromLng},
|
|
geospatial.Point{Latitude: toLat, Longitude: toLng},
|
|
)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
// Estimate road distance
|
|
roadDistance := result.DistanceKm * 1.3
|
|
|
|
// Calculate costs
|
|
transportCost := roadDistance * profile.CostPerKm
|
|
timeToDeliver := (roadDistance / profile.SpeedKmH)
|
|
|
|
// Environmental score (higher is better)
|
|
environmentalScore := 10.0 / profile.EnvironmentalFactor
|
|
|
|
option := &domain.TransportOption{
|
|
TransportMode: mode,
|
|
DistanceKm: roadDistance,
|
|
CostEur: transportCost,
|
|
TimeHours: timeToDeliver,
|
|
EnvironmentalScore: environmentalScore,
|
|
CapacityUtilization: (volume / profile.MaxCapacity) * 100,
|
|
}
|
|
|
|
// Calculate overall efficiency score
|
|
option.OverallScore = t.calculateTransportEfficiency(option)
|
|
|
|
options = append(options, option)
|
|
}
|
|
|
|
// Sort by overall score (highest first)
|
|
sort.Slice(options, func(i, j int) bool {
|
|
return options[i].OverallScore > options[j].OverallScore
|
|
})
|
|
|
|
return options, nil
|
|
}
|
|
|
|
// GetTransportProfile returns the profile for a transport mode
|
|
func (t *TransportationService) GetTransportProfile(mode domain.TransportMode) (domain.TransportProfile, error) {
|
|
profile, exists := transportProfiles[mode]
|
|
if !exists {
|
|
return domain.TransportProfile{}, fmt.Errorf("invalid transport mode: %s", mode)
|
|
}
|
|
return profile, nil
|
|
}
|
|
|
|
// calculateTransportEfficiency computes an overall efficiency score for transport options
|
|
func (t *TransportationService) calculateTransportEfficiency(option *domain.TransportOption) float64 {
|
|
// Multi-criteria scoring: cost, time, environment, capacity utilization
|
|
costEfficiency := math.Max(0, 1.0-(option.CostEur/1000.0)) // Better under €1000
|
|
timeEfficiency := math.Max(0, 1.0-(option.TimeHours/24.0)) // Better under 24 hours
|
|
envEfficiency := option.EnvironmentalScore / 10.0 // 0-1 scale
|
|
capacityEfficiency := math.Min(option.CapacityUtilization/100.0, 1.0) // Optimal around 80-100%
|
|
|
|
// Weighted average
|
|
return (costEfficiency * 0.4) + (timeEfficiency * 0.3) + (envEfficiency * 0.2) + (capacityEfficiency * 0.1)
|
|
}
|
|
|
|
// TransportCost represents detailed transportation cost analysis
|
|
type TransportCost struct {
|
|
TransportMode domain.TransportMode `json:"transport_mode"`
|
|
StraightDistanceKm float64 `json:"straight_distance_km"`
|
|
RoadDistanceKm float64 `json:"road_distance_km"`
|
|
CostEur float64 `json:"cost_eur"`
|
|
TimeHours float64 `json:"time_hours"`
|
|
EnvironmentalFactor float64 `json:"environmental_factor"`
|
|
CapacityUtilization float64 `json:"capacity_utilization_percent"`
|
|
}
|
|
|
|
// Errors
|
|
var (
|
|
ErrInvalidTransportMode = errors.New("invalid transport mode specified")
|
|
ErrVolumeExceedsCapacity = errors.New("transport volume exceeds capacity")
|
|
)
|