forked from Amsterdam-AI-Team/Urban_PointCloud_Processing
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmath_utils.py
98 lines (74 loc) · 2.63 KB
/
math_utils.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
89
90
91
92
93
94
95
96
97
98
import numpy as np
from scipy.spatial import ConvexHull
def _unit_vector(vector):
""" Returns the unit vector of the vector. """
return vector / np.linalg.norm(vector)
def angle_between(v1, v2):
""" Returns the angle in degrees between vectors 'v1' and 'v2'. """
v1_u = _unit_vector(v1)
v2_u = _unit_vector(v2)
dot_product = np.dot(v1_u, v2_u)
rad = np.arccos(np.clip(dot_product, -1.0, 1.0))
return np.degrees(rad)
def compute_bounding_box(points):
"""
Get the min/max values of a point list.
Parameters
----------
points : list
List of x and y points that belong to a polygon
Returns
-------
list
Bounding box with outer points of a polygon
"""
x_coord, y_coord = zip(*points)
return min(x_coord), max(y_coord), max(x_coord), min(y_coord)
def minimum_bounding_rectangle(points):
"""
Find the smallest bounding rectangle for a set of points.
Returns a set of points representing the corners of the bounding box.
:param points: an nx2 matrix of coordinates
:rval: an nx2 matrix of coordinates
"""
pi2 = np.pi/2.
# get the convex hull for the points
hull_points = points[ConvexHull(points).vertices]
# calculate edge angles
edges = np.zeros((len(hull_points)-1, 2))
edges = hull_points[1:] - hull_points[:-1]
angles = np.zeros((len(edges)))
angles = np.arctan2(edges[:, 1], edges[:, 0])
angles = np.abs(np.mod(angles, pi2))
angles = np.unique(angles)
# find rotation matrices
rotations = np.vstack([
np.cos(angles),
np.cos(angles-pi2),
np.cos(angles+pi2),
np.cos(angles)]).T
rotations = rotations.reshape((-1, 2, 2))
# apply rotations to the hull
rot_points = np.dot(rotations, hull_points.T)
# find the bounding points
min_x = np.nanmin(rot_points[:, 0], axis=1)
max_x = np.nanmax(rot_points[:, 0], axis=1)
min_y = np.nanmin(rot_points[:, 1], axis=1)
max_y = np.nanmax(rot_points[:, 1], axis=1)
# find the box with the best area
areas = (max_x - min_x) * (max_y - min_y)
best_idx = np.argmin(areas)
# return the best box
x1 = max_x[best_idx]
x2 = min_x[best_idx]
y1 = max_y[best_idx]
y2 = min_y[best_idx]
r = rotations[best_idx]
min_bounding_rect = np.zeros((4, 2))
min_bounding_rect[0] = np.dot([x1, y2], r)
min_bounding_rect[1] = np.dot([x2, y2], r)
min_bounding_rect[2] = np.dot([x2, y1], r)
min_bounding_rect[3] = np.dot([x1, y1], r)
# Compute the dims of the min bounding rectangle
dims = [(x1 - x2), (y1 - y2)]
return min_bounding_rect, hull_points, min(dims), max(dims)