5
5
TOLERANCE = 1e-8
6
6
7
7
8
- class GeometryPoint :
9
- def __init__ (self , xy : Union [Tuple [float , float ], np .ndarray ]):
10
- self .xy = np .array (xy )
11
- self .x = xy [0 ]
12
- self .y = xy [1 ]
13
-
14
- def __repr__ (self ) -> str :
15
- return f"GeometryPoint(xy=({ self .xy [0 ]} , { self .xy [1 ]} )"
16
-
17
- def __add__ (self , p : "GeometryPoint" ) -> "GeometryPoint" :
18
- return GeometryPoint (self .xy + p .xy )
19
-
20
- def __sub__ (self , p : "GeometryPoint" ) -> "GeometryPoint" :
21
- return GeometryPoint (self .xy - p .xy )
22
-
23
- def __rmul__ (self , scalar : float ) -> "GeometryPoint" :
24
- return GeometryPoint (self .xy * scalar )
25
-
26
- def __mul__ (self , scalar : float ) -> "GeometryPoint" :
27
- return GeometryPoint (self .xy * scalar )
28
-
29
- # Operator @
30
- def __matmul__ (self , p : "GeometryPoint" ) -> float :
31
- return self .xy @ p .xy
32
-
33
- def length (self ) -> float :
34
- return np .linalg .norm (self .xy )
35
-
36
- def cmp (self , p : "GeometryPoint" ) -> float :
37
- return np .abs (self .xy - p .xy ).sum ()
38
-
39
-
40
8
class GeometryPolygon :
41
- def __init__ (self , points : List [GeometryPoint ]):
42
- self .points = points
43
-
44
- points_x = np .array ([point .x for point in points ])
45
- points_y = np .array ([point .y for point in points ])
46
- self .signed_area = (
47
- points_x @ np .roll (points_y , 1 ) - points_x @ np .roll (points_y , - 1 )
48
- ) / 2
49
- self .area = np .abs (self .signed_area )
9
+ def __init__ (
10
+ self ,
11
+ points : Union [np .ndarray , List [Tuple [float , float ]]],
12
+ is_rectangle : bool = False ,
13
+ ):
14
+ self .points = (
15
+ points if isinstance (points , np .ndarray ) else np .array (points )
16
+ )
17
+ self .is_rectangle = is_rectangle
18
+ points_x = self .points [:, 0 ]
19
+ points_y = self .points [:, 1 ]
20
+ if is_rectangle :
21
+ self .signed_area = np .abs (self .points [2 ] - self .points [0 ]).prod ()
22
+ self .area = self .signed_area
23
+ else :
24
+ self .signed_area = (
25
+ points_x @ np .roll (points_y , - 1 )
26
+ - points_x @ np .roll (points_y , 1 )
27
+ ) / 2
28
+ self .area = np .abs (self .signed_area )
50
29
51
30
def __len__ (self ):
52
31
return len (self .points )
@@ -55,25 +34,22 @@ def __getitem__(self, idx):
55
34
return self .points [idx ]
56
35
57
36
def __repr__ (self ) -> str :
58
- points = ", " .join ([str (point ) for point in self .points ])
59
- return f"GeometryPolygon({ points } )"
60
-
61
-
62
- Segment = Tuple [GeometryPoint , GeometryPoint ]
37
+ return f"GeometryPolygon({ self .points } )"
63
38
64
39
65
40
# alpha * a1 + (1 - alpha) * a2 = beta * b1 + (1 - beta) * b2
66
41
def segment_intersection (
67
- segment1 : Segment , segment2 : Segment
68
- ) -> Tuple [float , float , GeometryPoint ]:
42
+ segment1 : Tuple [np .ndarray , np .ndarray ],
43
+ segment2 : Tuple [np .ndarray , np .ndarray ],
44
+ ) -> Tuple [float , float , np .ndarray ]:
69
45
a1 , a2 = segment1
70
46
b1 , b2 = segment2
71
- x2_x2 = b2 . x - a2 . x
72
- y2_y2 = b2 . y - a2 . y
73
- x1x2 = a1 . x - a2 . x
74
- y1y2 = a1 . y - a2 . y
75
- y1_y2_ = b1 . y - b2 . y
76
- x1_x2_ = b1 . x - b2 . x
47
+ x2_x2 = b2 [ 0 ] - a2 [ 0 ]
48
+ y2_y2 = b2 [ 1 ] - a2 [ 1 ]
49
+ x1x2 = a1 [ 0 ] - a2 [ 0 ]
50
+ y1y2 = a1 [ 1 ] - a2 [ 1 ]
51
+ y1_y2_ = b1 [ 1 ] - b2 [ 1 ]
52
+ x1_x2_ = b1 [ 0 ] - b2 [ 0 ]
77
53
78
54
if np .abs (y1_y2_ * x1x2 - x1_x2_ * y1y2 ) < TOLERANCE :
79
55
beta = 1.0
@@ -139,13 +115,13 @@ def convex_polygon_intersection_area(
139
115
140
116
def unique (ar ):
141
117
res = []
142
- for i , _ in enumerate (ar ):
143
- if _ . cmp ( ar [i - 1 ]) > TOLERANCE :
144
- res .append (_ )
118
+ for i , a in enumerate (ar ):
119
+ if np . abs ( a - ar [i - 1 ]). sum ( ) > TOLERANCE :
120
+ res .append (a )
145
121
146
122
return res
147
123
148
- ps = sorted (ps , key = lambda x : (x . x + TOLERANCE * x . y ))
124
+ ps = sorted (ps , key = lambda x : (x [ 0 ] + TOLERANCE * x [ 1 ] ))
149
125
ps = unique (ps )
150
126
151
127
if len (ps ) == 0 :
@@ -157,25 +133,63 @@ def unique(ar):
157
133
res .append (tmp )
158
134
ps = sorted (
159
135
ps [1 :],
160
- key = lambda x : - (
161
- (x - tmp ) @ GeometryPoint ((0 , 1 )) / (x - tmp ).length ()
162
- ),
136
+ key = lambda x : - ((x - tmp ) @ np .array ((0 , 1 )) / len (x - tmp )),
163
137
)
164
138
res .extend (ps )
165
139
166
140
return GeometryPolygon (res ).signed_area * sign
167
141
168
142
143
+ def area (box ):
144
+ if box [2 ] <= box [0 ] or box [3 ] <= box [1 ]:
145
+ return 0
146
+ return (box [2 ] - box [0 ]) * (box [3 ] - box [1 ])
147
+
148
+
149
+ def iou (box_a , box_b ):
150
+ box_c = intersection (box_a , box_b )
151
+ return area (box_c ) / (area (box_a ) + area (box_b ) - area (box_c ))
152
+
153
+
154
+ def intersection (box_a , box_b ):
155
+ """boxes are left, top, right, bottom where left < right and top < bottom"""
156
+ box_c = [
157
+ max (box_a [0 ], box_b [0 ]),
158
+ max (box_a [1 ], box_b [1 ]),
159
+ min (box_a [2 ], box_b [2 ]),
160
+ min (box_a [3 ], box_b [3 ]),
161
+ ]
162
+ return box_c
163
+
164
+
165
+ def rectangle_intersection_area (
166
+ polygon_a : GeometryPolygon , polygon_b : GeometryPolygon
167
+ ) -> float :
168
+ minx_a , miny_a = np .min (polygon_a .points , axis = 0 )
169
+ maxx_a , maxy_a = np .max (polygon_a .points , axis = 0 )
170
+ minx_b , miny_b = np .min (polygon_b .points , axis = 0 )
171
+ maxx_b , maxy_b = np .max (polygon_b .points , axis = 0 )
172
+
173
+ minx_c = max (minx_a , minx_b )
174
+ miny_c = max (miny_a , miny_b )
175
+ maxx_c = min (maxx_a , maxx_b )
176
+ maxy_c = min (maxy_a , maxy_b )
177
+ return max (maxx_c - minx_c , 0 ) * max (maxy_c - miny_c , 0 )
178
+
179
+
169
180
def polygon_intersection_area (
170
181
polygon_a : GeometryPolygon , polygon_b : GeometryPolygon
171
182
) -> float :
183
+ if polygon_a .is_rectangle and polygon_b .is_rectangle :
184
+ return rectangle_intersection_area (polygon_a , polygon_b )
185
+
172
186
na = len (polygon_a )
173
187
nb = len (polygon_b )
174
188
res = 0.0
175
189
for i in range (1 , na - 1 ):
176
- sa = [ polygon_a [0 ], polygon_a [ i ], polygon_a [ i + 1 ]]
190
+ sa = polygon_a [[ 0 , i , i + 1 ]]
177
191
for j in range (1 , nb - 1 ):
178
- sb = [ polygon_b [0 ], polygon_b [ j ], polygon_b [ j + 1 ]]
192
+ sb = polygon_b [[ 0 , j , j + 1 ]]
179
193
tmp = convex_polygon_intersection_area (
180
194
GeometryPolygon (sa ), GeometryPolygon (sb )
181
195
)
0 commit comments