|
import os |
|
|
|
import matplotlib.pyplot as plt |
|
import numpy as np |
|
|
|
|
|
def generate_dynamic_cycle_xy_values( |
|
length=21, |
|
init_elev=0, |
|
num_components=84, |
|
frequency_range=(1, 5), |
|
amplitude_range=(0.5, 10), |
|
step_range=(0, 2), |
|
): |
|
|
|
y_sequence = np.ones(length) * init_elev |
|
for _ in range(num_components): |
|
|
|
frequency = np.random.randint(*frequency_range) * (2 * np.pi / length) |
|
amplitude = np.random.uniform(*amplitude_range) |
|
phase_shift = np.random.choice([0, np.pi]) |
|
angles = ( |
|
np.linspace(0, frequency * length, length, endpoint=False) + phase_shift |
|
) |
|
y_sequence += np.sin(angles) * amplitude |
|
|
|
|
|
steps = np.random.uniform(*step_range, length - 1) |
|
total_step_sum = np.sum(steps) |
|
|
|
scale_factor = ( |
|
360 - ((360 / length) * np.random.uniform(*step_range)) |
|
) / total_step_sum |
|
|
|
x_values = np.cumsum(steps * scale_factor) |
|
|
|
x_values = np.insert(x_values, 0, 0) |
|
return x_values, y_sequence |
|
|
|
|
|
def smooth_data(data, window_size): |
|
|
|
pad_size = window_size |
|
padded_data = np.concatenate((data[-pad_size:], data, data[:pad_size])) |
|
|
|
|
|
kernel = np.ones(window_size) / window_size |
|
smoothed_data = np.convolve(padded_data, kernel, mode="same") |
|
|
|
|
|
|
|
start_index = pad_size |
|
end_index = -pad_size if pad_size != 0 else None |
|
smoothed_original_data = smoothed_data[start_index:end_index] |
|
return smoothed_original_data |
|
|
|
|
|
|
|
def gen_dynamic_loop(length=21, elev_deg=0): |
|
while True: |
|
|
|
azim_values, elev_values = generate_dynamic_cycle_xy_values( |
|
length=84, init_elev=elev_deg |
|
) |
|
|
|
smoothed_elev_values = smooth_data(elev_values, 5) |
|
max_magnitude = np.max(np.abs(smoothed_elev_values)) |
|
if max_magnitude < 90: |
|
break |
|
subsample = 84 // length |
|
azim_rad = np.deg2rad(azim_values[::subsample]) |
|
elev_rad = np.deg2rad(smoothed_elev_values[::subsample]) |
|
|
|
return np.roll(azim_rad, -1), np.roll(elev_rad, -1) |
|
|
|
|
|
def plot_3D(azim, polar, save_path, dynamic=True): |
|
os.makedirs(os.path.dirname(save_path), exist_ok=True) |
|
elev = np.deg2rad(90) - polar |
|
fig = plt.figure(figsize=(5, 5)) |
|
ax = fig.add_subplot(projection="3d") |
|
cm = plt.get_cmap("Greys") |
|
col_line = [cm(i) for i in np.linspace(0.3, 1, len(azim) + 1)] |
|
cm = plt.get_cmap("cool") |
|
col = [cm(float(i) / (len(azim))) for i in np.arange(len(azim))] |
|
xs = np.cos(elev) * np.cos(azim) |
|
ys = np.cos(elev) * np.sin(azim) |
|
zs = np.sin(elev) |
|
ax.scatter(xs[0], ys[0], zs[0], s=100, color=col[0]) |
|
xs_d, ys_d, zs_d = (xs[1:] - xs[:-1]), (ys[1:] - ys[:-1]), (zs[1:] - zs[:-1]) |
|
for i in range(len(xs) - 1): |
|
if dynamic: |
|
ax.quiver( |
|
xs[i], ys[i], zs[i], xs_d[i], ys_d[i], zs_d[i], lw=2, color=col_line[i] |
|
) |
|
else: |
|
ax.plot(xs[i : i + 2], ys[i : i + 2], zs[i : i + 2], lw=2, c=col_line[i]) |
|
ax.scatter(xs[i + 1], ys[i + 1], zs[i + 1], s=100, color=col[i + 1]) |
|
ax.scatter(xs[:1], ys[:1], zs[:1], s=120, facecolors="none", edgecolors="k") |
|
ax.scatter(xs[-1:], ys[-1:], zs[-1:], s=120, facecolors="none", edgecolors="k") |
|
ax.view_init(elev=30, azim=-20, roll=0) |
|
plt.savefig(save_path, bbox_inches="tight") |
|
plt.clf() |
|
plt.close() |
|
|