Search in sources :

Example 1 with Transform3D

use of org.scijava.java3d.Transform3D in project TrakEM2 by trakem2.

the class VectorString3D method mirror.

/**
 * Where axis is any of VectorString.X_AXIS, .Y_AXIS or .Z_AXIS,
 *	    and the mirroring is done relative to the local 0,0 of this VectorString.
 */
public void mirror(final int axis) {
    final Transform3D t = new Transform3D();
    switch(axis) {
        case VectorString.X_AXIS:
            t.setScale(new Vector3d(-1, 1, 1));
            tags ^= MIRROR_X;
            break;
        case VectorString.Y_AXIS:
            t.setScale(new Vector3d(1, -1, 1));
            tags ^= MIRROR_Y;
            break;
        case VectorString.Z_AXIS:
            t.setScale(new Vector3d(1, 1, -1));
            tags ^= MIRROR_Z;
            break;
        default:
            return;
    }
    final Point3d p = new Point3d();
    transform(x, y, z, t, p);
    if (null != this.vx)
        transform(vx, vy, vz, t, p);
    if (null != this.rvx)
        transform(rvx, rvy, rvz, t, p);
}
Also used : Vector3d(org.scijava.vecmath.Vector3d) Point3d(org.scijava.vecmath.Point3d) Transform3D(org.scijava.java3d.Transform3D)

Example 2 with Transform3D

use of org.scijava.java3d.Transform3D in project TrakEM2 by trakem2.

the class Treeline method generateMesh.

/**
 * Testing for performance, 100 iterations:
 * A: 3307  (current, with clearing of table on the fly)
 * B: 4613  (without clearing table)
 * C: 4012  (without point caching)
 *
 * Although in short runs (10 iterations) A can get very bad:
 * (first run of 10)
 * A: 664
 * B: 611
 * C: 196
 * (second run of 10)
 * A: 286
 * B: 314
 * C: 513  <-- gets worse !?
 *
 * Differences are not so huge in any case.
 */
