diff options
| author | Daniel Schadt <kingdread@gmx.de> | 2023-05-08 19:56:24 +0200 | 
|---|---|---|
| committer | Daniel Schadt <kingdread@gmx.de> | 2023-05-08 19:56:24 +0200 | 
| commit | c23e016886ad4a3f6c6dd5179074fa1b8c73641a (patch) | |
| tree | 1a57bfd5f71dab09f0974dd4a7e56bc149ddbdc3 | |
| parent | f7fce26deacf8b63b4852c511eb9cf460df694f9 (diff) | |
| download | fietsboek-c23e016886ad4a3f6c6dd5179074fa1b8c73641a.tar.gz fietsboek-c23e016886ad4a3f6c6dd5179074fa1b8c73641a.tar.bz2 fietsboek-c23e016886ad4a3f6c6dd5179074fa1b8c73641a.zip  | |
move FixNullElevation to separate file
| -rw-r--r-- | fietsboek/transformers/__init__.py | 95 | ||||
| -rw-r--r-- | fietsboek/transformers/elevation.py | 106 | 
2 files changed, 107 insertions, 94 deletions
diff --git a/fietsboek/transformers/__init__.py b/fietsboek/transformers/__init__.py index 330e699..7df700c 100644 --- a/fietsboek/transformers/__init__.py +++ b/fietsboek/transformers/__init__.py @@ -11,7 +11,6 @@ function to load and apply transformers.  from abc import ABC, abstractmethod  from collections.abc import Callable, Iterable, Mapping -from itertools import islice  from typing import Literal, NamedTuple, TypeVar  from gpxpy.gpx import GPX, GPXTrackPoint @@ -128,99 +127,6 @@ class Transformer(ABC):          """ -class FixNullElevation(Transformer): -    """A transformer that fixes points with zero elevation.""" - -    @classmethod -    def identifier(cls) -> str: -        return "fix-null-elevation" - -    @classmethod -    def name(cls) -> TranslationString: -        return _("transformers.fix-null-elevation.title") - -    @classmethod -    def description(cls) -> TranslationString: -        return _("transformers.fix-null-elevation.description") - -    @classmethod -    def parameter_model(cls) -> type[Parameters]: -        return Parameters - -    @property -    def parameters(self) -> Parameters: -        return Parameters() - -    @parameters.setter -    def parameters(self, value): -        pass - -    def execute(self, gpx: GPX): -        def all_points(): -            return gpx.walk(only_points=True) - -        def rev_points(): -            # We cannot use reversed(gpx.walk(...)) since that is not a -            # generator, so we do it manually. -            return ( -                point -                for track in reversed(gpx.tracks) -                for segment in reversed(track.segments) -                for point in reversed(segment.points) -            ) - -        # First, from the front -        self.fixup(all_points) -        # Then, from the back -        self.fixup(rev_points) - -    @classmethod -    def fixup(cls, points: Callable[[], Iterable[GPXTrackPoint]]): -        """Fixes the given GPX points. - -        This iterates over the points and checks for the first point that has a -        non-zero elevation, and a slope that doesn't exceed 100%. All previous -        points will have their elevation adjusted to match this first "good -        point". - -        :param points: A function that generates the iterable of points. -        """ -        max_slope = 1.0 - -        bad_until = 0 -        final_elevation = 0.0 -        for i, (point, next_point) in enumerate(zip(points(), islice(points(), 1, None))): -            if ( -                point.elevation is not None -                and point.elevation != 0.0 -                and cls.slope(point, next_point) < max_slope -            ): -                bad_until = i -                final_elevation = point.elevation -                break - -        for point in islice(points(), None, bad_until): -            point.elevation = final_elevation - -    @staticmethod -    def slope(point_a: GPXTrackPoint, point_b: GPXTrackPoint) -> float: -        """Returns the slope between two GPX points. - -        This is defined as delta_h / euclid_distance. - -        :param point_a: First point. -        :param point_b: Second point. -        :return: The slope, as percentage. -        """ -        if point_a.elevation is None or point_b.elevation is None: -            return 0.0 -        delta_h = abs(point_a.elevation - point_b.elevation) -        dist = point_a.distance_2d(point_b) -        if dist == 0.0 or dist is None: -            return 0.0 -        return delta_h / dist - -  def list_transformers() -> list[type[Transformer]]:      """Returns a list of all available transformers. @@ -228,6 +134,7 @@ def list_transformers() -> list[type[Transformer]]:      """      # pylint: disable=import-outside-toplevel,cyclic-import      from .breaks import RemoveBreaks +    from .elevation import FixNullElevation      return [          FixNullElevation, diff --git a/fietsboek/transformers/elevation.py b/fietsboek/transformers/elevation.py new file mode 100644 index 0000000..0e6f3b0 --- /dev/null +++ b/fietsboek/transformers/elevation.py @@ -0,0 +1,106 @@ +"""Transformers that deal with elevation changes in the track.""" +from collections.abc import Callable, Iterable +from itertools import islice + +from gpxpy.gpx import GPX, GPXTrackPoint +from pyramid.i18n import TranslationString + +from . import Parameters, Transformer + +_ = TranslationString + + +class FixNullElevation(Transformer): +    """A transformer that fixes points with zero elevation.""" + +    @classmethod +    def identifier(cls) -> str: +        return "fix-null-elevation" + +    @classmethod +    def name(cls) -> TranslationString: +        return _("transformers.fix-null-elevation.title") + +    @classmethod +    def description(cls) -> TranslationString: +        return _("transformers.fix-null-elevation.description") + +    @classmethod +    def parameter_model(cls) -> type[Parameters]: +        return Parameters + +    @property +    def parameters(self) -> Parameters: +        return Parameters() + +    @parameters.setter +    def parameters(self, value): +        pass + +    def execute(self, gpx: GPX): +        def all_points(): +            return gpx.walk(only_points=True) + +        def rev_points(): +            # We cannot use reversed(gpx.walk(...)) since that is not a +            # generator, so we do it manually. +            return ( +                point +                for track in reversed(gpx.tracks) +                for segment in reversed(track.segments) +                for point in reversed(segment.points) +            ) + +        # First, from the front +        self.fixup(all_points) +        # Then, from the back +        self.fixup(rev_points) + +    @classmethod +    def fixup(cls, points: Callable[[], Iterable[GPXTrackPoint]]): +        """Fixes the given GPX points. + +        This iterates over the points and checks for the first point that has a +        non-zero elevation, and a slope that doesn't exceed 100%. All previous +        points will have their elevation adjusted to match this first "good +        point". + +        :param points: A function that generates the iterable of points. +        """ +        max_slope = 1.0 + +        bad_until = 0 +        final_elevation = 0.0 +        for i, (point, next_point) in enumerate(zip(points(), islice(points(), 1, None))): +            if ( +                point.elevation is not None +                and point.elevation != 0.0 +                and cls.slope(point, next_point) < max_slope +            ): +                bad_until = i +                final_elevation = point.elevation +                break + +        for point in islice(points(), None, bad_until): +            point.elevation = final_elevation + +    @staticmethod +    def slope(point_a: GPXTrackPoint, point_b: GPXTrackPoint) -> float: +        """Returns the slope between two GPX points. + +        This is defined as delta_h / euclid_distance. + +        :param point_a: First point. +        :param point_b: Second point. +        :return: The slope, as percentage. +        """ +        if point_a.elevation is None or point_b.elevation is None: +            return 0.0 +        delta_h = abs(point_a.elevation - point_b.elevation) +        dist = point_a.distance_2d(point_b) +        if dist == 0.0 or dist is None: +            return 0.0 +        return delta_h / dist + + +__all__ = ["FixNullElevation"]  | 
