diff --git a/pom.xml b/pom.xml
index 50a28d6f..7fa0a2be 100644
--- a/pom.xml
+++ b/pom.xml
@@ -241,5 +241,16 @@
+ * Having a {@link Bdv} is useful for adding more stuff to a BigDataViewer + * window or panel. This is done using + * {@code BdvFunctions.show(..., Bdv.options().addTo(myBdv))}. + * + * @author Tobias Pietzsch <tobias.pietzsch@gmail.com> + */ +public interface Bdv +{ + BdvHandle getBdvHandle(); + + default void close() + { + getBdvHandle().close(); + } + + static BdvOptions options() + { + return BdvOptions.options(); + } +} diff --git a/src/main/java/bdv/util/BdvFunctions.java b/src/main/java/bdv/util/BdvFunctions.java new file mode 100644 index 00000000..beeab23a --- /dev/null +++ b/src/main/java/bdv/util/BdvFunctions.java @@ -0,0 +1,795 @@ +/*- + * #%L + * BigDataViewer core classes with minimal dependencies. + * %% + * Copyright (C) 2012 - 2024 BigDataViewer developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package bdv.util; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import net.imglib2.FinalInterval; +import net.imglib2.Interval; +import net.imglib2.RandomAccessible; +import net.imglib2.RandomAccessibleInterval; +import net.imglib2.RealInterval; +import net.imglib2.RealLocalizable; +import net.imglib2.RealRandomAccessible; +import net.imglib2.converter.Converter; +import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.realtransform.RealViews; +import net.imglib2.type.Type; +import net.imglib2.type.numeric.ARGBType; +import net.imglib2.type.numeric.NumericType; +import net.imglib2.type.numeric.RealType; +import net.imglib2.type.volatiles.VolatileARGBType; +import net.imglib2.util.Pair; +import net.imglib2.util.Util; +import net.imglib2.view.Views; + +import org.scijava.ui.behaviour.io.InputTriggerConfig; + +import bdv.BigDataViewer; +import bdv.ViewerImgLoader; +import bdv.cache.CacheControl; +import bdv.img.cache.VolatileGlobalCellCache; +import bdv.spimdata.WrapBasicImgLoader; +import bdv.tools.boundingbox.BoxSelectionOptions; +import bdv.tools.boundingbox.TransformedBoxSelectionDialog; +import bdv.tools.boundingbox.TransformedRealBoxSelectionDialog; +import bdv.tools.brightness.ConverterSetup; +import bdv.tools.brightness.SetupAssignments; +import bdv.tools.transformation.TransformedSource; +import bdv.util.VirtualChannels.VirtualChannel; +import bdv.util.volatiles.VolatileView; +import bdv.util.volatiles.VolatileViewData; +import bdv.viewer.Source; +import bdv.viewer.SourceAndConverter; +import mpicbg.spim.data.generic.AbstractSpimData; +import mpicbg.spim.data.generic.sequence.AbstractSequenceDescription; + +/** + * all show methods return a {@link Bdv} which can be used to add more stuff to the same window + * + * + * @author Tobias Pietzsch + * @author Philipp Hanslovsky + * @author Igor Pisarev + * @author Stephan Saalfeld + */ +public class BdvFunctions +{ + public static BdvHandle show() + { + return show( Bdv.options() ); + } + + public static BdvHandle show( + final BdvOptions options ) + { + final BdvHandle handle = getHandle( options ); + if ( handle instanceof BdvHandleFrame && ( ( BdvHandleFrame ) handle ).getBigDataViewer() == null ) + handle.createViewer( Collections.emptyList(), Collections.emptyList(), 1 ); + return handle; + } + + public static < T > BdvStackSource< T > show( + final RandomAccessibleInterval< T > img, + final String name ) + { + return show( img, name, Bdv.options() ); + } + + @SuppressWarnings( { "unchecked", "rawtypes" } ) + public static < T > BdvStackSource< T > show( + final RandomAccessibleInterval< T > img, + final String name, + final BdvOptions options ) + { + final BdvHandle handle = getHandle( options ); + final AxisOrder axisOrder = AxisOrder.getAxisOrder( options.values.axisOrder(), img, handle.is2D() ); + final AffineTransform3D sourceTransform = options.values.getSourceTransform(); + final T type; + if ( img instanceof VolatileView ) + { + final VolatileViewData< ?, ? > viewData = ( ( VolatileView< ?, ? > ) img ).getVolatileViewData(); + type = ( T ) viewData.getVolatileType(); + handle.getCacheControls().addCacheControl( viewData.getCacheControl() ); + } + else + type = Util.getTypeFromInterval( img ); + + return addRandomAccessibleInterval( handle, ( RandomAccessibleInterval ) img, ( NumericType ) type, name, axisOrder, sourceTransform ); + } + + public static < T extends NumericType< T > > BdvStackSource< T > show( + final RandomAccessible< T > img, + final Interval interval, + final String name ) + { + return show( img, interval, name, Bdv.options() ); + } + + // TODO version with numTimepoints argument + @SuppressWarnings( "unchecked" ) + public static < T extends NumericType< T > > BdvStackSource< T > show( + final RandomAccessible< T > img, + final Interval interval, + final String name, + final BdvOptions options ) + { + final BdvHandle handle = getHandle( options ); + final int numTimepoints = 1; + final AxisOrder axisOrder = AxisOrder.getAxisOrder( options.values.axisOrder(), img, handle.is2D() ); + final AffineTransform3D sourceTransform = options.values.getSourceTransform(); + final T type; + if ( img instanceof VolatileView ) + { + final VolatileViewData< ?, ? > viewData = ( ( VolatileView< ?, ? > ) img ).getVolatileViewData(); + type = ( T ) viewData.getVolatileType(); + handle.getCacheControls().addCacheControl( viewData.getCacheControl() ); + } + else + type = Util.getTypeFromInterval( Views.interval( img, interval ) ); + + return addRandomAccessible( handle, img, interval, numTimepoints, type, name, axisOrder, sourceTransform ); + } + + public static < T extends Type< T > > BdvStackSource< T > show( + final RealRandomAccessible< T > img, + final Interval interval, + final String name ) + { + return show( img, interval, name, Bdv.options() ); + } + + public static < T extends Type< T > > BdvStackSource< T > show( + final RealRandomAccessible< T > img, + final Interval interval, + final String name, + final BdvOptions options ) + { + final BdvHandle handle = getHandle( options ); + final AxisOrder axisOrder = AxisOrder.getAxisOrder( options.values.axisOrder(), img, handle.is2D() ); + final AffineTransform3D sourceTransform = options.values.getSourceTransform(); + final T type = img.realRandomAccess().get(); + return addRealRandomAccessible( handle, img, interval, type, name, axisOrder, sourceTransform ); + } + + public static List< BdvVirtualChannelSource > show( + final RandomAccessibleInterval< ARGBType > img, + final List< ? extends VirtualChannel > virtualChannels, + final String name ) + { + return show( img, virtualChannels, name, Bdv.options() ); + } + + public static List< BdvVirtualChannelSource > show( + final RandomAccessibleInterval< ARGBType > img, + final List< ? extends VirtualChannel > virtualChannels, + final String name, + final BdvOptions options ) + { + return VirtualChannels.show( img, virtualChannels, name, options ); + } + + public static < T > BdvStackSource< T > show( + final Source< T > source ) + { + return show( source, Bdv.options() ); + } + + public static < T > BdvStackSource< T > show( + final Source< T > source, + final BdvOptions options ) + { + return show( source, 1, options ); + } + + public static < T > BdvStackSource< T > show( + final Source< T > source, + final int numTimePoints ) + { + return show( source, numTimePoints, Bdv.options() ); + } + + public static < T > BdvStackSource< T > show( + final Source< T > source, + final int numTimePoints, + final BdvOptions options ) + { + final BdvHandle handle = getHandle( options ); + @SuppressWarnings( { "unchecked", "rawtypes" } ) + final BdvStackSource< T > stackSource = addSource( handle, ( Source ) source, numTimePoints ); + return stackSource; + } + + public static < T > BdvStackSource< T > show( + final SourceAndConverter< T > source ) + { + return show( source, Bdv.options() ); + } + + public static < T > BdvStackSource< T > show( + final SourceAndConverter< T > source, + final BdvOptions options ) + { + return show( source, 1, options ); + } + + public static < T > BdvStackSource< T > show( + final SourceAndConverter< T > source, + final int numTimePoints ) + { + return show( source, numTimePoints, Bdv.options() ); + } + + public static < T > BdvStackSource< T > show( + final SourceAndConverter< T > soc, + final int numTimepoints, + final BdvOptions options ) + { + final BdvHandle handle = getHandle( options ); + final T type = soc.getSpimSource().getType(); + final int setupId = handle.getUnusedSetupId(); + final List< ConverterSetup > converterSetups = Collections.singletonList( BigDataViewer.createConverterSetup( soc, setupId ) ); + final List< SourceAndConverter< T > > sources = Collections.singletonList( soc ); + handle.add( converterSetups, sources, numTimepoints ); + final BdvStackSource< T > bdvSource = new BdvStackSource<>( handle, numTimepoints, type, converterSetups, sources ); + handle.addBdvSource( bdvSource ); + return bdvSource; + } + + public static < T > BdvStackSource< T > show( + final List< SourceAndConverter< T > > sources, + final int numTimepoints, + final BdvOptions options ) + { + if ( sources.isEmpty() ) + throw new IllegalArgumentException(); + final BdvHandle handle = getHandle( options ); + final T type = sources.get( 0 ).getSpimSource().getType(); + final List< ConverterSetup > converterSetups = new ArrayList<>( sources.size() ); + for ( final SourceAndConverter< T > source : sources ) + { + final int setupId = handle.getUnusedSetupId(); + ConverterSetup converterSetup = BigDataViewer.createConverterSetup( source, setupId ); + handle.add( Collections.singletonList( converterSetup ), Collections.singletonList( source ), numTimepoints ); + converterSetups.add( converterSetup ); + } + final BdvStackSource< T > bdvSource = new BdvStackSource<>( handle, numTimepoints, type, converterSetups, sources ); + handle.addBdvSource( bdvSource ); + return bdvSource; + } + + public static < T > BdvStackSource< T > show( final ChannelSources< T > channels ) + { + return show( channels, Bdv.options() ); + } + + public static < T > BdvStackSource< T > show( + final ChannelSources< T > channels, + final BdvOptions options ) + { + final List< SourceAndConverter< T > > sources = channels.getSources(); + if ( sources.isEmpty() ) + throw new IllegalArgumentException(); + final int numTimepoints = channels.numTimepoints(); + + final BdvHandle handle = getHandle( options ); + final List< ConverterSetup > converterSetups = new ArrayList<>( sources.size() ); + for ( final SourceAndConverter< T > source : sources ) + { + final int setupId = handle.getUnusedSetupId(); + ConverterSetup converterSetup = BigDataViewer.createConverterSetup( source, setupId ); + handle.add( Collections.singletonList( converterSetup ), Collections.singletonList( source ), numTimepoints ); + converterSetups.add( converterSetup ); + } + final T type = channels.getType(); + final BdvStackSource< T > bdvSource = new BdvStackSource( handle, numTimepoints, type, converterSetups, sources ); + handle.addBdvSource( bdvSource ); + + final CacheControl cacheControl = channels.getCacheControl(); + if ( cacheControl != null ) + handle.getCacheControls().addCacheControl( cacheControl ); + + return bdvSource; + } + + public static List< BdvStackSource< ? > > show( + final AbstractSpimData< ? > spimData ) + { + return show( spimData, Bdv.options() ); + } + + public static List< BdvStackSource< ? > > show( + final AbstractSpimData< ? > spimData, + final BdvOptions options ) + { + final BdvHandle handle = getHandle( options ); + WrapBasicImgLoader.wrapImgLoaderIfNecessary( spimData ); + + final AbstractSequenceDescription< ?, ?, ? > seq = spimData.getSequenceDescription(); + final int numTimepoints = seq.getTimePoints().size(); + final CacheControl cache = ( ( ViewerImgLoader ) seq.getImgLoader() ).getCacheControl(); + handle.getBdvHandle().getCacheControls().addCacheControl( cache ); + if ( cache instanceof VolatileGlobalCellCache ) + ( ( VolatileGlobalCellCache ) cache ).clearCache(); + + final ArrayList< SourceAndConverter< ? > > sources = new ArrayList<>(); + BigDataViewer.initSetups( spimData, new ArrayList<>(), sources ); + + final List< BdvStackSource< ? > > bdvSources = new ArrayList<>(); + for ( final SourceAndConverter< ? > source : sources ) + bdvSources.add( addSpimDataSource( handle, source, numTimepoints ) ); + + WrapBasicImgLoader.removeWrapperIfPresent( spimData ); + return bdvSources; + } + + public static BdvPointsSource showPoints( + final List< ? extends RealLocalizable > points, + final String name ) + { + return showPoints( points, name, Bdv.options() ); + } + + public static BdvPointsSource showPoints( + final List< ? extends RealLocalizable > points, + final String name, + final BdvOptions options ) + { + final BdvHandle handle = getHandle( options ); + final AffineTransform3D sourceTransform = options.values.getSourceTransform(); + + final int setupId = handle.getUnusedSetupId(); + final ARGBType defaultColor = new ARGBType( 0xff00ff00 ); + final PlaceHolderConverterSetup setup = new PlaceHolderConverterSetup( setupId, 0, 255, defaultColor ); + final PlaceHolderSource source = new PlaceHolderSource( name ); + final SourceAndConverter< Void > soc = new SourceAndConverter<>( source, null ); + + final List< ConverterSetup > converterSetups = new ArrayList<>( Collections.singletonList( setup ) ); + final List< SourceAndConverter< Void > > sources = new ArrayList<>( Collections.singletonList( soc ) ); + + final int numTimepoints = 1; + handle.add( converterSetups, sources, numTimepoints ); + + final PlaceHolderOverlayInfo info = new PlaceHolderOverlayInfo( handle.getViewerPanel(), soc, setup ); + final PointsOverlay overlay = new PointsOverlay(); + overlay.setOverlayInfo( info ); + overlay.setPoints( points ); + overlay.setSourceTransform( sourceTransform ); + handle.getViewerPanel().getDisplay().overlays().add( overlay ); + + final BdvPointsSource bdvSource = new BdvPointsSource( handle, numTimepoints, setup, soc, info, overlay ); + handle.addBdvSource( bdvSource ); + return bdvSource; + } + + public static < O extends BdvOverlay > BdvOverlaySource< O > showOverlay( + final O overlay, + final String name ) + { + return showOverlay( overlay, name, Bdv.options() ); + } + + public static < O extends BdvOverlay > BdvOverlaySource< O > showOverlay( + final O overlay, + final String name, + final BdvOptions options ) + { + final BdvHandle handle = getHandle( options ); + final AffineTransform3D sourceTransform = options.values.getSourceTransform(); + + final int setupId = handle.getUnusedSetupId(); + final ARGBType defaultColor = new ARGBType( 0xff00ff00 ); + final PlaceHolderConverterSetup setup = new PlaceHolderConverterSetup( setupId, 0, 255, defaultColor ); + final PlaceHolderSource source = new PlaceHolderSource( name ); + final SourceAndConverter< Void > soc = new SourceAndConverter<>( source, null ); + + final List< ConverterSetup > converterSetups = new ArrayList<>( Collections.singletonList( setup ) ); + final List< SourceAndConverter< Void > > sources = new ArrayList<>( Collections.singletonList( soc ) ); + + final int numTimepoints = 1; + handle.add( converterSetups, sources, numTimepoints ); + + final PlaceHolderOverlayInfo info = new PlaceHolderOverlayInfo( handle.getViewerPanel(), soc, setup ); + overlay.setOverlayInfo( info ); + overlay.setSourceTransform( sourceTransform ); + handle.getViewerPanel().getDisplay().overlays().add( overlay ); + + final BdvOverlaySource< O > bdvSource = new BdvOverlaySource<>( handle, numTimepoints, setup, soc, info, overlay ); + handle.addBdvSource( bdvSource ); + return bdvSource; + } + + // TODO: move to BdvFunctionUtils + + /** + * @deprecated Ok to use for now, but shouldn't be required in the future. + */ + public static int getUnusedSetupId( final BigDataViewer bdv ) + { + return getUnusedSetupId( bdv.getSetupAssignments() ); + } + + // TODO: move to BdvFunctionUtils + /** + * @deprecated Ok to use for now, but shouldn't be required in the future. + */ + public static synchronized int getUnusedSetupId( final SetupAssignments setupAssignments ) + { + return SetupAssignments.getUnusedSetupId( setupAssignments ); + } + + public static TransformedRealBoxSelectionDialog.Result selectRealBox( + final Bdv bdv, + final AffineTransform3D boxTransform, + final RealInterval initialInterval, + final RealInterval rangeInterval ) + { + return selectRealBox( bdv, boxTransform, initialInterval, rangeInterval, BoxSelectionOptions.options() ); + } + + public static TransformedRealBoxSelectionDialog.Result selectRealBox( + final Bdv bdv, + final AffineTransform3D boxTransform, + final RealInterval initialInterval, + final RealInterval rangeInterval, + final BoxSelectionOptions options ) + { + final BdvHandle handle = bdv.getBdvHandle(); + + InputTriggerConfig keyConfig = options.values.getInputTriggerConfig(); + if ( keyConfig == null ) + keyConfig = new InputTriggerConfig(); + + return new TransformedRealBoxSelectionDialog( + handle.getViewerPanel(), + handle.getConverterSetups(), + handle.getUnusedSetupId(), + keyConfig, + handle.getTriggerbindings(), + boxTransform, + initialInterval, + rangeInterval, + options + ).getResult(); + } + + public static TransformedBoxSelectionDialog.Result selectBox( + final Bdv bdv, + final AffineTransform3D boxTransform, + final Interval initialInterval, + final Interval rangeInterval ) + { + return selectBox( bdv, boxTransform, initialInterval, rangeInterval, BoxSelectionOptions.options() ); + } + + public static TransformedBoxSelectionDialog.Result selectBox( + final Bdv bdv, + final AffineTransform3D boxTransform, + final Interval initialInterval, + final Interval rangeInterval, + final BoxSelectionOptions options ) + { + final BdvHandle handle = bdv.getBdvHandle(); + + InputTriggerConfig keyConfig = options.values.getInputTriggerConfig(); + if ( keyConfig == null ) + keyConfig = new InputTriggerConfig(); + + return new TransformedBoxSelectionDialog( + handle.getViewerPanel(), + handle.getConverterSetups(), + handle.getUnusedSetupId(), + keyConfig, + handle.getTriggerbindings(), + boxTransform, + initialInterval, + rangeInterval, + options + ).getResult(); + } + + /** + * Get existing {@code BdvHandle} from {@code options} or create a new + * {@code BdvHandleFrame}. + */ + private static BdvHandle getHandle( final BdvOptions options ) + { + final Bdv bdv = options.values.addTo(); + return ( bdv == null ) + ? new BdvHandleFrame( options ) + : bdv.getBdvHandle(); + } + + /** + * Add the given {@link RandomAccessibleInterval} {@code img} to the given + * {@link BdvHandle} as a new {@link BdvStackSource}. The {@code img} is + * expected to be 2D, 3D, 4D, or 5D with the given {@link AxisOrder}. + * + * @param handle + * handle to add the {@code img} to. + * @param img + * {@link RandomAccessibleInterval} to add. + * @param type + * instance of the {@code img} type. + * @param name + * name to give to the new source + * @param axisOrder + * {@link AxisOrder} of the source, is used to appropriately split {@code img} into channels and timepoints. + * @param sourceTransform + * transforms from source coordinates to global coordinates. + * @return a new {@link BdvStackSource} handle for the newly added source(s). + */ + private static < T extends NumericType< T > > BdvStackSource< T > addRandomAccessibleInterval( + final BdvHandle handle, + final RandomAccessibleInterval< T > img, + final T type, + final String name, + final AxisOrder axisOrder, + final AffineTransform3D sourceTransform ) + { + final List< ConverterSetup > converterSetups = new ArrayList<>(); + final List< SourceAndConverter< T > > sources = new ArrayList<>(); + final ArrayList< RandomAccessibleInterval< T > > stacks = AxisOrder.splitInputStackIntoSourceStacks( img, axisOrder ); + int numTimepoints = 1; + for ( final RandomAccessibleInterval< T > stack : stacks ) + { + final Source< T > s; + if ( stack.numDimensions() > 3 ) + { + numTimepoints = ( int ) stack.max( 3 ) + 1; + s = new RandomAccessibleIntervalSource4D<>( stack, type, sourceTransform, name ); + } + else + { + s = new RandomAccessibleIntervalSource<>( stack, type, sourceTransform, name ); + } + addSourceToListsGenericType( s, handle.getUnusedSetupId(), converterSetups, sources ); + } + handle.add( converterSetups, sources, numTimepoints ); + final BdvStackSource< T > bdvSource = new BdvStackSource<>( handle, numTimepoints, type, converterSetups, sources ); + handle.addBdvSource( bdvSource ); + return bdvSource; + } + + /** + * Add the given {@link RandomAccessible} {@code img} to the given + * {@link BdvHandle} as a new {@link BdvStackSource}. The {@code img} is + * expected to be 2D, 3D, 4D, or 5D with the given {@link AxisOrder}. + * + * @param handle + * handle to add the {@code img} to. + * @param img + * {@link RandomAccessible} to add. + * @param interval + * interval of the source (this is only used in the navigation + * box overlay in BDV). + * @param numTimepoints + * the number of timepoints of the source. + * @param type + * instance of the {@code img} type. + * @param name + * name to give to the new source + * @param axisOrder + * {@link AxisOrder} of the source, is used to appropriately split {@code img} into channels and timepoints. + * @param sourceTransform + * transforms from source coordinates to global coordinates. + * @return a new {@link BdvStackSource} handle for the newly added source(s). + */ + private static < T extends NumericType< T > > BdvStackSource< T > addRandomAccessible( + final BdvHandle handle, + final RandomAccessible< T > img, + final Interval interval, + final int numTimepoints, + final T type, + final String name, + final AxisOrder axisOrder, + final AffineTransform3D sourceTransform ) + { + + final List< ConverterSetup > converterSetups = new ArrayList<>(); + final List< SourceAndConverter< T > > sources = new ArrayList<>(); + final Pair< ArrayList< RandomAccessible< T > >, Interval > stacksAndInterval = AxisOrder.splitInputStackIntoSourceStacks( + img, + interval, + axisOrder ); + final ArrayList< RandomAccessible< T > > stacks = stacksAndInterval.getA(); + final Interval stackInterval = stacksAndInterval.getB(); + for ( final RandomAccessible< T > stack : stacks ) + { + final Source< T > s; + if ( stack.numDimensions() > 3 ) + s = new RandomAccessibleSource4D<>( stack, stackInterval, type, sourceTransform, name ); + else + s = new RandomAccessibleSource<>( stack, stackInterval, type, sourceTransform, name ); + addSourceToListsGenericType( s, handle.getUnusedSetupId(), converterSetups, sources ); + } + + handle.add( converterSetups, sources, numTimepoints ); + final BdvStackSource< T > bdvSource = new BdvStackSource<>( handle, numTimepoints, type, converterSetups, sources ); + handle.addBdvSource( bdvSource ); + return bdvSource; + } + + /** + * Add the given {@link RealRandomAccessible} {@code img} to the given + * {@link BdvHandle} as a new {@link BdvStackSource}. The {@code img} is + * expected to be 2D or 3D, and the new source will have one timepoint. + * + * @param handle + * handle to add the {@code img} to. + * @param img + * {@link RealRandomAccessible} to add. + * @param interval + * interval of the source (this is only used in the navigation + * box overlay in BDV). + * @param type + * instance of the {@code img} type. + * @param name + * name to give to the new source + * @param axisOrder + * {@link AxisOrder} of the source, must be {@link AxisOrder#XY} + * or {@link AxisOrder#XYZ}. + * @param sourceTransform + * transforms from source coordinates to global coordinates. + * @return a new {@link BdvStackSource} handle for the newly added source. + */ + private static < T extends Type< T > > BdvStackSource< T > addRealRandomAccessible( + final BdvHandle handle, + RealRandomAccessible< T > img, + Interval interval, + final T type, + final String name, + final AxisOrder axisOrder, + final AffineTransform3D sourceTransform ) + { + /* + * If AxisOrder is a 2D variant (has no Z dimension), augment the + * sourceStacks by a Z dimension. + */ + if ( !axisOrder.hasZ() ) + { + img = RealViews.addDimension( img ); + interval = new FinalInterval( + new long[]{ interval.min( 0 ), interval.min( 1 ), 0 }, + new long[]{ interval.max( 0 ), interval.max( 1 ), 0 } ); + } + + final Source< T > s = new RealRandomAccessibleIntervalSource<>( img, interval, type, sourceTransform, name ); + return addSource( handle, s, 1 ); + } + + /** + * Add the given {@link Source} to the given {@link BdvHandle} as a new + * {@link BdvStackSource}. + * + * @param handle + * handle to add the {@code source} to. + * @param source + * source to add. + * @param numTimepoints + * the number of timepoints of the source. + * @return a new {@link BdvStackSource} handle for the newly added + * {@code source}. + */ + @SuppressWarnings( "rawtypes" ) + private static < T > BdvStackSource< T > addSource( + final BdvHandle handle, + final Source< T > source, + final int numTimepoints ) + { + final T type = source.getType(); + final List< ConverterSetup > converterSetups = new ArrayList<>(); + final List< SourceAndConverter< T > > sources = new ArrayList<>(); + addSourceToListsGenericType( source, handle.getUnusedSetupId(), converterSetups, sources ); + handle.add( converterSetups, sources, numTimepoints ); + final BdvStackSource< T > bdvSource = new BdvStackSource<>( handle, numTimepoints, type, converterSetups, sources ); + handle.addBdvSource( bdvSource ); + return bdvSource; + } + + /** + * Add the given {@code source} to the lists of {@code converterSetups} + * (using specified {@code setupId}) and {@code sources}. For this, the + * {@code source} is wrapped with an appropriate {@link Converter} to + * {@link ARGBType} and into a {@link TransformedSource}. + * + * @param source + * source to add. + * @param setupId + * id of the new source for use in {@link SetupAssignments}. + * @param converterSetups + * list of {@link ConverterSetup}s to which the source should be + * added. + * @param sources + * list of {@link SourceAndConverter}s to which the source should + * be added. + */ + @SuppressWarnings( { "rawtypes", "unchecked" } ) + private static < T > void addSourceToListsGenericType( + final Source< T > source, + final int setupId, + final List< ConverterSetup > converterSetups, + final List< SourceAndConverter< T > > sources ) + { + final T type = source.getType(); + if ( type instanceof RealType || type instanceof ARGBType || type instanceof VolatileARGBType ) + addSourceToListsNumericType( ( Source ) source, setupId, converterSetups, ( List ) sources ); + else + throw new IllegalArgumentException( "Unknown source type. Expected RealType, ARGBType, or VolatileARGBType" ); + } + + /** + * Add the given {@code source} to the lists of {@code converterSetups} + * (using specified {@code setupId}) and {@code sources}. For this, the + * {@code source} is wrapped with an appropriate {@link Converter} to + * {@link ARGBType} and into a {@link TransformedSource}. + * + * @param source + * source to add. + * @param setupId + * id of the new source for use in {@link SetupAssignments}. + * @param converterSetups + * list of {@link ConverterSetup}s to which the source should be + * added. + * @param sources + * list of {@link SourceAndConverter}s to which the source should + * be added. + */ + private static < T extends NumericType< T > > void addSourceToListsNumericType( + final Source< T > source, + final int setupId, + final List< ConverterSetup > converterSetups, + final List< SourceAndConverter< T > > sources ) + { + final T type = source.getType(); + final SourceAndConverter< T > soc = BigDataViewer.wrapWithTransformedSource( + new SourceAndConverter<>( source, BigDataViewer.createConverterToARGB( type ) ) ); + converterSetups.add( BigDataViewer.createConverterSetup( soc, setupId ) ); + sources.add( soc ); + } + + private static < T > BdvStackSource< T > addSpimDataSource( + final BdvHandle handle, + final SourceAndConverter< T > source, + final int numTimepoints ) + { + final ConverterSetup setup = BigDataViewer.createConverterSetup( source, handle.getUnusedSetupId() ); + final List< ConverterSetup > setups = Collections.singletonList( setup ); + final List< SourceAndConverter< T > > sources = Collections.singletonList( source ); + handle.add( setups, sources, numTimepoints ); + + final T type = source.getSpimSource().getType(); + final BdvStackSource< T > bdvSource = new BdvStackSource<>( handle, numTimepoints, type, setups, sources ); + handle.addBdvSource( bdvSource ); + + return bdvSource; + } +} diff --git a/src/main/java/bdv/util/BdvHandle.java b/src/main/java/bdv/util/BdvHandle.java new file mode 100644 index 00000000..f40ef2e5 --- /dev/null +++ b/src/main/java/bdv/util/BdvHandle.java @@ -0,0 +1,304 @@ +/*- + * #%L + * BigDataViewer core classes with minimal dependencies. + * %% + * Copyright (C) 2012 - 2024 BigDataViewer developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package bdv.util; + +import bdv.ui.CardPanel; +import bdv.ui.appearance.AppearanceManager; +import bdv.ui.keymap.KeymapManager; +import bdv.ui.splitpanel.SplitPanel; +import bdv.viewer.ConverterSetups; +import bdv.viewer.ViewerStateChangeListener; +import java.util.ArrayList; +import java.util.List; + +import org.scijava.ui.behaviour.util.InputActionBindings; +import org.scijava.ui.behaviour.util.TriggerBehaviourBindings; + +import bdv.cache.CacheControl.CacheControls; +import bdv.tools.InitializeViewerState; +import bdv.tools.brightness.ConverterSetup; +import bdv.tools.brightness.SetupAssignments; +import bdv.tools.transformation.ManualTransformationEditor; +import bdv.viewer.SourceAndConverter; +import bdv.viewer.TimePointListener; +import bdv.viewer.ViewerPanel; +import net.imglib2.realtransform.AffineTransform3D; +import bdv.viewer.OverlayRenderer; +import bdv.viewer.TransformListener; + +/** + * Represents a BigDataViewer frame or panel and can be used to get to the bdv + * internals. + * + * @author Tobias Pietzsch + */ +public abstract class BdvHandle implements Bdv +{ + protected ViewerPanel viewer; + + protected CardPanel cards; + + protected SplitPanel splitPanel; + + protected ConverterSetups setups; + + // TODO: Remove + protected SetupAssignments setupAssignments; + + protected final ArrayList< BdvSource > bdvSources; + + protected final BdvOptions bdvOptions; + + protected boolean hasPlaceHolderSources; + + protected final int origNumTimepoints; + + protected CacheControls cacheControls; + + public BdvHandle( final BdvOptions options ) + { + bdvOptions = options; + bdvSources = new ArrayList<>(); + origNumTimepoints = 1; + } + + @Override + public BdvHandle getBdvHandle() + { + return this; + } + + public ViewerPanel getViewerPanel() + { + return viewer; + } + + public CardPanel getCardPanel() + { + return cards; + } + + public SplitPanel getSplitPanel() + { + return splitPanel; + } + + public ConverterSetups getConverterSetups() + { + return setups; + } + + // TODO: REMOVE + @Deprecated + public SetupAssignments getSetupAssignments() + { + return setupAssignments; + } + + public CacheControls getCacheControls() + { + return cacheControls; + } + + public abstract KeymapManager getKeymapManager(); + + public abstract AppearanceManager getAppearanceManager(); + + @Deprecated + int getUnusedSetupId() + { + return BdvFunctions.getUnusedSetupId( setupAssignments ); + } + + @Override + public void close() + { + if ( viewer != null ) + { + viewer.stop(); + bdvSources.clear(); + cacheControls.clear(); + + viewer = null; + cards = null; + splitPanel = null; + setups = null; + setupAssignments = null; + cacheControls = null; + } + } + + public abstract ManualTransformationEditor getManualTransformEditor(); + + public abstract InputActionBindings getKeybindings(); + + public abstract TriggerBehaviourBindings getTriggerbindings(); + + abstract boolean createViewer( + final List< ? extends ConverterSetup > converterSetups, + final List< ? extends SourceAndConverter< ? > > sources, + final int numTimepoints ); + + void add( + final List< ? extends ConverterSetup > converterSetups, + final List< ? extends SourceAndConverter< ? > > sources, + final int numTimepoints ) + { + final boolean initTransform; + if ( viewer == null ) + { + initTransform = createViewer( converterSetups, sources, numTimepoints ); + } + else + { + initTransform = viewer.state().getSources().isEmpty() && sources != null && !sources.isEmpty(); + + if ( converterSetups != null && sources != null && converterSetups.size() != sources.size() ) + System.err.println( "WARNING! Adding sources to BdvHandle with converterSetups.size() != sources.size()." ); + + if ( converterSetups != null ) + { + final int numSetups = Math.min( converterSetups.size(), sources.size() ); + for ( int i = 0; i < numSetups; ++i ) + { + final SourceAndConverter< ? > source = sources.get( i ); + final ConverterSetup setup = converterSetups.get( i ); + if ( setup != null ) + setups.put( source, setup ); + } + + // TODO: REMOVE + converterSetups.forEach( setupAssignments::addSetup ); + } + + if ( sources != null ) + for ( final SourceAndConverter< ? > soc : sources ) + { + viewer.state().addSource( soc ); + viewer.state().setSourceActive( soc, true ); + } + } + + if ( initTransform ) + { + synchronized ( this ) + { + initTransformPending = true; + tryInitTransform(); + } + } + } + + private boolean initTransformPending; + + protected synchronized void tryInitTransform() + { + if ( viewer.getDisplay().getWidth() <= 0 || viewer.getDisplay().getHeight() <= 0 ) + return; + + if ( initTransformPending ) + { + initTransformPending = false; + InitializeViewerState.initTransform( viewer ); + } + } + + void remove( + final List< ? extends ConverterSetup > converterSetups, + final List< ? extends SourceAndConverter< ? > > sources, + final List< TransformListener< AffineTransform3D > > transformListeners, + final List< TimePointListener > timepointListeners, + final List< ViewerStateChangeListener > viewerStateChangeListeners, + final List< OverlayRenderer > overlays ) + { + if ( viewer == null ) + return; + + // TODO: REMOVE + if ( converterSetups != null ) + converterSetups.forEach( setupAssignments::removeSetup ); + + if ( transformListeners != null ) + for ( final TransformListener< AffineTransform3D > l : transformListeners ) + viewer.removeTransformListener( l ); + + if ( timepointListeners != null ) + for ( final TimePointListener l : timepointListeners ) + viewer.removeTimePointListener( l ); + + if ( viewerStateChangeListeners != null ) + viewer.state().changeListeners().removeAll( viewerStateChangeListeners ); + + if ( overlays != null ) + for ( final OverlayRenderer o : overlays ) + viewer.getDisplay().overlays().remove( o ); + + if ( sources != null ) + viewer.state().removeSources( sources ); + } + + void addBdvSource( final BdvSource bdvSource ) + { + bdvSources.add( bdvSource ); + updateHasPlaceHolderSources(); + updateNumTimepoints(); + } + + void removeBdvSource( final BdvSource bdvSource ) + { + bdvSources.remove( bdvSource ); + updateHasPlaceHolderSources(); + updateNumTimepoints(); + } + + void updateHasPlaceHolderSources() + { + for ( final BdvSource s : bdvSources ) + if ( s.isPlaceHolderSource() ) + { + hasPlaceHolderSources = true; + return; + } + hasPlaceHolderSources = false; + } + + void updateNumTimepoints() + { + int numTimepoints = origNumTimepoints; + for ( final BdvSource s : bdvSources ) + numTimepoints = Math.max( numTimepoints, s.getNumTimepoints() ); + if ( viewer != null ) + viewer.setNumTimepoints( numTimepoints ); + } + + boolean is2D() + { + return bdvOptions.values.is2D(); + } +} diff --git a/src/main/java/bdv/util/BdvHandleFrame.java b/src/main/java/bdv/util/BdvHandleFrame.java new file mode 100644 index 00000000..a82c7a7d --- /dev/null +++ b/src/main/java/bdv/util/BdvHandleFrame.java @@ -0,0 +1,152 @@ +/*- + * #%L + * BigDataViewer core classes with minimal dependencies. + * %% + * Copyright (C) 2012 - 2024 BigDataViewer developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package bdv.util; + +import bdv.ui.UIUtils; +import bdv.ui.appearance.AppearanceManager; +import bdv.ui.keymap.KeymapManager; +import bdv.viewer.ViewerStateChange; +import java.awt.event.WindowEvent; +import java.util.ArrayList; +import java.util.List; + +import org.scijava.ui.behaviour.io.InputTriggerConfig; +import org.scijava.ui.behaviour.util.InputActionBindings; +import org.scijava.ui.behaviour.util.TriggerBehaviourBindings; + +import bdv.BigDataViewer; +import bdv.cache.CacheControl.CacheControls; +import bdv.export.ProgressWriter; +import bdv.export.ProgressWriterConsole; +import bdv.tools.brightness.ConverterSetup; +import bdv.tools.transformation.ManualTransformationEditor; +import bdv.viewer.DisplayMode; +import bdv.viewer.SourceAndConverter; +import bdv.viewer.ViewerFrame; +import bdv.viewer.ViewerOptions; + +public class BdvHandleFrame extends BdvHandle +{ + private BigDataViewer bdv; + + private final String frameTitle; + + BdvHandleFrame( final BdvOptions options ) + { + super( options ); + frameTitle = options.values.getFrameTitle(); + bdv = null; + cacheControls = new CacheControls(); + UIUtils.installFlatLafInfos(); + } + + public BigDataViewer getBigDataViewer() + { + return bdv; + } + + @Override + public void close() + { + if ( bdv != null ) + { + final ViewerFrame frame = bdv.getViewerFrame(); + frame.dispatchEvent( new WindowEvent( frame, WindowEvent.WINDOW_CLOSING ) ); + bdv = null; + } + super.close(); + } + + @Override + public ManualTransformationEditor getManualTransformEditor() + { + return bdv.getManualTransformEditor(); + } + + @Override + public KeymapManager getKeymapManager() + { + return bdv.getKeymapManager(); + } + + @Override + public AppearanceManager getAppearanceManager() + { + return bdv.getAppearanceManager(); + } + + @Override + public InputActionBindings getKeybindings() + { + return bdv.getViewerFrame().getKeybindings(); + } + + @Override + public TriggerBehaviourBindings getTriggerbindings() + { + return bdv.getViewerFrame().getTriggerbindings(); + } + + @Override + boolean createViewer( + final List< ? extends ConverterSetup > converterSetups, + final List< ? extends SourceAndConverter< ? > > sources, + final int numTimepoints ) + { + final ProgressWriter progressWriter = new ProgressWriterConsole(); + final ViewerOptions viewerOptions = bdvOptions.values.getViewerOptions(); + final InputTriggerConfig inputTriggerConfig = BigDataViewer.getInputTriggerConfig( viewerOptions ); + bdv = new BigDataViewer( + new ArrayList<>( converterSetups ), + new ArrayList<>( sources ), + null, + numTimepoints, + cacheControls, + frameTitle, + progressWriter, + viewerOptions.inputTriggerConfig( inputTriggerConfig ) ); + viewer = bdv.getViewer(); + cards = bdv.getViewerFrame().getCardPanel(); + splitPanel = bdv.getViewerFrame().getSplitPanel(); + setupAssignments = bdv.getSetupAssignments(); + setups = bdv.getConverterSetups(); + + // this triggers repaint when PlaceHolderSources are toggled + viewer.state().changeListeners().add( change -> { + if ( change == ViewerStateChange.VISIBILITY_CHANGED ) + viewer.getDisplay().repaint(); + } ); + + viewer.setDisplayMode( DisplayMode.FUSED ); + bdv.getViewerFrame().setVisible( true ); + + final boolean initTransform = !sources.isEmpty(); + return initTransform; + } +} diff --git a/src/main/java/bdv/util/BdvHandlePanel.java b/src/main/java/bdv/util/BdvHandlePanel.java new file mode 100644 index 00000000..9914b5f2 --- /dev/null +++ b/src/main/java/bdv/util/BdvHandlePanel.java @@ -0,0 +1,231 @@ +/*- + * #%L + * BigDataViewer core classes with minimal dependencies. + * %% + * Copyright (C) 2012 - 2024 BigDataViewer developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package bdv.util; + +import bdv.ui.BdvDefaultCards; +import bdv.ui.CardPanel; +import bdv.ui.UIUtils; +import bdv.ui.appearance.AppearanceManager; +import bdv.ui.keymap.KeymapManager; +import bdv.ui.splitpanel.SplitPanel; +import bdv.viewer.ConverterSetups; +import java.awt.Frame; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JComponent; +import javax.swing.SwingUtilities; + +import org.scijava.ui.behaviour.MouseAndKeyHandler; +import org.scijava.ui.behaviour.io.InputTriggerConfig; +import org.scijava.ui.behaviour.util.Actions; +import org.scijava.ui.behaviour.util.Behaviours; +import org.scijava.ui.behaviour.util.InputActionBindings; +import org.scijava.ui.behaviour.util.TriggerBehaviourBindings; + +import bdv.BigDataViewer; +import bdv.BigDataViewerActions; +import bdv.cache.CacheControl.CacheControls; +import bdv.tools.VisibilityAndGroupingDialog; +import bdv.tools.bookmarks.Bookmarks; +import bdv.tools.bookmarks.BookmarksEditor; +import bdv.tools.brightness.BrightnessDialog; +import bdv.tools.brightness.ConverterSetup; +import bdv.tools.brightness.SetupAssignments; +import bdv.tools.transformation.ManualTransformationEditor; +import bdv.viewer.DisplayMode; +import bdv.viewer.NavigationActions; +import bdv.viewer.SourceAndConverter; +import bdv.viewer.ViewerPanel; +import bdv.TransformEventHandler; + +import static bdv.BigDataViewerActions.COLLAPSE_CARDS; +import static bdv.BigDataViewerActions.COLLAPSE_CARDS_KEYS; +import static bdv.BigDataViewerActions.EXPAND_CARDS; +import static bdv.BigDataViewerActions.EXPAND_CARDS_KEYS; + +public class BdvHandlePanel extends BdvHandle +{ + private final BrightnessDialog brightnessDialog; + + private final VisibilityAndGroupingDialog activeSourcesDialog; + + private final ManualTransformationEditor manualTransformationEditor; + + private final Bookmarks bookmarks; + + private final BookmarksEditor bookmarksEditor; + + private final InputActionBindings keybindings; + + private final TriggerBehaviourBindings triggerbindings; + + private final KeymapManager keymapManager; + + private final AppearanceManager appearanceManager; + + public BdvHandlePanel( final Frame dialogOwner, final BdvOptions options ) + { + super( options ); + UIUtils.installFlatLafInfos(); + + final KeymapManager optionsKeymapManager = options.values.getKeymapManager(); + final AppearanceManager optionsAppearanceManager = options.values.getAppearanceManager(); + keymapManager = optionsKeymapManager != null ? optionsKeymapManager : new KeymapManager( BigDataViewer.configDir ); + appearanceManager = optionsAppearanceManager != null ? optionsAppearanceManager : new AppearanceManager( BigDataViewer.configDir ); + + cacheControls = new CacheControls(); + + viewer = new ViewerPanel( new ArrayList<>(), 1, cacheControls, options.values.getViewerOptions() ); + if ( !options.values.hasPreferredSize() ) + viewer.getDisplay().setPreferredSize( null ); + viewer.getDisplay().addComponentListener( new ComponentAdapter() + { + @Override + public void componentResized( final ComponentEvent e ) + { + tryInitTransform(); + } + } ); + + setupAssignments = new SetupAssignments( new ArrayList<>(), 0, 65535 ); + setups = new ConverterSetups( viewer.state() ); + setups.listeners().add( s -> viewer.requestRepaint() ); + + cards = new CardPanel(); + BdvDefaultCards.setup( cards, viewer, setups ); + splitPanel = new SplitPanel( viewer, cards ); + + keybindings = new InputActionBindings(); + SwingUtilities.replaceUIActionMap( viewer, keybindings.getConcatenatedActionMap() ); + SwingUtilities.replaceUIInputMap( viewer, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keybindings.getConcatenatedInputMap() ); + + triggerbindings = new TriggerBehaviourBindings(); + final MouseAndKeyHandler mouseAndKeyHandler = new MouseAndKeyHandler(); + mouseAndKeyHandler.setInputMap( triggerbindings.getConcatenatedInputTriggerMap() ); + mouseAndKeyHandler.setBehaviourMap( triggerbindings.getConcatenatedBehaviourMap() ); + viewer.getDisplay().addHandler( mouseAndKeyHandler ); + + final InputTriggerConfig inputTriggerConfig = viewer.getInputTriggerConfig(); + + // TODO: should be a field? + final Behaviours transformBehaviours = new Behaviours( inputTriggerConfig, "bdv" ); + transformBehaviours.install( triggerbindings, "transform" ); + + final TransformEventHandler tfHandler = viewer.getTransformEventHandler(); + tfHandler.install( transformBehaviours ); + + manualTransformationEditor = new ManualTransformationEditor( viewer, keybindings ); + + bookmarks = new Bookmarks(); + bookmarksEditor = new BookmarksEditor( viewer, keybindings, bookmarks ); + + brightnessDialog = new BrightnessDialog( dialogOwner, setupAssignments ); + activeSourcesDialog = new VisibilityAndGroupingDialog( dialogOwner, viewer.state() ); + + appearanceManager.appearance().updateListeners().add( () -> SwingUtilities.getWindowAncestor( viewer ).repaint() ); + SwingUtilities.invokeLater(() -> appearanceManager.updateLookAndFeel()); + + final Actions navigationActions = new Actions( inputTriggerConfig, "bdv", "navigation" ); + navigationActions.install( keybindings, "navigation" ); + NavigationActions.install( navigationActions, viewer, options.values.is2D() ); + + final Actions bdvActions = new Actions( inputTriggerConfig, "bdv" ); + bdvActions.install( keybindings, "bdv" ); + BigDataViewerActions.dialog( bdvActions, brightnessDialog ); + BigDataViewerActions.dialog( bdvActions, activeSourcesDialog ); + BigDataViewerActions.bookmarks( bdvActions, bookmarksEditor ); + BigDataViewerActions.manualTransform( bdvActions, manualTransformationEditor ); + bdvActions.runnableAction( this::expandAndFocusCardPanel, EXPAND_CARDS, EXPAND_CARDS_KEYS ); + bdvActions.runnableAction( this::collapseCardPanel, COLLAPSE_CARDS, COLLAPSE_CARDS_KEYS ); + + viewer.setDisplayMode( DisplayMode.FUSED ); + } + + @Override + public ManualTransformationEditor getManualTransformEditor() + { + return manualTransformationEditor; + } + + @Override + public KeymapManager getKeymapManager() + { + return keymapManager; + } + + @Override + public AppearanceManager getAppearanceManager() + { + return appearanceManager; + } + + @Override + public InputActionBindings getKeybindings() + { + return keybindings; + } + + @Override + public TriggerBehaviourBindings getTriggerbindings() + { + return triggerbindings; + } + + @Override + boolean createViewer( + final List< ? extends ConverterSetup > converterSetups, + final List< ? extends SourceAndConverter< ? > > sources, + final int numTimepoints ) + { + throw new UnsupportedOperationException(); + } + + @Override + public void close() + { + brightnessDialog.dispose(); + activeSourcesDialog.dispose(); + super.close(); + } + + public void expandAndFocusCardPanel() + { + splitPanel.setCollapsed( false ); + splitPanel.getRightComponent().requestFocusInWindow(); + } + + public void collapseCardPanel() + { + splitPanel.setCollapsed( true ); + viewer.requestFocusInWindow(); + } +} diff --git a/src/main/java/bdv/util/BdvOptions.java b/src/main/java/bdv/util/BdvOptions.java new file mode 100644 index 00000000..b959920b --- /dev/null +++ b/src/main/java/bdv/util/BdvOptions.java @@ -0,0 +1,407 @@ +/* + * #%L + * BigDataViewer core classes with minimal dependencies. + * %% + * Copyright (C) 2012 - 2024 BigDataViewer developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package bdv.util; + +import bdv.TransformEventHandler2D; +import bdv.TransformEventHandler3D; +import bdv.TransformEventHandlerFactory; +import bdv.ui.appearance.AppearanceManager; +import bdv.ui.keymap.KeymapManager; +import bdv.viewer.render.AccumulateProjectorARGB; +import org.scijava.ui.behaviour.io.InputTriggerConfig; + +import bdv.viewer.ViewerOptions; +import bdv.viewer.ViewerPanel; +import bdv.viewer.render.AccumulateProjector; +import bdv.viewer.render.AccumulateProjectorFactory; +import bdv.viewer.render.MultiResolutionRenderer; +import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.type.numeric.ARGBType; + +/** + * Optional parameters for {@link BdvFunctions}. + * + * @author Tobias Pietzsch <tobias.pietzsch@gmail.com> + */ +public class BdvOptions +{ + public final Values values = new Values(); + + /** + * Create default {@link BdvOptions}. + * @return default {@link BdvOptions}. + */ + public static BdvOptions options() + { + return new BdvOptions(); + } + + /** + * Set preferred size of {@link ViewerPanel} canvas. (This does not include + * the time slider). + */ + public BdvOptions preferredSize( final int w, final int h ) + { + values.width = w; + values.height = h; + return this; + } + + /** + * Set the number and scale factors for scaled screen images. + * + * @param s + * 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. + * @see MultiResolutionRenderer + */ + public BdvOptions screenScales( final double[] s ) + { + values.screenScales = s; + return this; + } + + /** + * Set target rendering time in nanoseconds. + * + * @param t + * Target rendering time in nanoseconds. The rendering time for + * the coarsest rendered scale should be below this threshold. + * @see MultiResolutionRenderer + */ + public BdvOptions targetRenderNanos( final long t ) + { + values.targetRenderNanos = t; + return this; + } + + /** + * Set how many threads to use for rendering. + * + * @param n + * How many threads to use for rendering. + * @see MultiResolutionRenderer + */ + public BdvOptions numRenderingThreads( final int n ) + { + values.numRenderingThreads = n; + return this; + } + + /** + * Set how many source groups there are initially. + * + * @param n + * How many source groups to create initially. + */ + public BdvOptions numSourceGroups( final int n ) + { + values.numSourceGroups = n; + return this; + } + + public BdvOptions transformEventHandlerFactory( final TransformEventHandlerFactory f ) + { + values.transformEventHandlerFactory = f; + return this; + } + + /** + * Set the factory for creating {@link AccumulateProjector}. This can be + * used to customize how sources are combined. + * + * @param f + * factory for creating {@link AccumulateProjector}. + * @see MultiResolutionRenderer + */ + public BdvOptions accumulateProjectorFactory( final AccumulateProjectorFactory< ARGBType > f ) + { + values.accumulateProjectorFactory = f; + return this; + } + + /** + * Set the {@link InputTriggerConfig} from which keyboard and mouse action mapping is loaded. + *
+ * Note that this will override the managed {@code InputTriggerConfig}, that is, + * modifying the keymap through the preferences dialog will have no effect. + * + * @param c the {@link InputTriggerConfig} from which keyboard and mouse action mapping is loaded + */ + public BdvOptions inputTriggerConfig( final InputTriggerConfig c ) + { + values.inputTriggerConfig = c; + return this; + } + + /** + * Set the {@link KeymapManager} to share keymap settings with other + * BigDataViewer windows. + *
+ * This can be used to link multiple BigDataViewer windows such that they + * use (and modify) the same {@code Keymap}, shortcuts and mouse gestures. + *
+ */ + public BdvOptions keymapManager( final KeymapManager keymapManager ) + { + values.keymapManager = keymapManager; + return this; + } + + /** + * Set the {@link AppearanceManager} to share appearance settings with other + * BigDataViewer windows. + *+ * This can be used to link multiple BigDataViewer windows such that they + * use (and modify) the same {@code Appearance} settings, e.g., LookAndFeel, + * scalebar overlay settings, etc. + *
+ */ + public BdvOptions appearanceManager( final AppearanceManager appearanceManager ) + { + values.appearanceManager = appearanceManager; + return this; + } + + /** + * Set the transform of the {@link BdvSource} to be created. + * + * @param t + * the source transform. + */ + public BdvOptions sourceTransform( final AffineTransform3D t ) + { + values.sourceTransform.set( t ); + return this; + } + + /** + * Set the title of the BigDataViewer window. + * + * @param title + * the window title. + */ + public BdvOptions frameTitle( final String title ) + { + values.frameTitle = title; + return this; + } + + /** + * Set the transform of the {@link BdvSource} to be created to account for + * the given calibration (scaling of the source axes). + * + * @param calibration + * the source calibration (scaling of the source axes). + */ + public BdvOptions sourceTransform( final double ... calibration ) + { + final double sx = calibration.length >= 1 ? calibration[ 0 ] : 1; + final double sy = calibration.length >= 2 ? calibration[ 1 ] : 1; + final double sz = calibration.length >= 3 ? calibration[ 2 ] : 1; + values.sourceTransform.set( + sx, 0, 0, 0, + 0, sy, 0, 0, + 0, 0, sz, 0 ); + return this; + } + + /** + * Set up the BigDataViewer for 2D navigation. + * + * TODO: add more detailed explanation + * + * @return + */ + public BdvOptions is2D() + { + values.is2D = true; + transformEventHandlerFactory( TransformEventHandler2D::new ); + return this; + } + + /** + * Specified when adding a stack. Describes how the axes of the stack are + * ordered. + * + * @param axisOrder + * the axis order of a stack to add. + */ + public BdvOptions axisOrder( final AxisOrder axisOrder ) + { + values.axisOrder = axisOrder; + return this; + } + + /** + * When showing content using one of the {@link BdvFunctions} methods, this + * option can be given to specify that the content should be added to an + * existing window. (All {@link BdvFunctions} methods return an instance of + * {@link Bdv} that can be used that way). + * + * @param bdv + * to which viewer should the content be added. + */ + public BdvOptions addTo( final Bdv bdv ) + { + values.addTo = bdv; + return this; + } + + /** + * Read-only {@link BdvOptions} values. + */ + public static class Values + { + private int width = -1; + + private int height = -1; + + private double[] screenScales = new double[] { 1, 0.75, 0.5, 0.25, 0.125 }; + + private long targetRenderNanos = 30 * 1000000l; + + private int numRenderingThreads = 3; + + private int numSourceGroups = 10; + + private TransformEventHandlerFactory transformEventHandlerFactory = TransformEventHandler3D::new; + + private AccumulateProjectorFactory< ARGBType > accumulateProjectorFactory = AccumulateProjectorARGB.factory; + + private InputTriggerConfig inputTriggerConfig = null; + + private KeymapManager keymapManager = null; + + private AppearanceManager appearanceManager = null; + + private final AffineTransform3D sourceTransform = new AffineTransform3D(); + + private String frameTitle = "BigDataViewer"; + + private boolean is2D = false; + + private AxisOrder axisOrder = AxisOrder.DEFAULT; + + private Bdv addTo = null; + + Values() + { + sourceTransform.identity(); + } + + public BdvOptions optionsFromValues() + { + final BdvOptions o = new BdvOptions() + .preferredSize( width, height ) + .screenScales( screenScales ) + .targetRenderNanos( targetRenderNanos ) + .numRenderingThreads( numRenderingThreads ) + .numSourceGroups( numSourceGroups ) + .transformEventHandlerFactory( transformEventHandlerFactory ) + .accumulateProjectorFactory( accumulateProjectorFactory ) + .inputTriggerConfig( inputTriggerConfig ) + .keymapManager( keymapManager ) + .appearanceManager( appearanceManager ) + .sourceTransform( sourceTransform ) + .frameTitle( frameTitle ) + .axisOrder( axisOrder ) + .addTo( addTo ); + if ( is2D() ) + o.is2D(); + return o; + } + + public ViewerOptions getViewerOptions() + { + final ViewerOptions o = ViewerOptions.options() + .screenScales( screenScales ) + .targetRenderNanos( targetRenderNanos ) + .numRenderingThreads( numRenderingThreads ) + .numSourceGroups( numSourceGroups ) + .is2D( is2D ) + .transformEventHandlerFactory( transformEventHandlerFactory ) + .accumulateProjectorFactory( accumulateProjectorFactory ) + .inputTriggerConfig( inputTriggerConfig ) + .keymapManager( keymapManager ) + .appearanceManager( appearanceManager ); + if ( hasPreferredSize() ) + o.width( width ).height( height ); + return o; + } + + public AffineTransform3D getSourceTransform() + { + return sourceTransform; + } + + public String getFrameTitle() + { + return frameTitle; + } + + public boolean is2D() + { + return is2D; + } + + public boolean hasPreferredSize() + { + return width > 0 && height > 0; + } + + public AxisOrder axisOrder() + { + return axisOrder; + } + + public InputTriggerConfig getInputTriggerConfig() + { + return inputTriggerConfig; + } + + public KeymapManager getKeymapManager() + { + return keymapManager; + } + + public AppearanceManager getAppearanceManager() + { + return appearanceManager; + } + + public Bdv addTo() + { + return addTo; + } + } +} diff --git a/src/main/java/bdv/util/BdvOverlay.java b/src/main/java/bdv/util/BdvOverlay.java new file mode 100644 index 00000000..0beee7fc --- /dev/null +++ b/src/main/java/bdv/util/BdvOverlay.java @@ -0,0 +1,125 @@ +/*- + * #%L + * BigDataViewer core classes with minimal dependencies. + * %% + * Copyright (C) 2012 - 2024 BigDataViewer developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package bdv.util; + +import java.awt.Graphics; +import java.awt.Graphics2D; + +import bdv.BigDataViewer; +import bdv.tools.brightness.ConverterSetup; +import bdv.viewer.Source; +import net.imglib2.realtransform.AffineTransform2D; +import net.imglib2.realtransform.AffineTransform3D; +import bdv.viewer.OverlayRenderer; + +/** + * An overlay that can be shown with + * {@link BdvFunctions#showOverlay(BdvOverlay, String, BdvOptions)}: This method + * will add a dummy {@link Source} and {@link ConverterSetup} to the + * {@link BigDataViewer} such that the visibility, display range, and color for + * the overlay can be adjusted by the user, like for a normal {@link Source}. + *+ * Derived classes need to implement {@link #draw(Graphics2D)}. They can access + * the current viewer transform using + * {@link #getCurrentTransform2D(AffineTransform2D)}, + * {@link #getCurrentTransform3D(AffineTransform3D)}. They can access the + * user-set display range and color via {@link #info}. + * + * @author Tobias Pietzsch + */ +public abstract class BdvOverlay implements OverlayRenderer +{ + protected final AffineTransform3D sourceTransform; + + private final AffineTransform3D tmp; + + protected PlaceHolderOverlayInfo info; + + public BdvOverlay() + { + this.sourceTransform = new AffineTransform3D(); + this.tmp = new AffineTransform3D(); + this.info = null; + } + + public void setOverlayInfo( final PlaceHolderOverlayInfo info ) + { + this.info = info; + } + + public void setSourceTransform( final AffineTransform3D t ) + { + sourceTransform.set( t ); + } + + @Override + public void drawOverlays( final Graphics g ) + { + if ( info == null || !info.isVisible() ) + return; + + draw( ( Graphics2D ) g ); + } + + /** + * Can be used by derived classes in the {@link #draw(Graphics2D)} method to + * get the current transform from 2D source coordinates to screen + * coordinates. + * + * @param transform + */ + protected void getCurrentTransform2D( final AffineTransform2D transform ) + { + info.getViewerTransform( tmp ); + tmp.concatenate( sourceTransform ); + transform.set( + tmp.get( 0, 0 ), tmp.get( 0, 1 ), tmp.get( 0, 3 ), + tmp.get( 1, 0 ), tmp.get( 1, 1 ), tmp.get( 1, 3 ) ); + } + + /** + * Can be used by derived classes in the {@link #draw(Graphics2D)} method to + * get the current transform from 3D source coordinates to 3D screen + * coordinates (where Z coordinate is distance from the slice shown on the + * screen). + * + * @param transform + */ + protected void getCurrentTransform3D( final AffineTransform3D transform ) + { + info.getViewerTransform( transform ); + transform.concatenate( sourceTransform ); + } + + protected abstract void draw( final Graphics2D g ); + + @Override + public void setCanvasSize( final int width, final int height ) + {} +} diff --git a/src/main/java/bdv/util/BdvOverlaySource.java b/src/main/java/bdv/util/BdvOverlaySource.java new file mode 100644 index 00000000..3d0dee26 --- /dev/null +++ b/src/main/java/bdv/util/BdvOverlaySource.java @@ -0,0 +1,129 @@ +/*- + * #%L + * BigDataViewer core classes with minimal dependencies. + * %% + * Copyright (C) 2012 - 2024 BigDataViewer developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package bdv.util; + +import java.util.Collections; + +import net.imglib2.type.numeric.ARGBType; +import bdv.viewer.OverlayRenderer; + +import bdv.tools.brightness.MinMaxGroup; +import bdv.tools.brightness.SetupAssignments; +import bdv.viewer.SourceAndConverter; + +public class BdvOverlaySource< O extends OverlayRenderer > extends BdvSource +{ + protected final PlaceHolderConverterSetup setup; + + private final SourceAndConverter< Void > source; + + private final PlaceHolderOverlayInfo info; + + protected final O overlay; + + public O getOverlay() + { + return overlay; + } + + protected BdvOverlaySource( + final BdvHandle bdv, + final int numTimepoints, + final PlaceHolderConverterSetup setup, + final SourceAndConverter< Void > source, + final PlaceHolderOverlayInfo info, + final O overlay ) + { + super( bdv, numTimepoints ); + this.setup = setup; + this.source = source; + this.info = info; + this.overlay = overlay; + } + + @Override + public void removeFromBdv() + { + getBdvHandle().remove( + Collections.singletonList( setup ), + Collections.singletonList( source ), + Collections.singletonList( info ), + Collections.singletonList( info ), + Collections.singletonList( info ), + Collections.singletonList( overlay ) ); + getBdvHandle().removeBdvSource( this ); + } + + @Override + protected boolean isPlaceHolderSource() + { + return true; + } + + @Override + public void setDisplayRange( final double min, final double max ) + { + setup.setDisplayRange( min, max ); + } + + @Override + public void setDisplayRangeBounds( final double min, final double max ) + { + getBdvHandle().getConverterSetups().getBounds().setBounds( setup, new Bounds( min, max ) ); + + // TODO: REMOVE + final SetupAssignments sa = getBdvHandle().getSetupAssignments(); + final MinMaxGroup group = sa.getMinMaxGroup( setup ); + group.setRange( min, max ); + } + + @Override + public void setColor( final ARGBType color ) + { + setup.setColor( color ); + } + + @Override + public void setCurrent() + { + getBdvHandle().getViewerPanel().state().setCurrentSource( source ); + } + + @Override + public boolean isCurrent() + { + return getBdvHandle().getViewerPanel().state().isCurrentSource( source ); + } + + @Override + public void setActive( final boolean isActive ) + { + getBdvHandle().getViewerPanel().state().setSourceActive( source, isActive ); + } +} diff --git a/src/main/java/bdv/util/BdvPointsSource.java b/src/main/java/bdv/util/BdvPointsSource.java new file mode 100644 index 00000000..0a5fcbd1 --- /dev/null +++ b/src/main/java/bdv/util/BdvPointsSource.java @@ -0,0 +1,67 @@ +/*- + * #%L + * BigDataViewer core classes with minimal dependencies. + * %% + * Copyright (C) 2012 - 2024 BigDataViewer developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package bdv.util; + +import java.util.List; + +import net.imglib2.RealLocalizable; +import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.type.numeric.ARGBType; + +import bdv.viewer.SourceAndConverter; + +public class BdvPointsSource extends BdvOverlaySource< PointsOverlay > +{ + protected BdvPointsSource( + final BdvHandle bdv, + final int numTimepoints, + final PlaceHolderConverterSetup setup, + final SourceAndConverter< Void > source, + final PlaceHolderOverlayInfo info, + final PointsOverlay overlay ) + { + super( bdv, numTimepoints, setup, source, info, overlay ); + } + + public < T extends RealLocalizable > void setPoints( final List< T > points ) + { + overlay.setPoints( points ); + } + + public void setSourceTransform( final AffineTransform3D t ) + { + overlay.setSourceTransform( t ); + } + + @Override + public void setColor( final ARGBType color ) + { + setup.setColor( color ); + } +} diff --git a/src/main/java/bdv/util/BdvSource.java b/src/main/java/bdv/util/BdvSource.java new file mode 100644 index 00000000..efba4d12 --- /dev/null +++ b/src/main/java/bdv/util/BdvSource.java @@ -0,0 +1,79 @@ +/*- + * #%L + * BigDataViewer core classes with minimal dependencies. + * %% + * Copyright (C) 2012 - 2024 BigDataViewer developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package bdv.util; + +import net.imglib2.type.numeric.ARGBType; + +public abstract class BdvSource implements Bdv +{ + private BdvHandle bdv; + + // so that we can fix the bdv numTimepoints when removing sources. + private final int numTimepoints; + + protected BdvSource( final BdvHandle bdv, final int numTimepoints ) + { + this.bdv = bdv; + this.numTimepoints = numTimepoints; + } + + // invalidates this BdvSource completely + // closes bdv if it was the last source + public abstract void removeFromBdv(); + + public abstract void setDisplayRange( final double min, final double max ); + + public abstract void setDisplayRangeBounds( final double min, final double max ); + + public abstract void setColor( final ARGBType color ); + + public abstract void setCurrent(); + + public abstract boolean isCurrent(); + + public abstract void setActive( final boolean isActive ); + + @Override + public BdvHandle getBdvHandle() + { + return bdv; + } + + protected void setBdvHandle( final BdvHandle bdv ) + { + this.bdv = bdv; + } + + protected abstract boolean isPlaceHolderSource(); + + protected int getNumTimepoints() + { + return numTimepoints; + } +} diff --git a/src/main/java/bdv/util/BdvStackSource.java b/src/main/java/bdv/util/BdvStackSource.java new file mode 100644 index 00000000..e7cb9d09 --- /dev/null +++ b/src/main/java/bdv/util/BdvStackSource.java @@ -0,0 +1,138 @@ +/*- + * #%L + * BigDataViewer core classes with minimal dependencies. + * %% + * Copyright (C) 2012 - 2024 BigDataViewer developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package bdv.util; + +import bdv.tools.brightness.ConverterSetup; +import bdv.tools.brightness.MinMaxGroup; +import bdv.tools.brightness.SetupAssignments; +import bdv.viewer.ConverterSetupBounds; +import bdv.viewer.SourceAndConverter; +import java.util.HashSet; +import java.util.List; +import net.imglib2.type.numeric.ARGBType; + +import static bdv.util.AbstractSource.tryCreateVariable; + +public class BdvStackSource< T > extends BdvSource +{ + private final T type; + + private final List< ConverterSetup > converterSetups; + + private final List< SourceAndConverter< T > > sources; + + protected BdvStackSource( + final BdvHandle bdv, + final int numTimepoints, + final T type, + final List< ConverterSetup > converterSetups, + final List< SourceAndConverter< T > > sources ) + { + super( bdv, numTimepoints ); + this.type = tryCreateVariable( type ); + this.converterSetups = converterSetups; + this.sources = sources; + } + + @Override + public void removeFromBdv() + { + getBdvHandle().remove( converterSetups, sources, null, null, null, null ); + getBdvHandle().removeBdvSource( this ); + } + + @Override + protected boolean isPlaceHolderSource() + { + return false; + } + + @Override + public void setColor( final ARGBType color ) + { + for ( final ConverterSetup setup : converterSetups ) + setup.setColor( color ); + } + + @Override + public void setDisplayRange( final double min, final double max ) + { + for ( final ConverterSetup setup : converterSetups ) + setup.setDisplayRange( min, max ); + } + + @Override + public void setDisplayRangeBounds( final double min, final double max ) + { + final ConverterSetupBounds bounds = getBdvHandle().getConverterSetups().getBounds(); + for ( final ConverterSetup setup : converterSetups ) + bounds.setBounds( setup, new Bounds( min, max ) ); + + // TODO: REMOVE + final HashSet< MinMaxGroup > groups = new HashSet<>(); + final SetupAssignments sa = getBdvHandle().getSetupAssignments(); + for ( final ConverterSetup setup : converterSetups ) + groups.add( sa.getMinMaxGroup( setup ) ); + for ( final MinMaxGroup group : groups ) + group.setRange( min, max ); + } + + @Override + public void setCurrent() + { + getBdvHandle().getViewerPanel().state().setCurrentSource( sources.get( 0 ) ); + } + + @Override + public boolean isCurrent() + { + return sources.contains( getBdvHandle().getViewerPanel().state().getCurrentSource() ); + } + + @Override + public void setActive( final boolean isActive ) + { + getBdvHandle().getViewerPanel().state().setSourcesActive( sources, isActive ); + } + +// public T getType() +// { +// return type; +// } + + public List< ConverterSetup > getConverterSetups() + { + return converterSetups; + } + + public List< SourceAndConverter< T > > getSources() + { + return sources; + } +} diff --git a/src/main/java/bdv/util/BdvVirtualChannelSource.java b/src/main/java/bdv/util/BdvVirtualChannelSource.java new file mode 100644 index 00000000..41c81630 --- /dev/null +++ b/src/main/java/bdv/util/BdvVirtualChannelSource.java @@ -0,0 +1,128 @@ +/*- + * #%L + * BigDataViewer core classes with minimal dependencies. + * %% + * Copyright (C) 2012 - 2024 BigDataViewer developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package bdv.util; + +import bdv.tools.brightness.MinMaxGroup; +import bdv.tools.brightness.SetupAssignments; +import bdv.util.VirtualChannels.ChannelSourceCoordinator; +import bdv.viewer.SourceAndConverter; +import java.util.Collections; +import net.imglib2.type.numeric.ARGBType; + +public class BdvVirtualChannelSource extends BdvSource +{ + protected final PlaceHolderConverterSetup setup; + + private final SourceAndConverter< ARGBType > source; + + private final PlaceHolderOverlayInfo info; + + private final ChannelSourceCoordinator coordinator; + + protected BdvVirtualChannelSource( + final BdvHandle bdv, + final int numTimepoints, + final PlaceHolderConverterSetup setup, + final SourceAndConverter< ARGBType > source, + final PlaceHolderOverlayInfo info, + final ChannelSourceCoordinator coordinator ) + { + super( bdv, numTimepoints ); + this.setup = setup; + this.source = source; + this.info = info; + this.coordinator = coordinator; + } + + public PlaceHolderOverlayInfo getPlaceHolderOverlayInfo() + { + return info; + } + + @Override + public void removeFromBdv() + { + coordinator.sharedInfos.remove( info ); + getBdvHandle().remove( + Collections.singletonList( setup ), + Collections.singletonList( source ), + Collections.singletonList( info ), + Collections.singletonList( info ), + Collections.singletonList( info ), + null ); + getBdvHandle().removeBdvSource( this ); + } + + @Override + protected boolean isPlaceHolderSource() + { + return false; + } + + @Override + public void setDisplayRange( final double min, final double max ) + { + setup.setDisplayRange( min, max ); + } + + @Override + public void setDisplayRangeBounds( final double min, final double max ) + { + getBdvHandle().getConverterSetups().getBounds().setBounds( setup, new Bounds( min, max ) ); + + // TODO: REMOVE + final SetupAssignments sa = getBdvHandle().getSetupAssignments(); + final MinMaxGroup group = sa.getMinMaxGroup( setup ); + group.setRange( min, max ); + } + + @Override + public void setColor( final ARGBType color ) + { + setup.setColor( color ); + } + + @Override + public void setCurrent() + { + getBdvHandle().getViewerPanel().state().setCurrentSource( source ); + } + + @Override + public boolean isCurrent() + { + return getBdvHandle().getViewerPanel().state().isCurrentSource( source ); + } + + @Override + public void setActive( final boolean isActive ) + { + getBdvHandle().getViewerPanel().state().setSourceActive( source, isActive ); + } +} diff --git a/src/main/java/bdv/util/ChannelSources.java b/src/main/java/bdv/util/ChannelSources.java new file mode 100644 index 00000000..799a8215 --- /dev/null +++ b/src/main/java/bdv/util/ChannelSources.java @@ -0,0 +1,67 @@ +/*- + * #%L + * BigDataViewer core classes with minimal dependencies. + * %% + * Copyright (C) 2012 - 2024 BigDataViewer developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package bdv.util; + +import bdv.cache.CacheControl; +import bdv.viewer.SourceAndConverter; +import java.util.List; + +/** + * Channels of an image as a collection of {@link SourceAndConverter + * sources}. The channels should all have the same pixel type, number of + * timepoints, and dimensions. + */ +public interface ChannelSources< T > +{ + /** + * Get the list of sources, one for each channel. + */ + List< SourceAndConverter< T > > getSources(); + + /** + * Get the number timepoints. + */ + int numTimepoints(); + + /** + * Get (an instance of) the pixel type. + */ + default T getType() + { + return getSources().get( 0 ).getSpimSource().getType(); + } + + /** + * Get handle for controlling cache behaviour. + */ + default CacheControl getCacheControl() + { + return null; + } +} diff --git a/src/main/java/bdv/util/DefaultInterpolators.java b/src/main/java/bdv/util/DefaultInterpolators.java new file mode 100644 index 00000000..986a0ba3 --- /dev/null +++ b/src/main/java/bdv/util/DefaultInterpolators.java @@ -0,0 +1,67 @@ +/*- + * #%L + * BigDataViewer core classes with minimal dependencies. + * %% + * Copyright (C) 2012 - 2024 BigDataViewer developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package bdv.util; + +import java.util.function.Function; + +import bdv.viewer.Interpolation; +import net.imglib2.RandomAccessible; +import net.imglib2.interpolation.InterpolatorFactory; +import net.imglib2.interpolation.randomaccess.ClampingNLinearInterpolatorFactory; +import net.imglib2.interpolation.randomaccess.NearestNeighborInterpolatorFactory; +import net.imglib2.type.numeric.NumericType; + +public class DefaultInterpolators< T extends NumericType< T > > implements Function< Interpolation, InterpolatorFactory< T, RandomAccessible< T > > > +{ + private final InterpolatorFactory< T, RandomAccessible< T > >[] factories; + + @SuppressWarnings( "unchecked" ) + public DefaultInterpolators() + { + factories = new InterpolatorFactory[ Interpolation.values().length ]; + factories[ Interpolation.NEARESTNEIGHBOR.ordinal() ] = new NearestNeighborInterpolatorFactory<>(); + factories[ Interpolation.NLINEAR.ordinal() ] = new ClampingNLinearInterpolatorFactory<>(); + } + + public InterpolatorFactory< T, RandomAccessible< T > > get( final Interpolation method ) + { + return factories[ method.ordinal() ]; + } + + public int size() + { + return factories.length; + } + + @Override + public InterpolatorFactory< T, RandomAccessible< T > > apply( final Interpolation t ) + { + return get( t ); + } +} diff --git a/src/main/java/bdv/util/PlaceHolderOverlayInfo.java b/src/main/java/bdv/util/PlaceHolderOverlayInfo.java new file mode 100644 index 00000000..4599f58c --- /dev/null +++ b/src/main/java/bdv/util/PlaceHolderOverlayInfo.java @@ -0,0 +1,214 @@ +/*- + * #%L + * BigDataViewer core classes with minimal dependencies. + * %% + * Copyright (C) 2012 - 2024 BigDataViewer developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package bdv.util; + +import bdv.viewer.SourceAndConverter; +import bdv.viewer.ViewerStateChange; +import bdv.viewer.ViewerStateChangeListener; + +import bdv.tools.brightness.ConverterSetup; +import bdv.viewer.TimePointListener; +import bdv.viewer.ViewerPanel; +import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.type.numeric.ARGBType; +import bdv.viewer.TransformListener; +import org.scijava.listeners.Listeners; + +public final class PlaceHolderOverlayInfo implements TransformListener< AffineTransform3D >, TimePointListener, ViewerStateChangeListener +{ + private final ViewerPanel viewer; + + private final SourceAndConverter< ? > source; + + private final ConverterSetup converterSetup; + + private final AffineTransform3D viewerTransform; + + private int timePointIndex; + + private boolean wasVisible; + + private final Listeners.List< VisibilityChangeListener > listeners; + + public interface VisibilityChangeListener + { + void visibilityChanged(); + } + + /** + * + * @param viewer + * @param source + * used for determining visibility. + * @param converterSetup + */ + public PlaceHolderOverlayInfo( + final ViewerPanel viewer, + final SourceAndConverter< ? > source, + final ConverterSetup converterSetup ) + { + this.viewer = viewer; + this.source = source; + this.converterSetup = converterSetup; + this.viewerTransform = new AffineTransform3D(); + this.listeners = new Listeners.SynchronizedList<>(); + + viewer.addRenderTransformListener( this ); + viewer.addTimePointListener( this ); + viewer.state().changeListeners().add( this ); + } + + SourceAndConverter< ? > getSource() + { + return source; + } + + @Override + public void transformChanged( final AffineTransform3D t ) + { + synchronized( viewerTransform ) + { + viewerTransform.set( t ); + } + } + + public boolean isVisible() + { + return viewer.state().isSourceVisible( source ); + } + + public void getViewerTransform( final AffineTransform3D t ) + { + synchronized( viewerTransform ) + { + t.set( viewerTransform ); + } + } + + public int getTimePointIndex() + { + return timePointIndex; + } + + /** + * Get the (largest) source value that is mapped to the minimum of the + * target range. + * + * @return source value that is mapped to the minimum of the target range. + */ + public double getDisplayRangeMin() + { + return converterSetup.getDisplayRangeMin(); + } + + /** + * Get the (smallest) source value that is mapped to the maximum of the + * target range. + * + * @return source value that is mapped to the maximum of the target range. + */ + public double getDisplayRangeMax() + { + return converterSetup.getDisplayRangeMax(); + } + + /** + * Get the color for this converter. + * + * @return the color for this converter. + */ + public ARGBType getColor() + { + return converterSetup.getColor(); + } + + @Override + public void timePointChanged( final int timePointIndex ) + { + this.timePointIndex = timePointIndex; + } + + @Override + public void viewerStateChanged( final ViewerStateChange change ) + { + if ( change == ViewerStateChange.VISIBILITY_CHANGED ) + { + final boolean isVisible = isVisible(); + if ( wasVisible != isVisible ) + { + wasVisible = isVisible; + listeners.list.forEach( VisibilityChangeListener::visibilityChanged ); + } + } + } + + /** + * Register {@code VisibilityChangeListener}s, that will be notified when the + * visibility of the source represented by this PlaceHolderOverlayInfo + * changes. + */ + public Listeners< VisibilityChangeListener > visibilityChangeListeners() + { + return listeners; + } + + /** + * Registers a VisibilityChangeListener, that will be notified when the + * visibility of the source represented by this PlaceHolderOverlayInfo + * changes. + * + * @deprecated Use {@code visibilityChangeListeners().add(listener)} instead. + * + * @param listener + * the listener to register. + * @return {@code true} if the listener was successfully registered. + * {@code false} if it was already registered. + */ + @Deprecated + public boolean addVisibilityChangeListener( final VisibilityChangeListener listener ) + { + return listeners.add( listener ); + } + + /** + * Removes the specified listener. + * + * @deprecated Use {@code visibilityChangeListeners().remove(listener)} instead. + * + * @param listener + * the listener to remove. + * @return {@code true} if the listener was present in the listeners of + * this model and was successfully removed. + */ + @Deprecated + public boolean removeVisibilityChangeListener( final VisibilityChangeListener listener ) + { + return listeners.remove( listener ); + } +} diff --git a/src/main/java/bdv/util/PlaceHolderSource.java b/src/main/java/bdv/util/PlaceHolderSource.java new file mode 100644 index 00000000..09e3cf7c --- /dev/null +++ b/src/main/java/bdv/util/PlaceHolderSource.java @@ -0,0 +1,109 @@ +/*- + * #%L + * BigDataViewer core classes with minimal dependencies. + * %% + * Copyright (C) 2012 - 2024 BigDataViewer developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package bdv.util; + +import net.imglib2.RandomAccessibleInterval; +import net.imglib2.RealRandomAccessible; +import net.imglib2.realtransform.AffineTransform3D; + +import bdv.viewer.Interpolation; +import bdv.viewer.Source; +import mpicbg.spim.data.sequence.VoxelDimensions; + +/** + * A dummy {@link Source} that represents a {@link BdvOverlay}. + *
+ * When a {@code BdvOverlay} is shown (with + * {@link BdvFunctions#showOverlay(BdvOverlay, String, BdvOptions)}), a dummy + * {@code Source} and {@code ConverterSetup} are added to the + * {@code BigDataViewer} such that the visibility, display range, and color for + * the overlay can be adjusted by the user, like for a normal {@link Source}. + *
+ * {@code PlaceHolderSource} is not {@link PlaceHolderSource#isPresent(int)
+ * present} at any time point, so it is never actually visible.
+ *
+ * @author Tobias Pietzsch
+ */
+public final class PlaceHolderSource implements Source< Void >
+{
+ private final String name;
+
+ public PlaceHolderSource( final String name )
+ {
+ this.name = name;
+ }
+
+ @Override
+ public Void getType()
+ {
+ return null;
+ }
+
+ @Override
+ public String getName()
+ {
+ return name;
+ }
+
+ @Override
+ public VoxelDimensions getVoxelDimensions()
+ {
+ return null;
+ }
+
+ @Override
+ public int getNumMipmapLevels()
+ {
+ return 1;
+ }
+
+ @Override
+ public boolean isPresent( final int t )
+ {
+ return false;
+ }
+
+ @Override
+ public RandomAccessibleInterval< Void > getSource( final int t, final int level )
+ {
+ return null;
+ }
+
+ @Override
+ public RealRandomAccessible< Void > getInterpolatedSource( final int t, final int level, final Interpolation method )
+ {
+ return null;
+ }
+
+ @Override
+ public void getSourceTransform( final int t, final int level, final AffineTransform3D transform )
+ {
+ transform.identity();
+ }
+}
diff --git a/src/main/java/bdv/util/PointsOverlay.java b/src/main/java/bdv/util/PointsOverlay.java
new file mode 100644
index 00000000..bac0ba80
--- /dev/null
+++ b/src/main/java/bdv/util/PointsOverlay.java
@@ -0,0 +1,92 @@
+/*-
+ * #%L
+ * BigDataViewer core classes with minimal dependencies.
+ * %%
+ * Copyright (C) 2012 - 2024 BigDataViewer developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.util;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.util.List;
+
+import net.imglib2.RealLocalizable;
+import net.imglib2.realtransform.AffineTransform3D;
+
+public class PointsOverlay extends BdvOverlay
+{
+ private List< ? extends RealLocalizable > points;
+
+ private Color col;
+
+ public < T extends RealLocalizable > void setPoints( final List< T > points )
+ {
+ this.points = points;
+ }
+
+ @Override
+ protected void draw( final Graphics2D graphics )
+ {
+ if ( points == null )
+ return;
+
+ col = new Color( info.getColor().get() );
+
+ final AffineTransform3D transform = new AffineTransform3D();
+ getCurrentTransform3D( transform );
+ final double[] lPos = new double[ 3 ];
+ final double[] gPos = new double[ 3 ];
+ for ( final RealLocalizable p : points )
+ {
+ p.localize( lPos );
+ transform.apply( lPos, gPos );
+ final double size = getPointSize( gPos );
+ final int x = ( int ) ( gPos[ 0 ] - 0.5 * size );
+ final int y = ( int ) ( gPos[ 1 ] - 0.5 * size );
+ final int w = ( int ) size;
+ graphics.setColor( getColor( gPos ) );
+ graphics.fillOval( x, y, w, w );
+ }
+ }
+
+ /** screen pixels [x,y,z] **/
+ private Color getColor( final double[] gPos )
+ {
+ int alpha = 255 - ( int ) Math.round( Math.abs( gPos[ 2 ] ) );
+
+ if ( alpha < 64 )
+ alpha = 64;
+
+ return new Color( col.getRed(), col.getGreen(), col.getBlue(), alpha );
+ }
+
+ private double getPointSize( final double[] gPos )
+ {
+ if ( Math.abs( gPos[ 2 ] ) < 3 )
+ return 5.0;
+ else
+ return 3.0;
+ }
+}
diff --git a/src/main/java/bdv/util/RandomAccessibleIntervalMipmapSource.java b/src/main/java/bdv/util/RandomAccessibleIntervalMipmapSource.java
new file mode 100644
index 00000000..56b28c57
--- /dev/null
+++ b/src/main/java/bdv/util/RandomAccessibleIntervalMipmapSource.java
@@ -0,0 +1,147 @@
+/*
+ * #%L
+ * BigDataViewer core classes with minimal dependencies.
+ * %%
+ * Copyright (C) 2012 - 2024 BigDataViewer developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.util;
+
+import java.util.function.Supplier;
+
+import bdv.cache.SharedQueue;
+import bdv.util.volatiles.VolatileTypeMatcher;
+import mpicbg.spim.data.sequence.VoxelDimensions;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.Volatile;
+import net.imglib2.realtransform.AffineTransform3D;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.numeric.NumericType;
+
+public class RandomAccessibleIntervalMipmapSource< T extends NumericType< T > > extends AbstractSource< T >
+{
+ protected final RandomAccessibleInterval< T >[] mipmapSources;
+
+ protected final AffineTransform3D[] mipmapTransforms;
+
+ public RandomAccessibleIntervalMipmapSource(
+ final RandomAccessibleInterval< T >[] imgs,
+ final T type,
+ final AffineTransform3D[] mipmapTransforms,
+ final VoxelDimensions voxelDimensions,
+ final String name,
+ final boolean doBoundingBoxCulling )
+ {
+ super( type, name, voxelDimensions, doBoundingBoxCulling );
+ assert imgs.length == mipmapTransforms.length : "Number of mipmaps and scale factors do not match.";
+
+ this.mipmapSources = imgs;
+ this.mipmapTransforms = mipmapTransforms;
+ }
+
+ public RandomAccessibleIntervalMipmapSource(
+ final RandomAccessibleInterval< T >[] imgs,
+ final T type,
+ final double[][] mipmapScales,
+ final VoxelDimensions voxelDimensions,
+ final AffineTransform3D sourceTransform,
+ final String name,
+ final boolean doBoundingBoxCulling )
+ {
+ super( type, name, voxelDimensions, doBoundingBoxCulling );
+ assert imgs.length == mipmapScales.length : "Number of mipmaps and scale factors do not match.";
+
+ this.mipmapSources = imgs;
+ this.mipmapTransforms = new AffineTransform3D[ mipmapScales.length ];
+ for ( int s = 0; s < mipmapScales.length; ++s )
+ {
+ final AffineTransform3D mipmapTransform = new AffineTransform3D();
+ mipmapTransform.set(
+ mipmapScales[ s ][ 0 ], 0, 0, 0.5 * ( mipmapScales[ s ][ 0 ] - 1 ),
+ 0, mipmapScales[ s ][ 1 ], 0, 0.5 * ( mipmapScales[ s ][ 1 ] - 1 ),
+ 0, 0, mipmapScales[ s ][ 2 ], 0.5 * ( mipmapScales[ s ][ 2 ] - 1 ) );
+ mipmapTransform.preConcatenate(sourceTransform);
+ mipmapTransforms[ s ] = mipmapTransform;
+ }
+ }
+
+ public RandomAccessibleIntervalMipmapSource(
+ final RandomAccessibleInterval< T >[] imgs,
+ final T type,
+ final double[][] mipmapScales,
+ final VoxelDimensions voxelDimensions,
+ final AffineTransform3D sourceTransform,
+ final String name )
+ {
+ this( imgs, type, mipmapScales, voxelDimensions, sourceTransform, name, true );
+ }
+
+ public RandomAccessibleIntervalMipmapSource(
+ final RandomAccessibleInterval< T >[] imgs,
+ final T type,
+ final double[][] mipmapScales,
+ final VoxelDimensions voxelDimensions,
+ final String name )
+ {
+ this(imgs, type, mipmapScales, voxelDimensions, new AffineTransform3D(), name);
+ }
+
+ @Override
+ public RandomAccessibleInterval< T > getSource( final int t, final int level )
+ {
+ return mipmapSources[ level ];
+ }
+
+ @Override
+ public synchronized void getSourceTransform( final int t, final int level, final AffineTransform3D transform )
+ {
+ transform.set( mipmapTransforms[ level ] );
+ }
+
+ @Override
+ public int getNumMipmapLevels()
+ {
+ return mipmapSources.length;
+ }
+
+ public < V extends Volatile< T > & NumericType< V > > VolatileRandomAccessibleIntervalMipmapSource< T, V > asVolatile( final V vType, final SharedQueue queue )
+ {
+ return new VolatileRandomAccessibleIntervalMipmapSource<>( this, vType, queue );
+ }
+
+ public < V extends Volatile< T > & NumericType< V > > VolatileRandomAccessibleIntervalMipmapSource< T, V > asVolatile( final Supplier< V > vTypeSupplier, final SharedQueue queue )
+ {
+ return new VolatileRandomAccessibleIntervalMipmapSource<>( this, vTypeSupplier, queue );
+ }
+
+ @SuppressWarnings( { "unchecked", "rawtypes" } )
+ public < V extends Volatile< T > & NumericType< V > > VolatileRandomAccessibleIntervalMipmapSource< T, V > asVolatile( final SharedQueue queue )
+ {
+ final T t = getType();
+ if ( t instanceof NativeType )
+ return new VolatileRandomAccessibleIntervalMipmapSource<>( this, ( V )VolatileTypeMatcher.getVolatileTypeForType( ( NativeType )getType() ), queue );
+ else
+ throw new UnsupportedOperationException( "This method only works for sources of NativeType." );
+ }
+}
diff --git a/src/main/java/bdv/util/RandomAccessibleIntervalMipmapSource4D.java b/src/main/java/bdv/util/RandomAccessibleIntervalMipmapSource4D.java
new file mode 100644
index 00000000..87d4e08e
--- /dev/null
+++ b/src/main/java/bdv/util/RandomAccessibleIntervalMipmapSource4D.java
@@ -0,0 +1,226 @@
+/*
+ * #%L
+ * BigDataViewer core classes with minimal dependencies.
+ * %%
+ * Copyright (C) 2012 - 2024 BigDataViewer developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.util;
+
+import java.util.Arrays;
+import java.util.function.Supplier;
+
+import bdv.cache.SharedQueue;
+import bdv.util.volatiles.VolatileTypeMatcher;
+import bdv.viewer.Interpolation;
+import mpicbg.spim.data.sequence.VoxelDimensions;
+import net.imglib2.Interval;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.RealRandomAccessible;
+import net.imglib2.Volatile;
+import net.imglib2.realtransform.AffineTransform3D;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.numeric.NumericType;
+import net.imglib2.view.Views;
+
+public class RandomAccessibleIntervalMipmapSource4D< T extends NumericType< T > > extends AbstractSource< T >
+{
+ protected final RandomAccessibleInterval< T >[] mipmapSources;
+
+ protected final long minT, maxT;
+
+ protected int currentTimePointIndex;
+
+ private final RandomAccessibleInterval< T >[] currentMipmaps;
+
+ private final RealRandomAccessible< T >[][] currentInterpolatedSources;
+
+ protected final AffineTransform3D[] mipmapTransforms;
+
+ private static boolean assertAllTDimensionsEqual(final Interval[] intervals) {
+
+ final long min = intervals[0].min(3);
+ final long max = intervals[0].min(3);
+
+ for (int i = 1; i < intervals.length; ++i)
+ if (!(intervals[i].min(3) == min && intervals[i].max(3) == max))
+ return false;
+
+ return true;
+ }
+
+ public RandomAccessibleIntervalMipmapSource4D(
+ final RandomAccessibleInterval< T >[] imgs,
+ final T type,
+ final AffineTransform3D[] mipmapTransforms,
+ final VoxelDimensions voxelDimensions,
+ final String name,
+ final boolean doBoundingBoxCulling )
+ {
+ super( type, name, voxelDimensions, doBoundingBoxCulling );
+ assert imgs.length == mipmapTransforms.length : "Number of mipmaps and scale factors do not match.";
+ assert assertAllTDimensionsEqual(imgs) : "Mipmaps have different numbers of timepoints.";
+
+ this.mipmapSources = imgs;
+ currentMipmaps = new RandomAccessibleInterval[ imgs.length ];
+ this.mipmapTransforms = mipmapTransforms;
+
+ minT = mipmapSources[0].min(3);
+ maxT = mipmapSources[0].max(3);
+
+ currentInterpolatedSources = new RealRandomAccessible[ Interpolation.values().length ][ imgs.length ];
+ loadTimepoint( 0 );
+ }
+
+ public RandomAccessibleIntervalMipmapSource4D(
+ final RandomAccessibleInterval< T >[] imgs,
+ final T type,
+ final double[][] mipmapScales,
+ final VoxelDimensions voxelDimensions,
+ final AffineTransform3D sourceTransform,
+ final String name,
+ final boolean doBoundingBoxCulling )
+ {
+ super( type, name, voxelDimensions, doBoundingBoxCulling );
+ assert imgs.length == mipmapScales.length : "Number of mipmaps and scale factors do not match.";
+ assert assertAllTDimensionsEqual(imgs) : "Mipmaps have different numbers of timepoints.";
+
+ this.mipmapSources = imgs;
+ currentMipmaps = new RandomAccessibleInterval[ imgs.length ];
+ this.mipmapTransforms = new AffineTransform3D[ mipmapScales.length ];
+ for ( int s = 0; s < mipmapScales.length; ++s )
+ {
+ final AffineTransform3D mipmapTransform = new AffineTransform3D();
+ mipmapTransform.set(
+ mipmapScales[ s ][ 0 ], 0, 0, 0.5 * ( mipmapScales[ s ][ 0 ] - 1 ),
+ 0, mipmapScales[ s ][ 1 ], 0, 0.5 * ( mipmapScales[ s ][ 1 ] - 1 ),
+ 0, 0, mipmapScales[ s ][ 2 ], 0.5 * ( mipmapScales[ s ][ 2 ] - 1 ) );
+ mipmapTransform.preConcatenate(sourceTransform);
+ mipmapTransforms[ s ] = mipmapTransform;
+ }
+
+ minT = mipmapSources[0].min(3);
+ maxT = mipmapSources[0].max(3);
+
+ currentInterpolatedSources = new RealRandomAccessible[ Interpolation.values().length ][ imgs.length ];
+ loadTimepoint( 0 );
+ }
+
+ public RandomAccessibleIntervalMipmapSource4D(
+ final RandomAccessibleInterval< T >[] imgs,
+ final T type,
+ final double[][] mipmapScales,
+ final VoxelDimensions voxelDimensions,
+ final AffineTransform3D sourceTransform,
+ final String name )
+ {
+ this( imgs, type, mipmapScales, voxelDimensions, sourceTransform, name, true );
+ }
+
+ public RandomAccessibleIntervalMipmapSource4D(
+ final RandomAccessibleInterval< T >[] imgs,
+ final T type,
+ final double[][] mipmapScales,
+ final VoxelDimensions voxelDimensions,
+ final String name )
+ {
+ this(imgs, type, mipmapScales, voxelDimensions, new AffineTransform3D(), name);
+ }
+
+ private void loadTimepoint( final int timepointIndex )
+ {
+ currentTimePointIndex = timepointIndex;
+ if ( isPresent( timepointIndex ) )
+ {
+ final T zero = getType().createVariable();
+ zero.setZero();
+ for ( int level = 0; level < currentMipmaps.length; ++level )
+ {
+ currentMipmaps[level] = Views.hyperSlice(mipmapSources[level], 3, timepointIndex );
+ for ( final Interpolation method : Interpolation.values() )
+ currentInterpolatedSources[ method.ordinal() ][ level ] =
+ Views.interpolate( Views.extendValue( currentMipmaps[level], zero ), interpolators.get( method ) );
+ }
+ }
+ else
+ {
+ Arrays.fill( currentMipmaps, null );
+ Arrays.fill( currentInterpolatedSources, null );
+ }
+ }
+
+ @Override
+ public boolean isPresent( final int t )
+ {
+ return minT <= t && t <= maxT;
+ }
+
+ @Override
+ public RandomAccessibleInterval< T > getSource( final int t, final int level )
+ {
+ if ( t != currentTimePointIndex )
+ loadTimepoint( t );
+ return currentMipmaps[ level ];
+ }
+
+ @Override
+ public RealRandomAccessible< T > getInterpolatedSource( final int t, final int level, final Interpolation method )
+ {
+ if ( t != currentTimePointIndex )
+ loadTimepoint( t );
+ return currentInterpolatedSources[ method.ordinal() ][ level ];
+ }
+
+ @Override
+ public synchronized void getSourceTransform( final int t, final int level, final AffineTransform3D transform )
+ {
+ transform.set( mipmapTransforms[ level ] );
+ }
+
+ @Override
+ public int getNumMipmapLevels()
+ {
+ return mipmapSources.length;
+ }
+
+ public < V extends Volatile< T > & NumericType< V > > VolatileSource< T, V > asVolatile( final V vType, final SharedQueue queue )
+ {
+ return new VolatileSource<>( this, vType, queue );
+ }
+
+ public < V extends Volatile< T > & NumericType< V > > VolatileSource< T, V > asVolatile( final Supplier< V > vTypeSupplier, final SharedQueue queue )
+ {
+ return new VolatileSource<>( this, vTypeSupplier, queue );
+ }
+
+ @SuppressWarnings( { "unchecked", "rawtypes" } )
+ public < V extends Volatile< T > & NumericType< V > > VolatileSource< T, V > asVolatile( final SharedQueue queue )
+ {
+ final T t = getType();
+ if ( t instanceof NativeType )
+ return new VolatileSource<>( this, ( V )VolatileTypeMatcher.getVolatileTypeForType( ( NativeType )getType() ), queue );
+ else
+ throw new UnsupportedOperationException( "This method only works for sources of NativeType." );
+ }
+}
diff --git a/src/main/java/bdv/util/RandomAccessibleIntervalSource.java b/src/main/java/bdv/util/RandomAccessibleIntervalSource.java
new file mode 100644
index 00000000..8697ca91
--- /dev/null
+++ b/src/main/java/bdv/util/RandomAccessibleIntervalSource.java
@@ -0,0 +1,98 @@
+/*
+ * #%L
+ * BigDataViewer core classes with minimal dependencies.
+ * %%
+ * Copyright (C) 2012 - 2024 BigDataViewer developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.util;
+
+import bdv.viewer.Interpolation;
+import mpicbg.spim.data.sequence.DefaultVoxelDimensions;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.RealRandomAccessible;
+import net.imglib2.realtransform.AffineTransform3D;
+import net.imglib2.type.numeric.NumericType;
+import net.imglib2.view.Views;
+
+public class RandomAccessibleIntervalSource< T extends NumericType< T > > extends AbstractSource< T >
+{
+ private final RandomAccessibleInterval< T > source;
+
+ private final RealRandomAccessible< T >[] interpolatedSources;
+
+ private final AffineTransform3D sourceTransform;
+
+ public RandomAccessibleIntervalSource(
+ final RandomAccessibleInterval< T > img,
+ final T type,
+ final String name )
+ {
+ this( img, type, new AffineTransform3D(), name, true );
+ }
+
+ public RandomAccessibleIntervalSource(
+ final RandomAccessibleInterval< T > img,
+ final T type,
+ final AffineTransform3D sourceTransform,
+ final String name )
+ {
+ this( img, type, sourceTransform, name, true );
+ }
+
+ public RandomAccessibleIntervalSource(
+ final RandomAccessibleInterval< T > img,
+ final T type,
+ final AffineTransform3D sourceTransform,
+ final String name,
+ final boolean doBoundingBoxCulling )
+ {
+ super( type, name, new DefaultVoxelDimensions( img.numDimensions() ), doBoundingBoxCulling );
+ this.source = img;
+ this.sourceTransform = sourceTransform;
+ interpolatedSources = new RealRandomAccessible[ Interpolation.values().length ];
+ final T zero = getType().createVariable();
+ zero.setZero();
+ for ( final Interpolation method : Interpolation.values() )
+ interpolatedSources[ method.ordinal() ] = Views.interpolate( Views.extendValue( source, zero ), interpolators.get( method ) );
+ }
+
+ @Override
+ public RandomAccessibleInterval< T > getSource( final int t, final int level )
+ {
+ return source;
+ }
+
+ @Override
+ public RealRandomAccessible< T > getInterpolatedSource( final int t, final int level, final Interpolation method )
+ {
+ return interpolatedSources[ method.ordinal() ];
+ }
+
+ @Override
+ public synchronized void getSourceTransform( final int t, final int level, final AffineTransform3D transform )
+ {
+ transform.set( sourceTransform );
+ }
+}
diff --git a/src/main/java/bdv/util/RandomAccessibleIntervalSource4D.java b/src/main/java/bdv/util/RandomAccessibleIntervalSource4D.java
new file mode 100644
index 00000000..6a68f9c6
--- /dev/null
+++ b/src/main/java/bdv/util/RandomAccessibleIntervalSource4D.java
@@ -0,0 +1,118 @@
+/*
+ * #%L
+ * BigDataViewer core classes with minimal dependencies.
+ * %%
+ * Copyright (C) 2012 - 2024 BigDataViewer developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.util;
+
+import java.util.Arrays;
+
+import bdv.viewer.Interpolation;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.RealRandomAccessible;
+import net.imglib2.realtransform.AffineTransform3D;
+import net.imglib2.type.numeric.NumericType;
+import net.imglib2.view.Views;
+
+public class RandomAccessibleIntervalSource4D< T extends NumericType< T > > extends AbstractSource< T >
+{
+ private final RandomAccessibleInterval< T > source;
+
+ protected int currentTimePointIndex;
+
+ private RandomAccessibleInterval< T > currentSource;
+
+ private final RealRandomAccessible< T >[] currentInterpolatedSources;
+
+ private final AffineTransform3D sourceTransform;
+
+ public RandomAccessibleIntervalSource4D(
+ final RandomAccessibleInterval< T > img,
+ final T type,
+ final String name )
+ {
+ this( img, type, new AffineTransform3D(), name );
+ }
+
+ public RandomAccessibleIntervalSource4D(
+ final RandomAccessibleInterval< T > img,
+ final T type,
+ final AffineTransform3D sourceTransform,
+ final String name )
+ {
+ super( type, name );
+ this.source = img;
+ this.sourceTransform = sourceTransform;
+ currentInterpolatedSources = new RealRandomAccessible[ Interpolation.values().length ];
+ loadTimepoint( 0 );
+ }
+
+ private void loadTimepoint( final int timepointIndex )
+ {
+ currentTimePointIndex = timepointIndex;
+ if ( isPresent( timepointIndex ) )
+ {
+ final T zero = getType().createVariable();
+ zero.setZero();
+ currentSource = Views.hyperSlice( source, 3, timepointIndex );
+ for ( final Interpolation method : Interpolation.values() )
+ currentInterpolatedSources[ method.ordinal() ] = Views.interpolate( Views.extendValue( currentSource, zero ), interpolators.get( method ) );
+ }
+ else
+ {
+ currentSource = null;
+ Arrays.fill( currentInterpolatedSources, null );
+ }
+ }
+
+ @Override
+ public boolean isPresent( final int t )
+ {
+ return source.min( 3 ) <= t && t <= source.max( 3 );
+ }
+
+ @Override
+ public RandomAccessibleInterval< T > getSource( final int t, final int level )
+ {
+ if ( t != currentTimePointIndex )
+ loadTimepoint( t );
+ return currentSource;
+ }
+
+ @Override
+ public RealRandomAccessible< T > getInterpolatedSource( final int t, final int level, final Interpolation method )
+ {
+ if ( t != currentTimePointIndex )
+ loadTimepoint( t );
+ return currentInterpolatedSources[ method.ordinal() ];
+ }
+
+ @Override
+ public synchronized void getSourceTransform( final int t, final int level, final AffineTransform3D transform )
+ {
+ transform.set( sourceTransform );
+ }
+}
diff --git a/src/main/java/bdv/util/RandomAccessibleSource.java b/src/main/java/bdv/util/RandomAccessibleSource.java
new file mode 100644
index 00000000..fc79a907
--- /dev/null
+++ b/src/main/java/bdv/util/RandomAccessibleSource.java
@@ -0,0 +1,104 @@
+/*
+ * #%L
+ * BigDataViewer core classes with minimal dependencies.
+ * %%
+ * Copyright (C) 2012 - 2024 BigDataViewer developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.util;
+
+import bdv.viewer.Interpolation;
+import net.imglib2.Interval;
+import net.imglib2.RandomAccessible;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.RealRandomAccessible;
+import net.imglib2.realtransform.AffineTransform3D;
+import net.imglib2.type.numeric.NumericType;
+import net.imglib2.view.Views;
+
+public class RandomAccessibleSource< T extends NumericType< T > > extends AbstractSource< T >
+{
+ private final RandomAccessible< T > source;
+
+ private final Interval interval;
+
+ private final RealRandomAccessible< T >[] interpolatedSources;
+
+ private final AffineTransform3D sourceTransform;
+
+ public RandomAccessibleSource(
+ final RandomAccessible< T > img,
+ final Interval interval,
+ final T type,
+ final String name )
+ {
+ this( img, interval, type, new AffineTransform3D(), name, false );
+ }
+
+ public RandomAccessibleSource(
+ final RandomAccessible< T > img,
+ final Interval interval,
+ final T type,
+ final AffineTransform3D sourceTransform,
+ final String name )
+ {
+ this( img, interval, type, sourceTransform, name, false );
+ }
+
+ public RandomAccessibleSource(
+ final RandomAccessible< T > img,
+ final Interval interval,
+ final T type,
+ final AffineTransform3D sourceTransform,
+ final String name,
+ final boolean doBoundingBoxCulling )
+ {
+ super( type, name, doBoundingBoxCulling );
+ this.source = img;
+ this.interval = interval;
+ this.sourceTransform = sourceTransform;
+ interpolatedSources = new RealRandomAccessible[ Interpolation.values().length ];
+ for ( final Interpolation method : Interpolation.values() )
+ interpolatedSources[ method.ordinal() ] = Views.interpolate( source, interpolators.get( method ) );
+
+ }
+
+ @Override
+ public RandomAccessibleInterval< T > getSource( final int t, final int level )
+ {
+ return Views.interval( source, interval );
+ }
+
+ @Override
+ public RealRandomAccessible< T > getInterpolatedSource( final int t, final int level, final Interpolation method )
+ {
+ return interpolatedSources[ method.ordinal() ];
+ }
+
+ @Override
+ public synchronized void getSourceTransform( final int t, final int level, final AffineTransform3D transform )
+ {
+ transform.set( sourceTransform );
+ }
+}
diff --git a/src/main/java/bdv/util/RandomAccessibleSource4D.java b/src/main/java/bdv/util/RandomAccessibleSource4D.java
new file mode 100644
index 00000000..617052b8
--- /dev/null
+++ b/src/main/java/bdv/util/RandomAccessibleSource4D.java
@@ -0,0 +1,142 @@
+/*
+ * #%L
+ * BigDataViewer core classes with minimal dependencies.
+ * %%
+ * Copyright (C) 2012 - 2024 BigDataViewer developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.util;
+
+import java.util.Arrays;
+
+import bdv.viewer.Interpolation;
+import net.imglib2.Interval;
+import net.imglib2.RandomAccessible;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.RealRandomAccessible;
+import net.imglib2.realtransform.AffineTransform3D;
+import net.imglib2.type.numeric.NumericType;
+import net.imglib2.util.Intervals;
+import net.imglib2.view.Views;
+
+public class RandomAccessibleSource4D< T extends NumericType< T > > extends AbstractSource< T >
+{
+ private final RandomAccessible< T > source;
+
+ private final Interval interval;
+
+ private final Interval timeSliceInterval;
+
+ protected int currentTimePointIndex;
+
+ private RandomAccessibleInterval< T > currentSource;
+
+ private final RealRandomAccessible< T >[] currentInterpolatedSources;
+
+ private final AffineTransform3D sourceTransform;
+
+ public RandomAccessibleSource4D(
+ final RandomAccessible< T > img,
+ final Interval interval,
+ final T type,
+ final String name )
+ {
+ this( img, interval, type, new AffineTransform3D(), name, false );
+ }
+ public RandomAccessibleSource4D(
+ final RandomAccessible< T > img,
+ final Interval interval,
+ final T type,
+ final AffineTransform3D sourceTransform,
+ final String name )
+ {
+ this( img, interval, type, sourceTransform, name, false );
+ }
+
+ public RandomAccessibleSource4D(
+ final RandomAccessible< T > img,
+ final Interval interval,
+ final T type,
+ final AffineTransform3D sourceTransform,
+ final String name,
+ final boolean doBoundingBoxCulling )
+ {
+ super( type, name, doBoundingBoxCulling );
+ this.source = img;
+ this.interval = interval;
+ this.timeSliceInterval = Intervals.createMinMax(
+ interval.min( 0 ), interval.min( 1 ), interval.min( 2 ),
+ interval.max( 0 ), interval.max( 1 ), interval.max( 2 ) );
+ this.sourceTransform = sourceTransform;
+ currentInterpolatedSources = new RealRandomAccessible[ Interpolation.values().length ];
+ loadTimepoint( 0 );
+ }
+
+ private void loadTimepoint( final int timepointIndex )
+ {
+ currentTimePointIndex = timepointIndex;
+ if ( isPresent( timepointIndex ) )
+ {
+ final T zero = getType().createVariable();
+ zero.setZero();
+ final RandomAccessible< T > slice = Views.hyperSlice( source, 3, timepointIndex );
+ currentSource = Views.interval( slice, timeSliceInterval );
+ for ( final Interpolation method : Interpolation.values() )
+ currentInterpolatedSources[ method.ordinal() ] = Views.interpolate( slice, interpolators.get( method ) );
+ }
+ else
+ {
+ currentSource = null;
+ Arrays.fill( currentInterpolatedSources, null );
+ }
+ }
+
+ @Override
+ public boolean isPresent( final int t )
+ {
+ return interval.min( 3 ) <= t && t <= interval.max( 3 );
+ }
+
+ @Override
+ public RandomAccessibleInterval< T > getSource( final int t, final int level )
+ {
+ if ( t != currentTimePointIndex )
+ loadTimepoint( t );
+ return currentSource;
+ }
+
+ @Override
+ public RealRandomAccessible< T > getInterpolatedSource( final int t, final int level, final Interpolation method )
+ {
+ if ( t != currentTimePointIndex )
+ loadTimepoint( t );
+ return currentInterpolatedSources[ method.ordinal() ];
+ }
+
+ @Override
+ public synchronized void getSourceTransform( final int t, final int level, final AffineTransform3D transform )
+ {
+ transform.set( sourceTransform );
+ }
+}
diff --git a/src/main/java/bdv/util/RealRandomAccessibleIntervalSource.java b/src/main/java/bdv/util/RealRandomAccessibleIntervalSource.java
new file mode 100644
index 00000000..d7d5825b
--- /dev/null
+++ b/src/main/java/bdv/util/RealRandomAccessibleIntervalSource.java
@@ -0,0 +1,86 @@
+/*
+ * #%L
+ * BigDataViewer core classes with minimal dependencies.
+ * %%
+ * Copyright (C) 2012 - 2024 BigDataViewer developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.util;
+
+import mpicbg.spim.data.sequence.DefaultVoxelDimensions;
+import net.imglib2.Interval;
+import net.imglib2.RealRandomAccessible;
+import net.imglib2.realtransform.AffineTransform3D;
+import net.imglib2.type.Type;
+
+public class RealRandomAccessibleIntervalSource< T extends Type< T > > extends RealRandomAccessibleSource< T >
+{
+ private final Interval interval;
+
+ private final AffineTransform3D sourceTransform;
+
+ public RealRandomAccessibleIntervalSource(
+ final RealRandomAccessible< T > accessible,
+ final Interval interval,
+ final T type,
+ final String name )
+ {
+ this( accessible, interval, type, new AffineTransform3D(), name, false );
+ }
+
+ public RealRandomAccessibleIntervalSource(
+ final RealRandomAccessible< T > accessible,
+ final Interval interval,
+ final T type,
+ final AffineTransform3D sourceTransform,
+ final String name )
+ {
+ this( accessible, interval, type, sourceTransform, name, false );
+ }
+
+ public RealRandomAccessibleIntervalSource(
+ final RealRandomAccessible< T > accessible,
+ final Interval interval,
+ final T type,
+ final AffineTransform3D sourceTransform,
+ final String name,
+ final boolean doBoundingBoxIntersectionCheck )
+ {
+ super( accessible, type, name, new DefaultVoxelDimensions( -1 ), doBoundingBoxIntersectionCheck );
+ this.interval = interval;
+ this.sourceTransform = sourceTransform;
+ }
+
+ @Override
+ public synchronized void getSourceTransform( final int t, final int level, final AffineTransform3D transform )
+ {
+ transform.set( sourceTransform );
+ }
+
+ @Override
+ public Interval getInterval( final int t, final int level )
+ {
+ return interval;
+ }
+}
diff --git a/src/main/java/bdv/util/VirtualChannels.java b/src/main/java/bdv/util/VirtualChannels.java
new file mode 100644
index 00000000..af892fd9
--- /dev/null
+++ b/src/main/java/bdv/util/VirtualChannels.java
@@ -0,0 +1,190 @@
+/*-
+ * #%L
+ * BigDataViewer core classes with minimal dependencies.
+ * %%
+ * Copyright (C) 2012 - 2024 BigDataViewer developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import bdv.viewer.SourceAndConverter;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.converter.TypeIdentity;
+import net.imglib2.realtransform.AffineTransform3D;
+import net.imglib2.type.numeric.ARGBType;
+
+
+/**
+ * The current application for VirtualChannel sources is the following scenario:
+ *
+ * We have a labeling and want to display it using lookup tables to convert
+ * labels to ARGBType. From the same labeling we want to make multiple channels,
+ * e.g., selected ROIs, ROIs having property A, property B, etc. These could be
+ * added to BDV as individually converted images. So we could use N lookup
+ * tables to display N converted images. Instead, it is more efficient to merge
+ * the N lookup tables and then display only one converted image. We still want
+ * to be able to control display range and color settings for the N
+ * "virtual channels" individually. So {@link VirtualChannels} adds N fake
+ * sources to the BDV. Each fake source is used to control visibility and
+ * settings for one lookup table. Only one of the fake source will then actually
+ * render the converted img.
+ *
+ * @author Tobias Pietzsch <tobias.pietzsch@gmail.com>
+ */
+public class VirtualChannels
+{
+ public interface VirtualChannel
+ {
+ void updateVisibility();
+
+ void updateSetupParameters();
+ }
+
+ static List< BdvVirtualChannelSource > show(
+ final RandomAccessibleInterval< ARGBType > img,
+ final List< ? extends VirtualChannel > virtualChannels,
+ final String name,
+ final BdvOptions options )
+ {
+ final Bdv bdv = options.values.addTo();
+ final BdvHandle handle = ( bdv == null )
+ ? new BdvHandleFrame( options )
+ : bdv.getBdvHandle();
+ final AffineTransform3D sourceTransform = options.values.getSourceTransform();
+ AxisOrder axisOrder = options.values.axisOrder();
+ axisOrder = AxisOrder.getAxisOrder( axisOrder, img, handle.is2D() );
+
+ final ArrayList< RandomAccessibleInterval< ARGBType > > stacks = AxisOrder.splitInputStackIntoSourceStacks( img, axisOrder );
+ if ( stacks.size() != 1 )
+ throw new IllegalArgumentException( "The RandomAccessibleInterval of a VirtualChannelSource must have exactly one channel!" );
+ final RandomAccessibleInterval< ARGBType > stack = stacks.get( 0 );
+
+ final List< BdvVirtualChannelSource > bdvSources = new ArrayList<>();
+
+ final int numTimepoints = ( stack.numDimensions() > 3 ) ? ( int ) stack.max( 3 ) + 1 : 1;
+ final ChannelSourceCoordinator coordinator = new ChannelSourceCoordinator();
+ for ( final VirtualChannel vc : virtualChannels )
+ {
+ final ChannelSource source = ( stack.numDimensions() > 3 )
+ ? new ChannelSource4D( stack, coordinator, sourceTransform, name )
+ : new DefaultChannelSource( stack, coordinator, sourceTransform, name );
+ final int setupId = handle.getUnusedSetupId();
+ final PlaceHolderConverterSetup setup = new PlaceHolderConverterSetup( setupId, 0, 255, new ARGBType( 0xffffffff ) );
+ final SourceAndConverter< ARGBType > soc = source.getSourceAndConverter();
+ handle.add( Collections.singletonList( setup ), Collections.singletonList( soc ), numTimepoints );
+
+ final PlaceHolderOverlayInfo info = new PlaceHolderOverlayInfo( handle.getViewerPanel(), soc, setup );
+ coordinator.sharedInfos.add( info );
+ setup.setupChangeListeners().add( s -> vc.updateSetupParameters() );
+ info.visibilityChangeListeners().add( vc::updateVisibility );
+ final BdvVirtualChannelSource bdvSource = new BdvVirtualChannelSource( handle, numTimepoints, setup, soc, info, coordinator );
+ handle.addBdvSource( bdvSource );
+ bdvSources.add( bdvSource );
+ }
+
+ return bdvSources;
+ }
+
+ static class ChannelSourceCoordinator
+ {
+ List< PlaceHolderOverlayInfo > sharedInfos = new ArrayList<>();
+
+ boolean shouldBePresent( final ChannelSource source )
+ {
+ for ( final PlaceHolderOverlayInfo info : sharedInfos )
+ if ( info.isVisible() )
+ return info.getSource().equals( source.getSourceAndConverter() );
+ return false;
+ }
+ }
+
+ interface ChannelSource
+ {
+ SourceAndConverter< ARGBType > getSourceAndConverter();
+ }
+
+ static class DefaultChannelSource extends RandomAccessibleIntervalSource< ARGBType > implements ChannelSource
+ {
+ private final ChannelSourceCoordinator coordinator;
+
+ private final SourceAndConverter< ARGBType > soc;
+
+ public DefaultChannelSource(
+ final RandomAccessibleInterval< ARGBType > img,
+ final ChannelSourceCoordinator coordinator,
+ final AffineTransform3D sourceTransform,
+ final String name )
+ {
+ super( img, new ARGBType(), sourceTransform, name );
+ this.coordinator = coordinator;
+ this.soc = new SourceAndConverter<>( this, new TypeIdentity< >() );
+ }
+
+ @Override
+ public boolean isPresent( final int t )
+ {
+ return super.isPresent( t ) && coordinator.shouldBePresent( this );
+ }
+
+ @Override
+ public SourceAndConverter< ARGBType > getSourceAndConverter()
+ {
+ return soc;
+ }
+ }
+
+ static class ChannelSource4D extends RandomAccessibleIntervalSource4D< ARGBType > implements ChannelSource
+ {
+ private final ChannelSourceCoordinator coordinator;
+
+ private final SourceAndConverter< ARGBType > soc;
+
+ public ChannelSource4D(
+ final RandomAccessibleInterval< ARGBType > img,
+ final ChannelSourceCoordinator coordinator,
+ final AffineTransform3D sourceTransform,
+ final String name )
+ {
+ super( img, new ARGBType(), sourceTransform, name );
+ this.coordinator = coordinator;
+ this.soc = new SourceAndConverter<>( this, new TypeIdentity< >() );
+ }
+
+ @Override
+ public boolean isPresent( final int t )
+ {
+ return super.isPresent( t ) && coordinator.shouldBePresent( this );
+ }
+
+ @Override
+ public SourceAndConverter< ARGBType > getSourceAndConverter()
+ {
+ return soc;
+ }
+ }
+}
diff --git a/src/main/java/bdv/util/VolatileRandomAccessibleIntervalMipmapSource.java b/src/main/java/bdv/util/VolatileRandomAccessibleIntervalMipmapSource.java
new file mode 100644
index 00000000..30a36da0
--- /dev/null
+++ b/src/main/java/bdv/util/VolatileRandomAccessibleIntervalMipmapSource.java
@@ -0,0 +1,58 @@
+/*
+ * #%L
+ * BigDataViewer core classes with minimal dependencies.
+ * %%
+ * Copyright (C) 2012 - 2024 BigDataViewer developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.util;
+
+import java.util.function.Supplier;
+
+import bdv.cache.SharedQueue;
+import net.imglib2.Volatile;
+import net.imglib2.type.numeric.NumericType;
+
+/**
+ * @deprecated use {@code VolatileSource}
+ */
+@Deprecated
+public class VolatileRandomAccessibleIntervalMipmapSource< T extends NumericType< T >, V extends Volatile< T > & NumericType< V > > extends VolatileSource< T, V >
+{
+ public VolatileRandomAccessibleIntervalMipmapSource(
+ final RandomAccessibleIntervalMipmapSource< T > source,
+ final V type,
+ final SharedQueue queue )
+ {
+ super( source, type, queue );
+ }
+
+ public VolatileRandomAccessibleIntervalMipmapSource(
+ final RandomAccessibleIntervalMipmapSource< T > source,
+ final Supplier< V > typeSupplier,
+ final SharedQueue queue )
+ {
+ super( source, typeSupplier, queue );
+ }
+}
diff --git a/src/main/java/bdv/util/VolatileSource.java b/src/main/java/bdv/util/VolatileSource.java
new file mode 100644
index 00000000..4f9de3f1
--- /dev/null
+++ b/src/main/java/bdv/util/VolatileSource.java
@@ -0,0 +1,91 @@
+/*
+ * #%L
+ * BigDataViewer core classes with minimal dependencies.
+ * %%
+ * Copyright (C) 2012 - 2024 BigDataViewer developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.util;
+
+import java.util.function.Supplier;
+
+import bdv.cache.SharedQueue;
+import bdv.util.volatiles.VolatileViews;
+import bdv.viewer.Source;
+import mpicbg.spim.data.sequence.VoxelDimensions;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.Volatile;
+import net.imglib2.cache.volatiles.CacheHints;
+import net.imglib2.cache.volatiles.LoadingStrategy;
+import net.imglib2.realtransform.AffineTransform3D;
+import net.imglib2.type.numeric.NumericType;
+
+public class VolatileSource< T extends NumericType< T >, V extends Volatile< T > & NumericType< V > > extends AbstractSource< V >
+{
+ private final Source< T > source;
+
+ private SharedQueue queue;
+
+ public VolatileSource(
+ final Source< T > source,
+ final V type,
+ final SharedQueue queue )
+ {
+ super( type, source.getName() );
+ this.source = source;
+ this.queue = queue;
+ }
+
+ public VolatileSource(
+ final Source< T > source,
+ final Supplier< V > typeSupplier,
+ final SharedQueue queue )
+ {
+ this( source, typeSupplier.get(), queue );
+ }
+
+ @Override
+ public RandomAccessibleInterval< V > getSource( final int t, final int level )
+ {
+ return VolatileViews.wrapAsVolatile( source.getSource( t, level ), queue, new CacheHints( LoadingStrategy.VOLATILE, level, true ) );
+ }
+
+ @Override
+ public synchronized void getSourceTransform( final int t, final int level, final AffineTransform3D transform )
+ {
+ source.getSourceTransform( t, level, transform );
+ }
+
+ @Override
+ public VoxelDimensions getVoxelDimensions()
+ {
+ return source.getVoxelDimensions();
+ }
+
+ @Override
+ public int getNumMipmapLevels()
+ {
+ return source.getNumMipmapLevels();
+ }
+}
diff --git a/src/main/java/bdv/util/volatiles/SharedQueue.java b/src/main/java/bdv/util/volatiles/SharedQueue.java
new file mode 100644
index 00000000..0829be55
--- /dev/null
+++ b/src/main/java/bdv/util/volatiles/SharedQueue.java
@@ -0,0 +1,48 @@
+/*-
+ * #%L
+ * BigDataViewer core classes with minimal dependencies.
+ * %%
+ * Copyright (C) 2012 - 2024 BigDataViewer developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.util.volatiles;
+
+/**
+ * @deprecated This class lives now in bigdataviewer-core. Use {@code bdv.cache.SharedQueue} instead.
+ */
+@Deprecated
+public class SharedQueue extends bdv.cache.SharedQueue
+{
+ @Deprecated
+ public SharedQueue( final int numFetcherThreads, final int numPriorities )
+ {
+ super( numFetcherThreads, numPriorities );
+ }
+
+ @Deprecated
+ public SharedQueue( final int numFetcherThreads )
+ {
+ super( numFetcherThreads, 1 );
+ }
+}
diff --git a/src/main/java/bdv/util/volatiles/VolatileRandomAccessibleIntervalView.java b/src/main/java/bdv/util/volatiles/VolatileRandomAccessibleIntervalView.java
new file mode 100644
index 00000000..bd833bdb
--- /dev/null
+++ b/src/main/java/bdv/util/volatiles/VolatileRandomAccessibleIntervalView.java
@@ -0,0 +1,73 @@
+/*-
+ * #%L
+ * BigDataViewer core classes with minimal dependencies.
+ * %%
+ * Copyright (C) 2012 - 2024 BigDataViewer developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.util.volatiles;
+
+import net.imglib2.AbstractWrappedInterval;
+import net.imglib2.Interval;
+import net.imglib2.RandomAccess;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.Volatile;
+
+public class VolatileRandomAccessibleIntervalView< T, V extends Volatile< T > >
+ extends AbstractWrappedInterval< RandomAccessibleInterval< V > >
+ implements VolatileView< T, V >, RandomAccessibleInterval< V >
+{
+ private final VolatileViewData< T, V > viewData;
+
+ public VolatileRandomAccessibleIntervalView(
+ final VolatileViewData< T, V > viewData )
+ {
+ super( ( RandomAccessibleInterval< V > ) viewData.getImg() );
+ this.viewData = viewData;
+ }
+
+ @Override
+ public VolatileViewData< T, V > getVolatileViewData()
+ {
+ return viewData;
+ }
+
+ @Override
+ public RandomAccess< V > randomAccess()
+ {
+ return sourceInterval.randomAccess();
+ }
+
+ @Override
+ public RandomAccess< V > randomAccess( final Interval interval )
+ {
+ return sourceInterval.randomAccess( interval );
+ }
+
+ @Override
+ public V getType()
+ {
+ return viewData.getVolatileType();
+ }
+}
diff --git a/src/main/java/bdv/util/volatiles/VolatileRandomAccessibleView.java b/src/main/java/bdv/util/volatiles/VolatileRandomAccessibleView.java
new file mode 100644
index 00000000..05f9909a
--- /dev/null
+++ b/src/main/java/bdv/util/volatiles/VolatileRandomAccessibleView.java
@@ -0,0 +1,77 @@
+/*-
+ * #%L
+ * BigDataViewer core classes with minimal dependencies.
+ * %%
+ * Copyright (C) 2012 - 2024 BigDataViewer developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.util.volatiles;
+
+import net.imglib2.Interval;
+import net.imglib2.RandomAccess;
+import net.imglib2.RandomAccessible;
+import net.imglib2.Volatile;
+
+public class VolatileRandomAccessibleView< T, V extends Volatile< T > >
+ implements VolatileView< T, V >, RandomAccessible< V >
+{
+ private final VolatileViewData< T, V > viewData;
+
+ public VolatileRandomAccessibleView(
+ final VolatileViewData< T, V > viewData )
+ {
+ this.viewData = viewData;
+ }
+
+ @Override
+ public VolatileViewData< T, V > getVolatileViewData()
+ {
+ return viewData;
+ }
+
+ @Override
+ public RandomAccess< V > randomAccess()
+ {
+ return viewData.getImg().randomAccess();
+ }
+
+ @Override
+ public RandomAccess< V > randomAccess( final Interval interval )
+ {
+ return viewData.getImg().randomAccess( interval );
+ }
+
+ @Override
+ public int numDimensions()
+ {
+ return viewData.getImg().numDimensions();
+
+ }
+
+ @Override
+ public V getType()
+ {
+ return viewData.getVolatileType();
+ }
+}
diff --git a/src/main/java/bdv/util/volatiles/VolatileTypeMatcher.java b/src/main/java/bdv/util/volatiles/VolatileTypeMatcher.java
new file mode 100644
index 00000000..5a97a057
--- /dev/null
+++ b/src/main/java/bdv/util/volatiles/VolatileTypeMatcher.java
@@ -0,0 +1,84 @@
+/*-
+ * #%L
+ * BigDataViewer core classes with minimal dependencies.
+ * %%
+ * Copyright (C) 2012 - 2024 BigDataViewer developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.util.volatiles;
+
+import net.imglib2.type.NativeType;
+import net.imglib2.type.numeric.ARGBType;
+import net.imglib2.type.numeric.integer.ByteType;
+import net.imglib2.type.numeric.integer.IntType;
+import net.imglib2.type.numeric.integer.LongType;
+import net.imglib2.type.numeric.integer.ShortType;
+import net.imglib2.type.numeric.integer.UnsignedByteType;
+import net.imglib2.type.numeric.integer.UnsignedIntType;
+import net.imglib2.type.numeric.integer.UnsignedLongType;
+import net.imglib2.type.numeric.integer.UnsignedShortType;
+import net.imglib2.type.numeric.real.DoubleType;
+import net.imglib2.type.numeric.real.FloatType;
+import net.imglib2.type.volatiles.VolatileARGBType;
+import net.imglib2.type.volatiles.VolatileByteType;
+import net.imglib2.type.volatiles.VolatileDoubleType;
+import net.imglib2.type.volatiles.VolatileFloatType;
+import net.imglib2.type.volatiles.VolatileIntType;
+import net.imglib2.type.volatiles.VolatileLongType;
+import net.imglib2.type.volatiles.VolatileShortType;
+import net.imglib2.type.volatiles.VolatileUnsignedByteType;
+import net.imglib2.type.volatiles.VolatileUnsignedIntType;
+import net.imglib2.type.volatiles.VolatileUnsignedLongType;
+import net.imglib2.type.volatiles.VolatileUnsignedShortType;
+
+public class VolatileTypeMatcher
+{
+ public static < T extends NativeType< T > > NativeType< ? > getVolatileTypeForType( final T type )
+ {
+ if ( type instanceof ARGBType )
+ return new VolatileARGBType();
+ else if ( type instanceof FloatType )
+ return new VolatileFloatType();
+ else if ( type instanceof DoubleType )
+ return new VolatileDoubleType();
+ else if ( type instanceof ByteType )
+ return new VolatileByteType();
+ else if ( type instanceof ShortType )
+ return new VolatileShortType();
+ else if ( type instanceof IntType )
+ return new VolatileIntType();
+ else if ( type instanceof LongType )
+ return new VolatileLongType();
+ else if ( type instanceof UnsignedByteType )
+ return new VolatileUnsignedByteType();
+ else if ( type instanceof UnsignedShortType )
+ return new VolatileUnsignedShortType();
+ else if ( type instanceof UnsignedIntType )
+ return new VolatileUnsignedIntType();
+ else if ( type instanceof UnsignedLongType )
+ return new VolatileUnsignedLongType();
+ else
+ return null;
+ }
+}
diff --git a/src/main/java/bdv/util/volatiles/VolatileView.java b/src/main/java/bdv/util/volatiles/VolatileView.java
new file mode 100644
index 00000000..8c6456b1
--- /dev/null
+++ b/src/main/java/bdv/util/volatiles/VolatileView.java
@@ -0,0 +1,46 @@
+/*-
+ * #%L
+ * BigDataViewer core classes with minimal dependencies.
+ * %%
+ * Copyright (C) 2012 - 2024 BigDataViewer developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.util.volatiles;
+
+import net.imglib2.Volatile;
+
+/**
+ * Something that provides {@link VolatileViewData}.
+ *
+ * @param
+ * {@link VolatileViewData} is used while wrapping deeper layers of a view
+ * cascade (ending at a {@link CachedCellImg}) and only on the top layer
+ * wrapped as a {@link RandomAccessible} / {@link RandomAccessibleInterval}.
+ *