-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconstructions_old.py
More file actions
154 lines (123 loc) · 5.87 KB
/
constructions_old.py
File metadata and controls
154 lines (123 loc) · 5.87 KB
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
147
148
149
150
151
152
153
154
"""
Constructions.py - Drawing and construction functions for geometric problems
This module provides functions to draw geometric objects and perform constructions
like finding midpoints, perpendiculars, angle bisectors, etc.
"""
import matplotlib.pyplot as plt
import numpy as np
from typing import Dict, Tuple, List
from relations import geometric
from Problem import GeometricProblem
import math
class GeometricConstructor:
"""
Class for drawing geometric constructions and performing geometric operations.
"""
def __init__(self):
self.fig, self.ax = plt.subplots(1, 1, figsize=(10, 8))
self.ax.set_aspect('equal')
self.ax.grid(True, alpha=0.3)
def draw_problem(self, problem: GeometricProblem):
"""Draw the complete geometric problem."""
self.draw_points(problem.points)
self.draw_lines(problem.lines)
self.draw_circles(problem.circles)
def draw_points(self, points: Dict[str, geometric.Point]):
"""Draw all points with labels."""
for name, point in points.items():
self.ax.plot(point.x, point.y, 'ko', markersize=6)
self.ax.annotate(name, (point.x, point.y),
xytext=(5, 5), textcoords='offset points',
fontsize=12, fontweight='bold')
def draw_lines(self, lines: Dict[str, Tuple[float, float, float]]):
"""Draw lines from ax + by + c = 0 format."""
for name, (a, b, c) in lines.items():
# Get current axis limits to draw line across visible area
xlim = self.ax.get_xlim()
ylim = self.ax.get_ylim()
if abs(b) > 1e-10: # Not vertical line
x_vals = np.array([xlim[0] - 1, xlim[1] + 1])
y_vals = -(a * x_vals + c) / b
else: # Vertical line
x_vals = np.array([-c/a, -c/a])
y_vals = np.array([ylim[0] - 1, ylim[1] + 1])
self.ax.plot(x_vals, y_vals, 'b-', linewidth=1.5, alpha=0.7)
def draw_circles(self, circles: Dict[str, Tuple[float, float, float]]):
"""Draw circles from (cx, cy, r) format."""
for name, (cx, cy, r) in circles.items():
circle = plt.Circle((cx, cy), r, fill=False, color='red', linewidth=2)
self.ax.add_patch(circle)
def construct_midpoint(self, p1: geometric.Point, p2: geometric.Point, name: str = None) -> geometric.Point:
"""Construct the midpoint of two points."""
if name is None:
name = f"M_{p1.name}{p2.name}"
mx = (p1.x + p2.x) / 2
my = (p1.y + p2.y) / 2
midpoint = geometric.Point(name, mx, my)
# Draw the midpoint
self.ax.plot(mx, my, 'ro', markersize=8)
self.ax.annotate(name, (mx, my),
xytext=(5, 5), textcoords='offset points',
fontsize=12, fontweight='bold', color='red')
return midpoint
def construct_perpendicular(self, p1: geometric.Point, p2: geometric.Point,
through_point: geometric.Point) -> Tuple[float, float, float]:
"""Construct perpendicular line through a point to line p1p2."""
# Direction vector of line p1p2
dx = p2.x - p1.x
dy = p2.y - p1.y
# Perpendicular direction vector
perp_dx = -dy
perp_dy = dx
# Line equation: perp_dx * (x - through_point.x) + perp_dy * (y - through_point.y) = 0
# Expanding: perp_dx * x + perp_dy * y - (perp_dx * through_point.x + perp_dy * through_point.y) = 0
a = perp_dx
b = perp_dy
c = -(perp_dx * through_point.x + perp_dy * through_point.y)
return (a, b, c)
def construct_angle_bisector(self, p1: geometric.Point, vertex: geometric.Point,
p2: geometric.Point) -> Tuple[float, float, float]:
"""Construct the angle bisector of angle p1-vertex-p2."""
# Vectors from vertex to p1 and p2
v1x, v1y = p1.x - vertex.x, p1.y - vertex.y
v2x, v2y = p2.x - vertex.x, p2.y - vertex.y
# Normalize vectors
len1 = math.sqrt(v1x**2 + v1y**2)
len2 = math.sqrt(v2x**2 + v2y**2)
if len1 > 1e-10:
v1x, v1y = v1x/len1, v1y/len1
if len2 > 1e-10:
v2x, v2y = v2x/len2, v2y/len2
# Bisector direction
bx, by = v1x + v2x, v1y + v2y
# Line equation through vertex with direction (bx, by)
# by * (x - vertex.x) - bx * (y - vertex.y) = 0
a = by
b = -bx
c = bx * vertex.y - by * vertex.x
return (a, b, c)
def construct_parallel_line(self, p1: geometric.Point, p2: geometric.Point,
through_point: geometric.Point) -> Tuple[float, float, float]:
"""Construct line parallel to p1p2 through given point."""
# Direction vector of line p1p2
dx = p2.x - p1.x
dy = p2.y - p1.y
# Parallel line has same direction
# Line equation: dy * (x - through_point.x) - dx * (y - through_point.y) = 0
a = dy
b = -dx
c = dx * through_point.y - dy * through_point.x
return (a, b, c)
def show_construction(self, title: str = "Geometric Construction"):
"""Display the construction."""
self.ax.set_title(title, fontsize=14, fontweight='bold')
plt.tight_layout()
plt.show()
def save_construction(self, filename: str):
"""Save the construction to a file."""
plt.savefig(filename, dpi=300, bbox_inches='tight')
def clear_construction(self):
"""Clear the current construction."""
self.ax.clear()
self.ax.set_aspect('equal')
self.ax.grid(True, alpha=0.3)