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);
+ }
+}