Search in sources :

Example 1 with ItemGroupNode

use of uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemGroupNode in project GDSC-SMLM by aherbert.

the class ImageJ3DResultsViewer method createImage3DUniverse.

/**
 * Creates the image 3D universe with a unique name.
 *
 * @param title the title
 * @param titleList the title list (of titles to ignore)
 * @return the image 3D universe
 */
private Image3DUniverse createImage3DUniverse(String title, List<String> titleList) {
    // Get a unique name by appending numbers to the end
    String title2 = title;
    int counter = 2;
    while (titleList.contains(title2)) {
        title2 = title + " " + (counter++);
    }
    final Image3DUniverse universe = new Image3DUniverse();
    universe.addUniverseListener(new LocalUniverseListener());
    universe.setShowBoundingBoxUponSelection(false);
    universe.showAttribute(DefaultUniverse.ATTRIBUTE_SCALEBAR, false);
    // Capture a canvas mouse click/region and identify the coordinates.
    final ImageCanvas3D canvas = (ImageCanvas3D) universe.getCanvas();
    final BranchGroup scene = universe.getScene();
    final MouseListener mouseListener = new MouseAdapter() {

        @Override
        public void mouseClicked(final MouseEvent event) {
            if (!consumeEvent(event)) {
                return;
            }
            // Consume the event
            event.consume();
            // This finds the vertex indices of the rendered object.
            final Pair<Content, IntersectionInfo> pair = getPickedContent(canvas, scene, event.getX(), event.getY());
            if (pair == null) {
                // Do the same as the mouseClicked in Image3DUniverse
                universe.select(null);
                return;
            }
            // Only process content added from localisations
            final Content c = pair.getKey();
            if (!(c.getUserData() instanceof ResultsMetaData)) {
                // Do the same as the mouseClicked in Image3DUniverse
                universe.select(c);
                return;
            }
            final ResultsMetaData data = (ResultsMetaData) c.getUserData();
            final MemoryPeakResults results = data.results;
            // Look up the localisation from the clicked vertex
            final ContentInstant content = c.getCurrent();
            int index = -1;
            if (content.getContent() instanceof CustomMeshNode) {
                final CustomMeshNode node = (CustomMeshNode) content.getContent();
                final CustomMesh mesh = node.getMesh();
                int vertexCount;
                final GeometryArray ga = (GeometryArray) mesh.getGeometry();
                // Default to the number of vertices
                vertexCount = ga.getValidVertexCount();
                final int countPerLocalisation = vertexCount / results.size();
                // Determine the localisation
                final int vertexIndex = pair.getValue().getVertexIndices()[0];
                index = vertexIndex / countPerLocalisation;
            } else if (content.getContent() instanceof ItemGroupNode) {
                // All shapes have the index as the user data
                final Object o = pair.getValue().getGeometry().getUserData();
                if (o instanceof Integer) {
                    index = (Integer) pair.getValue().getGeometry().getUserData();
                }
            }
            if (index == -1) {
                return;
            }
            final PeakResult result = results.get(index);
            if (event.getClickCount() > 1) {
                // Centre on the localisation
                final Point3d coordinate = new Point3d();
                coordinate.set(data.points.get(index));
                // Handle the local transform of the content ...
                final Transform3D vWorldToLocal = getVworldToLocal(content);
                vWorldToLocal.transform(coordinate);
                universe.centerAt(coordinate);
            } else if (event.isShiftDown()) {
                // Ctrl+Shift held down to remove selected
                data.removeFromSelectionModel(result);
            } else {
                // Ctrl held down to set selection
                data.addToSelectionModel(result);
            }
        }

        private boolean consumeEvent(final MouseEvent event) {
            if (event.isConsumed() || event.getButton() != MouseEvent.BUTTON1 || !(event.isControlDown())) {
                return false;
            }
            if (event.getClickCount() == 1) {
                return true;
            }
            return (event.getClickCount() == 2);
        }
    };
    // 0 = ImageCanvas3D
    // 1 = DefaultUniverse
    // 2 = Image3DUniverse
    final MouseListener[] l = canvas.getMouseListeners();
    for (int i = 0; i < l.length; i++) {
        if (l[i].getClass().getName().contains("Image3DUniverse")) {
            // We want to be before the Image3DUniverse to allow consuming the click event.
            // Only allow the click event.
            // This disables the right-click pop-up menu.
            // It doesn't have anything of use for localisations anyway.
            canvas.removeMouseListener(l[i]);
            canvas.addMouseListener(mouseListener);
            canvas.addMouseListener(new MouseListenerWrapper(l[i], MouseListenerWrapper.MOUSE_CLICKED));
        }
    }
    // 0 = ImageCanvas3D
    // 1 = DefaultUniverse
    // 2 = Image3DUniverse
    // 3 = EventCatcher (from scijava)
    final MouseMotionListener[] ml = canvas.getMouseMotionListeners();
    for (int i = 0; i < ml.length; i++) {
        if (ml[i].getClass().getName().contains("Image3DUniverse")) {
            // Ignore this as it just shows the name in the IJ status bar
            canvas.removeMouseMotionListener(ml[i]);
        }
    }
    // Finally display the window
    universe.show();
    final ImageWindow3D window = universe.getWindow();
    GUI.center(window);
    window.setTitle(title2);
    WindowManager.addWindow(window);
    window.addWindowListener(new WindowAdapter() {

        @Override
        public void windowClosing(WindowEvent event) {
            WindowManager.removeWindow(window);
        }
    });
    // Add a new menu for SMLM functionality
    createSmlmMenuBar(universe);
    return universe;
}
Also used : CustomMeshNode(customnode.CustomMeshNode) Transform3D(org.scijava.java3d.Transform3D) ItemGroupNode(uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemGroupNode) IndexedGeometryArray(org.scijava.java3d.IndexedGeometryArray) GeometryArray(org.scijava.java3d.GeometryArray) WindowAdapter(java.awt.event.WindowAdapter) MouseMotionListener(java.awt.event.MouseMotionListener) PeakResult(uk.ac.sussex.gdsc.smlm.results.PeakResult) MouseListener(java.awt.event.MouseListener) Point3d(org.scijava.vecmath.Point3d) CustomMesh(customnode.CustomMesh) MemoryPeakResults(uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults) IntersectionInfo(org.scijava.java3d.PickInfo.IntersectionInfo) MouseEvent(java.awt.event.MouseEvent) Image3DUniverse(ij3d.Image3DUniverse) ImageCanvas3D(ij3d.ImageCanvas3D) BranchGroup(org.scijava.java3d.BranchGroup) MouseAdapter(java.awt.event.MouseAdapter) ContentInstant(ij3d.ContentInstant) CustomContentInstant(uk.ac.sussex.gdsc.smlm.ij.ij3d.CustomContentInstant) ImageWindow3D(ij3d.ImageWindow3D) Content(ij3d.Content) CustomContent(uk.ac.sussex.gdsc.smlm.ij.ij3d.CustomContent) WindowEvent(java.awt.event.WindowEvent) NamedObject(uk.ac.sussex.gdsc.smlm.data.NamedObject)

