Search in sources :

Example 1 with ContentNode

use of ij3d.ContentNode in project GDSC-SMLM by aherbert.

the class CustomContentInstant method display.

@Override
public void display(final ContentNode node) {
    // Remove everything if possible
    for (final Enumeration<Node> e = ordered.getAllChildren(); e.hasMoreElements(); ) {
        final Switch s = (Switch) e.nextElement();
        s.removeAllChildren();
    }
    // Remove custom switch objects
    while (ordered.numChildren() > 5) {
        ordered.removeChild(ordered.numChildren() - 1);
    }
    customBefore = 0;
    if (switchMap != null) {
        switchMap.clear();
    }
    // Create content node and add it to the switch
    contentNode = node;
    ((Switch) ordered.getChild(CO)).addChild(contentNode);
    // Create the bounding box and add it to the switch
    final Point3d min = new Point3d();
    contentNode.getMin(min);
    final Point3d max = new Point3d();
    contentNode.getMax(max);
    BoundingBox bb = new BoundingBox(min, max);
    bb.setPickable(false);
    ((Switch) ordered.getChild(BS)).addChild(bb);
    bb = new BoundingBox(min, max, new Color3f(0, 1, 0));
    bb.setPickable(false);
    ((Switch) ordered.getChild(BB)).addChild(bb);
    // Create coordinate system and add it to the switch
    final float cl = (float) Math.abs(max.x - min.x) / 5f;
    final CoordinateSystem cs = new CoordinateSystem(cl, new Color3f(0, 1, 0));
    cs.setPickable(false);
    ((Switch) ordered.getChild(CS)).addChild(cs);
    // Create point list and add it to the switch
    ((Switch) ordered.getChild(PL)).addChild(plShape);
    // Adjust the landmark point size properly
    plShape.setRadius((float) min.distance(max) / 100f);
    // Initialize child mask of the switch
    setSwitchValue(BS, selected);
    setSwitchValue(CS, coordVisible);
    setSwitchValue(CO, visible);
    setSwitchValue(PL, showPl);
    // Update type
    this.type = CUSTOM;
}
Also used : Switch(org.scijava.java3d.Switch) Point3d(org.scijava.vecmath.Point3d) CoordinateSystem(ij3d.shapes.CoordinateSystem) ContentNode(ij3d.ContentNode) CustomMeshNode(customnode.CustomMeshNode) Node(org.scijava.java3d.Node) BoundingBox(ij3d.shapes.BoundingBox) Color3f(org.scijava.vecmath.Color3f)

Example 2 with ContentNode

use of ij3d.ContentNode 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

CustomMeshNode (customnode.CustomMeshNode)2 ContentNode (ij3d.ContentNode)2 Color3f (org.scijava.vecmath.Color3f)2 Content (ij3d.Content)1 Image3DUniverse (ij3d.Image3DUniverse)1 BoundingBox (ij3d.shapes.BoundingBox)1 CoordinateSystem (ij3d.shapes.CoordinateSystem)1 ExecutionException (java.util.concurrent.ExecutionException)1 DefaultListSelectionModel (javax.swing.DefaultListSelectionModel)1 ListSelectionModel (javax.swing.ListSelectionModel)1 StopWatch (org.apache.commons.lang3.time.StopWatch)1 Node (org.scijava.java3d.Node)1 Switch (org.scijava.java3d.Switch)1 Point3d (org.scijava.vecmath.Point3d)1 Point3f (org.scijava.vecmath.Point3f)1 ExtendedGenericDialog (uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog)1 LocalList (uk.ac.sussex.gdsc.core.utils.LocalList)1 PeakResultTableModel (uk.ac.sussex.gdsc.smlm.ij.gui.PeakResultTableModel)1 PeakResultTableModelFrame (uk.ac.sussex.gdsc.smlm.ij.gui.PeakResultTableModelFrame)1 CustomContent (uk.ac.sussex.gdsc.smlm.ij.ij3d.CustomContent)1