@Test public void testEllipsoidBand() { final double[] radii = { 1, 2, 3 }; final Matrix4dc symmetry = new Matrix4d( 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1); final Random rng = new Random(SEED); final List<Vector3d> points = ellipsoidPoints.calculate(radii, 1_000L); points.forEach(p -> { final double scale = (2 * rng.nextDouble() - 1) * 0.05 + 1.0; p.mul(scale); }); final Matrix4dc quadric = (Matrix4dc) IMAGE_J.op().run(Quadric.class, points); final Optional<Ellipsoid> result = quadricToEllipsoid.calculate(quadric); assertTrue(result.isPresent()); final Ellipsoid ellipsoid = result.get(); final Vector3dc centroid = new Vector3d(ellipsoid.getCentroid().x, ellipsoid .getCentroid().y, ellipsoid.getCentroid().z); assertTrue("Ellipsoid centre point is not within tolerance", epsilonEquals( new Vector3d(0, 0, 0), centroid, 0.05)); assertEquals(radii[0], ellipsoid.getA(), 0.025); assertEquals(radii[1], ellipsoid.getB(), 0.025); assertEquals(radii[2], ellipsoid.getC(), 0.025); epsilonEquals(symmetry, ellipsoid.getOrientation(), 0.025); }
@Override public Optional<Ellipsoid> calculate(final Matrix4dc quadricSolution) { final Vector3dc center = findCenter(quadricSolution); final Matrix4dc translated = translateToCenter(quadricSolution, center); final EigenDecomposition decomposition = solveEigenDecomposition( translated); final boolean invalidEv = Arrays.stream(decomposition.getRealEigenvalues()) .anyMatch(e -> e <= 0.0); if (invalidEv) { return Optional.empty(); } final double[] radii = Arrays.stream(decomposition.getRealEigenvalues()) .map(ev -> Math.sqrt(1.0 / ev)).toArray(); final Ellipsoid ellipsoid = new Ellipsoid(radii[0], radii[1], radii[2]); ellipsoid.setCentroid(center); final Matrix3dc orientation = toOrientationMatrix(decomposition); ellipsoid.setOrientation(orientation); return Optional.of(ellipsoid); }
QuadricToEllipsoid extends
	AbstractUnaryFunctionOp<Matrix4dc, Optional<Ellipsoid>> { @Override public Optional<Ellipsoid> calculate(final Matrix4dc quadricSolution) { final Vector3dc center = findCenter(quadricSolution); final Matrix4dc translated = translateToCenter(quadricSolution, center); final EigenDecomposition decomposition = solveEigenDecomposition( translated); final boolean invalidEv = Arrays.stream(decomposition.getRealEigenvalues()) .anyMatch(e -> e <= 0.0); if (invalidEv) { return Optional.empty(); } final double[] radii = Arrays.stream(decomposition.getRealEigenvalues()) .map(ev -> Math.sqrt(1.0 / ev)).toArray(); final Ellipsoid ellipsoid = new Ellipsoid(radii[0], radii[1], radii[2]); ellipsoid.setCentroid(center); final Matrix3dc orientation = toOrientationMatrix(decomposition); ellipsoid.setOrientation(orientation); return Optional.of(ellipsoid); } }
QuadricToEllipsoid extends
	AbstractUnaryFunctionOp<Matrix4dc, Optional<Ellipsoid>> { @Override public Optional<Ellipsoid> calculate(final Matrix4dc quadricSolution) { final Vector3dc center = findCenter(quadricSolution); final Matrix4dc translated = translateToCenter(quadricSolution, center); final EigenDecomposition decomposition = solveEigenDecomposition( translated); final boolean invalidEv = Arrays.stream(decomposition.getRealEigenvalues()) .anyMatch(e -> e <= 0.0); if (invalidEv) { return Optional.empty(); } final double[] radii = Arrays.stream(decomposition.getRealEigenvalues()) .map(ev -> Math.sqrt(1.0 / ev)).toArray(); final Ellipsoid ellipsoid = new Ellipsoid(radii[0], radii[1], radii[2]); ellipsoid.setCentroid(center); final Matrix3dc orientation = toOrientationMatrix(decomposition); ellipsoid.setOrientation(orientation); return Optional.of(ellipsoid); }  }
QuadricToEllipsoid extends
	AbstractUnaryFunctionOp<Matrix4dc, Optional<Ellipsoid>> { @Override public Optional<Ellipsoid> calculate(final Matrix4dc quadricSolution) { final Vector3dc center = findCenter(quadricSolution); final Matrix4dc translated = translateToCenter(quadricSolution, center); final EigenDecomposition decomposition = solveEigenDecomposition( translated); final boolean invalidEv = Arrays.stream(decomposition.getRealEigenvalues()) .anyMatch(e -> e <= 0.0); if (invalidEv) { return Optional.empty(); } final double[] radii = Arrays.stream(decomposition.getRealEigenvalues()) .map(ev -> Math.sqrt(1.0 / ev)).toArray(); final Ellipsoid ellipsoid = new Ellipsoid(radii[0], radii[1], radii[2]); ellipsoid.setCentroid(center); final Matrix3dc orientation = toOrientationMatrix(decomposition); ellipsoid.setOrientation(orientation); return Optional.of(ellipsoid); }  @Override Optional<Ellipsoid> calculate(final Matrix4dc quadricSolution); }
QuadricToEllipsoid extends
	AbstractUnaryFunctionOp<Matrix4dc, Optional<Ellipsoid>> { @Override public Optional<Ellipsoid> calculate(final Matrix4dc quadricSolution) { final Vector3dc center = findCenter(quadricSolution); final Matrix4dc translated = translateToCenter(quadricSolution, center); final EigenDecomposition decomposition = solveEigenDecomposition( translated); final boolean invalidEv = Arrays.stream(decomposition.getRealEigenvalues()) .anyMatch(e -> e <= 0.0); if (invalidEv) { return Optional.empty(); } final double[] radii = Arrays.stream(decomposition.getRealEigenvalues()) .map(ev -> Math.sqrt(1.0 / ev)).toArray(); final Ellipsoid ellipsoid = new Ellipsoid(radii[0], radii[1], radii[2]); ellipsoid.setCentroid(center); final Matrix3dc orientation = toOrientationMatrix(decomposition); ellipsoid.setOrientation(orientation); return Optional.of(ellipsoid); }  @Override Optional<Ellipsoid> calculate(final Matrix4dc quadricSolution);  }