Example 2 with ItemGroupNode

use of uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemGroupNode in project GDSC-SMLM by aherbert.

the class ImageJ3DResultsViewer method getTotalTransparentObjects.

private static long getTotalTransparentObjects(Image3DUniverse univ, String ignoreName) {
    long size = 0;
    for (final Iterator<Content> it = univ.contents(); it.hasNext(); ) {
        final Content c = it.next();
        if (ignoreName.equals(c.getName())) {
            continue;
        }
        if (!(c.getUserData() instanceof ResultsMetaData)) {
            return 0;
        }
        final ContentInstant content = c.getCurrent();
        if (content.getContent() instanceof ItemGroupNode) {
            final ItemGroupNode node = (ItemGroupNode) content.getContent();
            final ItemGroup g = node.getItemGroup();
            if (g instanceof ItemGeometryGroup) {
                size += g.size();
            }
        }
    }
    return size;
}
Also used : ItemGeometryGroup(uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemGeometryGroup) OrderedItemGeometryGroup(uk.ac.sussex.gdsc.smlm.ij.ij3d.OrderedItemGeometryGroup) ItemGroup(uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemGroup) Content(ij3d.Content) CustomContent(uk.ac.sussex.gdsc.smlm.ij.ij3d.CustomContent) ItemGroupNode(uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemGroupNode) ContentInstant(ij3d.ContentInstant) CustomContentInstant(uk.ac.sussex.gdsc.smlm.ij.ij3d.CustomContentInstant)

Example 3 with ItemGroupNode

use of uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemGroupNode in project GDSC-SMLM by aherbert.

the class ImageJ3DResultsViewerDemo method run.