/*
	static final public void testMeshGenerationPerformance(int n_iterations) {
		// test 3D mesh generation

		Layer la = Display.getFrontLayer();
		java.util.Random rnd = new java.util.Random(67779);
		Node root = new RadiusNode(rnd.nextFloat(), rnd.nextFloat(), la);
		Node parent = root;
		for (int i=0; i<10000; i++) {
			Node child = new RadiusNode(rnd.nextFloat(), rnd.nextFloat(), la);
			parent.add(child, Node.MAX_EDGE_CONFIDENCE);
			if (0 == i % 100) {
				// add a branch of 100 nodes
				Node pa = parent;
				for (int k = 0; k<100; k++) {
					Node ch = new RadiusNode(rnd.nextFloat(), rnd.nextFloat(), la);
					pa.add(ch, Node.MAX_EDGE_CONFIDENCE);
					pa = ch;
				}
			}
			parent = child;
		}

		final AffineTransform at = new AffineTransform(1, 0, 0, 1, 67, 134);

		final ArrayList list = new ArrayList();

		final LinkedList<Node> todo = new LinkedList<Node>();

		final float scale = 0.345f;
		final Calibration cal = la.getParent().getCalibration();
		final float pixelWidthScaled = (float) cal.pixelWidth * scale;
		final float pixelHeightScaled = (float) cal.pixelHeight * scale;
		final int sign = cal.pixelDepth < 0 ? -1 : 1;
		final Map<Node,Point3f> points = new HashMap<Node,Point3f>();

		// A few performance tests are needed:
		// 1 - if the map caching of points helps or recomputing every time is cheaper than lookup
		// 2 - if removing no-longer-needed points from the map helps lookup or overall slows down

		long t0 = System.currentTimeMillis();
		for (int i=0; i<n_iterations; i++) {
			// A -- current method
			points.clear();
			todo.clear();
			todo.add(root);
			list.clear();
			final float[] fps = new float[2];

			boolean go = true;
			while (go) {
				final Node node = todo.removeFirst();
				// Add children to todo list if any
				if (null != node.children) {
					for (final Node nd : node.children) todo.add(nd);
				}
				go = !todo.isEmpty();
				// Get node's 3D coordinate
				Point3f p = points.get(node);
				if (null == p) {
					fps[0] = node.x;
					fps[1] = node.y;
					at.transform(fps, 0, fps, 0, 1);
					p = new Point3f(fps[0] * pixelWidthScaled,
							fps[1] * pixelHeightScaled,
							(float)node.la.getZ() * pixelWidthScaled * sign);
					points.put(node, p);
				}
				if (null != node.parent) {
					// Create a line to the parent
					list.add(points.get(node.parent));
					list.add(p);
					if (go && node.parent != todo.getFirst().parent) {
						// node.parent point no longer needed (last child just processed)
						points.remove(node.parent);
					}
				}
			}
		}
		System.out.println("A: " + (System.currentTimeMillis() - t0));


		t0 = System.currentTimeMillis();
		for (int i=0; i<n_iterations; i++) {

			points.clear();
			todo.clear();
			todo.add(root);
			list.clear();
			final float[] fps = new float[2];

			// Simpler method, not clearing no-longer-used nodes from map
			while (!todo.isEmpty()) {
				final Node node = todo.removeFirst();
				// Add children to todo list if any
				if (null != node.children) {
					for (final Node nd : node.children) todo.add(nd);
				}
				// Get node's 3D coordinate
				Point3f p = points.get(node);
				if (null == p) {
					fps[0] = node.x;
					fps[1] = node.y;
					at.transform(fps, 0, fps, 0, 1);
					p = new Point3f(fps[0] * pixelWidthScaled,
							fps[1] * pixelHeightScaled,
							(float)node.la.getZ() * pixelWidthScaled * sign);
					points.put(node, p);
				}
				if (null != node.parent) {
					// Create a line to the parent
					list.add(points.get(node.parent));
					list.add(p);
				}
			}
		}
		System.out.println("B: " + (System.currentTimeMillis() - t0));

		t0 = System.currentTimeMillis();
		for (int i=0; i<n_iterations; i++) {

			todo.clear();
			todo.add(root);
			list.clear();

			// Simplest method: no caching in a map
			final float[] fp = new float[4];
			while (!todo.isEmpty()) {
				final Node node = todo.removeFirst();
				// Add children to todo list if any
				if (null != node.children) {
					for (final Node nd : node.children) todo.add(nd);
				}
				if (null != node.parent) {
					// Create a line to the parent
					fp[0] = node.x;
					fp[1] = node.y;
					fp[2] = node.parent.x;
					fp[3] = node.parent.y;
					at.transform(fp, 0, fp, 0, 2);
					list.add(new Point3f(fp[2] * pixelWidthScaled,
							     fp[3] * pixelHeightScaled,
							     (float)node.parent.la.getZ() * pixelWidthScaled * sign));
					list.add(new Point3f(fp[0] * pixelWidthScaled,
							     fp[1] * pixelHeightScaled,
							     (float)node.la.getZ() * pixelWidthScaled * sign));
				}
			}
		}
		System.out.println("C: " + (System.currentTimeMillis() - t0));
	}
	*/
/**
 * Returns a list of two lists: the {@code List<Point3f>} and the corresponding {@code List<Color3f>}.
 */
