def wrap_and_calc_psf(xpts, ypts, zpts, func, **kwargs):
<EOL>for t in [xpts,ypts,zpts]:<EOL><INDENT>if len(t.shape) != <NUM_LIT:1>:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT><DEDENT>dx = <NUM_LIT:1> if xpts[<NUM_LIT:0>]==<NUM_LIT:0> else <NUM_LIT:0><EOL>dy = <NUM_LIT:1> if ypts[<NUM_LIT:0>]==<NUM_LIT:0> else <NUM_LIT:0><EOL>xg,yg,zg = np.meshgrid(xpts,ypts,zpts, indexing='<STR_LIT>')<EOL>xs, ys, zs = [ pts.size for pts in [xpts,ypts,zpts] ]<EOL>to_return = np.zeros([<NUM_LIT:2>*xs-dx, <NUM_LIT:2>*ys-dy, zs])<EOL>up_corner_psf = func(xg,yg,zg, **kwargs)<EOL>to_return[xs-dx:,ys-dy:,:] = up_corner_psf.copy()                     <EOL>if dx == <NUM_LIT:0>:<EOL><INDENT>to_return[:xs-dx,ys-dy:,:] = up_corner_psf[::-<NUM_LIT:1>,:,:].copy()       <EOL><DEDENT>else:<EOL><INDENT>to_return[:xs-dx,ys-dy:,:] = up_corner_psf[-<NUM_LIT:1>:<NUM_LIT:0>:-<NUM_LIT:1>,:,:].copy()    <EOL><DEDENT>if dy == <NUM_LIT:0>:<EOL><INDENT>to_return[xs-dx:,:ys-dy,:] = up_corner_psf[:,::-<NUM_LIT:1>,:].copy()       <EOL><DEDENT>else:<EOL><INDENT>to_return[xs-dx:,:ys-dy,:] = up_corner_psf[:,-<NUM_LIT:1>:<NUM_LIT:0>:-<NUM_LIT:1>,:].copy()    <EOL><DEDENT>if (dx == <NUM_LIT:0>) and (dy == <NUM_LIT:0>):<EOL><INDENT>to_return[:xs-dx,:ys-dy,:] = up_corner_psf[::-<NUM_LIT:1>,::-<NUM_LIT:1>,:].copy()    <EOL><DEDENT>elif (dx == <NUM_LIT:0>) and (dy != <NUM_LIT:0>):<EOL><INDENT>to_return[:xs-dx,:ys-dy,:] = up_corner_psf[::-<NUM_LIT:1>,-<NUM_LIT:1>:<NUM_LIT:0>:-<NUM_LIT:1>,:].copy() <EOL><DEDENT>elif (dy == <NUM_LIT:0>) and (dx != <NUM_LIT:0>):<EOL><INDENT>to_return[:xs-dx,:ys-dy,:] = up_corner_psf[-<NUM_LIT:1>:<NUM_LIT:0>:-<NUM_LIT:1>,::-<NUM_LIT:1>,:].copy() <EOL><DEDENT>else: <EOL><INDENT>to_return[:xs-dx,:ys-dy,:] = up_corner_psf[-<NUM_LIT:1>:<NUM_LIT:0>:-<NUM_LIT:1>,-<NUM_LIT:1>:<NUM_LIT:0>:-<NUM_LIT:1>,:].copy()<EOL><DEDENT>return to_return<EOL>
Wraps a point-spread function in x and y.

Speeds up psf calculations by a factor of 4 for free / some broadcasting
by exploiting the x->-x, y->-y symmetry of a psf function. Pass x and y
as the positive (say) values of the coordinates at which to evaluate func,
and it will return the function sampled at [x[::-1]] + x. Note it is not
wrapped in z.

Parameters
----------
    xpts : numpy.ndarray
        1D N-element numpy.array of the x-points to evaluate func at.
    ypts : numpy.ndarray
        y-points to evaluate func at.
    zpts : numpy.ndarray
        z-points to evaluate func at.
    func : function
        The function to evaluate and wrap around. Syntax must be
        func(x,y,z, **kwargs)
    **kwargs : Any parameters passed to the function.

Outputs
-------
    to_return : numpy.ndarray
        The wrapped and calculated psf, of shape
        [2*x.size - x0, 2*y.size - y0, z.size], where x0=1 if x[0]=0, etc.

Notes
-----
The coordinates should be something like numpy.arange(start, stop, diff),
with start near 0. If x[0]==0, all of x is calcualted but only x[1:]
is wrapped (i.e. it works whether or not x[0]=0).

This doesn't work directly for a linescan psf because the illumination
portion is not like a grid. However, the illumination and detection
are already combined with wrap_and_calc in calculate_linescan_psf etc.