Coverage for src/traceplot/helpers/geo/__init__.py: 24%

72 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2025-07-21 13:29 +0200

1from traceplot.types import Point 

2 

3 

4def getSquareDistance(p1: Point, p2: Point) -> float: 

5 """ 

6 Square distance between two points 

7 """ 

8 dx = p1[1] - p2[1] 

9 dy = p1[0] - p2[0] 

10 

11 return dx * dx + dy * dy 

12 

13 

14def getSquareSegmentDistance(p: Segment, p1: Point, p2: Point) -> float: 

15 """ 

16 Square distance between point and a segment 

17 """ 

18 x = p1[1] 

19 y = p1[0] 

20 

21 dx = p2[1] - x 

22 dy = p2[0] - y 

23 

24 if dx != 0 or dy != 0: 

25 t = ((p[1] - x) * dx + (p[0] - y) * dy) / (dx * dx + dy * dy) 

26 

27 if t > 1: 

28 x = p2[1] 

29 y = p2[0] 

30 elif t > 0: 

31 x += dx * t 

32 y += dy * t 

33 

34 dx = p[1] - x 

35 dy = p[0] - y 

36 

37 return dx * dx + dy * dy 

38 

39 

40def _simplifyRadialDistance(points, tolerance): 

41 length = len(points) 

42 prev_point = points[0] 

43 new_points = [prev_point] 

44 

45 for i in range(length): 

46 point = points[i] 

47 

48 if getSquareDistance(point, prev_point) > tolerance: 

49 new_points.append(point) 

50 prev_point = point 

51 

52 if prev_point != point: 

53 new_points.append(point) 

54 

55 return new_points 

56 

57 

58def _simplifyDouglasPeucker(points, tolerance): 

59 length = len(points) 

60 markers = [0] * length # Maybe not the most efficent way? 

61 

62 first = 0 

63 last = length - 1 

64 

65 first_stack = [] 

66 last_stack = [] 

67 

68 new_points = [] 

69 

70 markers[first] = 1 

71 markers[last] = 1 

72 

73 while last: 

74 max_sqdist = 0 

75 

76 for i in range(first, last): 

77 sqdist = getSquareSegmentDistance(points[i], points[first], points[last]) 

78 

79 if sqdist > max_sqdist: 

80 index = i 

81 max_sqdist = sqdist 

82 

83 if max_sqdist > tolerance: 

84 markers[index] = 1 

85 

86 first_stack.append(first) 

87 last_stack.append(index) 

88 

89 first_stack.append(index) 

90 last_stack.append(last) 

91 

92 # Can pop an empty array in Javascript, but not Python, so check 

93 # the length of the list first 

94 if len(first_stack) == 0: 

95 first = None 

96 else: 

97 first = first_stack.pop() 

98 

99 if len(last_stack) == 0: 

100 last = None 

101 else: 

102 last = last_stack.pop() 

103 

104 for i in range(length): 

105 if markers[i]: 

106 new_points.append(points[i]) 

107 

108 return new_points 

109 

110 

111def simplify(points, tolerance=0.1, highestQuality=True): 

112 sqtolerance = tolerance * tolerance 

113 

114 if not highestQuality: 

115 points = _simplifyRadialDistance(points, sqtolerance) 

116 

117 points = _simplifyDouglasPeucker(points, sqtolerance) 

118 

119 return points