public MeshData generateMesh(final double scale_, int parallels) {
    // Construct a mesh made of straight tubes for each edge, and balls of the same ending diameter on the nodes.
    // 
    // TODO:
    // With some cleverness, such meshes could be welded together by merging the nearest vertices on the ball
    // surfaces, or by cleaving the surface where the diameter of the tube cuts it.
    // A tougher problem is where tubes cut each other, but perhaps if the resulting mesh is still non-manifold, it's ok.
    final float scale = (float) scale_;
    if (parallels < 3)
        parallels = 3;
    // Simple ball-and-stick model
    // first test: just the nodes as icosahedrons with 1 subdivision
    final Calibration cal = layer_set.getCalibration();
    final float pixelWidthScaled = (float) cal.pixelWidth * scale;
    final float pixelHeightScaled = (float) cal.pixelHeight * scale;
    final int sign = cal.pixelDepth < 0 ? -1 : 1;
    final List<Point3f> ico = M.createIcosahedron(1, 1);
    final List<Point3f> ps = new ArrayList<Point3f>();
    // A plane made of as many edges as parallels, with radius 1
    // Perpendicular vector of the plane is 0,0,1
    final List<Point3f> plane = new ArrayList<Point3f>();
    final double inc_rads = (Math.PI * 2) / parallels;
    double angle = 0;
    for (int i = 0; i < parallels; i++) {
        plane.add(new Point3f((float) Math.cos(angle), (float) Math.sin(angle), 0));
        angle += inc_rads;
    }
    final Vector3f vplane = new Vector3f(0, 0, 1);
    final Transform3D t = new Transform3D();
    final AxisAngle4f aa = new AxisAngle4f();
    final List<Color3f> colors = new ArrayList<Color3f>();
    final Color3f cf = new Color3f(this.color);
    final HashMap<Color, Color3f> cached_colors = new HashMap<Color, Color3f>();
    cached_colors.put(this.color, cf);
    for (final Set<Node<Float>> nodes : node_layer_map.values()) {
        for (final Node<Float> nd : nodes) {
            Point2D.Double po = transformPoint(nd.x, nd.y);
            final float x = (float) po.x * pixelWidthScaled;
            final float y = (float) po.y * pixelHeightScaled;
            final float z = (float) nd.la.getZ() * pixelWidthScaled * sign;
            // TODO r is not transformed by the AffineTransform
            final float r = ((RadiusNode) nd).r * pixelWidthScaled;
            for (final Point3f vert : ico) {
                final Point3f v = new Point3f(vert);
                v.x = v.x * r + x;
                v.y = v.y * r + y;
                v.z = v.z * r + z;
                ps.add(v);
            }
            int n_verts = ico.size();
            // Check if a 3D volume representation is necessary for this segment
            if (null != nd.parent && (0 != nd.parent.getData() || 0 != nd.getData())) {
                po = null;
                // parent:
                final Point2D.Double pp = transformPoint(nd.parent.x, nd.parent.y);
                final float parx = (float) pp.x * pixelWidthScaled;
                final float pary = (float) pp.y * pixelWidthScaled;
                final float parz = (float) nd.parent.la.getZ() * pixelWidthScaled * sign;
                // TODO r is not transformed by the AffineTransform
                final float parr = ((RadiusNode) nd.parent).r * pixelWidthScaled;
                // the vector perpendicular to the plane is 0,0,1
                // the vector from parent to child is:
                final Vector3f vpc = new Vector3f(x - parx, y - pary, z - parz);
                if (x == parx && y == pary) {
                    aa.set(0, 0, 1, 0);
                } else {
                    final Vector3f cross = new Vector3f();
                    cross.cross(vpc, vplane);
                    // not needed?
                    cross.normalize();
                    aa.set(cross.x, cross.y, cross.z, -vplane.angle(vpc));
                }
                t.set(aa);
                final List<Point3f> parent_verts = transform(t, plane, parx, pary, parz, parr);
                final List<Point3f> child_verts = transform(t, plane, x, y, z, r);
                for (int i = 1; i < parallels; i++) {
                    addTriangles(ps, parent_verts, child_verts, i - 1, i);
                    n_verts += 6;
                }
                // faces from last to first:
                addTriangles(ps, parent_verts, child_verts, parallels - 1, 0);
                n_verts += 6;
            }
            // Colors for each segment:
            Color3f c;
            if (null == nd.color) {
                c = cf;
            } else {
                c = cached_colors.get(nd.color);
                if (null == c) {
                    c = new Color3f(nd.color);
                    cached_colors.put(nd.color, c);
                }
            }
            while (n_verts > 0) {
                n_verts--;
                colors.add(c);
            }
        }
    }
    return new MeshData(ps, colors);
}
Also used : HashMap(java.util.HashMap) Transform3D(org.scijava.java3d.Transform3D) Color3f(org.scijava.vecmath.Color3f) Color(java.awt.Color) ArrayList(java.util.ArrayList) Calibration(ij.measure.Calibration) Point(java.awt.Point) Point3f(org.scijava.vecmath.Point3f) Point2D(java.awt.geom.Point2D) Vector3f(org.scijava.vecmath.Vector3f) AxisAngle4f(org.scijava.vecmath.AxisAngle4f)

