diff --git a/src/main/java/net/imglib2/KDTree.java b/src/main/java/net/imglib2/KDTree.java index 861931f5a..876cdaf3a 100644 --- a/src/main/java/net/imglib2/KDTree.java +++ b/src/main/java/net/imglib2/KDTree.java @@ -33,12 +33,14 @@ */ package net.imglib2; +import java.util.Iterator; import java.util.List; import net.imglib2.converter.AbstractConvertedIterableRealInterval; import net.imglib2.converter.AbstractConvertedRealCursor; import net.imglib2.kdtree.KDTreeData; import net.imglib2.kdtree.KDTreeImpl; +import net.imglib2.util.Cast; public class KDTree< T > implements EuclideanSpace, IterableRealInterval< T > { @@ -98,7 +100,7 @@ private static int verifySize( final List< ? > values, final List< ? > positions */ public KDTree( final IterableRealInterval< T > interval ) { - this( verifySize( interval ), interval, positionsIterable( interval ) ); + this( verifySize( interval ), copySamplesIterable( interval ), positionsIterable( interval ) ); } private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; @@ -158,6 +160,32 @@ public AbstractConvertedRealCursor< A, RealLocalizable > localizingCursor() }; } + private static < T > Iterable< T > copySamplesIterable( Iterable< T > source ) + { + if ( !( source.iterator() instanceof Sampler ) ) + throw new IllegalArgumentException(); + + return () -> { + final Iterator< T > it = source.iterator(); + final Sampler< T > sampler = Cast.unchecked( it ); + return new Iterator< T >() + { + @Override + public boolean hasNext() + { + return it.hasNext(); + } + + @Override + public T next() + { + it.next(); + return sampler.copy().get(); + } + }; + }; + } + public < L extends RealLocalizable > KDTree( final int numPoints, final Iterable< T > values, final Iterable< L > positions ) { // TODO make storeValuesAsNativeImg a parameter diff --git a/src/test/java/net/imglib2/kdtree/KDTreeTest.java b/src/test/java/net/imglib2/kdtree/KDTreeTest.java new file mode 100644 index 000000000..3d60035c0 --- /dev/null +++ b/src/test/java/net/imglib2/kdtree/KDTreeTest.java @@ -0,0 +1,141 @@ +package net.imglib2.kdtree; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.junit.Assert; +import org.junit.Test; + +import net.imglib2.IterableRealInterval; +import net.imglib2.KDTree; +import net.imglib2.RealCursor; +import net.imglib2.RealLocalizable; +import net.imglib2.RealPoint; + +public class KDTreeTest +{ + @Test + public void testCopySampler() { + + final int numPoints = 10; + + final List< RealLocalizable > points = new ArrayList<>( numPoints ); + final Random rand = new Random(); + for ( int i = 0; i < numPoints; ++i ) + points.add( new RealPoint( rand.nextDouble() ) ); + + final KDTree< RealLocalizable > tree = new KDTree<>( new Locations( points ) ); + final RealCursor< RealLocalizable > cursor = tree.cursor(); + while ( cursor.hasNext() ) + { + cursor.fwd(); + Assert.assertEquals( cursor.getDoublePosition( 0 ), cursor.get().getDoublePosition( 0 ), 0 ); + } + } + + static class Locations implements IterableRealInterval< RealLocalizable > + { + private final List< RealLocalizable > points; + + private final int n; + + Locations(final List< RealLocalizable > points ) + { + this.points = points; + n = points.get( 0 ).numDimensions(); + } + + @Override + public RealCursor< RealLocalizable > cursor() + { + return new LocationsCursor(); + } + + private class LocationsCursor implements RealCursor< RealLocalizable > + { + private int index = -1; + + @Override + public RealCursor< RealLocalizable > copy() + { + final LocationsCursor copy = new LocationsCursor(); + copy.index = this.index; + return copy; + } + + @Override + public void fwd() + { + ++index; + } + + @Override + public void reset() + { + index = -1; + } + + @Override + public boolean hasNext() + { + return index < points.size() - 1; + } + + @Override + public double getDoublePosition( final int d ) + { + return points.get( index ).getDoublePosition( d ); + } + + @Override + public int numDimensions() + { + return n; + } + + @Override + public RealLocalizable get() + { + return this; + } + } + + @Override + public RealCursor< RealLocalizable > localizingCursor() + { + return cursor(); + } + + @Override + public long size() + { + return points.size(); + } + + @Override + public Object iterationOrder() + { + return this; + } + + @Override + public double realMin( final int d ) + { + return Double.NEGATIVE_INFINITY; + } + + @Override + public double realMax( final int d ) + { + return Double.POSITIVE_INFINITY; + } + + @Override + public int numDimensions() + { + return n; + } + } + +}