diff options
| -rw-r--r-- | rideanalysis/analysis.go | 95 | ||||
| -rw-r--r-- | web/views.go | 81 |
2 files changed, 114 insertions, 62 deletions
diff --git a/rideanalysis/analysis.go b/rideanalysis/analysis.go new file mode 100644 index 0000000..3d34855 --- /dev/null +++ b/rideanalysis/analysis.go @@ -0,0 +1,95 @@ +package rideanalysis + +import ( + "math" + + "github.com/jftuga/geodist" + "github.com/martinlehoux/biking_home/mountain_pass" + "github.com/martinlehoux/biking_home/official_climb" + "github.com/martinlehoux/biking_home/ride" +) + +type Result struct { + Climbs []AnalyzedClimb + Crossings []mountain_pass.Crossing +} + +type AnalyzedClimb struct { + Segment ride.Climb + Name string + Score float64 + Category string + DistanceM float64 + SlopePercent float64 + Cotacol float64 + OfficialClimbID int64 + OfficialName string +} + +func Analyze(parsed ride.Ride, passes []mountain_pass.MountainPass, officialClimbs []official_climb.OfficialClimb, matchPolicy official_climb.MatchPolicy) Result { + result := Result{ + Climbs: make([]AnalyzedClimb, 0), + Crossings: make([]mountain_pass.Crossing, 0), + } + for _, detectedClimb := range parsed.AllClimbs() { + displayClimb := detectedClimb + if matchedPass, ok := mountain_pass.MatchClimb(displayClimb, passes, 300, 50); ok { + displayClimb.Name = matchedPass.Name + } + matchedOfficial, officialFound := official_climb.MatchClimb(detectedClimb, officialClimbs, matchPolicy) + if officialFound { + startIndex := nearestCoordIndex(parsed, matchedOfficial.StartCoord) + endIndex := nearestCoordIndex(parsed, matchedOfficial.EndCoord) + if startIndex < endIndex { + displayClimb = parsed.ClimbFromIndexes(startIndex, endIndex) + displayClimb.Name = matchedOfficial.Name + } else { + officialFound = false + matchedOfficial = official_climb.OfficialClimb{} + } + } + score := displayClimb.Score() + result.Climbs = append(result.Climbs, AnalyzedClimb{ + Segment: displayClimb, + Name: displayClimb.Name, + Score: score, + Category: ride.Category(score), + DistanceM: displayClimb.EndDistanceM() - displayClimb.StartDistanceM(), + SlopePercent: ride.Slope(parsed, displayClimb.StartIndex(), displayClimb.EndIndex()) * 100, + Cotacol: displayClimb.DifficultyScore(), + OfficialClimbID: officialClimbID(matchedOfficial, officialFound), + OfficialName: officialClimbName(matchedOfficial, officialFound), + }) + } + for _, crossing := range mountain_pass.DetectCrossings(parsed, passes, 100, 25) { + result.Crossings = append(result.Crossings, crossing) + } + return result +} + +func nearestCoordIndex(parsed ride.Ride, target geodist.Coord) int { + bestIndex := 0 + bestDistance := math.Inf(1) + for index := 0; index < parsed.Len(); index++ { + _, distanceKm := geodist.HaversineDistance(parsed.Coord(index), target) + if distanceKm < bestDistance { + bestDistance = distanceKm + bestIndex = index + } + } + return bestIndex +} + +func officialClimbID(climb official_climb.OfficialClimb, found bool) int64 { + if !found { + return 0 + } + return climb.ID +} + +func officialClimbName(climb official_climb.OfficialClimb, found bool) string { + if !found { + return "" + } + return climb.Name +} diff --git a/web/views.go b/web/views.go index 310c39c..79356d2 100644 --- a/web/views.go +++ b/web/views.go @@ -2,14 +2,13 @@ package web import ( "fmt" - "math" "net/url" "time" - "github.com/jftuga/geodist" "github.com/martinlehoux/biking_home/mountain_pass" "github.com/martinlehoux/biking_home/official_climb" "github.com/martinlehoux/biking_home/ride" + "github.com/martinlehoux/biking_home/rideanalysis" "github.com/martinlehoux/biking_home/rides" ) @@ -239,42 +238,27 @@ func buildRideProfile(parsed ride.Ride, passes []mountain_pass.MountainPass, off Longitude: coordinate.Lon, } } - climbs := parsed.AllClimbs() - for i := range climbs { - displayClimb := climbs[i] - if matchedPass, ok := mountain_pass.MatchClimb(displayClimb, passes, 300, 50); ok { - displayClimb.Name = matchedPass.Name - } - matchedOfficial, officialFound := official_climb.MatchClimb(climbs[i], officialClimbs, matchPolicy) - if officialFound { - startIndex := nearestCoordIndex(parsed, matchedOfficial.StartCoord) - endIndex := nearestCoordIndex(parsed, matchedOfficial.EndCoord) - if startIndex < endIndex { - displayClimb = parsed.ClimbFromIndexes(startIndex, endIndex) - displayClimb.Name = matchedOfficial.Name - } else { - officialFound = false - matchedOfficial = official_climb.OfficialClimb{} - } - } + analysis := rideanalysis.Analyze(parsed, passes, officialClimbs, matchPolicy) + for _, analyzedClimb := range analysis.Climbs { + climb := analyzedClimb.Segment profile.Climbs = append(profile.Climbs, RideProfileClimb{ - StartKm: displayClimb.StartDistanceM() / 1000, - EndKm: displayClimb.EndDistanceM() / 1000, - TopKm: displayClimb.TopDistanceM() / 1000, - TopElevationM: displayClimb.TopElevationM(), - Name: displayClimb.Name, - Score: displayClimb.Score(), - Category: ride.Category(displayClimb.Score()), - DistanceKm: (displayClimb.EndDistanceM() - displayClimb.StartDistanceM()) / 1000, - SlopePercent: ride.Slope(parsed, displayClimb.StartIndex(), displayClimb.EndIndex()) * 100, - Cotacol: displayClimb.DifficultyScore(), - OfficialClimbID: officialClimbID(matchedOfficial, officialFound), - OfficialName: officialClimbName(matchedOfficial, officialFound), - StartIndex: displayClimb.StartIndex(), - EndIndex: displayClimb.EndIndex(), + StartKm: climb.StartDistanceM() / 1000, + EndKm: climb.EndDistanceM() / 1000, + TopKm: climb.TopDistanceM() / 1000, + TopElevationM: climb.TopElevationM(), + Name: analyzedClimb.Name, + Score: analyzedClimb.Score, + Category: analyzedClimb.Category, + DistanceKm: analyzedClimb.DistanceM / 1000, + SlopePercent: analyzedClimb.SlopePercent, + Cotacol: analyzedClimb.Cotacol, + OfficialClimbID: analyzedClimb.OfficialClimbID, + OfficialName: analyzedClimb.OfficialName, + StartIndex: climb.StartIndex(), + EndIndex: climb.EndIndex(), }) } - for _, crossing := range mountain_pass.DetectCrossings(parsed, passes, 100, 25) { + for _, crossing := range analysis.Crossings { profile.Crossings = append(profile.Crossings, RideProfileCrossing{ DistanceKm: crossing.RideDistanceM / 1000, PassElevation: float64(crossing.Pass.Elevation), @@ -287,33 +271,6 @@ func buildRideProfile(parsed ride.Ride, passes []mountain_pass.MountainPass, off return profile } -func nearestCoordIndex(parsed ride.Ride, target geodist.Coord) int { - bestIndex := 0 - bestDistance := math.Inf(1) - for index := 0; index < parsed.Len(); index++ { - _, distanceKm := geodist.HaversineDistance(parsed.Coord(index), target) - if distanceKm < bestDistance { - bestDistance = distanceKm - bestIndex = index - } - } - return bestIndex -} - -func officialClimbID(climb official_climb.OfficialClimb, found bool) int64 { - if !found { - return 0 - } - return climb.ID -} - -func officialClimbName(climb official_climb.OfficialClimb, found bool) string { - if !found { - return "" - } - return climb.Name -} - type SyncPageData struct { From string To string |