Source code for galaxy_textures.irregular

"""Irregular galaxy renderer."""

import numpy as np
import torch


[docs] def draw_irregular(xx, yy): """Render a clumpy irregular galaxy with optional tidal debris.""" q_irr = float(0.45 + 0.35 * torch.rand(1)) pa_irr = float(2 * np.pi * torch.rand(1)) n_clumps = int(torch.randint(7, 13, (1,))) cxp = float(0.20 * (torch.rand(1) - 0.5)) cyp = float(0.20 * (torch.rand(1) - 0.5)) pts = [] for _ in range(n_clumps): cw = float(0.045 + 0.075 * torch.rand(1)) ca = float(0.35 + 0.50 * torch.rand(1)) img = ca * torch.exp(-((xx - cxp) ** 2 + (yy - cyp) ** 2) / cw ** 2) img += float(0.35 + 0.20 * torch.rand(1)) * ca * torch.exp(-((xx - cxp) ** 2 + (yy - cyp) ** 2) / (3.2 * cw) ** 2) pts.append((cxp, cyp)) stp = float(0.10 + 0.16 * torch.rand(1)) ang = float(2 * np.pi * torch.rand(1)) cxp += stp * (np.cos(ang) * abs(np.cos(ang - pa_irr)) + 0.4 * np.cos(ang)) cyp += stp * (np.sin(ang) * abs(np.cos(ang - pa_irr)) + 0.4 * np.sin(ang)) rr = (cxp ** 2 + cyp ** 2) ** 0.5 if rr > 0.60: cxp *= 0.60 / rr cyp *= 0.60 / rr mx = sum(p[0] for p in pts) / len(pts) my = sum(p[1] for p in pts) / len(pts) ex = (xx - mx - float(0.10 * (torch.rand(1) - 0.5))) * np.cos(pa_irr) + (yy - my - float(0.10 * (torch.rand(1) - 0.5))) * np.sin(pa_irr) ey = (-(xx - mx) * np.sin(pa_irr) + (yy - my) * np.cos(pa_irr)) / q_irr img += float(0.18 + 0.12 * torch.rand(1)) * torch.exp(-(ex ** 2 + ey ** 2) / 0.40 ** 2) n_arms_irr = int(torch.rand(1).item() < 0.70) + int(torch.rand(1).item() < 0.30) r_s = ((xx - mx) ** 2 + (yy - my) ** 2).sqrt() + 1e-6 th_s = torch.atan2(yy - my, xx - mx) spin_irr = 1.0 if torch.rand(1).item() > 0.5 else -1.0 for arm_i in range(n_arms_irr): phase_s = float(2 * np.pi * torch.rand(1)) arm_start_s = float(0.15 + 0.10 * torch.rand(1)) pitch_s = float(1.2 + 1.8 * torch.rand(1)) fade_s = float(0.50 + 0.30 * torch.rand(1)) width_s = float(0.15 + 0.10 * torch.rand(1)) fan_s = float(0.05 + 0.06 * torch.rand(1)) wig_a = float(0.18 + 0.20 * torch.rand(1)) wig_f = float(4.0 + 4.0 * torch.rand(1)) wig_p = float(2 * np.pi * torch.rand(1)) dim = 1.0 if arm_i == 0 else 0.55 dr_s = (r_s - arm_start_s).clamp(min=0) wind_s = pitch_s * dr_s / (1.0 + 0.9 * dr_s) phi_s = th_s - spin_irr * wind_s - phase_s - wig_a * torch.sin(wig_f * dr_s + wig_p) width_r = width_s + fan_s * dr_s img += dim * float(0.48 + 0.20 * torch.rand(1)) * torch.exp(-dr_s / fade_s) * torch.exp((torch.cos(phi_s) - 1) / width_r) * torch.sigmoid((r_s - arm_start_s) * 20.0) n_stream = int(torch.randint(14, 30, (1,))) for _ in range(n_stream): t = float(torch.rand(1)) ** 0.7 dr_pt = t * fade_s * 1.8 wind_pt = pitch_s * dr_pt / (1.0 + 0.9 * dr_pt) th_pt = phase_s + spin_irr * wind_pt + wig_a * np.sin(wig_f * dr_pt + wig_p) + float(0.10 * (torch.rand(1) - 0.5)) r_pt = arm_start_s + dr_pt kx = mx + r_pt * np.cos(th_pt) ky = my + r_pt * np.sin(th_pt) kw = float(0.008 + 0.012 * torch.rand(1)) ka = dim * float(0.15 + 0.30 * torch.rand(1)) * (1.0 - 0.6 * t) img += ka * torch.exp(-((xx - kx) ** 2 + (yy - ky) ** 2) / kw ** 2) n_kn = int(torch.randint(15, 36, (1,))) for _ in range(n_kn): bx, by = pts[int(torch.randint(0, len(pts), (1,)))] kx = bx + float(torch.randn(1)) * 0.07 ky = by + float(torch.randn(1)) * 0.07 lum_skew = float(torch.rand(1)) ** 3 kw = float(0.008 + 0.020 * lum_skew) ka = float(0.20 + 0.70 * lum_skew) img += ka * torch.exp(-((xx - kx) ** 2 + (yy - ky) ** 2) / kw ** 2) return img