Skip to content

Commit

Permalink
Set the correct elapsed and total distance for routes that have a loop
Browse files Browse the repository at this point in the history
  • Loading branch information
sandermvanvliet committed Aug 4, 2023
1 parent 97e01bc commit aa1766f
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 9 deletions.
4 changes: 3 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ Read more about how it works on [the RoadCaptain site](https://roadcaptain.nl/fe
### Runner

- **Windows only** Zwift credentials will now be stored securely in the Credential Manager instead of keeping them in memory only. This reduces the amount of times you'll need to log in to Zwift

- When entering a loop, the total distance is set to the distance of the loop.
-
#### Elevation profile

When riding hit <kbd>CTRL</kbd> + <kbd>E</kbd> / <kbd>META</kbd> + <kbd>E</kbd> to toggle the Elevation Plot window. This will allow you to see the elevation and grade of the route you are riding which helps you to plan your effort much easier than having to squint at the elevation profile for the entire route.
Expand All @@ -36,6 +37,7 @@ You can toggle the mode by clicking the elevation profile window and using <kbd>
- Resue the route after connection was lost. This should fix the remaining issue in [#107](https://github.com/sandermvanvliet/RoadCaptain/issues/107)
- Fixed a bug where a crash would occur because the map animation would continue running when the rider is already in-game.
- Fixed a bug where hitting <kbd>CTRL</kbd> + <kbd>X</kbd> / <kbd>META</kbd> + <kbd>X</kbd> in the in-game window when you are not yet in a game would not return to the main window.
- The progress bar now resets when you start a new loop (See [#117](https://github.com/sandermvanvliet/RoadCaptain/issues/117))

## 0.6.11.0

Expand Down
23 changes: 22 additions & 1 deletion src/RoadCaptain.App.Runner/Models/InGameWindowModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public class InGameWindowModel : ViewModelBase
private double _totalDistance;
private string _loopText = string.Empty;
private int _currentSegmentIndex;
private bool _isOnLoop;
private double _loopDistance = 0;

public InGameWindowModel(List<Segment> segments)
{
Expand Down Expand Up @@ -101,7 +103,7 @@ public double ElapsedDescent

public double TotalDistance
{
get => _totalDistance;
get => IsOnLoop ? _loopDistance : _totalDistance;
set
{
if (value.Equals(_totalDistance)) return;
Expand Down Expand Up @@ -178,6 +180,18 @@ public int CurrentSegmentIndex

public int SegmentCount => Route?.RouteSegmentSequence.Count ?? 0;

public bool IsOnLoop
{
get => _isOnLoop;
set
{
if (value == _isOnLoop) return;
_isOnLoop = value;
this.RaisePropertyChanged();
this.RaisePropertyChanged(nameof(TotalDistance));
}
}

private void InitializeRoute(PlannedRoute route)
{
if (route.CurrentSegmentSequence != null)
Expand Down Expand Up @@ -224,6 +238,7 @@ private void CalculateTotalAscentAndDescent(PlannedRoute route)
double totalAscent = 0;
double totalDescent = 0;
double totalDistance = 0;
double loopDistance = 0;

foreach (var sequence in route.RouteSegmentSequence)
{
Expand All @@ -241,9 +256,15 @@ private void CalculateTotalAscentAndDescent(PlannedRoute route)
}

totalDistance += segment.Distance;

if (sequence.Type is SegmentSequenceType.Loop or SegmentSequenceType.LoopEnd or SegmentSequenceType.LoopStart)
{
loopDistance += segment.Distance;
}
}

TotalDistance = Math.Round(totalDistance / 1000, 1);
_loopDistance = Math.Round(loopDistance / 1000, 1);
TotalAscent = totalAscent;
TotalDescent = totalDescent;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ private void UpdateRouteModel(PlannedRoute plannedRoute)
if (plannedRoute.IsLoop)
{
Model.LoopText = plannedRoute.OnLeadIn ? "Lead-in to loop" : $"On loop: {plannedRoute.LoopCount}";
Model.IsOnLoop = plannedRoute.IsOnLoop;
}
else
{
Expand Down
10 changes: 9 additions & 1 deletion src/RoadCaptain/GameStates/UpcomingTurnState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,15 @@ public override GameState UpdatePosition(TrackPoint position, List<Segment> segm

if (plannedRoute.NextSegmentId == segment.Id)
{
plannedRoute.EnteredSegment(segment.Id);
var result = plannedRoute.EnteredSegment(segment.Id);

if (result == RouteMoveResult.StartedNewLoop)
{
distance = 0;
ascent = 0;
descent = 0;
}

return new OnRouteState(
RiderId,
ActivityId,
Expand Down
12 changes: 7 additions & 5 deletions src/RoadCaptain/PlannedRoute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ public class PlannedRoute
[JsonIgnore]
public bool IsOnLastSegment => SegmentSequenceIndex == RouteSegmentSequence.Count - 1;

[JsonIgnore]
public bool IsOnLoop => CurrentSegmentSequence is { Type: SegmentSequenceType.LoopStart or SegmentSequenceType.Loop or SegmentSequenceType.LoopEnd };

[JsonIgnore]
public int SegmentSequenceIndex
{
Expand Down Expand Up @@ -145,12 +148,10 @@ public RouteMoveResult EnteredSegment(string segmentId)
{
SegmentSequenceIndex = NextSegmentSequence!.Index;
LoopCount++;
}
else
{
SegmentSequenceIndex++;
return RouteMoveResult.StartedNewLoop;
}

SegmentSequenceIndex++;
return RouteMoveResult.EnteredNextSegment;
}

Expand Down Expand Up @@ -300,6 +301,7 @@ public enum RouteMoveResult
Unknown,
StartedRoute,
EnteredNextSegment,
CompletedRoute
CompletedRoute,
StartedNewLoop
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using RoadCaptain.GameStates;
using System.Collections.Generic;
using FluentAssertions;
using Xunit;

namespace RoadCaptain.Tests.Unit.GameState.Loops
{
public class FromUpcomingTurnState : LoopStateTransitionTestBase
{
[Fact]
public void GivenOnLastLoopSegment_TotalDistanceOnRouteStateIsReset()
{
var result = GivenStartingState(Route).UpdatePosition(RouteSegment1Point1, Segments, Route);

result
.Should()
.BeOfType<OnRouteState>()
.Which
.ElapsedDistance
.Should()
.Be(0);
}

private UpcomingTurnState GivenStartingState(PlannedRoute plannedRoute)
{
// Ensure the route has started and we're on the first route segment
plannedRoute.EnteredSegment(RouteSegment1.Id);
plannedRoute.EnteredSegment(RouteSegment2.Id);
plannedRoute.EnteredSegment(RouteSegment3.Id);

return new UpcomingTurnState(
1,
2,
RouteSegment3Point3,
RouteSegment3,
plannedRoute,
SegmentDirection.AtoB,
new List<TurnDirection> { TurnDirection.Left, TurnDirection.Right },
1000,
1000,
1000);
}
}

public class LoopStateTransitionTestBase : StateTransitionTestBase
{
protected override PlannedRoute Route { get; } = new()
{
RouteSegmentSequence =
{
new SegmentSequence(segmentId: RouteSegment1.Id, direction: SegmentDirection.AtoB, type: SegmentSequenceType.LoopStart, nextSegmentId: RouteSegment2.Id, turnToNextSegment: TurnDirection.Left),
new SegmentSequence(segmentId: RouteSegment2.Id, direction: SegmentDirection.AtoB, type: SegmentSequenceType.Loop, nextSegmentId: RouteSegment3.Id, turnToNextSegment: TurnDirection.Left),
new SegmentSequence(segmentId: RouteSegment3.Id, direction: SegmentDirection.AtoB, type: SegmentSequenceType.LoopEnd)
},
Sport = SportType.Cycling,
WorldId = "watopia",
World = new World { Id = "watopia", ZwiftId = ZwiftWorldId.Watopia },
Name = "test",
ZwiftRouteName = "zwift test route name"
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public class StateTransitionTestBase
Sport = SportType.Cycling
};

protected readonly PlannedRoute Route = new()
protected virtual PlannedRoute Route { get; } = new()
{
RouteSegmentSequence =
{
Expand Down

0 comments on commit aa1766f

Please sign in to comment.