squish/scripts/maxcenter.py
2024-10-22 19:06:05 -04:00

203 lines
4.9 KiB
Python

from __future__ import annotations
import matplotlib.pyplot as plt
import os, numpy as np
import cmath, math, pickle
def main():
with open("site_verts.pkl", "rb") as f:
sites, site_verts = pickle.load(f)
for i in range(400):
verts = [
as_complex(site_verts[i][j] - sites[i]) for j in range(len(site_verts[i]))
]
plot_2d(verts, f"squish_output/maxcenters_sim/{i:03}.png")
return
v = [
0.266 + 0.87j,
-0.626 + 0.747j,
-0.976 - 0.046j,
-0.283 - 0.873j,
0.676 - 0.447j,
0.875 + 0.414j,
]
# v = [v[0], v[1], v[3]]
line = np.linspace(-1, 1, 120)
line2 = np.linspace(-1, 1, 120)
X, Y = np.meshgrid(line, line2)
Z = np.empty(X.shape)
DZ = np.empty(X.shape, dtype="complex")
HZ = np.empty((X.shape[0], X.shape[1], 2, 2))
for i, x in enumerate(line):
for j, y in enumerate(line2):
rad, deriv, hess = average_radius(x + 1j * y, v, l)
Z[j][i] = rad
DZ[j][i] = deriv
HZ[j][i] = hess
max_indices = np.unravel_index(np.argmax(Z), Z.shape)
fig = plt.figure()
ax1 = fig.add_subplot(111, projection="3d")
ax1.contour(
X,
Y,
Z,
np.linspace(4, 5.7, 15),
rstride=1,
cstride=1,
cmap="viridis",
edgecolor="none",
)
ax1.scatter(X[max_indices], Y[max_indices], Z[max_indices])
cent = centroid(v, l)
maxcent = maxcenter(v, l)
ax1.scatter(cent.real, cent.imag, 3)
ax1.scatter(maxcent.real, maxcent.imag, 3)
print(maxcent)
print(abs(maxcent - cent))
ax1.view_init(elev=90, azim=270)
plt.show()
ax2 = fig.add_subplot(111, projection="3d")
ax2.contour(
X,
Y,
DZ.real,
np.linspace(-3, 3, 9),
rstride=1,
cstride=1,
cmap="viridis",
edgecolor="none",
)
ax2.contour(
X,
Y,
DZ.imag,
np.linspace(-3, 3, 9),
rstride=1,
cstride=1,
cmap="viridis",
edgecolor="none",
)
ax2.view_init(elev=90, azim=270)
ax2.scatter(X[max_indices], Y[max_indices], Z[max_indices])
# ax2.plot_surface(X, Y, DZy, rstride=1, cstride=1, cmap="viridis", edgecolor="none")
# for vert in v:
# ax.scatter(vert.real, vert.imag, 5)
plt.savefig("TestPolygonAverageRadius.png")
plt.show()
def plot_2d(v: List[complex], name: str):
l = get_l(v)
cent, maxcent = centroid(v, l), maxcenter(v, l)
fig, ax = plt.subplots(1, figsize=(8, 8))
for i in range(len(v)):
va, vap = v[i], v[(i + 1) % len(v)]
ax.plot([va.real, vap.real], [va.imag, vap.imag], color="black")
ax.scatter(cent.real, cent.imag, label="Centroid")
ax.scatter(maxcent.real, maxcent.imag, label="Maxcenter")
ax.legend()
ax.grid()
plt.savefig(name)
plt.close()
def get_l(v):
l = []
for i in range(len(v)):
l.append(v[(i + 1) % len(v)] - v[i])
return l
def generate_hexagon():
angles = np.sort(np.random.random_sample((6,)))
while np.any(np.diff(angles) >= 0.5):
angles = np.sort(np.random.random_sample((6,)))
angles *= 2 * math.pi
mags = np.random.random_sample((3,))
mags = np.array([mags[0], 1, mags[1], 1, mags[2], 1])
v = []
for mag, angle in zip(mags, angles):
v.append(cmath.rect(1, angle))
return v
def centroid(v, l):
area, cent = 0, 0
for i in range(len(v)):
jdi = v[i] * 1j
A = (jdi.conjugate() * l[i] + jdi * l[i].conjugate()) / 4
area += A
cent += (2 * v[i] + l[i]) * A
return (1 / (3 * area)) * cent
def average_radius(x, v, l):
radius, deriv, hess = [], [], []
for i in range(len(v)):
jdi = (v[i] - x) * 1j
A = (jdi.conjugate() * l[i] + jdi * l[i].conjugate()) / 2
k = -1j * l[i]
da, dap = v[i] - x, v[i] - x + l[i]
dau, dapu = da / abs(da), dap / abs(dap)
kcu = k.conjugate() / abs(k)
z, zp = kcu * dau, kcu * dapu
int_rad = 2 * (cmath.atan(zp) - cmath.atan(z)) / (1j * abs(k))
radius.append(A * int_rad)
deriv.append(-k * int_rad)
hess.append(np.dot(as_vector(k).T, as_vector(1j * (dapu - dau) / A)))
if True in [x.real < 0 for x in radius]:
return 0, 0, 0
else:
return sum(radius).real, sum(deriv), sum(hess)
def as_vector(c):
return np.atleast_2d(np.array([c.real, c.imag]))
def as_complex(v):
v = v.flatten()
return v[0] + 1j * v[1]
def maxcenter(v, l, delta=1e-8):
above_thres = True
x = centroid(v, l)
while above_thres:
rad, deriv, hess = average_radius(x, v, l)
above_thres = np.linalg.norm(deriv) > delta
x -= as_complex(as_vector(deriv).dot(np.linalg.inv(hess)))
return x
if __name__ == "__main__":
os.environ["QT_LOGGING_RULES"] = "*=false"
try:
main()
except KeyboardInterrupt:
print("Program terminated by user.")