diff --git a/src/main/java/net/imglib2/realtransform/AbstractAffineTransform.java b/src/main/java/net/imglib2/realtransform/AbstractAffineTransform.java index 6030524..f35dd00 100644 --- a/src/main/java/net/imglib2/realtransform/AbstractAffineTransform.java +++ b/src/main/java/net/imglib2/realtransform/AbstractAffineTransform.java @@ -11,13 +11,13 @@ * %% * 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 @@ -34,17 +34,19 @@ package net.imglib2.realtransform; +import Jama.Matrix; +import net.imglib2.RealInterval; import net.imglib2.RealLocalizable; import net.imglib2.RealPoint; import net.imglib2.RealPositionable; -import Jama.Matrix; +import net.imglib2.realtransform.interval.IntervalSamplingMethod; /** * An abstract implementation of an affine transformation that returns default * values referring to the identity transformation for all fields. This * implementation is not thread safe. Create a {@link #copy()} for each * consumer. - * + * * @author Stephan Saalfeld */ public abstract class AbstractAffineTransform implements AffineGet, AffineSet @@ -136,7 +138,7 @@ public int numTargetDimensions() { return n; } - + @Override public void apply( final double[] source, final double[] target ) { @@ -148,11 +150,11 @@ public void apply( final double[] source, final double[] target ) for ( int c = 0; c < n; ++c ) tmp[ r ] += source[ c ] * a.get( r, c ); } - + for ( int r = 0; r < n; ++r ) target[ r ] = tmp[ r ] + t[ r ]; } - + @Override public void apply( final float[] source, final float[] target ) { @@ -164,7 +166,7 @@ public void apply( final float[] source, final float[] target ) for ( int c = 0; c < n; ++c ) tmp[ r ] += source[ c ] * a.get( r, c ); } - + for ( int r = 0; r < n; ++r ) target[ r ] = ( float )( tmp[ r ] + t[ r ] ); } @@ -180,7 +182,7 @@ public void apply( final RealLocalizable source, final RealPositionable target ) for ( int c = 0; c < n; ++c ) tmp[ r ] += source.getDoublePosition( c ) * a.get( r, c ); } - + for ( int r = 0; r < n; ++r ) target.setPosition( tmp[ r ] + t[ r ], r ); } @@ -215,4 +217,10 @@ public RealLocalizable d( final int d ) return ds[ d ]; } + + @Override + public RealInterval boundingInterval( final RealInterval interval, final IntervalSamplingMethod samplingMethdod ) + { + return AffineGet.super.boundingInterval( interval, IntervalSamplingMethod.CORNERS ); + } } diff --git a/src/main/java/net/imglib2/realtransform/AbstractScale.java b/src/main/java/net/imglib2/realtransform/AbstractScale.java index c223f20..25e3f15 100644 --- a/src/main/java/net/imglib2/realtransform/AbstractScale.java +++ b/src/main/java/net/imglib2/realtransform/AbstractScale.java @@ -11,13 +11,13 @@ * %% * 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 @@ -34,9 +34,12 @@ package net.imglib2.realtransform; +import net.imglib2.FinalRealInterval; +import net.imglib2.RealInterval; import net.imglib2.RealLocalizable; import net.imglib2.RealPoint; import net.imglib2.RealPositionable; +import net.imglib2.realtransform.interval.IntervalSamplingMethod; /** * n-d arbitrary scaling. Abstract base implementation. @@ -63,7 +66,7 @@ public AbstractScale( final double... s ) /** * Set the scale vector. - * + * * @param s * s.length <= the number of dimensions of this * {@link AbstractScale} @@ -74,7 +77,7 @@ public AbstractScale( final double... s ) public void applyInverse( final double[] source, final double[] target ) { assert source.length >= s.length && target.length >= s.length : "Input dimensions too small."; - + for ( int d = 0; d < s.length; ++d ) source[ d ] = target[ d ] / s[ d ]; } @@ -83,17 +86,17 @@ public void applyInverse( final double[] source, final double[] target ) public void applyInverse( final float[] source, final float[] target ) { assert source.length >= s.length && target.length >= s.length : "Input dimensions too small."; - + for ( int d = 0; d < s.length; ++d ) source[ d ] = ( float )( target[ d ] / s[ d ] ); - + } @Override public void applyInverse( final RealPositionable source, final RealLocalizable target ) { assert source.numDimensions() >= s.length && target.numDimensions() >= s.length : "Input dimensions too small."; - + for ( int d = 0; d < s.length; ++d ) source.setPosition( target.getDoublePosition( d ) / s[ d ], d ); } @@ -123,7 +126,7 @@ public int numTargetDimensions() public void apply( final double[] source, final double[] target ) { assert source.length >= s.length && target.length >= s.length : "Input dimensions too small."; - + for ( int d = 0; d < s.length; ++d ) target[ d ] = source[ d ] * s[ d ]; } @@ -132,7 +135,7 @@ public void apply( final double[] source, final double[] target ) public void apply( final float[] source, final float[] target ) { assert source.length >= s.length && target.length >= s.length : "Input dimensions too small."; - + for ( int d = 0; d < s.length; ++d ) target[ d ] = ( float )( source[ d ] * s[ d ] ); } @@ -141,7 +144,7 @@ public void apply( final float[] source, final float[] target ) public void apply( final RealLocalizable source, final RealPositionable target ) { assert source.numDimensions() >= s.length && target.numDimensions() >= s.length : "Input dimensions too small."; - + for ( int d = 0; d < s.length; ++d ) target.setPosition( source.getDoublePosition( d ) * s[ d ], d ); } @@ -150,7 +153,7 @@ public void apply( final RealLocalizable source, final RealPositionable target ) public double get( final int row, final int column ) { assert row >= 0 && row < numDimensions() : "Dimension index out of bounds."; - + return row == column ? s[ row ] : 0; } @@ -168,7 +171,7 @@ public double[] getRowPackedCopy() public RealLocalizable d( final int d ) { assert d >= 0 && d < numDimensions() : "Dimension index out of bounds."; - + return ds[ d ]; } @@ -186,14 +189,33 @@ public double[] getScaleCopy() { return s.clone(); } - + @Override - public double getTranslation( final int d ) { + public double getTranslation( final int d ) + { return 0.0; } @Override - public double[] getTranslationCopy() { + public double[] getTranslationCopy() + { return new double[ s.length ]; } + + @Override + public RealInterval boundingInterval( final RealInterval interval, final IntervalSamplingMethod samplingMethdod ) + { + assert interval.numDimensions() >= s.length : "Interval does not have enough dimensions."; + + final double[] min = interval.minAsDoubleArray(); + final double[] max = interval.maxAsDoubleArray(); + + for ( int d = 0; d < s.length; ++d ) + { + min[ d ] *= s[ d ]; + max[ d ] *= s[ d ]; + } + + return new FinalRealInterval( min, max, false ); + } } diff --git a/src/main/java/net/imglib2/realtransform/AbstractTranslation.java b/src/main/java/net/imglib2/realtransform/AbstractTranslation.java index 694bc9a..7c594eb 100644 --- a/src/main/java/net/imglib2/realtransform/AbstractTranslation.java +++ b/src/main/java/net/imglib2/realtransform/AbstractTranslation.java @@ -11,13 +11,13 @@ * %% * 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 @@ -34,13 +34,16 @@ package net.imglib2.realtransform; +import net.imglib2.FinalRealInterval; +import net.imglib2.RealInterval; import net.imglib2.RealLocalizable; import net.imglib2.RealPoint; import net.imglib2.RealPositionable; +import net.imglib2.realtransform.interval.IntervalSamplingMethod; /** * n-d translation. Abstract base implementation. - * + * * @author Stephan Saalfeld */ abstract public class AbstractTranslation implements TranslationGet @@ -77,7 +80,7 @@ public AbstractTranslation( final double... t ) /** * Set the translation vector. - * + * * @param t * t.length <= the number of dimensions of this * {@link AbstractTranslation} @@ -86,7 +89,7 @@ public AbstractTranslation( final double... t ) /** * Set one value of the translation vector. - * + * * @param t * t.length <= the number of dimensions of this * {@link AbstractTranslation} @@ -197,7 +200,7 @@ public RealLocalizable d( final int d ) return ds[ d ]; } - + @Override public double getScale( final int d ) { return 0.0; @@ -224,4 +227,21 @@ public double[] getTranslationCopy() @Override abstract public AbstractTranslation inverse(); + + @Override + public RealInterval boundingInterval( final RealInterval interval, final IntervalSamplingMethod samplingMethdod ) + { + assert interval.numDimensions() >= t.length : "Interval does not have enough dimensions."; + + final double[] min = interval.minAsDoubleArray(); + final double[] max = interval.maxAsDoubleArray(); + + for ( int d = 0; d < t.length; ++d ) + { + min[ d ] += t[ d ]; + max[ d ] += t[ d ]; + } + + return new FinalRealInterval( min, max, false ); + } } diff --git a/src/main/java/net/imglib2/realtransform/RealTransform.java b/src/main/java/net/imglib2/realtransform/RealTransform.java index 2f09892..8634e9d 100644 --- a/src/main/java/net/imglib2/realtransform/RealTransform.java +++ b/src/main/java/net/imglib2/realtransform/RealTransform.java @@ -34,9 +34,11 @@ package net.imglib2.realtransform; +import net.imglib2.RealInterval; import net.imglib2.RealLocalizable; import net.imglib2.RealPoint; import net.imglib2.RealPositionable; +import net.imglib2.realtransform.interval.IntervalSamplingMethod; /** * Transformation from Rn to Rm. @@ -257,4 +259,26 @@ default boolean isIdentity() { return false; } + + /** + * Estimate the {@link RealInterval} that bounds the given RealInterval + * after being transformed by a {@link RealTransform}. + *
+ * For arbitrary transformations, it is not necessarily possible to + * directly calculate the resulting bounding box trivially, therefore, + * a sampling methods for coordinates in the source interval must be + * provided. {@link RealTransform}s that can calculate the bounding + * interval more efficiently than by sampling coordinates are encouraged + * to override this method and to ignore the provided sampling method. + * + * @param interval + * the real interval + * @param samplingMethod + * the method used to sample coordinates of the source interval + * @return the bounding interval + */ + default RealInterval boundingInterval( final RealInterval interval, final IntervalSamplingMethod samplingMethod ) + { + return samplingMethod.bounds( interval, this ); + } } diff --git a/src/main/java/net/imglib2/realtransform/ScaleAndTranslation.java b/src/main/java/net/imglib2/realtransform/ScaleAndTranslation.java index b28624e..758fe75 100644 --- a/src/main/java/net/imglib2/realtransform/ScaleAndTranslation.java +++ b/src/main/java/net/imglib2/realtransform/ScaleAndTranslation.java @@ -11,13 +11,13 @@ * %% * 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 @@ -36,11 +36,14 @@ */ package net.imglib2.realtransform; +import net.imglib2.FinalRealInterval; +import net.imglib2.RealInterval; import net.imglib2.RealLocalizable; import net.imglib2.RealPoint; import net.imglib2.RealPositionable; import net.imglib2.concatenate.Concatenable; import net.imglib2.concatenate.PreConcatenable; +import net.imglib2.realtransform.interval.IntervalSamplingMethod; /** * An n transform that applies a scaling first and then shifts coordinates. @@ -319,11 +322,28 @@ public Class< ScaleAndTranslationGet > getConcatenableClass() { return ScaleAndTranslationGet.class; } - - + + @Override public boolean isIdentity() { return RealViewsSimplifyUtils.isIdentity( this ); } + + @Override + public RealInterval boundingInterval( final RealInterval interval, final IntervalSamplingMethod samplingMethdod ) + { + assert interval.numDimensions() >= n : "Interval does not have enough dimensions."; + + final double[] min = interval.minAsDoubleArray(); + final double[] max = interval.maxAsDoubleArray(); + + for ( int d = 0; d < n; ++d ) + { + min[ d ] = min[ d ] * scales[ d ] + translations[ d ]; + max[ d ] = max[ d ] * scales[ d ] + translations[ d ]; + } + + return new FinalRealInterval( min, max, false ); + } } diff --git a/src/main/java/net/imglib2/realtransform/interval/Corners.java b/src/main/java/net/imglib2/realtransform/interval/Corners.java new file mode 100644 index 0000000..4101e0d --- /dev/null +++ b/src/main/java/net/imglib2/realtransform/interval/Corners.java @@ -0,0 +1,98 @@ +/* + * #%L + * ImgLib2: a general-purpose, multidimensional image processing library. + * %% + * Copyright (C) 2009 - 2024 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, + * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, + * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, + * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, + * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, + * Jean-Yves Tinevez and Michael Zinsmaier. + * %% + * 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 net.imglib2.realtransform.interval; + +import java.util.Arrays; + +import net.imglib2.FinalRealInterval; +import net.imglib2.RealInterval; +import net.imglib2.iterator.IntervalIterator; +import net.imglib2.realtransform.RealTransform; + +/** + * + * @author John Bogovic + * @author Stephan Saalfeld + */ +public class Corners implements IntervalSamplingMethod +{ + /** + * + * @param interval + * the real interval + * @param transform + * the transformation + * @return the bounding interval + */ + @Override + public RealInterval bounds( final RealInterval interval, final RealTransform transform ) + { + final int nd = interval.numDimensions(); + final double[] pt = new double[ nd ]; + + final double[] min = new double[ nd ]; + final double[] max = new double[ nd ]; + Arrays.fill( min, Double.MAX_VALUE ); + Arrays.fill( max, Double.MIN_VALUE ); + + // iterate over the corners of an nd-hypercube + final long[] unitInterval = new long[ nd ]; + Arrays.fill( unitInterval, 2 ); + final IntervalIterator it = new IntervalIterator( unitInterval ); + while ( it.hasNext() ) + { + it.fwd(); + for ( int d = 0; d < nd; d++ ) + { + if ( it.getLongPosition( d ) == 0 ) + pt[ d ] = interval.realMin( d ); + else + pt[ d ] = interval.realMax( d ); + } + + transform.apply( pt, pt ); + for ( int d = 0; d < nd; d++ ) + { + if ( pt[ d ] < min[ d ] ) + min[ d ] = pt[ d ]; + + if ( pt[ d ] > max[ d ] ) + max[ d ] = pt[ d ]; + } + } + + return new FinalRealInterval( min, max, false ); + } +} \ No newline at end of file diff --git a/src/main/java/net/imglib2/realtransform/interval/Faces.java b/src/main/java/net/imglib2/realtransform/interval/Faces.java new file mode 100644 index 0000000..629e16a --- /dev/null +++ b/src/main/java/net/imglib2/realtransform/interval/Faces.java @@ -0,0 +1,106 @@ +/* + * #%L + * ImgLib2: a general-purpose, multidimensional image processing library. + * %% + * Copyright (C) 2009 - 2024 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, + * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, + * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, + * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, + * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, + * Jean-Yves Tinevez and Michael Zinsmaier. + * %% + * 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 net.imglib2.realtransform.interval; + +import java.util.Arrays; + +import net.imglib2.FinalRealInterval; +import net.imglib2.RealInterval; +import net.imglib2.iterator.LocalizingRealIntervalIterator; +import net.imglib2.realtransform.RealTransform; + +/** + * @author John Bogovic + * @author Stephan Saalfeld + */ +public abstract class Faces implements IntervalSamplingMethod +{ + protected abstract double[] spacing( final RealInterval interval ); + + /** + * Estimate the {@link RealInterval} that bounds the given RealInterval + * after being transformed by a {@link RealTransform}. + *
+ * This implementation estimates the bounding interval by transforming points + * on the faces of the given real interval. + * + * @param interval + * the real interval + * @param transform + * the transformation + * @return the bounding interval + */ + @Override + public RealInterval bounds( final RealInterval interval, final RealTransform transform ) + { + assert interval.numDimensions() >= transform.numSourceDimensions() : "Interval dimensions too small for transformation."; + + final int nSource = transform.numSourceDimensions(); + final int nTarget = transform.numTargetDimensions(); + + final double[] itSpacing = spacing( interval ); + + final double[] min = new double[ nTarget ]; + final double[] max = new double[ nTarget ]; + + Arrays.fill( min, Double.MAX_VALUE ); + Arrays.fill( max, Double.MIN_VALUE ); + + final double[] itMin = new double[ nTarget ]; + final double[] itMax = new double[ nTarget ]; + for( int i = 0; i < nSource; i++ ) + { + interval.realMin( itMin ); + interval.realMax( itMax ); + itMin[ i ] = interval.realMin( i ); + itMax[ i ] = interval.realMin( i ); + IntervalSamplingMethod.transformedCoordinateBounds( + transform, + new LocalizingRealIntervalIterator( itMin, itMax, itSpacing ), + min, + max ); + + itMin[ i ] = interval.realMax( i ); + itMax[ i ] = interval.realMax( i ); + IntervalSamplingMethod.transformedCoordinateBounds( + transform, + new LocalizingRealIntervalIterator( itMin, itMax, itSpacing ), + min, + max ); + } + + return new FinalRealInterval( min, max, false ); + } +} \ No newline at end of file diff --git a/src/main/java/net/imglib2/realtransform/interval/FacesSpacing.java b/src/main/java/net/imglib2/realtransform/interval/FacesSpacing.java new file mode 100644 index 0000000..b7f01d1 --- /dev/null +++ b/src/main/java/net/imglib2/realtransform/interval/FacesSpacing.java @@ -0,0 +1,63 @@ +/* + * #%L + * ImgLib2: a general-purpose, multidimensional image processing library. + * %% + * Copyright (C) 2009 - 2024 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, + * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, + * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, + * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, + * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, + * Jean-Yves Tinevez and Michael Zinsmaier. + * %% + * 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 net.imglib2.realtransform.interval; + +import java.util.Arrays; + +import net.imglib2.RealInterval; + +/** + * @author John Bogovic + * @author Stephan Saalfeld + */ +public class FacesSpacing extends Faces +{ + private final double[] spacing; + + public FacesSpacing( final double... spacing ) + { + this.spacing = spacing; + } + + @Override + protected double[] spacing( final RealInterval interval ) + { + final double[] out = Arrays.copyOf( spacing, interval.numDimensions() ); + for ( int i = spacing.length; i < out.length; ++i ) + out[ i ] = out[ i - 1 ]; + + return out; + } +} \ No newline at end of file diff --git a/src/main/java/net/imglib2/realtransform/interval/FacesSteps.java b/src/main/java/net/imglib2/realtransform/interval/FacesSteps.java new file mode 100644 index 0000000..1977ea2 --- /dev/null +++ b/src/main/java/net/imglib2/realtransform/interval/FacesSteps.java @@ -0,0 +1,66 @@ +/* + * #%L + * ImgLib2: a general-purpose, multidimensional image processing library. + * %% + * Copyright (C) 2009 - 2024 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, + * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, + * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, + * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, + * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, + * Jean-Yves Tinevez and Michael Zinsmaier. + * %% + * 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 net.imglib2.realtransform.interval; + +import net.imglib2.RealInterval; + +/** + * @author John Bogovic + * @author Stephan Saalfeld + */ +public class FacesSteps extends Faces +{ + private final long[] steps; + + public FacesSteps( final long... steps ) + { + this.steps = steps; + } + + @Override + protected double[] spacing( final RealInterval interval ) + { + final double[] spacing = new double[ interval.numDimensions() ]; + for( int i = 0; i < spacing.length; i++ ) + { + final double w = interval.realMax( i ) - interval.realMin( i ); + if( i < steps.length ) + spacing[ i ] = w / steps[ i ]; + else + spacing[ i ] = w / steps[ steps.length - 1 ]; + } + return spacing; + } +} \ No newline at end of file diff --git a/src/main/java/net/imglib2/realtransform/interval/IntervalSamplingMethod.java b/src/main/java/net/imglib2/realtransform/interval/IntervalSamplingMethod.java new file mode 100644 index 0000000..b6ebbe5 --- /dev/null +++ b/src/main/java/net/imglib2/realtransform/interval/IntervalSamplingMethod.java @@ -0,0 +1,112 @@ +/* + * #%L + * ImgLib2: a general-purpose, multidimensional image processing library. + * %% + * Copyright (C) 2009 - 2024 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, + * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, + * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, + * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, + * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, + * Jean-Yves Tinevez and Michael Zinsmaier. + * %% + * 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 net.imglib2.realtransform.interval; + +import net.imglib2.RealInterval; +import net.imglib2.RealPoint; +import net.imglib2.iterator.LocalizingRealIntervalIterator; +import net.imglib2.realtransform.RealTransform; + +/** + * + * @author John Bogovic + * @author Stephan Saalfeld + * + */ +public interface IntervalSamplingMethod +{ + /** + * Singleton instance of stateless {@link Corners} method. Use instead of + * creating new instances with {@code new Corners()}. + */ + static Corners CORNERS = new Corners(); + + /** + * Transforms all points produced by the {@link LocalizingRealIntervalIterator} + * with the provided {@link RealTransform} and stores the min and max coordinates + * for each dimension in the provided arrays. + *
+ * Min and max arrays are not reset before iteration, meaning this method + * may be called repeatedly with different iterators to find bounds of + * the union of iterated points. + * + * @param transform a transformation + * @param it the real interval iterator + * @param min the min coordinate array to modify + * @param max the max coordinate array to modify + */ + static void transformedCoordinateBounds( + final RealTransform transform, + final LocalizingRealIntervalIterator it, + final double[] min, + final double[] max ) + { + assert + transform.numTargetDimensions() <= min.length && + transform.numTargetDimensions() <= max.length : + "Transformation target dimensionality too large for min and max vectors."; + + assert + transform.numSourceDimensions() <= it.numDimensions() : + "Transformation target dimensionality too large for min and max vectors."; + + final int nTarget = transform.numTargetDimensions(); + final RealPoint targetPoint = new RealPoint( nTarget ); + while( it.hasNext() ) + { + it.fwd(); + transform.apply( it, targetPoint ); + for( int d = 0; d < nTarget; d++ ) + { + final double p = targetPoint.getDoublePosition( d ); + if( p < min[ d ] ) + min[ d ] = p; + + if( p > max[ d ] ) + max[ d ] = p; + } + } + } + + /** + * + * @param interval + * the real interval + * @param transform + * the transformation + * @return the bounding interval + */ + RealInterval bounds( final RealInterval interval, final RealTransform transform ); +} \ No newline at end of file diff --git a/src/main/java/net/imglib2/realtransform/interval/Volume.java b/src/main/java/net/imglib2/realtransform/interval/Volume.java new file mode 100644 index 0000000..ec7b5e9 --- /dev/null +++ b/src/main/java/net/imglib2/realtransform/interval/Volume.java @@ -0,0 +1,86 @@ +/* + * #%L + * ImgLib2: a general-purpose, multidimensional image processing library. + * %% + * Copyright (C) 2009 - 2024 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, + * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, + * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, + * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, + * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, + * Jean-Yves Tinevez and Michael Zinsmaier. + * %% + * 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 net.imglib2.realtransform.interval; + +import java.util.Arrays; + +import net.imglib2.FinalRealInterval; +import net.imglib2.RealInterval; +import net.imglib2.iterator.LocalizingRealIntervalIterator; +import net.imglib2.realtransform.RealTransform; + +/** + * @author John Bogovic + * @author Stephan Saalfeld + */ +public abstract class Volume implements IntervalSamplingMethod +{ + protected abstract double[] spacing( final RealInterval interval ); + + /** + * Estimate the {@link RealInterval} that bounds the given RealInterval + * after being transformed by a {@link RealTransform}. + *
+ * This implementation estimates the bounding interval by transforming
+ * points in the volume of the given real interval.
+ *
+ * @param interval
+ * the real interval
+ * @param transform
+ * the transformation
+ * @return the bounding interval
+ */
+ @Override
+ public RealInterval bounds( final RealInterval interval, final RealTransform transform )
+ {
+ assert interval.numDimensions() >= transform.numSourceDimensions() : "Interval dimensions too small for transformation.";
+
+ final int nTarget = transform.numTargetDimensions();
+
+ final double[] min = new double[ nTarget ];
+ final double[] max = new double[ nTarget ];
+
+ Arrays.fill( min, Double.MAX_VALUE );
+ Arrays.fill( max, Double.MIN_VALUE );
+
+ IntervalSamplingMethod.transformedCoordinateBounds(
+ transform,
+ new LocalizingRealIntervalIterator( interval, spacing( interval ) ),
+ min,
+ max );
+
+ return new FinalRealInterval( min, max, false );
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/imglib2/realtransform/interval/VolumeSpacing.java b/src/main/java/net/imglib2/realtransform/interval/VolumeSpacing.java
new file mode 100644
index 0000000..1ba46da
--- /dev/null
+++ b/src/main/java/net/imglib2/realtransform/interval/VolumeSpacing.java
@@ -0,0 +1,63 @@
+/*
+ * #%L
+ * ImgLib2: a general-purpose, multidimensional image processing library.
+ * %%
+ * Copyright (C) 2009 - 2024 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld,
+ * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke,
+ * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner,
+ * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert,
+ * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin,
+ * Jean-Yves Tinevez and Michael Zinsmaier.
+ * %%
+ * 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 net.imglib2.realtransform.interval;
+
+import java.util.Arrays;
+
+import net.imglib2.RealInterval;
+
+/**
+ * @author John Bogovic
+ * @author Stephan Saalfeld
+ */
+public class VolumeSpacing extends Volume
+{
+ private final double[] spacing;
+
+ public VolumeSpacing( final double... spacing )
+ {
+ this.spacing = spacing;
+ }
+
+ @Override
+ protected double[] spacing( final RealInterval interval )
+ {
+ final double[] out = Arrays.copyOf( spacing, interval.numDimensions() );
+ for ( int i = spacing.length; i < out.length; ++i )
+ out[ i ] = out[ i - 1 ];
+
+ return out;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/imglib2/realtransform/interval/VolumeSteps.java b/src/main/java/net/imglib2/realtransform/interval/VolumeSteps.java
new file mode 100644
index 0000000..ccc3887
--- /dev/null
+++ b/src/main/java/net/imglib2/realtransform/interval/VolumeSteps.java
@@ -0,0 +1,65 @@
+/*
+ * #%L
+ * ImgLib2: a general-purpose, multidimensional image processing library.
+ * %%
+ * Copyright (C) 2009 - 2024 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld,
+ * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke,
+ * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner,
+ * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert,
+ * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin,
+ * Jean-Yves Tinevez and Michael Zinsmaier.
+ * %%
+ * 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 net.imglib2.realtransform.interval;
+
+import net.imglib2.RealInterval;
+
+/**
+ * @author John Bogovic
+ * @author Stephan Saalfeld
+ */
+public class VolumeSteps extends Volume
+{
+ private final long[] steps;
+
+ public VolumeSteps( final long... steps )
+ {
+ this.steps = steps;
+ }
+
+ @Override
+ protected double[] spacing( final RealInterval interval )
+ {
+ final double[] spacing = new double[ interval.numDimensions() ];
+ final int l = Math.min( spacing.length, steps.length );
+ for( int i = 0; i < l; i++ )
+ spacing[ i ] = ( interval.realMax( i ) - interval.realMin( i ) ) / steps[ i ];
+
+ for ( int i = steps.length; i < spacing.length; ++i )
+ spacing[ i ] = ( interval.realMax( i ) - interval.realMin( i ) ) / steps[ steps.length - 1 ];
+
+ return spacing;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/net/imglib2/realtransform/interval/RealIntervalsTests.java b/src/test/java/net/imglib2/realtransform/interval/RealIntervalsTests.java
new file mode 100644
index 0000000..10f917b
--- /dev/null
+++ b/src/test/java/net/imglib2/realtransform/interval/RealIntervalsTests.java
@@ -0,0 +1,203 @@
+
+/*-
+ * #%L
+ * ImgLib2: a general-purpose, multidimensional image processing library.
+ * %%
+ * Copyright (C) 2009 - 2024 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld,
+ * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke,
+ * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner,
+ * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert,
+ * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin,
+ * Jean-Yves Tinevez and Michael Zinsmaier.
+ * %%
+ * 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 net.imglib2.realtransform.interval;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import net.imglib2.FinalRealInterval;
+import net.imglib2.RealInterval;
+import net.imglib2.RealPoint;
+import net.imglib2.position.FunctionRealRandomAccessible;
+import net.imglib2.realtransform.AffineTransform3D;
+import net.imglib2.realtransform.PositionFieldTransform;
+
+public class RealIntervalsTests {
+
+ static final double EPS = 1e-9;
+ static final FinalRealInterval itvl = new FinalRealInterval(
+ new double[] { 0, 0, 0 }, new double[] { 40, 30, 20 });
+
+ @Test
+ public void testBboxCornersAffine()
+ {
+ final AffineTransform3D xfm = new AffineTransform3D();
+ xfm.scale(2, 3, 4);
+
+ final RealInterval bbox = xfm.boundingInterval( itvl, IntervalSamplingMethod.CORNERS );
+ assertEquals( "max x ", itvl.realMax(0) * 2, bbox.realMax(0), EPS );
+ assertEquals( "max y ", itvl.realMax(1) * 3, bbox.realMax(1), EPS );
+ assertEquals( "max z ", itvl.realMax(2) * 4, bbox.realMax(2), EPS );
+ }
+
+ @Test
+ public void testBboxFacesAffine()
+ {
+ final AffineTransform3D xfm = new AffineTransform3D();
+ xfm.scale(2, 3, 4);
+
+ final RealInterval bbox = xfm.boundingInterval( itvl, new FacesSpacing( 10, 10, 10 ) );
+ assertEquals( "max x ", itvl.realMax(0) * 2, bbox.realMax(0), EPS );
+ assertEquals( "max y ", itvl.realMax(1) * 3, bbox.realMax(1), EPS );
+ assertEquals( "max z ", itvl.realMax(2) * 4, bbox.realMax(2), EPS );
+ }
+
+ @Test
+ public void testBboxVolumeAffine()
+ {
+ final AffineTransform3D xfm = new AffineTransform3D();
+ xfm.scale(2, 3, 4);
+
+ final RealInterval bbox = xfm.boundingInterval( itvl, new VolumeSpacing( 10 ) );
+ assertEquals( "max x ", itvl.realMax(0) * 2, bbox.realMax(0), EPS );
+ assertEquals( "max y ", itvl.realMax(1) * 3, bbox.realMax(1), EPS );
+ assertEquals( "max z ", itvl.realMax(2) * 4, bbox.realMax(2), EPS );
+ }
+
+ @Test
+ public void testBboxCornersPfield()
+ {
+ final PositionFieldTransform xfm = pfield();
+
+ // estimating with the corners does NOT correctly estimate the bounding box
+ // for this transformation. Make sure that it behaves as expected -
+ // returning the original interval.
+ final RealInterval bbox = xfm.boundingInterval( itvl, IntervalSamplingMethod.CORNERS );
+ assertEquals( "min x ", itvl.realMin(0), bbox.realMin(0), EPS );
+ assertEquals( "max x ", itvl.realMax(0), bbox.realMax(0), EPS );
+
+ assertEquals( "min y ", itvl.realMin(1), bbox.realMin(1), EPS );
+ assertEquals( "max y ", itvl.realMax(1), bbox.realMax(1), EPS );
+
+ assertEquals( "min z ", itvl.realMin(2), bbox.realMin(2), EPS );
+ assertEquals( "max z ", itvl.realMax(2), bbox.realMax(2), EPS );
+ }
+
+ @Test
+ public void testBboxFacesPfield()
+ {
+ final PositionFieldTransform xfm = pfield();
+ final RealInterval bbox = xfm.boundingInterval( itvl, new FacesSpacing( 5, 5, 5 ) );
+ assertEquals( "min x ", itvl.realMin(0), bbox.realMin(0), EPS );
+ assertEquals( "max x ", itvl.realMax(0) + 5, bbox.realMax(0), EPS );
+
+ assertEquals( "min y ", itvl.realMin(1) - 5, bbox.realMin(1), EPS );
+ assertEquals( "max y ", itvl.realMax(1), bbox.realMax(1), EPS );
+
+ assertEquals( "min z ", itvl.realMin(2), bbox.realMin(2), EPS );
+ assertEquals( "max z ", itvl.realMax(2), bbox.realMax(2), EPS );
+
+ final RealInterval bboxSamples = xfm.boundingInterval( itvl, new FacesSteps( 8, 6, 4 ) );
+ assertEquals( "min x ", itvl.realMin(0), bboxSamples.realMin(0), EPS );
+ assertEquals( "max x ", itvl.realMax(0) + 5, bboxSamples.realMax(0), EPS );
+
+ assertEquals( "min y ", itvl.realMin(1) - 5, bboxSamples.realMin(1), EPS );
+ assertEquals( "max y ", itvl.realMax(1), bboxSamples.realMax(1), EPS );
+
+ assertEquals( "min z ", itvl.realMin(2), bboxSamples.realMin(2), EPS );
+ assertEquals( "max z ", itvl.realMax(2), bboxSamples.realMax(2), EPS );
+ }
+
+ @Test
+ public void testBboxVolumePfield()
+ {
+ final PositionFieldTransform xfm = pfield();
+ final RealInterval bbox = xfm.boundingInterval( itvl, new VolumeSpacing( 5 ) );
+ assertEquals( "min x ", itvl.realMin(0), bbox.realMin(0), EPS );
+ assertEquals( "max x ", itvl.realMax(0) + 5, bbox.realMax(0), EPS );
+
+ assertEquals( "min y ", itvl.realMin(1) - 5, bbox.realMin(1), EPS );
+ assertEquals( "max y ", itvl.realMax(1), bbox.realMax(1), EPS );
+
+ assertEquals( "min z ", itvl.realMin(2), bbox.realMin(2), EPS );
+ assertEquals( "max z ", itvl.realMax(2), bbox.realMax(2), EPS );
+
+ final RealInterval bboxSamples = xfm.boundingInterval( itvl, new VolumeSteps( 8, 6, 4 ) );
+ assertEquals( "min x samples", itvl.realMin(0), bboxSamples.realMin(0), EPS );
+ assertEquals( "max x samples", itvl.realMax(0) + 5, bboxSamples.realMax(0), EPS );
+
+ assertEquals( "min y samples", itvl.realMin(1) - 5, bboxSamples.realMin(1), EPS );
+ assertEquals( "max y samples", itvl.realMax(1), bboxSamples.realMax(1), EPS );
+
+ assertEquals( "min z samples", itvl.realMin(2), bboxSamples.realMin(2), EPS );
+ assertEquals( "max z samples", itvl.realMax(2), bboxSamples.realMax(2), EPS );
+ }
+
+ /**
+ * This strange position field is designed so that different bounding box
+ * estimation methods perform differently.
+ *
+ * @return a position field.
+ */
+ private static PositionFieldTransform pfield()
+ {
+ // center
+ final double xc = 15;
+ final double yc = 20;
+
+ // width
+ final double xwidth = 3;
+ final double ywidth = 3;
+
+ // amount
+ final double dx = 5;
+ final double dy = -5;
+
+ final FunctionRealRandomAccessible