package com.indago.iddea.view.viewer;
import net.imglib2.RandomAccessible;
import net.imglib2.RealRandomAccessible;
import net.imglib2.concatenate.Concatenable;
import net.imglib2.converter.Converter;
import net.imglib2.display.screenimage.awt.ARGBScreenImage;
import net.imglib2.realtransform.AffineGet;
import net.imglib2.realtransform.AffineSet;
import net.imglib2.realtransform.RealViews;
import net.imglib2.type.numeric.ARGBType;
import net.imglib2.ui.AbstractMultiResolutionRenderer;
import net.imglib2.ui.AbstractRenderer;
import net.imglib2.ui.AffineTransformType;
import net.imglib2.ui.AffineTransformType2D;
import net.imglib2.ui.AffineTransformType3D;
import net.imglib2.ui.MultiResolutionRenderer;
import net.imglib2.ui.PainterThread;
import net.imglib2.ui.RenderSource;
import net.imglib2.ui.RenderTarget;
import net.imglib2.ui.RendererFactory;
import net.imglib2.ui.SimpleInterruptibleProjector;
/**
* An {@link AbstractMultiResolutionRenderer} for a single {@link RenderSource}.
*
* @param <A>
* transform type
*
* @author Tobias Pietzsch <tobias.pietzsch@gmail.com>
* @author Stephan Saalfeld
* @author HongKee Moon
*/
public class InjectableMultiResolutionRenderer< A extends AffineSet & AffineGet & Concatenable< AffineGet > > extends AbstractMultiResolutionRenderer< A > {
/**
* Factory for creating {@link MultiResolutionRenderer}.
*/
public static class Factory< A extends AffineSet & AffineGet & Concatenable< AffineGet > > implements RendererFactory< A > {
final protected AffineTransformType< A > transformType;
final protected RenderSource< ?, A > source;
final protected double[] screenScales;
final protected long targetRenderNanos;
final protected boolean doubleBuffered;
final protected int numRenderingThreads;
/**
* Create a factory for {@link MultiResolutionRenderer
* MultiResolutionRenderer} of the given source, with the specified
* multi-resolution, multi-threading, and double-buffering properties.
*
* @param transformType
* which transformation type (e.g.
* {@link AffineTransformType2D affine 2d} or
* {@link AffineTransformType3D affine 3d}) is used for the
* source and viewer transforms.
* @param source
* source data to be rendered.
* @param screenScales
* Scale factors from the viewer canvas to screen images of
* different resolutions. A scale factor of 1 means 1 pixel
* in the screen image is displayed as 1 pixel on the canvas,
* a scale factor of 0.5 means 1 pixel in the screen image is
* displayed as 2 pixel on the canvas, etc. The screen scales
* are assumed to be ordered finer-to-coarse, with index 0
* corresponding to the full resolution usually.
* @param targetRenderNanos
* Target rendering time in nanoseconds. The rendering time
* for the coarsest rendered scale should be below this
* threshold.
* @param doubleBuffered
* Whether to use double buffered rendering.
* @param numRenderingThreads
* How many threads to use for rendering.
*/
public Factory( final AffineTransformType< A > transformType, final RenderSource< ?, A > source, final double[] screenScales, final long targetRenderNanos, final boolean doubleBuffered, final int numRenderingThreads ) {
this.transformType = transformType;
this.source = source;
this.screenScales = screenScales;
this.targetRenderNanos = targetRenderNanos;
this.doubleBuffered = doubleBuffered;
this.numRenderingThreads = numRenderingThreads;
}
@Override
public AbstractRenderer< A > create( final RenderTarget display, final PainterThread painterThread ) {
return new InjectableMultiResolutionRenderer< A >( transformType, source, display, painterThread, screenScales, targetRenderNanos, doubleBuffered, numRenderingThreads );
}
}
/**
* source data to be rendered.
*/
protected RenderSource< ?, A > source;
/**
* @param transformType
* which transformation type (e.g. {@link AffineTransformType2D
* affine 2d} or {@link AffineTransformType3D affine 3d}) is used
* for the source and viewer transforms.
* @param source
* source data to be rendered.
* @param display
* The canvas that will display the images we render.
* @param painterThread
* Thread that triggers repainting of the display. Requests for
* repainting are send there.
* @param screenScales
* Scale factors from the viewer canvas to screen images of
* different resolutions. A scale factor of 1 means 1 pixel in
* the screen image is displayed as 1 pixel on the canvas, a
* scale factor of 0.5 means 1 pixel in the screen image is
* displayed as 2 pixel on the canvas, etc. The screen scales are
* assumed to be ordered finer-to-coarse, with index 0
* corresponding to the full resolution usually.
* @param targetRenderNanos
* Target rendering time in nanoseconds. The rendering time for
* the coarsest rendered scale should be below this threshold.
* @param doubleBuffered
* Whether to use double buffered rendering.
* @param numRenderingThreads
* How many threads to use for rendering.
*/
public InjectableMultiResolutionRenderer( final AffineTransformType< A > transformType, final RenderSource< ?, A > source, final RenderTarget display, final PainterThread painterThread, final double[] screenScales, final long targetRenderNanos, final boolean doubleBuffered, final int numRenderingThreads ) {
super( transformType, display, painterThread, screenScales, targetRenderNanos, doubleBuffered, numRenderingThreads );
this.source = source;
}
@Override
protected SimpleInterruptibleProjector< ?, ARGBType > createProjector( final A viewerTransform, final A screenScaleTransform, final ARGBScreenImage target ) {
return createProjector( transformType, source, viewerTransform, screenScaleTransform, target, numRenderingThreads );
}
protected static < T, A extends AffineGet & Concatenable< AffineGet > > SimpleInterruptibleProjector< T, ARGBType > createProjector( final AffineTransformType< A > transformType, final RenderSource< T, A > source, final A viewerTransform, final A screenScaleTransform, final ARGBScreenImage screenImage, final int numRenderingThreads ) {
return new SimpleInterruptibleProjector< T, ARGBType >( getTransformedSource( transformType, source, viewerTransform, screenScaleTransform ), source.getConverter(), screenImage, numRenderingThreads );
}
protected static < T, A extends AffineGet & Concatenable< AffineGet > > RandomAccessible< T > getTransformedSource( final AffineTransformType< A > transformType, final RenderSource< T, A > source, final A viewerTransform, final A screenScaleTransform ) {
final RealRandomAccessible< T > img = source.getInterpolatedSource();
final A sourceToScreen = transformType.createTransform();
transformType.set( sourceToScreen, screenScaleTransform );
sourceToScreen.concatenate( viewerTransform );
sourceToScreen.concatenate( source.getSourceTransform() );
return RealViews.affine( img, sourceToScreen );
}
public void injectSource( final RealRandomAccessible source ) {
( ( Injectable ) this.source ).injectSource( source );
}
public void injectConverter( final Converter converter ) {
( ( Injectable ) this.source ).injectConverter( converter );
}
public void injectSourceTransform( final A transform )
{
( ( Injectable ) this.source ).injectSourceTransform( transform );
}
}