@Override
public void run(String arg) {
    if (ImageJ3DViewerUtils.JAVA_3D_VERSION == null) {
        IJ.error(TITLE, "Java 3D is not available");
        return;
    }
    final boolean renderingTest = true;
    if (renderingTest) {
        // Put all the shapes from rendering on a view and see how they look.
        final Image3DUniverse univ = new Image3DUniverse();
        univ.showAttribute(DefaultUniverse.ATTRIBUTE_SCALEBAR, false);
        univ.show();
        final ImageWindow3D w = univ.getWindow();
        GUI.center(w);
        // Test how many vertices a primitive sphere has
        float x = 0;
        final float y = 0;
        final float space = 2.5f;
        for (final Rendering rendering : Rendering.values()) {
            final Shape3D shape = Shape3DHelper.createShape(rendering, 3);
            final Appearance a = shape.getAppearance();
            final ItemMesh mesh = new ReferenceItemMesh(new Point3f[] { new Point3f(x, y, 0) }, (GeometryArray) shape.getGeometry(), a, null, null, 0f);
            ImageJUtils.log("R=%s %s  Vc=%d  V=%d  T=%d", rendering, shape.getGeometry().getClass().getSimpleName(), mesh.getVerticesCountPerItem(), mesh.getVerticesPerItem(), Shape3DHelper.getNumberOfTriangles(rendering));
            if (rendering == Rendering.POINT) {
                a.getPointAttributes().setPointSize(10);
            }
            univ.addCustomMesh(mesh, x + "," + y);
            x += space;
        }
        return;
    }
    final boolean sphereTest = true;
    if (sphereTest) {
        // Sphere test
        // Put lots of spheres on a view and see how they look.
        // Is it worth supporting an ItemTriangleStripMesh so we can control
        // the sphere better than the icosahedron?
        final Image3DUniverse univ = new Image3DUniverse();
        univ.showAttribute(DefaultUniverse.ATTRIBUTE_SCALEBAR, false);
        univ.show();
        final ImageWindow3D w = univ.getWindow();
        GUI.center(w);
        // Test how many vertices a primitive sphere has
        float x = 0;
        float y = 0;
        final float space = 2.5f;
        Appearance app = null;
        for (int d = 0; d < 4; d++) {
            final List<Point3f> points = customnode.MeshMaker.createIcosahedron(d, 1f);
            final Pair<Point3f[], int[]> p = CustomContentHelper.createIndexedObject(points);
            final int v = points.size();
            final int t = v / 3;
            ImageJUtils.log("Icosahedron divisions = %d, V=%d, T=%d, Vi=%d (%.2f), i=%d", d, v, t, p.getKey().length, v / (double) p.getKey().length, p.getValue().length);
            CustomMesh mesh = new ItemTriangleMesh(points.toArray(new Point3f[0]), new Point3f[] { new Point3f(x, y, 0) }, null, null, 0);
            app = mesh.getAppearance();
            univ.addCustomMesh(mesh, x + "," + y + "," + t);
            final float y2 = y + space;
            mesh = new ItemIndexedTriangleMesh(p.getKey(), p.getValue(), new Point3f[] { new Point3f(x, y2, 0) }, null, null, 0);
            univ.addCustomMesh(mesh, x + "," + y2 + "," + t);
            x += space;
        }
        // Avoid null pointer warnings
        if (app == null) {
            throw new NullPointerException();
        }
        // The T=800 sphere looks about the same as the Icosahedron(div=3) T=1280
        // This may be a better super-high resolution option.
        x = 0;
        y += 2 * space;
        app = (Appearance) app.cloneNodeComponent(true);
        // a.getColoringAttributes().setColor(0, 1, 0);
        app.getMaterial().setDiffuseColor(0, 1, 0);
        for (int d = 4; d < 50; d += 4) {
            // This is a triangle strip array so is more space efficient
            final Sphere s = new Sphere(1, Primitive.GENERATE_NORMALS, d);
            final int t = s.getNumTriangles();
            ImageJUtils.log("Sphere divisions = %d, V=%d, T=%d", d, s.getNumVertices(), t);
            final ItemGeometryGroup g = new ItemGeometryGroup(new Point3f[] { new Point3f(x, y, 0) }, (GeometryArray) s.getShape().getGeometry(), app, null, null, null);
            final String name = x + "," + y + "," + t;
            final CustomContent content = new CustomContent(name, true);
            content.getCurrent().display(new ItemGroupNode(g));
            univ.addContent(content);
            x += space;
        }
        return;
    }
    LocalList<Point3f> pointList;
    float scale;
    if (MemoryPeakResults.isMemoryEmpty()) {
        pointList = new LocalList<>();
        int range;
        // 9 points
        range = 1;
        // range = 49; // 99^3 = 970299 points
        for (int x = -range; x <= range; x++) {
            for (int y = -range; y <= range; y++) {
                for (int z = -range; z <= range; z++) {
                    pointList.add(new Point3f(x, y, z));
                }
            }
        }
        scale = 0.25f;
    } else {
        final ImageJ3DResultsViewerSettings.Builder settings = SettingsManager.readImageJ3DResultsViewerSettings(0).toBuilder();
        final ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
        gd.addMessage("Select a dataset to display");
        ResultsManager.addInput(gd, settings.getInputOption(), InputSource.MEMORY);
        gd.showDialog();
        if (gd.wasCanceled()) {
            return;
        }
        final String name = ResultsManager.getInputSource(gd);
        settings.setInputOption(name);
        SettingsManager.writeSettings(settings);
        final MemoryPeakResults results = ResultsManager.loadInputResults(name, false, null, null);
        if (MemoryPeakResults.isEmpty(results)) {
            IJ.error(TITLE, "No results could be loaded");
            IJ.showStatus("");
            return;
        }
        pointList = ImageJ3DResultsViewer.getPoints(results, settings);
        if (pointList == null) {
            return;
        }
        scale = 10f;
    }
    final Image3DUniverse univ = new Image3DUniverse();
    univ.showAttribute(DefaultUniverse.ATTRIBUTE_SCALEBAR, false);
    univ.show();
    final ImageWindow3D w = univ.getWindow();
    GUI.center(w);
    final View view = univ.getViewer().getView();
    view.setTransparencySortingPolicy(View.TRANSPARENCY_SORT_GEOMETRY);
    // I am not sure if this is required if objects are sorted.
    // view.setDepthBufferFreezeTransparent(false)
    IJ.showStatus("Creating points ...");
    final Point3f[] points = pointList.toArray(new Point3f[0]);
    final Point3f[] sizes = new Point3f[] { new Point3f(scale, scale, scale) };
    final Appearance appearance = new Appearance();
    final TransparencyAttributes ta = new TransparencyAttributes();
    ta.setTransparency(0.5f);
    ta.setTransparencyMode(TransparencyAttributes.FASTEST);
    appearance.setTransparencyAttributes(ta);
    final ItemGeometryGroup pointGroup = new ItemGeometryGroup(points, null, appearance, sizes, null, null);
    // pointGroup = new OrderedItemGeometryGroup(points, null, appearance, sizes, null, null);
    // // This supports transparency sorting
    // BranchGroup bg = new BranchGroup();
    // bg.addChild(pointGroup);
    // bg.compile();
    // univ.getScene().addChild(bg);
    // // This does not since ContentInstant uses an OrderedPath to show:
    // // the content; the object bounding box, coordinate system and point list
    // final Content c = new Content("Test");
    // final ContentInstant content = c.getCurrent();
    // content.display(new PointGroupNode(pointGroup));
    // univ.addContent(c);
    // This does since ItemGeometryNode uses a Group to show the points as individual shapes
    // and the CustomContentInstant uses a group not an ordered group so show all the adornments.
    IJ.showStatus("Displaying points ...");
    final CustomContent c = new CustomContent("Test", false);
    final ContentInstant content = c.getCurrent();
    content.display(new ItemGroupNode(pointGroup));
    univ.addContent(c);
    IJ.showStatus("Done");
}
Also used : ImageJ3DResultsViewerSettings(uk.ac.sussex.gdsc.smlm.ij.settings.GUIProtos.ImageJ3DResultsViewerSettings) ItemMesh(uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemMesh) ReferenceItemMesh(uk.ac.sussex.gdsc.smlm.ij.ij3d.ReferenceItemMesh) ItemTriangleMesh(uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemTriangleMesh) ItemGroupNode(uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemGroupNode) Sphere(org.scijava.java3d.utils.geometry.Sphere) CustomContent(uk.ac.sussex.gdsc.smlm.ij.ij3d.CustomContent) Point3f(org.scijava.vecmath.Point3f) CustomMesh(customnode.CustomMesh) Shape3D(org.scijava.java3d.Shape3D) MemoryPeakResults(uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults) TransparencyAttributes(org.scijava.java3d.TransparencyAttributes) Image3DUniverse(ij3d.Image3DUniverse) ReferenceItemMesh(uk.ac.sussex.gdsc.smlm.ij.ij3d.ReferenceItemMesh) ContentInstant(ij3d.ContentInstant) ExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog) Appearance(org.scijava.java3d.Appearance) View(org.scijava.java3d.View) ImageWindow3D(ij3d.ImageWindow3D) ItemGeometryGroup(uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemGeometryGroup) Rendering(uk.ac.sussex.gdsc.smlm.ij.ij3d.Shape3DHelper.Rendering) ItemIndexedTriangleMesh(uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemIndexedTriangleMesh)

