package rideanalysis import ( "slices" "github.com/martinlehoux/biking_home/mountain_pass" "github.com/martinlehoux/biking_home/official_climb" "github.com/martinlehoux/biking_home/ride" ) const ( passMatchRadiusM = 300 passMatchElevationToleranceM = 50 passCrossingRadiusM = 100 passCrossingElevationToleranceM = 25 ) type Result struct { Climbs []AnalyzedClimb Crossings []mountain_pass.Crossing } type AnalyzedClimb struct { Segment ride.Climb Name string 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), } claimedClimbs := make([]AnalyzedClimb, 0) claimedRanges := make([]ride.Range, 0) for _, official := range officialClimbs { matched, found := official_climb.MatchClimb(parsed.Coords, official, matchPolicy.EndpointRadiusM) if !found { continue } claimedRanges = append(claimedRanges, ride.Range{Start: matched.StartIndex, End: matched.EndIndex}) claimedClimbs = append(claimedClimbs, analyzedClimb(parsed, parsed.ClimbFromIndexes(matched.StartIndex, matched.EndIndex), official.Name, official.ID)) } for _, detectedClimb := range parsed.DetectClimbs(claimedRanges, ride.ClimbSlopeMinimum) { displayClimb := detectedClimb if matchedPass, ok := mountain_pass.MatchClimb(displayClimb, passes, passMatchRadiusM, passMatchElevationToleranceM); ok { displayClimb.Name = matchedPass.Name } result.Climbs = append(result.Climbs, analyzedClimb(parsed, displayClimb, displayClimb.Name, 0)) } climbs := make([]AnalyzedClimb, 0, len(claimedClimbs)+len(result.Climbs)) climbs = append(climbs, claimedClimbs...) climbs = append(climbs, result.Climbs...) slices.SortFunc(climbs, func(a, b AnalyzedClimb) int { return a.Segment.StartIndex() - b.Segment.StartIndex() }) result.Climbs = climbs for _, crossing := range mountain_pass.DetectCrossings(parsed, passes, passCrossingRadiusM, passCrossingElevationToleranceM) { result.Crossings = append(result.Crossings, crossing) } return result } func analyzedClimb(parsed ride.Ride, segment ride.Climb, name string, officialID int64) AnalyzedClimb { cotacol := segment.DifficultyScore() return AnalyzedClimb{ Segment: segment, Name: name, Category: ride.CategoryOf(cotacol).String(), DistanceM: segment.EndDistanceM() - segment.StartDistanceM(), SlopePercent: ride.Slope(parsed, segment.StartIndex(), segment.EndIndex()) * 100, Cotacol: cotacol, OfficialClimbID: officialID, OfficialName: officialClimbNameForID(name, officialID), } } func officialClimbNameForID(name string, officialID int64) string { if officialID == 0 { return "" } return name }