Example 3 with Transform3D

use of org.scijava.java3d.Transform3D in project TrakEM2 by trakem2.

the class Display3D method showOrthoslices.

public static void showOrthoslices(final ImagePlus imp, final String title, final int wx, final int wy, final float scale2D, final Layer first) {
    final Display3D d3d = get(first.getParent());
    d3d.universe.removeContent(title);
    final Content ct = d3d.universe.addOrthoslice(imp, null, title, 0, new boolean[] { true, true, true }, 1);
    final Calibration cal = imp.getCalibration();
    final Transform3D t = new Transform3D(new double[] { 1, 0, 0, wx * cal.pixelWidth * scale2D, 0, 1, 0, wy * cal.pixelHeight * scale2D, // not pixelDepth!
    0, // not pixelDepth!
    0, // not pixelDepth!
    scale2D, // not pixelDepth!
    first.getZ() * cal.pixelWidth * scale2D, 0, 0, 0, 1 });
    // why scale2D has to be there at all reflects a horrible underlying setting of the calibration, plus of the scaling in the Display3D.
    Utils.log(t);
    ct.applyTransform(t);
    ct.setLocked(true);
}
Also used : Content(ij3d.Content) Transform3D(org.scijava.java3d.Transform3D) Calibration(ij.measure.Calibration)

Example 4 with Transform3D

use of org.scijava.java3d.Transform3D in project TrakEM2 by trakem2.

the class Display3D method setTransform.

private static void setTransform(final Content ct, final Patch p) {
    final double[] a = new double[6];
    p.getAffineTransform().getMatrix(a);
    final Calibration cal = p.getLayerSet().getCalibration();
    // a is: m00 m10 m01 m11 m02 m12
    // d expects: m01 m02 m03 m04, m11 m12 ...
    ct.applyTransform(new Transform3D(new double[] { a[0], a[2], 0, a[4] * cal.pixelWidth, a[1], a[3], 0, a[5] * cal.pixelWidth, 0, 0, 1, p.getLayer().getZ() * cal.pixelWidth, 0, 0, 0, 1 }));
}
Also used : Transform3D(org.scijava.java3d.Transform3D) Calibration(ij.measure.Calibration)

Example 5 with Transform3D

use of org.scijava.java3d.Transform3D in project TrakEM2 by trakem2.

the class Compare method gatherChains.

/**
 * Gather chains for all projects considering the cp.regex, and transforms all relative to the reference Project p[0].
 *  Will ignore any for which a match exists in @param ignore.
 */