Example 4 with ItemGroupNode

use of uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemGroupNode in project GDSC-SMLM by aherbert.

the class ImageJ3DResultsViewer method run.

@Override
public void run(String arg) {
    // For testing
    // if (true || Utils.isExtraOptions())
    // {
    // new ImageJ3DResultsViewerDemo().run(arg);
    // return;
    // }
    SmlmUsageTracker.recordPlugin(this.getClass(), arg);
    if (ImageJ3DViewerUtils.JAVA_3D_VERSION == null) {
        IJ.error(TITLE, "Java 3D is not available");
        return;
    }
    if (MemoryPeakResults.isMemoryEmpty()) {
        IJ.error(TITLE, "There are no fitting results in memory");
        return;
    }
    final ImageJ3DResultsViewerSettings.Builder settings = SettingsManager.readImageJ3DResultsViewerSettings(0).toBuilder();
    addToSelection.set(settings.getAddToSelection());
    // Get a list of the window titles available. Allow the user to select
    // an existing window or a new one.
    final String title = TITLE;
    final List<Image3DUniverse> univList = new LocalList<>();
    final List<String> titleList = new LocalList<>();
    titleList.add("New window");
    buildWindowList(title, univList, titleList);
    final String[] titles = titleList.toArray(new String[0]);
    final ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
    gd.addMessage("Select a dataset to display");
    ResultsManager.addInput(gd, settings.getInputOption(), InputSource.MEMORY);
    // The behaviour is to allow the settings to store if the user prefers a new window
    // or to reuse an existing window. If 'new window' then a new window should always
    // be selected. Otherwise open in the same window as last time. If there was no last
    // window then the settings will carried over from the last ImageJ session.
    final String window = (settings.getNewWindow()) ? "" : lastWindow.get();
    gd.addChoice("Window", titles, window);
    gd.addSlider("Transparancy", 0, 0.9, settings.getTransparency(), new OptionListener<Double>() {

        @Override
        public boolean collectOptions(Double value) {
            return collectOptions(false);
        }

        @Override
        public boolean collectOptions() {
            return collectOptions(true);
        }

        private boolean collectOptions(boolean silent) {
            final ExtendedGenericDialog egd = new ExtendedGenericDialog("Transparancy options", null);
            egd.addCheckbox("Support_dynamic_transparency", settings.getSupportDynamicTransparency());
            egd.addCheckbox("Enable_dynamic_transparency", settings.getEnableDynamicTransparency());
            egd.setSilent(silent);
            egd.showDialog(true, gd);
            if (egd.wasCanceled()) {
                return false;
            }
            settings.setSupportDynamicTransparency(egd.getNextBoolean());
            settings.setEnableDynamicTransparency(egd.getNextBoolean());
            return true;
        }
    });
    gd.addChoice("Colour", LutHelper.getLutNames(), settings.getLut());
    gd.addChoice("Rendering", RENDERING, settings.getRendering(), new OptionListener<Integer>() {

        @Override
        public boolean collectOptions(Integer value) {
            settings.setRendering(value);
            return collectOptions(false);
        }

        @Override
        public boolean collectOptions() {
            return collectOptions(true);
        }

        private boolean collectOptions(boolean silent) {
            final ExtendedGenericDialog egd = new ExtendedGenericDialog("Drawing mode options", null);
            final int rendering = settings.getRendering();
            if (rendering != 0) {
                return false;
            }
            egd.addNumericField("Pixel_size", settings.getPixelSize(), 2, 6, "px");
            egd.setSilent(silent);
            egd.showDialog(true, gd);
            if (egd.wasCanceled()) {
                return false;
            }
            settings.setPixelSize(egd.getNextNumber());
            return true;
        }
    });
    gd.addCheckbox("Shaded", settings.getShaded());
    gd.addChoice("Size_mode", SIZE_MODE, settings.getSizeMode(), new OptionListener<Integer>() {

        @Override
        public boolean collectOptions(Integer value) {
            settings.setSizeMode(value);
            return collectOptions(false);
        }

        @Override
        public boolean collectOptions() {
            return collectOptions(true);
        }

        private boolean collectOptions(boolean silent) {
            final ExtendedGenericDialog egd = new ExtendedGenericDialog("Size mode options", null);
            final SizeMode mode = SizeMode.forNumber(settings.getSizeMode());
            if (mode == SizeMode.FIXED_SIZE) {
                egd.addNumericField("Size", settings.getSize(), 2, 6, "nm");
            } else {
                // Other modes do not require options
                return false;
            }
            egd.setSilent(silent);
            egd.showDialog(true, gd);
            if (egd.wasCanceled()) {
                return false;
            }
            settings.setSize(egd.getNextNumber());
            return true;
        }
    });
    gd.addChoice("Sort_mode", SORT_MODE, settings.getSortMode(), new OptionListener<Integer>() {

        @Override
        public boolean collectOptions(Integer value) {
            settings.setSortMode(value);
            return collectOptions(false);
        }

        @Override
        public boolean collectOptions() {
            return collectOptions(true);
        }

        private boolean collectOptions(boolean silent) {
            final ExtendedGenericDialog egd = new ExtendedGenericDialog("Sort mode options", null);
            final SortMode mode = SortMode.forNumber(settings.getSortMode());
            if (mode == SortMode.NONE) {
                return false;
            }
            egd.addMessage(TextUtils.wrap("Note: The sort mode is used to correctly render transparent objects. " + "For non-transparent objects faster rendering is achieved with a reverse " + "sort to put close objects at the front.", 80));
            egd.addMessage(TextUtils.wrap(mode.getDetails(), 80));
            egd.addMessage("Define the direction of the view");
            egd.addNumericField("Direction_x", settings.getSortDirectionX(), 3, 10, "");
            egd.addNumericField("Direction_y", settings.getSortDirectionY(), 3, 10, "");
            egd.addNumericField("Direction_z", settings.getSortDirectionZ(), 3, 10, "");
            if (mode == SortMode.PERSPECTIVE) {
                egd.addMessage("Define the view eye position");
                egd.addNumericField("Eye_x", settings.getSortEyeX(), 3, 10, "nm");
                egd.addNumericField("Eye_y", settings.getSortEyeY(), 3, 10, "nm");
                egd.addNumericField("Eye_z", settings.getSortEyeZ(), 3, 10, "nm");
            }
            egd.setSilent(silent);
            egd.showDialog(true, gd);
            if (egd.wasCanceled()) {
                return false;
            }
            settings.setSortDirectionX(egd.getNextNumber());
            settings.setSortDirectionY(egd.getNextNumber());
            settings.setSortDirectionZ(egd.getNextNumber());
            if (mode == SortMode.PERSPECTIVE) {
                settings.setSortEyeX(egd.getNextNumber());
                settings.setSortEyeY(egd.getNextNumber());
                settings.setSortEyeZ(egd.getNextNumber());
            }
            return true;
        }
    });
    gd.addChoice("Transparency_mode", TRANSPARENCY_MODE, settings.getTransparencyMode(), new OptionListener<Integer>() {

        @Override
        public boolean collectOptions(Integer value) {
            settings.setTransparencyMode(value);
            return collectOptions(false);
        }

        @Override
        public boolean collectOptions() {
            return collectOptions(true);
        }

        private boolean collectOptions(boolean silent) {
            final ExtendedGenericDialog egd = new ExtendedGenericDialog("Transparency mode options", null);
            final TransparencyMode mode = TransparencyMode.forNumber(settings.getTransparencyMode());
            if (mode == TransparencyMode.NONE) {
                return false;
            }
            egd.addSlider("Min_transparancy", 0, 0.95, settings.getMinTransparency());
            egd.addSlider("Max_transparancy", 0, 0.95, settings.getMaxTransparency());
            egd.setSilent(silent);
            egd.showDialog(true, gd);
            if (egd.wasCanceled()) {
                return false;
            }
            settings.setMinTransparency(egd.getNextNumber());
            settings.setMaxTransparency(egd.getNextNumber());
            return true;
        }
    });
    addColourMode(settings, gd);
    gd.addMessage("2D options");
    gd.addChoice("Depth_mode", DEPTH_MODE, settings.getDepthMode(), new OptionListener<Integer>() {

        @Override
        public boolean collectOptions(Integer value) {
            settings.setDepthMode(value);
            return collectOptions(false);
        }

        @Override
        public boolean collectOptions() {
            return collectOptions(true);
        }

        private boolean collectOptions(boolean silent) {
            final ExtendedGenericDialog egd = new ExtendedGenericDialog("Depth mode options", null);
            final DepthMode mode = DepthMode.forNumber(settings.getDepthMode());
            if (mode == DepthMode.NONE) {
                return false;
            }
            egd.addNumericField("Depth_range", settings.getDepthRange(), 2, 6, "nm");
            if (mode == DepthMode.DITHER) {
                egd.addNumericField("Dither_seed", settings.getDitherSeed(), 0);
            }
            egd.setSilent(silent);
            egd.showDialog(true, gd);
            if (egd.wasCanceled()) {
                return false;
            }
            settings.setDepthRange(egd.getNextNumber());
            if (mode == DepthMode.DITHER) {
                settings.setDitherSeed((int) egd.getNextNumber());
            }
            return true;
        }
    });
    addHelp(gd);
    gd.showDialog();
    if (gd.wasCanceled()) {
        return;
    }
    final String name = ResultsManager.getInputSource(gd);
    final int windowChoice = gd.getNextChoiceIndex();
    lastWindow.set(titles[windowChoice]);
    settings.setInputOption(name);
    settings.setTransparency(gd.getNextNumber());
    settings.setLut(gd.getNextChoiceIndex());
    settings.setRendering(gd.getNextChoiceIndex());
    settings.setShaded(gd.getNextBoolean());
    settings.setSizeMode(gd.getNextChoiceIndex());
    settings.setSortMode(gd.getNextChoiceIndex());
    settings.setTransparencyMode(gd.getNextChoiceIndex());
    settings.setColourMode(gd.getNextChoiceIndex());
    settings.setDepthMode(gd.getNextChoiceIndex());
    gd.collectOptions();
    if (windowChoice == 0) {
        // Store if the user chose a new window when they had a choice of an existing window
        if (titleList.size() > 1) {
            settings.setNewWindow(true);
        // Otherwise they had no choice so leave the preferences as they are.
        }
    } else {
        // This was not a new window
        settings.setNewWindow(false);
    }
    SettingsManager.writeSettings(settings);
    MemoryPeakResults results = ResultsManager.loadInputResults(name, false, null, null);
    if (MemoryPeakResults.isEmpty(results)) {
        IJ.error(TITLE, "No results could be loaded");
        return;
    }
    // Determine if the drawing mode is supported and compute the point size
    final Point3f[] sphereSize = createSphereSize(results, settings);
    if (sphereSize == null) {
        return;
    }
    // Cache the table settings
    resultsTableSettings.set(settings.getResultsTableSettings());
    // Create a 3D viewer.
    if (windowChoice == 0) {
        univ = createImage3DUniverse(title, titleList);
    } else {
        // Ignore the new window
        univ = univList.get(windowChoice - 1);
    }
    lastWindow.set(univ.getWindow().getTitle());
    results = results.copy();
    // Commence a digest
    final Future<PeakResultsDigest> futureDigest = PeakResultsDigest.digestLater(executorService, results.toArray());
    final LocalList<Point3f> points = getPoints(results, settings);
    final ResultsMetaData data = new ResultsMetaData(settings.build(), results, points, sphereSize);
    sort(data);
    final float[] alpha = createAlpha(results, settings, sphereSize);
    final float transparency = getTransparency(settings);
    final Color3f[] colors = createColour(results, settings);
    ContentNode contentNode;
    // Build to support true transparency (depends on settings).
    // Currently this is not supported for PointArrays as they require colouring
    // in the coordinate data.
    IJ.showStatus("Creating 3D geometry ...");
    if (settings.getSupportDynamicTransparency()) {
        final ItemGeometryGroup pointGroup = createItemGroup(settings, sphereSize, points, alpha, transparency, colors);
        if (pointGroup == null) {
            IJ.showStatus("");
            return;
        }
        if (settings.getEnableDynamicTransparency()) {
            final long total = points.size() + getTotalTransparentObjects(univ, name);
            activateDynamicTransparency(univ, total, settings.getEnableDynamicTransparency());
        } else {
            activateDynamicTransparency(univ, 0, settings.getEnableDynamicTransparency());
        }
        contentNode = new ItemGroupNode(pointGroup);
    } else {
        final ItemMesh mesh = createItemMesh(settings, points, sphereSize, transparency, alpha);
        if (mesh == null) {
            IJ.showStatus("");
            return;
        }
        setColour(mesh, colors);
        contentNode = new CustomMeshNode(mesh);
    }
    IJ.showStatus("Creating 3D content ...");
    // Use custom content to support adding new switchable nodes
    final CustomContent content = new CustomContent(name, !settings.getSupportDynamicTransparency());
    final CustomContentInstant contentInstant = (CustomContentInstant) content.getCurrent();
    contentInstant.setTransparency((float) settings.getTransparency());
    contentInstant.setShaded(settings.getShaded());
    contentInstant.showCoordinateSystem(UniverseSettings.showLocalCoordinateSystemsByDefault);
    contentInstant.display(contentNode);
    createHighlightColour(settings.getHighlightColour());
    content.setUserData(data);
    // Prevent relative rotation
    content.setLocked(true);
    // Set up the click selection node
    data.createClickSelectionNode(contentInstant);
    // Set up the results selection model
    data.digest = PeakResultsDigest.waitForDigest(futureDigest, -1);
    if (data.digest == null) {
        IJ.error(TITLE, "Failed to identify repeat results set");
        IJ.showStatus("");
        return;
    }
    Triple<PeakResultTableModel, ListSelectionModel, PeakResultTableModelFrame> triplet = resultsTables.get(data.digest);
    if (triplet == null) {
        triplet = Triple.of(new PeakResultTableModel(results, false, // Note the settings do not matter until the table is set live
        resultsTableSettings.get()), new DefaultListSelectionModel(), null);
        triplet.getLeft().setCheckDuplicates(true);
        resultsTables.put(data.digest, triplet);
    }
    // Preserve orientation on the content
    final boolean auto = univ.getAutoAdjustView();
    final Content oldContent = univ.getContent(name);
    if (oldContent == null) {
        univ.setAutoAdjustView(true);
    } else {
        univ.removeContent(name);
        univ.setAutoAdjustView(false);
    }
    IJ.showStatus("Drawing 3D content ... ");
    final StopWatch sw = StopWatch.createStarted();
    final Future<Content> future = univ.addContentLater(content);
    Content added = null;
    for (; ; ) {
        try {
            // Wait for 1 second
            for (int i = 0; i < 20; i++) {
                Thread.sleep(50);
                if (future.isDone()) {
                    // Only get the result when finished, so avoiding a blocking wait
                    added = future.get();
                    break;
                }
            }
            if (added != null) {
                break;
            }
            final long seconds = sw.getTime(TimeUnit.SECONDS);
            if (seconds % 20 == 0) {
                final ExtendedGenericDialog egd = new ExtendedGenericDialog(TITLE, null);
                egd.addMessage("Current wait time is " + sw.toString());
                egd.setOKLabel("Wait");
                egd.showDialog();
                if (egd.wasCanceled()) {
                    future.cancel(true);
                    break;
                }
            }
            IJ.showStatus("Drawing 3D content ... " + seconds);
        } catch (final InterruptedException ex) {
            Thread.currentThread().interrupt();
        } catch (final ExecutionException ex) {
            break;
        }
    }
    univ.setAutoAdjustView(auto);
    // Initialise the selection model
    if (added != null) {
        data.addSelectionModel(triplet);
    }
    IJ.showStatus("");
}
Also used : ImageJ3DResultsViewerSettings(uk.ac.sussex.gdsc.smlm.ij.settings.GUIProtos.ImageJ3DResultsViewerSettings) DefaultListSelectionModel(javax.swing.DefaultListSelectionModel) PeakResultTableModel(uk.ac.sussex.gdsc.smlm.ij.gui.PeakResultTableModel) LocalList(uk.ac.sussex.gdsc.core.utils.LocalList) CustomContentInstant(uk.ac.sussex.gdsc.smlm.ij.ij3d.CustomContentInstant) MemoryPeakResults(uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults) Builder(uk.ac.sussex.gdsc.smlm.ij.settings.GUIProtos.ImageJ3DResultsViewerSettings.Builder) DefaultListSelectionModel(javax.swing.DefaultListSelectionModel) ListSelectionModel(javax.swing.ListSelectionModel) ExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog) ItemGeometryGroup(uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemGeometryGroup) OrderedItemGeometryGroup(uk.ac.sussex.gdsc.smlm.ij.ij3d.OrderedItemGeometryGroup) PeakResultsDigest(uk.ac.sussex.gdsc.smlm.results.PeakResultsDigest) Content(ij3d.Content) CustomContent(uk.ac.sussex.gdsc.smlm.ij.ij3d.CustomContent) CustomMeshNode(customnode.CustomMeshNode) ReferenceItemMesh(uk.ac.sussex.gdsc.smlm.ij.ij3d.ReferenceItemMesh) ItemMesh(uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemMesh) Color3f(org.scijava.vecmath.Color3f) ItemGroupNode(uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemGroupNode) ContentNode(ij3d.ContentNode) CustomContent(uk.ac.sussex.gdsc.smlm.ij.ij3d.CustomContent) Point3f(org.scijava.vecmath.Point3f) ExecutionException(java.util.concurrent.ExecutionException) Image3DUniverse(ij3d.Image3DUniverse) PeakResultTableModelFrame(uk.ac.sussex.gdsc.smlm.ij.gui.PeakResultTableModelFrame) StopWatch(org.apache.commons.lang3.time.StopWatch)

