-
Notifications
You must be signed in to change notification settings - Fork 1
/
rectangle.py
130 lines (101 loc) · 3.72 KB
/
rectangle.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
119
120
121
122
123
124
125
126
127
128
129
130
import itertools
import math
import csv
class Rectangle:
def __init__(self, left, top, width, height):
self.left = int(left)
self.top = int(top)
self.width = int(width)
self.height = int(height)
# So we can track how far the rectangle moved from original position
self.original_left = self.left
self.original_top = self.top
@property
def right(self):
return self.left + self.width
@property
def bottom(self):
return self.top + self.height
@property
def area(self):
return self.width * self.height
@property
def original_right(self):
return self.original_left + self.width
@property
def original_bottom(self):
return self.original_top + self.height
@property
def midx(self):
return (self.left + self.right) / 2
@property
def midy(self):
return (self.top + self.bottom) / 2
@property
def original_midx(self):
return (self.original_left + self.original_right) / 2
@property
def original_midy(self):
return (self.original_top + self.original_bottom) / 2
@property
def distance_from_original(self):
return math.sqrt((self.left - self.original_left) ** 2 + (self.top - self.original_top) ** 2)
@property
def deltax(self):
return self.original_left - self.left
@property
def deltay(self):
return self.original_top - self.top
def rotate(self, theta):
# Note: important not to assign directly to self.left here first, as that would then mess
# up calculation of the value for self.top
new_left = self.original_left + self.deltax * math.cos(theta) - self.deltay * math.sin(theta)
new_top = self.original_top + self.deltax * math.sin(theta) + self.deltay * math.cos(theta)
self.left = new_left
self.top = new_top
def overlap(self, other):
if(self.left >= other.right or other.left >= self.right):
return False
if(self.top >= other.bottom or other.top >= self.bottom):
return False
return True
def overlapx(self, other):
return max(0, min(self.right, other.right) - max(self.left, other.left))
def overlapy(self, other):
return max(0, min(self.bottom, other.bottom) - max(self.top, other.top))
def overlap_rect(self, other):
left = max(self.left, other.left)
top = max(self.top, other.top)
return Rectangle(left, top, self.overlapx(other), self.overlapy(other))
def center_vec(self, other):
return (self.midx - other.midx, self.midy - other.midy)
def as_tuple(self):
return (self.left, self.top, self.width, self.height)
def __str__(self):
return "Rect" + str(self.as_tuple())
@staticmethod
def has_overlaps(rectangles):
for (r1, r2) in itertools.combinations(rectangles, 2):
if r1.overlap(r2):
return True
return False
@staticmethod
def overlap_rectangles(rectangles):
return [r1.overlap_rect(r2) for r1, r2 in itertools.combinations(rectangles, 2)
if r1.overlap(r2)]
@staticmethod
def total_movement(rectangles):
return sum([r.distance_from_original for r in rectangles])
@staticmethod
def to_csv(rectangles, out):
with open(out, 'w') as f:
writer = csv.writer(f)
writer.writerows([r.as_tuple() for r in rectangles])
@staticmethod
def from_csv(csvfile):
rects = []
with open(csvfile, 'r') as f:
reader = csv.reader(f)
for (left, top, width, height) in reader:
rects.append(Rectangle(left, top, width, height))
return rects