geometryai 0.0.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- geometryai-0.0.9/PKG-INFO +11 -0
- geometryai-0.0.9/README.md +3 -0
- geometryai-0.0.9/geometryai/__init__.py +4 -0
- geometryai-0.0.9/geometryai/core.py +482 -0
- geometryai-0.0.9/geometryai.egg-info/PKG-INFO +11 -0
- geometryai-0.0.9/geometryai.egg-info/SOURCES.txt +8 -0
- geometryai-0.0.9/geometryai.egg-info/dependency_links.txt +1 -0
- geometryai-0.0.9/geometryai.egg-info/top_level.txt +1 -0
- geometryai-0.0.9/setup.cfg +4 -0
- geometryai-0.0.9/setup.py +11 -0
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
from fractions import Fraction
|
|
3
|
+
from PIL import Image, ImageDraw, ImageFont
|
|
4
|
+
class Graph:
|
|
5
|
+
def __init__(self, space):
|
|
6
|
+
self.n = len(space.point_location)
|
|
7
|
+
self.adj = {i: set() for i in range(self.n)}
|
|
8
|
+
self._build(space.give_connect())
|
|
9
|
+
def _build(self, edges):
|
|
10
|
+
for u, v in edges:
|
|
11
|
+
self.adj[u].add(v)
|
|
12
|
+
self.adj[v].add(u)
|
|
13
|
+
def all_cycles(self):
|
|
14
|
+
cycles = []
|
|
15
|
+
visited = [False] * self.n
|
|
16
|
+
def dfs(start, current, parent, path):
|
|
17
|
+
visited[current] = True
|
|
18
|
+
path.append(current)
|
|
19
|
+
for nxt in self.adj[current]:
|
|
20
|
+
if nxt == parent:
|
|
21
|
+
continue
|
|
22
|
+
if nxt == start and len(path) > 2:
|
|
23
|
+
cycles.append(path.copy())
|
|
24
|
+
elif not visited[nxt]:
|
|
25
|
+
dfs(start, nxt, current, path)
|
|
26
|
+
path.pop()
|
|
27
|
+
visited[current] = False
|
|
28
|
+
for v in range(self.n):
|
|
29
|
+
dfs(v, v, -1, [])
|
|
30
|
+
return cycles
|
|
31
|
+
def _canonical_cycle(self, cycle):
|
|
32
|
+
cycle = cycle[:-1] if cycle[0] == cycle[-1] else cycle
|
|
33
|
+
n = len(cycle)
|
|
34
|
+
rotations = []
|
|
35
|
+
for i in range(n):
|
|
36
|
+
r = cycle[i:] + cycle[:i]
|
|
37
|
+
rotations.append(tuple(r))
|
|
38
|
+
rotations.append(tuple(reversed(r)))
|
|
39
|
+
return min(rotations)
|
|
40
|
+
def simple_cycles(self):
|
|
41
|
+
raw = self.all_cycles()
|
|
42
|
+
unique = set()
|
|
43
|
+
for cycle in raw:
|
|
44
|
+
if len(set(cycle)) != len(cycle):
|
|
45
|
+
continue
|
|
46
|
+
unique.add(self._canonical_cycle(cycle))
|
|
47
|
+
return [list(c) for c in unique]
|
|
48
|
+
def consecutive_triplets_at(self):
|
|
49
|
+
triplets = []
|
|
50
|
+
for v in self.adj.keys():
|
|
51
|
+
nbrs = list(self.adj[v])
|
|
52
|
+
if len(nbrs) >=2:
|
|
53
|
+
for i in range(len(nbrs)):
|
|
54
|
+
for j in range(len(nbrs)):
|
|
55
|
+
if i != j:
|
|
56
|
+
triplets.append((nbrs[i], v, nbrs[j]))
|
|
57
|
+
return triplets
|
|
58
|
+
def draw_geometry(points, edges, size, margin):
|
|
59
|
+
pts = [(float(x), float(y)) for x, y in points]
|
|
60
|
+
xs = [x for x, y in pts]
|
|
61
|
+
ys = [y for x, y in pts]
|
|
62
|
+
min_x, max_x = min(xs), max(xs)
|
|
63
|
+
min_y, max_y = min(ys), max(ys)
|
|
64
|
+
width = max_x - min_x or 1
|
|
65
|
+
height = max_y - min_y or 1
|
|
66
|
+
if size is None:
|
|
67
|
+
size = 300
|
|
68
|
+
if margin is None:
|
|
69
|
+
margin = 40
|
|
70
|
+
scale = min(
|
|
71
|
+
(size - 2 * margin) / width,
|
|
72
|
+
(size - 2 * margin) / height
|
|
73
|
+
)
|
|
74
|
+
def transform(x, y):
|
|
75
|
+
px = margin + (x - min_x) * scale
|
|
76
|
+
py = size - (margin + (y - min_y) * scale)
|
|
77
|
+
return px, py
|
|
78
|
+
|
|
79
|
+
img = Image.new("RGB", (size, size), "white")
|
|
80
|
+
draw = ImageDraw.Draw(img)
|
|
81
|
+
for i, j in edges:
|
|
82
|
+
p1 = transform(*pts[i])
|
|
83
|
+
p2 = transform(*pts[j])
|
|
84
|
+
draw.line([p1, p2], fill="black", width=2)
|
|
85
|
+
try:
|
|
86
|
+
font = ImageFont.truetype("arial.ttf", 22)
|
|
87
|
+
except:
|
|
88
|
+
font = ImageFont.load_default()
|
|
89
|
+
r = 4
|
|
90
|
+
label_offset = (6, -6)
|
|
91
|
+
for idx, (x, y) in enumerate(pts):
|
|
92
|
+
px, py = transform(x, y)
|
|
93
|
+
draw.ellipse((px-r, py-r, px+r, py+r), fill="red")
|
|
94
|
+
label = chr(ord("A") + idx)
|
|
95
|
+
draw.text(
|
|
96
|
+
(px + label_offset[0], py + label_offset[1]),
|
|
97
|
+
label,
|
|
98
|
+
fill="blue",
|
|
99
|
+
font=font
|
|
100
|
+
)
|
|
101
|
+
img.save("output.png")
|
|
102
|
+
return img
|
|
103
|
+
def merge_category(cat, mergefx):
|
|
104
|
+
n = len(cat)
|
|
105
|
+
used = [False] * n
|
|
106
|
+
out = []
|
|
107
|
+
for i in range(n):
|
|
108
|
+
if used[i]:
|
|
109
|
+
continue
|
|
110
|
+
merged = []
|
|
111
|
+
for j in range(i, n):
|
|
112
|
+
if not used[j] and mergefx(cat[i], cat[j]):
|
|
113
|
+
merged += cat[j]
|
|
114
|
+
used[j] = True
|
|
115
|
+
out.append(merged)
|
|
116
|
+
return [list(set(item)) for item in out]
|
|
117
|
+
|
|
118
|
+
def are_collinear(points):
|
|
119
|
+
"""
|
|
120
|
+
Returns True if all points are collinear, False otherwise.
|
|
121
|
+
points: list of (x, y), x and y can be Fraction or int
|
|
122
|
+
"""
|
|
123
|
+
n = len(points)
|
|
124
|
+
if n <= 2:
|
|
125
|
+
return True
|
|
126
|
+
x0, y0 = points[0]
|
|
127
|
+
x1, y1 = points[1]
|
|
128
|
+
dx = x1 - x0
|
|
129
|
+
dy = y1 - y0
|
|
130
|
+
for i in range(2, n):
|
|
131
|
+
xi, yi = points[i]
|
|
132
|
+
if (xi - x0) * dy != (yi - y0) * dx:
|
|
133
|
+
return False
|
|
134
|
+
return True
|
|
135
|
+
def intersection(p1, p2, p3, p4):
|
|
136
|
+
x1, y1 = p1
|
|
137
|
+
x2, y2 = p2
|
|
138
|
+
x3, y3 = p3
|
|
139
|
+
x4, y4 = p4
|
|
140
|
+
A1 = y2 - y1
|
|
141
|
+
B1 = x1 - x2
|
|
142
|
+
C1 = A1 * x1 + B1 * y1
|
|
143
|
+
A2 = y4 - y3
|
|
144
|
+
B2 = x3 - x4
|
|
145
|
+
C2 = A2 * x3 + B2 * y3
|
|
146
|
+
det = A1 * B2 - A2 * B1
|
|
147
|
+
if det == 0:
|
|
148
|
+
return None
|
|
149
|
+
x = (C1 * B2 - C2 * B1) / det
|
|
150
|
+
y = (A1 * C2 - A2 * C1) / det
|
|
151
|
+
return (x, y)
|
|
152
|
+
|
|
153
|
+
def point_sort(point):
|
|
154
|
+
if isinstance(point, str):
|
|
155
|
+
return ord(point)-ord("A")
|
|
156
|
+
return point
|
|
157
|
+
def line_sort(line):
|
|
158
|
+
if isinstance(line, str):
|
|
159
|
+
return tuple(sorted([ord(item)-ord("A") for item in line]))
|
|
160
|
+
return tuple(sorted(list(line)))
|
|
161
|
+
class Space:
|
|
162
|
+
def __init__(self):
|
|
163
|
+
self.point_location = []
|
|
164
|
+
self.line_info = []
|
|
165
|
+
self.angle_list = {}
|
|
166
|
+
self.command = []
|
|
167
|
+
self.line = []
|
|
168
|
+
self.ray = []
|
|
169
|
+
self.graph = None
|
|
170
|
+
self.line_eq = []
|
|
171
|
+
self.angle_eq = []
|
|
172
|
+
self.tri_eq = []
|
|
173
|
+
self.perpendicular_angle = []
|
|
174
|
+
self.perpendicular = []
|
|
175
|
+
def standard_angle(self, angle):
|
|
176
|
+
if isinstance(angle, str):
|
|
177
|
+
angle = tuple([ord(item)-ord("A") for item in angle])
|
|
178
|
+
if angle[0] > angle[2]:
|
|
179
|
+
angle = (angle[2],angle[1],angle[0])
|
|
180
|
+
if isinstance(angle, list):
|
|
181
|
+
angle = tuple(angle)
|
|
182
|
+
for key in self.angle_list.keys():
|
|
183
|
+
if key == angle or angle in self.angle_list[key]:
|
|
184
|
+
return key
|
|
185
|
+
return None
|
|
186
|
+
def perpen_angle(self):
|
|
187
|
+
self.perpendicular = [[list(item2) for item2 in item] for item in self.perpendicular]
|
|
188
|
+
for item in itertools.combinations(self.line_info, 2):
|
|
189
|
+
item = list(item)
|
|
190
|
+
if all(not self.straight_line(list(set(item[0]+item2[0]))) or not self.straight_line(list(set(item[1]+item2[1]))) for item2 in self.perpendicular)\
|
|
191
|
+
and all(not self.straight_line(list(set(item[0]+item2[1]))) or not self.straight_line(list(set(item[1]+item2[0]))) for item2 in self.perpendicular):
|
|
192
|
+
continue
|
|
193
|
+
if len(set(item[0])&set(item[1]))==1:
|
|
194
|
+
c = list(set(item[0])&set(item[1]))[0]
|
|
195
|
+
a = item[0].index(c)
|
|
196
|
+
b = item[1].index(c)
|
|
197
|
+
m, n = [], []
|
|
198
|
+
for i in range(2):
|
|
199
|
+
d = [a,b][i]
|
|
200
|
+
if d>0:
|
|
201
|
+
[m,n][i].append(item[i][d-1])
|
|
202
|
+
if d<len(item[i])-1:
|
|
203
|
+
[m,n][i].append(item[i][d+1])
|
|
204
|
+
for item2 in itertools.product(m,n):
|
|
205
|
+
angle = space.standard_angle((item2[0],c,item2[1]))
|
|
206
|
+
if angle not in self.perpendicular_angle:
|
|
207
|
+
self.perpendicular_angle.append(angle)
|
|
208
|
+
space.angle_eq.append(self.perpendicular_angle)
|
|
209
|
+
space.angle_eq = merge_category(space.angle_eq, default_merge)
|
|
210
|
+
def straight_line(self, point_list):
|
|
211
|
+
return are_collinear([self.point_location[x] for x in point_list])
|
|
212
|
+
def sort_collinear(self, point_list):
|
|
213
|
+
p = min([self.point_location[x][1] for x in point_list])
|
|
214
|
+
p2 = [x for x in point_list if self.point_location[x][1] == p]
|
|
215
|
+
p3 = list(sorted(p2, key=lambda x: self.point_location[x][0]))[0]
|
|
216
|
+
m, n = self.point_location[p3]
|
|
217
|
+
return list(sorted(point_list, key=lambda x: (self.point_location[x][0]-m)**2 + (self.point_location[x][1]-n)**2))
|
|
218
|
+
def calc_angle_list(self):
|
|
219
|
+
lst = self.graph.consecutive_triplets_at()
|
|
220
|
+
lst = list(set([item if item[0]<item[2] else (item[2],item[1],item[0]) for item in lst]))
|
|
221
|
+
lst = [item for item in lst if not self.straight_line(list(item))]
|
|
222
|
+
for item2 in lst:
|
|
223
|
+
self.angle_list[item2] = []
|
|
224
|
+
for item in itertools.permutations(self.line_info, 2):
|
|
225
|
+
if item2[0] in item[0] and item2[2] in item[1] and item2[1] in item[0] and item2[1] in item[1]:
|
|
226
|
+
h = []
|
|
227
|
+
for i in range(2):
|
|
228
|
+
m = item[i][:item[i].index(item2[1])]
|
|
229
|
+
n = item[i][item[i].index(item2[1])+1:]
|
|
230
|
+
if item2[0] in m or item2[2] in m:
|
|
231
|
+
h.append(m)
|
|
232
|
+
elif item2[0] in n or item2[2] in n:
|
|
233
|
+
h.append(n)
|
|
234
|
+
for item3 in itertools.product(*h):
|
|
235
|
+
x = (item3[0], item2[1], item3[1])
|
|
236
|
+
y = (item3[1], item2[1], item3[0])
|
|
237
|
+
self.angle_list[item2] += [x,y]
|
|
238
|
+
def give_connect(self):
|
|
239
|
+
out = []
|
|
240
|
+
for item in self.line_info:
|
|
241
|
+
for i in range(len(item)-1):
|
|
242
|
+
out.append(item[i:i+2])
|
|
243
|
+
return out
|
|
244
|
+
def line_eq_fx(self, line1, line2):
|
|
245
|
+
line1 = line_sort(line1)
|
|
246
|
+
line2 = line_sort(line2)
|
|
247
|
+
if line1 == line2:
|
|
248
|
+
return True
|
|
249
|
+
for item in self.line_eq:
|
|
250
|
+
if line1 in item and line2 in item:
|
|
251
|
+
return True
|
|
252
|
+
return False
|
|
253
|
+
def angle_eq_fx(self, angle1, angle2):
|
|
254
|
+
angle1 = self.standard_angle(angle1)
|
|
255
|
+
angle2 = self.standard_angle(angle2)
|
|
256
|
+
if angle1 == angle2:
|
|
257
|
+
return True
|
|
258
|
+
for item in self.angle_eq:
|
|
259
|
+
if angle1 in item and angle2 in item:
|
|
260
|
+
return True
|
|
261
|
+
return False
|
|
262
|
+
def valid_line(self, line):
|
|
263
|
+
line = line_sort(line)
|
|
264
|
+
return any((line[0] in item and line[1] in item) for item in self.line_info)
|
|
265
|
+
def show_diagram(self, size):
|
|
266
|
+
out = draw_geometry(self.point_location, self.give_connect(), size, None)
|
|
267
|
+
try:
|
|
268
|
+
from IPython.display import display
|
|
269
|
+
display(out)
|
|
270
|
+
out.show()
|
|
271
|
+
except:
|
|
272
|
+
print("error displaying image")
|
|
273
|
+
def calc_line_info(self):
|
|
274
|
+
line = [self.line_info[x] for x in self.line]
|
|
275
|
+
ray = [(self.line_info[x[0]], x[1]) for x in self.ray]
|
|
276
|
+
self.line = []
|
|
277
|
+
self.ray = []
|
|
278
|
+
cat = []
|
|
279
|
+
for index in range(2):
|
|
280
|
+
for item in itertools.combinations(list(range(len(self.point_location))), 3):
|
|
281
|
+
if self.straight_line(list(item)):
|
|
282
|
+
cat.append(list(item))
|
|
283
|
+
for item in self.line_info:
|
|
284
|
+
if len(item) == 2 and all(item[0] not in item2 or item[1] not in item2 for item2 in cat):
|
|
285
|
+
cat.append(list(item))
|
|
286
|
+
def mergefx(a, b):
|
|
287
|
+
return self.straight_line(list(set(a+b)))
|
|
288
|
+
cat = merge_category(cat, mergefx)
|
|
289
|
+
p = []
|
|
290
|
+
|
|
291
|
+
for item in itertools.combinations(cat, 2):
|
|
292
|
+
p2 = intersection(*[self.point_location[item2] for item2 in item[0][:2]+item[1][:2]])
|
|
293
|
+
p.append(p2)
|
|
294
|
+
p = list(set(p))
|
|
295
|
+
if self.command != [] and index == 0:
|
|
296
|
+
for i in range(len(self.command)-1,-1,-1):
|
|
297
|
+
for item in p:
|
|
298
|
+
if any(item2[0]==item[0] and item2[1]==item[1] for item2 in self.point_location):
|
|
299
|
+
continue
|
|
300
|
+
self.point_location.append(item)
|
|
301
|
+
lst = [self.command[i][0], len(self.point_location)-1, self.command[i][1]]
|
|
302
|
+
if self.straight_line(lst) and (any(lst[0] in item2 and lst[1] in item2 for item2 in self.line) or self.sort_collinear(lst)[1] == lst[1]):
|
|
303
|
+
pass
|
|
304
|
+
else:
|
|
305
|
+
self.point_location.pop(-1)
|
|
306
|
+
cat = []
|
|
307
|
+
else:
|
|
308
|
+
break
|
|
309
|
+
self.line_info = [self.sort_collinear(item) for item in cat]
|
|
310
|
+
for item in line:
|
|
311
|
+
for i in range(len(self.line_info)):
|
|
312
|
+
if self.straight_line(list(self.line_info[i])+item):
|
|
313
|
+
self.line.append(i)
|
|
314
|
+
for item in ray:
|
|
315
|
+
for i in range(len(self.line_info)):
|
|
316
|
+
if self.straight_line(list(self.line_info[i])+item[0]):
|
|
317
|
+
self.ray.append((i, item[1]))
|
|
318
|
+
self.graph = Graph(self)
|
|
319
|
+
def default_merge(a, b):
|
|
320
|
+
return (set(a)&set(b)) != {}
|
|
321
|
+
space = Space()
|
|
322
|
+
def draw_triangle():
|
|
323
|
+
global space
|
|
324
|
+
space.point_location = [
|
|
325
|
+
(Fraction(0), Fraction(0)),
|
|
326
|
+
(Fraction(4), Fraction(1)),
|
|
327
|
+
(Fraction(1), Fraction(3)),
|
|
328
|
+
]
|
|
329
|
+
space.line_info = [[0,1],[1,2],[2,0]]
|
|
330
|
+
def given_equal_line(line1, line2):
|
|
331
|
+
global space
|
|
332
|
+
line1 = line_sort(line1)
|
|
333
|
+
line2 = line_sort(line2)
|
|
334
|
+
space.line_eq.append([line1, line2])
|
|
335
|
+
space.line_eq = merge_category(space.line_eq, default_merge)
|
|
336
|
+
def cpct():
|
|
337
|
+
global space
|
|
338
|
+
for item in space.tri_eq:
|
|
339
|
+
for item2 in itertools.combinations(item, 2):
|
|
340
|
+
m2 = list(zip(*item2))
|
|
341
|
+
for item3 in itertools.permutations(m2):
|
|
342
|
+
angle1, angle2 = (item3[0][0], item3[1][0], item3[2][0]), (item3[0][1], item3[1][1], item3[2][1])
|
|
343
|
+
angle1, angle2 = space.standard_angle(angle1), space.standard_angle(angle2)
|
|
344
|
+
|
|
345
|
+
if angle1 is None or angle2 is None or angle1 == angle2:
|
|
346
|
+
continue
|
|
347
|
+
space.angle_eq.append([angle1, angle2])
|
|
348
|
+
for item3 in itertools.combinations(m2, 2):
|
|
349
|
+
line1, line2 = item3
|
|
350
|
+
line1, line2 = line_sort(line1), line_sort(line2)
|
|
351
|
+
if not space.valid_line(line1) or not space.valid_line(line2) or line1 == line2:
|
|
352
|
+
continue
|
|
353
|
+
space.line_eq.append([line1, line2])
|
|
354
|
+
space.line_eq = merge_category(space.line_eq, default_merge)
|
|
355
|
+
space.angle_eq = merge_category(space.angle_eq, default_merge)
|
|
356
|
+
def sss_rule(a1, a2, a3, b1, b2, b3):
|
|
357
|
+
global space
|
|
358
|
+
a1, a2, a3, b1, b2, b3 = [[item] for item in [a1, a2, a3, b1, b2, b3]]
|
|
359
|
+
line = [
|
|
360
|
+
line_sort(a1 + a2),
|
|
361
|
+
line_sort(b1 + b2),
|
|
362
|
+
line_sort(a2 + a3),
|
|
363
|
+
line_sort(b2 + b3),
|
|
364
|
+
line_sort(a1 + a3),
|
|
365
|
+
line_sort(b1 + b3),
|
|
366
|
+
]
|
|
367
|
+
|
|
368
|
+
for item in line:
|
|
369
|
+
if not space.valid_line(item):
|
|
370
|
+
return False
|
|
371
|
+
|
|
372
|
+
return (
|
|
373
|
+
space.line_eq_fx(line[0], line[1])
|
|
374
|
+
and space.line_eq_fx(line[2], line[3])
|
|
375
|
+
and space.line_eq_fx(line[4], line[5])
|
|
376
|
+
)
|
|
377
|
+
def rhs_rule(a1, a2, a3, b1, b2, b3):
|
|
378
|
+
global space
|
|
379
|
+
a1, a2, a3, b1, b2, b3 = [[item] for item in [a1, a2, a3, b1, b2, b3]]
|
|
380
|
+
line = [
|
|
381
|
+
line_sort(a1 + a2),
|
|
382
|
+
line_sort(b1 + b2),
|
|
383
|
+
line_sort(a1 + a3),
|
|
384
|
+
line_sort(b1 + b3),
|
|
385
|
+
]
|
|
386
|
+
angle = [space.standard_angle(a1 + a2 + a3), space.standard_angle(b1 + b2 + b3)]
|
|
387
|
+
|
|
388
|
+
for item in line:
|
|
389
|
+
if not space.valid_line(item):
|
|
390
|
+
return False
|
|
391
|
+
|
|
392
|
+
for item in angle:
|
|
393
|
+
if item is None:
|
|
394
|
+
return False
|
|
395
|
+
|
|
396
|
+
return (
|
|
397
|
+
space.line_eq_fx(line[0], line[1])
|
|
398
|
+
and space.angle_eq_fx(angle[0], angle[1])
|
|
399
|
+
and space.line_eq_fx(line[2], line[3])
|
|
400
|
+
and angle[0] in space.perpendicular_angle
|
|
401
|
+
)
|
|
402
|
+
def tri_sort(tri):
|
|
403
|
+
return tuple([ord(item)-ord("A") for item in tri])
|
|
404
|
+
def check_equal_angle(a, b):
|
|
405
|
+
global space
|
|
406
|
+
return space.angle_eq_fx(a, b)
|
|
407
|
+
def check_equal_line(a, b):
|
|
408
|
+
global space
|
|
409
|
+
return space.line_eq_fx(a, b)
|
|
410
|
+
def prove_congruent_triangle(tri1, tri2=None):
|
|
411
|
+
global space
|
|
412
|
+
if tri2 is None:
|
|
413
|
+
tri2 = tri1
|
|
414
|
+
list1 = list(itertools.permutations(list(tri_sort(tri1))))
|
|
415
|
+
list2 = list(itertools.permutations(list(tri_sort(tri2))))
|
|
416
|
+
for x in list1:
|
|
417
|
+
for y in list2:
|
|
418
|
+
a = list(x)
|
|
419
|
+
b = list(y)
|
|
420
|
+
for item in [a+b,b+a]:
|
|
421
|
+
for rule in [sss_rule, rhs_rule]:
|
|
422
|
+
out = rule(*item)
|
|
423
|
+
if out:
|
|
424
|
+
space.tri_eq.append([x, y])
|
|
425
|
+
space.tri_eq = merge_category(space.tri_eq, default_merge)
|
|
426
|
+
def process():
|
|
427
|
+
global space
|
|
428
|
+
space.calc_line_info()
|
|
429
|
+
space.calc_angle_list()
|
|
430
|
+
space.perpen_angle()
|
|
431
|
+
def split_line(line, p=None):
|
|
432
|
+
global space
|
|
433
|
+
line = line_sort(line)
|
|
434
|
+
a, b = space.point_location[line[0]], space.point_location[line[1]]
|
|
435
|
+
px = (a[0]+b[0])/2
|
|
436
|
+
py = (a[1]+b[1])/2
|
|
437
|
+
if p is not None:
|
|
438
|
+
px, py = p
|
|
439
|
+
space.point_location.append((px, py))
|
|
440
|
+
r = len(space.point_location)-1
|
|
441
|
+
for i in range(len(space.line_info)-1,-1,-1):
|
|
442
|
+
if line[0] in space.line_info[i] and line[1] in space.line_info[i]:
|
|
443
|
+
|
|
444
|
+
space.line_info[i] = space.line_info[i][:min(line)]+[len(space.point_location)-1]+space.line_info[i][max(line):]
|
|
445
|
+
|
|
446
|
+
return r
|
|
447
|
+
def extended_line(line):
|
|
448
|
+
global space
|
|
449
|
+
line = line_sort(line)
|
|
450
|
+
for i in range(len(space.line_info)):
|
|
451
|
+
if line[0] in space.line_info[i] and line[1] in space.line_info[i]:
|
|
452
|
+
self.line.append(i)
|
|
453
|
+
def join(line):
|
|
454
|
+
global space
|
|
455
|
+
line = line_sort(line)
|
|
456
|
+
space.line_info.append(line)
|
|
457
|
+
space.command.append(line)
|
|
458
|
+
def foot_of_perpendicular(P, A, B):
|
|
459
|
+
x0, y0 = P
|
|
460
|
+
x1, y1 = A
|
|
461
|
+
x2, y2 = B
|
|
462
|
+
dx = x2 - x1
|
|
463
|
+
dy = y2 - y1
|
|
464
|
+
t = ((x0 - x1) * dx + (y0 - y1) * dy) / (dx*dx + dy*dy)
|
|
465
|
+
x = x1 + t * dx
|
|
466
|
+
y = y1 + t * dy
|
|
467
|
+
return (x, y)
|
|
468
|
+
def draw_perpendicular(point, line):
|
|
469
|
+
global space
|
|
470
|
+
point = point_sort(point)
|
|
471
|
+
line = line_sort(line)
|
|
472
|
+
out = foot_of_perpendicular(space.point_location[point], space.point_location[line[0]], space.point_location[line[1]])
|
|
473
|
+
out2 = split_line(line, out)
|
|
474
|
+
m = line_sort((point, out2))
|
|
475
|
+
join(m)
|
|
476
|
+
space.perpendicular.append([m,line])
|
|
477
|
+
def show(size=None):
|
|
478
|
+
global space
|
|
479
|
+
space.show_diagram(size)
|
|
480
|
+
def norm_angle(angle):
|
|
481
|
+
global space
|
|
482
|
+
return space.standard_angle(angle)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
geometryai
|