import numpy as np
import matplotlib.pyplot as plt
The tangent grid is defined by the family of tangent lines to the hyperbola. Initially, attempts were made using gradients and shear transformations, but these approaches did not yield satisfactory results. The current approach uses a parametric transformation based on the geometry of the hyperbola and its tangent lines.
The first approach involved using the gradient of the hyperbola to project shapes onto its tangent grid. The gradient of the hyperbola $y = \frac{b}{a} \sqrt{x^2 - a^2}$ is given by: $$ \frac{dy}{dx} = \frac{b^2 x}{a^2 y}. $$ Shear transformations were attempted to align the circle with the tangent grid. A shear transformation is defined as: $$ \begin{pmatrix} x' \\ y' \end{pmatrix} = \begin{pmatrix} 1 & k \\ 0 & 1 \end{pmatrix} \begin{pmatrix} x \\ y \end{pmatrix}, $$ where $k$ is the shear factor, which is the derivative. While this approach worked for simple curves, it failed to account for the curvature of the hyperbola, resulting in distorted and inaccurate projections, and, this approach also led to numerical instability near the asymptotes of the hyperbola (where $y \approx 0$), causing division by zero and incorrect projections.
The hyperbola is defined parametrically as: $$ x = a \cosh(t), \quad y = b \sinh(t), $$ where $a$ and $b$ are the semi-major and semi-minor axes, respectively. The derivative of the hyperbola is: $$ \frac{dx}{dt} = a \sinh(t), \quad \frac{dy}{dt} = b \cosh(t). $$ At a point $t$ on the hyperbola, the tangent line is given by: $$ y = \frac{b \cosh(t)}{a \sinh(t)} (x - a \cosh(t)) + b \sinh(t). $$
A coordinate system $(t, v)$ is defined, where:
The transformation from $(t, v)$ to Cartesian coordinates $(x, y)$ is: $$ x = a \cosh(t) + v \cdot a \sinh(t), \quad y = b \sinh(t) + v \cdot b \cosh(t). $$
A circle in $(t, v)$ space is defined by: $$ (t - p)^2 + (v - q)^2 = r^2, $$ where $(p, q)$ is the center and $r$ is the radius. Applying the transformation: $$ x = a \cosh(t) + v \cdot a \sinh(t), \quad y = b \sinh(t) + v \cdot b \cosh(t), $$ the circle is projected onto the tangent grid of the hyperbola. The resulting shape is a distorted version of the original circle, often resembling a cardioid or other interesting curves.
# THIS IS THE GRID FORMED BY THE TANGENTS
# LOOKS BEAUTIFUL
a = 3
b = 2
def curve(t):
return a * np.cosh(t), b * np.sinh(t)
def derivative(t):
return a * np.sinh(t), b * np.cosh(t)
t_values = np.linspace(-3.5, 3.5, 50)
t_smooth = np.linspace(-3.5, 3.5, 400)
x_curve, y_curve = curve(t_smooth)
fig, ax = plt.subplots(figsize=(10, 8))
ax.plot(x_curve, y_curve, 'k', linewidth=2)
ax.plot(-x_curve, y_curve, 'k', linewidth=2)
threshold = 1e-5
tangent_length = 100
for t in t_values:
x_t, y_t = curve(t)
dx, dy = derivative(t)
if abs(dx) > threshold:
tangent_x = np.linspace(x_t - tangent_length, x_t + tangent_length, 2)
tangent_y = y_t + (dy/dx) * (tangent_x - x_t)
color = 'red' if t < 0 else 'purple'
ax.plot(tangent_x, tangent_y, color=color, linewidth=1)
ax.plot(x_t, y_t, 'bo', markersize=4)
x_t_neg, y_t_neg = -x_t, y_t
dx_neg, dy_neg = -dx, dy
if abs(dx_neg) > threshold:
tangent_x_neg = np.linspace(x_t_neg - tangent_length, x_t_neg + tangent_length, 2)
tangent_y_neg = y_t_neg + (dy_neg/dx_neg) * (tangent_x_neg - x_t_neg)
color = 'red' if t < 0 else 'purple'
ax.plot(tangent_x_neg, tangent_y_neg, color=color, linewidth=1)
ax.plot(x_t_neg, y_t_neg, 'bo', markersize=4)
ax.set_xlim(-5, 5)
ax.set_ylim(-5, 5)
ax.axhline(0, color='black', linewidth=0.5)
ax.axvline(0, color='black', linewidth=0.5)
ax.set_title("the tangent grid (this looks amazing)")
ax.grid(True, alpha=0.3)
ax.set_aspect('equal', adjustable='box')
plt.tight_layout()
plt.show()
def hyperbola(t):
return np.cosh(t), np.sinh(t)
def hyperbola_derivative(t):
return np.sinh(t), np.cosh(t)
def transform(t, v):
x = np.cosh(t) + v * np.sinh(t)
y = np.sinh(t) + v * np.cosh(t)
return x, y
t_values = np.linspace(-3, 3, 400)
x_hyperbola, y_hyperbola = hyperbola(t_values)
fig, ax = plt.subplots(figsize=(10, 8))
ax.plot(x_hyperbola, y_hyperbola, 'k', linewidth=2, label="Hyperbola")
ax.plot(-x_hyperbola, y_hyperbola, 'k', linewidth=2)
tangent_length = 100
t_tangent_points = np.linspace(-3, 3, 50)
for t in t_tangent_points:
x_t, y_t = hyperbola(t)
dx, dy = hyperbola_derivative(t)
tangent_x = np.linspace(x_t - tangent_length, x_t + tangent_length, 2)
tangent_y = y_t + (dy / dx) * (tangent_x - x_t)
color = 'red' if t < 0 else 'purple'
ax.plot(tangent_x, tangent_y, color=color, linewidth=1)
ax.plot(x_t, y_t, 'bo', markersize=4)
x_t_neg, y_t_neg = -x_t, y_t
dx_neg, dy_neg = -dx, dy
tangent_x_neg = np.linspace(x_t_neg - tangent_length, x_t_neg + tangent_length, 2)
tangent_y_neg = y_t_neg + (dy_neg / dx_neg) * (tangent_x_neg - x_t_neg)
ax.plot(tangent_x_neg, tangent_y_neg, color=color, linewidth=1)
ax.plot(x_t_neg, y_t_neg, 'bo', markersize=4)
radii = [0.2, 0.4, 0.6, 0.8]
centers = [(1.5, 0), (-1.5, 0), (0, 1.5), (0, -1.5)]
theta = np.linspace(0, 2 * np.pi, 100)
for center in centers:
for radius in radii:
t_circle = center[0] + radius * np.cos(theta)
v_circle = center[1] + radius * np.sin(theta)
x_proj, y_proj = transform(t_circle, v_circle)
ax.plot(t_circle, v_circle, color="blue", alpha=0.5)
ax.plot(x_proj, y_proj, color="black", linestyle='-', alpha=0.8)
ax.set_xlim(-2, 2)
ax.set_ylim(-2, 2)
ax.axhline(0, color='black', linewidth=0.5)
ax.axvline(0, color='black', linewidth=0.5)
ax.set_title("Hyperbolic Tangent Grid with Concentric Circle Projections")
ax.grid(True, alpha=0.3)
ax.set_aspect('equal', adjustable='box')
plt.tight_layout()
plt.show()