diff options
| author | Daniel Schadt <kingdread@gmx.de> | 2026-09-24 22:26:24 +0200 |
|---|---|---|
| committer | Daniel Schadt <kingdread@gmx.de> | 2026-09-24 22:26:24 +0200 |
| commit | 9a0a4fbfbd005c64c2db2c1606cc7dccbff22053 (patch) | |
| tree | 443dd534d9e9d338b5c06da056a8f7c6ad0e671b | |
| parent | e592c65a55c8523987c9aeec627d693be7487c82 (diff) | |
| download | fietsboek-9a0a4fbfbd005c64c2db2c1606cc7dccbff22053.tar.gz fietsboek-9a0a4fbfbd005c64c2db2c1606cc7dccbff22053.tar.bz2 fietsboek-9a0a4fbfbd005c64c2db2c1606cc7dccbff22053.zip | |
fix climb detection
The old algorithm didn't work; it left large amounts of "non-climb"
space before the climb. This is because we always kept the window at the
minimum length, so even a large mountain at the end of the window could
push the average above the ascension threshold and cause the whole
window to be included.
| -rw-r--r-- | fietsboek/geo.py | 81 |
1 files changed, 16 insertions, 65 deletions
diff --git a/fietsboek/geo.py b/fietsboek/geo.py index e7a58a9..190454b 100644 --- a/fietsboek/geo.py +++ b/fietsboek/geo.py @@ -197,71 +197,22 @@ class Path: yield current_climb def _climbs(self): - # Detection of climbs: - # We use a single pass over the track with two pointers, the "leader" - # and the "chaser". The chaser always points behind the leader. In a - # loop, one of each is always advanced: - # - # If the distance between leader and chaser is less than the minimum - # climb length, we advance the leader to enlarge the window. This - # does not constitute a climb. - # - # If the current ascension is below the ascension threshold, we advance - # the chaser. This moves the window to advance the search. If the - # ascension was above the threshold before the last advancement, we emit - # the climb (which is now over). - # - # If the current ascension is above the threshold, we advance the - # leader. This enlarges the window while constituting a climb. - try: - front = enumerate(self.points) - li, lead = next(front) - back = enumerate(self.points) - ci, chaser = next(back) - except StopIteration: - # Happens if there are no points - return - - length = 0.0 - elevation_diff = 0.0 - climb_start = None - - try: - while True: - if length < CLIMB_MIN_LENGTH: - old_point = lead - li, lead = next(front) - length += old_point.distance(lead) - elevation_diff += lead.elevation - old_point.elevation - continue - - ascension = elevation_diff / length - if ascension < CLIMB_MIN_ASCENSION: - if climb_start is not None: - yield (climb_start, li) - climb_start = None - # Skip to the end of the just emitted climb - while ci != li: - old_point = chaser - ci, chaser = next(back) - length -= old_point.distance(chaser) - elevation_diff -= chaser.elevation - old_point.elevation - else: - old_point = chaser - ci, chaser = next(back) - length -= old_point.distance(chaser) - elevation_diff -= chaser.elevation - old_point.elevation - else: - if climb_start is None: - climb_start = ci - # See how much farther we can extend this climb - old_point = lead - li, lead = next(front) - length += old_point.distance(lead) - elevation_diff += lead.elevation - old_point.elevation - except StopIteration: - if climb_start is not None: - yield (climb_start, li) + i = 0 + + while i < len(self.points): + left = self.points[i] + j = i + length = 0.0 + elevation_diff = 0.0 + while j + 1 < len(self.points) and (length == 0.0 or elevation_diff / length >= CLIMB_MIN_ASCENSION): + length += self.points[j].distance(self.points[j + 1]) + elevation_diff += self.points[j + 1].elevation - self.points[j].elevation + j += 1 + if length >= CLIMB_MIN_LENGTH: + yield (i, j) + i = j + else: + i += 1 def gpx_xml( |
