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
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-21 13:29 +0200
1from traceplot.types import Point
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]
11 return dx * dx + dy * dy
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]
21 dx = p2[1] - x
22 dy = p2[0] - y
24 if dx != 0 or dy != 0:
25 t = ((p[1] - x) * dx + (p[0] - y) * dy) / (dx * dx + dy * dy)
27 if t > 1:
28 x = p2[1]
29 y = p2[0]
30 elif t > 0:
31 x += dx * t
32 y += dy * t
34 dx = p[1] - x
35 dy = p[0] - y
37 return dx * dx + dy * dy
40def _simplifyRadialDistance(points, tolerance):
41 length = len(points)
42 prev_point = points[0]
43 new_points = [prev_point]
45 for i in range(length):
46 point = points[i]
48 if getSquareDistance(point, prev_point) > tolerance:
49 new_points.append(point)
50 prev_point = point
52 if prev_point != point:
53 new_points.append(point)
55 return new_points
58def _simplifyDouglasPeucker(points, tolerance):
59 length = len(points)
60 markers = [0] * length # Maybe not the most efficent way?
62 first = 0
63 last = length - 1
65 first_stack = []
66 last_stack = []
68 new_points = []
70 markers[first] = 1
71 markers[last] = 1
73 while last:
74 max_sqdist = 0
76 for i in range(first, last):
77 sqdist = getSquareSegmentDistance(points[i], points[first], points[last])
79 if sqdist > max_sqdist:
80 index = i
81 max_sqdist = sqdist
83 if max_sqdist > tolerance:
84 markers[index] = 1
86 first_stack.append(first)
87 last_stack.append(index)
89 first_stack.append(index)
90 last_stack.append(last)
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()
99 if len(last_stack) == 0:
100 last = None
101 else:
102 last = last_stack.pop()
104 for i in range(length):
105 if markers[i]:
106 new_points.append(points[i])
108 return new_points
111def simplify(points, tolerance=0.1, highestQuality=True):
112 sqtolerance = tolerance * tolerance
114 if not highestQuality:
115 points = _simplifyRadialDistance(points, sqtolerance)
117 points = _simplifyDouglasPeucker(points, sqtolerance)
119 return points