-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathgeometry_utils.py
118 lines (98 loc) · 3.56 KB
/
geometry_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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
from abc import ABCMeta
import casadi as ca
import matplotlib.patches as patches
import matplotlib.pyplot as plt
import numpy as np
import polytope as pt
class ConvexRegion2D:
__metaclass__ = ABCMeta
def get_convex_rep(self):
raise NotImplementedError()
def get_plot_patch(self):
raise NotImplementedError()
class RectangleRegion(ConvexRegion2D):
"""[Rectangle shape]"""
def __init__(self, left, right, down, up):
self.left = left
self.right = right
self.down = down
self.up = up
def get_convex_rep(self):
mat_A = np.array([[-1, 0], [0, -1], [1, 0], [0, 1]])
vec_b = np.array([[-self.left], [-self.down], [self.right], [self.up]])
return mat_A, vec_b
def get_plot_patch(self):
return patches.Rectangle(
(self.left, self.down),
self.right - self.left,
self.up - self.down,
linewidth=1,
edgecolor="k",
facecolor="r",
)
class PolytopeRegion(ConvexRegion2D):
"""[Genral polytope shape]"""
def __init__(self, mat_A, vec_b):
self.mat_A = mat_A
self.vec_b = vec_b
self.points = pt.extreme(pt.Polytope(mat_A, vec_b))
@classmethod
def convex_hull(self, points):
"""Convex hull of N points in d dimensions as Nxd numpy array"""
P = pt.reduce(pt.qhull(points))
return PolytopeRegion(P.A, P.b)
def get_convex_rep(self):
# TODO: Move this change into constructor instead of API here
return self.mat_A, self.vec_b.reshape(self.vec_b.shape[0], -1)
def get_plot_patch(self):
return patches.Polygon(self.points, closed=True, linewidth=1, edgecolor="k", facecolor="r")
def get_dist_point_to_region(point, mat_A, vec_b):
"""Return distance between a point and a convex region"""
opti = ca.Opti()
# variables and cost
point_in_region = opti.variable(mat_A.shape[-1], 1)
cost = 0
# constraints
constraint = ca.mtimes(mat_A, point_in_region) <= vec_b
opti.subject_to(constraint)
dist_vec = point - point_in_region
cost += ca.mtimes(dist_vec.T, dist_vec)
# solve optimization
opti.minimize(cost)
option = {"verbose": False, "ipopt.print_level": 0, "print_time": 0}
opti.solver("ipopt", option)
opt_sol = opti.solve()
# minimum distance & dual variables
dist = opt_sol.value(ca.norm_2(dist_vec))
if dist > 0:
lamb = opt_sol.value(opti.dual(constraint)) / (2 * dist)
else:
lamb = np.zeros(shape=(mat_A.shape[0],))
return dist, lamb
def get_dist_region_to_region(mat_A1, vec_b1, mat_A2, vec_b2):
opti = ca.Opti()
# variables and cost
point1 = opti.variable(mat_A1.shape[-1], 1)
point2 = opti.variable(mat_A2.shape[-1], 1)
cost = 0
# constraints
constraint1 = ca.mtimes(mat_A1, point1) <= vec_b1
constraint2 = ca.mtimes(mat_A2, point2) <= vec_b2
opti.subject_to(constraint1)
opti.subject_to(constraint2)
dist_vec = point1 - point2
cost += ca.mtimes(dist_vec.T, dist_vec)
# solve optimization
opti.minimize(cost)
option = {"verbose": False, "ipopt.print_level": 0, "print_time": 0}
opti.solver("ipopt", option)
opt_sol = opti.solve()
# minimum distance & dual variables
dist = opt_sol.value(ca.norm_2(dist_vec))
if dist > 0:
lamb = opt_sol.value(opti.dual(constraint1)) / (2 * dist)
mu = opt_sol.value(opti.dual(constraint2)) / (2 * dist)
else:
lamb = np.zeros(shape=(mat_A1.shape[0],))
mu = np.zeros(shape=(mat_A2.shape[0],))
return dist, lamb, mu