Source code for geo2d.utils

#!/usr/bin/env python
#-*- coding:utf-8 -*-

"""
This module is used by the :mod:`geometry` module. It introduces some
helper functions that I felt would best go in another module altogether.
"""

import math
from functools import wraps

# convenience notation
inf = float('inf')

[docs]def find_first_missing(seq): """ Given an ascending sequence `seq`, the first missing number is returned if any, else None. Parameters ---------- seq : list of ints A sequence of numbers in ascending order in which to search for the first missing element (ie. the sequence is not contiguous and the first gap is found). Returns ------- out : int If a first missing number is found then it is returned, else `None` is returned. """ mid = int(len(seq)/2) first_half = seq[:mid] last_half = seq[mid:] if seq[mid] - seq[mid-1] > 1: return seq[mid-1] + 1 if first_half[-1] - first_half[0] != len(first_half) - 1: return find_first_missing(first_half) if last_half[-1] - last_half[0] != len(last_half) - 1: return find_first_missing(last_half) return None
[docs]def float_to_2pi(angle): """ Convert any floating point number to the inverval [0, 2pi). Parameters ---------- angle : float The floating point number to be remapped to [0, 2pi). Returns ------- out : float A number in the interval [0, 2pi), corresponding to the floating point number `angle`. """ return angle % (2*math.pi)
[docs]def rotated(list_, by): """ Rotates an iterable (but only if it supports negative indexing) by the given amount. Parameters ---------- list_ : list-like with negative indexing The `list` to be rotated. by : int The amount, ie. the number of places to rotate in the right direction the list by, 0 returns an identical `list`. This can also be negative and if so, then it will rotate the `list` to the left by the amount given. """ if by == 0: return list_ if by == -len(list_): # since giving by as -len(list_) is essentially the same as giving # by == 0, we make it raise an IndexError to be consistent with the # positive counterpart by -= 1 # here we first determine if the number of places is in the right interval list_[by] if by < 0: by += len(list_) return list_[-by:] + list_[:-by]
[docs]def cached_property(func): """ Simple decorator for caching class properties. Parameters ---------- func : class method The class method to perform caching on. It has to be part of a class otherwise this won't make sense. Returns ------- out : function The function decorated with property decorator (only for getting, not setting). """ @wraps(func) def fget(self): if not hasattr(self, '_cached'): self._cached = {} return self._cached.setdefault(cached_name, func(self)) cached_name = func.__name__ return property(fget=fget)