Aggregations

CustomContent (uk.ac.sussex.gdsc.smlm.ij.ij3d.CustomContent)4 ItemGroupNode (uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemGroupNode)4 Content (ij3d.Content)3 ContentInstant (ij3d.ContentInstant)3 Image3DUniverse (ij3d.Image3DUniverse)3 CustomContentInstant (uk.ac.sussex.gdsc.smlm.ij.ij3d.CustomContentInstant)3 ItemGeometryGroup (uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemGeometryGroup)3 MemoryPeakResults (uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults)3 CustomMesh (customnode.CustomMesh)2 CustomMeshNode (customnode.CustomMeshNode)2 ImageWindow3D (ij3d.ImageWindow3D)2 Point3f (org.scijava.vecmath.Point3f)2 ExtendedGenericDialog (uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog)2 ItemMesh (uk.ac.sussex.gdsc.smlm.ij.ij3d.ItemMesh)2 OrderedItemGeometryGroup (uk.ac.sussex.gdsc.smlm.ij.ij3d.OrderedItemGeometryGroup)2 ReferenceItemMesh (uk.ac.sussex.gdsc.smlm.ij.ij3d.ReferenceItemMesh)2 ImageJ3DResultsViewerSettings (uk.ac.sussex.gdsc.smlm.ij.settings.GUIProtos.ImageJ3DResultsViewerSettings)2 ContentNode (ij3d.ContentNode)1 ImageCanvas3D (ij3d.ImageCanvas3D)1 MouseAdapter (java.awt.event.MouseAdapter)1