( components );
+ }
+
/**
* Positive shear transform of a RandomAccessible using
* {@link ShearTransform}, i.e. c[ shearDimension ] = c[ shearDimension ] +
diff --git a/src/main/java/net/imglib2/view/composite/RealStackCompositeView.java b/src/main/java/net/imglib2/view/composite/RealStackCompositeView.java
new file mode 100644
index 000000000..7a9daddc3
--- /dev/null
+++ b/src/main/java/net/imglib2/view/composite/RealStackCompositeView.java
@@ -0,0 +1,483 @@
+package net.imglib2.view.composite;
+
+import net.imglib2.Localizable;
+import net.imglib2.RealInterval;
+import net.imglib2.RealLocalizable;
+import net.imglib2.RealRandomAccess;
+import net.imglib2.RealRandomAccessible;
+import net.imglib2.View;
+import net.imglib2.view.StackView.StackAccessMode;
+
+/**
+ * A {@link RealStackCompositeView} converts an array of {@link RealRandomAccessible}s
+ * of T into a RealRandomAccessible of {@link Composite} of T.
+ *
+ * This view has the same dimensionality as each source RealRandomAccessible, and
+ * at every position, the i-th value of the composite is the value for the i-th input RealRandomAccessible.
+ *
+ * @author John Bogovic
+ */
+public class RealStackCompositeView< T > implements RealRandomAccessible>, View
+{
+ protected final int n, nd;
+
+ protected final RealRandomAccessible< T >[] sources;
+
+ private final StackAccessMode stackAccessMode;
+
+ /**
+ * Creates a RealStackCompositeView. Every input {@link RealRandomAccessible} must
+ * have the same dimensionality, and be of the same type.
+ *
+ * @param sources the list of RealRandomAccessibles
+ * @param stackAccessMode the mode
+ */
+ public RealStackCompositeView( final RealRandomAccessible< T >[] sources, StackAccessMode stackAccessMode )
+ {
+ assert( sources.length > 0 );
+ this.sources = sources;
+ n = sources.length;
+ nd = sources[0].numDimensions();
+ this.stackAccessMode = stackAccessMode;
+ }
+
+ /**
+ * Creates a RealStackCompositeView. Every input {@link RealRandomAccessible} must
+ * have the same dimensionality, and be of the same type. Uses the DEFAULT
+ * {@link StackAccessMode}.
+ *
+ * @param sources the list of RealRandomAccessibles
+ */
+ public RealStackCompositeView( final RealRandomAccessible< T >[] sources )
+ {
+ this( sources, StackAccessMode.DEFAULT );
+ }
+
+ @Override
+ public int numDimensions()
+ {
+ return nd;
+ }
+
+ @Override
+ public RealRandomAccess< Composite > realRandomAccess()
+ {
+ return stackAccessMode == StackAccessMode.MOVE_ALL_SLICE_ACCESSES ?
+ new CompositeRealRandomAccessMoveAll() :
+ new CompositeRealRandomAccessDefault();
+ }
+
+ @Override
+ public RealRandomAccess< Composite > realRandomAccess( RealInterval interval )
+ {
+ return realRandomAccess();
+ }
+
+ public class CompositeRealRandomAccessMoveAll implements RealRandomAccess< Composite >, Composite
+ {
+ final protected RealRandomAccess< T >[] sourceAccesses;
+
+ @SuppressWarnings( "unchecked" )
+ public CompositeRealRandomAccessMoveAll()
+ {
+ sourceAccesses = new RealRandomAccess[ n ];
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ] = sources[ i ].realRandomAccess();
+ }
+
+ @SuppressWarnings( "unchecked" )
+ protected CompositeRealRandomAccessMoveAll( final CompositeRealRandomAccessMoveAll other )
+ {
+ sourceAccesses = new RealRandomAccess[ n ];
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ] = other.sourceAccesses[i].copy();
+ }
+
+ @Override
+ public int numDimensions()
+ {
+ return n;
+ }
+
+ @Override
+ public Composite get()
+ {
+ return this;
+ }
+
+ @Override
+ public CompositeRealRandomAccessMoveAll copy()
+ {
+ return new CompositeRealRandomAccessMoveAll( this );
+ }
+
+ @Override
+ public double getDoublePosition( int d )
+ {
+ return sourceAccesses[0].getDoublePosition( d );
+ }
+
+ @Override
+ public void move( float distance, int d )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].move( distance, d );
+ }
+
+ @Override
+ public void move( double distance, int d )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].move( distance, d );
+ }
+
+ @Override
+ public void move( RealLocalizable distance )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].move( distance );
+ }
+
+ @Override
+ public void move( float[] distance )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].move( distance );
+ }
+
+ @Override
+ public void move( double[] distance )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].move( distance );
+ }
+
+ @Override
+ public void setPosition( RealLocalizable position )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].setPosition( position );
+ }
+
+ @Override
+ public void setPosition( float[] position )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].setPosition( position );
+ }
+
+ @Override
+ public void setPosition( double[] position )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].setPosition( position );
+ }
+
+ @Override
+ public void setPosition( float position, int d )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].setPosition( position, d );
+ }
+
+ @Override
+ public void setPosition( double position, int d )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].setPosition( position, d );
+ }
+
+ @Override
+ public void fwd( int d )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].fwd( d );
+ }
+
+ @Override
+ public void bck( int d )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].bck( d );
+ }
+
+ @Override
+ public void move( int distance, int d )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].move( distance, d );
+ }
+
+ @Override
+ public void move( long distance, int d )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].move( distance, d );
+ }
+
+ @Override
+ public void move( Localizable distance )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].move( distance );
+ }
+
+ @Override
+ public void move( int[] distance )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].move( distance );
+ }
+
+ @Override
+ public void move( long[] distance )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].move( distance );
+ }
+
+ @Override
+ public void setPosition( Localizable position )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].setPosition( position );
+ }
+
+ @Override
+ public void setPosition( int[] position )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].setPosition( position );
+ }
+
+ @Override
+ public void setPosition( long[] position )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].setPosition( position );
+ }
+
+ @Override
+ public void setPosition( int position, int d )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].setPosition( position, d );
+ }
+
+ @Override
+ public void setPosition( long position, int d )
+ {
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ].setPosition( position, d );
+ }
+
+ @Override
+ public T get( long i )
+ {
+ return sourceAccesses[ (int)i ].get();
+ }
+ }
+
+ public class CompositeRealRandomAccessDefault implements RealRandomAccess< Composite >, Composite
+ {
+ final protected RealRandomAccess< T >[] sourceAccesses;
+
+ protected int currentIndex = 0;
+
+ protected RealRandomAccess< T > currentAccess;
+
+ @SuppressWarnings( "unchecked" )
+ public CompositeRealRandomAccessDefault()
+ {
+ sourceAccesses = new RealRandomAccess[ n ];
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ] = sources[ i ].realRandomAccess();
+
+ currentIndex = 0;
+ currentAccess = sourceAccesses[ currentIndex ];
+ }
+
+ @SuppressWarnings( "unchecked" )
+ protected CompositeRealRandomAccessDefault( final CompositeRealRandomAccessDefault other )
+ {
+ sourceAccesses = new RealRandomAccess[ n ];
+ for ( int i = 0; i < n; i++ )
+ sourceAccesses[ i ] = other.sourceAccesses[i].copy();
+
+ currentIndex = other.currentIndex;
+ currentAccess = sourceAccesses[currentIndex];
+ }
+
+ @Override
+ public int numDimensions()
+ {
+ return n;
+ }
+
+ @Override
+ public Composite get()
+ {
+ return this;
+ }
+
+ @Override
+ public CompositeRealRandomAccessDefault copy()
+ {
+ return new CompositeRealRandomAccessDefault( this );
+ }
+
+ @Override
+ public double getDoublePosition( int d )
+ {
+ return sourceAccesses[0].getDoublePosition( d );
+ }
+
+ @Override
+ public void move( float distance, int d )
+ {
+ currentAccess.move( distance, d );
+ }
+
+ @Override
+ public void move( double distance, int d )
+ {
+ currentAccess.move( distance, d );
+ }
+
+ @Override
+ public void move( RealLocalizable distance )
+ {
+ currentAccess.move( distance );
+ }
+
+ @Override
+ public void move( float[] distance )
+ {
+ for ( int i = 0; i < n; i++ )
+ currentAccess.move( distance );
+ }
+
+ @Override
+ public void move( double[] distance )
+ {
+ currentAccess.move( distance );
+ }
+
+ @Override
+ public void setPosition( RealLocalizable position )
+ {
+ currentAccess.setPosition( position );
+ }
+
+ @Override
+ public void setPosition( float[] position )
+ {
+ currentAccess.setPosition( position );
+ }
+
+ @Override
+ public void setPosition( double[] position )
+ {
+ currentAccess.setPosition( position );
+ }
+
+ @Override
+ public void setPosition( float position, int d )
+ {
+ currentAccess.setPosition( position, d );
+ }
+
+ @Override
+ public void setPosition( double position, int d )
+ {
+ currentAccess.setPosition( position, d );
+ }
+
+ @Override
+ public void fwd( int d )
+ {
+ currentAccess.fwd( d );
+ }
+
+ @Override
+ public void bck( int d )
+ {
+ currentAccess.bck( d );
+ }
+
+ @Override
+ public void move( int distance, int d )
+ {
+ currentAccess.move( distance, d );
+ }
+
+ @Override
+ public void move( long distance, int d )
+ {
+ currentAccess.move( distance, d );
+ }
+
+ @Override
+ public void move( Localizable distance )
+ {
+ currentAccess.move( distance );
+ }
+
+ @Override
+ public void move( int[] distance )
+ {
+ currentAccess.move( distance );
+ }
+
+ @Override
+ public void move( long[] distance )
+ {
+ currentAccess.move( distance );
+ }
+
+ @Override
+ public void setPosition( Localizable position )
+ {
+ currentAccess.setPosition( position );
+ }
+
+ @Override
+ public void setPosition( int[] position )
+ {
+ currentAccess.setPosition( position );
+ }
+
+ @Override
+ public void setPosition( long[] position )
+ {
+ currentAccess.setPosition( position );
+ }
+
+ @Override
+ public void setPosition( int position, int d )
+ {
+ currentAccess.setPosition( position, d );
+ }
+
+ @Override
+ public void setPosition( long position, int d )
+ {
+ currentAccess.setPosition( position, d );
+ }
+
+ @Override
+ public T get( long i )
+ {
+ if( i == currentIndex )
+ return currentAccess.get();
+ else
+ {
+ sourceAccesses[(int)i].setPosition(currentAccess);
+ currentAccess = sourceAccesses[(int)i];
+ currentIndex = (int)i;
+ return currentAccess.get();
+ }
+ }
+ }
+
+}
diff --git a/src/test/java/net/imglib2/view/composite/RealStackCompositeTest.java b/src/test/java/net/imglib2/view/composite/RealStackCompositeTest.java
new file mode 100644
index 000000000..76325c96e
--- /dev/null
+++ b/src/test/java/net/imglib2/view/composite/RealStackCompositeTest.java
@@ -0,0 +1,139 @@
+package net.imglib2.view.composite;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import net.imglib2.RealRandomAccess;
+import net.imglib2.RealRandomAccessible;
+import net.imglib2.position.FunctionRealRandomAccessible;
+import net.imglib2.type.numeric.real.DoubleType;
+import net.imglib2.view.StackView.StackAccessMode;
+
+public class RealStackCompositeTest
+{
+ private static final double EPS = 1e-9;
+
+ private int N = 5;
+ private RealRandomAccessible[] sources;
+ private RealRandomAccessible[] sources2;
+
+ @SuppressWarnings( "unchecked" )
+ @Before
+ public void before() throws Exception
+ {
+ // 1d
+ sources = new RealRandomAccessible[ N ];
+ for( int i = 0; i < N; i++ )
+ {
+ final int j = i;
+ sources[i] = new FunctionRealRandomAccessible<>( 1,
+ ( x, v ) -> { v.set( j * x.getDoublePosition( 0 ) ); },
+ DoubleType::new );
+ }
+
+ // 2d
+ sources2 = new RealRandomAccessible[ N ];
+ for( int i = 0; i < N; i++ )
+ {
+ final int j = i;
+ sources2[i] = new FunctionRealRandomAccessible<>( 2,
+ ( x, v ) -> { v.set( j * x.getDoublePosition( 0 ) + x.getDoublePosition( 1 )); },
+ DoubleType::new );
+ }
+ }
+
+ @Test
+ public final void test1d()
+ {
+ test1dHelper("default", new RealStackCompositeView<>(sources));
+ test1dHelper("moveAll", new RealStackCompositeView<>(sources, StackAccessMode.MOVE_ALL_SLICE_ACCESSES));
+ }
+
+ protected final void test1dHelper( String accessMode, RealStackCompositeView rimg )
+ {
+ assertEquals( "ndims", 1, rimg.numDimensions() );
+
+ final RealRandomAccess> access = rimg.realRandomAccess();
+ for( int i = 0; i < N; i++ )
+ assertEquals( accessMode, 0, access.get().get( i ).get(), EPS );
+
+ // test setPosition
+ double p = 10;
+ access.setPosition( p, 0 );
+ for( int i = 0; i < N; i++ )
+ assertEquals( accessMode, i * p, access.get().get( i ).get(), EPS );
+
+ // test setPosition 2
+ p = 4;
+ access.setPosition( p, 0 );
+ for( int i = 0; i < N; i++ )
+ assertEquals( accessMode, i * p, access.get().get( i ).get(), EPS );
+
+ // test fwd
+ p++;
+ access.fwd( 0 );
+ for( int i = 0; i < N; i++ )
+ assertEquals( accessMode, i * p, access.get().get( i ).get(), EPS );
+
+ // test move
+ p -= 2;
+ access.move( -2, 0 );
+ for( int i = 0; i < N; i++ )
+ assertEquals( accessMode, i * p, access.get().get( i ).get(), EPS );
+
+ }
+
+ @Test
+ public final void test2d()
+ {
+ final RealStackCompositeView rimg = new RealStackCompositeView<>( sources2 );
+ assertEquals( "ndims", 2, rimg.numDimensions() );
+
+ final RealRandomAccess> access = rimg.realRandomAccess();
+ for( int i = 0; i < N; i++ )
+ assertEquals( 0, access.get().get( i ).get(), EPS );
+
+ double x = 10;
+ double y = 2;
+ final double[] pa = new double[]{x,y};
+
+ // test setPosition
+ access.setPosition( x, 0 );
+ access.setPosition( y, 1 );
+ for( int i = 0; i < N; i++ )
+ assertEquals( i * x + y, access.get().get( i ).get(), EPS );
+
+ // test setPosition
+ x = 11; pa[0] = x;
+ y = 3; pa[1] = y;
+ access.setPosition( pa );
+ for( int i = 0; i < N; i++ )
+ assertEquals( i * x + y, access.get().get( i ).get(), EPS );
+
+ // test fwd
+ x++;
+ access.fwd( 0 );
+ for( int i = 0; i < N; i++ )
+ assertEquals( i * x + y, access.get().get( i ).get(), EPS );
+
+ y++;
+ access.fwd( 1 );
+ for( int i = 0; i < N; i++ )
+ assertEquals( i * x + y, access.get().get( i ).get(), EPS );
+
+ // test move
+ x -= 2.5;
+ access.move( -2.5, 0 );
+ for( int i = 0; i < N; i++ )
+ assertEquals( i * x + y, access.get().get( i ).get(), EPS );
+
+ // test move
+ y -= 0.7;
+ access.move( -0.7, 1 );
+ for( int i = 0; i < N; i++ )
+ assertEquals( i * x + y, access.get().get( i ).get(), EPS );
+
+ }
+}