From 20c87650f6ae1127d11b47b10497d20beddf0fe7 Mon Sep 17 00:00:00 2001 From: Stephan Saalfeld Date: Thu, 13 Jun 2024 12:44:10 -0400 Subject: [PATCH] feat: move bounding box calculation into RealTransform with extensible interface for sampling method, override trivial cases in Translations, scales, and affine transformations --- .../AbstractAffineTransform.java | 26 +- .../imglib2/realtransform/AbstractScale.java | 52 +++- .../realtransform/AbstractTranslation.java | 32 +- .../imglib2/realtransform/RealTransform.java | 24 ++ .../realtransform/ScaleAndTranslation.java | 28 +- .../realtransform/interval/Corners.java | 98 ++++++ .../imglib2/realtransform/interval/Faces.java | 106 +++++++ .../realtransform/interval/FacesSpacing.java | 63 ++++ .../realtransform/interval/FacesSteps.java | 66 ++++ .../interval/IntervalSamplingMethod.java | 112 +++++++ .../realtransform/interval/Volume.java | 88 ++++++ .../realtransform/interval/VolumeSpacing.java | 63 ++++ .../realtransform/interval/VolumeSteps.java | 65 ++++ .../java/net/imglib2/util/RealIntervals.java | 288 ------------------ .../interval}/RealIntervalsTests.java | 35 +-- 15 files changed, 807 insertions(+), 339 deletions(-) create mode 100644 src/main/java/net/imglib2/realtransform/interval/Corners.java create mode 100644 src/main/java/net/imglib2/realtransform/interval/Faces.java create mode 100644 src/main/java/net/imglib2/realtransform/interval/FacesSpacing.java create mode 100644 src/main/java/net/imglib2/realtransform/interval/FacesSteps.java create mode 100644 src/main/java/net/imglib2/realtransform/interval/IntervalSamplingMethod.java create mode 100644 src/main/java/net/imglib2/realtransform/interval/Volume.java create mode 100644 src/main/java/net/imglib2/realtransform/interval/VolumeSpacing.java create mode 100644 src/main/java/net/imglib2/realtransform/interval/VolumeSteps.java delete mode 100644 src/main/java/net/imglib2/util/RealIntervals.java rename src/test/java/net/imglib2/{util => realtransform/interval}/RealIntervalsTests.java (88%) 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..dcdfa06 --- /dev/null +++ b/src/main/java/net/imglib2/realtransform/interval/Volume.java @@ -0,0 +1,88 @@ +/* + * #%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 + * @param spacing + * spacing between samples along each dimension + * @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/main/java/net/imglib2/util/RealIntervals.java b/src/main/java/net/imglib2/util/RealIntervals.java deleted file mode 100644 index 34b3953..0000000 --- a/src/main/java/net/imglib2/util/RealIntervals.java +++ /dev/null @@ -1,288 +0,0 @@ -/*- - * #%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.util; - -import java.util.Arrays; - -import net.imglib2.FinalRealInterval; -import net.imglib2.RealInterval; -import net.imglib2.RealPoint; -import net.imglib2.iterator.IntervalIterator; -import net.imglib2.iterator.LocalizingRealIntervalIterator; -import net.imglib2.realtransform.RealTransform; - -/** - * Convenience methods for manipulating {@link RealInterval RealIntervals}. - * - * @author John Bogovic - * - */ -public class RealIntervals -{ - /** - * 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 corners of the given real interval. - * - * @param interval - * the real interval - * @param transform - * the transformation - * @return the bounding interval - */ - public static RealInterval boundingIntervalCorners( 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 ); - 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 ); - } - - - /** - * 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 - * @param spacing - * spacing between samples along each dimension - * @return the bounding interval - */ - public static RealInterval boundingIntervalFaces( final RealInterval interval, final RealTransform transform, double... spacing ) - { - final int nd = interval.numDimensions(); - final double[] itSpacing = fillSpacing( nd, spacing ) ; - - final double[] min = new double[ nd ]; - final double[] max = new double[ nd ]; - Arrays.fill( min, Double.MAX_VALUE ); - Arrays.fill( max, Double.MIN_VALUE ); - - final double[] itvlMin = new double[ nd ]; - final double[] itvlMax = new double[ nd ]; - for( int i = 0; i < nd; i++ ) - { - interval.realMin( itvlMin ); - interval.realMax( itvlMax ); - itvlMin[ i ] = interval.realMin( i ); - itvlMax[ i ] = interval.realMin( i ); - transformedCoordinateBounds( transform, new LocalizingRealIntervalIterator( itvlMin, itvlMax, itSpacing ), min, max ); - - itvlMin[ i ] = interval.realMax( i ); - itvlMax[ i ] = interval.realMax( i ); - transformedCoordinateBounds( transform, new LocalizingRealIntervalIterator( itvlMin, itvlMax, itSpacing ), min, max ); - } - - return new FinalRealInterval( min, max ); - } - - /** - * 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 - * @param numSamples - * number of samples per dimension - * @return the bounding interval - */ - public static RealInterval boundingIntervalFacesSamples( final RealInterval interval, final RealTransform transform, int... numSamples ) - { - return boundingIntervalFaces( interval, transform, stepsFromSamples( interval, numSamples )); - } - - /** - * 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 - * @param spacing - * spacing between samples along each dimension - * @return the bounding interval - */ - public static RealInterval boundingIntervalVolume( - final RealInterval interval, final RealTransform transform, double... spacing ) - { - int nd = interval.numDimensions(); - final double[] itSpacing = fillSpacing( nd, spacing ) ; - - double[] min = new double[ nd ]; - double[] max = new double[ nd ]; - Arrays.fill( min, Long.MAX_VALUE ); - Arrays.fill( max, Long.MIN_VALUE ); - final LocalizingRealIntervalIterator it = new LocalizingRealIntervalIterator( interval, itSpacing ); - transformedCoordinateBounds( transform, it, min, max ); - return new FinalRealInterval( min, max ); - } - - /** - * 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 - * @param numSamples - * the number of samples per dimension - * @return the bounding interval - */ - public static RealInterval boundingIntervalVolumeSamples( - final RealInterval interval, final RealTransform transform, int... numSamples ) - { - return boundingIntervalVolume( interval, transform, stepsFromSamples( interval, numSamples )); - - } - - /** - * 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 - */ - protected static void transformedCoordinateBounds( - final RealTransform transform, final LocalizingRealIntervalIterator it, - final double[] min, final double[] max ) - { - final int nd = it.numDimensions(); - final RealPoint ptxfm = new RealPoint( nd ); - while( it.hasNext() ) - { - it.fwd(); - transform.apply( it, ptxfm ); - for( int d = 0; d < nd; d++ ) - { - final double p = ptxfm.getDoublePosition(d); - if( p < min[ d ]) - min[ d ] = p; - - if( p > max[ d ]) - max[ d ] = p; - } - } - } - - private static double[] fillSpacing( int nd, double... spacing ) - { - final double[] out; - if( spacing.length >= nd ) - out = spacing; - else - { - out = new double[ nd ]; - for( int i = 0; i < nd; i++ ) - if( i < spacing.length ) - out[i] = spacing[ i ]; - else - out[i] = spacing[ spacing.length - 1 ]; - } - return out; - } - - private static double[] stepsFromSamples( final RealInterval interval , int... numSamples ) - { - final double[] out = new double[ interval.numDimensions() ]; - for( int i = 0; i < out.length; i++ ) - { - final double w = interval.realMax( i ) - interval.realMin( i ); - if( i < numSamples.length ) - out[i] = w / numSamples[ i ]; - else - out[i] = w / numSamples[ numSamples.length - 1 ]; - } - return out; - } - -} diff --git a/src/test/java/net/imglib2/util/RealIntervalsTests.java b/src/test/java/net/imglib2/realtransform/interval/RealIntervalsTests.java similarity index 88% rename from src/test/java/net/imglib2/util/RealIntervalsTests.java rename to src/test/java/net/imglib2/realtransform/interval/RealIntervalsTests.java index a4a856b..10f917b 100644 --- a/src/test/java/net/imglib2/util/RealIntervalsTests.java +++ b/src/test/java/net/imglib2/realtransform/interval/RealIntervalsTests.java @@ -12,13 +12,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 @@ -32,9 +32,10 @@ * POSSIBILITY OF SUCH DAMAGE. * #L% */ -package net.imglib2.util; +package net.imglib2.realtransform.interval; + +import static org.junit.Assert.assertEquals; -import static org.junit.Assert.*; import org.junit.Test; import net.imglib2.FinalRealInterval; @@ -47,7 +48,7 @@ public class RealIntervalsTests { static final double EPS = 1e-9; - static final FinalRealInterval itvl = new FinalRealInterval( + static final FinalRealInterval itvl = new FinalRealInterval( new double[] { 0, 0, 0 }, new double[] { 40, 30, 20 }); @Test @@ -56,7 +57,7 @@ public void testBboxCornersAffine() final AffineTransform3D xfm = new AffineTransform3D(); xfm.scale(2, 3, 4); - final RealInterval bbox = RealIntervals.boundingIntervalCorners( itvl, xfm ); + 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 ); @@ -68,7 +69,7 @@ public void testBboxFacesAffine() final AffineTransform3D xfm = new AffineTransform3D(); xfm.scale(2, 3, 4); - final RealInterval bbox = RealIntervals.boundingIntervalFaces( itvl, xfm, 10, 10, 10 ); + 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 ); @@ -80,7 +81,7 @@ public void testBboxVolumeAffine() final AffineTransform3D xfm = new AffineTransform3D(); xfm.scale(2, 3, 4); - final RealInterval bbox = RealIntervals.boundingIntervalVolume( itvl, xfm, 10 ); + 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 ); @@ -91,10 +92,10 @@ 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 - + // 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 = RealIntervals.boundingIntervalCorners( itvl, xfm ); + 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 ); @@ -109,7 +110,7 @@ public void testBboxCornersPfield() public void testBboxFacesPfield() { final PositionFieldTransform xfm = pfield(); - final RealInterval bbox = RealIntervals.boundingIntervalFaces( itvl, xfm, 5, 5, 5 ); + 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 ); @@ -118,8 +119,8 @@ public void testBboxFacesPfield() assertEquals( "min z ", itvl.realMin(2), bbox.realMin(2), EPS ); assertEquals( "max z ", itvl.realMax(2), bbox.realMax(2), EPS ); - - final RealInterval bboxSamples = RealIntervals.boundingIntervalFacesSamples( itvl, xfm, 8, 6, 4 ); + + 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 ); @@ -134,7 +135,7 @@ public void testBboxFacesPfield() public void testBboxVolumePfield() { final PositionFieldTransform xfm = pfield(); - final RealInterval bbox = RealIntervals.boundingIntervalVolume( itvl, xfm, 5 ); + 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 ); @@ -143,8 +144,8 @@ public void testBboxVolumePfield() assertEquals( "min z ", itvl.realMin(2), bbox.realMin(2), EPS ); assertEquals( "max z ", itvl.realMax(2), bbox.realMax(2), EPS ); - - final RealInterval bboxSamples = RealIntervals.boundingIntervalVolumeSamples( itvl, xfm, 8, 6, 4 ); + + 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 );