# geoalg / geoalg / polyline.py

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88``` ```#!/usr/bin/env python #coding:utf-8 # Author: mozman # Purpose: polylines # Created: 31.03.2010 from __future__ import division from __future__ import print_function from __future__ import unicode_literals from __future__ import absolute_import class Polyline(list): def __init__(self, points=[], closed=False): super(Polyline, self).__init__(points) self.closed = closed @property def nsegments(self): if self.closed: return len(self) else: return len(self)-1 def length(self): plen = 0. for index in range(self.nsegments): plen += self.segment_length(index) return plen def point_at(self, distance): """Get point with from polyline start-point.""" plen = 0. index = 0 while plen < distance: try: plen += self.segment_length(index) except IndexError: return None index += 1 if index == len(self): start = self[-1] end = self[0] else: start = self[index-1] end = self[index] return _interpolate(start, end, plen-distance) def segment_length(self, index): seg = self.segment(index) return _dist(seg[0], seg[1]) def segment(self, index): try: return (self[index], self[index+1]) except IndexError: # for closed polylines exists an extra segment from tail to head # with the index == len(self) if self.closed: return (self[index], self[0]) else: raise # reraise IndexError def itersegments(self): """Iterate polyline segments as (startpoint, endpoint) tuples.""" for index in range(self.nsegments): yield self.segment(index) def _dist(p1, p2): return sum( [(c1-c2)**2 for (c1, c2) in zip(p1, p2)] )**0.5 def _interpolate(start, end, dist): """Interpolate point with distance from start.""" def ip_2d(): dx = end[0] - start[0] dy = end[1] - start[1] factor = dist / (dx**2 + dy**2)**0.5 return (start[0]+dx*factor, start[1]+dy*factor) def ip_3d(): dx = end[0] - start[0] dy = end[1] - start[1] dz = end[2] - start[2] factor = dist / (dx**2 + dy**2 + dz**2)**0.5 return (start[0]+dx*factor, start[1]+dy*factor, start[2]+dz*factor) return (ip_2d() if len(start) == 2 else ip_3d()) ```