def test_piecewise_linear_interpolation(self): # Empty function f = ContinousPiecewiseLinearFunc() catched = False try: self.assertAlmostEqual(f.interpolate(0), 0, 3) except: catched = True self.assertTrue(catched) # Single point function f = ContinousPiecewiseLinearFunc() f.append(0, 0) self.assertAlmostEqual(f.interpolate(0), 0, 6) self.assertAlmostEqual(f.interpolate(-1), 0, 6) self.assertAlmostEqual(f.interpolate(1), 0, 6) # A simple well-behaved function f = ContinousPiecewiseLinearFunc() f.append(0, 0) f.append(1, 100) self.assertAlmostEqual(f.interpolate(-0.000000001), 0, 6) self.assertAlmostEqual(f.interpolate(0), 0, 6) self.assertAlmostEqual(f.interpolate(0.000000001), 0, 6) self.assertAlmostEqual(f.interpolate(0.5), 50.0, 6) self.assertAlmostEqual(f.interpolate(0.9999999999), 100, 6) self.assertAlmostEqual(f.interpolate(1.0), 100, 6) self.assertAlmostEqual(f.interpolate(1.0000000001), 100, 6) # Function with double-point (infinite derivative) f = ContinousPiecewiseLinearFunc() f.append(0, 0) f.append(1, 0) f.append(1, 100) f.append(2, 100) self.assertAlmostEqual(f.interpolate(0), 0, 6) self.assertAlmostEqual(f.interpolate(1), 100, 6) self.assertAlmostEqual(f.interpolate(-1), 0, 6) # A more complex one f = ContinousPiecewiseLinearFunc() f.append(10, 9000) f.append(20, 10000) f.append(1000, 10980) self.assertAlmostEqual(f.interpolate(5), 9000.0, 6) self.assertAlmostEqual(f.interpolate(15), 9500.0, 6) self.assertAlmostEqual(f.interpolate(40), 10020.0, 3) self.assertAlmostEqual(f.interpolate(1010), 10980.0, 3)
def __init__(self, shape): self._shape = shape self._cache = _CacheEntry(None) self._cache_hit = 0 self._cache_miss = 0 if all(pt.shape_dist_traveled != -999999 for pt in shape.points): self._xdist = ContinousPiecewiseLinearFunc() else: self._xdist = None # Normalize the shape here: # 1) dist_traveled to meters # 2) pt_seq to contiguous numbering from 0 ptseq = 0 distance_meters = 0.0 last_pt = None shape.points.sort(key=lambda p: p.shape_pt_sequence) for pt in shape.points: if last_pt is not None: # Note: we do not use distance cache, as most probably # many of the points will be different from each other. distance_meters += orthodromic_distance(last_pt, pt) last_pt = pt pt.shape_pt_sequence = ptseq old_distance = pt.shape_dist_traveled pt.shape_dist_traveled = distance_meters # Remember the distance mapping for stop times if self._xdist: self._xdist.append(old_distance, pt.shape_dist_traveled) ptseq += 1