AxisUtils { public static <S extends AnnotatedSpace<A>, A extends CalibratedAxis> boolean isSpatialCalibrationsIsotropic(final S space, final double tolerance, final UnitService unitService) throws IllegalArgumentException { if (tolerance < 0.0) { throw new IllegalArgumentException("Tolerance cannot be negative"); } if (Double.isNaN(tolerance)) { throw new IllegalArgumentException("Tolerance cannot be NaN"); } final Optional<String> commonUnit = getSpatialUnit(space, unitService); if (!commonUnit.isPresent()) { throw new IllegalArgumentException( "Isotropy cannot be determined: units of spatial calibrations are inconvertible"); } final String outputUnit = commonUnit.get(); final double[] scales = spatialAxisStream(space).mapToDouble( axis -> unitService.value(axis.averageScale(0, 1), axis.unit(), outputUnit)).sorted().toArray(); for (int i = 0; i < scales.length - 1; i++) { for (int j = i + 1; j < scales.length; j++) { final double anisotropy = scales[j] / scales[i] - 1.0; if (anisotropy - tolerance > 1e-12) { return false; } } } return true; } private  AxisUtils(); static long countSpatialDimensions(final S space); static Optional<String> getSpatialUnit(final S space, final UnitService unitService); static boolean hasChannelDimensions(final S space); static boolean hasSpatialDimensions(final S space); static boolean hasTimeDimensions(final S space); static boolean isSpatialCalibrationsIsotropic(final S space, final double tolerance,
			final UnitService unitService);  }
@Test public void isSpatialCalibrationsIsotropic() { final Img<DoubleType> img = ArrayImgs.doubles(10, 10, 10); final DefaultLinearAxis xAxis = new DefaultLinearAxis(Axes.X, "mm", 1.0); final DefaultLinearAxis yAxis = new DefaultLinearAxis(Axes.Y, "mm", 1.0); final DefaultLinearAxis zAxis = new DefaultLinearAxis(Axes.Z, "mm", 1.0); final ImgPlus<DoubleType> imgPlus = new ImgPlus<>(img, "", xAxis, yAxis, zAxis); final boolean result = AxisUtils.isSpatialCalibrationsIsotropic(imgPlus, 0.0, unitService); assertTrue(result); }
@Test public void isSpatialCalibrationsIsotropicAnisotropicBeyondTolerance() { final Img<DoubleType> img = ArrayImgs.doubles(10, 10, 10); final DefaultLinearAxis xAxis = new DefaultLinearAxis(Axes.X, "mm", 1.0); final DefaultLinearAxis yAxis = new DefaultLinearAxis(Axes.Y, "mm", 1.06); final DefaultLinearAxis zAxis = new DefaultLinearAxis(Axes.Z, "mm", 1.0); final ImgPlus<DoubleType> imgPlus = new ImgPlus<>(img, "", xAxis, yAxis, zAxis); final boolean result = AxisUtils.isSpatialCalibrationsIsotropic(imgPlus, 0.05, unitService); assertFalse(result); }
@Test public void isSpatialCalibrationsIsotropicAnisotropicWithinTolerance() { final Img<DoubleType> img = ArrayImgs.doubles(10, 10, 10); final DefaultLinearAxis xAxis = new DefaultLinearAxis(Axes.X, "mm", 1.0); final DefaultLinearAxis yAxis = new DefaultLinearAxis(Axes.Y, "mm", 1.05); final DefaultLinearAxis zAxis = new DefaultLinearAxis(Axes.Z, "mm", 1.0); final ImgPlus<DoubleType> imgPlus = new ImgPlus<>(img, "", xAxis, yAxis, zAxis); final boolean result = AxisUtils.isSpatialCalibrationsIsotropic(imgPlus, 0.05, unitService); assertTrue(result); }
@Test public void isSpatialCalibrationsIsotropicDifferentUnits() { final Img<DoubleType> img = ArrayImgs.doubles(10, 10, 10); final DefaultLinearAxis xAxis = new DefaultLinearAxis(Axes.X, "mm", 1.0); final DefaultLinearAxis yAxis = new DefaultLinearAxis(Axes.Y, "cm", 0.1); final DefaultLinearAxis zAxis = new DefaultLinearAxis(Axes.Z, "mm", 1.0); final ImgPlus<DoubleType> imgPlus = new ImgPlus<>(img, "", xAxis, yAxis, zAxis); final boolean result = AxisUtils.isSpatialCalibrationsIsotropic(imgPlus, 0.0, unitService); assertTrue(result); }
@Test public void isSpatialCalibrationsIsotropicThrowsIAEInconvertibleUnits() { final Img<DoubleType> img = ArrayImgs.doubles(10, 10, 10); final DefaultLinearAxis xAxis = new DefaultLinearAxis(Axes.X, "mm", 1.0); final DefaultLinearAxis yAxis = new DefaultLinearAxis(Axes.Y, "mm", 1.0); final DefaultLinearAxis zAxis = new DefaultLinearAxis(Axes.Z, "kg", 1.0); final ImgPlus<DoubleType> imgPlus = new ImgPlus<>(img, "", xAxis, yAxis, zAxis); expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage( "Isotropy cannot be determined: units of spatial calibrations are inconvertible"); AxisUtils.isSpatialCalibrationsIsotropic(imgPlus, 0.0, unitService); }
@Test public void isSpatialCalibrationsIsotropicThrowsIAENanTolerance() { final Img<DoubleType> img = ArrayImgs.doubles(10, 10, 10); final DefaultLinearAxis xAxis = new DefaultLinearAxis(Axes.X, "mm", 1.0); final DefaultLinearAxis yAxis = new DefaultLinearAxis(Axes.Y, "mm", 1.0); final DefaultLinearAxis zAxis = new DefaultLinearAxis(Axes.Z, "mm", 1.0); final ImgPlus<DoubleType> imgPlus = new ImgPlus<>(img, "", xAxis, yAxis, zAxis); expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("Tolerance cannot be NaN"); AxisUtils.isSpatialCalibrationsIsotropic(imgPlus, Double.NaN, unitService); }
@Test public void isSpatialCalibrationsIsotropicThrowsIAENegativeTolerance() { final Img<DoubleType> img = ArrayImgs.doubles(10, 10, 10); final DefaultLinearAxis xAxis = new DefaultLinearAxis(Axes.X, "mm", 1.0); final DefaultLinearAxis yAxis = new DefaultLinearAxis(Axes.Y, "mm", 1.0); final DefaultLinearAxis zAxis = new DefaultLinearAxis(Axes.Z, "mm", 1.0); final ImgPlus<DoubleType> imgPlus = new ImgPlus<>(img, "", xAxis, yAxis, zAxis); expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("Tolerance cannot be negative"); AxisUtils.isSpatialCalibrationsIsotropic(imgPlus, -1.0, unitService); }