Spaces:
Sleeping
Sleeping
Upload 2 files
Browse files
ag4masses/alphageometry/graph.py
CHANGED
@@ -2773,7 +2773,7 @@ class Graph:
|
|
2773 |
|
2774 |
# not necessary for proofing, but for visualization.
|
2775 |
c_args = list(map(lambda x: self.get(x, lambda: int(x)), c.args))
|
2776 |
-
self.additionally_draw(c.name, c_args)
|
2777 |
|
2778 |
for points, bs in cdef.basics:
|
2779 |
if points:
|
|
|
2773 |
|
2774 |
# not necessary for proofing, but for visualization.
|
2775 |
c_args = list(map(lambda x: self.get(x, lambda: int(x)), c.args))
|
2776 |
+
# self.additionally_draw(c.name, c_args)
|
2777 |
|
2778 |
for points, bs in cdef.basics:
|
2779 |
if points:
|
ag4masses/alphageometry/numericals.py
CHANGED
@@ -18,6 +18,7 @@ from __future__ import annotations
|
|
18 |
|
19 |
import math
|
20 |
from typing import Any, Optional, Union
|
|
|
21 |
|
22 |
import geometry as gm
|
23 |
import matplotlib
|
@@ -26,8 +27,10 @@ import matplotlib.colors as mcolors
|
|
26 |
import numpy as np
|
27 |
from numpy.random import uniform as unif # pylint: disable=g-importing-member
|
28 |
import graph as gh
|
|
|
|
|
29 |
|
30 |
-
matplotlib.use('
|
31 |
|
32 |
|
33 |
ATOM = 1e-12
|
@@ -440,72 +443,72 @@ class Circle:
|
|
440 |
|
441 |
|
442 |
class SemiCircle(Circle):
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
|
510 |
|
511 |
class HoleCircle(Circle):
|
@@ -789,7 +792,7 @@ def check_perp(points: list[Point]) -> bool:
|
|
789 |
|
790 |
def check_cyclic(points: list[Point]) -> bool:
|
791 |
points = list(set(points))
|
792 |
-
(a, b, c, *ps)
|
793 |
circle = Circle(p1=a, p2=b, p3=c)
|
794 |
for d in ps:
|
795 |
if not close_enough(d.distance(circle.center), circle.radius):
|
@@ -975,7 +978,7 @@ def draw_angle(
|
|
975 |
|
976 |
|
977 |
def naming_position(
|
978 |
-
ax: matplotlib.axes.Axes, p: Point, lines: list[Line], circles: list[Circle]
|
979 |
) -> tuple[float, float]:
|
980 |
"""Figure out a good naming position on the drawing."""
|
981 |
_ = ax
|
@@ -1034,7 +1037,7 @@ def draw_point(
|
|
1034 |
name = name[0] + '_' + name[1:]
|
1035 |
|
1036 |
ax.annotate(
|
1037 |
-
name, naming_position(ax, p, lines, circles), color=color, fontsize=15
|
1038 |
)
|
1039 |
|
1040 |
|
@@ -1106,6 +1109,7 @@ def draw_circle(
|
|
1106 |
ax: matplotlib.axes.Axes, circle: Circle, color: Any = 'cyan'
|
1107 |
) -> Circle:
|
1108 |
"""Draw a circle."""
|
|
|
1109 |
if circle.num is not None:
|
1110 |
circle = circle.num
|
1111 |
else:
|
@@ -1113,11 +1117,14 @@ def draw_circle(
|
|
1113 |
if len(points) <= 2:
|
1114 |
return
|
1115 |
points = [p.num for p in points]
|
|
|
1116 |
p1, p2, p3 = points[:3]
|
1117 |
circle = Circle(p1=p1, p2=p2, p3=p3)
|
1118 |
-
|
1119 |
-
|
1120 |
-
|
|
|
|
|
1121 |
|
1122 |
def check_points_semicircle(p1, p2, p3):
|
1123 |
"""
|
@@ -1175,7 +1182,7 @@ def check_points_semicircle(p1, p2, p3):
|
|
1175 |
}
|
1176 |
|
1177 |
def _draw_semicircle(
|
1178 |
-
ax: matplotlib.axes.Axes, P1: Point, P2: Point, P3: Point, color: Any = 'cyan', lw: float = 1.2
|
1179 |
) -> None:
|
1180 |
"""
|
1181 |
Draws a semicircle passing through three points or with one or two points on the diameter.
|
@@ -1186,45 +1193,71 @@ def _draw_semicircle(
|
|
1186 |
color (Any): Color of the semicircle.
|
1187 |
lw (float): Line width of the semicircle.
|
1188 |
"""
|
1189 |
-
|
1190 |
-
if
|
1191 |
-
|
1192 |
-
|
1193 |
-
|
1194 |
-
|
1195 |
-
|
1196 |
-
|
1197 |
-
|
1198 |
-
|
1199 |
-
|
1200 |
-
|
1201 |
-
|
1202 |
-
|
1203 |
-
|
1204 |
-
|
1205 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1206 |
|
1207 |
-
|
1208 |
-
|
1209 |
-
|
1210 |
-
|
1211 |
-
|
1212 |
-
|
1213 |
-
|
1214 |
-
|
1215 |
-
|
1216 |
-
|
1217 |
-
|
1218 |
-
|
1219 |
-
|
1220 |
-
|
1221 |
-
|
1222 |
-
|
1223 |
-
|
1224 |
-
|
1225 |
-
|
1226 |
-
|
1227 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1228 |
|
1229 |
def draw_semicircle(
|
1230 |
ax: matplotlib.axes.Axes, semicircle: SemiCircle, color: Any = 'cyan'
|
@@ -1296,7 +1329,6 @@ def highlight(
|
|
1296 |
_draw_line(ax, c, d, color=color2, lw=2.0)
|
1297 |
if name == 'eqangle':
|
1298 |
a, b, c, d, e, f, g, h = args
|
1299 |
-
|
1300 |
x = line_line_intersection(Line(a, b), Line(c, d))
|
1301 |
if b.distance(x) > a.distance(x):
|
1302 |
a, b = b, a
|
@@ -1343,12 +1375,37 @@ def highlight(
|
|
1343 |
_draw_line(ax, c, d, color=color2, lw=2.0, alpha=0.5)
|
1344 |
_draw_line(ax, m, n, color=color1, lw=2.0, alpha=0.5)
|
1345 |
_draw_line(ax, p, q, color=color2, lw=2.0, alpha=0.5)
|
1346 |
-
|
1347 |
-
|
1348 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1349 |
|
1350 |
HCOLORS = None
|
1351 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1352 |
|
1353 |
def _draw(
|
1354 |
ax: matplotlib.axes.Axes,
|
@@ -1362,6 +1419,7 @@ def _draw(
|
|
1362 |
):
|
1363 |
"""Draw everything."""
|
1364 |
colors = ['red', 'green', 'blue', 'orange', 'magenta', 'purple']
|
|
|
1365 |
pcolor = 'black'
|
1366 |
lcolor = 'black'
|
1367 |
ccolor = 'grey'
|
@@ -1374,15 +1432,45 @@ def _draw(
|
|
1374 |
colors = ['grey']
|
1375 |
|
1376 |
line_boundaries = []
|
|
|
|
|
|
|
|
|
1377 |
for l in lines:
|
1378 |
p1, p2 = draw_line(ax, l, color=lcolor)
|
1379 |
line_boundaries.append((p1, p2))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1380 |
circles = [draw_circle(ax, c, color=ccolor) for c in circles]
|
1381 |
semicircles = [draw_semicircle(ax, c, color=ccolor) for c in semicircles]
|
1382 |
|
1383 |
for p in points:
|
1384 |
draw_point(ax, p.num, p.name, line_boundaries, circles, semicircles, color=pcolor)
|
1385 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1386 |
if equals:
|
1387 |
for i, segs in enumerate(equals['segments']):
|
1388 |
color = colors[i % len(colors)]
|
@@ -1947,6 +2035,9 @@ def sketch_midp(args: tuple[gm.Point, ...]) -> Point:
|
|
1947 |
a, b = args
|
1948 |
return (a + b) * 0.5
|
1949 |
|
|
|
|
|
|
|
1950 |
|
1951 |
def sketch_pentagon(args: tuple[gm.Point, ...]) -> tuple[Point, ...]:
|
1952 |
points = [Point(1.0, 0.0)]
|
|
|
18 |
|
19 |
import math
|
20 |
from typing import Any, Optional, Union
|
21 |
+
import random
|
22 |
|
23 |
import geometry as gm
|
24 |
import matplotlib
|
|
|
27 |
import numpy as np
|
28 |
from numpy.random import uniform as unif # pylint: disable=g-importing-member
|
29 |
import graph as gh
|
30 |
+
from collections import defaultdict
|
31 |
+
from itertools import combinations
|
32 |
|
33 |
+
matplotlib.use('TkAgg')
|
34 |
|
35 |
|
36 |
ATOM = 1e-12
|
|
|
443 |
|
444 |
|
445 |
class SemiCircle(Circle):
|
446 |
+
"""Numerical semicircle, inherits from Circle."""
|
447 |
+
|
448 |
+
def __init__(
|
449 |
+
self,
|
450 |
+
center: Optional[Point] = None,
|
451 |
+
radius: Optional[float] = None,
|
452 |
+
p1: Optional[Point] = None,
|
453 |
+
p2: Optional[Point] = None,
|
454 |
+
p3: Optional[Point] = None,
|
455 |
+
):
|
456 |
+
self.p1 = p1
|
457 |
+
self.p2 = p2
|
458 |
+
self.p3 = p3
|
459 |
+
# Initialize as a Circle
|
460 |
+
super().__init__(center, radius, p1, p2, p3)
|
461 |
+
# If p1 and p2 define a diameter, set the center and radius accordingly
|
462 |
+
if p1 and p2 and not center:
|
463 |
+
self.center = Point((p1.x + p2.x) / 2, (p1.y + p2.y) / 2)
|
464 |
+
self.radius = p1.distance(p2) / 2
|
465 |
+
self.r2 = self.radius ** 2
|
466 |
+
|
467 |
+
# Define the direction or plane for the semicircle (important for sampling and boundaries)
|
468 |
+
|
469 |
+
def is_within_boundary(self, point: Point) -> bool:
|
470 |
+
"""Check if a point is within the boundary of the semicircle."""
|
471 |
+
vector_to_point = point - self.center
|
472 |
+
angle = math.atan2(vector_to_point.y, vector_to_point.x)
|
473 |
+
|
474 |
+
# Normalize the angle within [0, 2*pi]
|
475 |
+
angle = angle if angle >= 0 else (2 * np.pi + angle)
|
476 |
+
|
477 |
+
# Check if the point is within the semicircle (half of the circle)
|
478 |
+
return -np.pi / 2 <= angle <= np.pi / 2
|
479 |
+
|
480 |
+
def sample_within(self, points: list[Point], n: int = 5) -> list[Point]:
|
481 |
+
"""Sample a point within the semicircle."""
|
482 |
+
result = None
|
483 |
+
best = -1.0
|
484 |
+
for _ in range(n):
|
485 |
+
# Generate a random angle between -π/2 and π/2 for the semicircle
|
486 |
+
ang = unif(-0.5, 0.5) * np.pi
|
487 |
+
x = self.center + Point(np.cos(ang), np.sin(ang)) * self.radius
|
488 |
+
|
489 |
+
# Check if the sampled point is within the active part of the semicircle
|
490 |
+
if not self.is_within_boundary(x):
|
491 |
+
continue
|
492 |
+
|
493 |
+
# Find the minimum distance between the generated point and the provided points
|
494 |
+
mind = min([x.distance(p) for p in points])
|
495 |
+
if mind > best:
|
496 |
+
best = mind
|
497 |
+
result = x
|
498 |
+
|
499 |
+
return [result]
|
500 |
+
|
501 |
+
def intersect(self, obj: Union[Line, Circle]) -> tuple[Point, ...]:
|
502 |
+
"""Find intersection points with a Line or another Circle, constrained to the semicircle."""
|
503 |
+
if isinstance(obj, Line):
|
504 |
+
intersections = obj.intersect(self)
|
505 |
+
elif isinstance(obj, Circle):
|
506 |
+
intersections = circle_circle_intersection(self, obj)
|
507 |
+
else:
|
508 |
+
return tuple()
|
509 |
+
|
510 |
+
# Filter intersections to only return points within the semicircle
|
511 |
+
return tuple(p for p in intersections if self.is_within_boundary(p))
|
512 |
|
513 |
|
514 |
class HoleCircle(Circle):
|
|
|
792 |
|
793 |
def check_cyclic(points: list[Point]) -> bool:
|
794 |
points = list(set(points))
|
795 |
+
(a, b, c, *ps) = points
|
796 |
circle = Circle(p1=a, p2=b, p3=c)
|
797 |
for d in ps:
|
798 |
if not close_enough(d.distance(circle.center), circle.radius):
|
|
|
978 |
|
979 |
|
980 |
def naming_position(
|
981 |
+
ax: matplotlib.axes.Axes, p: Point, lines: list[Line], circles: list[Circle], semicircles: list[SemiCircle]
|
982 |
) -> tuple[float, float]:
|
983 |
"""Figure out a good naming position on the drawing."""
|
984 |
_ = ax
|
|
|
1037 |
name = name[0] + '_' + name[1:]
|
1038 |
|
1039 |
ax.annotate(
|
1040 |
+
name, naming_position(ax, p, lines, circles, semicircles), color=color, fontsize=15
|
1041 |
)
|
1042 |
|
1043 |
|
|
|
1109 |
ax: matplotlib.axes.Axes, circle: Circle, color: Any = 'cyan'
|
1110 |
) -> Circle:
|
1111 |
"""Draw a circle."""
|
1112 |
+
name_circle = circle.name
|
1113 |
if circle.num is not None:
|
1114 |
circle = circle.num
|
1115 |
else:
|
|
|
1117 |
if len(points) <= 2:
|
1118 |
return
|
1119 |
points = [p.num for p in points]
|
1120 |
+
print(len(points))
|
1121 |
p1, p2, p3 = points[:3]
|
1122 |
circle = Circle(p1=p1, p2=p2, p3=p3)
|
1123 |
+
if "," in name_circle:
|
1124 |
+
_draw_circle(ax, circle, color)
|
1125 |
+
return circle
|
1126 |
+
else:
|
1127 |
+
return circle
|
1128 |
|
1129 |
def check_points_semicircle(p1, p2, p3):
|
1130 |
"""
|
|
|
1182 |
}
|
1183 |
|
1184 |
def _draw_semicircle(
|
1185 |
+
ax: matplotlib.axes.Axes, P1: Point = None, P2: Point = None, P3: Point = None, color: Any = 'cyan', lw: float = 1.2
|
1186 |
) -> None:
|
1187 |
"""
|
1188 |
Draws a semicircle passing through three points or with one or two points on the diameter.
|
|
|
1193 |
color (Any): Color of the semicircle.
|
1194 |
lw (float): Line width of the semicircle.
|
1195 |
"""
|
1196 |
+
points = [P for P in (P1, P2, P3) if P is not None] # Filter out None values
|
1197 |
+
if len(points) == 2:
|
1198 |
+
cx = (P1.x + P2.x) / 2
|
1199 |
+
cy = (P1.y + P2.y) / 2
|
1200 |
+
radius = np.sqrt((P2.x - P1.x) ** 2 + (P2.y - P1.y) ** 2) / 2
|
1201 |
+
|
1202 |
+
# Compute angle of the diameter
|
1203 |
+
angle_diameter = np.arctan2(P2.y - P1.y, P2.x - P1.x)
|
1204 |
+
|
1205 |
+
# Randomly determine the orientation of the semicircle
|
1206 |
+
offset_angle = np.pi / 2 if random.choice([True, False]) else -np.pi / 2
|
1207 |
+
|
1208 |
+
# Start and end angles for the semicircle
|
1209 |
+
start_angle = angle_diameter + offset_angle
|
1210 |
+
end_angle = start_angle + np.pi
|
1211 |
+
|
1212 |
+
# Generate points for the semicircle
|
1213 |
+
t = np.linspace(start_angle, end_angle, 100)
|
1214 |
+
x = cx + radius * np.cos(t)
|
1215 |
+
y = cy + radius * np.sin(t)
|
1216 |
+
|
1217 |
+
# Plot the semicircle
|
1218 |
+
ax.plot(x, y, color=color, lw=lw)
|
1219 |
+
|
1220 |
+
if len(points) == 3:
|
1221 |
|
1222 |
+
result = check_points_semicircle((P1.x, P1.y), (P2.x, P2.y), (P3.x, P3.y))
|
1223 |
+
if not result['is_valid']:
|
1224 |
+
print("Points are collinear; cannot form a semicircle.")
|
1225 |
+
return
|
1226 |
+
|
1227 |
+
cx, cy = result['center']
|
1228 |
+
radius = result['radius']
|
1229 |
+
diameter_points = result['diameter_points']
|
1230 |
+
|
1231 |
+
# If no pair forms a diameter, determine angles for all three points
|
1232 |
+
if diameter_points is None:
|
1233 |
+
# Calculate angles of all three points relative to the circle's center
|
1234 |
+
angles = np.arctan2(
|
1235 |
+
[P1.y - cy, P2.y - cy, P3.y - cy],
|
1236 |
+
[P1.x - cx, P2.x - cx, P3.x - cx]
|
1237 |
+
)
|
1238 |
+
angles = (angles + 2 * np.pi) % (2 * np.pi) # Normalize to [0, 2π]
|
1239 |
+
|
1240 |
+
# Determine the start and end angle for the semicircle
|
1241 |
+
start_angle = np.min(angles)
|
1242 |
+
end_angle = np.max(angles)
|
1243 |
+
if end_angle - start_angle > np.pi:
|
1244 |
+
start_angle, end_angle = end_angle, start_angle + 2 * np.pi
|
1245 |
+
else:
|
1246 |
+
# Use diameter points to define the semicircle angles
|
1247 |
+
px, py = diameter_points[0]
|
1248 |
+
qx, qy = diameter_points[1]
|
1249 |
+
start_angle = np.arctan2(py - cy, px - cx)
|
1250 |
+
end_angle = np.arctan2(qy - cy, qx - cx)
|
1251 |
+
if end_angle - start_angle > np.pi:
|
1252 |
+
start_angle, end_angle = end_angle, start_angle + 2 * np.pi
|
1253 |
+
|
1254 |
+
# Generate points for the semicircle
|
1255 |
+
t = np.linspace(start_angle, end_angle, 100)
|
1256 |
+
x = cx + radius * np.cos(t)
|
1257 |
+
y = cy + radius * np.sin(t)
|
1258 |
+
|
1259 |
+
# Plot the semicircle
|
1260 |
+
ax.plot(x, y, color=color, lw=lw)
|
1261 |
|
1262 |
def draw_semicircle(
|
1263 |
ax: matplotlib.axes.Axes, semicircle: SemiCircle, color: Any = 'cyan'
|
|
|
1329 |
_draw_line(ax, c, d, color=color2, lw=2.0)
|
1330 |
if name == 'eqangle':
|
1331 |
a, b, c, d, e, f, g, h = args
|
|
|
1332 |
x = line_line_intersection(Line(a, b), Line(c, d))
|
1333 |
if b.distance(x) > a.distance(x):
|
1334 |
a, b = b, a
|
|
|
1375 |
_draw_line(ax, c, d, color=color2, lw=2.0, alpha=0.5)
|
1376 |
_draw_line(ax, m, n, color=color1, lw=2.0, alpha=0.5)
|
1377 |
_draw_line(ax, p, q, color=color2, lw=2.0, alpha=0.5)
|
1378 |
+
if name == 'iso_triangle':
|
1379 |
+
a, b, c = args
|
1380 |
+
_draw_line(ax, c, b, color=color1, lw=2.0)
|
1381 |
+
_draw_line(ax, c, a, color=color1, lw=2.0)
|
1382 |
+
_draw_line(ax, b, a, color=color2, lw=2.0)
|
1383 |
+
if name == 'semicircle':
|
1384 |
+
o, a, b, c = args
|
1385 |
+
_draw_semicircle(ax, SemiCircle(center=o, p1=a, p2=b, p3=c), color=color1, lw=2.0)
|
1386 |
+
|
1387 |
+
def convert_point(gm_point: gm.Point) -> Point:
|
1388 |
+
return Point(gm_point.num.x, gm_point.num.y)
|
1389 |
|
1390 |
HCOLORS = None
|
1391 |
|
1392 |
+
def find_pairs_with_same_distance(line_lengths):
|
1393 |
+
# Step 1: Group point pairs by distance
|
1394 |
+
distance_groups = defaultdict(list)
|
1395 |
+
for (p1, p2), distance in line_lengths.items():
|
1396 |
+
distance_groups[distance].append((p1, p2))
|
1397 |
+
|
1398 |
+
# Step 2: Find combinations of pairs with the same distance
|
1399 |
+
result = []
|
1400 |
+
for pairs in distance_groups.values():
|
1401 |
+
if len(pairs) > 1: # Only consider distances with multiple pairs
|
1402 |
+
for i in range(len(pairs)):
|
1403 |
+
for j in range(i + 1, len(pairs)):
|
1404 |
+
line1 = pairs[i]
|
1405 |
+
line2 = pairs[j]
|
1406 |
+
result.append((line1, line2)) # Group as ((p1, p2), (p3, p4))
|
1407 |
+
|
1408 |
+
return result
|
1409 |
|
1410 |
def _draw(
|
1411 |
ax: matplotlib.axes.Axes,
|
|
|
1419 |
):
|
1420 |
"""Draw everything."""
|
1421 |
colors = ['red', 'green', 'blue', 'orange', 'magenta', 'purple']
|
1422 |
+
colors_highlight = [color for color in mcolors.TABLEAU_COLORS.keys() if color not in colors]
|
1423 |
pcolor = 'black'
|
1424 |
lcolor = 'black'
|
1425 |
ccolor = 'grey'
|
|
|
1432 |
colors = ['grey']
|
1433 |
|
1434 |
line_boundaries = []
|
1435 |
+
line_lengths = {}
|
1436 |
+
# Convert all points
|
1437 |
+
for p in points:
|
1438 |
+
points_numericals = [convert_point(p) for p in points]
|
1439 |
for l in lines:
|
1440 |
p1, p2 = draw_line(ax, l, color=lcolor)
|
1441 |
line_boundaries.append((p1, p2))
|
1442 |
+
points_numericals.append(p1)
|
1443 |
+
points_numericals.append(p2)
|
1444 |
+
unique_points = []
|
1445 |
+
seen = set()
|
1446 |
+
for p in points_numericals:
|
1447 |
+
if (p.x, p.y) not in seen:
|
1448 |
+
unique_points.append(p)
|
1449 |
+
seen.add((p.x, p.y))
|
1450 |
+
print(len(unique_points))
|
1451 |
+
for p1, p2 in combinations(unique_points, 2):
|
1452 |
+
line_lengths[(p1, p2)] = round(p1.distance(p2), 9)
|
1453 |
circles = [draw_circle(ax, c, color=ccolor) for c in circles]
|
1454 |
semicircles = [draw_semicircle(ax, c, color=ccolor) for c in semicircles]
|
1455 |
|
1456 |
for p in points:
|
1457 |
draw_point(ax, p.num, p.name, line_boundaries, circles, semicircles, color=pcolor)
|
1458 |
|
1459 |
+
same_length_pairs = find_pairs_with_same_distance(line_lengths)
|
1460 |
+
print(len(same_length_pairs))
|
1461 |
+
|
1462 |
+
length_color_map = {} # Dictionary to map length to its color
|
1463 |
+
for i, ((p1, p2), (p3, p4)) in enumerate(same_length_pairs):
|
1464 |
+
line_length = p1.distance(p2) # Calculate the length of the line
|
1465 |
+
if line_length not in length_color_map: # Check if length is already in the dictionary
|
1466 |
+
#color = colors_highlight[i % len(colors_highlight)]
|
1467 |
+
color = colors_highlight[i % len(colors_highlight) ] # Assign a new color
|
1468 |
+
length_color_map[line_length] = color # Store the length and color in the dictionary
|
1469 |
+
else:
|
1470 |
+
color = length_color_map[line_length] # Use the existing color for this length
|
1471 |
+
|
1472 |
+
# Call the highlight function with the determined color
|
1473 |
+
highlight(ax, 'cong', [p1, p2, p3, p4], lcolor, color, color)
|
1474 |
if equals:
|
1475 |
for i, segs in enumerate(equals['segments']):
|
1476 |
color = colors[i % len(colors)]
|
|
|
2035 |
a, b = args
|
2036 |
return (a + b) * 0.5
|
2037 |
|
2038 |
+
def sketch_foot(args: tuple[gm.Point, ...]) -> Point:
|
2039 |
+
a, b, c = args
|
2040 |
+
return a.foot(Line(b, c))
|
2041 |
|
2042 |
def sketch_pentagon(args: tuple[gm.Point, ...]) -> tuple[Point, ...]:
|
2043 |
points = [Point(1.0, 0.0)]
|