-
Notifications
You must be signed in to change notification settings - Fork 1
/
lib_geom.py
146 lines (124 loc) · 4.21 KB
/
lib_geom.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import math
from dataclasses import dataclass
# noinspection PyPackageRequirements
import celpy
@dataclass(frozen=True)
class Point:
x: float
y: float
def to_cel(self) -> celpy.celtypes.Value:
"""
Convert this object to a CEL value.
:return:
"""
return celpy.celtypes.MapType(
{
"x": celpy.celtypes.DoubleType(self.x),
"y": celpy.celtypes.DoubleType(self.y),
}
)
def distance_to(self, other: "Point") -> float:
return ((self.x - other.x) ** 2 + (self.y - other.y) ** 2) ** 0.5
def vector_to(self, other: "Point") -> "Vector":
return Vector.from_points(self, other)
@dataclass(frozen=True)
class Box:
"""
Box represents a rectangle in an image.
a is the upper-left point.
b is the lower-right point.
Origin is top-left of the image.
"""
a: Point
b: Point
def w(self) -> float:
return self.b.x - self.a.x
def h(self) -> float:
return self.b.y - self.a.y
def center(self) -> Point:
return Point(
x=(self.a.x + self.b.x) / 2,
y=(self.a.y + self.b.y) / 2,
)
def area(self) -> float:
return self.w() * self.h()
def to_cel(self) -> celpy.celtypes.Value:
"""
Convert this object to a CEL value.
:return:
"""
return celpy.celtypes.MapType(
{
"a": self.a.to_cel(),
"b": self.b.to_cel(),
"w": celpy.celtypes.DoubleType(self.w()),
"h": celpy.celtypes.DoubleType(self.h()),
"center": self.center().to_cel(),
"area": celpy.celtypes.DoubleType(self.area()),
}
)
def percent_intersection_with(self, other: "Box") -> float:
self_a = (self.b.x - self.a.x) * (self.b.y - self.a.y)
other_a = (other.b.x - other.a.x) * (other.b.y - other.a.y)
i_a = max(0.0, min(self.b.x, other.b.x) - max(self.a.x, other.a.x)) * max(
0.0, min(self.b.y, other.b.y) - max(self.a.y, other.a.y)
)
return i_a / (self_a + other_a - i_a)
def average_with(self, other: "Box") -> "Box":
return Box(
a=Point(
x=(self.a.x + other.a.x) / 2,
y=(self.a.y + other.a.y) / 2,
),
b=Point(
x=(self.b.x + other.b.x) / 2,
y=(self.b.y + other.b.y) / 2,
),
)
@dataclass(frozen=True, kw_only=True)
class Vector:
# direction is expressed in degrees, with:
# ┌───┐
# │ b │
# ┌───┐ └─▲─┘ ┌───┐
# │ b │ │ │ b │
# └─▲─┘ 90º └─▲─┘
# ╲ │ ╱
# 135º╲ │ ╱45º
# ╳───┴───╳
# ┌───┐ │ │ ┌───┐
# │ b ◀──────┤ a │──0º──▶ b │
# └───┘-180º │ │ └───┘
# ╳───┬───╳
# -135º╱ │ ╲-45º
# ╱ │ ╲
# ┌─▼─┐ -90º ┌─▼─┐
# │ b │ │ │ b │
# └───┘ ┌─▼─┐ └───┘
# │ b │
# └───┘
direction: float
direction360: float
length: float
def to_cel(self) -> celpy.celtypes.Value:
"""
Convert this object to a CEL value.
:return:
"""
return celpy.celtypes.MapType(
{
"direction": celpy.celtypes.DoubleType(self.direction),
"direction360": celpy.celtypes.DoubleType(self.direction360),
"length": celpy.celtypes.DoubleType(self.length),
}
)
@staticmethod
def from_points(a: Point, b: Point) -> "Vector":
dx = b.x - a.x
dy = b.y - a.y
direct = -1 * math.degrees(math.atan2(dy, dx))
return Vector(
length=(dx**2 + dy**2) ** 0.5,
direction=direct,
direction360=direct + 180.0,
)