public static final Object[] gatherChains(final Project[] p, final CATAParameters cp, final String[] ignore) throws Exception {
    String regex_exclude = null;
    if (null != ignore) {
        final StringBuilder sb = new StringBuilder();
        for (final String ig : ignore) {
            sb.append("(.*").append(ig).append(".*)|");
        }
        sb.setLength(sb.length() - 1);
        regex_exclude = sb.toString();
    }
    Utils.logAll("Compare/gatherChains: using ignore string: " + regex_exclude);
    Utils.logAll("Compare/gatherChains: using regex: " + cp.regex);
    // gather all chains
    // to keep track of each project's chains
    final ArrayList[] p_chains = new ArrayList[p.length];
    final ArrayList<Chain> chains = new ArrayList<Chain>();
    for (int i = 0; i < p.length; i++) {
        // for each project:
        if (null == cp.regex) {
            p_chains[i] = createPipeChains(p[i].getRootProjectThing(), p[i].getRootLayerSet(), regex_exclude);
        } else {
            // Search (shallow) for cp.regex matches
            for (final ProjectThing pt : p[i].getRootProjectThing().findChildren(cp.regex, regex_exclude, true)) {
                final ArrayList<Chain> ac = createPipeChains(pt, p[i].getRootLayerSet(), regex_exclude);
                if (null == p_chains[i])
                    p_chains[i] = ac;
                else
                    p_chains[i].addAll(ac);
            }
            // empty
            if (null == p_chains[i])
                p_chains[i] = new ArrayList<Chain>();
        }
        chains.addAll(p_chains[i]);
        // calibrate
        final Calibration cal = p[i].getRootLayerSet().getCalibrationCopy();
        for (final Chain chain : (ArrayList<Chain>) p_chains[i]) chain.vs.calibrate(cal);
    }
    final int n_chains = chains.size();
    // register all, or relative
    if (4 == cp.transform_type) {
        // compute global average delta
        if (0 == cp.delta) {
            for (final Chain chain : chains) {
                cp.delta += (chain.vs.getAverageDelta() / n_chains);
            }
        }
        Utils.log2("Using delta: " + cp.delta);
        for (final Chain chain : chains) {
            // BEFORE making it relative
            chain.vs.resample(cp.delta, cp.with_source);
            chain.vs.relative();
        }
    } else {
        if (3 == cp.transform_type) {
            // '3' means moving least squares computed from 3D landmarks
            Utils.log2("Moving Least Squares Registration based on common fiducial points");
            // Find fiducial points, if any
            final HashMap<Project, Map<String, Tuple3d>> fiducials = new HashMap<Project, Map<String, Tuple3d>>();
            for (final Project pr : p) {
                final Set<ProjectThing> fids = pr.getRootProjectThing().findChildrenOfTypeR("fiducial_points");
                if (null == fids || 0 == fids.size()) {
                    Utils.log("No fiducial points found in project: " + pr);
                } else {
                    // the first fiducial group
                    fiducials.put(pr, Compare.extractPoints(fids.iterator().next()));
                }
            }
            if (!fiducials.isEmpty()) {
                // Register all VectorString3D relative to the first project:
                final List<VectorString3D> lvs = new ArrayList<VectorString3D>();
                final Calibration cal2 = p[0].getRootLayerSet().getCalibrationCopy();
                for (final Chain chain : chains) {
                    final Project pr = chain.pipes.get(0).getProject();
                    // first project is reference, no need to transform.
                    if (pr == p[0])
                        continue;
                    lvs.clear();
                    lvs.add(chain.vs);
                    chain.vs = transferVectorStrings(lvs, fiducials.get(pr), fiducials.get(p[0])).get(0);
                    // Set (but do not apply!) the calibration of the reference project
                    chain.vs.setCalibration(cal2);
                }
            }
        } else if (cp.transform_type < 3) {
            // '0', '1' and '2' involve a 3D affine computed from the 3 axes
            // no need //VectorString3D[][] vs_axes = new VectorString3D[p.length][];
            Vector3d[][] o = new Vector3d[p.length][];
            for (int i = 0; i < p.length; i++) {
                // 1 - find pipes to work as axes for each project
                final ArrayList<ZDisplayable> pipes = p[i].getRootLayerSet().getZDisplayables(Line3D.class, true);
                final String[] pipe_names = new String[pipes.size()];
                for (int k = 0; k < pipes.size(); k++) {
                    pipe_names[k] = p[i].getMeaningfulTitle(pipes.get(k));
                }
                final int[] s = findFirstXYZAxes(cp.preset, pipes, pipe_names);
                // if axes are -1, forget it: not found
                if (-1 == s[0] || -1 == s[1] || -1 == s[2]) {
                    Utils.log("Can't find axes for project " + p[i]);
                    o = null;
                    return null;
                }
                // obtain axes and origin
                final Object[] pack = obtainOrigin(new Line3D[] { (Line3D) pipes.get(s[0]), (Line3D) pipes.get(s[1]), (Line3D) pipes.get(s[2]) }, cp.transform_type, // will be null for the first, which will then be non-null and act as the reference for the others.
                o[0]);
                // no need //vs_axes[i] = (VectorString3D[])pack[0];
                o[i] = (Vector3d[]) pack[1];
            }
            /* // OLD WAY
				// match the scales to make the largest be 1.0
				final double scaling_factor = VectorString3D.matchOrigins(o, transform_type);
				Utils.log2("matchOrigins scaling factor: " + scaling_factor + " for transform_type " + transform_type);
				*/
            // transform all except the first (which acts as reference)
            final Transform3D M_ref = Compare.createTransform(o[0]);
            for (int i = 1; i < p.length; i++) {
                final Vector3d trans = new Vector3d(-o[i][3].x, -o[i][3].y, -o[i][3].z);
                final Transform3D M_query = Compare.createTransform(o[i]);
                // The transfer T transform: from query space to reference space.
                final Transform3D T = new Transform3D(M_ref);
                T.mulInverse(M_query);
                for (final Chain chain : (ArrayList<Chain>) p_chains[i]) {
                    // in place
                    chain.vs.transform(T);
                }
            }
        }
        // compute global average delta, after correcting calibration and transformation
        if (0 == cp.delta) {
            for (final Chain chain : chains) {
                cp.delta += (chain.vs.getAverageDelta() / n_chains);
            }
        }
        Utils.log2("Using delta: " + cp.delta);
        // After calibration and transformation, resample all to the same delta
        for (final Chain chain : chains) chain.vs.resample(cp.delta, cp.with_source);
    }
    return new Object[] { chains, p_chains };
}
Also used : HashMap(java.util.HashMap) Transform3D(org.scijava.java3d.Transform3D) ArrayList(java.util.ArrayList) Calibration(ij.measure.Calibration) Line3D(ini.trakem2.display.Line3D) Project(ini.trakem2.Project) VectorString3D(ini.trakem2.vector.VectorString3D) Vector3d(org.scijava.vecmath.Vector3d) Tuple3d(org.scijava.vecmath.Tuple3d) Map(java.util.Map) HashMap(java.util.HashMap) TreeMap(java.util.TreeMap) ProjectThing(ini.trakem2.tree.ProjectThing)

Aggregations

Transform3D (org.scijava.java3d.Transform3D)6 Calibration (ij.measure.Calibration)4 Vector3d (org.scijava.vecmath.Vector3d)3 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 Content (ij3d.Content)1 Project (ini.trakem2.Project)1 Line3D (ini.trakem2.display.Line3D)1 ProjectThing (ini.trakem2.tree.ProjectThing)1 VectorString3D (ini.trakem2.vector.VectorString3D)1 Color (java.awt.Color)1 Point (java.awt.Point)1 Point2D (java.awt.geom.Point2D)1 Map (java.util.Map)1 TreeMap (java.util.TreeMap)1 AxisAngle4f (org.scijava.vecmath.AxisAngle4f)1 Color3f (org.scijava.vecmath.Color3f)1 Matrix3d (org.scijava.vecmath.Matrix3d)1 Point3d (org.scijava.vecmath.Point3d)1 Point3f (org.scijava.vecmath.Point3f)1