diff --git a/pom.xml b/pom.xml index 5909e9d219..55145f51f4 100644 --- a/pom.xml +++ b/pom.xml @@ -266,6 +266,14 @@ org.apache.commons commons-math3 + + org.joml + joml + + + gov.nist.math + jama + @@ -294,10 +302,5 @@ ij test - - net.imglib2 - imglib2-ij - test - diff --git a/src/main/java/net/imagej/ops/geom/CentroidVector3d.java b/src/main/java/net/imagej/ops/geom/CentroidVector3d.java new file mode 100644 index 0000000000..77b3924c84 --- /dev/null +++ b/src/main/java/net/imagej/ops/geom/CentroidVector3d.java @@ -0,0 +1,37 @@ + +package net.imagej.ops.geom; + +import java.util.Iterator; + +import net.imagej.ops.Ops; +import net.imagej.ops.special.function.AbstractUnaryFunctionOp; + +import org.joml.Vector3d; +import org.joml.Vector3dc; +import org.scijava.plugin.Plugin; + +/** + * Calculates the centroid (geometrical centre) of the vectors + * + * @author Richard Domander (Royal Veterinary College, London) + */ +@Plugin(type = Ops.Geometric.Centroid.class) +public class CentroidVector3d extends + AbstractUnaryFunctionOp, Vector3d> implements + Ops.Geometric.Centroid +{ + + @Override + public Vector3d calculate(final Iterable input) { + final Iterator iterator = input.iterator(); + final Vector3d sum = new Vector3d(); + long count = 0; + while (iterator.hasNext()) { + final Vector3dc v = iterator.next(); + sum.add(v); + count++; + } + sum.div(count); + return sum; + } +} diff --git a/src/main/java/net/imagej/ops/geom/GeomNamespace.java b/src/main/java/net/imagej/ops/geom/GeomNamespace.java index 621fc28fbf..5a0c6314f1 100644 --- a/src/main/java/net/imagej/ops/geom/GeomNamespace.java +++ b/src/main/java/net/imagej/ops/geom/GeomNamespace.java @@ -50,6 +50,8 @@ import net.imglib2.util.Pair; import org.apache.commons.math3.linear.RealMatrix; +import org.joml.Vector3d; +import org.joml.Vector3dc; import org.scijava.plugin.Plugin; /** @@ -228,6 +230,11 @@ public RealLocalizable centroid(final Mesh in) { return result; } + @OpMethod(op = net.imagej.ops.geom.CentroidVector3d.class) + public Vector3d centroid(final Iterable in) { + return (Vector3d) ops().run(net.imagej.ops.Ops.Geometric.Centroid.class, in); + } + @OpMethod(op = net.imagej.ops.geom.geom2d.DefaultCircularity.class) public DoubleType circularity(final Polygon2D in) { final DoubleType result = diff --git a/src/test/java/net/imagej/ops/geom/CentroidVector3dTest.java b/src/test/java/net/imagej/ops/geom/CentroidVector3dTest.java new file mode 100644 index 0000000000..1aa12e803a --- /dev/null +++ b/src/test/java/net/imagej/ops/geom/CentroidVector3dTest.java @@ -0,0 +1,66 @@ + +package net.imagej.ops.geom; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.DoubleStream; + +import net.imagej.ops.AbstractOpTest; + +import org.joml.Vector3d; +import org.junit.Test; + +/** + * Unit tests for {@link CentroidVector3d} + * + * @author Richard Domander (Royal Veterinary College, London) + */ +public class CentroidVector3dTest extends AbstractOpTest { + + @Test + public void testCalculate() { + final Vector3d expected = new Vector3d(0.5, 0.5, 0.5); + //@formatter:off + final List cubeVectors = Arrays.asList( + new Vector3d(0.0, 0.0, 0.0), + new Vector3d(1.0, 0.0, 0.0), + new Vector3d(1.0, 1.0, 0.0), + new Vector3d(0.0, 1.0, 0.0), + new Vector3d(0.0, 0.0, 1.0), + new Vector3d(1.0, 0.0, 1.0), + new Vector3d(1.0, 1.0, 1.0), + new Vector3d(0.0, 1.0, 1.0) + ); + //@formatter:on + + final Vector3d result = (Vector3d) ops.run(CentroidVector3d.class, + cubeVectors); + + assertEquals("Incorrect centroid vector", expected, result); + } + + @Test + public void testCalculateEmptyCollection() { + final List emptyList = Collections.emptyList(); + + final Vector3d result = (Vector3d) ops.run(CentroidVector3d.class, + emptyList); + + assertTrue("Coordinates should all be NaN", DoubleStream.of(result.x, + result.y, result.z).allMatch(Double::isNaN)); + } + + @Test + public void testCalculateSingleVector() { + final Vector3d vector = new Vector3d(1.0, 2.0, 3.0); + final List vectors = Collections.singletonList(vector); + + final Vector3d result = (Vector3d) ops.run(CentroidVector3d.class, vectors); + + assertEquals("Incorrect centroid vector", vector, result); + } +}