Source code for pmesh.lic
import numpy
from .window import FindResampler
[docs]def lic(vectors, kernel, length, ds, resampler=None, texture=None, normalize=True):
""" Line Intergral Convolution for visualizing vector fields.
The vectors must be normalized to norm of 1.0 for LIC to give a reasonable
image.
The image looks bad if the vectors are noisy.
Parameters
----------
vectors : list of RealField
vx, vy, vz, ... must be normalized.
kernel : function kernel(s)
the line integral kernel function. s is the line coordinate variable between
-1 and 1.
length : float
the length of the line, in pixels.
ds : float
step size in the line integration. in pixels.
resampler: string, ResamplerWindow
the resampler window. See pmesh.window module for a full list. if None, use pm's
default sampler, pm.resampler, where pm is infered from the first vector.
texture : RealField, or None
the texture to use. If None, a default gaussian texture is used.
normalize : bool
True if normalize the vectors to 1.0
Returns
-------
lic : RealField
the integration result.
"""
pm = vectors[0].pm
if normalize:
vabs = sum(vi**2 for vi in vectors) ** 0.5
mask = vabs[...] == 0.0
vabs[mask] = 1.0
vectors = [vi / vabs for vi in vectors]
if texture is None:
texture = pm.generate_whitenoise(seed=990919, type='real')
Q = pm.generate_uniform_particle_grid(shift=0.0)
if resampler is None:
resampler = pm.resampler
resampler = FindResampler(resampler)
f = texture.readout(Q, resampler='nearest')
vmax = max(abs(v[...]).max() for v in vectors)
for sign in [-1, +1]:
x = Q.copy()
s = 0
while s < length * 0.5:
k = kernel(s * sign / (length * 0.5))
dx = x * 0.0
layout = pm.decompose(x, smoothing=vmax * ds * 0.5 + resampler.support * 0.5)
for d, v in enumerate(vectors):
dx[..., d] = v.readout(x, layout=layout, resampler=resampler) * ds
x[...] += dx * 0.5 * sign
f[...] += texture.readout(x, layout=layout, resampler=resampler) * k * ds
x[...] += dx * 0.5 * sign
s += ds
return pm.paint(Q, f, resampler='nearest')