diff --git a/pom.xml b/pom.xml
index 242fda1e..7c3827be 100644
--- a/pom.xml
+++ b/pom.xml
@@ -108,7 +108,7 @@
deploy-to-scijava
- 94e8d97
+ 9d42647
2.0.3
a40d46f
diff --git a/src/main/java/sc/iview/vector/FloatVector3.java b/src/main/java/sc/iview/ImageJMain.kt
similarity index 63%
rename from src/main/java/sc/iview/vector/FloatVector3.java
rename to src/main/java/sc/iview/ImageJMain.kt
index 4c57084a..7f98b55f 100644
--- a/src/main/java/sc/iview/vector/FloatVector3.java
+++ b/src/main/java/sc/iview/ImageJMain.kt
@@ -6,13 +6,13 @@
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
- *
+ *
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -26,39 +26,35 @@
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
-package sc.iview.vector;
+package sc.iview
+
+import net.imagej.lut.LUTService
+import net.imagej.ops.OpService
+import net.imagej.units.UnitService
+import org.scijava.Context
+import org.scijava.console.ConsoleService
+import org.scijava.io.IOService
+import org.scijava.menu.MenuService
+import org.scijava.options.OptionsService
+import org.scijava.tool.ToolService
+import org.scijava.ui.UIService
+import org.scijava.ui.swing.SwingIconService
/**
- * {@link Vector3} backed by three {@code float}s.
- *
- * @author Curtis Rueden
+ * Entry point for testing SciView functionality.
+ *
* @author Kyle Harrington
+ * @author Ulrik Guenther
*/
-public class FloatVector3 implements Vector3 {
-
- private float x, y, z;
-
- public FloatVector3( float x, float y, float z ) {
- this.x = x;
- this.y = y;
- this.z = z;
- }
-
- @Override public float xf() { return x; }
- @Override public float yf() { return y; }
- @Override public float zf() { return z; }
-
- @Override public void setX( float position ) { x = position; }
- @Override public void setY( float position ) { y = position; }
- @Override public void setZ( float position ) { z = position; }
-
- @Override
- public Vector3 copy() {
- return new FloatVector3(xf(),yf(),zf());
- }
+object ImageJMain {
+ @Throws(Exception::class)
+ @JvmStatic
+ fun main(args: Array) {
+ val context = Context()
+ val uiService = context.service(UIService::class.java)
+ val sciViewService = context.service(SciViewService::class.java)
- @Override
- public String toString() {
- return "[" + xf() + "; " + yf() + "; " + zf() + "]";
+ uiService.showUI()
+ sciViewService.createSciView()
}
}
diff --git a/src/main/java/sc/iview/SciView.java b/src/main/java/sc/iview/SciView.java
deleted file mode 100644
index e396c8b8..00000000
--- a/src/main/java/sc/iview/SciView.java
+++ /dev/null
@@ -1,2727 +0,0 @@
-/*-
- * #%L
- * Scenery-backed 3D visualization package for ImageJ.
- * %%
- * Copyright (C) 2016 - 2020 SciView developers.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-package sc.iview;
-
-import bdv.BigDataViewer;
-import bdv.cache.CacheControl;
-import bdv.tools.brightness.ConverterSetup;
-import bdv.util.AxisOrder;
-import bdv.util.RandomAccessibleIntervalSource;
-import bdv.util.RandomAccessibleIntervalSource4D;
-import bdv.util.volatiles.VolatileView;
-import bdv.util.volatiles.VolatileViewData;
-import bdv.viewer.Source;
-import bdv.viewer.SourceAndConverter;
-import cleargl.GLVector;
-import com.formdev.flatlaf.FlatLightLaf;
-import com.intellij.ui.tabs.JBTabsPosition;
-import com.intellij.ui.tabs.TabInfo;
-import com.intellij.ui.tabs.impl.JBEditorTabs;
-import graphics.scenery.Box;
-import graphics.scenery.*;
-import graphics.scenery.backends.RenderedImage;
-import graphics.scenery.backends.Renderer;
-import graphics.scenery.backends.opengl.OpenGLRenderer;
-import graphics.scenery.backends.vulkan.VulkanRenderer;
-import graphics.scenery.controls.InputHandler;
-import graphics.scenery.controls.OpenVRHMD;
-import graphics.scenery.controls.TrackerInput;
-import graphics.scenery.controls.behaviours.ArcballCameraControl;
-import graphics.scenery.controls.behaviours.FPSCameraControl;
-import graphics.scenery.controls.behaviours.MovementCommand;
-import graphics.scenery.controls.behaviours.SelectCommand;
-import graphics.scenery.utils.*;
-import graphics.scenery.volumes.Colormap;
-import graphics.scenery.volumes.RAIVolume;
-import graphics.scenery.volumes.TransferFunction;
-import graphics.scenery.volumes.Volume;
-import io.scif.SCIFIOService;
-import kotlin.Unit;
-import kotlin.jvm.functions.Function0;
-import kotlin.jvm.functions.Function1;
-import kotlin.jvm.functions.Function3;
-import net.imagej.Dataset;
-import net.imagej.ImageJService;
-import net.imagej.axis.CalibratedAxis;
-import net.imagej.axis.DefaultAxisType;
-import net.imagej.axis.DefaultLinearAxis;
-import net.imagej.interval.CalibratedRealInterval;
-import net.imagej.lut.LUTService;
-import net.imagej.ops.OpService;
-import net.imagej.units.UnitService;
-import net.imglib2.Cursor;
-import net.imglib2.RandomAccess;
-import net.imglib2.*;
-import net.imglib2.display.ColorTable;
-import net.imglib2.img.Img;
-import net.imglib2.realtransform.AffineTransform3D;
-import net.imglib2.type.numeric.ARGBType;
-import net.imglib2.type.numeric.RealType;
-import net.imglib2.type.numeric.integer.UnsignedByteType;
-import net.imglib2.view.Views;
-import org.jetbrains.annotations.NotNull;
-import org.joml.Quaternionf;
-import org.joml.Vector2f;
-import org.joml.Vector3f;
-import org.lwjgl.system.Platform;
-import org.scijava.Context;
-import org.scijava.command.CommandService;
-import org.scijava.display.Display;
-import org.scijava.display.DisplayService;
-import org.scijava.event.EventHandler;
-import org.scijava.event.EventService;
-import org.scijava.io.IOService;
-import org.scijava.log.LogLevel;
-import org.scijava.log.LogService;
-import org.scijava.menu.MenuService;
-import org.scijava.object.ObjectService;
-import org.scijava.plugin.Parameter;
-import org.scijava.service.SciJavaService;
-import org.scijava.thread.ThreadService;
-import org.scijava.ui.behaviour.Behaviour;
-import org.scijava.ui.behaviour.ClickBehaviour;
-import org.scijava.ui.behaviour.InputTrigger;
-import org.scijava.ui.swing.menu.SwingJMenuBarCreator;
-import org.scijava.util.ColorRGB;
-import org.scijava.util.Colors;
-import org.scijava.util.VersionUtils;
-import sc.iview.commands.help.Help;
-import sc.iview.commands.view.NodePropertyEditor;
-import sc.iview.controls.behaviours.*;
-import sc.iview.event.NodeActivatedEvent;
-import sc.iview.event.NodeAddedEvent;
-import sc.iview.event.NodeChangedEvent;
-import sc.iview.event.NodeRemovedEvent;
-import sc.iview.process.MeshConverter;
-import sc.iview.ui.ContextPopUpNodeChooser;
-import sc.iview.ui.REPLPane;
-import sc.iview.vector.JOMLVector3;
-import sc.iview.vector.Vector3;
-import tpietzsch.example2.VolumeViewerOptions;
-
-import javax.imageio.ImageIO;
-import javax.script.ScriptException;
-import javax.swing.*;
-import java.awt.Image;
-import java.awt.*;
-import java.awt.event.*;
-import java.awt.geom.AffineTransform;
-import java.awt.image.BufferedImage;
-import java.awt.image.DataBufferByte;
-import java.io.*;
-import java.net.URL;
-import java.nio.ByteBuffer;
-import java.nio.FloatBuffer;
-import java.util.List;
-import java.util.Queue;
-import java.util.*;
-import java.util.concurrent.Future;
-import java.util.function.Function;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-
-/**
- * Main SciView class.
- *
- * @author Kyle Harrington
- */
-// we suppress unused warnings here because @Parameter-annotated fields
-// get updated automatically by SciJava.
-@SuppressWarnings({"unused", "WeakerAccess"})
-public class SciView extends SceneryBase implements CalibratedRealInterval {
-
- public static final ColorRGB DEFAULT_COLOR = Colors.LIGHTGRAY;
- private final SceneryPanel[] sceneryPanel = { null };
- /**
- * Mouse controls for FPS movement and Arcball rotation
- */
- protected AnimatedCenteringBeforeArcBallControl targetArcball;
- protected FPSCameraControl fpsControl;
- /**
- * The floor that orients the user in the scene
- */
- protected Node floor;
- protected boolean vrActive = false;
- /**
- * The primary camera/observer in the scene
- */
- Camera camera = null;
- /**
- * Geometry/Image information of scene
- */
- private CalibratedAxis[] axes;
-
- @Parameter
- private LogService log;
- @Parameter
- private MenuService menus;
- @Parameter
- private IOService io;
- @Parameter
- private OpService ops;
- @Parameter
- private EventService eventService;
- @Parameter
- private DisplayService displayService;
- @Parameter
- private LUTService lutService;
- @Parameter
- private ThreadService threadService;
- @Parameter
- private ObjectService objectService;
- @Parameter
- private UnitService unitService;
- /**
- * Queue keeps track of the currently running animations
- **/
- private Queue animations;
- /**
- * Animation pause tracking
- **/
- private boolean animating;
- /**
- * This tracks the actively selected Node in the scene
- */
- private Node activeNode = null;
-
- /**
- * Speeds for input controls
- */
- public ControlsParameters controlsParameters = new ControlsParameters();
-
- private Display> scijavaDisplay;
- private SplashLabel splashLabel;
- private SceneryJPanel panel;
- private JSplitPane mainSplitPane;
- private JSplitPane inspector;
- private JSplitPane interpreterSplitPane;
- private REPLPane interpreterPane;
- private NodePropertyEditor nodePropertyEditor;
- private ArrayList lights;
- private Stack> controlStack;
- private JFrame frame;
- private Predicate super Node> notAbstractNode = (Predicate) node -> !( (node instanceof Camera) || (node instanceof Light) || (node==getFloor()));
- private boolean isClosed = false;
- private Function> notAbstractBranchingFunction = node -> node.getChildren().stream().filter(notAbstractNode).collect(Collectors.toList());
-
- // If true, then when a new node is added to the scene, the camera will refocus on this node by default
- private boolean centerOnNewNodes;
-
- // If true, then when a new node is added the thread will block until the node is added to the scene. This is required for
- // centerOnNewNodes
- private boolean blockOnNewNodes;
- private PointLight headlight;
-
- public SciView( Context context ) {
- super( "SciView", 1280, 720, false, context );
- context.inject( this );
- }
-
- public SciView( String applicationName, int windowWidth, int windowHeight ) {
- super( applicationName, windowWidth, windowHeight, false );
- }
-
- public boolean isClosed() {
- return isClosed;
- }
-
- public InputHandler publicGetInputHandler() {
- return getInputHandler();
- }
-
- /**
- * Toggle video recording with scenery's video recording mechanism
- * Note: this video recording may skip frames because it is asynchronous
- */
- public void toggleRecordVideo() {
- if( getRenderer() instanceof OpenGLRenderer )
- ((OpenGLRenderer)getRenderer()).recordMovie();
- else
- ((VulkanRenderer)getRenderer()).recordMovie();
- }
-
- /**
- * Toggle video recording with scenery's video recording mechanism
- * Note: this video recording may skip frames because it is asynchronous
- *
- * @param filename destination for saving video
- * @param overwrite should the file be replaced, otherwise a unique incrementing counter will be appended
- */
- public void toggleRecordVideo(String filename, boolean overwrite) {
- if( getRenderer() instanceof OpenGLRenderer )
- ((OpenGLRenderer)getRenderer()).recordMovie(filename, overwrite);
- else
- ((VulkanRenderer)getRenderer()).recordMovie(filename, overwrite);
- }
-
- /**
- * This pushes the current input setup onto a stack that allows them to be restored with restoreControls.
- * It stacks in particular: all keybindings, all Behaviours, and all step sizes and mouse sensitivities
- * (which are held together in {@link ControlsParameters}).
- *
- * Word of warning: The stashing memorizes references only on currently used controls
- * (such as, e.g., {@link MovementCommand}, {@link FPSCameraControl} or {@link NodeTranslateControl}),
- * it does not create an extra copy of any control. That said, if you modify any control
- * object despite it was already stashed with this method, the change will be visible in the "stored"
- * control and will not go away after the restore... To be on the safe side for now at least, create
- * new and modified controls rather than directly changing them.
- */
- public void stashControls() {
- final InputHandler inputHandler = getInputHandler();
- if (inputHandler == null) {
- getLogger().error( "InputHandler is null, cannot store controls" );
- return;
- }
-
- final HashMap controlState = new HashMap<>();
-
- //behaviours:
- for ( String actionName: inputHandler.getAllBehaviours() )
- controlState.put( STASH_BEHAVIOUR_KEY+actionName, inputHandler.getBehaviour(actionName) );
-
- //bindings:
- for ( String actionName: inputHandler.getAllBehaviours() )
- for ( InputTrigger trigger : inputHandler.getKeyBindings(actionName) )
- controlState.put( STASH_BINDING_KEY+actionName, trigger.toString() );
-
- //finally, stash the control parameters
- controlState.put( STASH_CONTROLSPARAMS_KEY, controlsParameters );
-
- //...and stash it!
- controlStack.push(controlState);
- }
-
- /**
- * This pops/restores the previously stashed controls. Emits a warning if there are no stashed controls.
- * It first clears all controls, and then resets in particular: all keybindings, all Behaviours,
- * and all step sizes and mouse sensitivities (which are held together in {@link ControlsParameters}).
- *
- * Some recent changes may not be removed with this restore --
- * see discussion in the docs of {@link SciView#stashControls()} for more details.
- */
- public void restoreControls() {
- if (controlStack.empty()) {
- getLogger().warn("Not restoring controls, the controls stash stack is empty!");
- return;
- }
-
- final InputHandler inputHandler = getInputHandler();
- if (inputHandler == null) {
- getLogger().error( "InputHandler is null, cannot restore controls" );
- return;
- }
-
- //clear the input handler entirely
- for ( String actionName : inputHandler.getAllBehaviours() ) {
- inputHandler.removeKeyBinding( actionName );
- inputHandler.removeBehaviour( actionName );
- }
-
- //retrieve the most recent stash with controls
- final HashMap controlState = controlStack.pop();
- for (Map.Entry control : controlState.entrySet()) {
- String key;
- if (control.getKey().startsWith(STASH_BEHAVIOUR_KEY)) {
- //processing behaviour
- key = control.getKey().substring(STASH_BEHAVIOUR_KEY.length());
- inputHandler.addBehaviour( key, (Behaviour)control.getValue() );
- }
- else
- if (control.getKey().startsWith(STASH_BINDING_KEY)) {
- //processing key binding
- key = control.getKey().substring(STASH_BINDING_KEY.length());
- inputHandler.addKeyBinding( key, (String)control.getValue() );
- }
- else
- if (control.getKey().startsWith(STASH_CONTROLSPARAMS_KEY)) {
- //processing mouse sensitivities and step sizes...
- controlsParameters = (ControlsParameters)control.getValue();
- }
- }
- }
-
- private static final String STASH_BEHAVIOUR_KEY = "behaviour:";
- private static final String STASH_BINDING_KEY = "binding:";
- private static final String STASH_CONTROLSPARAMS_KEY = "parameters:";
-
- public ArrayList getLights() {
- return lights;
- }
-
- /**
- * Reset the scene to initial conditions
- */
- public void reset() {
- // Initialize the 3D axes
- axes = new CalibratedAxis[3];
-
- axes[0] = new DefaultLinearAxis(new DefaultAxisType("X", true), "um", 1);
- axes[1] = new DefaultLinearAxis(new DefaultAxisType("Y", true), "um", 1);
- axes[2] = new DefaultLinearAxis(new DefaultAxisType("Z", true), "um", 1);
-
- // Remove everything except camera
- Node[] toRemove = getSceneNodes( n -> !( n instanceof Camera ) );
- for( Node n : toRemove ) {
- deleteNode(n, false);
- }
-
- // Setup camera
- Camera cam;
- if( getCamera() == null ) {
- cam = new DetachedHeadCamera();
- this.camera = cam;
- cam.setPosition(new Vector3f(0.0f, 1.65f, 0.0f));
- getScene().addChild( cam );
- } else {
- cam = getCamera();
- }
- cam.setPosition( new Vector3f( 0.0f, 1.65f, 5.0f ) );
- cam.perspectiveCamera( 50.0f, getWindowWidth(), getWindowHeight(), 0.1f, 1000.0f );
-
- // Setup lights
- Vector3f[] tetrahedron = new Vector3f[4];
- tetrahedron[0] = new Vector3f( 1.0f, 0f, -1.0f/(float)Math.sqrt(2.0f) );
- tetrahedron[1] = new Vector3f( -1.0f,0f,-1.0f/(float)Math.sqrt(2.0) );
- tetrahedron[2] = new Vector3f( 0.0f,1.0f,1.0f/(float)Math.sqrt(2.0) );
- tetrahedron[3] = new Vector3f( 0.0f,-1.0f,1.0f/(float)Math.sqrt(2.0) );
-
- lights = new ArrayList<>();
-
- for( int i = 0; i < 4; i++ ) {// TODO allow # initial lights to be customizable?
- PointLight light = new PointLight(150.0f);
- light.setPosition( tetrahedron[i].mul(25.0f) );
- light.setEmissionColor( new Vector3f( 1.0f, 1.0f, 1.0f ) );
- light.setIntensity( 1.0f );
- lights.add( light );
- //camera.addChild( light );
- getScene().addChild( light );
- }
-
- // Make a headlight for the camera
- headlight = new PointLight(150.0f);
- headlight.setPosition( new Vector3f(0f, 0f, -1f).mul(25.0f) );
- headlight.setEmissionColor( new Vector3f( 1.0f, 1.0f, 1.0f ) );
- headlight.setIntensity( 0.5f );
- headlight.setName("headlight");
-
-
- Icosphere lightSphere = new Icosphere(1.0f, 2);
- headlight.addChild(lightSphere);
- lightSphere.getMaterial().setDiffuse(headlight.getEmissionColor());
- lightSphere.getMaterial().setSpecular(headlight.getEmissionColor());
- lightSphere.getMaterial().setAmbient(headlight.getEmissionColor());
- lightSphere.getMaterial().setWireframe(true);
- lightSphere.setVisible(false);
- //lights.add( light );
- camera.setNearPlaneDistance(0.01f);
- camera.setFarPlaneDistance(1000.0f);
- camera.addChild( headlight );
-
- floor = new InfinitePlane();//new Box( new Vector3f( 500f, 0.2f, 500f ) );
- ((InfinitePlane)floor).setType(InfinitePlane.Type.Grid);
- floor.setName( "Floor" );
- getScene().addChild( floor );
-
- }
-
- /**
- * Initialization of SWING and scenery. Also triggers an initial population of lights/camera in the scene
- */
- @SuppressWarnings("restriction") @Override public void init() {
-
- // Darcula dependency went missing from maven repo, factor it out
-// if(Boolean.parseBoolean(System.getProperty("sciview.useDarcula", "false"))) {
-// try {
-// BasicLookAndFeel darcula = new DarculaLaf();
-// UIManager.setLookAndFeel(darcula);
-// } catch (Exception e) {
-// getLogger().info("Could not load Darcula Look and Feel");
-// }
-// }
- final String logLevel = System.getProperty("scenery.LogLevel", "info");
- log.setLevel(LogLevel.value(logLevel));
-
- LogbackUtils.setLogLevel(null, logLevel);
-
- System.getProperties().stringPropertyNames().forEach(name -> {
- if(name.startsWith("scenery.LogLevel")) {
- LogbackUtils.setLogLevel("", System.getProperty(name, "info"));
- }
- });
-
- // determine imagej-launcher version and to disable Vulkan if XInitThreads() fix
- // is not deployed
- try {
- final Class> launcherClass = Class.forName("net.imagej.launcher.ClassLauncher");
- String versionString = VersionUtils.getVersion(launcherClass);
-
- if (versionString != null && ExtractsNatives.Companion.getPlatform() == ExtractsNatives.Platform.LINUX) {
- versionString = versionString.substring(0, 5);
-
- final Version launcherVersion = new Version(versionString);
- final Version nonWorkingVersion = new Version("4.0.5");
-
- if (launcherVersion.compareTo(nonWorkingVersion) <= 0
- && !Boolean.parseBoolean(System.getProperty("sciview.DisableLauncherVersionCheck", "false"))) {
- getLogger().info("imagej-launcher version smaller or equal to non-working version (" + versionString + " vs. 4.0.5), disabling Vulkan as rendering backend. Disable check by setting 'scenery.DisableLauncherVersionCheck' system property to 'true'.");
- System.setProperty("scenery.Renderer", "OpenGLRenderer");
- } else {
- getLogger().info("imagej-launcher version bigger that non-working version (" + versionString + " vs. 4.0.5), all good.");
- }
- }
- } catch (ClassNotFoundException cnfe) {
- // Didn't find the launcher, so we're probably good.
- getLogger().info("imagej-launcher not found, not touching renderer preferences.");
- }
-
- // TODO: check for jdk 8 v. jdk 11 on linux and choose renderer accordingly
- if( Platform.get() == Platform.LINUX ) {
- String version = System.getProperty("java.version");
- if( version.startsWith("1.") ) {
- version = version.substring(2, 3);
- } else {
- int dot = version.indexOf(".");
- if (dot != -1) {
- version = version.substring(0, dot);
- }
- }
-
- // If Linux and JDK 8, then use OpenGLRenderer
- if( version.equals("8") )
- System.setProperty("scenery.Renderer", "OpenGLRenderer");
- }
-
- int x, y;
-
- try {
- Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
-
- x = screenSize.width/2 - getWindowWidth()/2;
- y = screenSize.height/2 - getWindowHeight()/2;
- } catch(HeadlessException e) {
- x = 10;
- y = 10;
- }
-
- frame = new JFrame("SciView");
- frame.setLayout(new BorderLayout(0, 0));
- frame.setSize(getWindowWidth(), getWindowHeight());
- frame.setLocation(x, y);
- frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
- nodePropertyEditor = new NodePropertyEditor( this );
-
- final JPanel p = new JPanel(new BorderLayout(0, 0));
- panel = new SceneryJPanel();
-
- JPopupMenu.setDefaultLightWeightPopupEnabled(false);
- final JMenuBar swingMenuBar = new JMenuBar();
- new SwingJMenuBarCreator().createMenus(menus.getMenu("SciView"), swingMenuBar);
- frame.setJMenuBar(swingMenuBar);
-
- p.setLayout(new OverlayLayout(p));
- p.setBackground(new Color(50, 48, 47));
- p.add(panel, BorderLayout.CENTER);
- panel.setVisible(true);
-
- nodePropertyEditor.getComponent(); // Initialize node property panel
-
- JTree inspectorTree = nodePropertyEditor.getTree();
- inspectorTree.setToggleClickCount(0);// This disables expanding menus on double click
- JPanel inspectorProperties = nodePropertyEditor.getProps();
-
- JBEditorTabs tp = new JBEditorTabs(null);
- tp.setTabsPosition(JBTabsPosition.right);
- tp.setSideComponentVertical(true);
-
- inspector = new JSplitPane(JSplitPane.VERTICAL_SPLIT, //
- new JScrollPane( inspectorTree ),
- new JScrollPane( inspectorProperties ));
- inspector.setDividerLocation( getWindowHeight() / 3 );
- inspector.setContinuousLayout(true);
- inspector.setBorder(BorderFactory.createEmptyBorder());
- inspector.setDividerSize(1);
- ImageIcon inspectorIcon = getScaledImageIcon(this.getClass().getResource("toolbox.png"), 16, 16);
-
- TabInfo tiInspector = new TabInfo(inspector, inspectorIcon);
- tiInspector.setText("");
- tp.addTab(tiInspector);
-
- // We need to get the surface scale here before initialising scenery's renderer, as
- // the information is needed already at initialisation time.
- final AffineTransform dt = frame.getGraphicsConfiguration().getDefaultTransform();
- final Vector2f surfaceScale = new Vector2f((float)dt.getScaleX(), (float)dt.getScaleY());
- getSettings().set("Renderer.SurfaceScale", surfaceScale);
-
- interpreterPane = new REPLPane(getScijavaContext());
- interpreterPane.getComponent().setBorder(BorderFactory.createEmptyBorder());
- ImageIcon interpreterIcon = getScaledImageIcon(this.getClass().getResource("terminal.png"), 16, 16);
-
- TabInfo tiREPL = new TabInfo(interpreterPane.getComponent(), interpreterIcon);
- tiREPL.setText("");
- tp.addTab(tiREPL);
-
- tp.addTabMouseListener(new MouseListener() {
- private boolean hidden = false;
- private int previousPosition = 0;
-
- @Override
- public void mouseClicked(MouseEvent e) {
- if(e.getClickCount() == 2) {
- toggleSidebar();
- }
- }
-
- @Override
- public void mousePressed(MouseEvent e) {
-
- }
-
- @Override
- public void mouseReleased(MouseEvent e) {
-
- }
-
- @Override
- public void mouseEntered(MouseEvent e) {
-
- }
-
- @Override
- public void mouseExited(MouseEvent e) {
-
- }
- });
-
- initializeInterpreter();
-
- mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, //
- p,
- tp.getComponent()
- );
- mainSplitPane.setDividerLocation(frame.getSize().width - 36);
- mainSplitPane.setBorder(BorderFactory.createEmptyBorder());
- mainSplitPane.setDividerSize(1);
- mainSplitPane.setResizeWeight(0.9);
- sidebarHidden = true;
-
- //frame.add(mainSplitPane, BorderLayout.CENTER);
- frame.add(mainSplitPane, BorderLayout.CENTER);
-
- SciView sciView = this;
- frame.addWindowListener(new WindowAdapter() {
- @Override public void windowClosing(WindowEvent e) {
- getLogger().debug("Closing SciView window.");
- close();
- getScijavaContext().service(SciViewService.class).close(sciView);
- isClosed = true;
- }
- });
-
- splashLabel = new SplashLabel();
- frame.setGlassPane(splashLabel);
- frame.getGlassPane().setVisible(true);
- frame.getGlassPane().requestFocusInWindow();
-// frame.getGlassPane().setBackground(new java.awt.Color(50, 48, 47, 255));
- frame.setVisible(true);
-
- sceneryPanel[0] = panel;
-
- setRenderer( Renderer.createRenderer( getHub(), getApplicationName(), getScene(),
- getWindowWidth(), getWindowHeight(),
- sceneryPanel[0]) );
-
- getHub().add( SceneryElement.Renderer, getRenderer() );
-
- reset();
-
- animations = new LinkedList<>();
- controlStack = new Stack<>();
-
- SwingUtilities.invokeLater(() -> {
- try {
- while (!getSceneryRenderer().getFirstImageReady()) {
- getLogger().debug("Waiting for renderer initialisation");
- Thread.sleep(300);
- }
-
- Thread.sleep(200);
- } catch (InterruptedException e) {
- getLogger().error("Renderer construction interrupted.");
- }
-
- nodePropertyEditor.rebuildTree();
- getLogger().info("Done initializing SciView");
-
- // subscribe to Node{Added, Removed, Changed} events happens automagically owing to the annotations
- frame.getGlassPane().setVisible(false);
- panel.setVisible(true);
-
- // install hook to keep inspector updated on external changes (scripting, etc)
- getScene().getOnNodePropertiesChanged().put("updateInspector",
- node -> {
- if( node == nodePropertyEditor.getCurrentNode() ) {
- nodePropertyEditor.updateProperties(node);
- }
- return null;
- });
-
- // Enable push rendering by default
- getRenderer().setPushMode( true );
-
- sciView.getCamera().setPosition(1.65, 1);
-
- });
- }
-
- private boolean sidebarHidden = false;
- private int previousSidebarPosition = 0;
-
- public boolean toggleSidebar() {
- if(!sidebarHidden) {
- previousSidebarPosition = mainSplitPane.getDividerLocation();
- // TODO: remove hard-coded tab width
- mainSplitPane.setDividerLocation(frame.getSize().width - 36);
- sidebarHidden = true;
- } else {
- if(previousSidebarPosition == 0) {
- previousSidebarPosition = getWindowWidth()/3 * 2;
- }
-
- mainSplitPane.setDividerLocation(previousSidebarPosition);
- sidebarHidden = false;
- }
-
- return sidebarHidden;
- }
-
- private ImageIcon getScaledImageIcon(final URL resource, int width, int height) {
- final ImageIcon first = new ImageIcon(resource);
- final Image image = first.getImage();
-
- BufferedImage resizedImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
- Graphics2D g2 = resizedImg.createGraphics();
-
- g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
- g2.drawImage(first.getImage(), 0, 0, width, height, null);
- g2.dispose();
-
- return new ImageIcon(resizedImg);
- }
-
- private void initializeInterpreter() {
- String startupCode = "";
- startupCode = new Scanner(SciView.class.getResourceAsStream("startup.py"), "UTF-8").useDelimiter("\\A").next();
- interpreterPane.getREPL().getInterpreter().getBindings().put("sciView", this);
- try {
- interpreterPane.getREPL().getInterpreter().eval(startupCode);
- } catch (ScriptException e) {
- e.printStackTrace();
- }
- }
-
- /*
- * Completely close the SciView window + cleanup
- */
- public void closeWindow() {
- frame.dispose();
- }
-
- /*
- * Return the default floor object
- */
- public Node getFloor() {
- return floor;
- }
-
- /*
- * Set the default floor object
- */
- public void setFloor( Node n ) {
- floor = n;
- }
-
- /**
- * Return the current SceneryJPanel. This is necessary for custom context menus
- * @return panel the current SceneryJPanel
- */
- public SceneryJPanel getSceneryJPanel() {
- return panel;
- }
-
- /*
- * Return true if the scene has been initialized
- */
- public boolean isInitialized() {
- return sceneInitialized();
- }
-
- /*
- * Return the current camera that is rendering the scene
- */
- public Camera getCamera() {
- return camera;
- }
-
- /*
- * Return the SciJava Display that contains SciView
- */
- public Display> getDisplay() {
- return scijavaDisplay;
- }
-
- /*
- * Set the SciJava Display
- */
- public void setDisplay( Display> display ) {
- scijavaDisplay = display;
- }
-
- /*
- * Get the InputHandler that is managing mouse, input, VR controls, etc.
- */
- public InputHandler getSceneryInputHandler() {
- return getInputHandler();
- }
-
- /*
- * Return a bounding box around a subgraph of the scenegraph
- */
- public OrientedBoundingBox getSubgraphBoundingBox( Node n ) {
- Function> predicate = node -> node.getChildren();
- return getSubgraphBoundingBox(n,predicate);
- }
-
- /*
- * Return a bounding box around a subgraph of the scenegraph
- */
- public OrientedBoundingBox getSubgraphBoundingBox( Node n, Function> branchFunction ) {
- if(n.getBoundingBox() == null && n.getChildren().size() != 0) {
- return n.getMaximumBoundingBox().asWorld();
- }
-
- List branches = branchFunction.apply(n);
- if( branches.size() == 0 ) {
- if( n.getBoundingBox() == null )
- return null;
- else
- return n.getBoundingBox().asWorld();
- }
-
- OrientedBoundingBox bb = n.getMaximumBoundingBox();
- for( Node c : branches ){
- OrientedBoundingBox cBB = getSubgraphBoundingBox(c, branchFunction);
- if( cBB != null )
- bb = bb.expand(bb, cBB);
- }
- return bb;
- }
-
- /**
- * Place the scene into the center of camera view, and zoom in/out such
- * that the whole scene is in the view (everything would be visible if it
- * would not be potentially occluded).
- */
- public void fitCameraToScene() {
- centerOnNode(getScene());
- //TODO: smooth zoom in/out VLADO vlado Vlado
- }
-
- /**
- * Place the scene into the center of camera view.
- */
- public void centerOnScene() {
- centerOnNode(getScene());
- }
-
- /**
- * Place the active node into the center of camera view.
- */
- public void centerOnActiveNode() {
- if (activeNode == null) return;
- centerOnNode(activeNode);
- }
-
- /**
- * Place the specified node into the center of camera view.
- */
- public void centerOnNode( Node currentNode ) {
- if (currentNode == null) {
- log.info("Cannot center on null node.");
- return;
- }
-
- //center the on the same spot as ArcBall does
- centerOnPosition( currentNode.getMaximumBoundingBox().getBoundingSphere().getOrigin() );
- }
-
- /**
- * Center the camera on the specified Node
- */
- public void centerOnPosition( Vector3f currentPos ) {
- //desired view direction in world coords
- final Vector3f worldDirVec = new Vector3f(currentPos).sub(camera.getPosition());
- if (worldDirVec.lengthSquared() < 0.01)
- {
- //ill defined task, happens typically when cam is inside the node which we want center on
- log.info("Camera is on the spot you want to look at. Please, move the camera away first.");
- return;
- }
-
- Vector2f camForwardXZ = new Vector2f(camera.getForward().x, camera.getForward().z);
- Vector2f wantLookAtXZ = new Vector2f(worldDirVec.x, worldDirVec.z);
- double totalYawAng = camForwardXZ.normalize().dot( wantLookAtXZ.normalize() );
- //while mathematically impossible, cumulated numerical inaccuracies have different opinion
- totalYawAng = totalYawAng > 1 ? 0 : Math.acos( totalYawAng );
-
- //switch direction?
- camForwardXZ.set(camForwardXZ.y, -camForwardXZ.x);
- if ( wantLookAtXZ.dot(camForwardXZ) > 0) totalYawAng *= -1;
-
- final Vector3f camForwardYed = new Vector3f( camera.getForward() );
- new Quaternionf().rotateXYZ(0,-(float)totalYawAng,0).normalize().transform( camForwardYed );
- double totalPitchAng = camForwardYed.normalize().dot( worldDirVec.normalize() );
- totalPitchAng = totalPitchAng > 1 ? 0 : Math.acos( totalPitchAng );
-
- //switch direction?
- if (camera.getForward().y > worldDirVec.y) totalPitchAng *= -1;
- if (camera.getUp().y < 0) totalPitchAng *= -1;
-
- //animation options: control delay between animation frames -- fluency
- final long rotPausePerStep = 30; //miliseconds
-
- //animation options: control max number of steps -- upper limit on total time for animation
- final int rotMaxSteps = 999999; //effectively disabled....
-
- //animation options: the hardcoded 5 deg (0.087 rad) -- smoothness
- //how many steps when max update/move is 5 deg
- float totalDeltaAng = (float)Math.max( Math.abs(totalPitchAng), Math.abs(totalYawAng) );
- int rotSteps = (int)Math.ceil( totalDeltaAng / 0.087 );
- if (rotSteps > rotMaxSteps) rotSteps = rotMaxSteps;
-
- /*
- log.info("centering over "+rotSteps+" steps the pitch " + 180*totalPitchAng/Math.PI
- + " and the yaw " + 180*totalYawAng/Math.PI);
- */
-
- //angular progress aux variables
- double donePitchAng = 0, doneYawAng = 0;
- float deltaAng;
-
- camera.setTargeted(false);
- for (int i = 1; i <= rotSteps; ++i) {
- //this emulates ease-in ease-out animation, both vars are in [0:1]
- float timeProgress = (float)i / rotSteps;
- final float angProgress = ((timeProgress *= 2) <= 1 ? //two cubics connected smoothly into S-shape curve from [0,0] to [1,1]
- timeProgress * timeProgress * timeProgress :
- (timeProgress -= 2) * timeProgress * timeProgress + 2) / 2;
-
- //rotate now by this ang: "where should I be by now" minus "where I got last time"
- deltaAng = (float)(angProgress * totalPitchAng - donePitchAng);
- Quaternionf pitchQ = new Quaternionf().rotateXYZ(-deltaAng, 0f, 0f).normalize();
-
- deltaAng = (float)(angProgress * totalYawAng - doneYawAng);
- Quaternionf yawQ = new Quaternionf().rotateXYZ(0f, deltaAng, 0f).normalize();
-
- camera.setRotation( pitchQ.mul(camera.getRotation()).mul(yawQ).normalize() );
- donePitchAng = angProgress * totalPitchAng;
- doneYawAng = angProgress * totalYawAng;
-
- try {
- Thread.sleep(rotPausePerStep);
- } catch (InterruptedException e) {
- i = rotSteps;
- }
- }
- }
-
- //a couple of shortcut methods to readout controls params
- public float getFPSSpeedSlow() {
- return controlsParameters.getFpsSpeedSlow();
- }
- public float getFPSSpeedFast() {
- return controlsParameters.getFpsSpeedFast();
- }
- public float getFPSSpeedVeryFast() {
- return controlsParameters.getFpsSpeedVeryFast();
- }
-
- public float getMouseSpeed() {
- return controlsParameters.getMouseSpeedMult();
- }
- public float getMouseScrollSpeed() {
- return controlsParameters.getMouseScrollMult();
- }
-
- //a couple of setters with scene sensible boundary checks
- public void setFPSSpeedSlow( float slowSpeed ) {
- controlsParameters.setFpsSpeedSlow( paramWithinBounds(slowSpeed, FPSSPEED_MINBOUND_SLOW,FPSSPEED_MAXBOUND_SLOW) );
- }
- public void setFPSSpeedFast( float fastSpeed ) {
- controlsParameters.setFpsSpeedFast( paramWithinBounds(fastSpeed, FPSSPEED_MINBOUND_FAST,FPSSPEED_MAXBOUND_FAST) );
- }
- public void setFPSSpeedVeryFast( float veryFastSpeed ) {
- controlsParameters.setFpsSpeedVeryFast( paramWithinBounds(veryFastSpeed, FPSSPEED_MINBOUND_VERYFAST,FPSSPEED_MAXBOUND_VERYFAST) );
- }
-
- public void setFPSSpeed( float newBaseSpeed ) {
- // we don't want to escape bounds checking
- // (so we call "our" methods rather than directly the controlsParameters)
- setFPSSpeedSlow( 1f * newBaseSpeed );
- setFPSSpeedFast( 20f * newBaseSpeed );
- setFPSSpeedVeryFast( 500f * newBaseSpeed );
-
- //report what's been set in the end
- log.debug( "FPS speeds: slow=" + controlsParameters.getFpsSpeedSlow()
- + ", fast=" + controlsParameters.getFpsSpeedFast()
- + ", very fast=" + controlsParameters.getFpsSpeedVeryFast() );
- }
-
- public void setMouseSpeed( float newSpeed ) {
- controlsParameters.setMouseSpeedMult( paramWithinBounds(newSpeed, MOUSESPEED_MINBOUND,MOUSESPEED_MAXBOUND) );
- log.debug( "Mouse movement speed: " + controlsParameters.getMouseSpeedMult() );
- }
- public void setMouseScrollSpeed( float newSpeed ) {
- controlsParameters.setMouseScrollMult( paramWithinBounds(newSpeed, MOUSESCROLL_MINBOUND,MOUSESCROLL_MAXBOUND) );
- log.debug( "Mouse scroll speed: " + controlsParameters.getMouseScrollMult() );
- }
-
- //bounds for the controls
- public static final float FPSSPEED_MINBOUND_SLOW = 0.01f;
- public static final float FPSSPEED_MAXBOUND_SLOW = 30.0f;
- public static final float FPSSPEED_MINBOUND_FAST = 0.2f;
- public static final float FPSSPEED_MAXBOUND_FAST = 600f;
- public static final float FPSSPEED_MINBOUND_VERYFAST = 10f;
- public static final float FPSSPEED_MAXBOUND_VERYFAST = 2000f;
-
- public static final float MOUSESPEED_MINBOUND = 0.1f;
- public static final float MOUSESPEED_MAXBOUND = 3.0f;
- public static final float MOUSESCROLL_MINBOUND = 0.3f;
- public static final float MOUSESCROLL_MAXBOUND = 10.0f;
-
- private float paramWithinBounds(float param, final float minBound, final float maxBound)
- {
- if( param < minBound ) param = minBound;
- else if( param > maxBound ) param = maxBound;
- return param;
- }
-
-
- public void setObjectSelectionMode() {
- Function3 selectAction = (nearest,x,y) -> {
- if( !nearest.getMatches().isEmpty() ) {
- // copy reference on the last object picking result into "public domain"
- // (this must happen before the ContextPopUpNodeChooser menu!)
- objectSelectionLastResult = nearest;
-
- // Setup the context menu for this picking
- // (in the menu, the user will chose node herself)
- new ContextPopUpNodeChooser(this).show(panel,x,y);
- }
- return Unit.INSTANCE;
- };
- setObjectSelectionMode(selectAction);
- }
-
- public Scene.RaycastResult objectSelectionLastResult;
-
- /*
- * Set the action used during object selection
- */
- public void setObjectSelectionMode(Function3 selectAction) {
- final InputHandler h = getInputHandler();
- List> ignoredObjects = new ArrayList<>();
- ignoredObjects.add( BoundingGrid.class );
- ignoredObjects.add( Camera.class ); //do not mess with "scene params", allow only "scene data" to be selected
- ignoredObjects.add( DetachedHeadCamera.class );
- ignoredObjects.add( DirectionalLight.class );
- ignoredObjects.add( PointLight.class );
-
- if(h == null) {
- getLogger().error("InputHandler is null, cannot change object selection mode.");
- return;
- }
- h.addBehaviour( "node: choose one from the view panel",
- new SelectCommand( "objectSelector", getRenderer(), getScene(),
- () -> getScene().findObserver(), false, ignoredObjects,
- selectAction ) );
- h.addKeyBinding( "node: choose one from the view panel", "double-click button1" );
- }
-
- /*
- * Initial configuration of the scenery InputHandler
- * This is automatically called and should not be used directly
- */
- @Override public void inputSetup() {
- final InputHandler h = getInputHandler();
- if ( h == null ) {
- getLogger().error( "InputHandler is null, cannot run input setup." );
- return;
- }
- //when we get here, the Behaviours and key bindings from scenery are already in place
-
- //possibly, disable some (unused?) controls from scenery
- /*
- h.removeBehaviour( "gamepad_camera_control");
- h.removeKeyBinding("gamepad_camera_control");
- h.removeBehaviour( "gamepad_movement_control");
- h.removeKeyBinding("gamepad_movement_control");
- */
-
- // node-selection and node-manipulation (translate & rotate) controls
- setObjectSelectionMode();
- final NodeTranslateControl nodeTranslateControl = new NodeTranslateControl(this);
- h.addBehaviour( "node: move selected one left, right, up, or down", nodeTranslateControl);
- h.addKeyBinding( "node: move selected one left, right, up, or down", "ctrl button1" );
- h.addBehaviour( "node: move selected one closer or further away", nodeTranslateControl);
- h.addKeyBinding( "node: move selected one closer or further away", "ctrl scroll" );
- h.addBehaviour( "node: rotate selected one", new NodeRotateControl(this) );
- h.addKeyBinding( "node: rotate selected one", "ctrl shift button1" );
-
- // within-scene navigation: ArcBall and FPS
- enableArcBallControl();
- enableFPSControl();
-
- // whole-scene rolling
- h.addBehaviour( "view: rotate (roll) clock-wise", new SceneRollControl(this,+0.05f) ); //2.8 deg
- h.addKeyBinding("view: rotate (roll) clock-wise", "R");
- h.addBehaviour( "view: rotate (roll) counter clock-wise", new SceneRollControl(this,-0.05f) );
- h.addKeyBinding("view: rotate (roll) counter clock-wise", "shift R");
- h.addBehaviour( "view: rotate (roll) with mouse", h.getBehaviour("view: rotate (roll) clock-wise"));
- h.addKeyBinding("view: rotate (roll) with mouse", "ctrl button3");
-
- // adjusters of various controls sensitivities
- h.addBehaviour( "moves: step size decrease", (ClickBehaviour)(x,y) -> setFPSSpeed( getFPSSpeedSlow() - 0.01f ) );
- h.addKeyBinding("moves: step size decrease", "MINUS");
- h.addBehaviour( "moves: step size increase", (ClickBehaviour)(x,y) -> setFPSSpeed( getFPSSpeedSlow() + 0.01f ) );
- h.addKeyBinding("moves: step size increase", "EQUALS" );
-
- h.addBehaviour( "mouse: move sensitivity decrease", (ClickBehaviour)(x,y) -> setMouseSpeed( getMouseSpeed() - 0.02f ) );
- h.addKeyBinding("mouse: move sensitivity decrease", "M MINUS");
- h.addBehaviour( "mouse: move sensitivity increase", (ClickBehaviour)(x,y) -> setMouseSpeed( getMouseSpeed() + 0.02f ) );
- h.addKeyBinding("mouse: move sensitivity increase", "M EQUALS" );
-
- h.addBehaviour( "mouse: scroll sensitivity decrease", (ClickBehaviour)(x,y) -> setMouseScrollSpeed( getMouseScrollSpeed() - 0.3f ) );
- h.addKeyBinding("mouse: scroll sensitivity decrease", "S MINUS");
- h.addBehaviour( "mouse: scroll sensitivity increase", (ClickBehaviour)(x,y) -> setMouseScrollSpeed( getMouseScrollSpeed() + 0.3f ) );
- h.addKeyBinding("mouse: scroll sensitivity increase", "S EQUALS" );
-
- // help window
- h.addBehaviour( "show help", new showHelpDisplay() );
- h.addKeyBinding("show help", "F1" );
- }
-
- /*
- * Change the control mode to circle around the active object in an arcball
- */
- private void enableArcBallControl() {
- final InputHandler h = getInputHandler();
- if ( h == null ) {
- getLogger().error( "InputHandler is null, cannot setup arcball control." );
- return;
- }
-
- Vector3f target;
- if( getActiveNode() == null ) {
- target = new Vector3f( 0, 0, 0 );
- } else {
- target = getActiveNode().getPosition();
- }
-
- //setup ArcballCameraControl from scenery, register it with SciView's controlsParameters
- Supplier cameraSupplier = () -> getScene().findObserver();
- targetArcball = new AnimatedCenteringBeforeArcBallControl( "view: rotate it around selected node", cameraSupplier,
- getRenderer().getWindow().getWidth(),
- getRenderer().getWindow().getHeight(), target );
- targetArcball.setMaximumDistance( Float.MAX_VALUE );
- controlsParameters.registerArcballCameraControl( targetArcball );
-
- h.addBehaviour( "view: rotate around selected node", targetArcball );
- h.addKeyBinding( "view: rotate around selected node", "shift button1" );
- h.addBehaviour( "view: zoom outward or toward selected node", targetArcball );
- h.addKeyBinding( "view: zoom outward or toward selected node", "shift scroll" );
- }
-
- /*
- * A wrapping class for the {@ArcballCameraControl} that calls {@link CenterOnPosition()}
- * before the actual Arcball camera movement takes place. This way, the targeted node is
- * first smoothly brought into the centre along which Arcball is revolving, preventing
- * from sudden changes of view (and lost of focus from the user.
- */
- class AnimatedCenteringBeforeArcBallControl extends ArcballCameraControl {
- //a bunch of necessary c'tors (originally defined in the ArcballCameraControl class)
- public AnimatedCenteringBeforeArcBallControl(@NotNull String name, @NotNull Function0 extends Camera> n, int w, int h, @NotNull Function0 extends Vector3f> target) {
- super(name, n, w, h, target);
- }
-
- public AnimatedCenteringBeforeArcBallControl(@NotNull String name, @NotNull Supplier n, int w, int h, @NotNull Supplier target) {
- super(name, n, w, h, target);
- }
-
- public AnimatedCenteringBeforeArcBallControl(@NotNull String name, @NotNull Function0 extends Camera> n, int w, int h, @NotNull Vector3f target) {
- super(name, n, w, h, target);
- }
-
- public AnimatedCenteringBeforeArcBallControl(@NotNull String name, @NotNull Supplier n, int w, int h, @NotNull Vector3f target) {
- super(name, n, w, h, target);
- }
-
- @Override
- public void init( int x, int y )
- {
- centerOnPosition( targetArcball.getTarget().invoke() );
- super.init(x,y);
- }
-
- @Override
- public void scroll(double wheelRotation, boolean isHorizontal, int x, int y)
- {
- centerOnPosition( targetArcball.getTarget().invoke() );
- super.scroll(wheelRotation,isHorizontal,x,y);
- }
- }
-
- /*
- * Enable FPS style controls
- */
- private void enableFPSControl() {
- final InputHandler h = getInputHandler();
- if ( h == null ) {
- getLogger().error( "InputHandler is null, cannot setup fps control." );
- return;
- }
-
- // Mouse look around (Lclick) and move around (Rclick)
- //
- //setup FPSCameraControl from scenery, register it with SciView's controlsParameters
- Supplier cameraSupplier = () -> getScene().findObserver();
- fpsControl = new FPSCameraControl( "view: freely look around", cameraSupplier, getRenderer().getWindow().getWidth(),
- getRenderer().getWindow().getHeight() );
- controlsParameters.registerFpsCameraControl( fpsControl );
-
- h.addBehaviour( "view: freely look around", fpsControl );
- h.addKeyBinding( "view: freely look around", "button1" );
-
- //slow and fast camera motion
- h.addBehaviour( "move_withMouse_back/forward/left/right", new CameraTranslateControl( this, 1f ) );
- h.addKeyBinding( "move_withMouse_back/forward/left/right", "button3" );
- //
- //fast and very fast camera motion
- h.addBehaviour( "move_withMouse_back/forward/left/right_fast", new CameraTranslateControl( this, 10f ) );
- h.addKeyBinding( "move_withMouse_back/forward/left/right_fast", "shift button3" );
-
- // Keyboard move around (WASD keys)
- //
- //override 'WASD' from Scenery
- MovementCommand mcW,mcA,mcS,mcD;
- mcW = new MovementCommand( "move_forward", "forward", () -> getScene().findObserver(), controlsParameters.getFpsSpeedSlow() );
- mcS = new MovementCommand( "move_backward", "back", () -> getScene().findObserver(), controlsParameters.getFpsSpeedSlow() );
- mcA = new MovementCommand( "move_left", "left", () -> getScene().findObserver(), controlsParameters.getFpsSpeedSlow() );
- mcD = new MovementCommand( "move_right", "right", () -> getScene().findObserver(), controlsParameters.getFpsSpeedSlow() );
- controlsParameters.registerSlowStepMover( mcW );
- controlsParameters.registerSlowStepMover( mcS );
- controlsParameters.registerSlowStepMover( mcA );
- controlsParameters.registerSlowStepMover( mcD );
- h.addBehaviour( "move_forward", mcW );
- h.addBehaviour( "move_back", mcS );
- h.addBehaviour( "move_left", mcA );
- h.addBehaviour( "move_right", mcD );
- // 'WASD' keys are registered already in scenery
-
- //override shift+'WASD' from Scenery
- mcW = new MovementCommand( "move_forward_fast", "forward", () -> getScene().findObserver(), controlsParameters.getFpsSpeedFast() );
- mcS = new MovementCommand( "move_backward_fast", "back", () -> getScene().findObserver(), controlsParameters.getFpsSpeedFast() );
- mcA = new MovementCommand( "move_left_fast", "left", () -> getScene().findObserver(), controlsParameters.getFpsSpeedFast() );
- mcD = new MovementCommand( "move_right_fast", "right", () -> getScene().findObserver(), controlsParameters.getFpsSpeedFast() );
- controlsParameters.registerFastStepMover( mcW );
- controlsParameters.registerFastStepMover( mcS );
- controlsParameters.registerFastStepMover( mcA );
- controlsParameters.registerFastStepMover( mcD );
- h.addBehaviour( "move_forward_fast", mcW );
- h.addBehaviour( "move_back_fast", mcS );
- h.addBehaviour( "move_left_fast", mcA );
- h.addBehaviour( "move_right_fast", mcD );
- // shift+'WASD' keys are registered already in scenery
-
- //define additionally shift+ctrl+'WASD'
- mcW = new MovementCommand( "move_forward_veryfast", "forward", () -> getScene().findObserver(), controlsParameters.getFpsSpeedVeryFast() );
- mcS = new MovementCommand( "move_back_veryfast", "back", () -> getScene().findObserver(), controlsParameters.getFpsSpeedVeryFast() );
- mcA = new MovementCommand( "move_left_veryfast", "left", () -> getScene().findObserver(), controlsParameters.getFpsSpeedVeryFast() );
- mcD = new MovementCommand( "move_right_veryfast", "right", () -> getScene().findObserver(), controlsParameters.getFpsSpeedVeryFast() );
- controlsParameters.registerVeryFastStepMover( mcW );
- controlsParameters.registerVeryFastStepMover( mcS );
- controlsParameters.registerVeryFastStepMover( mcA );
- controlsParameters.registerVeryFastStepMover( mcD );
- h.addBehaviour( "move_forward_veryfast", mcW );
- h.addBehaviour( "move_back_veryfast", mcS );
- h.addBehaviour( "move_left_veryfast", mcA );
- h.addBehaviour( "move_right_veryfast", mcD );
- h.addKeyBinding( "move_forward_veryfast", "ctrl shift W" );
- h.addKeyBinding( "move_back_veryfast", "ctrl shift S" );
- h.addKeyBinding( "move_left_veryfast", "ctrl shift A" );
- h.addKeyBinding( "move_right_veryfast", "ctrl shift D" );
-
- // Keyboard only move up/down (XC keys)
- //
- //[[ctrl]+shift]+'XC'
- mcW = new MovementCommand( "move_up", "up", () -> getScene().findObserver(), controlsParameters.getFpsSpeedSlow() );
- mcS = new MovementCommand( "move_down", "down", () -> getScene().findObserver(), controlsParameters.getFpsSpeedSlow() );
- controlsParameters.registerSlowStepMover( mcW );
- controlsParameters.registerSlowStepMover( mcS );
- h.addBehaviour( "move_up", mcW );
- h.addBehaviour( "move_down", mcS );
- h.addKeyBinding( "move_up", "C" );
- h.addKeyBinding( "move_down", "X" );
-
- mcW = new MovementCommand( "move_up_fast", "up", () -> getScene().findObserver(), controlsParameters.getFpsSpeedFast() );
- mcS = new MovementCommand( "move_down_fast", "down", () -> getScene().findObserver(), controlsParameters.getFpsSpeedFast() );
- controlsParameters.registerFastStepMover( mcW );
- controlsParameters.registerFastStepMover( mcS );
- h.addBehaviour( "move_up_fast", mcW );
- h.addBehaviour( "move_down_fast", mcS );
- h.addKeyBinding( "move_up_fast", "shift C" );
- h.addKeyBinding( "move_down_fast", "shift X" );
-
- mcW = new MovementCommand( "move_up_veryfast", "up", () -> getScene().findObserver(), controlsParameters.getFpsSpeedVeryFast() );
- mcS = new MovementCommand( "move_down_veryfast", "down", () -> getScene().findObserver(), controlsParameters.getFpsSpeedVeryFast() );
- controlsParameters.registerVeryFastStepMover( mcW );
- controlsParameters.registerVeryFastStepMover( mcS );
- h.addBehaviour( "move_up_veryfast", mcW );
- h.addBehaviour( "move_down_veryfast", mcS );
- h.addKeyBinding( "move_up_veryfast", "ctrl shift C" );
- h.addKeyBinding( "move_down_veryfast", "ctrl shift X" );
- }
-
- /**
- * Add a box to the scene with default parameters
- * @return the Node corresponding to the box
- */
- public Node addBox() {
- return addBox( new JOMLVector3( 0.0f, 0.0f, 0.0f ) );
- }
-
- /**
- * Add a box at the specific position and unit size
- * @param position position to put the box
- * @return the Node corresponding to the box
- */
- public Node addBox( Vector3 position ) {
- return addBox( position, new JOMLVector3( 1.0f, 1.0f, 1.0f ) );
- }
-
- /**
- * Add a box at the specified position and with the specified size
- * @param position position to put the box
- * @param size size of the box
- * @return the Node corresponding to the box
- */
- public Node addBox( Vector3 position, Vector3 size ) {
- return addBox( position, size, DEFAULT_COLOR, false );
- }
-
- /**
- * Add a box at the specified position with specified size, color, and normals on the inside/outside
- * @param position position to put the box
- * @param size size of the box
- * @param color color of the box
- * @param inside are normals inside the box?
- * @return the Node corresponding to the box
- */
- public Node addBox( final Vector3 position, final Vector3 size, final ColorRGB color,
- final boolean inside ) {
- // TODO: use a material from the current palate by default
- final Material boxmaterial = new Material();
- boxmaterial.setAmbient( new Vector3f( 1.0f, 0.0f, 0.0f ) );
- boxmaterial.setDiffuse( Utils.convertToVector3f( color ) );
- boxmaterial.setSpecular( new Vector3f( 1.0f, 1.0f, 1.0f ) );
-
- final Box box = new Box( JOMLVector3.convert( size ), inside );
- box.setMaterial( boxmaterial );
- box.setPosition( JOMLVector3.convert( position ) );
-
- return addNode( box );
- }
-
- /**
- * Add a unit sphere at the origin
- * @return the Node corresponding to the sphere
- */
- public Node addSphere() {
- return addSphere( new JOMLVector3( 0.0f, 0.0f, 0.0f ), 1 );
- }
-
- /**
- * Add a sphere at the specified position with a given radius
- * @param position position to put the sphere
- * @param radius radius of the sphere
- * @return the Node corresponding to the sphere
- */
- public Node addSphere( Vector3 position, float radius ) {
- return addSphere( position, radius, DEFAULT_COLOR );
- }
-
- /**
- * Add a sphere at the specified positoin with a given radius and color
- * @param position position to put the sphere
- * @param radius radius the sphere
- * @param color color of the sphere
- * @return the Node corresponding to the sphere
- */
- public Node addSphere( final Vector3 position, final float radius, final ColorRGB color ) {
- final Material material = new Material();
- material.setAmbient( new Vector3f( 1.0f, 0.0f, 0.0f ) );
- material.setDiffuse( Utils.convertToVector3f( color ) );
- material.setSpecular( new Vector3f( 1.0f, 1.0f, 1.0f ) );
-
- final Sphere sphere = new Sphere( radius, 20 );
- sphere.setMaterial( material );
- sphere.setPosition( JOMLVector3.convert( position ) );
-
- return addNode( sphere );
- }
-
- /**
- * Add a Cylinder at the given position with radius, height, and number of faces/segments
- * @param position position of the cylinder
- * @param radius radius of the cylinder
- * @param height height of the cylinder
- * @param num_segments number of segments to represent the cylinder
- * @return the Node corresponding to the cylinder
- */
- public Node addCylinder( final Vector3 position, final float radius, final float height, final int num_segments ) {
- final Cylinder cyl = new Cylinder( radius, height, num_segments );
- cyl.setPosition( JOMLVector3.convert( position ) );
- return addNode( cyl );
- }
-
- /**
- * Add a Cone at the given position with radius, height, and number of faces/segments
- * @param position position to put the cone
- * @param radius radius of the cone
- * @param height height of the cone
- * @param num_segments number of segments used to represent cone
- * @return the Node corresponding to the cone
- */
- public Node addCone( final Vector3 position, final float radius, final float height, final int num_segments ) {
- final Cone cone = new Cone( radius, height, num_segments, new Vector3f(0,0,1) );
- cone.setPosition( JOMLVector3.convert( position ) );
- return addNode( cone );
- }
-
- /**
- * Add a Line from 0,0,0 to 1,1,1
- * @return the Node corresponding to the line
- */
- public Node addLine() {
- return addLine( new JOMLVector3( 0.0f, 0.0f, 0.0f ), new JOMLVector3( 1.0f, 1.0f, 1.0f ) );
- }
-
- /**
- * Add a line from start to stop
- * @param start start position of line
- * @param stop stop position of line
- * @return the Node corresponding to the line
- */
- public Node addLine( Vector3 start, Vector3 stop ) {
- return addLine( start, stop, DEFAULT_COLOR );
- }
-
- /**
- * Add a line from start to stop with the given color
- * @param start start position of line
- * @param stop stop position of line
- * @param color color of line
- * @return the Node corresponding to the line
- */
- public Node addLine( Vector3 start, Vector3 stop, ColorRGB color ) {
- return addLine( new Vector3[] { start, stop }, color, 0.1f );
- }
-
- /**
- * Add a multi-segment line that goes through the supplied points with a single color and edge width
- * @param points points along line including first and terminal points
- * @param color color of line
- * @param edgeWidth width of line segments
- * @return the Node corresponding to the line
- */
- public Node addLine( final Vector3[] points, final ColorRGB color, final double edgeWidth ) {
- final Material material = new Material();
- material.setAmbient( new Vector3f( 1.0f, 1.0f, 1.0f ) );
- material.setDiffuse( Utils.convertToVector3f( color ) );
- material.setSpecular( new Vector3f( 1.0f, 1.0f, 1.0f ) );
-
- final Line line = new Line( points.length );
- for( final Vector3 pt : points ) {
- line.addPoint( JOMLVector3.convert( pt ) );
- }
-
- line.setEdgeWidth( ( float ) edgeWidth );
-
- line.setMaterial( material );
- line.setPosition( JOMLVector3.convert( points[0] ) );
-
- return addNode( line );
- }
-
- /**
- * Add a PointLight source at the origin
- * @return a Node corresponding to the PointLight
- */
- public Node addPointLight() {
- final Material material = new Material();
- material.setAmbient( new Vector3f( 1.0f, 0.0f, 0.0f ) );
- material.setDiffuse( new Vector3f( 0.0f, 1.0f, 0.0f ) );
- material.setSpecular( new Vector3f( 1.0f, 1.0f, 1.0f ) );
-
- final PointLight light = new PointLight( 5.0f );
- light.setMaterial( material );
- light.setPosition( new Vector3f( 0.0f, 0.0f, 0.0f ) );
- lights.add(light);
-
- return addNode( light );
- }
-
- /**
- * Position all lights that were initialized by default around the scene in a circle at Y=0
- */
- public void surroundLighting() {
- OrientedBoundingBox bb = getSubgraphBoundingBox(getScene(), notAbstractBranchingFunction);
- OrientedBoundingBox.BoundingSphere boundingSphere = bb.getBoundingSphere();
- // Choose a good y-position, then place lights around the cross-section through this plane
- float y = 0;
- Vector3f c = boundingSphere.getOrigin();
- float r = boundingSphere.getRadius();
- for( int k = 0; k < lights.size(); k++ ) {
- PointLight light = lights.get(k);
- float x = (float) (c.x() + r * Math.cos( k == 0 ? 0 : Math.PI * 2 * ((float)k / (float)lights.size()) ));
- float z = (float) (c.y() + r * Math.sin( k == 0 ? 0 : Math.PI * 2 * ((float)k / (float)lights.size()) ));
- light.setLightRadius( 2 * r );
- light.setPosition( new Vector3f( x, y, z ) );
- }
- }
-
- /**
- * Write a scenery mesh as an stl to the given file
- * @param filename filename of the stl
- * @param scMesh mesh to save
- */
- public void writeSCMesh( String filename, Mesh scMesh ) {
- File f = new File( filename );
- BufferedOutputStream out;
- try {
- out = new BufferedOutputStream( new FileOutputStream( f ) );
- out.write( "solid STL generated by FIJI\n".getBytes() );
-
- FloatBuffer normalsFB = scMesh.getNormals().duplicate();
- FloatBuffer verticesFB = scMesh.getVertices().duplicate();
-
- while( verticesFB.hasRemaining() && normalsFB.hasRemaining() ) {
- out.write( ( "facet normal " + normalsFB.get() + " " + normalsFB.get() + " " + normalsFB.get() +
- "\n" ).getBytes() );
- out.write( "outer loop\n".getBytes() );
- for( int v = 0; v < 3; v++ ) {
- out.write( ( "vertex\t" + verticesFB.get() + " " + verticesFB.get() + " " + verticesFB.get() +
- "\n" ).getBytes() );
- }
- out.write( "endloop\n".getBytes() );
- out.write( "endfacet\n".getBytes() );
- }
- out.write( "endsolid vcg\n".getBytes() );
- out.close();
- } catch( FileNotFoundException e ) {
- e.printStackTrace();
- } catch( IOException e ) {
- e.printStackTrace();
- }
-
- }
-
- /**
- * Return the default point size to use for point clouds
- * @return default point size used for point clouds
- */
- public float getDefaultPointSize() {
- return 0.025f;
- }
-
- /**
- * Create an array of normal vectors from a set of vertices corresponding to triangles
- *
- * @param verts vertices to use for computing normals, assumed to be ordered as triangles
- * @return array of normals
- */
- public float[] makeNormalsFromVertices( ArrayList verts ) {
- float[] normals = new float[verts.size()];// div3 * 3coords
-
- for( int k = 0; k < verts.size(); k += 3 ) {
- Vector3f v1 = new Vector3f( verts.get( k ).getFloatPosition( 0 ), //
- verts.get( k ).getFloatPosition( 1 ), //
- verts.get( k ).getFloatPosition( 2 ) );
- Vector3f v2 = new Vector3f( verts.get( k + 1 ).getFloatPosition( 0 ),
- verts.get( k + 1 ).getFloatPosition( 1 ),
- verts.get( k + 1 ).getFloatPosition( 2 ) );
- Vector3f v3 = new Vector3f( verts.get( k + 2 ).getFloatPosition( 0 ),
- verts.get( k + 2 ).getFloatPosition( 1 ),
- verts.get( k + 2 ).getFloatPosition( 2 ) );
- Vector3f a = v2.sub( v1 );
- Vector3f b = v3.sub( v1 );
- Vector3f n = a.cross( b ).normalize();
- normals[k / 3] = n.get( 0 );
- normals[k / 3 + 1] = n.get( 1 );
- normals[k / 3 + 2] = n.get( 2 );
- }
- return normals;
- }
-
- /**
- * Open a file specified by the source path. The file can be anything that SciView knows about: mesh, volume, point cloud
- * @param source string of a data source
- * @throws IOException
- */
- public void open( final String source ) throws IOException {
- if(source.endsWith(".xml")) {
- addNode(Volume.Companion.fromXML(source, getHub(), new VolumeViewerOptions()));
- return;
- }
-
- final Object data = io.open( source );
- if( data instanceof net.imagej.mesh.Mesh ) addMesh( ( net.imagej.mesh.Mesh ) data );
- else if( data instanceof Mesh ) addMesh( ( Mesh ) data );
- else if( data instanceof PointCloud ) addPointCloud( ( PointCloud ) data );
- else if( data instanceof Dataset ) addVolume( ( Dataset ) data );
- else if( data instanceof RandomAccessibleInterval ) addVolume( ( ( RandomAccessibleInterval ) data ), source );
- else if( data instanceof List ) {
- final List> list = ( List> ) data;
- if( list.isEmpty() ) {
- throw new IllegalArgumentException( "Data source '" + source + "' appears empty." );
- }
- final Object element = list.get( 0 );
- if( element instanceof RealLocalizable ) {
- // NB: For now, we assume all elements will be RealLocalizable.
- // Highly likely to be the case, barring antagonistic importers.
- @SuppressWarnings("unchecked") final List extends RealLocalizable> points = ( List extends RealLocalizable> ) list;
- addPointCloud( points, source );
- } else {
- final String type = element == null ? "" : element.getClass().getName();
- throw new IllegalArgumentException( "Data source '" + source + //
- "' contains elements of unknown type '" + type + "'" );
- }
- } else {
- final String type = data == null ? "" : data.getClass().getName();
- throw new IllegalArgumentException( "Data source '" + source + //
- "' contains data of unknown type '" + type + "'" );
- }
- }
-
- /**
- * Add the given points to the scene as a PointCloud
- * @param points points to use in a PointCloud
- * @return a Node corresponding to the PointCloud
- */
- public Node addPointCloud( Collection extends RealLocalizable> points ) {
- return addPointCloud( points, "PointCloud" );
- }
-
- /**
- * Add the given points to the scene as a PointCloud with a given name
- * @param points points to use in a PointCloud
- * @param name name of the PointCloud
- * @return
- */
- public Node addPointCloud( final Collection extends RealLocalizable> points,
- final String name ) {
- final float[] flatVerts = new float[points.size() * 3];
- int k = 0;
- for( final RealLocalizable point : points ) {
- flatVerts[k * 3] = point.getFloatPosition( 0 );
- flatVerts[k * 3 + 1] = point.getFloatPosition( 1 );
- flatVerts[k * 3 + 2] = point.getFloatPosition( 2 );
- k++;
- }
-
- final PointCloud pointCloud = new PointCloud( getDefaultPointSize(), name );
- final Material material = new Material();
- final FloatBuffer vBuffer = BufferUtils.allocateFloat( flatVerts.length * 4 );
- final FloatBuffer nBuffer = BufferUtils.allocateFloat( 0 );
-
- vBuffer.put( flatVerts );
- vBuffer.flip();
-
- pointCloud.setVertices( vBuffer );
- pointCloud.setNormals( nBuffer );
- pointCloud.setIndices( BufferUtils.allocateInt( 0 ) );
- pointCloud.setupPointCloud();
- material.setAmbient( new Vector3f( 1.0f, 1.0f, 1.0f ) );
- material.setDiffuse( new Vector3f( 1.0f, 1.0f, 1.0f ) );
- material.setSpecular( new Vector3f( 1.0f, 1.0f, 1.0f ) );
- pointCloud.setMaterial( material );
- pointCloud.setPosition( new Vector3f( 0f, 0f, 0f ) );
-
- return addNode( pointCloud );
- }
-
- /**
- * Add a PointCloud to the scene
- * @param pointCloud existing PointCloud to add to scene
- * @return a Node corresponding to the PointCloud
- */
- public Node addPointCloud( final PointCloud pointCloud ) {
- pointCloud.setupPointCloud();
- pointCloud.getMaterial().setAmbient( new Vector3f( 1.0f, 1.0f, 1.0f ) );
- pointCloud.getMaterial().setDiffuse( new Vector3f( 1.0f, 1.0f, 1.0f ) );
- pointCloud.getMaterial().setSpecular( new Vector3f( 1.0f, 1.0f, 1.0f ) );
- pointCloud.setPosition( new Vector3f( 0f, 0f, 0f ) );
-
- return addNode( pointCloud );
- }
-
- /**
- * Add a Node to the scene and publish it to the eventservice
- * @param n node to add to scene
- * @return a Node corresponding to the Node
- */
- public Node addNode( final Node n ) {
- return addNode(n, true);
- }
-
- /**
- * Add Node n to the scene and set it as the active node/publish it to the event service if activePublish is true
- * @param n node to add to scene
- * @param activePublish flag to specify whether the node becomes active *and* is published in the inspector/services
- * @return a Node corresponding to the Node
- */
- public Node addNode( final Node n, final boolean activePublish ) {
- getScene().addChild( n );
-
- objectService.addObject(n);
-
- if( blockOnNewNodes ) {
- blockWhile(sciView -> (sciView.find(n.getName()) == null), 20);
- //System.out.println("find(name) " + find(n.getName()) );
- }
-
- // Set new node as active and centered?
- setActiveNode(n);
- if( centerOnNewNodes ) centerOnNode(n);
- if( activePublish ) eventService.publish(new NodeAddedEvent(n));
-
- return n;
- }
-
- /**
- * Add a scenery Mesh to the scene
- * @param scMesh scenery mesh to add to scene
- * @return a Node corresponding to the mesh
- */
- public Node addMesh( final Mesh scMesh ) {
- final Material material = new Material();
- material.setAmbient( new Vector3f( 1.0f, 0.0f, 0.0f ) );
- material.setDiffuse( new Vector3f( 0.0f, 1.0f, 0.0f ) );
- material.setSpecular( new Vector3f( 1.0f, 1.0f, 1.0f ) );
-
- scMesh.setMaterial( material );
- scMesh.setPosition( new Vector3f( 0.0f, 0.0f, 0.0f ) );
-
- objectService.addObject(scMesh);
-
- return addNode( scMesh );
- }
-
- /**
- * Add an ImageJ mesh to the scene
- * @param mesh net.imagej.mesh to add to scene
- * @return a Node corresponding to the mesh
- */
- public Node addMesh( net.imagej.mesh.Mesh mesh ) {
- Mesh scMesh = MeshConverter.toScenery( mesh );
-
- return addMesh( scMesh );
- }
-
- /**
- * [Deprecated: use deleteNode]
- * Remove a Mesh from the scene
- * @param scMesh mesh to remove from scene
- */
- public void removeMesh( Mesh scMesh ) {
- getScene().removeChild( scMesh );
- }
-
- /**
- * @return a Node corresponding to the currently active node
- */
- public Node getActiveNode() {
- return activeNode;
- }
-
- /**
- * Activate the node (without centering view on it). The node becomes a target
- * of the Arcball camera movement, will become subject of the node dragging
- * (ctrl[+shift]+mouse-left-click-and-drag), will be selected in the scene graph
- * inspector (the {@link NodePropertyEditor})
- * and {@link sc.iview.event.NodeActivatedEvent} will be published.
- *
- * @param n existing node that should become active focus of this SciView
- * @return the currently active node
- */
- public Node setActiveNode( Node n ) {
- if( activeNode == n ) return activeNode;
- activeNode = n;
- targetArcball.setTarget( n == null ? () -> new Vector3f( 0, 0, 0 ) : () -> n.getMaximumBoundingBox().getBoundingSphere().getOrigin());
- nodePropertyEditor.trySelectNode( activeNode );
- eventService.publish( new NodeActivatedEvent( activeNode ) );
-
- return activeNode;
- }
-
- /**
- * Activate the node, and center the view on it.
- * @param n
- * @return the currently active node
- */
- public Node setActiveCenteredNode( Node n ) {
- //activate...
- Node ret = setActiveNode(n);
- //...and center it
- if (ret != null) centerOnNode(ret);
- return ret;
- }
-
- @EventHandler
- protected void onNodeAdded(NodeAddedEvent event) {
- nodePropertyEditor.rebuildTree();
- }
-
- @EventHandler
- protected void onNodeRemoved(NodeRemovedEvent event) {
- nodePropertyEditor.rebuildTree();
- }
-
- @EventHandler
- protected void onNodeChanged(NodeChangedEvent event) {
- nodePropertyEditor.rebuildTree();
- }
-
- @EventHandler
- protected void onNodeActivated(NodeActivatedEvent event) {
- // TODO: add listener code for node activation, if necessary
- // NOTE: do not update property window here, this will lead to a loop.
- }
-
- public void toggleInspectorWindow()
- {
- toggleSidebar();
- }
-
- public void setInspectorWindowVisibility(boolean visible)
- {
-// inspector.setVisible(visible);
-// if( visible )
-// mainSplitPane.setDividerLocation(getWindowWidth()/4 * 3);
-// else
-// mainSplitPane.setDividerLocation(getWindowWidth());
- }
-
- public void setInterpreterWindowVisibility(boolean visible)
- {
-// interpreterPane.getComponent().setVisible(visible);
-// if( visible )
-// interpreterSplitPane.setDividerLocation(getWindowHeight()/10 * 6);
-// else
-// interpreterSplitPane.setDividerLocation(getWindowHeight());
- }
-
-
- /**
- * Create an animation thread with the given fps speed and the specified action
- * @param fps frames per second at which this action should be run
- * @param action Runnable that contains code to run fps times per second
- * @return a Future corresponding to the thread
- */
- public synchronized Future> animate(int fps, Runnable action ) {
- // TODO: Make animation speed less laggy and more accurate.
- final int delay = 1000 / fps;
- Future> thread = threadService.run(() -> {
- while (animating) {
- action.run();
- try {
- Thread.sleep(delay);
- } catch (InterruptedException e) {
- break;
- }
- }
- });
- animations.add( thread );
- animating = true;
- return thread;
- }
-
- /**
- * Stop all animations
- */
- public synchronized void stopAnimation() {
- animating = false;
- while( !animations.isEmpty() ) {
- animations.peek().cancel( true );
- animations.remove();
- }
- }
-
- /**
- * Take a screenshot and save it to the default scenery location
- */
- public void takeScreenshot() {
- getRenderer().screenshot();
- }
-
- /**
- * Take a screenshot and save it to the specified path
- * @param path path for saving the screenshot
- */
- public void takeScreenshot( String path ) {
- getRenderer().screenshot( path, false );
- }
-
- /**
- * Take a screenshot and return it as an Img
- * @return an Img of type UnsignedByteType
- */
- public Img getScreenshot() {
- RenderedImage screenshot = getSceneryRenderer().requestScreenshot();
-
- BufferedImage image = new BufferedImage(screenshot.getWidth(), screenshot.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
- byte[] imgData = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
- System.arraycopy(screenshot.getData(), 0, imgData, 0, screenshot.getData().length);
-
- Img img = null;
- File tmpFile = null;
- try {
- tmpFile = File.createTempFile("sciview-", "-tmp.png");
- ImageIO.write(image, "png", tmpFile);
- img = (Img)io.open(tmpFile.getAbsolutePath());
- tmpFile.delete();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return img;
- }
-
- /**
- * Take a screenshot and return it as an Img
- * @return an Img of type UnsignedByteType
- */
- public Img getARGBScreenshot() {
- Img screenshot = getScreenshot();
-
- return Utils.convertToARGB(screenshot);
- }
-
- /**
- * @param name The name of the node to find.
- * @return the node object or null, if the node has not been found.
- */
- public Node find(final String name) {
- final Node n = getScene().find(name);
-
- if(n == null) {
- getLogger().warn("Node with name " + name + " not found.");
- }
-
- return n;
- }
-
- /**
- * @return an array of all nodes in the scene except Cameras and PointLights
- */
- public Node[] getSceneNodes() {
- return getSceneNodes( n -> !( n instanceof Camera ) && !( n instanceof PointLight ) );
- }
-
- /**
- * Get a list of nodes filtered by filter predicate
- * @param filter, a predicate that filters the candidate nodes
- * @return all nodes that match the predicate
- */
- public Node[] getSceneNodes( Predicate super Node> filter ) {
- return getScene().getChildren().stream().filter( filter ).toArray( Node[]::new );
- }
-
- /**
- * @return an array of all Node's in the scene
- */
- public Node[] getAllSceneNodes() {
- return getSceneNodes( n -> true );
- }
-
- /**
- * Delete the current active node
- */
- public void deleteActiveNode() {
- deleteNode( getActiveNode() );
- }
-
- /**
- * Delete the specified node, this event is published
- * @param node node to delete from scene
- */
- public void deleteNode( Node node ) {
- deleteNode( node, true );
- }
-
- /**
- * Delete a specified node and control whether the event is published
- * @param node node to delete from scene
- * @param activePublish whether the deletion should be published
- */
- public void deleteNode( Node node, boolean activePublish ) {
- for( Node child : node.getChildren() ) {
- deleteNode(child, activePublish);
- }
-
- objectService.removeObject(node);
- node.getParent().removeChild( node );
- if (activeNode == node) setActiveNode(null); //maintain consistency
- if( activePublish ) eventService.publish(new NodeRemovedEvent(node));
- }
-
- /**
- * Dispose the current scenery renderer, hub, and other scenery things
- */
- public void dispose() {
- List objs = objectService.getObjects(Node.class);
- for( Node obj : objs ) {
- objectService.removeObject(obj);
- }
- getScijavaContext().service(SciViewService.class).close(this);
- this.close();
- }
-
-
- public void close() {
- super.close();
-
- frame.dispose();
- }
-
- /**
- * Move the current active camera to the specified position
- * @param position position to move the camera to
- */
- public void moveCamera( float[] position ) {
- getCamera().setPosition( new Vector3f( position[0], position[1], position[2] ) );
- }
-
- /**
- * Move the current active camera to the specified position
- * @param position position to move the camera to
- */
- public void moveCamera( double[] position ) {
- getCamera().setPosition( new Vector3f( ( float ) position[0], ( float ) position[1], ( float ) position[2] ) );
- }
-
- /**
- * Get the current application name
- * @return a String of the application name
- */
- public String getName() {
- return getApplicationName();
- }
-
- /**
- * Add a child to the scene. you probably want addNode
- * @param node node to add as a child to the scene
- */
- public void addChild( Node node ) {
- getScene().addChild( node );
- }
-
- /**
- * Add a Dataset to the scene as a volume. Voxel resolution and name are extracted from the Dataset itself
- * @param image image to add as a volume
- * @return a Node corresponding to the Volume
- */
- public Node addVolume( Dataset image ) {
-
- float[] voxelDims = new float[image.numDimensions()];
- for( int d = 0; d < voxelDims.length; d++ ) {
- double inValue = image.axis(d).averageScale(0, 1);
- if( image.axis(d).unit() == null )
- voxelDims[d] = (float) inValue;
- else
- voxelDims[d] = (float) unitService.value( inValue, image.axis(d).unit(), axis(d).unit() );
- }
-
- return addVolume( image, voxelDims );
- }
-
- /**
- * Add a Dataset as a Volume with the specified voxel dimensions
- * @param image image to add as a volume
- * @param voxelDimensions dimensions of voxels in volume
- * @return a Node corresponding to the Volume
- */
- @SuppressWarnings({ "rawtypes", "unchecked" }) public Node addVolume( Dataset image, float[] voxelDimensions ) {
- return addVolume( ( RandomAccessibleInterval ) image.getImgPlus(), image.getName(),
- voxelDimensions );
- }
-
- /**
- * Add a RandomAccessibleInterval to the image
- * @param image image to add as a volume
- * @param name name of image
- * @param extra, kludge argument to prevent matching issues
- * @param pixel type of image
- * @return a Node corresponding to the volume
- */
- public > Node addVolume( RandomAccessibleInterval image, String name, String extra ) {
- return addVolume( image, name, 1, 1, 1 );
- }
-
- /**
- * Add a RandomAccessibleInterval to the image
- * @param image image to add as a volume
- * @param pixel type of image
- * @return a Node corresponding to the volume
- */
- public > Node addVolume(RandomAccessibleInterval image, String name) {
- return addVolume(image, name, 1f, 1f, 1f);
- }
-
- /**
- * Add a RandomAccessibleInterval to the image
- * @param image image to add as a volume
- * @param pixel type of image
- * @return a Node corresponding to the volume
- */
- public > Node addVolume( RandomAccessibleInterval image, float[] voxelDimensions ) {
- long[] pos = new long[]{10, 10, 10};
-
- return addVolume( image, "volume", voxelDimensions );
- }
-
- /**
- * Add an IterableInterval as a Volume
- * @param image
- * @param
- * @return a Node corresponding to the Volume
- */
- public > Node addVolume( IterableInterval image ) throws Exception {
- if( image instanceof RandomAccessibleInterval ) {
- return addVolume((RandomAccessibleInterval) image, "Volume");
- } else {
- throw new Exception("Unsupported Volume type:" + image);
- }
- }
-
- /**
- * Add an IterableInterval as a Volume
- * @param image image to add as a volume
- * @param name name of image
- * @param pixel type of image
- * @return a Node corresponding to the Volume
- */
- public > Node addVolume( IterableInterval image, String name ) throws Exception {
- if( image instanceof RandomAccessibleInterval ) {
- return addVolume( (RandomAccessibleInterval) image, name, 1, 1, 1 );
- } else {
- throw new Exception("Unsupported Volume type:" + image);
- }
- }
-
- /**
- * Set the colormap using an ImageJ LUT name
- * @param n node to apply colormap to
- * @param lutName name of LUT according to imagej LUTService
- */
- public void setColormap( Node n, String lutName ) {
- try {
- setColormap( n, lutService.loadLUT( lutService.findLUTs().get( lutName ) ) );
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- /**
- * Set the ColorMap of node n to the supplied colorTable
- * @param n node to apply colortable to
- * @param colorTable ColorTable to use
- */
- public void setColormap( Node n, ColorTable colorTable ) {
- final int copies = 16;
-
- final ByteBuffer byteBuffer = ByteBuffer.allocateDirect(
- 4 * colorTable.getLength() * copies );// Num bytes * num components * color map length * height of color map texture
-
- final byte[] tmp = new byte[4 * colorTable.getLength()];
- for( int k = 0; k < colorTable.getLength(); k++ ) {
- for( int c = 0; c < colorTable.getComponentCount(); c++ ) {
- // TODO this assumes numBits is 8, could be 16
- tmp[4 * k + c] = ( byte ) colorTable.get( c, k );
- }
-
- if( colorTable.getComponentCount() == 3 ) {
- tmp[4 * k + 3] = (byte)255;
- }
- }
-
- for( int i = 0; i < copies; i++ ) {
- byteBuffer.put(tmp);
- }
-
- byteBuffer.flip();
-
- n.getMetadata().put("sciviewColormap", colorTable);
-
- if(n instanceof Volume) {
- ((Volume) n).setColormap(Colormap.fromColorTable(colorTable));
- n.setDirty(true);
- n.setNeedsUpdate(true);
- }
- }
-
- /**
- * Adss a SourceAndConverter to the scene.
- *
- * @param sac The SourceAndConverter to add
- * @param name Name of the dataset
- * @param voxelDimensions Array with voxel dimensions.
- * @param Type of the dataset.
- * @return THe node corresponding to the volume just added.
- */
- public > Node addVolume(SourceAndConverter sac,
- int numTimepoints,
- String name,
- float... voxelDimensions ) {
- List> sources = new ArrayList<>();
- sources.add(sac);
-
- return addVolume(sources, numTimepoints, name, voxelDimensions);
- }
-
- /**
- * Add an IterableInterval to the image with the specified voxelDimensions and name
- * This version of addVolume does most of the work
- * @param image image to add as a volume
- * @param name name of image
- * @param voxelDimensions dimensions of voxel in volume
- * @param pixel type of image
- * @return a Node corresponding to the Volume
- */
- public > Node addVolume( RandomAccessibleInterval image, String name,
- float... voxelDimensions ) {
- //log.debug( "Add Volume " + name + " image: " + image );
-
- long[] dimensions = new long[image.numDimensions()];
- image.dimensions( dimensions );
-
- long[] minPt = new long[image.numDimensions()];
-
- // Get type at min point
- RandomAccess imageRA = image.randomAccess();
- image.min(minPt);
- imageRA.setPosition(minPt);
- T voxelType = imageRA.get().createVariable();
-
- ArrayList converterSetups = new ArrayList();
- ArrayList> stacks = AxisOrder.splitInputStackIntoSourceStacks(image, AxisOrder.getAxisOrder(AxisOrder.DEFAULT, image, false));
- AffineTransform3D sourceTransform = new AffineTransform3D();
- ArrayList> sources = new ArrayList();
-
- int numTimepoints = 1;
- for (RandomAccessibleInterval stack : stacks) {
- Source s;
- if (stack.numDimensions() > 3) {
- numTimepoints = (int) (stack.max(3) + 1);
- s = new RandomAccessibleIntervalSource4D(stack, voxelType, sourceTransform, name);
- } else {
- s = new RandomAccessibleIntervalSource(stack, voxelType, sourceTransform, name);
- }
- SourceAndConverter source = BigDataViewer.wrapWithTransformedSource(
- new SourceAndConverter(s, BigDataViewer.createConverterToARGB(voxelType)));
- converterSetups.add(BigDataViewer.createConverterSetup(source, Volume.Companion.getSetupId().getAndIncrement()));
- sources.add(source);
- }
-
- Node v = addVolume(sources, numTimepoints, name, voxelDimensions);
-
- v.getMetadata().put("RandomAccessibleInterval", image);
-
- return v;
- }
-
- /**
- * Adds a SourceAndConverter to the scene.
- *
- * This method actually instantiates the volume.
- *
- * @param sources The list of SourceAndConverter to add
- * @param name Name of the dataset
- * @param voxelDimensions Array with voxel dimensions.
- * @param Type of the dataset.
- * @return THe node corresponding to the volume just added.
- */
- public > Node addVolume(List> sources,
- ArrayList converterSetups,
- int numTimepoints,
- String name,
- float... voxelDimensions ) {
-
- CacheControl cacheControl = null;
-
-// RandomAccessibleInterval image =
-// ((RandomAccessibleIntervalSource4D) sources.get(0).getSpimSource()).
-// .getSource(0, 0);
- RandomAccessibleInterval image = sources.get(0).getSpimSource().getSource(0, 0);
-
- if (image instanceof VolatileView) {
- VolatileViewData> viewData = ((VolatileView>) image).getVolatileViewData();
- cacheControl = viewData.getCacheControl();
- }
-
- long[] dimensions = new long[image.numDimensions()];
- image.dimensions( dimensions );
-
- long[] minPt = new long[image.numDimensions()];
-
- // Get type at min point
- RandomAccess imageRA = image.randomAccess();
- image.min(minPt);
- imageRA.setPosition(minPt);
- T voxelType = imageRA.get().createVariable();
-
- System.out.println("addVolume " + image.numDimensions() + " interval " + ((Interval) image) );
-
- //int numTimepoints = 1;
- if( image.numDimensions() > 3 ) {
- numTimepoints = (int) image.dimension(3);
- }
-
- Volume.VolumeDataSource.RAISource ds = new Volume.VolumeDataSource.RAISource(voxelType, sources, converterSetups, numTimepoints, cacheControl);
- VolumeViewerOptions options = new VolumeViewerOptions();
-
- Volume v = new RAIVolume(ds, options, getHub());
- v.setName(name);
-
- v.getMetadata().put("sources", sources);
-
- TransferFunction tf = v.getTransferFunction();
- float rampMin = 0f;
- float rampMax = 0.1f;
- tf.clear();
- tf.addControlPoint(0.0f, 0.0f);
- tf.addControlPoint(rampMin, 0.0f);
- tf.addControlPoint(1.0f, rampMax);
-
- BoundingGrid bg = new BoundingGrid();
- bg.setNode(v);
-
- return addNode(v);
- }
-
- /**
- * Block while predicate is true
- *
- * @param predicate predicate function that returns true as long as this function should block
- * @param waitTime wait time before predicate re-evaluation
- */
- private void blockWhile(Function predicate, int waitTime) {
- while( predicate.apply(this) ) {
- try {
- Thread.sleep(waitTime);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
-
- /**
- * Adds a SourceAndConverter to the scene.
- *
- * @param sources The list of SourceAndConverter to add
- * @param name Name of the dataset
- * @param voxelDimensions Array with voxel dimensions.
- * @param Type of the dataset.
- * @return THe node corresponding to the volume just added.
- */
- public > Node addVolume(List> sources,
- int numTimepoints,
- String name,
- float... voxelDimensions ) {
- int setupId = 0;
- ArrayList converterSetups = new ArrayList<>();
- for( SourceAndConverter source: sources ) {
- converterSetups.add(BigDataViewer.createConverterSetup(source, setupId++));
- }
-
- return addVolume(sources, converterSetups, numTimepoints, name, voxelDimensions);
- }
-
- /**
- * Update a volume with the given IterableInterval.
- * This method actually populates the volume
- * @param image image to update into volume
- * @param name name of image
- * @param voxelDimensions dimensions of voxel in volume
- * @param v existing volume to update
- * @param pixel type of image
- * @return a Node corresponding to the input volume
- */
- public > Node updateVolume( IterableInterval image, String name,
- float[] voxelDimensions, Volume v ) {
- List> sacs = (List>) v.getMetadata().get("sources");
-
- RandomAccessibleInterval source = sacs.get(0).getSpimSource().getSource(0, 0);// hard coded to timepoint and mipmap 0
-
- Cursor sCur = Views.iterable(source).cursor();
- Cursor iCur = image.cursor();
- while( sCur.hasNext() ) {
- sCur.fwd();
- iCur.fwd();
- sCur.get().set(iCur.get());
- }
-
- v.getVolumeManager().notifyUpdate(v);
- v.getVolumeManager().requestRepaint();
- //v.getCacheControls().clear();
- //v.setDirty( true );
- v.setNeedsUpdate( true );
- //v.setNeedsUpdateWorld( true );
-
- return v;
- }
-
- /**
- *
- * @return whether PushMode is currently active
- */
- public boolean getPushMode() {
- return getRenderer().getPushMode();
- }
-
- /**
- * Set the status of PushMode, which only updates the render panel when there is a change in the scene
- * @param push true if push mode should be used
- * @return current PushMode status
- */
- public boolean setPushMode( boolean push ) {
- getRenderer().setPushMode( push );
- return getRenderer().getPushMode();
- }
-
- public ArcballCameraControl getTargetArcball() {
- return targetArcball;
- }
-
- @Override
- protected void finalize() {
- stopAnimation();
- }
-
- public Settings getScenerySettings() {
- return this.getSettings();
- }
-
- public Statistics getSceneryStatistics() {
- return this.getStats();
- }
-
- public Renderer getSceneryRenderer() {
- return this.getRenderer();
- }
-
- /**
- * Enable VR rendering
- */
- public void toggleVRRendering() {
- vrActive = !vrActive;
- Camera cam = getScene().getActiveObserver();
- if(!(cam instanceof DetachedHeadCamera)) {
- return;
- }
-
- TrackerInput ti = null;
- boolean hmdAdded = false;
-
- if (!getHub().has(SceneryElement.HMDInput)) {
- try {
- final OpenVRHMD hmd = new OpenVRHMD(false, true);
-
- if(hmd.initializedAndWorking()) {
- getHub().add(SceneryElement.HMDInput, hmd);
- ti = hmd;
- } else {
- getLogger().warn("Could not initialise VR headset, just activating stereo rendering.");
- }
-
- hmdAdded = true;
- } catch (Exception e) {
- getLogger().error("Could not add OpenVRHMD: " + e.toString());
- }
- } else {
- ti = getHub().getWorkingHMD();
- }
-
- if(vrActive && ti != null) {
- ((DetachedHeadCamera) cam).setTracker(ti);
- } else {
- ((DetachedHeadCamera) cam).setTracker(null);
- }
-
- getRenderer().setPushMode(false);
- // we need to force reloading the renderer as the HMD might require device or instance extensions
- if(getRenderer() instanceof VulkanRenderer && hmdAdded) {
- replaceRenderer(getRenderer().getClass().getSimpleName(), true, true);
- getRenderer().toggleVR();
-
- while(!getRenderer().getInitialized()/* || !getRenderer().getFirstImageReady()*/) {
- getLogger().debug("Waiting for renderer reinitialisation");
- try {
- Thread.sleep(200);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- } else {
- getRenderer().toggleVR();
- }
-
- }
-
- /**
- * Utility function to generate GLVector in cases like usage from Python
- * @param x x coord
- * @param y y coord
- * @param z z coord
- * @return a GLVector of x,y,z
- */
- static public GLVector getGLVector(float x, float y, float z) {
- return new GLVector(x, y, z);
- }
-
- /**
- * Set the rotation of Node N by generating a quaternion from the supplied arguments
- * @param n node to set rotation for
- * @param x x coord of rotation quat
- * @param y y coord of rotation quat
- * @param z z coord of rotation quat
- * @param w w coord of rotation quat
- */
- public void setRotation(Node n, float x, float y, float z, float w) {
- n.setRotation(new Quaternionf(x,y,z,w));
- }
-
- public void setScale(Node n, float x, float y, float z) {
- n.setScale(new Vector3f(x,y,z));
- }
-
- public void setColor(Node n, float x, float y, float z, float w) {
- Vector3f col = new Vector3f(x, y, z);
- n.getMaterial().setAmbient(col);
- n.getMaterial().setDiffuse(col);
- n.getMaterial().setSpecular(col);
- }
-
- public void setPosition(Node n, float x, float y, float z) {
- n.setPosition(new Vector3f(x,y,z));
- }
-
- public void addWindowListener(WindowListener wl) {
- frame.addWindowListener(wl);
- }
-
- @Override
- public CalibratedAxis axis(int i) {
- return axes[i];
- }
-
- @Override
- public void axes(CalibratedAxis[] calibratedAxes) {
- axes = calibratedAxes;
- }
-
- @Override
- public void setAxis(CalibratedAxis calibratedAxis, int i) {
- axes[i] = calibratedAxis;
- }
-
- @Override
- public double realMin(int i) {
- return Double.NEGATIVE_INFINITY;
- }
-
- @Override
- public void realMin(double[] doubles) {
- for( int i = 0; i < doubles.length; i++ ) {
- doubles[i] = Double.NEGATIVE_INFINITY;
- }
- }
-
- @Override
- public void realMin(RealPositionable realPositionable) {
- for( int i = 0; i < realPositionable.numDimensions(); i++ ) {
- realPositionable.move(Double.NEGATIVE_INFINITY, i);
- }
- }
-
- @Override
- public double realMax(int i) {
- return Double.POSITIVE_INFINITY;
- }
-
- @Override
- public void realMax(double[] doubles) {
- for( int i = 0; i < doubles.length; i++ ) {
- doubles[i] = Double.POSITIVE_INFINITY;
- }
- }
-
- @Override
- public void realMax(RealPositionable realPositionable) {
- for( int i = 0; i < realPositionable.numDimensions(); i++ ) {
- realPositionable.move(Double.POSITIVE_INFINITY, i);
- }
- }
-
- @Override
- public int numDimensions() {
- return axes.length;
- }
-
- public void setCamera(Camera camera) {
- this.camera = camera;
- setActiveObserver(camera);
- }
-
- public void setActiveObserver(Camera screenshotCam) {
- getScene().setActiveObserver(screenshotCam);
- }
-
- public Camera getActiveObserver() {
- return getScene().getActiveObserver();
- }
-
- public void setCenterOnNewNodes(boolean centerOnNewNodes) {
- this.centerOnNewNodes = centerOnNewNodes;
- }
-
- public boolean getCenterOnNewNodes() {
- return centerOnNewNodes;
- }
-
- public void setBlockOnNewNodes(boolean blockOnNewNodes) {
- this.blockOnNewNodes = blockOnNewNodes;
- }
-
- public boolean getBlockOnNewNodes() {
- return blockOnNewNodes;
- }
-
- public class TransparentSlider extends JSlider {
-
- public TransparentSlider() {
- // Important, we taking over the filling of the
- // component...
- setOpaque(false);
- setBackground(Color.DARK_GRAY);
- setForeground(Color.LIGHT_GRAY);
- }
-
- @Override
- protected void paintComponent(Graphics g) {
- Graphics2D g2d = (Graphics2D) g.create();
- g2d.setColor(getBackground());
- g2d.setComposite(AlphaComposite.SrcOver.derive(0.9f));
- g2d.fillRect(0, 0, getWidth(), getHeight());
- g2d.dispose();
-
- super.paintComponent(g);
- }
-
- }
-
- class showHelpDisplay implements ClickBehaviour {
-
- @Override public void click( int x, int y ) {
- // show nice dialog box with the help
- getScijavaContext().getService(CommandService.class).run(Help.class,true);
- }
- }
-
- /**
- * Return a list of all nodes that match a given predicate function
- * @param nodeMatchPredicate, returns true if a node is a match
- * @return list of nodes that match the predicate
- */
- public List findNodes(Function1 nodeMatchPredicate) {
- return getScene().discover(getScene(), nodeMatchPredicate, false);
- }
-
- /*
- * Convenience function for getting a string of info about a Node
- */
- public String nodeInfoString(Node n) {
- return "Node name: " + n.getName() + " Node type: " + n.getNodeType() + " To String: " + n;
- }
-
- /**
- * Static launching method
- *
- * @return a newly created SciView
- */
- public static SciView create() throws Exception {
- SceneryBase.xinitThreads();
-
- FlatLightLaf.install();
- try {
- UIManager.setLookAndFeel( new FlatLightLaf() );
- } catch( Exception ex ) {
- System.err.println( "Failed to initialize Flat Light LaF, falling back to Swing default." );
- }
-
- System.setProperty( "scijava.log.level:sc.iview", "debug" );
- Context context = new Context( ImageJService.class, SciJavaService.class, SCIFIOService.class, ThreadService.class);
-
- SciViewService sciViewService = context.service( SciViewService.class );
- SciView sciView = sciViewService.getOrCreateActiveSciView();
-
- return sciView;
- }
-
- /**
- * Static launching method
- * [DEPRECATED] use SciView.create() instead
- *
- * @return a newly created SciView
- */
- @Deprecated
- public static SciView createSciView() throws Exception {
- return create();
- }
-
-}
diff --git a/src/main/java/sc/iview/SciView.kt b/src/main/java/sc/iview/SciView.kt
new file mode 100644
index 00000000..dbdc1a3b
--- /dev/null
+++ b/src/main/java/sc/iview/SciView.kt
@@ -0,0 +1,2457 @@
+/*-
+ * #%L
+ * Scenery-backed 3D visualization package for ImageJ.
+ * %%
+ * Copyright (C) 2016 - 2020 SciView developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package sc.iview
+
+import bdv.BigDataViewer
+import bdv.cache.CacheControl
+import bdv.tools.brightness.ConverterSetup
+import bdv.util.AxisOrder
+import bdv.util.RandomAccessibleIntervalSource
+import bdv.util.RandomAccessibleIntervalSource4D
+import bdv.util.volatiles.VolatileView
+import bdv.viewer.Source
+import bdv.viewer.SourceAndConverter
+import cleargl.GLVector
+import com.formdev.flatlaf.FlatLightLaf
+import com.intellij.ui.tabs.JBTabsPosition
+import com.intellij.ui.tabs.TabInfo
+import com.intellij.ui.tabs.impl.JBEditorTabs
+import graphics.scenery.*
+import graphics.scenery.Box
+import graphics.scenery.Scene.RaycastResult
+import graphics.scenery.backends.Renderer
+import graphics.scenery.backends.opengl.OpenGLRenderer
+import graphics.scenery.backends.vulkan.VulkanRenderer
+import graphics.scenery.controls.InputHandler
+import graphics.scenery.controls.OpenVRHMD
+import graphics.scenery.controls.TrackerInput
+import graphics.scenery.controls.behaviours.ArcballCameraControl
+import graphics.scenery.controls.behaviours.FPSCameraControl
+import graphics.scenery.controls.behaviours.MovementCommand
+import graphics.scenery.controls.behaviours.SelectCommand
+import graphics.scenery.utils.*
+import graphics.scenery.utils.ExtractsNatives.Companion.getPlatform
+import graphics.scenery.volumes.Colormap
+import graphics.scenery.volumes.RAIVolume
+import graphics.scenery.volumes.Volume
+import graphics.scenery.volumes.Volume.Companion.fromXML
+import graphics.scenery.volumes.Volume.Companion.setupId
+import graphics.scenery.volumes.Volume.VolumeDataSource.RAISource
+import io.scif.SCIFIOService
+import net.imagej.Dataset
+import net.imagej.ImageJService
+import net.imagej.axis.CalibratedAxis
+import net.imagej.axis.DefaultAxisType
+import net.imagej.axis.DefaultLinearAxis
+import net.imagej.interval.CalibratedRealInterval
+import net.imagej.lut.LUTService
+import net.imagej.mesh.Mesh
+import net.imagej.units.UnitService
+import net.imglib2.*
+import net.imglib2.display.ColorTable
+import net.imglib2.img.Img
+import net.imglib2.realtransform.AffineTransform3D
+import net.imglib2.type.numeric.ARGBType
+import net.imglib2.type.numeric.NumericType
+import net.imglib2.type.numeric.RealType
+import net.imglib2.type.numeric.integer.UnsignedByteType
+import net.imglib2.view.Views
+import org.joml.Quaternionf
+import org.joml.Vector2f
+import org.joml.Vector3f
+import org.lwjgl.system.Platform
+import org.scijava.Context
+import org.scijava.`object`.ObjectService
+import org.scijava.command.CommandService
+import org.scijava.display.Display
+import org.scijava.event.EventHandler
+import org.scijava.event.EventService
+import org.scijava.io.IOService
+import org.scijava.log.LogLevel
+import org.scijava.log.LogService
+import org.scijava.menu.MenuService
+import org.scijava.plugin.Parameter
+import org.scijava.service.SciJavaService
+import org.scijava.thread.ThreadService
+import org.scijava.ui.behaviour.Behaviour
+import org.scijava.ui.behaviour.ClickBehaviour
+import org.scijava.ui.swing.menu.SwingJMenuBarCreator
+import org.scijava.util.ColorRGB
+import org.scijava.util.Colors
+import org.scijava.util.VersionUtils
+import sc.iview.commands.help.Help
+import sc.iview.commands.view.NodePropertyEditor
+import sc.iview.controls.behaviours.*
+import sc.iview.event.NodeActivatedEvent
+import sc.iview.event.NodeAddedEvent
+import sc.iview.event.NodeChangedEvent
+import sc.iview.event.NodeRemovedEvent
+import sc.iview.process.MeshConverter
+import sc.iview.ui.ContextPopUpNodeChooser
+import sc.iview.ui.ProgressPie
+import sc.iview.ui.REPLPane
+import sc.iview.ui.TaskManager
+import tpietzsch.example2.VolumeViewerOptions
+import java.awt.*
+import java.awt.event.*
+import java.awt.image.BufferedImage
+import java.awt.image.DataBufferByte
+import java.io.*
+import java.net.URL
+import java.nio.ByteBuffer
+import java.nio.FloatBuffer
+import java.util.*
+import java.util.concurrent.Future
+import java.util.function.Consumer
+import java.util.function.Function
+import java.util.function.Predicate
+import java.util.function.Supplier
+import java.util.stream.Collectors
+import javax.imageio.ImageIO
+import javax.script.ScriptException
+import javax.swing.*
+import kotlin.math.acos
+import kotlin.math.cos
+import kotlin.math.sin
+
+/**
+ * Main SciView class.
+ *
+ * @author Kyle Harrington
+ */
+// we suppress unused warnings here because @Parameter-annotated fields
+// get updated automatically by SciJava.
+class SciView : SceneryBase, CalibratedRealInterval {
+ private val sceneryPanel = arrayOf(null)
+
+ /**
+ * Mouse controls for FPS movement and Arcball rotation
+ */
+ lateinit var targetArcball: SciView.AnimatedCenteringBeforeArcBallControl
+ protected var fpsControl: FPSCameraControl? = null
+ /*
+ * Return the default floor object
+ *//*
+ * Set the default floor object
+ */
+ /**
+ * The floor that orients the user in the scene
+ */
+ var floor: Node? = null
+ protected var vrActive = false
+
+ /**
+ * The primary camera/observer in the scene
+ */
+ var camera: Camera? = null
+ set(value) {
+ field = value
+ setActiveObserver(field)
+ }
+
+ /**
+ * Geometry/Image information of scene
+ */
+ private lateinit var axes: Array
+
+ @Parameter
+ private val log: LogService? = null
+
+ @Parameter
+ private val menus: MenuService? = null
+
+ @Parameter
+ private val io: IOService? = null
+
+ @Parameter
+ private val eventService: EventService? = null
+
+ @Parameter
+ private val lutService: LUTService? = null
+
+ @Parameter
+ private val threadService: ThreadService? = null
+
+ @Parameter
+ private val objectService: ObjectService? = null
+
+ @Parameter
+ private val unitService: UnitService? = null
+
+ /**
+ * Queue keeps track of the currently running animations
+ */
+ private var animations: Queue>? = null
+
+ /**
+ * Animation pause tracking
+ */
+ private var animating = false
+
+ /**
+ * This tracks the actively selected Node in the scene
+ */
+ var activeNode: Node? = null
+ private set
+
+ /**
+ * Speeds for input controls
+ */
+ var controlsParameters: ControlsParameters = ControlsParameters()
+ /*
+ * Return the SciJava Display that contains SciView
+ *//*
+ * Set the SciJava Display
+ */ var display: Display<*>? = null
+ private var splashLabel: SplashLabel? = null
+
+ /**
+ * Return the current SceneryJPanel. This is necessary for custom context menus
+ * @return panel the current SceneryJPanel
+ */
+ var sceneryJPanel: SceneryJPanel? = null
+ private set
+ private var mainSplitPane: JSplitPane? = null
+ private var inspector: JSplitPane? = null
+ private var interpreterPane: REPLPane? = null
+ private var nodePropertyEditor: NodePropertyEditor? = null
+ var lights: ArrayList? = null
+ private set
+ private var controlStack: Stack>? = null
+ private var frame: JFrame? = null
+ private val notAbstractNode: Predicate = Predicate { node: Node -> !(node is Camera || node is Light || node === floor) }
+ var isClosed = false
+ private set
+ private val notAbstractBranchingFunction = Function { node: Node -> node.children.stream().filter(notAbstractNode).collect(Collectors.toList()) }
+
+ val taskManager = TaskManager()
+
+ // If true, then when a new node is added to the scene, the camera will refocus on this node by default
+ var centerOnNewNodes = false
+
+ // If true, then when a new node is added the thread will block until the node is added to the scene. This is required for
+ // centerOnNewNodes
+ var blockOnNewNodes = false
+ private var headlight: PointLight? = null
+
+ constructor(context: Context) : super("SciView", 1280, 720, false, context) {
+ context.inject(this)
+ }
+
+ constructor(applicationName: String?, windowWidth: Int, windowHeight: Int) : super(applicationName!!, windowWidth, windowHeight, false) {}
+
+ fun publicGetInputHandler(): InputHandler {
+ return inputHandler!!
+ }
+
+ /**
+ * Toggle video recording with scenery's video recording mechanism
+ * Note: this video recording may skip frames because it is asynchronous
+ */
+ fun toggleRecordVideo() {
+ if (renderer is OpenGLRenderer) (renderer as OpenGLRenderer).recordMovie() else (renderer as VulkanRenderer).recordMovie()
+ }
+
+ /**
+ * Toggle video recording with scenery's video recording mechanism
+ * Note: this video recording may skip frames because it is asynchronous
+ *
+ * @param filename destination for saving video
+ * @param overwrite should the file be replaced, otherwise a unique incrementing counter will be appended
+ */
+ fun toggleRecordVideo(filename: String?, overwrite: Boolean) {
+ if (renderer is OpenGLRenderer) (renderer as OpenGLRenderer).recordMovie(filename!!, overwrite) else (renderer as VulkanRenderer).recordMovie(filename!!, overwrite)
+ }
+
+ /**
+ * This pushes the current input setup onto a stack that allows them to be restored with restoreControls
+ * This pushes the current input setup onto a stack that allows them to be restored with restoreControls.
+ * It stacks in particular: all keybindings, all Behaviours, and all step sizes and mouse sensitivities
+ * (which are held together in [ControlsParameters]).
+ *
+ * *Word of warning:* The stashing memorizes *references only* on currently used controls
+ * (such as, e.g., [MovementCommand], [FPSCameraControl] or [NodeTranslateControl]),
+ * it *does not* create an extra copy of any control. That said, if you modify any control
+ * object despite it was already stashed with this method, the change will be visible in the "stored"
+ * control and will not go away after the restore... To be on the safe side for now at least, *create
+ * new and modified* controls rather than directly changing them.
+ */
+ fun stashControls() {
+ val controlState = HashMap()
+ val handler = inputHandler
+ if (handler == null) {
+ logger.error("InputHandler is null, cannot store controls")
+ return
+ }
+
+ //behaviours:
+ for (actionName in handler.getAllBehaviours()) {
+ controlState[STASH_BEHAVIOUR_KEY + actionName] = handler.getBehaviour(actionName) as Any
+ }
+
+ //bindings:
+ for (actionName in handler.getAllBehaviours()) {
+ for (trigger in handler.getKeyBindings(actionName)) {
+ controlState[STASH_BINDING_KEY + actionName] = trigger.toString()
+ }
+ }
+
+ //finally, stash the control parameters
+ controlState[STASH_CONTROLSPARAMS_KEY] = controlsParameters
+
+ //...and stash it!
+ controlStack!!.push(controlState)
+ }
+
+ /**
+ * This pops/restores the previously stashed controls. Emits a warning if there are no stashed controls.
+ * It first clears all controls, and then resets in particular: all keybindings, all Behaviours,
+ * and all step sizes and mouse sensitivities (which are held together in [ControlsParameters]).
+ *
+ * *Some recent changes may not be removed* with this restore --
+ * see discussion in the docs of [SciView.stashControls] for more details.
+ */
+ fun restoreControls() {
+ if (controlStack!!.empty()) {
+ logger.warn("Not restoring controls, the controls stash stack is empty!")
+ return
+ }
+ val inputHandler = inputHandler
+ if (inputHandler == null) {
+ logger.error("InputHandler is null, cannot restore controls")
+ return
+ }
+
+ //clear the input handler entirely
+ for (actionName in inputHandler.getAllBehaviours()) {
+ inputHandler.removeKeyBinding(actionName)
+ inputHandler.removeBehaviour(actionName)
+ }
+
+ //retrieve the most recent stash with controls
+ val controlState = controlStack!!.pop()
+ for (control in controlState.entries) {
+ var key: String
+ when {
+ control.key.startsWith(STASH_BEHAVIOUR_KEY) -> {
+ //processing behaviour
+ key = control.key.substring(STASH_BEHAVIOUR_KEY.length)
+ inputHandler.addBehaviour(key, control.value as Behaviour)
+ }
+ control.key.startsWith(STASH_BINDING_KEY) -> {
+ //processing key binding
+ key = control.key.substring(STASH_BINDING_KEY.length)
+ inputHandler.addKeyBinding(key, (control.value as String))
+ }
+ control.key.startsWith(STASH_CONTROLSPARAMS_KEY) -> {
+ //processing mouse sensitivities and step sizes...
+ controlsParameters = control.value as ControlsParameters
+ }
+ }
+ }
+ }
+
+ private val STASH_BEHAVIOUR_KEY = "behaviour:"
+ private val STASH_BINDING_KEY = "binding:"
+ private val STASH_CONTROLSPARAMS_KEY = "parameters:"
+
+ /**
+ * Reset the scene to initial conditions
+ */
+ fun reset() {
+ // Initialize the 3D axes
+ axes = arrayOf(
+ DefaultLinearAxis(DefaultAxisType("X", true), "um", 1.0),
+ DefaultLinearAxis(DefaultAxisType("Y", true), "um", 1.0),
+ DefaultLinearAxis(DefaultAxisType("Z", true), "um", 1.0)
+ )
+
+ // Remove everything except camera
+ val toRemove = getSceneNodes { n: Node? -> n !is Camera }
+ for (n in toRemove) {
+ deleteNode(n, false)
+ }
+
+ // Setup camera
+ if (camera == null) {
+ camera = DetachedHeadCamera()
+ (camera as DetachedHeadCamera).position = Vector3f(0.0f, 1.65f, 0.0f)
+ scene.addChild(camera as DetachedHeadCamera)
+ }
+ camera!!.position = Vector3f(0.0f, 1.65f, 5.0f)
+ camera!!.perspectiveCamera(50.0f, windowWidth, windowHeight, 0.1f, 1000.0f)
+
+ // Setup lights
+ val tetrahedron = arrayOfNulls(4)
+ tetrahedron[0] = Vector3f(1.0f, 0f, -1.0f / Math.sqrt(2.0).toFloat())
+ tetrahedron[1] = Vector3f(-1.0f, 0f, -1.0f / Math.sqrt(2.0).toFloat())
+ tetrahedron[2] = Vector3f(0.0f, 1.0f, 1.0f / Math.sqrt(2.0).toFloat())
+ tetrahedron[3] = Vector3f(0.0f, -1.0f, 1.0f / Math.sqrt(2.0).toFloat())
+ lights = ArrayList()
+ for (i in 0..3) { // TODO allow # initial lights to be customizable?
+ val light = PointLight(150.0f)
+ light.position = tetrahedron[i]!!.mul(25.0f)
+ light.emissionColor = Vector3f(1.0f, 1.0f, 1.0f)
+ light.intensity = 1.0f
+ lights!!.add(light)
+ //camera.addChild( light );
+ scene.addChild(light)
+ }
+
+ // Make a headlight for the camera
+ headlight = PointLight(150.0f)
+ headlight!!.position = Vector3f(0f, 0f, -1f).mul(25.0f)
+ headlight!!.emissionColor = Vector3f(1.0f, 1.0f, 1.0f)
+ headlight!!.intensity = 0.5f
+ headlight!!.name = "headlight"
+ val lightSphere = Icosphere(1.0f, 2)
+ headlight!!.addChild(lightSphere)
+ lightSphere.material.diffuse = headlight!!.emissionColor
+ lightSphere.material.specular = headlight!!.emissionColor
+ lightSphere.material.ambient = headlight!!.emissionColor
+ lightSphere.material.wireframe = true
+ lightSphere.visible = false
+ //lights.add( light );
+ camera!!.nearPlaneDistance = 0.01f
+ camera!!.farPlaneDistance = 1000.0f
+ camera!!.addChild(headlight!!)
+ floor = InfinitePlane() //new Box( new Vector3f( 500f, 0.2f, 500f ) );
+ (floor as InfinitePlane).type = InfinitePlane.Type.Grid
+ (floor as Node).name = "Floor"
+ scene.addChild(floor as Node)
+ }
+
+ /**
+ * Initialization of SWING and scenery. Also triggers an initial population of lights/camera in the scene
+ */
+ override fun init() {
+
+ // Darcula dependency went missing from maven repo, factor it out
+// if(Boolean.parseBoolean(System.getProperty("sciview.useDarcula", "false"))) {
+// try {
+// BasicLookAndFeel darcula = new DarculaLaf();
+// UIManager.setLookAndFeel(darcula);
+// } catch (Exception e) {
+// getLogger().info("Could not load Darcula Look and Feel");
+// }
+// }
+ val logLevel = System.getProperty("scenery.LogLevel", "info")
+ log!!.level = LogLevel.value(logLevel)
+ LogbackUtils.setLogLevel(null, logLevel)
+ System.getProperties().stringPropertyNames().forEach(Consumer { name: String ->
+ if (name.startsWith("scenery.LogLevel")) {
+ LogbackUtils.setLogLevel("", System.getProperty(name, "info"))
+ }
+ })
+
+ // determine imagej-launcher version and to disable Vulkan if XInitThreads() fix
+ // is not deployed
+ try {
+ val launcherClass = Class.forName("net.imagej.launcher.ClassLauncher")
+ var versionString = VersionUtils.getVersion(launcherClass)
+ if (versionString != null && getPlatform() == ExtractsNatives.Platform.LINUX) {
+ versionString = versionString.substring(0, 5)
+ val launcherVersion = Version(versionString)
+ val nonWorkingVersion = Version("4.0.5")
+ if (launcherVersion.compareTo(nonWorkingVersion) <= 0
+ && !java.lang.Boolean.parseBoolean(System.getProperty("sciview.DisableLauncherVersionCheck", "false"))) {
+ logger.info("imagej-launcher version smaller or equal to non-working version ($versionString vs. 4.0.5), disabling Vulkan as rendering backend. Disable check by setting 'scenery.DisableLauncherVersionCheck' system property to 'true'.")
+ System.setProperty("scenery.Renderer", "OpenGLRenderer")
+ } else {
+ logger.info("imagej-launcher version bigger that non-working version ($versionString vs. 4.0.5), all good.")
+ }
+ }
+ } catch (cnfe: ClassNotFoundException) {
+ // Didn't find the launcher, so we're probably good.
+ logger.info("imagej-launcher not found, not touching renderer preferences.")
+ }
+
+ // TODO: check for jdk 8 v. jdk 11 on linux and choose renderer accordingly
+ if (Platform.get() === Platform.LINUX) {
+ var version = System.getProperty("java.version")
+ if (version.startsWith("1.")) {
+ version = version.substring(2, 3)
+ } else {
+ val dot = version.indexOf(".")
+ if (dot != -1) {
+ version = version.substring(0, dot)
+ }
+ }
+
+ // If Linux and JDK 8, then use OpenGLRenderer
+ if (version == "8") System.setProperty("scenery.Renderer", "OpenGLRenderer")
+ }
+ var x: Int
+ var y: Int
+ try {
+ val screenSize = Toolkit.getDefaultToolkit().screenSize
+ x = screenSize.width / 2 - windowWidth / 2
+ y = screenSize.height / 2 - windowHeight / 2
+ } catch (e: HeadlessException) {
+ x = 10
+ y = 10
+ }
+ frame = JFrame("SciView")
+ frame!!.layout = BorderLayout(0, 0)
+ frame!!.setSize(windowWidth, windowHeight)
+ frame!!.setLocation(x, y)
+ frame!!.defaultCloseOperation = JFrame.DISPOSE_ON_CLOSE
+ nodePropertyEditor = NodePropertyEditor(this)
+ val p = JPanel(BorderLayout(0, 0))
+ sceneryJPanel = SceneryJPanel()
+ JPopupMenu.setDefaultLightWeightPopupEnabled(false)
+ val swingMenuBar = JMenuBar()
+ SwingJMenuBarCreator().createMenus(menus!!.getMenu("SciView"), swingMenuBar)
+ val bar = ProgressPie()
+// progress.add(bar)
+ bar.value = 0.0
+ bar.minimumSize = Dimension(30, 30)
+ bar.maximumSize = Dimension(30, 30)
+ bar.preferredSize = Dimension(30, 30)
+ val progressLabel = JLabel("")
+ progressLabel.horizontalAlignment = SwingConstants.RIGHT
+ swingMenuBar.add(javax.swing.Box.createHorizontalGlue())
+ swingMenuBar.add(progressLabel)
+ swingMenuBar.add(bar)
+ frame!!.jMenuBar = swingMenuBar
+ p.layout = OverlayLayout(p)
+ p.background = Color(50, 48, 47)
+ p.add(sceneryJPanel, BorderLayout.CENTER)
+
+ taskManager.update = { current ->
+ if(current != null) {
+ progressLabel.text = "${current.source}: ${current.status} "
+ bar.value = current.completion.toDouble()
+ } else {
+ progressLabel.text = ""
+ bar.value = 0.0
+ }
+
+ bar.repaint()
+ }
+ sceneryJPanel!!.isVisible = true
+ nodePropertyEditor!!.component // Initialize node property panel
+ val inspectorTree = nodePropertyEditor!!.tree
+ inspectorTree.toggleClickCount = 0 // This disables expanding menus on double click
+ val inspectorProperties = nodePropertyEditor!!.props
+ val tp = JBEditorTabs(null)
+ tp.tabsPosition = JBTabsPosition.right
+ tp.isSideComponentVertical = true
+ inspector = JSplitPane(JSplitPane.VERTICAL_SPLIT, //
+ JScrollPane(inspectorTree),
+ JScrollPane(inspectorProperties))
+ inspector!!.dividerLocation = windowHeight / 3
+ inspector!!.isContinuousLayout = true
+ inspector!!.border = BorderFactory.createEmptyBorder()
+ inspector!!.dividerSize = 1
+ val inspectorIcon = getScaledImageIcon(this.javaClass.getResource("toolbox.png"), 16, 16)
+ val tiInspector = TabInfo(inspector, inspectorIcon)
+ tiInspector.text = ""
+ tp.addTab(tiInspector)
+
+ // We need to get the surface scale here before initialising scenery's renderer, as
+ // the information is needed already at initialisation time.
+ val dt = frame!!.graphicsConfiguration.defaultTransform
+ val surfaceScale = Vector2f(dt.scaleX.toFloat(), dt.scaleY.toFloat())
+ settings.set("Renderer.SurfaceScale", surfaceScale)
+ interpreterPane = REPLPane(scijavaContext)
+ interpreterPane!!.component.border = BorderFactory.createEmptyBorder()
+ val interpreterIcon = getScaledImageIcon(this.javaClass.getResource("terminal.png"), 16, 16)
+ val tiREPL = TabInfo(interpreterPane!!.component, interpreterIcon)
+ tiREPL.text = ""
+ tp.addTab(tiREPL)
+ tp.addTabMouseListener(object : MouseListener {
+ override fun mouseClicked(e: MouseEvent) {
+ if (e.clickCount == 2) {
+ toggleSidebar()
+ }
+ }
+
+ override fun mousePressed(e: MouseEvent) {}
+ override fun mouseReleased(e: MouseEvent) {}
+ override fun mouseEntered(e: MouseEvent) {}
+ override fun mouseExited(e: MouseEvent) {}
+ })
+ initializeInterpreter()
+ mainSplitPane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, //
+ p,
+ tp.component
+ )
+ mainSplitPane!!.dividerLocation = frame!!.size.width - 36
+ mainSplitPane!!.border = BorderFactory.createEmptyBorder()
+ mainSplitPane!!.dividerSize = 1
+ mainSplitPane!!.resizeWeight = 0.9
+ sidebarHidden = true
+
+ //frame.add(mainSplitPane, BorderLayout.CENTER);
+ frame!!.add(mainSplitPane, BorderLayout.CENTER)
+ val sciView = this
+ frame!!.addWindowListener(object : WindowAdapter() {
+ override fun windowClosing(e: WindowEvent) {
+ logger.debug("Closing SciView window.")
+ close()
+ scijavaContext!!.service(SciViewService::class.java).close(sciView)
+ isClosed = true
+ }
+ })
+ splashLabel = SplashLabel()
+ frame!!.glassPane = splashLabel
+ frame!!.glassPane.isVisible = true
+ frame!!.glassPane.requestFocusInWindow()
+ // frame.getGlassPane().setBackground(new java.awt.Color(50, 48, 47, 255));
+ frame!!.isVisible = true
+ sceneryPanel[0] = sceneryJPanel
+ renderer = Renderer.createRenderer(hub, applicationName, scene,
+ windowWidth, windowHeight,
+ sceneryPanel[0])
+ hub.add(SceneryElement.Renderer, renderer!!)
+ reset()
+ animations = LinkedList()
+ controlStack = Stack()
+ SwingUtilities.invokeLater {
+ try {
+ while (!getSceneryRenderer()!!.firstImageReady) {
+ logger.debug("Waiting for renderer initialisation")
+ Thread.sleep(300)
+ }
+ Thread.sleep(200)
+ } catch (e: InterruptedException) {
+ logger.error("Renderer construction interrupted.")
+ }
+ nodePropertyEditor!!.rebuildTree()
+ logger.info("Done initializing SciView")
+
+ // subscribe to Node{Added, Removed, Changed} events, happens automatically
+// eventService!!.subscribe(this)
+ frame!!.glassPane.isVisible = false
+ sceneryJPanel!!.isVisible = true
+
+ // install hook to keep inspector updated on external changes (scripting, etc)
+ scene.onNodePropertiesChanged["updateInspector"] = { node: Node ->
+ if (node === nodePropertyEditor!!.currentNode) {
+ nodePropertyEditor!!.updateProperties(node)
+ }
+ }
+
+ // Enable push rendering by default
+ renderer!!.pushMode = true
+ sciView.camera!!.setPosition(1.65, 1)
+ }
+ }
+
+ private var sidebarHidden = false
+ private var previousSidebarPosition = 0
+ fun toggleSidebar(): Boolean {
+ if (!sidebarHidden) {
+ previousSidebarPosition = mainSplitPane!!.dividerLocation
+ // TODO: remove hard-coded tab width
+ mainSplitPane!!.dividerLocation = frame!!.size.width - 36
+ sidebarHidden = true
+ } else {
+ if (previousSidebarPosition == 0) {
+ previousSidebarPosition = windowWidth / 3 * 2
+ }
+ mainSplitPane!!.dividerLocation = previousSidebarPosition
+ sidebarHidden = false
+ }
+ return sidebarHidden
+ }
+
+ private fun getScaledImageIcon(resource: URL, width: Int, height: Int): ImageIcon {
+ val first = ImageIcon(resource)
+ val resizedImg = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
+ val g2 = resizedImg.createGraphics()
+ g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR)
+ g2.drawImage(first.image, 0, 0, width, height, null)
+ g2.dispose()
+ return ImageIcon(resizedImg)
+ }
+
+ private fun initializeInterpreter() {
+ val startupCode = Scanner(SciView::class.java.getResourceAsStream("startup.py"), "UTF-8").useDelimiter("\\A").next()
+ interpreterPane!!.repl.interpreter.bindings["sciView"] = this
+ try {
+ interpreterPane!!.repl.interpreter.eval(startupCode)
+ } catch (e: ScriptException) {
+ e.printStackTrace()
+ }
+ }
+
+ /*
+ * Completely close the SciView window + cleanup
+ */
+ fun closeWindow() {
+ frame!!.dispose()
+ }
+
+ /*
+ * Return true if the scene has been initialized
+ */
+ val isInitialized: Boolean
+ get() = sceneInitialized()
+
+ /**
+ * Place the scene into the center of camera view, and zoom in/out such
+ * that the whole scene is in the view (everything would be visible if it
+ * would not be potentially occluded).
+ */
+ fun fitCameraToScene() {
+ centerOnNode(scene)
+ //TODO: smooth zoom in/out VLADO vlado Vlado
+ }
+
+ /**
+ * Place the scene into the center of camera view.
+ */
+ fun centerOnScene() {
+ centerOnNode(scene)
+ }
+ /*
+ * Get the InputHandler that is managing mouse, input, VR controls, etc.
+ */
+ val sceneryInputHandler: InputHandler
+ get() = inputHandler!!
+
+ /*
+ * Return a bounding box around a subgraph of the scenegraph
+ */
+ fun getSubgraphBoundingBox(n: Node): OrientedBoundingBox? {
+ val predicate = Function> { node: Node -> node.children }
+ return getSubgraphBoundingBox(n, predicate)
+ }
+
+ /*
+ * Return a bounding box around a subgraph of the scenegraph
+ */
+ fun getSubgraphBoundingBox(n: Node, branchFunction: Function>): OrientedBoundingBox? {
+ if (n.boundingBox == null && n.children.size != 0) {
+ return n.getMaximumBoundingBox().asWorld()
+ }
+ val branches = branchFunction.apply(n)
+ if (branches.size == 0) {
+ return if (n.boundingBox == null) null else n.boundingBox!!.asWorld()
+ }
+ var bb = n.getMaximumBoundingBox()
+ for (c in branches) {
+ val cBB = getSubgraphBoundingBox(c, branchFunction)
+ if (cBB != null) bb = bb.expand(bb, cBB)
+ }
+ return bb
+ }
+
+ /**
+ * Place the active node into the center of camera view.
+ */
+ fun centerOnActiveNode() {
+ if (activeNode == null) return
+ centerOnNode(activeNode)
+ }
+
+ /**
+ * Place the specified node into the center of camera view.
+ */
+ fun centerOnNode(currentNode: Node?) {
+ if (currentNode == null) {
+ log!!.info("Cannot center on null node.")
+ return
+ }
+
+ //center the on the same spot as ArcBall does
+ centerOnPosition(currentNode.getMaximumBoundingBox().getBoundingSphere().origin)
+ }
+
+ /**
+ * Center the camera on the specified Node
+ */
+ fun centerOnPosition(currentPos: Vector3f?) {
+ //desired view direction in world coords
+ val worldDirVec = Vector3f(currentPos).sub(camera!!.position)
+ if (worldDirVec.lengthSquared() < 0.01) {
+ //ill defined task, happens typically when cam is inside the node which we want center on
+ log!!.info("Camera is on the spot you want to look at. Please, move the camera away first.")
+ return
+ }
+ val camForwardXZ = Vector2f(camera!!.forward.x, camera!!.forward.z)
+ val wantLookAtXZ = Vector2f(worldDirVec.x, worldDirVec.z)
+ var totalYawAng = camForwardXZ.normalize().dot(wantLookAtXZ.normalize()).toDouble()
+ //while mathematically impossible, cumulated numerical inaccuracies have different opinion
+ totalYawAng = if (totalYawAng > 1) {
+ 0.0
+ } else {
+ acos(totalYawAng)
+ }
+
+ //switch direction?
+ camForwardXZ[camForwardXZ.y] = -camForwardXZ.x
+ if (wantLookAtXZ.dot(camForwardXZ) > 0) totalYawAng *= -1.0
+ val camForwardYed = Vector3f(camera!!.forward)
+ Quaternionf().rotateXYZ(0f, (-totalYawAng).toFloat(), 0f).normalize().transform(camForwardYed)
+ var totalPitchAng = camForwardYed.normalize().dot(worldDirVec.normalize()).toDouble()
+ totalPitchAng = if (totalPitchAng > 1) {
+ 0.0
+ } else {
+ acos(totalPitchAng)
+ }
+
+ //switch direction?
+ if (camera!!.forward.y > worldDirVec.y) totalPitchAng *= -1.0
+ if (camera!!.up.y < 0) totalPitchAng *= -1.0
+
+ //animation options: control delay between animation frames -- fluency
+ val rotPausePerStep: Long = 30 //miliseconds
+
+ //animation options: control max number of steps -- upper limit on total time for animation
+ val rotMaxSteps = 999999 //effectively disabled....
+
+ //animation options: the hardcoded 5 deg (0.087 rad) -- smoothness
+ //how many steps when max update/move is 5 deg
+ val totalDeltaAng = Math.max(Math.abs(totalPitchAng), Math.abs(totalYawAng)).toFloat()
+ var rotSteps = Math.ceil(totalDeltaAng / 0.087).toInt()
+ if (rotSteps > rotMaxSteps) rotSteps = rotMaxSteps
+
+ /*
+ log.info("centering over "+rotSteps+" steps the pitch " + 180*totalPitchAng/Math.PI
+ + " and the yaw " + 180*totalYawAng/Math.PI);
+ */
+
+ //angular progress aux variables
+ var donePitchAng = 0.0
+ var doneYawAng = 0.0
+ var deltaAng: Float
+ camera!!.targeted = false
+ var i = 1
+ while (i <= rotSteps) {
+
+ //this emulates ease-in ease-out animation, both vars are in [0:1]
+ var timeProgress = i.toFloat() / rotSteps
+ val angProgress = (if (2.let { timeProgress *= it; timeProgress } <= 1) //two cubics connected smoothly into S-shape curve from [0,0] to [1,1]
+ timeProgress * timeProgress * timeProgress else 2.let { timeProgress -= it; timeProgress } * timeProgress * timeProgress + 2) / 2
+
+ //rotate now by this ang: "where should I be by now" minus "where I got last time"
+ deltaAng = (angProgress * totalPitchAng - donePitchAng).toFloat()
+ val pitchQ = Quaternionf().rotateXYZ(-deltaAng, 0f, 0f).normalize()
+ deltaAng = (angProgress * totalYawAng - doneYawAng).toFloat()
+ val yawQ = Quaternionf().rotateXYZ(0f, deltaAng, 0f).normalize()
+ camera!!.rotation = pitchQ.mul(camera!!.rotation).mul(yawQ).normalize()
+ donePitchAng = angProgress * totalPitchAng
+ doneYawAng = angProgress * totalYawAng
+ try {
+ Thread.sleep(rotPausePerStep)
+ } catch (e: InterruptedException) {
+ i = rotSteps
+ }
+ ++i
+ }
+ }
+
+ /**
+ * Activate the node, and center the view on it.
+ * @param n
+ * @return the currently active node
+ */
+ fun setActiveCenteredNode(n: Node?): Node? {
+ //activate...
+ val ret = setActiveNode(n)
+ //...and center it
+ ret?.let { centerOnNode(it) }
+ return ret
+ }
+
+ //a couple of shortcut methods to readout controls params
+ fun getFPSSpeedSlow(): Float {
+ return controlsParameters.getFpsSpeedSlow()
+ }
+
+ fun getFPSSpeedFast(): Float {
+ return controlsParameters.getFpsSpeedFast()
+ }
+
+ fun getFPSSpeedVeryFast(): Float {
+ return controlsParameters.getFpsSpeedVeryFast()
+ }
+
+ fun getMouseSpeed(): Float {
+ return controlsParameters.getMouseSpeedMult()
+ }
+
+ fun getMouseScrollSpeed(): Float {
+ return controlsParameters.getMouseScrollMult()
+ }
+
+ //a couple of setters with scene sensible boundary checks
+ fun setFPSSpeedSlow(slowSpeed: Float) {
+ controlsParameters.setFpsSpeedSlow(paramWithinBounds(slowSpeed, FPSSPEED_MINBOUND_SLOW, FPSSPEED_MAXBOUND_SLOW))
+ }
+
+ fun setFPSSpeedFast(fastSpeed: Float) {
+ controlsParameters.setFpsSpeedFast(paramWithinBounds(fastSpeed, FPSSPEED_MINBOUND_FAST, FPSSPEED_MAXBOUND_FAST))
+ }
+
+ fun setFPSSpeedVeryFast(veryFastSpeed: Float) {
+ controlsParameters.setFpsSpeedVeryFast(paramWithinBounds(veryFastSpeed, FPSSPEED_MINBOUND_VERYFAST, FPSSPEED_MAXBOUND_VERYFAST))
+ }
+
+ fun setFPSSpeed(newBaseSpeed: Float) {
+ // we don't want to escape bounds checking
+ // (so we call "our" methods rather than directly the controlsParameters)
+ setFPSSpeedSlow(1f * newBaseSpeed)
+ setFPSSpeedFast(20f * newBaseSpeed)
+ setFPSSpeedVeryFast(500f * newBaseSpeed)
+
+ //report what's been set in the end
+ log!!.debug("FPS speeds: slow=" + controlsParameters.getFpsSpeedSlow()
+ .toString() + ", fast=" + controlsParameters.getFpsSpeedFast()
+ .toString() + ", very fast=" + controlsParameters.getFpsSpeedVeryFast())
+ }
+
+ fun setMouseSpeed(newSpeed: Float) {
+ controlsParameters.setMouseSpeedMult(paramWithinBounds(newSpeed, MOUSESPEED_MINBOUND, MOUSESPEED_MAXBOUND))
+ log!!.debug("Mouse movement speed: " + controlsParameters.getMouseSpeedMult())
+ }
+
+ fun setMouseScrollSpeed(newSpeed: Float) {
+ controlsParameters.setMouseScrollMult(paramWithinBounds(newSpeed, MOUSESCROLL_MINBOUND, MOUSESCROLL_MAXBOUND))
+ log!!.debug("Mouse scroll speed: " + controlsParameters.getMouseScrollMult())
+ }
+
+ // TODO replace with coerce?
+ private fun paramWithinBounds(param: Float, minBound: Float, maxBound: Float): Float {
+ var newParam = param
+ if (newParam < minBound) newParam = minBound else if (newParam > maxBound) newParam = maxBound
+ return newParam
+ }
+
+
+ fun setObjectSelectionMode() {
+ val selectAction = { nearest: RaycastResult, x: Int, y: Int ->
+ if (!nearest.matches.isEmpty()) {
+ // copy reference on the last object picking result into "public domain"
+ // (this must happen before the ContextPopUpNodeChooser menu!)
+ objectSelectionLastResult = nearest
+
+ // Setup the context menu for this picking
+ // (in the menu, the user will chose node herself)
+ ContextPopUpNodeChooser(this).show(sceneryJPanel, x, y)
+ }
+ }
+ setObjectSelectionMode(selectAction)
+ }
+
+ var objectSelectionLastResult: RaycastResult? = null
+
+ /*
+ * Set the action used during object selection
+ */
+ fun setObjectSelectionMode(selectAction: Function3?) {
+ val h = inputHandler
+ val ignoredObjects = ArrayList>()
+ ignoredObjects.add(BoundingGrid::class.java)
+ ignoredObjects.add(Camera::class.java) //do not mess with "scene params", allow only "scene data" to be selected
+ ignoredObjects.add(DetachedHeadCamera::class.java)
+ ignoredObjects.add(DirectionalLight::class.java)
+ ignoredObjects.add(PointLight::class.java)
+ if (h == null) {
+ logger.error("InputHandler is null, cannot change object selection mode.")
+ return
+ }
+ h.addBehaviour("node: choose one from the view panel",
+ SelectCommand("objectSelector", renderer!!, scene,
+ { scene.findObserver() }, false, ignoredObjects,
+ selectAction!!))
+ h.addKeyBinding("node: choose one from the view panel", "double-click button1")
+ }
+
+ /*
+ * Initial configuration of the scenery InputHandler
+ * This is automatically called and should not be used directly
+ */
+ override fun inputSetup() {
+ val h = inputHandler
+ if (h == null) {
+ logger.error("InputHandler is null, cannot run input setup.")
+ return
+ }
+ //when we get here, the Behaviours and key bindings from scenery are already in place
+
+ //possibly, disable some (unused?) controls from scenery
+ /*
+ h.removeBehaviour( "gamepad_camera_control");
+ h.removeKeyBinding("gamepad_camera_control");
+ h.removeBehaviour( "gamepad_movement_control");
+ h.removeKeyBinding("gamepad_movement_control");
+ */
+
+ // node-selection and node-manipulation (translate & rotate) controls
+ setObjectSelectionMode()
+ val nodeTranslateControl = NodeTranslateControl(this)
+ h.addBehaviour("node: move selected one left, right, up, or down", nodeTranslateControl)
+ h.addKeyBinding("node: move selected one left, right, up, or down", "ctrl button1")
+ h.addBehaviour("node: move selected one closer or further away", nodeTranslateControl)
+ h.addKeyBinding("node: move selected one closer or further away", "ctrl scroll")
+ h.addBehaviour("node: rotate selected one", NodeRotateControl(this))
+ h.addKeyBinding("node: rotate selected one", "ctrl shift button1")
+
+ // within-scene navigation: ArcBall and FPS
+ enableArcBallControl()
+ enableFPSControl()
+
+ // whole-scene rolling
+ h.addBehaviour("view: rotate (roll) clock-wise", SceneRollControl(this, +0.05f)) //2.8 deg
+ h.addKeyBinding("view: rotate (roll) clock-wise", "R")
+ h.addBehaviour("view: rotate (roll) counter clock-wise", SceneRollControl(this, -0.05f))
+ h.addKeyBinding("view: rotate (roll) counter clock-wise", "shift R")
+ h.addBehaviour("view: rotate (roll) with mouse", h.getBehaviour("view: rotate (roll) clock-wise")!!)
+ h.addKeyBinding("view: rotate (roll) with mouse", "ctrl button3")
+
+ // adjusters of various controls sensitivities
+ h.addBehaviour("moves: step size decrease", ClickBehaviour { _: Int, _: Int -> setFPSSpeed(getFPSSpeedSlow() - 0.01f) })
+ h.addKeyBinding("moves: step size decrease", "MINUS")
+ h.addBehaviour("moves: step size increase", ClickBehaviour { _: Int, _: Int -> setFPSSpeed(getFPSSpeedSlow() + 0.01f) })
+ h.addKeyBinding("moves: step size increase", "EQUALS")
+ h.addBehaviour("mouse: move sensitivity decrease", ClickBehaviour { _: Int, _: Int -> setMouseSpeed(getMouseSpeed() - 0.02f) })
+ h.addKeyBinding("mouse: move sensitivity decrease", "M MINUS")
+ h.addBehaviour("mouse: move sensitivity increase", ClickBehaviour { _: Int, _: Int -> setMouseSpeed(getMouseSpeed() + 0.02f) })
+ h.addKeyBinding("mouse: move sensitivity increase", "M EQUALS")
+ h.addBehaviour("mouse: scroll sensitivity decrease", ClickBehaviour { _: Int, _: Int -> setMouseScrollSpeed(getMouseScrollSpeed() - 0.3f) })
+ h.addKeyBinding("mouse: scroll sensitivity decrease", "S MINUS")
+ h.addBehaviour("mouse: scroll sensitivity increase", ClickBehaviour { _: Int, _: Int -> setMouseScrollSpeed(getMouseScrollSpeed() + 0.3f) })
+ h.addKeyBinding("mouse: scroll sensitivity increase", "S EQUALS")
+
+ // help window
+ h.addBehaviour("show help", showHelpDisplay())
+ h.addKeyBinding("show help", "F1")
+ }
+
+ /*
+ * Change the control mode to circle around the active object in an arcball
+ */
+ private fun enableArcBallControl() {
+ val h = inputHandler
+ if (h == null) {
+ logger.error("InputHandler is null, cannot setup arcball control.")
+ return
+ }
+
+ val target: Vector3f = activeNode?.position ?: Vector3f(0.0f, 0.0f, 0.0f)
+
+ //setup ArcballCameraControl from scenery, register it with SciView's controlsParameters
+ val cameraSupplier = Supplier { scene.findObserver() }
+ targetArcball = AnimatedCenteringBeforeArcBallControl("view: rotate it around selected node", cameraSupplier,
+ renderer!!.window.width,
+ renderer!!.window.height, target)
+ targetArcball.maximumDistance = Float.MAX_VALUE
+ controlsParameters.registerArcballCameraControl(targetArcball)
+ h.addBehaviour("view: rotate around selected node", targetArcball)
+ h.addKeyBinding("view: rotate around selected node", "shift button1")
+ h.addBehaviour("view: zoom outward or toward selected node", targetArcball)
+ h.addKeyBinding("view: zoom outward or toward selected node", "shift scroll")
+ }
+
+ /*
+ * A wrapping class for the {@ArcballCameraControl} that calls {@link CenterOnPosition()}
+ * before the actual Arcball camera movement takes place. This way, the targeted node is
+ * first smoothly brought into the centre along which Arcball is revolving, preventing
+ * from sudden changes of view (and lost of focus from the user.
+ */
+ inner class AnimatedCenteringBeforeArcBallControl : ArcballCameraControl {
+ //a bunch of necessary c'tors (originally defined in the ArcballCameraControl class)
+ constructor(name: String, n: Function0, w: Int, h: Int, target: Function0) : super(name, n, w, h, target) {}
+ constructor(name: String,n: Supplier, w: Int, h: Int, target: Supplier) : super(name, n, w, h, target) {}
+ constructor(name: String, n: Function0, w: Int, h: Int, target: Vector3f) : super(name, n, w, h, target) {}
+ constructor(name: String, n: Supplier, w: Int, h: Int, target: Vector3f) : super(name, n, w, h, target) {}
+
+ override fun init(x: Int, y: Int) {
+ centerOnPosition(targetArcball.target.invoke())
+ super.init(x, y)
+ }
+
+ override fun scroll(wheelRotation: Double, isHorizontal: Boolean, x: Int, y: Int) {
+ centerOnPosition(targetArcball.target.invoke())
+ super.scroll(wheelRotation, isHorizontal, x, y)
+ }
+ }
+
+ /*
+ * Enable FPS style controls
+ */
+ private fun enableFPSControl() {
+ val h = inputHandler
+ if (h == null) {
+ logger.error("InputHandler is null, cannot setup fps control.")
+ return
+ }
+
+ // Mouse look around (Lclick) and move around (Rclick)
+ //
+ //setup FPSCameraControl from scenery, register it with SciView's controlsParameters
+ val cameraSupplier = Supplier { scene.findObserver() }
+ fpsControl = FPSCameraControl("view: freely look around", cameraSupplier, renderer!!.window.width,
+ renderer!!.window.height)
+ controlsParameters.registerFpsCameraControl(fpsControl)
+ h.addBehaviour("view: freely look around", fpsControl!!)
+ h.addKeyBinding("view: freely look around", "button1")
+
+ //slow and fast camera motion
+ h.addBehaviour("move_withMouse_back/forward/left/right", CameraTranslateControl(this, 1f))
+ h.addKeyBinding("move_withMouse_back/forward/left/right", "button3")
+ //
+ //fast and very fast camera motion
+ h.addBehaviour("move_withMouse_back/forward/left/right_fast", CameraTranslateControl(this, 10f))
+ h.addKeyBinding("move_withMouse_back/forward/left/right_fast", "shift button3")
+
+ // Keyboard move around (WASD keys)
+ //
+ //override 'WASD' from Scenery
+ var mcW: MovementCommand
+ var mcA: MovementCommand
+ var mcS: MovementCommand
+ var mcD: MovementCommand
+ mcW = MovementCommand("move_forward", "forward", { scene.findObserver() }, controlsParameters.getFpsSpeedSlow())
+ mcS = MovementCommand("move_backward", "back", { scene.findObserver() }, controlsParameters.getFpsSpeedSlow())
+ mcA = MovementCommand("move_left", "left", { scene.findObserver() }, controlsParameters.getFpsSpeedSlow())
+ mcD = MovementCommand("move_right", "right", { scene.findObserver() }, controlsParameters.getFpsSpeedSlow())
+ controlsParameters.registerSlowStepMover(mcW)
+ controlsParameters.registerSlowStepMover(mcS)
+ controlsParameters.registerSlowStepMover(mcA)
+ controlsParameters.registerSlowStepMover(mcD)
+ h.addBehaviour("move_forward", mcW)
+ h.addBehaviour("move_back", mcS)
+ h.addBehaviour("move_left", mcA)
+ h.addBehaviour("move_right", mcD)
+ // 'WASD' keys are registered already in scenery
+
+ //override shift+'WASD' from Scenery
+ mcW = MovementCommand("move_forward_fast", "forward", { scene.findObserver() }, controlsParameters.getFpsSpeedFast())
+ mcS = MovementCommand("move_backward_fast", "back", { scene.findObserver() }, controlsParameters.getFpsSpeedFast())
+ mcA = MovementCommand("move_left_fast", "left", { scene.findObserver() }, controlsParameters.getFpsSpeedFast())
+ mcD = MovementCommand("move_right_fast", "right", { scene.findObserver() }, controlsParameters.getFpsSpeedFast())
+ controlsParameters.registerFastStepMover(mcW)
+ controlsParameters.registerFastStepMover(mcS)
+ controlsParameters.registerFastStepMover(mcA)
+ controlsParameters.registerFastStepMover(mcD)
+ h.addBehaviour("move_forward_fast", mcW)
+ h.addBehaviour("move_back_fast", mcS)
+ h.addBehaviour("move_left_fast", mcA)
+ h.addBehaviour("move_right_fast", mcD)
+ // shift+'WASD' keys are registered already in scenery
+
+ //define additionally shift+ctrl+'WASD'
+ mcW = MovementCommand("move_forward_veryfast", "forward", { scene.findObserver() }, controlsParameters.getFpsSpeedVeryFast())
+ mcS = MovementCommand("move_back_veryfast", "back", { scene.findObserver() }, controlsParameters.getFpsSpeedVeryFast())
+ mcA = MovementCommand("move_left_veryfast", "left", { scene.findObserver() }, controlsParameters.getFpsSpeedVeryFast())
+ mcD = MovementCommand("move_right_veryfast", "right", { scene.findObserver() }, controlsParameters.getFpsSpeedVeryFast())
+ controlsParameters.registerVeryFastStepMover(mcW)
+ controlsParameters.registerVeryFastStepMover(mcS)
+ controlsParameters.registerVeryFastStepMover(mcA)
+ controlsParameters.registerVeryFastStepMover(mcD)
+ h.addBehaviour("move_forward_veryfast", mcW)
+ h.addBehaviour("move_back_veryfast", mcS)
+ h.addBehaviour("move_left_veryfast", mcA)
+ h.addBehaviour("move_right_veryfast", mcD)
+ h.addKeyBinding("move_forward_veryfast", "ctrl shift W")
+ h.addKeyBinding("move_back_veryfast", "ctrl shift S")
+ h.addKeyBinding("move_left_veryfast", "ctrl shift A")
+ h.addKeyBinding("move_right_veryfast", "ctrl shift D")
+
+ // Keyboard only move up/down (XC keys)
+ //
+ //[[ctrl]+shift]+'XC'
+ mcW = MovementCommand("move_up", "up", { scene.findObserver() }, controlsParameters.getFpsSpeedSlow())
+ mcS = MovementCommand("move_down", "down", { scene.findObserver() }, controlsParameters.getFpsSpeedSlow())
+ controlsParameters.registerSlowStepMover(mcW)
+ controlsParameters.registerSlowStepMover(mcS)
+ h.addBehaviour("move_up", mcW)
+ h.addBehaviour("move_down", mcS)
+ h.addKeyBinding("move_up", "C")
+ h.addKeyBinding("move_down", "X")
+ mcW = MovementCommand("move_up_fast", "up", { scene.findObserver() }, controlsParameters.getFpsSpeedFast())
+ mcS = MovementCommand("move_down_fast", "down", { scene.findObserver() }, controlsParameters.getFpsSpeedFast())
+ controlsParameters.registerFastStepMover(mcW)
+ controlsParameters.registerFastStepMover(mcS)
+ h.addBehaviour("move_up_fast", mcW)
+ h.addBehaviour("move_down_fast", mcS)
+ h.addKeyBinding("move_up_fast", "shift C")
+ h.addKeyBinding("move_down_fast", "shift X")
+ mcW = MovementCommand("move_up_veryfast", "up", { scene.findObserver() }, controlsParameters.getFpsSpeedVeryFast())
+ mcS = MovementCommand("move_down_veryfast", "down", { scene.findObserver() }, controlsParameters.getFpsSpeedVeryFast())
+ controlsParameters.registerVeryFastStepMover(mcW)
+ controlsParameters.registerVeryFastStepMover(mcS)
+ h.addBehaviour("move_up_veryfast", mcW)
+ h.addBehaviour("move_down_veryfast", mcS)
+ h.addKeyBinding("move_up_veryfast", "ctrl shift C")
+ h.addKeyBinding("move_down_veryfast", "ctrl shift X")
+ }
+
+ /**
+ * Add a box at the specified position with specified size, color, and normals on the inside/outside
+ * @param position position to put the box
+ * @param size size of the box
+ * @param color color of the box
+ * @param inside are normals inside the box?
+ * @return the Node corresponding to the box
+ */
+ @JvmOverloads
+ fun addBox(position: Vector3f? = Vector3f(0.0f, 0.0f, 0.0f), size: Vector3f? = Vector3f(1.0f, 1.0f, 1.0f), color: ColorRGB? = DEFAULT_COLOR,
+ inside: Boolean = false): Node? {
+ // TODO: use a material from the current palate by default
+ val boxmaterial = Material()
+ boxmaterial.ambient = Vector3f(1.0f, 0.0f, 0.0f)
+ boxmaterial.diffuse = Utils.convertToVector3f(color)
+ boxmaterial.specular = Vector3f(1.0f, 1.0f, 1.0f)
+ val box = size?.let { Box(it, inside) }
+ box?.material = boxmaterial
+ if (position != null) {
+ box?.position = position
+ }
+ return addNode(box)
+ }
+ /**
+ * Add a sphere at the specified positoin with a given radius and color
+ * @param position position to put the sphere
+ * @param radius radius the sphere
+ * @param color color of the sphere
+ * @return the Node corresponding to the sphere
+ */
+ /**
+ * Add a sphere at the specified position with a given radius
+ * @param position position to put the sphere
+ * @param radius radius of the sphere
+ * @return the Node corresponding to the sphere
+ */
+ /**
+ * Add a unit sphere at the origin
+ * @return the Node corresponding to the sphere
+ */
+ @JvmOverloads
+ fun addSphere(position: Vector3f? = Vector3f(0.0f, 0.0f, 0.0f), radius: Float = 1f, color: ColorRGB? = DEFAULT_COLOR): Node? {
+ val material = Material()
+ material.ambient = Vector3f(1.0f, 0.0f, 0.0f)
+ material.diffuse = Utils.convertToVector3f(color)
+ material.specular = Vector3f(1.0f, 1.0f, 1.0f)
+ val sphere = Sphere(radius, 20)
+ sphere.material = material
+ if (position != null) {
+ sphere.position = position
+ }
+ return addNode(sphere)
+ }
+
+ /**
+ * Add a Cylinder at the given position with radius, height, and number of faces/segments
+ * @param position position of the cylinder
+ * @param radius radius of the cylinder
+ * @param height height of the cylinder
+ * @param num_segments number of segments to represent the cylinder
+ * @return the Node corresponding to the cylinder
+ */
+ fun addCylinder(position: Vector3f?, radius: Float, height: Float, num_segments: Int): Node? {
+ val cyl = Cylinder(radius, height, num_segments)
+ if (position != null) {
+ cyl.position = position
+ }
+ return addNode(cyl)
+ }
+
+ /**
+ * Add a Cone at the given position with radius, height, and number of faces/segments
+ * @param position position to put the cone
+ * @param radius radius of the cone
+ * @param height height of the cone
+ * @param num_segments number of segments used to represent cone
+ * @return the Node corresponding to the cone
+ */
+ fun addCone(position: Vector3f?, radius: Float, height: Float, num_segments: Int): Node? {
+ val cone = Cone(radius, height, num_segments, Vector3f(0.0f, 0.0f, 1.0f))
+ if (position != null) {
+ cone.position = position
+ }
+ return addNode(cone)
+ }
+
+ /**
+ * Add a line from start to stop with the given color
+ * @param start start position of line
+ * @param stop stop position of line
+ * @param color color of line
+ * @return the Node corresponding to the line
+ */
+ @JvmOverloads
+ fun addLine(start: Vector3f = Vector3f(0.0f, 0.0f, 0.0f), stop: Vector3f = Vector3f(1.0f, 1.0f, 1.0f), color: ColorRGB? = DEFAULT_COLOR): Node? {
+ return addLine(arrayOf(start, stop), color, 0.1)
+ }
+
+ /**
+ * Add a multi-segment line that goes through the supplied points with a single color and edge width
+ * @param points points along line including first and terminal points
+ * @param color color of line
+ * @param edgeWidth width of line segments
+ * @return the Node corresponding to the line
+ */
+ fun addLine(points: Array, color: ColorRGB?, edgeWidth: Double): Node? {
+ val material = Material()
+ material.ambient = Vector3f(1.0f, 1.0f, 1.0f)
+ material.diffuse = Utils.convertToVector3f(color)
+ material.specular = Vector3f(1.0f, 1.0f, 1.0f)
+ val line = Line(points.size)
+ for (pt in points) {
+ line.addPoint(pt)
+ }
+ line.edgeWidth = edgeWidth.toFloat()
+ line.material = material
+ line.position = points[0]
+ return addNode(line)
+ }
+
+ /**
+ * Add a PointLight source at the origin
+ * @return a Node corresponding to the PointLight
+ */
+ fun addPointLight(): Node? {
+ val material = Material()
+ material.ambient = Vector3f(1.0f, 0.0f, 0.0f)
+ material.diffuse = Vector3f(0.0f, 1.0f, 0.0f)
+ material.specular = Vector3f(1.0f, 1.0f, 1.0f)
+ val light = PointLight(5.0f)
+ light.material = material
+ light.position = Vector3f(0.0f, 0.0f, 0.0f)
+ lights!!.add(light)
+ return addNode(light)
+ }
+
+ /**
+ * Position all lights that were initialized by default around the scene in a circle at Y=0
+ */
+ fun surroundLighting() {
+ val bb = getSubgraphBoundingBox(scene, notAbstractBranchingFunction)
+ val (c, r) = bb!!.getBoundingSphere()
+ // Choose a good y-position, then place lights around the cross-section through this plane
+ val y = 0f
+ for (k in lights!!.indices) {
+ val light = lights!![k]
+ val x = (c.x() + r * cos(if (k == 0) 0.0 else Math.PI * 2 * (k.toFloat() / lights!!.size.toFloat()))).toFloat()
+ val z = (c.y() + r * sin(if (k == 0) 0.0 else Math.PI * 2 * (k.toFloat() / lights!!.size.toFloat()))).toFloat()
+ light.lightRadius = 2 * r
+ light.position = Vector3f(x, y, z)
+ }
+ }
+
+ /**
+ * Write a scenery mesh as an stl to the given file
+ * @param filename filename of the stl
+ * @param scMesh mesh to save
+ */
+ fun writeSCMesh(filename: String?, scMesh: graphics.scenery.Mesh) {
+ val f = File(filename)
+ val out: BufferedOutputStream
+ try {
+ out = BufferedOutputStream(FileOutputStream(f))
+ out.write("solid STL generated by FIJI\n".toByteArray())
+ val normalsFB = scMesh.normals
+ val verticesFB = scMesh.vertices
+ while (verticesFB.hasRemaining() && normalsFB.hasRemaining()) {
+ out.write("""facet normal ${normalsFB.get()} ${normalsFB.get()} ${normalsFB.get()}
+""".toByteArray())
+ out.write("outer loop\n".toByteArray())
+ for (v in 0..2) {
+ out.write("""vertex ${verticesFB.get()} ${verticesFB.get()} ${verticesFB.get()}
+""".toByteArray())
+ }
+ out.write("endloop\n".toByteArray())
+ out.write("endfacet\n".toByteArray())
+ }
+ out.write("endsolid vcg\n".toByteArray())
+ out.close()
+ } catch (e: FileNotFoundException) {
+ e.printStackTrace()
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+
+ /**
+ * Return the default point size to use for point clouds
+ * @return default point size used for point clouds
+ */
+ private val defaultPointSize: Float
+ get() = 0.025f
+
+ /**
+ * Create an array of normal vectors from a set of vertices corresponding to triangles
+ *
+ * @param verts vertices to use for computing normals, assumed to be ordered as triangles
+ * @return array of normals
+ */
+ fun makeNormalsFromVertices(verts: ArrayList): FloatArray {
+ val normals = FloatArray(verts.size) // div3 * 3coords
+ var k = 0
+ while (k < verts.size) {
+ val v1 = Vector3f(verts[k].getFloatPosition(0), //
+ verts[k].getFloatPosition(1), //
+ verts[k].getFloatPosition(2))
+ val v2 = Vector3f(verts[k + 1].getFloatPosition(0),
+ verts[k + 1].getFloatPosition(1),
+ verts[k + 1].getFloatPosition(2))
+ val v3 = Vector3f(verts[k + 2].getFloatPosition(0),
+ verts[k + 2].getFloatPosition(1),
+ verts[k + 2].getFloatPosition(2))
+ val a = v2.sub(v1)
+ val b = v3.sub(v1)
+ val n = a.cross(b).normalize()
+ normals[k / 3] = n[0]
+ normals[k / 3 + 1] = n[1]
+ normals[k / 3 + 2] = n[2]
+ k += 3
+ }
+ return normals
+ }
+
+ /**
+ * Open a file specified by the source path. The file can be anything that SciView knows about: mesh, volume, point cloud
+ * @param source string of a data source
+ * @throws IOException
+ */
+ @Suppress("UNCHECKED_CAST")
+ @Throws(IOException::class)
+ fun open(source: String) {
+ if (source.endsWith(".xml")) {
+ addNode(fromXML(source, hub, VolumeViewerOptions()))
+ return
+ }
+ val data = io!!.open(source)
+ if (data is Mesh)
+ addMesh(data)
+ else if (data is graphics.scenery.Mesh)
+ addMesh(data)
+ else if (data is PointCloud)
+ addPointCloud(data)
+ else if (data is Dataset)
+ addVolume(data)
+ else if (data is RandomAccessibleInterval<*>)
+ addVolume(data as RandomAccessibleInterval>, source)
+ else if (data is List<*>) {
+ val list = data
+ require(!list.isEmpty()) { "Data source '$source' appears empty." }
+ val element = list[0]
+ if (element is RealLocalizable) {
+ // NB: For now, we assume all elements will be RealLocalizable.
+ // Highly likely to be the case, barring antagonistic importers.
+ val points = list as List
+ addPointCloud(points, source)
+ } else {
+ val type = if (element == null) "" else element.javaClass.name
+ throw IllegalArgumentException("Data source '" + source + //
+ "' contains elements of unknown type '" + type + "'")
+ }
+ } else {
+ val type = if (data == null) "" else data.javaClass.name
+ throw IllegalArgumentException("Data source '" + source + //
+ "' contains data of unknown type '" + type + "'")
+ }
+ }
+
+ /**
+ * Add the given points to the scene as a PointCloud with a given name
+ * @param points points to use in a PointCloud
+ * @param name name of the PointCloud
+ * @return
+ */
+ @JvmOverloads
+ fun addPointCloud(points: Collection,
+ name: String? = "PointCloud"): Node? {
+ val flatVerts = FloatArray(points.size * 3)
+ var k = 0
+ for (point in points) {
+ flatVerts[k * 3] = point.getFloatPosition(0)
+ flatVerts[k * 3 + 1] = point.getFloatPosition(1)
+ flatVerts[k * 3 + 2] = point.getFloatPosition(2)
+ k++
+ }
+ val pointCloud = PointCloud(defaultPointSize, name!!)
+ val material = Material()
+ val vBuffer: FloatBuffer = BufferUtils.allocateFloat(flatVerts.size * 4)
+ val nBuffer: FloatBuffer = BufferUtils.allocateFloat(0)
+ vBuffer.put(flatVerts)
+ vBuffer.flip()
+ pointCloud.vertices = vBuffer
+ pointCloud.normals = nBuffer
+ pointCloud.indices = BufferUtils.allocateInt(0)
+ pointCloud.setupPointCloud()
+ material.ambient = Vector3f(1.0f, 1.0f, 1.0f)
+ material.diffuse = Vector3f(1.0f, 1.0f, 1.0f)
+ material.specular = Vector3f(1.0f, 1.0f, 1.0f)
+ pointCloud.material = material
+ pointCloud.position = Vector3f(0f, 0f, 0f)
+ return addNode(pointCloud)
+ }
+
+ /**
+ * Add a PointCloud to the scene
+ * @param pointCloud existing PointCloud to add to scene
+ * @return a Node corresponding to the PointCloud
+ */
+ fun addPointCloud(pointCloud: PointCloud): Node? {
+ pointCloud.setupPointCloud()
+ pointCloud.material.ambient = Vector3f(1.0f, 1.0f, 1.0f)
+ pointCloud.material.diffuse = Vector3f(1.0f, 1.0f, 1.0f)
+ pointCloud.material.specular = Vector3f(1.0f, 1.0f, 1.0f)
+ pointCloud.position = Vector3f(0f, 0f, 0f)
+ return addNode(pointCloud)
+ }
+
+ /**
+ * Add Node n to the scene and set it as the active node/publish it to the event service if activePublish is true
+ * @param n node to add to scene
+ * @param activePublish flag to specify whether the node becomes active *and* is published in the inspector/services
+ * @return a Node corresponding to the Node
+ */
+ @JvmOverloads
+ fun addNode(n: Node?, activePublish: Boolean = true): Node? {
+ n?.let {
+ scene.addChild(it)
+ objectService?.addObject(n)
+ if (blockOnNewNodes) {
+ blockWhile({ sciView: SciView -> sciView.find(n.name) == null }, 20)
+ //System.out.println("find(name) " + find(n.getName()) );
+ }
+ // Set new node as active and centered?
+ setActiveNode(n);
+ if (centerOnNewNodes) {
+ centerOnNode(n)
+ }
+ if (activePublish) {
+ eventService?.publish(NodeAddedEvent(n));
+ }
+ }
+ return n;
+ }
+
+ /**
+ * Add a scenery Mesh to the scene
+ * @param scMesh scenery mesh to add to scene
+ * @return a Node corresponding to the mesh
+ */
+ fun addMesh(scMesh: graphics.scenery.Mesh): Node? {
+ val material = Material()
+ material.ambient = Vector3f(1.0f, 0.0f, 0.0f)
+ material.diffuse = Vector3f(0.0f, 1.0f, 0.0f)
+ material.specular = Vector3f(1.0f, 1.0f, 1.0f)
+ scMesh.material = material
+ scMesh.position = Vector3f(0.0f, 0.0f, 0.0f)
+ objectService?.addObject(scMesh)
+ return addNode(scMesh)
+ }
+
+ /**
+ * Add an ImageJ mesh to the scene
+ * @param mesh net.imagej.mesh to add to scene
+ * @return a Node corresponding to the mesh
+ */
+ fun addMesh(mesh: Mesh): Node? {
+ val scMesh = MeshConverter.toScenery(mesh)
+ return addMesh(scMesh)
+ }
+
+ /**
+ * [Deprecated: use deleteNode]
+ * Remove a Mesh from the scene
+ * @param scMesh mesh to remove from scene
+ */
+ fun removeMesh(scMesh: graphics.scenery.Mesh?) {
+ scene.removeChild(scMesh!!)
+ }
+
+ /**
+ * Set the currently active node
+ * @param n existing node that should become active focus of this SciView
+ * @return the currently active node
+ */
+ fun setActiveNode(n: Node?): Node? {
+ if (activeNode === n) return activeNode
+ activeNode = n
+ targetArcball.target = { n?.getMaximumBoundingBox()?.getBoundingSphere()?.origin ?: Vector3f(0.0f, 0.0f, 0.0f) }
+ nodePropertyEditor?.trySelectNode(activeNode);
+ eventService!!.publish(NodeActivatedEvent(activeNode))
+ return activeNode
+ }
+
+ @Suppress("UNUSED_PARAMETER")
+ @EventHandler
+ protected fun onNodeAdded(event: NodeAddedEvent?) {
+ nodePropertyEditor!!.rebuildTree()
+ }
+
+ @Suppress("UNUSED_PARAMETER")
+ @EventHandler
+ protected fun onNodeRemoved(event: NodeRemovedEvent?) {
+ nodePropertyEditor!!.rebuildTree()
+ }
+
+ @Suppress("UNUSED_PARAMETER")
+ @EventHandler
+ protected fun onNodeChanged(event: NodeChangedEvent?) {
+ nodePropertyEditor!!.rebuildTree()
+ }
+
+ @Suppress("UNUSED_PARAMETER")
+ @EventHandler
+ protected fun onNodeActivated(event: NodeActivatedEvent?) {
+ // TODO: add listener code for node activation, if necessary
+ // NOTE: do not update property window here, this will lead to a loop.
+ }
+
+ fun toggleInspectorWindow() {
+ toggleSidebar()
+ }
+
+ @Suppress("UNUSED_PARAMETER")
+ fun setInspectorWindowVisibility(visible: Boolean) {
+// inspector.setVisible(visible);
+// if( visible )
+// mainSplitPane.setDividerLocation(getWindowWidth()/4 * 3);
+// else
+// mainSplitPane.setDividerLocation(getWindowWidth());
+ }
+
+ @Suppress("UNUSED_PARAMETER")
+ fun setInterpreterWindowVisibility(visible: Boolean) {
+// interpreterPane.getComponent().setVisible(visible);
+// if( visible )
+// interpreterSplitPane.setDividerLocation(getWindowHeight()/10 * 6);
+// else
+// interpreterSplitPane.setDividerLocation(getWindowHeight());
+ }
+
+ /**
+ * Create an animation thread with the given fps speed and the specified action
+ * @param fps frames per second at which this action should be run
+ * @param action Runnable that contains code to run fps times per second
+ * @return a Future corresponding to the thread
+ */
+ @Synchronized
+ fun animate(fps: Int, action: Runnable): Future<*> {
+ // TODO: Make animation speed less laggy and more accurate.
+ val delay = 1000 / fps
+ val thread = threadService!!.run {
+ while (animating) {
+ action.run()
+ try {
+ Thread.sleep(delay.toLong())
+ } catch (e: InterruptedException) {
+ break
+ }
+ }
+ }
+ animations!!.add(thread)
+ animating = true
+ return thread
+ }
+
+ /**
+ * Stop all animations
+ */
+ @Synchronized
+ fun stopAnimation() {
+ animating = false
+ while (!animations!!.isEmpty()) {
+ animations!!.peek().cancel(true)
+ animations!!.remove()
+ }
+ }
+
+ /**
+ * Take a screenshot and save it to the default scenery location
+ */
+ fun takeScreenshot() {
+ renderer!!.screenshot()
+ }
+
+ /**
+ * Take a screenshot and save it to the specified path
+ * @param path path for saving the screenshot
+ */
+ fun takeScreenshot(path: String?) {
+ renderer!!.screenshot(path!!, false)
+ }
+
+ /**
+ * Take a screenshot and return it as an Img
+ * @return an Img of type UnsignedByteType
+ */
+ val screenshot: Img?
+ get() {
+ val screenshot = getSceneryRenderer()!!.requestScreenshot()
+ val image = BufferedImage(screenshot.width, screenshot.height, BufferedImage.TYPE_4BYTE_ABGR)
+ val imgData = (image.raster.dataBuffer as DataBufferByte).data
+ System.arraycopy(screenshot.data, 0, imgData, 0, screenshot.data!!.size)
+ var img: Img? = null
+ try {
+ val tmpFile = File.createTempFile("sciview-", "-tmp.png")
+ ImageIO.write(image, "png", tmpFile)
+ @Suppress("UNCHECKED_CAST")
+ img = io!!.open(tmpFile.absolutePath) as Img
+ tmpFile.delete()
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ return img
+ }
+
+ /**
+ * Take a screenshot and return it as an Img
+ * @return an Img of type UnsignedByteType
+ */
+ val aRGBScreenshot: Img
+ get() {
+ val screenshot = screenshot
+ return Utils.convertToARGB(screenshot)
+ }
+
+ /**
+ * @param name The name of the node to find.
+ * @return the node object or null, if the node has not been found.
+ */
+ fun find(name: String): Node? {
+ val n = scene.find(name)
+ if (n == null) {
+ logger.warn("Node with name $name not found.")
+ }
+ return n
+ }
+
+ /**
+ * @return an array of all nodes in the scene except Cameras and PointLights
+ */
+ val sceneNodes: Array
+ get() = getSceneNodes { n: Node? -> n !is Camera && n !is PointLight }
+
+ /**
+ * Get a list of nodes filtered by filter predicate
+ * @param filter, a predicate that filters the candidate nodes
+ * @return all nodes that match the predicate
+ */
+ fun getSceneNodes(filter: Predicate): Array {
+ return scene.children.filter{ filter.test(it) }.toTypedArray()
+ }
+
+ /**
+ * @return an array of all Node's in the scene
+ */
+ val allSceneNodes: Array
+ get() = getSceneNodes { _: Node? -> true }
+
+ /**
+ * Delete the current active node
+ */
+ fun deleteActiveNode() {
+ deleteNode(activeNode)
+ }
+ /**
+ * Delete a specified node and control whether the event is published
+ * @param node node to delete from scene
+ * @param activePublish whether the deletion should be published
+ */
+ /**
+ * Delete the specified node, this event is published
+ * @param node node to delete from scene
+ */
+ @JvmOverloads
+ fun deleteNode(node: Node?, activePublish: Boolean = true) {
+ for (child in node!!.children) {
+ deleteNode(child, activePublish)
+ }
+ objectService?.removeObject(node);
+ node.parent?.removeChild(node);
+ if (activeNode == node) {
+ setActiveNode(null)
+ }
+ //maintain consistency
+ if( activePublish ) {
+ eventService?.publish(NodeRemovedEvent(node))
+ };
+ }
+
+ /**
+ * Dispose the current scenery renderer, hub, and other scenery things
+ */
+ fun dispose() {
+ val objs: List = objectService!!.getObjects(Node::class.java)
+ for (obj in objs) {
+ objectService.removeObject(obj)
+ }
+ scijavaContext!!.service(SciViewService::class.java).close(this)
+ close()
+ }
+
+ override fun close() {
+ super.close()
+ frame!!.dispose()
+ }
+
+ /**
+ * Move the current active camera to the specified position
+ * @param position position to move the camera to
+ */
+ fun moveCamera(position: FloatArray) {
+ camera!!.position = Vector3f(position[0], position[1], position[2])
+ }
+
+ /**
+ * Move the current active camera to the specified position
+ * @param position position to move the camera to
+ */
+ fun moveCamera(position: DoubleArray) {
+ camera!!.position = Vector3f(position[0].toFloat(), position[1].toFloat(), position[2].toFloat())
+ }
+
+ /**
+ * Get the current application name
+ * @return a String of the application name
+ */
+ fun getName(): String {
+ return applicationName
+ }
+
+ /**
+ * Add a child to the scene. you probably want addNode
+ * @param node node to add as a child to the scene
+ */
+ fun addChild(node: Node?) {
+ scene.addChild(node!!)
+ }
+
+ /**
+ * Add a Dataset to the scene as a volume. Voxel resolution and name are extracted from the Dataset itself
+ * @param image image to add as a volume
+ * @return a Node corresponding to the Volume
+ */
+ fun addVolume(image: Dataset): Node? {
+ val voxelDims = FloatArray(image.numDimensions())
+ for (d in voxelDims.indices) {
+ val inValue = image.axis(d).averageScale(0.0, 1.0)
+ if (image.axis(d).unit() == null) voxelDims[d] = inValue.toFloat() else voxelDims[d] = unitService!!.value(inValue, image.axis(d).unit(), axis(d)!!.unit()).toFloat()
+ }
+ return addVolume(image, voxelDims)
+ }
+
+ /**
+ * Add a Dataset as a Volume with the specified voxel dimensions
+ * @param image image to add as a volume
+ * @param voxelDimensions dimensions of voxels in volume
+ * @return a Node corresponding to the Volume
+ */
+ @Suppress("UNCHECKED_CAST")
+ fun addVolume(image: Dataset, voxelDimensions: FloatArray): Node? {
+ return addVolume>(image.imgPlus as RandomAccessibleInterval>, image.name,
+ *voxelDimensions)
+ }
+
+// /**
+// * Add a RandomAccessibleInterval to the image
+// * @param image image to add as a volume
+// * @param name name of image
+// * @param extra, kludge argument to prevent matching issues
+// * @param pixel type of image
+// * @return a Node corresponding to the volume
+// */
+// fun ?> addVolume(image: RandomAccessibleInterval, name: String?, extra: String?): Node {
+// return addVolume(image, name, 1f, 1f, 1f)
+// }
+
+ /**
+ * Add a RandomAccessibleInterval to the image
+ * @param image image to add as a volume
+ * @param pixel type of image
+ * @return a Node corresponding to the volume
+ */
+ fun > addVolume(image: RandomAccessibleInterval, name: String?): Node? {
+ return addVolume(image, name, 1f, 1f, 1f)
+ }
+
+ /**
+ * Add a RandomAccessibleInterval to the image
+ * @param image image to add as a volume
+ * @param pixel type of image
+ * @return a Node corresponding to the volume
+ */
+ fun > addVolume(image: RandomAccessibleInterval, voxelDimensions: FloatArray): Node? {
+ return addVolume(image, "volume", *voxelDimensions)
+ }
+
+ /**
+ * Add an IterableInterval as a Volume
+ * @param image
+ * @param
+ * @return a Node corresponding to the Volume
+ */
+ @Suppress("UNCHECKED_CAST")
+ @Throws(Exception::class)
+ fun ?> addVolume(image: IterableInterval): Node? {
+ return if (image is RandomAccessibleInterval<*>) {
+ addVolume(image as RandomAccessibleInterval>, "Volume")
+ } else {
+ throw Exception("Unsupported Volume type:$image")
+ }
+ }
+
+ /**
+ * Add an IterableInterval as a Volume
+ * @param image image to add as a volume
+ * @param name name of image
+ * @param pixel type of image
+ * @return a Node corresponding to the Volume
+ */
+ @Suppress("UNCHECKED_CAST")
+ @Throws(Exception::class)
+ fun ?> addVolume(image: IterableInterval, name: String?): Node? {
+ return if (image is RandomAccessibleInterval<*>) {
+ addVolume(image as RandomAccessibleInterval>, name, 1f, 1f, 1f)
+ } else {
+ throw Exception("Unsupported Volume type:$image")
+ }
+ }
+
+ /**
+ * Set the colormap using an ImageJ LUT name
+ * @param n node to apply colormap to
+ * @param lutName name of LUT according to imagej LUTService
+ */
+ fun setColormap(n: Node, lutName: String?) {
+ try {
+ setColormap(n, lutService!!.loadLUT(lutService.findLUTs()[lutName]))
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+
+ /**
+ * Set the ColorMap of node n to the supplied colorTable
+ * @param n node to apply colortable to
+ * @param colorTable ColorTable to use
+ */
+ fun setColormap(n: Node, colorTable: ColorTable) {
+ val copies = 16
+ val byteBuffer = ByteBuffer.allocateDirect(
+ 4 * colorTable.length * copies) // Num bytes * num components * color map length * height of color map texture
+ val tmp = ByteArray(4 * colorTable.length)
+ for (k in 0 until colorTable.length) {
+ for (c in 0 until colorTable.componentCount) {
+ // TODO this assumes numBits is 8, could be 16
+ tmp[4 * k + c] = colorTable[c, k].toByte()
+ }
+ if (colorTable.componentCount == 3) {
+ tmp[4 * k + 3] = 255.toByte()
+ }
+ }
+ for (i in 0 until copies) {
+ byteBuffer.put(tmp)
+ }
+ byteBuffer.flip()
+ n.metadata["sciviewColormap"] = colorTable
+ if (n is Volume) {
+ n.colormap = Colormap.fromColorTable(colorTable)
+ n.dirty = true
+ n.needsUpdate = true
+ }
+ }
+
+ /**
+ * Adss a SourceAndConverter to the scene.
+ *
+ * @param sac The SourceAndConverter to add
+ * @param name Name of the dataset
+ * @param voxelDimensions Array with voxel dimensions.
+ * @param Type of the dataset.
+ * @return THe node corresponding to the volume just added.
+ */
+ fun > addVolume(sac: SourceAndConverter,
+ numTimepoints: Int,
+ name: String?,
+ vararg voxelDimensions: Float): Node? {
+ val sources: MutableList> = ArrayList()
+ sources.add(sac)
+ return addVolume(sources, numTimepoints, name, *voxelDimensions)
+ }
+
+ /**
+ * Add an IterableInterval to the image with the specified voxelDimensions and name
+ * This version of addVolume does most of the work
+ * @param image image to add as a volume
+ * @param name name of image
+ * @param voxelDimensions dimensions of voxel in volume
+ * @param pixel type of image
+ * @return a Node corresponding to the Volume
+ */
+ fun > addVolume(image: RandomAccessibleInterval, name: String?,
+ vararg voxelDimensions: Float): Node? {
+ //log.debug( "Add Volume " + name + " image: " + image );
+ val dimensions = LongArray(image.numDimensions())
+ image.dimensions(dimensions)
+ val minPt = LongArray(image.numDimensions())
+
+ // Get type at min point
+ val imageRA = image.randomAccess()
+ image.min(minPt)
+ imageRA.setPosition(minPt)
+ val voxelType = imageRA.get()!!.createVariable()
+ val converterSetups: ArrayList = ArrayList()
+ val stacks = AxisOrder.splitInputStackIntoSourceStacks(image, AxisOrder.getAxisOrder(AxisOrder.DEFAULT, image, false))
+ val sourceTransform = AffineTransform3D()
+ val sources: ArrayList> = ArrayList>()
+ var numTimepoints = 1
+ for (stack in stacks) {
+ var s: Source
+ if (stack.numDimensions() > 3) {
+ numTimepoints = (stack.max(3) + 1).toInt()
+ s = RandomAccessibleIntervalSource4D(stack, voxelType, sourceTransform, name)
+ } else {
+ s = RandomAccessibleIntervalSource(stack, voxelType, sourceTransform, name)
+ }
+ val source = BigDataViewer.wrapWithTransformedSource(
+ SourceAndConverter(s, BigDataViewer.createConverterToARGB(voxelType)))
+ converterSetups.add(BigDataViewer.createConverterSetup(source, setupId.getAndIncrement()))
+ sources.add(source)
+ }
+ val v = addVolume(sources, numTimepoints, name, *voxelDimensions)
+ v?.metadata?.set("RandomAccessibleInterval", image)
+ return v
+ }
+
+ /**
+ * Adds a SourceAndConverter to the scene.
+ *
+ * This method actually instantiates the volume.
+ *
+ * @param sources The list of SourceAndConverter to add
+ * @param name Name of the dataset
+ * @param voxelDimensions Array with voxel dimensions.
+ * @param Type of the dataset.
+ * @return THe node corresponding to the volume just added.
+ */
+ @Suppress("UNCHECKED_CAST")
+ fun > addVolume(sources: List>,
+ converterSetups: ArrayList?,
+ numTimepoints: Int,
+ name: String?,
+ vararg voxelDimensions: Float): Node? {
+ var timepoints = numTimepoints
+ var cacheControl: CacheControl? = null
+
+// RandomAccessibleInterval image =
+// ((RandomAccessibleIntervalSource4D) sources.get(0).getSpimSource()).
+// .getSource(0, 0);
+ val image = sources[0].spimSource.getSource(0, 0)
+ if (image is VolatileView<*, *>) {
+ val viewData = (image as VolatileView?>).volatileViewData
+ cacheControl = viewData.cacheControl
+ }
+ val dimensions = LongArray(image.numDimensions())
+ image.dimensions(dimensions)
+ val minPt = LongArray(image.numDimensions())
+
+ // Get type at min point
+ val imageRA = image.randomAccess()
+ image.min(minPt)
+ imageRA.setPosition(minPt)
+ val voxelType = imageRA.get()!!.createVariable() as T
+ println("addVolume " + image.numDimensions() + " interval " + image as Interval)
+
+ //int numTimepoints = 1;
+ if (image.numDimensions() > 3) {
+ timepoints = image.dimension(3).toInt()
+ }
+ val ds = RAISource(voxelType, sources, converterSetups!!, timepoints, cacheControl)
+ val options = VolumeViewerOptions()
+ val v: Volume = RAIVolume(ds, options, hub)
+ v.name = name!!
+ v.metadata["sources"] = sources
+ v.metadata["VoxelDimensions"] = voxelDimensions
+ val tf = v.transferFunction
+ val rampMin = 0f
+ val rampMax = 0.1f
+ tf.clear()
+ tf.addControlPoint(0.0f, 0.0f)
+ tf.addControlPoint(rampMin, 0.0f)
+ tf.addControlPoint(1.0f, rampMax)
+ val bg = BoundingGrid()
+ bg.node = v
+ return addNode(v)
+ }
+
+ /**
+ * Block while predicate is true
+ *
+ * @param predicate predicate function that returns true as long as this function should block
+ * @param waitTime wait time before predicate re-evaluation
+ */
+ private fun blockWhile(predicate: Function, waitTime: Int) {
+ while (predicate.apply(this)) {
+ try {
+ Thread.sleep(waitTime.toLong())
+ } catch (e: InterruptedException) {
+ e.printStackTrace()
+ }
+ }
+ }
+
+ /**
+ * Adds a SourceAndConverter to the scene.
+ *
+ * @param sources The list of SourceAndConverter to add
+ * @param name Name of the dataset
+ * @param voxelDimensions Array with voxel dimensions.
+ * @param Type of the dataset.
+ * @return THe node corresponding to the volume just added.
+ */
+ fun > addVolume(sources: List>,
+ numTimepoints: Int,
+ name: String?,
+ vararg voxelDimensions: Float): Node? {
+ var setupId = 0
+ val converterSetups = ArrayList()
+ for (source in sources) {
+ converterSetups.add(BigDataViewer.createConverterSetup(source, setupId++))
+ }
+ return addVolume(sources, converterSetups, numTimepoints, name, *voxelDimensions)
+ }
+
+ /**
+ * Update a volume with the given IterableInterval.
+ * This method actually populates the volume
+ * @param image image to update into volume
+ * @param name name of image
+ * @param voxelDimensions dimensions of voxel in volume
+ * @param v existing volume to update
+ * @param pixel type of image
+ * @return a Node corresponding to the input volume
+ */
+ @Suppress("UNCHECKED_CAST")
+ fun > updateVolume(image: IterableInterval, name: String,
+ voxelDimensions: FloatArray, v: Volume): Node {
+ val sacs = v.metadata["sources"] as List>?
+ val source = sacs!![0].spimSource.getSource(0, 0) // hard coded to timepoint and mipmap 0
+ val sCur = Views.iterable(source).cursor()
+ val iCur = image.cursor()
+ while (sCur.hasNext()) {
+ sCur.fwd()
+ iCur.fwd()
+ sCur.get()!!.set(iCur.get())
+ }
+ v.name = name
+ v.metadata["VoxelDimensions"] = voxelDimensions
+ v.volumeManager.notifyUpdate(v)
+ v.volumeManager.requestRepaint()
+ //v.getCacheControls().clear();
+ //v.setDirty( true );
+ v.needsUpdate = true
+ //v.setNeedsUpdateWorld( true );
+ return v
+ }
+
+ /**
+ *
+ * @return whether PushMode is currently active
+ */
+ fun getPushMode(): Boolean {
+ return renderer!!.pushMode
+ }
+
+ /**
+ * Set the status of PushMode, which only updates the render panel when there is a change in the scene
+ * @param push true if push mode should be used
+ * @return current PushMode status
+ */
+ fun setPushMode(push: Boolean): Boolean {
+ renderer!!.pushMode = push
+ return renderer!!.pushMode
+ }
+
+ protected fun finalize() {
+ stopAnimation()
+ }
+
+ fun getScenerySettings(): Settings {
+ return settings
+ }
+
+ fun getSceneryStatistics(): Statistics {
+ return stats
+ }
+
+ fun getSceneryRenderer(): Renderer? {
+ return renderer
+ }
+
+ /**
+ * Enable VR rendering
+ */
+ fun toggleVRRendering() {
+ vrActive = !vrActive
+ val cam = scene.activeObserver as? DetachedHeadCamera ?: return
+ var ti: TrackerInput? = null
+ var hmdAdded = false
+ if (!hub.has(SceneryElement.HMDInput)) {
+ try {
+ val hmd = OpenVRHMD(false, true)
+ if (hmd.initializedAndWorking()) {
+ hub.add(SceneryElement.HMDInput, hmd)
+ ti = hmd
+ } else {
+ logger.warn("Could not initialise VR headset, just activating stereo rendering.")
+ }
+ hmdAdded = true
+ } catch (e: Exception) {
+ logger.error("Could not add OpenVRHMD: $e")
+ }
+ } else {
+ ti = hub.getWorkingHMD()
+ }
+ if (vrActive && ti != null) {
+ cam.tracker = ti
+ } else {
+ cam.tracker = null
+ }
+ renderer!!.pushMode = false
+ // we need to force reloading the renderer as the HMD might require device or instance extensions
+ if (renderer is VulkanRenderer && hmdAdded) {
+ replaceRenderer((renderer as VulkanRenderer).javaClass.simpleName, true, true)
+ (renderer as VulkanRenderer).toggleVR()
+ while (!(renderer as VulkanRenderer).initialized /* || !getRenderer().getFirstImageReady()*/) {
+ logger.debug("Waiting for renderer reinitialisation")
+ try {
+ Thread.sleep(200)
+ } catch (e: InterruptedException) {
+ e.printStackTrace()
+ }
+ }
+ } else {
+ renderer!!.toggleVR()
+ }
+ }
+
+ /**
+ * Set the rotation of Node N by generating a quaternion from the supplied arguments
+ * @param n node to set rotation for
+ * @param x x coord of rotation quat
+ * @param y y coord of rotation quat
+ * @param z z coord of rotation quat
+ * @param w w coord of rotation quat
+ */
+ fun setRotation(n: Node, x: Float, y: Float, z: Float, w: Float) {
+ n.rotation = Quaternionf(x, y, z, w)
+ }
+
+ fun setScale(n: Node, x: Float, y: Float, z: Float) {
+ n.scale = Vector3f(x, y, z)
+ }
+
+ @Suppress("UNUSED_PARAMETER")
+ fun setColor(n: Node, x: Float, y: Float, z: Float, w: Float) {
+ val col = Vector3f(x, y, z)
+ n.material.ambient = col
+ n.material.diffuse = col
+ n.material.specular = col
+ }
+
+ fun setPosition(n: Node, x: Float, y: Float, z: Float) {
+ n.position = Vector3f(x, y, z)
+ }
+
+ fun addWindowListener(wl: WindowListener?) {
+ frame!!.addWindowListener(wl)
+ }
+
+ override fun axis(i: Int): CalibratedAxis? {
+ return axes[i]
+ }
+
+ override fun axes(calibratedAxes: Array) {
+ axes = calibratedAxes
+ }
+
+ override fun setAxis(calibratedAxis: CalibratedAxis, i: Int) {
+ axes[i] = calibratedAxis
+ }
+
+ override fun realMin(i: Int): Double {
+ return Double.NEGATIVE_INFINITY
+ }
+
+ override fun realMin(doubles: DoubleArray) {
+ for (i in doubles.indices) {
+ doubles[i] = Double.NEGATIVE_INFINITY
+ }
+ }
+
+ override fun realMin(realPositionable: RealPositionable) {
+ for (i in 0 until realPositionable.numDimensions()) {
+ realPositionable.move(Double.NEGATIVE_INFINITY, i)
+ }
+ }
+
+ override fun realMax(i: Int): Double {
+ return Double.POSITIVE_INFINITY
+ }
+
+ override fun realMax(doubles: DoubleArray) {
+ for (i in doubles.indices) {
+ doubles[i] = Double.POSITIVE_INFINITY
+ }
+ }
+
+ override fun realMax(realPositionable: RealPositionable) {
+ for (i in 0 until realPositionable.numDimensions()) {
+ realPositionable.move(Double.POSITIVE_INFINITY, i)
+ }
+ }
+
+ override fun numDimensions(): Int {
+ return axes.size
+ }
+
+ fun setActiveObserver(screenshotCam: Camera?) {
+ scene.activeObserver = screenshotCam
+ }
+
+ fun getActiveObserver(): Camera? {
+ return scene.activeObserver
+ }
+
+ inner class TransparentSlider : JSlider() {
+ override fun paintComponent(g: Graphics) {
+ val g2d = g.create() as Graphics2D
+ g2d.color = background
+ g2d.composite = AlphaComposite.SrcOver.derive(0.9f)
+ g2d.fillRect(0, 0, width, height)
+ g2d.dispose()
+ super.paintComponent(g)
+ }
+
+ init {
+ // Important, we taking over the filling of the
+ // component...
+ isOpaque = false
+ background = Color.DARK_GRAY
+ foreground = Color.LIGHT_GRAY
+ }
+ }
+
+ internal inner class showHelpDisplay : ClickBehaviour {
+ override fun click(x: Int, y: Int) {
+ scijavaContext?.getService(CommandService::class.java)?.run(Help::class.java, true)
+ }
+ }
+
+ /**
+ * Return a list of all nodes that match a given predicate function
+ * @param nodeMatchPredicate, returns true if a node is a match
+ * @return list of nodes that match the predicate
+ */
+ fun findNodes(nodeMatchPredicate: Function1): List {
+ return scene.discover(scene, nodeMatchPredicate, false)
+ }
+
+ /*
+ * Convenience function for getting a string of info about a Node
+ */
+ fun nodeInfoString(n: Node): String {
+ return "Node name: " + n.name + " Node type: " + n.nodeType + " To String: " + n
+ }
+
+ companion object {
+ //bounds for the controls
+ @JvmField
+ val FPSSPEED_MINBOUND_SLOW = 0.01f
+ @JvmField
+ val FPSSPEED_MAXBOUND_SLOW = 30.0f
+ @JvmField
+ val FPSSPEED_MINBOUND_FAST = 0.2f
+ @JvmField
+ val FPSSPEED_MAXBOUND_FAST = 600f
+ @JvmField
+ val FPSSPEED_MINBOUND_VERYFAST = 10f
+ @JvmField
+ val FPSSPEED_MAXBOUND_VERYFAST = 2000f
+
+ @JvmField
+ val MOUSESPEED_MINBOUND = 0.1f
+ @JvmField
+ val MOUSESPEED_MAXBOUND = 3.0f
+ @JvmField
+ val MOUSESCROLL_MINBOUND = 0.3f
+ @JvmField
+ val MOUSESCROLL_MAXBOUND = 10.0f
+
+ @JvmField
+ val DEFAULT_COLOR = Colors.LIGHTGRAY
+
+ /**
+ * Utility function to generate GLVector in cases like usage from Python
+ * @param x x coord
+ * @param y y coord
+ * @param z z coord
+ * @return a GLVector of x,y,z
+ */
+ fun getGLVector(x: Float, y: Float, z: Float): GLVector {
+ return GLVector(x, y, z)
+ }
+
+ /**
+ * Static launching method
+ *
+ * @return a newly created SciView
+ */
+ @JvmStatic
+ @Throws(Exception::class)
+ fun create(): SciView {
+ xinitThreads()
+ FlatLightLaf.install()
+ try {
+ UIManager.setLookAndFeel(FlatLightLaf())
+ } catch (ex: Exception) {
+ System.err.println("Failed to initialize Flat Light LaF, falling back to Swing default.")
+ }
+ System.setProperty("scijava.log.level:sc.iview", "debug")
+ val context = Context(ImageJService::class.java, SciJavaService::class.java, SCIFIOService::class.java, ThreadService::class.java)
+ val sciViewService = context.service(SciViewService::class.java)
+ return sciViewService.orCreateActiveSciView
+ }
+
+ /**
+ * Static launching method
+ * DEPRECATED use SciView.create() instead
+ *
+ * @return a newly created SciView
+ */
+ @Deprecated("")
+ @Throws(Exception::class)
+ fun createSciView(): SciView {
+ return create()
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/LaunchViewer.java b/src/main/java/sc/iview/commands/LaunchViewer.java
deleted file mode 100644
index bbbab351..00000000
--- a/src/main/java/sc/iview/commands/LaunchViewer.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*-
- * #%L
- * Scenery-backed 3D visualization package for ImageJ.
- * %%
- * Copyright (C) 2016 - 2020 SciView developers.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-package sc.iview.commands;
-
-import org.scijava.ItemIO;
-import org.scijava.command.Command;
-import org.scijava.display.DisplayService;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-import org.scijava.ui.UIService;
-
-import sc.iview.SciView;
-import sc.iview.SciViewService;
-import sc.iview.display.SciViewDisplay;
-
-/**
- * Command to launch SciView
- *
- * @author Kyle Harrington
- *
- */
-@Plugin(type = Command.class, menuPath = "Plugins>SciView")
-public class LaunchViewer implements Command {
-
- @Parameter
- private DisplayService displayService;
-
- @Parameter
- private SciViewService sciViewService;
-
- @Parameter(required = false)
- private UIService uiService;
-
- @Parameter(type = ItemIO.OUTPUT)
- private SciView sciView = null;
-
- @Override
- public void run() {
- final SciViewDisplay display = displayService.getActiveDisplay(SciViewDisplay.class);
- try {
- if (display == null) {
- sciView = sciViewService.getOrCreateActiveSciView();
- }
- else
- sciViewService.createSciView();
- } catch (Exception e) {
- e.printStackTrace();
- }
-
-// else if (uiService != null)
-// uiService.showDialog( "The SciView window is already open. For now, only one SciView window is supported.", "SciView" );
- }
-
-}
diff --git a/src/main/java/sc/iview/commands/LaunchViewer.kt b/src/main/java/sc/iview/commands/LaunchViewer.kt
new file mode 100644
index 00000000..142f3ff4
--- /dev/null
+++ b/src/main/java/sc/iview/commands/LaunchViewer.kt
@@ -0,0 +1,67 @@
+/*-
+ * #%L
+ * Scenery-backed 3D visualization package for ImageJ.
+ * %%
+ * Copyright (C) 2016 - 2020 SciView developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package sc.iview.commands
+
+import org.scijava.ItemIO
+import org.scijava.command.Command
+import org.scijava.display.DisplayService
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import org.scijava.ui.UIService
+import sc.iview.SciView
+import sc.iview.SciViewService
+import sc.iview.display.SciViewDisplay
+
+/**
+ * Command to launch SciView
+ *
+ * @author Kyle Harrington
+ */
+@Plugin(type = Command::class, menuPath = "Plugins>SciView")
+class LaunchViewer : Command {
+ @Parameter
+ private lateinit var displayService: DisplayService
+
+ @Parameter
+ private lateinit var sciViewService: SciViewService
+
+ @Parameter(type = ItemIO.OUTPUT)
+ private var sciView: SciView? = null
+ override fun run() {
+ val display = displayService.getActiveDisplay(SciViewDisplay::class.java)
+ try {
+ if (display == null) {
+ sciView = sciViewService.orCreateActiveSciView
+ } else sciViewService.createSciView()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/MenuWeights.java b/src/main/java/sc/iview/commands/MenuWeights.java
deleted file mode 100644
index e737709b..00000000
--- a/src/main/java/sc/iview/commands/MenuWeights.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*-
- * #%L
- * Scenery-backed 3D visualization package for ImageJ.
- * %%
- * Copyright (C) 2016 - 2020 SciView developers.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-package sc.iview.commands;
-
-/**
- * Constants for coherent menu ordering.
- *
- * @author Curtis Rueden
- * @author Kyle Harrington
- */
-public final class MenuWeights {
- private MenuWeights() {
- // NB: Prevent instantiation of utility class.
- }
-
- public static final double FILE = 0;
- public static final double EDIT = 1;
- public static final double PROCESS = 2;
- public static final double VIEW = 3;
- public static final double DEMO = 4;
- public static final double HELP = 4;
-
- public static final double FILE_OPEN = 0;
- public static final double FILE_EXPORT_STL = 100;
-
- public static final double EDIT_ADD_BOX = 0;
- public static final double EDIT_ADD_SPHERE = 1;
- public static final double EDIT_ADD_LINE = 2;
- public static final double EDIT_ADD_POINT_LIGHT = 3;
- public static final double EDIT_ADD_LABEL_IMAGE = 4;
- public static final double EDIT_ADD_VOLUME = 5;
- public static final double EDIT_ADD_CAMERA = 6;
- public static final double EDIT_ADD_COMPASS = 49;
- public static final double EDIT_TOGGLE_FLOOR = 50;
- public static final double EDIT_DELETE_OBJECT = 100;
- public static final double EDIT_SCIVIEW_SETTINGS = 200;
-
- public static final double PROCESS_ISOSURFACE = 0;
- public static final double PROCESS_CONVEX_HULL = 1;
- public static final double PROCESS_MESH_TO_IMAGE = 2;
- public static final double PROCESS_INTERACTIVE_CONVEX_MESH = 3;
- public static final double PROCESS_DRAW_LINES = 4;
-
- public static final double VIEW_ROTATE = 0;
- public static final double VIEW_STOP_ANIMATION = 1;
- public static final double VIEW_TOGGLE_UNLIMITED_FRAMERATE = 2;
- public static final double VIEW_SET_SUPERSAMPLING_FACTOR = 3;
- public static final double VIEW_SET_FAR_PLANE = 4;
- public static final double VIEW_START_RECORDING_VIDEO = 98;
- public static final double VIEW_STOP_RECORDING_VIDEO = 99;
- public static final double VIEW_SCREENSHOT = 100;
- public static final double VIEW_SET_LUT = 101;
- public static final double VIEW_TOGGLE_BOUNDING_GRID = 102;
- public static final double VIEW_CENTER_ON_ACTIVE_NODE = 103;
- public static final double VIEW_RESET_CAMERA_ROTATION = 202;
- public static final double VIEW_RESET_CAMERA_POSITION = 203;
- public static final double VIEW_SAVE_CAMERA_CONFIGURATION = 204;
- public static final double VIEW_TOGGLE_INSPECTOR = 302;
- public static final double VIEW_RENDER_TO_OPENVR = 303;
- public static final double VIEW_SET_TRANSFER_FUNCTION = 400;
-
-
- public static final double DEMO_LINES = 0;
- public static final double DEMO_MESH = 1;
- public static final double DEMO_MESH_TEXTURE = 2;
- public static final double DEMO_VOLUME_RENDER = 3;
- public static final double DEMO_GAME_OF_LIFE = 4;
- public static final double DEMO_TEXT = 5;
- public static final double DEMO_EMBRYO = 6;
-
- public static final double HELP_HELP = 0;
- public static final double HELP_ABOUT = 200;
-}
diff --git a/src/main/java/sc/iview/commands/MenuWeights.kt b/src/main/java/sc/iview/commands/MenuWeights.kt
new file mode 100644
index 00000000..bcbfd18b
--- /dev/null
+++ b/src/main/java/sc/iview/commands/MenuWeights.kt
@@ -0,0 +1,88 @@
+/*-
+ * #%L
+ * Scenery-backed 3D visualization package for ImageJ.
+ * %%
+ * Copyright (C) 2016 - 2020 SciView developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package sc.iview.commands
+
+/**
+ * Constants for coherent menu ordering.
+ *
+ * @author Curtis Rueden
+ * @author Kyle Harrington
+ */
+object MenuWeights {
+ const val FILE = 0.0
+ const val EDIT = 1.0
+ const val PROCESS = 2.0
+ const val VIEW = 3.0
+ const val DEMO = 4.0
+ const val HELP = 4.0
+ const val FILE_OPEN = 0.0
+ const val FILE_EXPORT_STL = 100.0
+ const val EDIT_ADD_BOX = 0.0
+ const val EDIT_ADD_SPHERE = 1.0
+ const val EDIT_ADD_LINE = 2.0
+ const val EDIT_ADD_POINT_LIGHT = 3.0
+ const val EDIT_ADD_LABEL_IMAGE = 4.0
+ const val EDIT_ADD_VOLUME = 5.0
+ const val EDIT_ADD_CAMERA = 6.0
+ const val EDIT_ADD_COMPASS = 49.0
+ const val EDIT_TOGGLE_FLOOR = 50.0
+ const val EDIT_DELETE_OBJECT = 100.0
+ const val EDIT_SCIVIEW_SETTINGS = 200.0
+ const val PROCESS_ISOSURFACE = 0.0
+ const val PROCESS_CONVEX_HULL = 1.0
+ const val PROCESS_MESH_TO_IMAGE = 2.0
+ const val PROCESS_INTERACTIVE_CONVEX_MESH = 3.0
+ const val PROCESS_DRAW_LINES = 4.0
+ const val VIEW_ROTATE = 0.0
+ const val VIEW_STOP_ANIMATION = 1.0
+ const val VIEW_TOGGLE_UNLIMITED_FRAMERATE = 2.0
+ const val VIEW_SET_SUPERSAMPLING_FACTOR = 3.0
+ const val VIEW_SET_FAR_PLANE = 4.0
+ const val VIEW_START_RECORDING_VIDEO = 98.0
+ const val VIEW_STOP_RECORDING_VIDEO = 99.0
+ const val VIEW_SCREENSHOT = 100.0
+ const val VIEW_SET_LUT = 101.0
+ const val VIEW_TOGGLE_BOUNDING_GRID = 102.0
+ const val VIEW_CENTER_ON_ACTIVE_NODE = 103.0
+ const val VIEW_RESET_CAMERA_ROTATION = 202.0
+ const val VIEW_RESET_CAMERA_POSITION = 203.0
+ const val VIEW_SAVE_CAMERA_CONFIGURATION = 204.0
+ const val VIEW_TOGGLE_INSPECTOR = 302.0
+ const val VIEW_RENDER_TO_OPENVR = 303.0
+ const val VIEW_SET_TRANSFER_FUNCTION = 400.0
+ const val DEMO_LINES = 0.0
+ const val DEMO_MESH = 1.0
+ const val DEMO_MESH_TEXTURE = 2.0
+ const val DEMO_VOLUME_RENDER = 3.0
+ const val DEMO_GAME_OF_LIFE = 4.0
+ const val DEMO_TEXT = 5.0
+ const val DEMO_EMBRYO = 6.0
+ const val HELP_HELP = 0.0
+ const val HELP_ABOUT = 200.0
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/demo/GameOfLife3D.java b/src/main/java/sc/iview/commands/demo/GameOfLife3D.java
deleted file mode 100644
index 83589e7e..00000000
--- a/src/main/java/sc/iview/commands/demo/GameOfLife3D.java
+++ /dev/null
@@ -1,380 +0,0 @@
-/*-
- * #%L
- * Scenery-backed 3D visualization package for ImageJ.
- * %%
- * Copyright (C) 2016 - 2020 SciView developers.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-
-package sc.iview.commands.demo;
-
-import bdv.BigDataViewer;
-import bdv.util.RandomAccessibleIntervalSource;
-import bdv.viewer.SourceAndConverter;
-import cleargl.GLVector;
-import graphics.scenery.BoundingGrid;
-import graphics.scenery.volumes.Volume;
-import ij.gui.GenericDialog;
-import ij.gui.NonBlockingGenericDialog;
-import net.imglib2.Cursor;
-import net.imglib2.RandomAccess;
-import net.imglib2.RandomAccessibleInterval;
-import net.imglib2.Sampler;
-import net.imglib2.img.Img;
-import net.imglib2.img.array.ArrayImgs;
-import net.imglib2.type.numeric.integer.UnsignedByteType;
-import org.joml.Vector3f;
-import org.scijava.command.Command;
-import org.scijava.command.CommandService;
-import org.scijava.command.InteractiveCommand;
-import org.scijava.event.EventHandler;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-import org.scijava.widget.Button;
-import org.scijava.widget.NumberWidget;
-import sc.iview.SciView;
-import sc.iview.event.NodeRemovedEvent;
-
-import javax.swing.*;
-
-import java.util.HashMap;
-
-import static sc.iview.commands.MenuWeights.DEMO;
-import static sc.iview.commands.MenuWeights.DEMO_GAME_OF_LIFE;
-
-/**
- * Conway's Game of Life—in 3D!
- *
- * @author Curtis Rueden
- * @author Kyle Harrington
- */
-@Plugin(type = Command.class, menuRoot = "SciView", //
- menu = { @Menu(label = "Demo", weight = DEMO), //
- @Menu(label = "Game of Life 3D", weight = DEMO_GAME_OF_LIFE) })
-public class GameOfLife3D implements Command {
-
- private static final int ALIVE = 255;
- private static final int DEAD = 16;
-
- private static final String SIX = "6-connected";
- private static final String EIGHTEEN = "18-connected";
- private static final String TWENTY_SIX = "26-connected";
-
- @Parameter
- private SciView sciView;
-
- @Parameter(label = "Starvation threshold", min = "0", max = "26", persist = false)
- private int starvation = 5;
-
- @Parameter(label = "Birth threshold", min = "0", max = "26", persist = false)
- private int birth = 6;
-
- @Parameter(label = "Suffocation threshold", min = "0", max = "26", persist = false)
- private int suffocation = 9;
-
- @Parameter(choices = { SIX, EIGHTEEN, TWENTY_SIX }, persist = false)
- private String connectedness = TWENTY_SIX;
-
- @Parameter(label = "Initial saturation % when randomizing", min = "1", max = "99", style = NumberWidget.SCROLL_BAR_STYLE, persist = false)
- private int saturation = 10;
-
-// @Parameter(label = "Play speed", min = "1", max="100", style = NumberWidget.SCROLL_BAR_STYLE, persist = false)
- private int playSpeed = 10;
-//
- @Parameter(callback = "iterate")
- private Button iterate;
-
- @Parameter(callback = "randomize")
- private Button randomize;
-
- @Parameter(callback = "play")
- private Button play;
-
- @Parameter(callback = "pause")
- private Button pause;
-
- private int w = 64, h = 64, d = 64;
- private Img field;
- private String name;
- private float[] voxelDims;
- private Volume volume;
-
- /** Temporary buffer for use while recomputing the image. */
- private boolean[] bits = new boolean[w * h * d];
- private GenericDialog dialog;
-
- /** Repeatedly iterates the simulation until stopped **/
- public void play() {
- sciView.animate( playSpeed, this::iterate);
- }
-
- /** Stops the simulation **/
- public void pause() {
- sciView.stopAnimation();
- }
-
- /** Randomizes a new bit field. */
- public void randomize() {
- final Cursor cursor = field.localizingCursor();
- final double chance = saturation / 100d;
- while( cursor.hasNext() ) {
- final boolean alive = Math.random() <= chance;
- cursor.next().set( alive ? ALIVE : DEAD );
- }
- updateVolume();
- }
-
- /** Performs one iteration of the game. */
- public void iterate() {
- final int connected;
- switch( connectedness ) {
- case SIX: connected = 6; break;
- case EIGHTEEN: connected = 18; break;
- default: connected = 26; break;
- }
-
- // compute the new image field
- final RandomAccess access = field.randomAccess();
-
- //RandomAccess access = ((SourceAndConverter) ((Volume.VolumeDataSource.RAIISource) volume.getDataSource()).getSources().get(0)).getSpimSource().getSource(0, 0).randomAccess();
-
- for( int z = 0; z < d; z++ ) {
- for( int y = 0; y < h; y++ ) {
- for( int x = 0; x < w; x++ ) {
- final int i = z * w * h + y * w + x;
- final int n = neighbors( access, x, y, z, connected );
- access.setPosition( x, 0 );
- access.setPosition( y, 1 );
- access.setPosition( y, 2 );
- if( alive( access ) ) {
- // Living cell stays alive within (starvation, suffocation).
- bits[i] = n > starvation && n < suffocation;
- } else {
- // New cell forms within [birth, suffocation).
- bits[i] = n >= birth && n < suffocation;
- }
- }
- }
- }
-
- // write the new bit field into the image
- final Cursor cursor = field.localizingCursor();
- while( cursor.hasNext() ) {
- cursor.fwd();
- final int x = cursor.getIntPosition( 0 );
- final int y = cursor.getIntPosition( 1 );
- final int z = cursor.getIntPosition( 2 );
- final boolean alive = bits[z * w * h + y * w + x];
- cursor.get().set( alive ? ALIVE : DEAD );
- }
-
-// for( int z = 0; z < d; z++ ) {
-// for( int y = 0; y < h; y++ ) {
-// for( int x = 0; x < w; x++ ) {
-// access.setPosition( x, 0 );
-// access.setPosition( y, 1 );
-// access.setPosition( y, 2 );
-// final boolean alive = bits[z * w * h + y * w + x];
-// access.get().set( alive ? ALIVE : DEAD );
-// }
-// }
-// }
-
- updateVolume();
- }
-
- @Override
- public void run() {
- field = ArrayImgs.unsignedBytes( w, h, d );
- randomize();
-
- dialog = new GenericDialog("Game of Life 3D");
- dialog.addNumericField("Starvation threshold", starvation, 0);
- dialog.addNumericField("Birth threshold", birth, 0);
- dialog.addNumericField("Suffocation threshold", suffocation, 0);
- dialog.addNumericField("Initial saturation % when randomizing", saturation, 0);
- dialog.showDialog();
-
- if( dialog.wasCanceled() ) return;
-
- starvation = (int) dialog.getNextNumber();
- birth = (int) dialog.getNextNumber();
- suffocation = (int) dialog.getNextNumber();
- saturation = (int) dialog.getNextNumber();
-
- randomize();
- play();
-
-//
-// @Parameter(callback = "iterate")
-// private Button iterate;
-//
-// @Parameter(callback = "randomize")
-// private Button randomize;
-//
-// @Parameter(callback = "play")
-// private Button play;
-//
-// @Parameter(callback = "pause")
-// private Button pause;
-
- //play();
-
- //eventService.subscribe(this);
- }
-
-
- // -- Helper methods --
-
- private int neighbors( RandomAccess access, int x, int y, int z, int connected ) {
- int n = 0;
- // six-connected
- n += val( access, x - 1, y, z );
- n += val( access, x + 1, y, z );
- n += val( access, x, y - 1, z );
- n += val( access, x, y + 1, z );
- n += val( access, x, y, z - 1 );
- n += val( access, x, y, z + 1 );
- // eighteen-connected
- if( connected >= 18 ) {
- n += val( access, x - 1, y - 1, z );
- n += val( access, x + 1, y - 1, z );
- n += val( access, x - 1, y + 1, z );
- n += val( access, x + 1, y + 1, z );
- n += val( access, x - 1, y, z - 1 );
- n += val( access, x + 1, y, z - 1 );
- n += val( access, x - 1, y, z + 1 );
- n += val( access, x + 1, y, z + 1 );
- n += val( access, x, y - 1, z - 1 );
- n += val( access, x, y + 1, z - 1 );
- n += val( access, x, y - 1, z + 1 );
- n += val( access, x, y + 1, z + 1 );
- }
- // twenty-six-connected
- if( connected == 26 ) {
- n += val( access, x - 1, y - 1, z - 1 );
- n += val( access, x + 1, y - 1, z - 1 );
- n += val( access, x - 1, y + 1, z - 1 );
- n += val( access, x + 1, y + 1, z - 1 );
- n += val( access, x - 1, y - 1, z + 1 );
- n += val( access, x + 1, y - 1, z + 1 );
- n += val( access, x - 1, y + 1, z + 1 );
- n += val( access, x + 1, y + 1, z + 1 );
- }
- return n;
- }
-
-
-
- private int val( RandomAccess access, int x, int y, int z ) {
- if( x < 0 || x >= w || y < 0 || y >= h || z < 0 || z >= d ) return 0;
- access.setPosition( x, 0 );
- access.setPosition( y, 1 );
- access.setPosition( z, 2 );
- return alive( access ) ? 1 : 0;
- }
-
- private boolean alive( final Sampler access ) {
- return access.get().get() == ALIVE;
- }
-
- private long tick;
-
- private void updateVolume() {
- if( volume == null ) {
- name = "Life Simulation";
- voxelDims = new float[] { 1, 1, 1 };
- volume = ( Volume ) sciView.addVolume( field, name, voxelDims );
-
- BoundingGrid bg = new BoundingGrid();
- bg.setNode( volume );
-
-// volume.setVoxelSizeX(10.0f);
-// volume.setVoxelSizeY(10.0f);
-// volume.setVoxelSizeZ(10.0f);
-
- volume.putAbove(new Vector3f(0.0f, 0.0f, 0.0f));
-// volume.setRenderingMethod(2);
- volume.getTransferFunction().addControlPoint(0.0f, 0.0f);
- volume.getTransferFunction().addControlPoint(0.4f, 0.3f);
-
- volume.setName( "Game of Life 3D" );
-
- sciView.centerOnNode(volume);
- } else {
- // NB: Name must be unique each time.
- sciView.updateVolume( field, name + "-" + ++tick, voxelDims, volume );
-
-// RandomAccessibleIntervalSource newSource = new RandomAccessibleIntervalSource(field, new UnsignedByteType(), name + "-" + ++tick);
-//
-// SourceAndConverter sourceAndConverter = BigDataViewer.wrapWithTransformedSource(
-// new SourceAndConverter<>(newSource, BigDataViewer.createConverterToARGB(new UnsignedByteType())));
-//
-// ((Volume.VolumeDataSource.RAISource) volume.getDataSource()).getSources().set(0, sourceAndConverter);
-//
-// volume.getVolumeManager().notifyUpdate(volume);
-//
-// volume.setDirty(true);
-// volume.setNeedsUpdate(true);
-// volume.getVolumeManager().requestRepaint();
- //volume.getCacheControl().prepareNextFrame();
- }
- }
-
- /**
- * Stops the animation when the volume node is removed.
- * @param event
- */
- @EventHandler
- private void onNodeRemoved(NodeRemovedEvent event) {
- if(event.getNode() == volume) {
- sciView.stopAnimation();
- }
- }
-
- /**
- * Returns the current Img
- */
- public Img getImg() {
- return field;
- }
-
- /**
- * Returns the scenery volume node.
- */
- public Volume getVolume() {
- return volume;
- }
-
- public static void main(String... args) throws Exception {
- SciView sv = SciView.create();
-
- CommandService command = sv.getScijavaContext().getService(CommandService.class);
-
- HashMap argmap = new HashMap<>();
-
- command.run(GameOfLife3D.class, true, argmap);
- }
-}
diff --git a/src/main/java/sc/iview/commands/demo/GameOfLife3D.kt b/src/main/java/sc/iview/commands/demo/GameOfLife3D.kt
new file mode 100644
index 00000000..72650e12
--- /dev/null
+++ b/src/main/java/sc/iview/commands/demo/GameOfLife3D.kt
@@ -0,0 +1,346 @@
+/*-
+ * #%L
+ * Scenery-backed 3D visualization package for ImageJ.
+ * %%
+ * Copyright (C) 2016 - 2020 SciView developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package sc.iview.commands.demo
+
+import graphics.scenery.BoundingGrid
+import graphics.scenery.volumes.Volume
+import ij.gui.GenericDialog
+import net.imglib2.IterableInterval
+import net.imglib2.RandomAccess
+import net.imglib2.RandomAccessibleInterval
+import net.imglib2.Sampler
+import net.imglib2.img.Img
+import net.imglib2.img.array.ArrayImgs
+import net.imglib2.type.numeric.integer.UnsignedByteType
+import org.joml.Vector3f
+import org.scijava.command.Command
+import org.scijava.command.CommandService
+import org.scijava.event.EventHandler
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import org.scijava.widget.Button
+import org.scijava.widget.NumberWidget
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights
+import sc.iview.event.NodeRemovedEvent
+import java.util.*
+
+/**
+ * Conway's Game of Lifein 3D!
+ *
+ * @author Curtis Rueden
+ * @author Kyle Harrington
+ * @author Ulrik Guenther
+ */
+@Plugin(type = Command::class, menuRoot = "SciView", menu = [Menu(label = "Demo", weight = MenuWeights.DEMO), Menu(label = "Game of Life 3D", weight = MenuWeights.DEMO_GAME_OF_LIFE)])
+class GameOfLife3D : Command {
+ @Parameter
+ private lateinit var sciView: SciView
+
+ @Parameter(label = "Starvation threshold", min = "0", max = "26", persist = false)
+ private var starvation = 5
+
+ @Parameter(label = "Birth threshold", min = "0", max = "26", persist = false)
+ private var birth = 6
+
+ @Parameter(label = "Suffocation threshold", min = "0", max = "26", persist = false)
+ private var suffocation = 9
+
+ @Parameter(choices = [SIX, EIGHTEEN, TWENTY_SIX], persist = false)
+ private var connectedness = TWENTY_SIX
+
+ @Parameter(label = "Initial saturation % when randomizing", min = "1", max = "99", style = NumberWidget.SCROLL_BAR_STYLE, persist = false)
+ private var saturation = 10
+
+ // @Parameter(label = "Play speed", min = "1", max="100", style = NumberWidget.SCROLL_BAR_STYLE, persist = false)
+ private val playSpeed = 10
+
+ //
+ @Parameter(callback = "iterate")
+ private lateinit var iterate: Button
+
+ @Parameter(callback = "randomize")
+ private lateinit var randomize: Button
+
+ @Parameter(callback = "play")
+ private lateinit var play: Button
+
+ @Parameter(callback = "pause")
+ private lateinit var pause: Button
+ private val w = 64
+ private val h = 64
+ private val d = 64
+
+ /**
+ * Returns the current Img
+ */
+ var img: Img? = null
+ private set
+ private var name: String? = null
+ private var voxelDims: FloatArray = floatArrayOf(1.0f, 1.0f, 1.0f)
+
+ /**
+ * Returns the scenery volume node.
+ */
+ var volume: Volume? = null
+ private set
+
+ /** Temporary buffer for use while recomputing the image. */
+ private val bits = BooleanArray(w * h * d)
+ private var dialog: GenericDialog? = null
+
+ /** Repeatedly iterates the simulation until stopped */
+ fun play() {
+ sciView.animate(playSpeed) { iterate() }
+ }
+
+ /** Stops the simulation */
+ fun pause() {
+ sciView.stopAnimation()
+ }
+
+ /** Randomizes a new bit field. */
+ fun randomize() {
+ val cursor = img!!.localizingCursor()
+ val chance = saturation / 100.0
+ while (cursor.hasNext()) {
+ val alive = Math.random() <= chance
+ cursor.next().set(if (alive) ALIVE else DEAD)
+ }
+ updateVolume()
+ }
+
+ /** Performs one iteration of the game. */
+ fun iterate() {
+ val connected = when (connectedness) {
+ SIX -> 6
+ EIGHTEEN -> 18
+ else -> 26
+ }
+
+ // compute the new image field
+ val access = img!!.randomAccess()
+
+ //RandomAccess access = ((SourceAndConverter) ((Volume.VolumeDataSource.RAIISource) volume.getDataSource()).getSources().get(0)).getSpimSource().getSource(0, 0).randomAccess();
+ for (z in 0 until d) {
+ for (y in 0 until h) {
+ for (x in 0 until w) {
+ val i = z * w * h + y * w + x
+ val n = neighbors(access, x, y, z, connected)
+ access.setPosition(x, 0)
+ access.setPosition(y, 1)
+ access.setPosition(y, 2)
+ if (alive(access)) {
+ // Living cell stays alive within (starvation, suffocation).
+ bits[i] = n > starvation && n < suffocation
+ } else {
+ // New cell forms within [birth, suffocation).
+ bits[i] = n >= birth && n < suffocation
+ }
+ }
+ }
+ }
+
+ // write the new bit field into the image
+ val cursor = img!!.localizingCursor()
+ while (cursor.hasNext()) {
+ cursor.fwd()
+ val x = cursor.getIntPosition(0)
+ val y = cursor.getIntPosition(1)
+ val z = cursor.getIntPosition(2)
+ val alive = bits[z * w * h + y * w + x]
+ cursor.get().set(if (alive) ALIVE else DEAD)
+ }
+
+// for( int z = 0; z < d; z++ ) {
+// for( int y = 0; y < h; y++ ) {
+// for( int x = 0; x < w; x++ ) {
+// access.setPosition( x, 0 );
+// access.setPosition( y, 1 );
+// access.setPosition( y, 2 );
+// final boolean alive = bits[z * w * h + y * w + x];
+// access.get().set( alive ? ALIVE : DEAD );
+// }
+// }
+// }
+ updateVolume()
+ }
+
+ override fun run() {
+ img = ArrayImgs.unsignedBytes(w.toLong(), h.toLong(), d.toLong())
+ randomize()
+ dialog = GenericDialog("Game of Life 3D")
+ dialog!!.addNumericField("Starvation threshold", starvation.toDouble(), 0)
+ dialog!!.addNumericField("Birth threshold", birth.toDouble(), 0)
+ dialog!!.addNumericField("Suffocation threshold", suffocation.toDouble(), 0)
+ dialog!!.addNumericField("Initial saturation % when randomizing", saturation.toDouble(), 0)
+ dialog!!.showDialog()
+ if (dialog!!.wasCanceled()) return
+ starvation = dialog!!.nextNumber.toInt()
+ birth = dialog!!.nextNumber.toInt()
+ suffocation = dialog!!.nextNumber.toInt()
+ saturation = dialog!!.nextNumber.toInt()
+ randomize()
+ play()
+
+//
+// @Parameter(callback = "iterate")
+// private Button iterate;
+//
+// @Parameter(callback = "randomize")
+// private Button randomize;
+//
+// @Parameter(callback = "play")
+// private Button play;
+//
+// @Parameter(callback = "pause")
+// private Button pause;
+
+ //play();
+
+ //eventService.subscribe(this);
+ }
+
+ // -- Helper methods --
+ private fun neighbors(access: RandomAccess, x: Int, y: Int, z: Int, connected: Int): Int {
+ var n = 0
+ // six-connected
+ n += value(access, x - 1, y, z)
+ n += value(access, x + 1, y, z)
+ n += value(access, x, y - 1, z)
+ n += value(access, x, y + 1, z)
+ n += value(access, x, y, z - 1)
+ n += value(access, x, y, z + 1)
+ // eighteen-connected
+ if (connected >= 18) {
+ n += value(access, x - 1, y - 1, z)
+ n += value(access, x + 1, y - 1, z)
+ n += value(access, x - 1, y + 1, z)
+ n += value(access, x + 1, y + 1, z)
+ n += value(access, x - 1, y, z - 1)
+ n += value(access, x + 1, y, z - 1)
+ n += value(access, x - 1, y, z + 1)
+ n += value(access, x + 1, y, z + 1)
+ n += value(access, x, y - 1, z - 1)
+ n += value(access, x, y + 1, z - 1)
+ n += value(access, x, y - 1, z + 1)
+ n += value(access, x, y + 1, z + 1)
+ }
+ // twenty-six-connected
+ if (connected == 26) {
+ n += value(access, x - 1, y - 1, z - 1)
+ n += value(access, x + 1, y - 1, z - 1)
+ n += value(access, x - 1, y + 1, z - 1)
+ n += value(access, x + 1, y + 1, z - 1)
+ n += value(access, x - 1, y - 1, z + 1)
+ n += value(access, x + 1, y - 1, z + 1)
+ n += value(access, x - 1, y + 1, z + 1)
+ n += value(access, x + 1, y + 1, z + 1)
+ }
+ return n
+ }
+
+ private fun value(access: RandomAccess, x: Int, y: Int, z: Int): Int {
+ if (x < 0 || x >= w || y < 0 || y >= h || z < 0 || z >= d) return 0
+ access.setPosition(x, 0)
+ access.setPosition(y, 1)
+ access.setPosition(z, 2)
+ return if (alive(access)) 1 else 0
+ }
+
+ private fun alive(access: Sampler): Boolean {
+ return access.get().get() == ALIVE
+ }
+
+ private var tick: Long = 0
+ private fun updateVolume() {
+ if (volume == null) {
+ name = "Life Simulation"
+ voxelDims = floatArrayOf(1f, 1f, 1f)
+ volume = sciView.addVolume(img as RandomAccessibleInterval, name, *voxelDims) as Volume?
+ val bg = BoundingGrid()
+ bg.node = volume
+
+// volume.setVoxelSizeX(10.0f);
+// volume.setVoxelSizeY(10.0f);
+// volume.setVoxelSizeZ(10.0f);
+ volume!!.putAbove(Vector3f(0.0f, 0.0f, 0.0f))
+ // volume.setRenderingMethod(2);
+ volume!!.transferFunction.addControlPoint(0.0f, 0.0f)
+ volume!!.transferFunction.addControlPoint(0.4f, 0.3f)
+ volume!!.name = "Game of Life 3D"
+ sciView.centerOnNode(volume)
+ } else {
+ // NB: Name must be unique each time.
+ sciView.updateVolume(img as IterableInterval, name + "-" + ++tick, voxelDims, volume!!)
+
+// RandomAccessibleIntervalSource newSource = new RandomAccessibleIntervalSource(field, new UnsignedByteType(), name + "-" + ++tick);
+//
+// SourceAndConverter sourceAndConverter = BigDataViewer.wrapWithTransformedSource(
+// new SourceAndConverter<>(newSource, BigDataViewer.createConverterToARGB(new UnsignedByteType())));
+//
+// ((Volume.VolumeDataSource.RAISource) volume.getDataSource()).getSources().set(0, sourceAndConverter);
+//
+// volume.getVolumeManager().notifyUpdate(volume);
+//
+// volume.setDirty(true);
+// volume.setNeedsUpdate(true);
+// volume.getVolumeManager().requestRepaint();
+ //volume.getCacheControl().prepareNextFrame();
+ }
+ }
+
+ /**
+ * Stops the animation when the volume node is removed.
+ * @param event
+ */
+ @EventHandler
+ private fun onNodeRemoved(event: NodeRemovedEvent) {
+ if (event.node === volume) {
+ sciView.stopAnimation()
+ }
+ }
+
+ companion object {
+ private const val ALIVE = 255
+ private const val DEAD = 16
+ private const val SIX = "6-connected"
+ private const val EIGHTEEN = "18-connected"
+ private const val TWENTY_SIX = "26-connected"
+ @Throws(Exception::class)
+ @JvmStatic
+ fun main(args: Array) {
+ val sv = SciView.create()
+ val command = sv.scijavaContext!!.getService(CommandService::class.java)
+ val argmap = HashMap()
+ command.run(GameOfLife3D::class.java, true, argmap)
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/demo/Line3DDemo.java b/src/main/java/sc/iview/commands/demo/Line3DDemo.java
index 931e4330..7c35024f 100644
--- a/src/main/java/sc/iview/commands/demo/Line3DDemo.java
+++ b/src/main/java/sc/iview/commands/demo/Line3DDemo.java
@@ -28,6 +28,7 @@
*/
package sc.iview.commands.demo;
+import org.joml.Vector3f;
import org.scijava.command.Command;
import org.scijava.command.CommandService;
import org.scijava.plugin.Menu;
@@ -36,8 +37,6 @@
import org.scijava.util.ColorRGB;
import sc.iview.SciView;
import sc.iview.node.Line3D;
-import sc.iview.vector.JOMLVector3;
-import sc.iview.vector.Vector3;
import java.util.ArrayList;
import java.util.HashMap;
@@ -62,11 +61,11 @@ public class Line3DDemo implements Command {
@Override
public void run() {
int numPoints = 25;
- List points = new ArrayList<>();
+ List points = new ArrayList<>();
List colors = new ArrayList<>();
for( int k = 0; k < numPoints; k++ ) {
- points.add( new JOMLVector3( ( float ) ( 10.0f * Math.random() - 5.0f ), //
+ points.add( new Vector3f( ( float ) ( 10.0f * Math.random() - 5.0f ), //
( float ) ( 10.0f * Math.random() - 5.0f ), //
( float ) ( 10.0f * Math.random() - 5.0f ) ) );
colors.add(new ColorRGB((int) (Math.random()*255), (int) (Math.random()*255), (int) (Math.random()*255)));
diff --git a/src/main/java/sc/iview/commands/demo/LineDemo.java b/src/main/java/sc/iview/commands/demo/LineDemo.java
index b601e72f..89802452 100644
--- a/src/main/java/sc/iview/commands/demo/LineDemo.java
+++ b/src/main/java/sc/iview/commands/demo/LineDemo.java
@@ -31,6 +31,7 @@
import static sc.iview.commands.MenuWeights.DEMO;
import static sc.iview.commands.MenuWeights.DEMO_LINES;
+import org.joml.Vector3f;
import org.scijava.command.Command;
import org.scijava.command.CommandService;
import org.scijava.plugin.Menu;
@@ -39,9 +40,6 @@
import org.scijava.util.Colors;
import sc.iview.SciView;
-import sc.iview.vector.JOMLVector3;
-import sc.iview.vector.Vector3;
-
import java.util.HashMap;
/**
@@ -61,12 +59,12 @@ public class LineDemo implements Command {
@Override
public void run() {
int numPoints = 25;
- Vector3[] points = new Vector3[numPoints];
+ Vector3f[] points = new Vector3f[numPoints];
for( int k = 0; k < numPoints; k++ ) {
- points[k] = new JOMLVector3( ( float ) ( 10.0f * Math.random() - 5.0f ), //
- ( float ) ( 10.0f * Math.random() - 5.0f ), //
- ( float ) ( 10.0f * Math.random() - 5.0f ) );
+ points[k] = new Vector3f( ( float ) ( 10.0f * Math.random() - 5.0f ), //
+ ( float ) ( 10.0f * Math.random() - 5.0f ), //
+ ( float ) ( 10.0f * Math.random() - 5.0f ) );
}
double edgeWidth = 0.1;
diff --git a/src/main/java/sc/iview/commands/demo/LoadCremiDatasetAndNeurons.kt b/src/main/java/sc/iview/commands/demo/LoadCremiDatasetAndNeurons.kt
index ce118ffa..818e7ebb 100644
--- a/src/main/java/sc/iview/commands/demo/LoadCremiDatasetAndNeurons.kt
+++ b/src/main/java/sc/iview/commands/demo/LoadCremiDatasetAndNeurons.kt
@@ -5,14 +5,13 @@ import bdv.viewer.Interpolation
import ch.systemsx.cisd.hdf5.HDF5Factory
import graphics.scenery.Material
import graphics.scenery.Origin
-import graphics.scenery.numerics.Random
import graphics.scenery.utils.extensions.xyz
import graphics.scenery.volumes.Colormap
-import graphics.scenery.volumes.Colormap.Companion.fromColorTable
import graphics.scenery.volumes.TransferFunction
import graphics.scenery.volumes.Volume
import net.imagej.lut.LUTService
import net.imagej.mesh.Mesh
+import net.imagej.mesh.Meshes
import net.imagej.ops.OpService
import net.imagej.ops.geom.geom3d.mesh.BitTypeVertexInterpolator
import net.imglib2.RandomAccessibleInterval
@@ -35,7 +34,6 @@ import org.scijava.plugin.Plugin
import org.scijava.ui.UIService
import org.scijava.widget.FileWidget
import sc.iview.SciView
-import sc.iview.SciViewService
import sc.iview.commands.MenuWeights
import sc.iview.process.MeshConverter
import java.io.FileFilter
@@ -87,6 +85,7 @@ class LoadCremiDatasetAndNeurons: Command {
* @see Thread.run
*/
override fun run() {
+ val task = sciview.taskManager.newTask("Cremi", "Loading dataset")
val filter = FileFilter { file ->
val extension = file.name.substringAfterLast(".").toLowerCase()
@@ -112,6 +111,8 @@ class LoadCremiDatasetAndNeurons: Command {
volume?.scale = Vector3f(0.04f, 0.04f, 2.5f)
volume?.transferFunction = TransferFunction.ramp(0.3f, 0.1f, 0.1f)
// min 20, max 180, color map fire
+
+ volume?.transferFunction?.addControlPoint(0.3f, 0.5f)
volume?.transferFunction?.addControlPoint(0.8f, 0.01f)
volume?.converterSetups?.get(0)?.setDisplayRange(20.0, 220.0)
val colormap = lut.loadLUT(lut.findLUTs().get("Grays.lut"))
@@ -120,6 +121,8 @@ class LoadCremiDatasetAndNeurons: Command {
volume?.colormap = Colormap.fromColorTable(colormap)
+ task.status = "Creating labeling"
+ task.completion = 10.0f
val rai = nai.second
log.info("Got ${nai.first.size} labels")
@@ -138,9 +141,11 @@ class LoadCremiDatasetAndNeurons: Command {
regions.filter { largestNeuronLabels.contains(it.label.toLong() + 1L) }.forEachIndexed { i, region ->
log.info("Meshing neuron ${i + 1}/${largestNeuronLabels.size} with label ${region.label}...")
+ task.status = "Meshing neuron ${i+1}/${largestNeuronLabels.size}"
+
// ui.show(region)
// Generate the mesh with imagej-ops
- val m: Mesh = ops.geom().marchingCubes(region, 1.0, BitTypeVertexInterpolator())
+ val m: Mesh = Meshes.marchingCubes(region);
log.info("Converting neuron ${i + 1}/${largestNeuronLabels.size} to scenery format...")
// Convert the mesh into a scenery mesh for visualization
@@ -149,11 +154,13 @@ class LoadCremiDatasetAndNeurons: Command {
mesh.material.diffuse = colormapNeurons.lookupARGB(0.0, 255.0, kotlin.random.Random.nextDouble(0.0, 255.0)).toRGBColor().xyz()
mesh.material.roughness = 0.0f
- // marching cubes produces CW meshes, not CCW as expected by default
- mesh.material.cullingMode = Material.CullingMode.Front
mesh.name = "Neuron $i"
sciview.addNode(mesh)
+ val completion = 10.0f + ((i+1)/largestNeuronLabels.size.toFloat())*90.0f
+ task.completion = completion
}
+
+ task.completion = 100.0f
}
fun readCremiHDF5(path: String, scale: Double = 1.0): NeuronsAndImage? {
diff --git a/src/main/java/sc/iview/commands/demo/VolumeRenderDemo.java b/src/main/java/sc/iview/commands/demo/VolumeRenderDemo.java
deleted file mode 100644
index 618ac57c..00000000
--- a/src/main/java/sc/iview/commands/demo/VolumeRenderDemo.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*-
- * #%L
- * Scenery-backed 3D visualization package for ImageJ.
- * %%
- * Copyright (C) 2016 - 2020 SciView developers.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-package sc.iview.commands.demo;
-
-import graphics.scenery.volumes.Volume;
-import io.scif.services.DatasetIOService;
-import net.imagej.Dataset;
-import net.imagej.mesh.Mesh;
-import net.imagej.ops.OpService;
-import net.imagej.ops.geom.geom3d.mesh.BitTypeVertexInterpolator;
-import net.imglib2.img.Img;
-import net.imglib2.type.logic.BitType;
-import net.imglib2.type.numeric.integer.UnsignedByteType;
-import org.scijava.command.Command;
-import org.scijava.command.CommandService;
-import org.scijava.log.LogService;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-import sc.iview.SciView;
-import sc.iview.process.MeshConverter;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.HashMap;
-
-import static sc.iview.commands.MenuWeights.DEMO;
-import static sc.iview.commands.MenuWeights.DEMO_VOLUME_RENDER;
-
-/**
- * A demo of volume rendering.
- *
- * @author Kyle Harrington
- * @author Curtis Rueden
- */
-@Plugin(type = Command.class, label = "Volume Render/Isosurface Demo", menuRoot = "SciView", //
- menu = { @Menu(label = "Demo", weight = DEMO), //
- @Menu(label = "Volume Render/Isosurface", weight = DEMO_VOLUME_RENDER) })
-public class VolumeRenderDemo implements Command {
-
- @Parameter
- private DatasetIOService datasetIO;
-
- @Parameter
- private LogService log;
-
- @Parameter
- private OpService ops;
-
- @Parameter
- private SciView sciView;
-
- @Parameter(label = "Show isosurface")
- private boolean iso = true;
-
- @Override
- public void run() {
- final Dataset cube;
- try {
- File cubeFile = ResourceLoader.createFile( getClass(), "/cored_cube_var2_8bit.tif" );
-
- cube = datasetIO.open( cubeFile.getAbsolutePath() );
- }
- catch (IOException exc) {
- log.error( exc );
- return;
- }
-
- Volume v = (Volume) sciView.addVolume( cube, new float[] { 1, 1, 1 } );
- v.setPixelToWorldRatio(0.05f);
- v.setName( "Volume Render Demo" );
- v.setDirty(true);
- v.setNeedsUpdate(true);
-
- if (iso) {
- int isoLevel = 1;
-
- @SuppressWarnings("unchecked")
- Img cubeImg = ( Img ) cube.getImgPlus().getImg();
-
- Img bitImg = ( Img ) ops.threshold().apply( cubeImg, new UnsignedByteType( isoLevel ) );
-
- Mesh m = ops.geom().marchingCubes( bitImg, isoLevel, new BitTypeVertexInterpolator() );
-
- graphics.scenery.Mesh isoSurfaceMesh = MeshConverter.toScenery(m,false);
- v.addChild(isoSurfaceMesh);
-
- isoSurfaceMesh.setName( "Volume Render Demo Isosurface" );
- }
-
- sciView.setActiveNode(v);
- sciView.centerOnNode( sciView.getActiveNode() );
- }
-
- public static void main(String... args) throws Exception {
- SciView sv = SciView.create();
-
- CommandService command = sv.getScijavaContext().getService(CommandService.class);
-
- HashMap argmap = new HashMap();
- argmap.put("iso",true);
-
- command.run(VolumeRenderDemo.class, true, argmap);
- }
-}
diff --git a/src/main/java/sc/iview/commands/demo/VolumeRenderDemo.kt b/src/main/java/sc/iview/commands/demo/VolumeRenderDemo.kt
new file mode 100644
index 00000000..d5c07c42
--- /dev/null
+++ b/src/main/java/sc/iview/commands/demo/VolumeRenderDemo.kt
@@ -0,0 +1,115 @@
+/*-
+ * #%L
+ * Scenery-backed 3D visualization package for ImageJ.
+ * %%
+ * Copyright (C) 2016 - 2020 SciView developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package sc.iview.commands.demo
+
+import graphics.scenery.volumes.Volume
+import io.scif.services.DatasetIOService
+import net.imagej.Dataset
+import net.imagej.ops.OpService
+import net.imagej.ops.geom.geom3d.mesh.BitTypeVertexInterpolator
+import net.imglib2.img.Img
+import net.imglib2.type.logic.BitType
+import net.imglib2.type.numeric.integer.UnsignedByteType
+import org.scijava.command.Command
+import org.scijava.command.CommandService
+import org.scijava.log.LogService
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights.DEMO
+import sc.iview.commands.MenuWeights.DEMO_VOLUME_RENDER
+import sc.iview.process.MeshConverter
+import java.io.IOException
+import java.util.*
+
+/**
+ * A demo of volume rendering.
+ *
+ * @author Kyle Harrington
+ * @author Curtis Rueden
+ */
+@Plugin(type = Command::class, label = "Volume Render/Isosurface Demo", menuRoot = "SciView", menu = [Menu(label = "Demo", weight = DEMO), Menu(label = "Volume Render/Isosurface", weight = DEMO_VOLUME_RENDER)])
+class VolumeRenderDemo : Command {
+ @Parameter
+ private lateinit var datasetIO: DatasetIOService
+
+ @Parameter
+ private lateinit var log: LogService
+
+ @Parameter
+ private lateinit var ops: OpService
+
+ @Parameter
+ private lateinit var sciView: SciView
+
+ @Parameter(label = "Show isosurface")
+ private var iso: Boolean = true
+
+ override fun run() {
+ val cube: Dataset
+ cube = try {
+ val cubeFile = ResourceLoader.createFile(javaClass, "/cored_cube_var2_8bit.tif")
+ datasetIO.open(cubeFile.absolutePath)
+ } catch (exc: IOException) {
+ log.error(exc)
+ return
+ }
+ val v = sciView.addVolume(cube, floatArrayOf(1f, 1f, 1f)) as Volume
+ v.pixelToWorldRatio = 0.05f
+ v.name = "Volume Render Demo"
+ v.dirty = true
+ v.needsUpdate = true
+ if (iso) {
+ val isoLevel = 1
+
+ @Suppress("UNCHECKED_CAST")
+ val cubeImg = cube.imgPlus.img as Img
+ val bitImg = ops.threshold().apply(cubeImg, UnsignedByteType(isoLevel)) as Img
+ val m = ops.geom().marchingCubes(bitImg, isoLevel.toDouble(), BitTypeVertexInterpolator())
+ val isoSurfaceMesh = MeshConverter.toScenery(m, false)
+ v.addChild(isoSurfaceMesh)
+ isoSurfaceMesh.name = "Volume Render Demo Isosurface"
+ }
+ sciView.setActiveNode(v)
+ sciView.centerOnNode(sciView.activeNode)
+ }
+
+ companion object {
+ @Throws(Exception::class)
+ @JvmStatic
+ fun main(args: Array) {
+ val sv = SciView.create()
+ val command = sv.scijavaContext!!.getService(CommandService::class.java)
+ val argmap = HashMap()
+ argmap["iso"] = true
+ command.run(VolumeRenderDemo::class.java, true, argmap)
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/edit/AddBox.java b/src/main/java/sc/iview/commands/edit/AddBox.java
index 31558031..47ab4542 100644
--- a/src/main/java/sc/iview/commands/edit/AddBox.java
+++ b/src/main/java/sc/iview/commands/edit/AddBox.java
@@ -31,6 +31,7 @@
import static sc.iview.commands.MenuWeights.EDIT;
import static sc.iview.commands.MenuWeights.EDIT_ADD_BOX;
+import org.joml.Vector3f;
import org.scijava.command.Command;
import org.scijava.display.DisplayService;
import org.scijava.plugin.Menu;
@@ -39,8 +40,6 @@
import org.scijava.util.ColorRGB;
import sc.iview.SciView;
-import sc.iview.vector.JOMLVector3;
-import sc.iview.vector.Vector3;
/**
* Command to add a box to the scene
@@ -75,8 +74,8 @@ public class AddBox implements Command {
@Override
public void run() {
//final Vector3 pos = ClearGLVector3.parse( position );
- final Vector3 pos = new JOMLVector3(0, 0, 0);
- final Vector3 vSize = new JOMLVector3( size, size, size );
+ final Vector3f pos = new Vector3f(0f, 0f, 0f);
+ final Vector3f vSize = new Vector3f( size, size, size );
sciView.addBox( pos, vSize, color, inside );
}
}
diff --git a/src/main/java/sc/iview/commands/edit/AddCamera.java b/src/main/java/sc/iview/commands/edit/AddCamera.java
index 666c77a8..d5738492 100644
--- a/src/main/java/sc/iview/commands/edit/AddCamera.java
+++ b/src/main/java/sc/iview/commands/edit/AddCamera.java
@@ -29,14 +29,13 @@
package sc.iview.commands.edit;
import graphics.scenery.DetachedHeadCamera;
+import org.joml.Vector3f;
import org.scijava.command.Command;
import org.scijava.display.DisplayService;
import org.scijava.plugin.Menu;
import org.scijava.plugin.Parameter;
import org.scijava.plugin.Plugin;
import sc.iview.SciView;
-import sc.iview.vector.JOMLVector3;
-import sc.iview.vector.Vector3;
import static sc.iview.commands.MenuWeights.EDIT;
import static sc.iview.commands.MenuWeights.EDIT_ADD_CAMERA;
@@ -74,7 +73,7 @@ public class AddCamera implements Command {
@Override
public void run() {
//final Vector3 pos = ClearGLVector3.parse( position );
- final Vector3 pos = new JOMLVector3(0, 0, 0);
+ final Vector3f pos = new Vector3f(0, 0, 0);
final DetachedHeadCamera cam = new DetachedHeadCamera();
cam.perspectiveCamera( fov, sciView.getWindowWidth(), sciView.getWindowHeight(), Math.min(nearPlane, farPlane), Math.max(nearPlane, farPlane) );
cam.setPosition( pos );
diff --git a/src/main/java/sc/iview/commands/edit/AddLine.java b/src/main/java/sc/iview/commands/edit/AddLine.java
index 5288e327..e1386b37 100644
--- a/src/main/java/sc/iview/commands/edit/AddLine.java
+++ b/src/main/java/sc/iview/commands/edit/AddLine.java
@@ -31,6 +31,7 @@
import static sc.iview.commands.MenuWeights.EDIT;
import static sc.iview.commands.MenuWeights.EDIT_ADD_LINE;
+import org.joml.Vector3f;
import org.scijava.command.Command;
import org.scijava.plugin.Menu;
import org.scijava.plugin.Parameter;
@@ -38,8 +39,6 @@
import org.scijava.util.ColorRGB;
import sc.iview.SciView;
-import sc.iview.vector.JOMLVector3;
-import sc.iview.vector.Vector3;
/**
* Command to add a line in the scene
@@ -71,7 +70,7 @@ public class AddLine implements Command {
@Override
public void run() {
//Vector3[] endpoints = { JOMLVector3.parse( start ), JOMLVector3.parse( stop ) };
- Vector3[] endpoints = { new JOMLVector3( 0, 0, 0 ), new JOMLVector3( 1, 1, 1 ) };
+ Vector3f[] endpoints = { new Vector3f( 0, 0, 0 ), new Vector3f( 1, 1, 1 ) };
sciView.addLine( endpoints, color, edgeWidth );
}
}
diff --git a/src/main/java/sc/iview/commands/edit/AddOrientationCompass.java b/src/main/java/sc/iview/commands/edit/AddOrientationCompass.java
index c9da9995..2df81396 100644
--- a/src/main/java/sc/iview/commands/edit/AddOrientationCompass.java
+++ b/src/main/java/sc/iview/commands/edit/AddOrientationCompass.java
@@ -121,10 +121,9 @@ public void run() {
root.getUpdate().add(() -> {
final Camera cam = sciView.getCamera();
root.setPosition(cam.viewportToView(new Vector2f(-0.9f, 0.7f)));
- root.setRotation(new Quaternionf(sciView.getCamera().getRotation()).conjugate());
+ root.setRotation(new Quaternionf(sciView.getCamera().getRotation()).conjugate().normalize());
return null;
});
-
}
public static void main(String... args) throws Exception {
diff --git a/src/main/java/sc/iview/commands/edit/AddSphere.java b/src/main/java/sc/iview/commands/edit/AddSphere.java
index 23f9a05d..69fbd560 100644
--- a/src/main/java/sc/iview/commands/edit/AddSphere.java
+++ b/src/main/java/sc/iview/commands/edit/AddSphere.java
@@ -31,6 +31,7 @@
import static sc.iview.commands.MenuWeights.EDIT;
import static sc.iview.commands.MenuWeights.EDIT_ADD_SPHERE;
+import org.joml.Vector3f;
import org.scijava.command.Command;
import org.scijava.plugin.Menu;
import org.scijava.plugin.Parameter;
@@ -38,8 +39,6 @@
import org.scijava.util.ColorRGB;
import sc.iview.SciView;
-import sc.iview.vector.JOMLVector3;
-import sc.iview.vector.Vector3;
/**
* Command to add a sphere in the scene
@@ -67,7 +66,7 @@ public class AddSphere implements Command {
@Override
public void run() {
//final Vector3 pos = ClearGLVector3.parse( position );
- final Vector3 pos = new JOMLVector3(0, 0, 0);
+ final Vector3f pos = new Vector3f(0, 0, 0);
sciView.addSphere( pos, radius, color );
}
}
diff --git a/src/main/java/sc/iview/commands/edit/NavigationControlsSettings.java b/src/main/java/sc/iview/commands/edit/NavigationControlsSettings.java
index 9c9ea1a4..93f020b7 100644
--- a/src/main/java/sc/iview/commands/edit/NavigationControlsSettings.java
+++ b/src/main/java/sc/iview/commands/edit/NavigationControlsSettings.java
@@ -100,11 +100,11 @@ private void setupBoundsFromSciView()
//backup the current state of SciView before we eventually override it
//so that there is something to return to with the "first toggle"
- orig_fpsSlowSpeed = sciView.controlsParameters.getFpsSpeedSlow();
- orig_fpsFastSpeed = sciView.controlsParameters.getFpsSpeedFast();
- orig_fpsVeryFastSpeed = sciView.controlsParameters.getFpsSpeedVeryFast();
- orig_mouseMoveSensitivity = sciView.controlsParameters.getMouseSpeedMult();
- orig_mouseScrollSensitivity = sciView.controlsParameters.getMouseScrollMult();
+ orig_fpsSlowSpeed = sciView.getControlsParameters().getFpsSpeedSlow();
+ orig_fpsFastSpeed = sciView.getControlsParameters().getFpsSpeedFast();
+ orig_fpsVeryFastSpeed = sciView.getControlsParameters().getFpsSpeedVeryFast();
+ orig_mouseMoveSensitivity = sciView.getControlsParameters().getMouseSpeedMult();
+ orig_mouseScrollSensitivity = sciView.getControlsParameters().getMouseScrollMult();
//try to retrieve stored dialog state and push it to SciView
//so that the SciView and dialog states match
@@ -120,11 +120,11 @@ private void setupBoundsFromSciView()
//updates GUI with fresh values
private void updateDialogSpeedsAndMouseParams()
{
- fpsSlowSpeed = sciView.controlsParameters.getFpsSpeedSlow();
- fpsFastSpeed = sciView.controlsParameters.getFpsSpeedFast();
- fpsVeryFastSpeed = sciView.controlsParameters.getFpsSpeedVeryFast();
- mouseMoveSensitivity = sciView.controlsParameters.getMouseSpeedMult();
- mouseScrollSensitivity = sciView.controlsParameters.getMouseScrollMult();
+ fpsSlowSpeed = sciView.getControlsParameters().getFpsSpeedSlow();
+ fpsFastSpeed = sciView.getControlsParameters().getFpsSpeedFast();
+ fpsVeryFastSpeed = sciView.getControlsParameters().getFpsSpeedVeryFast();
+ mouseMoveSensitivity = sciView.getControlsParameters().getMouseSpeedMult();
+ mouseScrollSensitivity = sciView.getControlsParameters().getMouseScrollMult();
}
diff --git a/src/main/java/sc/iview/commands/process/DrawLines.java b/src/main/java/sc/iview/commands/process/DrawLines.java
index 2fbfd7f4..2a760d11 100644
--- a/src/main/java/sc/iview/commands/process/DrawLines.java
+++ b/src/main/java/sc/iview/commands/process/DrawLines.java
@@ -41,7 +41,6 @@
import sc.iview.SciView;
import sc.iview.node.Line3D;
import sc.iview.process.ControlPoints;
-import sc.iview.vector.Vector3;
import java.util.ArrayList;
@@ -84,8 +83,8 @@ public void createLine() {
//Line line = new Line();
ArrayList points = new ArrayList<>();
- for( Vector3 v : controlPoints.getVertices() ) {
- points.add(new Vector3f(v.xf(), v.yf(), v.zf()));
+ for( Vector3f v : controlPoints.getVertices() ) {
+ points.add(new Vector3f(v.x(), v.y(), v.z()));
}
float r = 0.1f;
diff --git a/src/main/java/sc/iview/commands/process/InteractiveConvexMesh.java b/src/main/java/sc/iview/commands/process/InteractiveConvexMesh.java
index f7029431..408c6d9c 100644
--- a/src/main/java/sc/iview/commands/process/InteractiveConvexMesh.java
+++ b/src/main/java/sc/iview/commands/process/InteractiveConvexMesh.java
@@ -33,6 +33,7 @@
import net.imagej.mesh.naive.NaiveDoubleMesh;
import net.imagej.ops.OpService;
import net.imagej.ops.geom.geom3d.DefaultConvexHull3D;
+import org.joml.Vector3f;
import org.scijava.command.Command;
import org.scijava.command.InteractiveCommand;
import org.scijava.plugin.Menu;
@@ -41,7 +42,6 @@
import org.scijava.widget.Button;
import sc.iview.SciView;
import sc.iview.process.ControlPoints;
-import sc.iview.vector.Vector3;
import java.util.List;
@@ -83,8 +83,8 @@ public void run() {
public void createMesh() {
Mesh mesh = new NaiveDoubleMesh();
- for( Vector3 v : controlPoints.getVertices() ) {
- mesh.vertices().add(v.xf(), v.yf(), v.zf());
+ for( Vector3f v : controlPoints.getVertices() ) {
+ mesh.vertices().add(v.x(), v.y(), v.z());
}
final List> result = (List>) opService.run(DefaultConvexHull3D.class, mesh );
diff --git a/src/main/java/sc/iview/commands/view/CenterOnActiveNode.java b/src/main/java/sc/iview/commands/view/CenterOnActiveNode.java
deleted file mode 100644
index 5924164e..00000000
--- a/src/main/java/sc/iview/commands/view/CenterOnActiveNode.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*-
- * #%L
- * Scenery-backed 3D visualization package for ImageJ.
- * %%
- * Copyright (C) 2016 - 2020 SciView developers.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-package sc.iview.commands.view;
-
-import graphics.scenery.Mesh;
-import graphics.scenery.Node;
-import org.scijava.command.Command;
-import org.scijava.log.LogService;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-import sc.iview.SciView;
-
-import static sc.iview.commands.MenuWeights.VIEW;
-import static sc.iview.commands.MenuWeights.VIEW_CENTER_ON_ACTIVE_NODE;
-
-/**
- * Command to center the camera on the currently active Node
- *
- * @author Kyle Harrington
- *
- */
-@Plugin(type = Command.class, menuRoot = "SciView", //
-menu = {@Menu(label = "View", weight = VIEW), //
- @Menu(label = "Center On Active Node", weight = VIEW_CENTER_ON_ACTIVE_NODE)})
-public class CenterOnActiveNode implements Command {
-
- @Parameter
- private LogService logService;
-
- @Parameter
- private SciView sciView;
-
- @Override
- public void run() {
- if( sciView.getActiveNode() instanceof Mesh ) {
- Node currentNode = sciView.getActiveNode();
-
- sciView.centerOnNode( currentNode );
-
- }
-
- }
-
-}
diff --git a/src/main/java/sc/iview/commands/view/CenterOnActiveNode.kt b/src/main/java/sc/iview/commands/view/CenterOnActiveNode.kt
new file mode 100644
index 00000000..bc4fc3f9
--- /dev/null
+++ b/src/main/java/sc/iview/commands/view/CenterOnActiveNode.kt
@@ -0,0 +1,57 @@
+/*-
+ * #%L
+ * Scenery-backed 3D visualization package for ImageJ.
+ * %%
+ * Copyright (C) 2016 - 2020 SciView developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package sc.iview.commands.view
+
+import graphics.scenery.Mesh
+import org.scijava.command.Command
+import org.scijava.log.LogService
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights.VIEW
+import sc.iview.commands.MenuWeights.VIEW_CENTER_ON_ACTIVE_NODE
+
+/**
+ * Command to center the camera on the currently active Node
+ *
+ * @author Kyle Harrington
+ */
+@Plugin(type = Command::class, menuRoot = "SciView", menu = [Menu(label = "View", weight = VIEW), Menu(label = "Center On Active Node", weight = VIEW_CENTER_ON_ACTIVE_NODE)])
+class CenterOnActiveNode : Command {
+ @Parameter
+ private lateinit var sciView: SciView
+
+ override fun run() {
+ if (sciView.activeNode is Mesh) {
+ val currentNode = sciView.activeNode
+ sciView.centerOnNode(currentNode)
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/view/DisplayVertices.java b/src/main/java/sc/iview/commands/view/DisplayVertices.kt
similarity index 50%
rename from src/main/java/sc/iview/commands/view/DisplayVertices.java
rename to src/main/java/sc/iview/commands/view/DisplayVertices.kt
index 9102ff6a..df2206a9 100644
--- a/src/main/java/sc/iview/commands/view/DisplayVertices.java
+++ b/src/main/java/sc/iview/commands/view/DisplayVertices.kt
@@ -26,72 +26,62 @@
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
-package sc.iview.commands.view;
+package sc.iview.commands.view
-import graphics.scenery.Mesh;
-import net.imagej.mesh.Vertex;
-import org.scijava.ItemIO;
-import org.scijava.command.Command;
-import org.scijava.log.LogService;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-import org.scijava.table.*;
-import sc.iview.SciView;
-import sc.iview.process.MeshConverter;
-
-import static sc.iview.commands.MenuWeights.VIEW;
-import static sc.iview.commands.MenuWeights.VIEW_SET_TRANSFER_FUNCTION;
+import graphics.scenery.Mesh
+import org.scijava.ItemIO
+import org.scijava.command.Command
+import org.scijava.log.LogService
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import org.scijava.table.DefaultGenericTable
+import org.scijava.table.DoubleColumn
+import org.scijava.table.GenericColumn
+import org.scijava.table.Table
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights.VIEW
+import sc.iview.commands.MenuWeights.VIEW_SET_TRANSFER_FUNCTION
+import sc.iview.process.MeshConverter
/**
* Command to display the vertices of the currently active Node as a table.
*
* @author Kyle Harrington
- *
*/
-@Plugin(type = Command.class, menuRoot = "SciView", //
- menu = {@Menu(label = "View", weight = VIEW), //
- @Menu(label = "Display Vertices", weight = VIEW_SET_TRANSFER_FUNCTION)})
-public class DisplayVertices implements Command {
-
- @Parameter
- private LogService logService;
-
+@Plugin(type = Command::class, menuRoot = "SciView", menu = [Menu(label = "View", weight = VIEW), Menu(label = "Display Vertices", weight = VIEW_SET_TRANSFER_FUNCTION)])
+class DisplayVertices : Command {
@Parameter
- private SciView sciView;
+ private lateinit var sciView: SciView
// TODO: this should be the way to do this instead of using sciView.activeNode()
-// @Parameter
-// private Mesh mesh;
+ // @Parameter
+ // private Mesh mesh;
@Parameter(type = ItemIO.OUTPUT)
- private Table table;
-
- @Override
- public void run() {
- if( sciView.getActiveNode() instanceof Mesh ) {
- Mesh scMesh = (Mesh) sciView.getActiveNode();
- net.imagej.mesh.Mesh mesh = MeshConverter.toImageJ(scMesh);
+ private lateinit var table: Table<*, *>
- table = new DefaultGenericTable();
+ override fun run() {
+ if (sciView.activeNode is Mesh) {
+ val scMesh = sciView.activeNode as Mesh
+ val mesh = MeshConverter.toImageJ(scMesh)
+ table = DefaultGenericTable()
// we create two columns
- GenericColumn idColumn = new GenericColumn("ID");
- DoubleColumn xColumn = new DoubleColumn("X");
- DoubleColumn yColumn = new DoubleColumn("Y");
- DoubleColumn zColumn = new DoubleColumn("Z");
-
- for (Vertex v : mesh.vertices()) {
- idColumn.add(v.index());
- xColumn.add(v.x());
- yColumn.add(v.y());
- zColumn.add(v.z());
+ val idColumn = GenericColumn("ID")
+ val xColumn = DoubleColumn("X")
+ val yColumn = DoubleColumn("Y")
+ val zColumn = DoubleColumn("Z")
+ for (v in mesh.vertices()) {
+ idColumn.add(v.index())
+ xColumn.add(v.x())
+ yColumn.add(v.y())
+ zColumn.add(v.z())
}
-
- table.add(idColumn);
- table.add(xColumn);
- table.add(yColumn);
- table.add(zColumn);
+ (table as DefaultGenericTable).add(idColumn)
+ (table as DefaultGenericTable).add(xColumn)
+ (table as DefaultGenericTable).add(yColumn)
+ (table as DefaultGenericTable).add(zColumn)
}
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/view/RenderToOpenVRHMD.java b/src/main/java/sc/iview/commands/view/RenderToOpenVRHMD.kt
similarity index 70%
rename from src/main/java/sc/iview/commands/view/RenderToOpenVRHMD.java
rename to src/main/java/sc/iview/commands/view/RenderToOpenVRHMD.kt
index fe251778..58270614 100644
--- a/src/main/java/sc/iview/commands/view/RenderToOpenVRHMD.java
+++ b/src/main/java/sc/iview/commands/view/RenderToOpenVRHMD.kt
@@ -26,32 +26,27 @@
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
-package sc.iview.commands.view;
+package sc.iview.commands.view
-import org.scijava.command.Command;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-
-import sc.iview.SciView;
-
-import static sc.iview.commands.MenuWeights.*;
+import org.scijava.command.Command
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights.VIEW
+import sc.iview.commands.MenuWeights.VIEW_RENDER_TO_OPENVR
/**
* Activates rendering to an OpenVR headset
*
* @author Ulrik Guenther
*/
-@Plugin(type = Command.class, initializer = "initValues", menuRoot = "SciView", selectable = true,
- menu = { @Menu(label = "View", weight = VIEW),
- @Menu(label = "Render to OpenVR Headset", weight = VIEW_RENDER_TO_OPENVR) })
-public class RenderToOpenVRHMD implements Command {
-
+@Plugin(type = Command::class, initializer = "initValues", menuRoot = "SciView", selectable = true, menu = [Menu(label = "View", weight = VIEW), Menu(label = "Render to OpenVR Headset", weight = VIEW_RENDER_TO_OPENVR)])
+class RenderToOpenVRHMD : Command {
@Parameter
- private SciView sciView;
+ private lateinit var sciView: SciView
- @Override
- public void run() {
- sciView.toggleVRRendering();
+ override fun run() {
+ sciView.toggleVRRendering()
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/view/ResetCameraPosition.java b/src/main/java/sc/iview/commands/view/ResetCameraPosition.kt
similarity index 66%
rename from src/main/java/sc/iview/commands/view/ResetCameraPosition.java
rename to src/main/java/sc/iview/commands/view/ResetCameraPosition.kt
index f710cbb1..4ff62b25 100644
--- a/src/main/java/sc/iview/commands/view/ResetCameraPosition.java
+++ b/src/main/java/sc/iview/commands/view/ResetCameraPosition.kt
@@ -26,39 +26,32 @@
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
-package sc.iview.commands.view;
+package sc.iview.commands.view
-import org.joml.Vector3f;
-import org.scijava.command.Command;
-import org.scijava.log.LogService;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-import sc.iview.SciView;
-
-import static sc.iview.commands.MenuWeights.VIEW;
-import static sc.iview.commands.MenuWeights.VIEW_RESET_CAMERA_POSITION;
+import org.joml.Vector3f
+import org.scijava.command.Command
+import org.scijava.log.LogService
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights.VIEW
+import sc.iview.commands.MenuWeights.VIEW_RESET_CAMERA_POSITION
/**
* Command to set the camera position to the default position
*
* @author Kyle Harrington
- *
*/
-@Plugin(type = Command.class, menuRoot = "SciView", //
-menu = {@Menu(label = "View", weight = VIEW), //
- @Menu(label = "Reset Camera Position", weight = VIEW_RESET_CAMERA_POSITION)})
-public class ResetCameraPosition implements Command {
-
+@Plugin(type = Command::class, menuRoot = "SciView", menu = [Menu(label = "View", weight = VIEW), Menu(label = "Reset Camera Position", weight = VIEW_RESET_CAMERA_POSITION)])
+class ResetCameraPosition : Command {
@Parameter
- private LogService logService;
+ private lateinit var logService: LogService
@Parameter
- private SciView sciView;
+ private lateinit var sciView: SciView
- @Override
- public void run() {
- sciView.getCamera().setPosition( new Vector3f(0,5,5) );
+ override fun run() {
+ sciView.camera?.position = Vector3f(0.0f, 1.65f, 5f)
}
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/view/ResetCameraRotation.java b/src/main/java/sc/iview/commands/view/ResetCameraRotation.kt
similarity index 66%
rename from src/main/java/sc/iview/commands/view/ResetCameraRotation.java
rename to src/main/java/sc/iview/commands/view/ResetCameraRotation.kt
index 88782bfb..d89faae4 100644
--- a/src/main/java/sc/iview/commands/view/ResetCameraRotation.java
+++ b/src/main/java/sc/iview/commands/view/ResetCameraRotation.kt
@@ -26,39 +26,32 @@
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
-package sc.iview.commands.view;
+package sc.iview.commands.view
-import org.joml.Quaternionf;
-import org.scijava.command.Command;
-import org.scijava.log.LogService;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-import sc.iview.SciView;
-
-import static sc.iview.commands.MenuWeights.VIEW;
-import static sc.iview.commands.MenuWeights.VIEW_RESET_CAMERA_ROTATION;
+import org.joml.Quaternionf
+import org.scijava.command.Command
+import org.scijava.log.LogService
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights.VIEW
+import sc.iview.commands.MenuWeights.VIEW_RESET_CAMERA_ROTATION
/**
* Command to set the camera rotation to the default orientation.
*
* @author Kyle Harrington
- *
*/
-@Plugin(type = Command.class, menuRoot = "SciView", //
-menu = {@Menu(label = "View", weight = VIEW), //
- @Menu(label = "Reset Camera Rotation", weight = VIEW_RESET_CAMERA_ROTATION)})
-public class ResetCameraRotation implements Command {
-
+@Plugin(type = Command::class, menuRoot = "SciView", menu = [Menu(label = "View", weight = VIEW), Menu(label = "Reset Camera Rotation", weight = VIEW_RESET_CAMERA_ROTATION)])
+class ResetCameraRotation : Command {
@Parameter
- private LogService logService;
+ private lateinit var logService: LogService
@Parameter
- private SciView sciView;
+ private lateinit var sciView: SciView
- @Override
- public void run() {
- sciView.getCamera().setRotation( new Quaternionf(0, 0, 0, 1) );
+ override fun run() {
+ sciView.camera?.rotation = Quaternionf(0f, 0f, 0f, 1f)
}
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/view/RotateView.java b/src/main/java/sc/iview/commands/view/RotateView.kt
similarity index 63%
rename from src/main/java/sc/iview/commands/view/RotateView.java
rename to src/main/java/sc/iview/commands/view/RotateView.kt
index 922c071b..9335b24d 100644
--- a/src/main/java/sc/iview/commands/view/RotateView.java
+++ b/src/main/java/sc/iview/commands/view/RotateView.kt
@@ -26,45 +26,37 @@
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
-package sc.iview.commands.view;
+package sc.iview.commands.view
-import static sc.iview.commands.MenuWeights.VIEW;
-import static sc.iview.commands.MenuWeights.VIEW_ROTATE;
-
-import org.scijava.command.Command;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-
-import sc.iview.SciView;
+import org.scijava.command.Command
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights.VIEW
+import sc.iview.commands.MenuWeights.VIEW_ROTATE
/**
* Command to circle the camera around the currently active Node
*
* @author Kyle Harrington
- *
*/
-@Plugin(type = Command.class, menuRoot = "SciView", //
- menu = { @Menu(label = "View", weight = VIEW), //
- @Menu(label = "Circle camera around current object", weight = VIEW_ROTATE) })
-public class RotateView implements Command {
-
+@Plugin(type = Command::class, menuRoot = "SciView", menu = [Menu(label = "View", weight = VIEW), Menu(label = "Circle camera around current object", weight = VIEW_ROTATE)])
+class RotateView : Command {
@Parameter
- private SciView sciView;
+ private lateinit var sciView: SciView
@Parameter
- private int xSpeed = 3;
+ private var xSpeed = 3
@Parameter
- private int ySpeed = 0;
-
- @Override
- public void run() {
- sciView.animate( 30, () -> {
- sciView.getTargetArcball().init( 1, 1 );
- sciView.getTargetArcball().drag( 1+xSpeed, 1+ySpeed );
- sciView.getTargetArcball().end( 1+xSpeed, 1+ySpeed );
- } );
+ private var ySpeed = 0
+
+ override fun run() {
+ sciView.animate(30) {
+ sciView.targetArcball.init(1, 1)
+ sciView.targetArcball.drag(1 + xSpeed, 1 + ySpeed)
+ sciView.targetArcball.end(1 + xSpeed, 1 + ySpeed)
+ }
}
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/view/SaveCameraConfiguration.java b/src/main/java/sc/iview/commands/view/SaveCameraConfiguration.java
deleted file mode 100644
index b5115335..00000000
--- a/src/main/java/sc/iview/commands/view/SaveCameraConfiguration.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*-
- * #%L
- * Scenery-backed 3D visualization package for ImageJ.
- * %%
- * Copyright (C) 2016 - 2020 SciView developers.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-package sc.iview.commands.view;
-
-import com.google.common.io.Files;
-import org.joml.Quaternionf;
-import org.joml.Vector3f;
-import org.scijava.command.Command;
-import org.scijava.log.LogService;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-import org.scijava.script.ScriptService;
-import sc.iview.SciView;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-
-import static sc.iview.commands.MenuWeights.VIEW;
-import static sc.iview.commands.MenuWeights.VIEW_SAVE_CAMERA_CONFIGURATION;
-
-/**
- * Save the current camera configuration to file.
- *
- * @author Kyle Harrington
- *
- */
-@Plugin(type = Command.class, menuRoot = "SciView", //
-menu = {@Menu(label = "View", weight = VIEW), //
- @Menu(label = "Save Camera Configuration", weight = VIEW_SAVE_CAMERA_CONFIGURATION)})
-public class SaveCameraConfiguration implements Command {
-
- @Parameter
- private LogService logService;
-
- @Parameter
- private SciView sciView;
-
- @Parameter
- private File saveFile;
-
- @Parameter
- private ScriptService scriptService;
-
- @Override
- public void run() {
- try {
- FileWriter fw = new FileWriter(saveFile);
- BufferedWriter bw = new BufferedWriter(fw);
-
- if( !Files.getFileExtension(saveFile.getAbsolutePath()).equalsIgnoreCase("clj") )
- throw new IOException("File must be Clojure (extension = .clj)");
-
- Vector3f pos = sciView.getCamera().getPosition();
- Quaternionf rot = sciView.getCamera().getRotation();
-
- String scriptContents = "; @SciView sciView\n\n";
- scriptContents += "(.setPosition (.getCamera sciView) (cleargl.GLVector. (float-array [" + pos.x() + " " + pos.y() + " " + pos.z() + "])))\n";
- scriptContents += "(.setRotation (.getCamera sciView) (com.jogamp.opengl.math.Quaternion. " + rot.x() + " " + rot.y() + " " + rot.z() + " " + rot.w() + "))\n";
-
- bw.write(scriptContents);
-
- bw.close();
- fw.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
-}
diff --git a/src/main/java/sc/iview/commands/view/SaveCameraConfiguration.kt b/src/main/java/sc/iview/commands/view/SaveCameraConfiguration.kt
new file mode 100644
index 00000000..4d726ea8
--- /dev/null
+++ b/src/main/java/sc/iview/commands/view/SaveCameraConfiguration.kt
@@ -0,0 +1,81 @@
+/*-
+ * #%L
+ * Scenery-backed 3D visualization package for ImageJ.
+ * %%
+ * Copyright (C) 2016 - 2020 SciView developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package sc.iview.commands.view
+
+import com.google.common.io.Files
+import org.scijava.command.Command
+import org.scijava.log.LogService
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import org.scijava.script.ScriptService
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights.VIEW
+import sc.iview.commands.MenuWeights.VIEW_SAVE_CAMERA_CONFIGURATION
+import java.io.BufferedWriter
+import java.io.File
+import java.io.FileWriter
+import java.io.IOException
+
+/**
+ * Save the current camera configuration to file.
+ *
+ * @author Kyle Harrington
+ */
+@Suppress("UnstableApiUsage")
+@Plugin(type = Command::class, menuRoot = "SciView", menu = [Menu(label = "View", weight = VIEW), Menu(label = "Save Camera Configuration", weight = VIEW_SAVE_CAMERA_CONFIGURATION)])
+class SaveCameraConfiguration : Command {
+ @Parameter
+ private lateinit var sciView: SciView
+
+ @Parameter
+ private lateinit var saveFile: File
+
+ override fun run() {
+ try {
+ val cam = sciView.camera ?: return
+
+ val fw = FileWriter(saveFile)
+ val bw = BufferedWriter(fw)
+ if (!Files.getFileExtension(saveFile.absolutePath).equals("clj", ignoreCase = true)) throw IOException("File must be Clojure (extension = .clj)")
+ val pos = cam.position
+ val rot = cam.rotation
+ var scriptContents = "; @SciView sciView\n\n"
+ scriptContents += """(.setPosition (.getCamera sciView) (cleargl.GLVector. (float-array [${pos.x()} ${pos.y()} ${pos.z()}])))
+"""
+ scriptContents += """(.setRotation (.getCamera sciView) (com.jogamp.opengl.math.Quaternion. ${rot.x()} ${rot.y()} ${rot.z()} ${rot.w()}))
+"""
+ bw.write(scriptContents)
+ bw.close()
+ fw.close()
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/view/Screenshot.java b/src/main/java/sc/iview/commands/view/Screenshot.java
deleted file mode 100644
index ac7ad65a..00000000
--- a/src/main/java/sc/iview/commands/view/Screenshot.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*-
- * #%L
- * Scenery-backed 3D visualization package for ImageJ.
- * %%
- * Copyright (C) 2016 - 2020 SciView developers.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-package sc.iview.commands.view;
-
-import graphics.scenery.backends.RenderedImage;
-import net.imagej.Dataset;
-import net.imagej.ImgPlus;
-import net.imagej.ops.OpService;
-import net.imglib2.RandomAccessibleInterval;
-import net.imglib2.img.Img;
-import net.imglib2.img.display.imagej.ImageJFunctions;
-import net.imglib2.type.numeric.ARGBType;
-import org.scijava.ItemIO;
-import org.scijava.command.Command;
-import org.scijava.io.IOService;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-import org.scijava.ui.UIService;
-import sc.iview.SciView;
-
-import javax.imageio.ImageIO;
-import java.awt.image.BufferedImage;
-import java.awt.image.DataBufferByte;
-import java.io.File;
-import java.io.IOException;
-
-import static sc.iview.commands.MenuWeights.VIEW;
-import static sc.iview.commands.MenuWeights.VIEW_SCREENSHOT;
-
-/**
- * Command to take a screenshot. The screenshot is opened in ImageJ.
- *
- * @author Kyle Harrington
- *
- */
-@Plugin(type = Command.class, menuRoot = "SciView", //
- menu = { @Menu(label = "View", weight = VIEW), //
- @Menu(label = "Screenshot", weight = VIEW_SCREENSHOT) })
-public class Screenshot implements Command {
-
- @Parameter
- private SciView sciView;
-
- @Parameter
- private OpService opService;
-
- @Parameter
- private IOService ioService;
-
- @Parameter
- private UIService uiService;
-
- @Parameter(type = ItemIO.OUTPUT)
- private ImgPlus img;
-
- @Override
- public void run() {
- Img screenshot = sciView.getARGBScreenshot();
-
- img = new ImgPlus<>(screenshot);
-
- uiService.show(img);
- }
-}
diff --git a/src/main/java/sc/iview/commands/view/Screenshot.kt b/src/main/java/sc/iview/commands/view/Screenshot.kt
new file mode 100644
index 00000000..4b598f92
--- /dev/null
+++ b/src/main/java/sc/iview/commands/view/Screenshot.kt
@@ -0,0 +1,65 @@
+/*-
+ * #%L
+ * Scenery-backed 3D visualization package for ImageJ.
+ * %%
+ * Copyright (C) 2016 - 2020 SciView developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package sc.iview.commands.view
+
+import net.imagej.ImgPlus
+import net.imagej.ops.OpService
+import org.scijava.ItemIO
+import org.scijava.command.Command
+import org.scijava.io.IOService
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import org.scijava.ui.UIService
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights.VIEW
+import sc.iview.commands.MenuWeights.VIEW_SCREENSHOT
+
+/**
+ * Command to take a screenshot. The screenshot is opened in ImageJ.
+ *
+ * @author Kyle Harrington
+ */
+@Plugin(type = Command::class, menuRoot = "SciView", menu = [Menu(label = "View", weight = VIEW), Menu(label = "Screenshot", weight = VIEW_SCREENSHOT)])
+class Screenshot : Command {
+ @Parameter
+ private lateinit var sciView: SciView
+
+ @Parameter
+ private lateinit var uiService: UIService
+
+ @Parameter(type = ItemIO.OUTPUT)
+ private var img: ImgPlus<*>? = null
+
+ override fun run() {
+ val screenshot = sciView.aRGBScreenshot
+ img = ImgPlus(screenshot)
+ uiService.show(img)
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/view/SetFarPlane.java b/src/main/java/sc/iview/commands/view/SetFarPlane.kt
similarity index 68%
rename from src/main/java/sc/iview/commands/view/SetFarPlane.java
rename to src/main/java/sc/iview/commands/view/SetFarPlane.kt
index 78ecf8f2..24c2b8ed 100644
--- a/src/main/java/sc/iview/commands/view/SetFarPlane.java
+++ b/src/main/java/sc/iview/commands/view/SetFarPlane.kt
@@ -26,42 +26,31 @@
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
-package sc.iview.commands.view;
+package sc.iview.commands.view
-import org.scijava.command.Command;
-import org.scijava.log.LogService;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-import sc.iview.SciView;
-
-import static sc.iview.commands.MenuWeights.*;
+import org.scijava.command.Command
+import org.scijava.log.LogService
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights.VIEW
+import sc.iview.commands.MenuWeights.VIEW_SET_FAR_PLANE
/**
* Command to set the far plane for the renderer. Everything beyond this **will not** be rendered
*
* @author Kyle Harrington
- *
*/
-@Plugin(type = Command.class, menuRoot = "SciView", //
- menu = {@Menu(label = "View", weight = VIEW), //
- @Menu(label = "Set Far Plane", weight = VIEW_SET_FAR_PLANE)})
-public class SetFarPlane implements Command {
-
- @Parameter
- private LogService logService;
-
+@Plugin(type = Command::class, menuRoot = "SciView", menu = [Menu(label = "View", weight = VIEW), Menu(label = "Set Far Plane", weight = VIEW_SET_FAR_PLANE)])
+class SetFarPlane : Command {
@Parameter
- private SciView sciView;
+ private lateinit var sciView: SciView
@Parameter
- private float farPlane = 1000f;
-
- @Override
- public void run() {
-
- sciView.getCamera().setFarPlaneDistance(farPlane);
+ private var farPlane = 1000f
+ override fun run() {
+ sciView.camera?.farPlaneDistance = farPlane
}
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/view/SetLUT.java b/src/main/java/sc/iview/commands/view/SetLUT.java
deleted file mode 100644
index 954cae95..00000000
--- a/src/main/java/sc/iview/commands/view/SetLUT.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*-
- * #%L
- * Scenery-backed 3D visualization package for ImageJ.
- * %%
- * Copyright (C) 2016 - 2020 SciView developers.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-package sc.iview.commands.view;
-
-import graphics.scenery.Node;
-import net.imagej.lut.LUTService;
-import net.imglib2.display.AbstractArrayColorTable;
-import net.imglib2.display.ColorTable;
-import org.scijava.command.Command;
-import org.scijava.command.DynamicCommand;
-import org.scijava.module.MutableModuleItem;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-import sc.iview.SciView;
-
-import java.io.IOException;
-import java.util.ArrayList;
-
-import static sc.iview.commands.MenuWeights.VIEW;
-import static sc.iview.commands.MenuWeights.VIEW_SET_LUT;
-
-/**
- * Command to set the currently used Look Up Table (LUT). This is a colormap for the volume.
- *
- * @author Kyle Harrington
- *
- */
-@Plugin(type = Command.class, menuRoot = "SciView", //
- menu = { @Menu(label = "View", weight = VIEW), //
- @Menu(label = "Set LUT", weight = VIEW_SET_LUT) })
-public class SetLUT extends DynamicCommand {
-
- @Parameter
- private SciView sciView;
-
- @Parameter
- private LUTService lutService;
-
- @Parameter(label = "Node")
- private Node node;
-
- @Parameter(label = "Selected LUT", choices = {}, callback = "lutNameChanged")
- private String lutName;
-
- @Parameter(label = "LUT Selection")
- private ColorTable colorTable;
-
- protected void lutNameChanged() {
- final MutableModuleItem lutNameItem = getInfo().getMutableInput("lutName", String.class);
- try {
- colorTable = lutService.loadLUT( lutService.findLUTs().get( lutName ) );
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- @Override
- public void initialize() {
- try {
- colorTable = lutService.loadLUT( lutService.findLUTs().get( "Red.lut" ) );
- } catch (IOException e) {
- e.printStackTrace();
- }
- final MutableModuleItem lutNameItem = getInfo().getMutableInput("lutName", String.class );
- lutNameItem.setChoices( new ArrayList( lutService.findLUTs().keySet() ) );
- }
-
- @Override
- public void run() {
- sciView.setColormap( node, (AbstractArrayColorTable) colorTable);
- }
-}
diff --git a/src/main/java/sc/iview/commands/view/SetLUT.kt b/src/main/java/sc/iview/commands/view/SetLUT.kt
new file mode 100644
index 00000000..9a8bc975
--- /dev/null
+++ b/src/main/java/sc/iview/commands/view/SetLUT.kt
@@ -0,0 +1,91 @@
+/*-
+ * #%L
+ * Scenery-backed 3D visualization package for ImageJ.
+ * %%
+ * Copyright (C) 2016 - 2020 SciView developers.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package sc.iview.commands.view
+
+import graphics.scenery.Node
+import net.imagej.lut.LUTService
+import net.imglib2.display.AbstractArrayColorTable
+import net.imglib2.display.ColorTable
+import org.scijava.command.Command
+import org.scijava.command.DynamicCommand
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights.VIEW
+import sc.iview.commands.MenuWeights.VIEW_SET_LUT
+import java.io.IOException
+import java.util.*
+
+/**
+ * Command to set the currently used Look Up Table (LUT). This is a colormap for the volume.
+ *
+ * @author Kyle Harrington
+ */
+@Suppress("TYPE_INFERENCE_ONLY_INPUT_TYPES_WARNING")
+@Plugin(type = Command::class, menuRoot = "SciView", menu = [Menu(label = "View", weight = VIEW), Menu(label = "Set LUT", weight = VIEW_SET_LUT)])
+class SetLUT : DynamicCommand() {
+ @Parameter
+ private lateinit var sciView: SciView
+
+ @Parameter
+ private lateinit var lutService: LUTService
+
+ @Parameter(label = "Node")
+ private lateinit var node: Node
+
+ @Parameter(label = "Selected LUT", choices = [], callback = "lutNameChanged")
+ private lateinit var lutName: String
+
+ @Parameter(label = "LUT Selection")
+ private lateinit var colorTable: ColorTable
+
+ protected fun lutNameChanged() {
+ val lutNameItem = info.getMutableInput("lutName", String::class.java)
+ try {
+ colorTable = lutService.loadLUT(lutService.findLUTs()[lutNameItem])
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+
+ override fun initialize() {
+ try {
+ colorTable = lutService.loadLUT(lutService.findLUTs()["Red.lut"])
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ val lutNameItem = info.getMutableInput("lutName", String::class.java)
+ lutNameItem.choices = ArrayList(lutService.findLUTs().keys)
+ }
+
+ override fun run() {
+ sciView.setColormap(node, colorTable)
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/view/SetSupersamplingFactor.java b/src/main/java/sc/iview/commands/view/SetSupersamplingFactor.kt
similarity index 65%
rename from src/main/java/sc/iview/commands/view/SetSupersamplingFactor.java
rename to src/main/java/sc/iview/commands/view/SetSupersamplingFactor.kt
index ff95132a..b9699f75 100644
--- a/src/main/java/sc/iview/commands/view/SetSupersamplingFactor.java
+++ b/src/main/java/sc/iview/commands/view/SetSupersamplingFactor.kt
@@ -26,42 +26,31 @@
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
-package sc.iview.commands.view;
+package sc.iview.commands.view
-import org.scijava.command.Command;
-import org.scijava.log.LogService;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-import sc.iview.SciView;
-
-import static sc.iview.commands.MenuWeights.*;
+import org.scijava.command.Command
+import org.scijava.log.LogService
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights.VIEW
+import sc.iview.commands.MenuWeights.VIEW_SET_SUPERSAMPLING_FACTOR
/**
* Command to set scenery's Supersampling Factor
*
* @author Kyle Harrington
- *
*/
-@Plugin(type = Command.class, menuRoot = "SciView", //
- menu = {@Menu(label = "View", weight = VIEW), //
- @Menu(label = "Set Supersampling Factor", weight = VIEW_SET_SUPERSAMPLING_FACTOR)})
-public class SetSupersamplingFactor implements Command {
-
- @Parameter
- private LogService logService;
-
+@Plugin(type = Command::class, menuRoot = "SciView", menu = [Menu(label = "View", weight = VIEW), Menu(label = "Set Supersampling Factor", weight = VIEW_SET_SUPERSAMPLING_FACTOR)])
+class SetSupersamplingFactor : Command {
@Parameter
- private SciView sciView;
+ private lateinit var sciView: SciView
@Parameter
- private double supersamplingFactor = 1.0;
-
- @Override
- public void run() {
-
- sciView.getSceneryRenderer().getSettings().set("Renderer.SupersamplingFactor",supersamplingFactor);
+ private var supersamplingFactor = 1.0
+ override fun run() {
+ sciView.getSceneryRenderer()?.settings?.set("Renderer.SupersamplingFactor", supersamplingFactor)
}
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/view/SetTransferFunction.java b/src/main/java/sc/iview/commands/view/SetTransferFunction.kt
similarity index 57%
rename from src/main/java/sc/iview/commands/view/SetTransferFunction.java
rename to src/main/java/sc/iview/commands/view/SetTransferFunction.kt
index 61a9ef6d..db8409ea 100644
--- a/src/main/java/sc/iview/commands/view/SetTransferFunction.java
+++ b/src/main/java/sc/iview/commands/view/SetTransferFunction.kt
@@ -26,74 +26,53 @@
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
-package sc.iview.commands.view;
+package sc.iview.commands.view
-import graphics.scenery.volumes.TransferFunction;
-import graphics.scenery.volumes.Volume;
-import org.scijava.command.Command;
-import org.scijava.command.InteractiveCommand;
-import org.scijava.log.LogService;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-import org.scijava.widget.NumberWidget;
-import sc.iview.SciView;
-
-import static sc.iview.commands.MenuWeights.VIEW;
-import static sc.iview.commands.MenuWeights.VIEW_SET_TRANSFER_FUNCTION;
+import graphics.scenery.volumes.Volume
+import org.scijava.command.Command
+import org.scijava.command.InteractiveCommand
+import org.scijava.log.LogService
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import org.scijava.widget.NumberWidget
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights.VIEW
+import sc.iview.commands.MenuWeights.VIEW_SET_TRANSFER_FUNCTION
/**
* Command to set the transfer function of a Volume
*
* @author Kyle Harrington
- *
*/
-@Plugin(type = Command.class, menuRoot = "SciView", //
- menu = {@Menu(label = "View", weight = VIEW), //
- @Menu(label = "Set Transfer Function", weight = VIEW_SET_TRANSFER_FUNCTION)})
-public class SetTransferFunction extends InteractiveCommand {
-
- @Parameter
- private LogService logService;
-
- @Parameter
- private SciView sciView;
-
+@Plugin(type = Command::class, menuRoot = "SciView", menu = [Menu(label = "View", weight = VIEW), Menu(label = "Set Transfer Function", weight = VIEW_SET_TRANSFER_FUNCTION)])
+class SetTransferFunction : InteractiveCommand() {
@Parameter(label = "Target Volume")
- private Volume volume;
+ private lateinit var volume: Volume
- @Parameter(label = "TF Ramp Min", style = NumberWidget.SLIDER_STYLE, //
- min = "0", max = "1.0", stepSize = "0.001", callback = "updateTransferFunction")
- private float rampMin = 0;
+ @Parameter(label = "TF Ramp Min", style = NumberWidget.SLIDER_STYLE, min = "0", max = "1.0", stepSize = "0.001", callback = "updateTransferFunction")
+ private var rampMin = 0f
- @Parameter(label = "TF Ramp Max", style = NumberWidget.SLIDER_STYLE, //
- min = "0", max = "1.0", stepSize = "0.001", callback = "updateTransferFunction")
- private float rampMax = 1.0f;
+ @Parameter(label = "TF Ramp Max", style = NumberWidget.SLIDER_STYLE, min = "0", max = "1.0", stepSize = "0.001", callback = "updateTransferFunction")
+ private var rampMax = 1.0f
/**
* Nothing happens here, as cancelling the dialog is not possible.
*/
- @Override
- public void cancel() {
-
- }
+ override fun cancel() {}
/**
* Nothing is done here, as the refreshing of the objects properties works via
* callback methods.
*/
- @Override
- public void run() {
-
- }
-
- protected void updateTransferFunction() {
- TransferFunction tf = volume.getTransferFunction();
+ override fun run() {}
+ protected fun updateTransferFunction() {
+ val tf = volume.transferFunction
//float currentOffset = tf.getControlPoint$scenery(1).getValue();
//float currentFactor = tf.getControlPoint$scenery(2).getFactor();
- tf.clear();
- tf.addControlPoint(0.0f, 0.0f);
- tf.addControlPoint(rampMin, 0.0f);
- tf.addControlPoint(1.0f, rampMax);
+ tf.clear()
+ tf.addControlPoint(0.0f, 0.0f)
+ tf.addControlPoint(rampMin, 0.0f)
+ tf.addControlPoint(1.0f, rampMax)
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/view/StartRecordingVideo.java b/src/main/java/sc/iview/commands/view/StartRecordingVideo.kt
similarity index 60%
rename from src/main/java/sc/iview/commands/view/StartRecordingVideo.java
rename to src/main/java/sc/iview/commands/view/StartRecordingVideo.kt
index f76bac48..64d935c2 100644
--- a/src/main/java/sc/iview/commands/view/StartRecordingVideo.java
+++ b/src/main/java/sc/iview/commands/view/StartRecordingVideo.kt
@@ -26,40 +26,38 @@
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
-package sc.iview.commands.view;
+package sc.iview.commands.view
-import org.scijava.command.Command;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-import sc.iview.SciView;
-
-import static sc.iview.commands.MenuWeights.*;
+import org.scijava.command.Command
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights.VIEW
+import sc.iview.commands.MenuWeights.VIEW_START_RECORDING_VIDEO
+import kotlin.math.max
/**
* Command to start recording a video. Currently this will record to ~/Desktop
*
* @author Kyle Harrington
- *
*/
-@Plugin(type = Command.class, menuRoot = "SciView", //
- menu = { @Menu(label = "View", weight = VIEW), //
- @Menu(label = "Start recording video", weight = VIEW_START_RECORDING_VIDEO) })
-public class StartRecordingVideo implements Command {
+@Plugin(type = Command::class, menuRoot = "SciView", menu = [Menu(label = "View", weight = VIEW), Menu(label = "Start recording video", weight = VIEW_START_RECORDING_VIDEO)])
+class StartRecordingVideo : Command {
@Parameter
- private SciView sciView;
+ private lateinit var sciView: SciView
@Parameter
- private int bitrate = 10000000;// 10 MBit
+ private var bitrate = 10000000 // 10 MBit
- @Parameter(choices={"VeryLow", "Low", "Medium", "High", "Ultra", "Insane"}, style="listBox")
- private String videoEncodingQuality;// listed as an enum here, cant access from java https://github.com/scenerygraphics/scenery/blob/1a451c2864e5a48e47622d9313fe1681e47d7958/src/main/kotlin/graphics/scenery/utils/H264Encoder.kt#L65
+ @Parameter(choices = ["VeryLow", "Low", "Medium", "High", "Ultra", "Insane"], style = "listBox")
+ private lateinit var videoEncodingQuality // listed as an enum here, cant access from java https://github.com/scenerygraphics/scenery/blob/1a451c2864e5a48e47622d9313fe1681e47d7958/src/main/kotlin/graphics/scenery/utils/H264Encoder.kt#L65
+ : String
- @Override
- public void run() {
- bitrate = Math.max(0,bitrate);
- sciView.getScenerySettings().set("VideoEncoder.Bitrate", bitrate);
- sciView.getScenerySettings().set("VideoEncoder.Quality", videoEncodingQuality);
- sciView.toggleRecordVideo();
+ override fun run() {
+ bitrate = max(0, bitrate)
+ sciView.getScenerySettings().set("VideoEncoder.Bitrate", bitrate)
+ sciView.getScenerySettings().set("VideoEncoder.Quality", videoEncodingQuality)
+ sciView.toggleRecordVideo()
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/view/StopAnimation.java b/src/main/java/sc/iview/commands/view/StopAnimation.kt
similarity index 70%
rename from src/main/java/sc/iview/commands/view/StopAnimation.java
rename to src/main/java/sc/iview/commands/view/StopAnimation.kt
index 38899f2e..cd0b1307 100644
--- a/src/main/java/sc/iview/commands/view/StopAnimation.java
+++ b/src/main/java/sc/iview/commands/view/StopAnimation.kt
@@ -26,34 +26,27 @@
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
-package sc.iview.commands.view;
+package sc.iview.commands.view
-import static sc.iview.commands.MenuWeights.VIEW;
-import static sc.iview.commands.MenuWeights.VIEW_STOP_ANIMATION;
-
-import org.scijava.command.Command;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-
-import sc.iview.SciView;
+import org.scijava.command.Command
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights.VIEW
+import sc.iview.commands.MenuWeights.VIEW_STOP_ANIMATION
/**
* Command to stop all current animations
*
* @author Kyle Harrington
- *
*/
-@Plugin(type = Command.class, menuRoot = "SciView", //
- menu = { @Menu(label = "View", weight = VIEW), //
- @Menu(label = "Stop Animation", weight = VIEW_STOP_ANIMATION) })
-public class StopAnimation implements Command {
-
+@Plugin(type = Command::class, menuRoot = "SciView", menu = [Menu(label = "View", weight = VIEW), Menu(label = "Stop Animation", weight = VIEW_STOP_ANIMATION)])
+class StopAnimation : Command {
@Parameter
- private SciView sciView;
+ private lateinit var sciView: SciView
- @Override
- public void run() {
- sciView.stopAnimation();
+ override fun run() {
+ sciView.stopAnimation()
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/view/StopRecordingVideo.java b/src/main/java/sc/iview/commands/view/StopRecordingVideo.kt
similarity index 69%
rename from src/main/java/sc/iview/commands/view/StopRecordingVideo.java
rename to src/main/java/sc/iview/commands/view/StopRecordingVideo.kt
index db9b2f88..b28ec6fa 100644
--- a/src/main/java/sc/iview/commands/view/StopRecordingVideo.java
+++ b/src/main/java/sc/iview/commands/view/StopRecordingVideo.kt
@@ -26,33 +26,27 @@
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
-package sc.iview.commands.view;
+package sc.iview.commands.view
-import org.scijava.command.Command;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-import sc.iview.SciView;
-
-import static sc.iview.commands.MenuWeights.VIEW;
-import static sc.iview.commands.MenuWeights.VIEW_STOP_RECORDING_VIDEO;
+import org.scijava.command.Command
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights.VIEW
+import sc.iview.commands.MenuWeights.VIEW_STOP_RECORDING_VIDEO
/**
* Command to stop recording the current video
*
* @author Kyle Harrington
- *
*/
-@Plugin(type = Command.class, menuRoot = "SciView", //
- menu = { @Menu(label = "View", weight = VIEW), //
- @Menu(label = "Stop recording video", weight = VIEW_STOP_RECORDING_VIDEO) })
-public class StopRecordingVideo implements Command {
-
+@Plugin(type = Command::class, menuRoot = "SciView", menu = [Menu(label = "View", weight = VIEW), Menu(label = "Stop recording video", weight = VIEW_STOP_RECORDING_VIDEO)])
+class StopRecordingVideo : Command {
@Parameter
- private SciView sciView;
+ private lateinit var sciView: SciView
- @Override
- public void run() {
- sciView.toggleRecordVideo();
+ override fun run() {
+ sciView.toggleRecordVideo()
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/view/ToggleBoundingGrid.java b/src/main/java/sc/iview/commands/view/ToggleBoundingGrid.kt
similarity index 56%
rename from src/main/java/sc/iview/commands/view/ToggleBoundingGrid.java
rename to src/main/java/sc/iview/commands/view/ToggleBoundingGrid.kt
index eb5a9ee7..12553719 100644
--- a/src/main/java/sc/iview/commands/view/ToggleBoundingGrid.java
+++ b/src/main/java/sc/iview/commands/view/ToggleBoundingGrid.kt
@@ -26,57 +26,48 @@
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
-package sc.iview.commands.view;
+package sc.iview.commands.view
-import graphics.scenery.BoundingGrid;
-import graphics.scenery.Mesh;
-import graphics.scenery.Node;
-import org.scijava.command.Command;
-import org.scijava.log.LogService;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-import sc.iview.SciView;
-
-import static sc.iview.commands.MenuWeights.*;
+import graphics.scenery.BoundingGrid
+import graphics.scenery.Mesh
+import graphics.scenery.Node
+import org.scijava.command.Command
+import org.scijava.log.LogService
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights.VIEW
+import sc.iview.commands.MenuWeights.VIEW_TOGGLE_BOUNDING_GRID
/**
* Command to toggle the bounding grid around a Node
*
* @author Kyle Harrington
- *
*/
-@Plugin(type = Command.class, menuRoot = "SciView", //
-menu = {@Menu(label = "View", weight = VIEW), //
- @Menu(label = "Toggle Bounding Grid", weight = VIEW_TOGGLE_BOUNDING_GRID)})
-public class ToggleBoundingGrid implements Command {
-
+@Plugin(type = Command::class, menuRoot = "SciView", menu = [Menu(label = "View", weight = VIEW), Menu(label = "Toggle Bounding Grid", weight = VIEW_TOGGLE_BOUNDING_GRID)])
+class ToggleBoundingGrid : Command {
@Parameter
- private LogService logService;
+ private lateinit var logService: LogService
@Parameter
- private SciView sciView;
+ private lateinit var sciView: SciView
@Parameter
- private Node node;
-
- @Override
- public void run() {
- if( node instanceof Mesh ) {
+ private lateinit var node: Node
- if( node.getMetadata().containsKey("BoundingGrid") ) {
- BoundingGrid bg = (BoundingGrid) node.getMetadata().get("BoundingGrid");
- bg.setNode( null );
- node.getMetadata().remove("BoundingGrid");
- bg.getScene().removeChild(bg);
+ override fun run() {
+ if (node is Mesh) {
+ if (node.metadata.containsKey("BoundingGrid")) {
+ val bg = node.metadata["BoundingGrid"] as BoundingGrid?
+ bg!!.node = null
+ node.metadata.remove("BoundingGrid")
+ bg.getScene()!!.removeChild(bg)
} else {
- BoundingGrid bg = new BoundingGrid();
- bg.setNode(node);
-
- node.getMetadata().put("BoundingGrid", bg);
+ val bg = BoundingGrid()
+ bg.node = node
+ node.metadata["BoundingGrid"] = bg
}
}
-
}
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/view/ToggleInspector.java b/src/main/java/sc/iview/commands/view/ToggleInspector.kt
similarity index 68%
rename from src/main/java/sc/iview/commands/view/ToggleInspector.java
rename to src/main/java/sc/iview/commands/view/ToggleInspector.kt
index c277ef3e..6e80b439 100644
--- a/src/main/java/sc/iview/commands/view/ToggleInspector.java
+++ b/src/main/java/sc/iview/commands/view/ToggleInspector.kt
@@ -26,32 +26,27 @@
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
-package sc.iview.commands.view;
+package sc.iview.commands.view
-import org.scijava.command.Command;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-
-import sc.iview.SciView;
-
-import static sc.iview.commands.MenuWeights.*;
+import org.scijava.command.Command
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights.VIEW
+import sc.iview.commands.MenuWeights.VIEW_TOGGLE_INSPECTOR
/**
- * Command that displays a {@link NodePropertyEditor} window.
+ * Command that displays a [NodePropertyEditor] window.
*
* @author Curtis Rueden
*/
-@Plugin(type = Command.class, initializer = "initValues", menuRoot = "SciView", //
- menu = { @Menu(label = "View", weight = VIEW), //
- @Menu(label = "Toggle Inspector", weight = VIEW_TOGGLE_INSPECTOR) })
-public class ToggleInspector implements Command {
-
+@Plugin(type = Command::class, initializer = "initValues", menuRoot = "SciView", menu = [Menu(label = "View", weight = VIEW), Menu(label = "Toggle Inspector", weight = VIEW_TOGGLE_INSPECTOR)])
+class ToggleInspector : Command {
@Parameter
- private SciView sciView;
+ private lateinit var sciView: SciView
- @Override
- public void run() {
- sciView.toggleInspectorWindow();
+ override fun run() {
+ sciView.toggleInspectorWindow()
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/commands/view/ToggleUnlimitedFramerate.java b/src/main/java/sc/iview/commands/view/ToggleUnlimitedFramerate.java
deleted file mode 100644
index d3399138..00000000
--- a/src/main/java/sc/iview/commands/view/ToggleUnlimitedFramerate.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*-
- * #%L
- * Scenery-backed 3D visualization package for ImageJ.
- * %%
- * Copyright (C) 2016 - 2020 SciView developers.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-package sc.iview.commands.view;
-
-import org.scijava.command.Command;
-import org.scijava.log.LogService;
-import org.scijava.plugin.Menu;
-import org.scijava.plugin.Parameter;
-import org.scijava.plugin.Plugin;
-import sc.iview.SciView;
-
-import static sc.iview.commands.MenuWeights.VIEW;
-import static sc.iview.commands.MenuWeights.VIEW_TOGGLE_UNLIMITED_FRAMERATE;
-
-/**
- * Command to toggle scenery's PushMode. If this is true the scene only renders when it is changed, otherwise it is
- * continuously rendered
- *
- * @author Kyle Harrington
- *
- */
-@Plugin(type = Command.class, menuRoot = "SciView", //
- menu = {@Menu(label = "View", weight = VIEW), //
- @Menu(label = "Toggle Unlimited Framerate", weight = VIEW_TOGGLE_UNLIMITED_FRAMERATE)})
-public class ToggleUnlimitedFramerate implements Command {
-
- @Parameter
- private LogService logService;
-
- @Parameter
- private SciView sciView;
-
- @Override
- public void run() {
- sciView.setPushMode(!sciView.getPushMode());
- }
-
-}
diff --git a/src/main/java/sc/iview/commands/view/ToggleUnlimitedFramerate.kt b/src/main/java/sc/iview/commands/view/ToggleUnlimitedFramerate.kt
new file mode 100644
index 00000000..494aecf1
--- /dev/null
+++ b/src/main/java/sc/iview/commands/view/ToggleUnlimitedFramerate.kt
@@ -0,0 +1,24 @@
+package sc.iview.commands.view
+
+import org.scijava.command.Command
+import org.scijava.plugin.Menu
+import org.scijava.plugin.Parameter
+import org.scijava.plugin.Plugin
+import sc.iview.SciView
+import sc.iview.commands.MenuWeights
+
+/**
+ * Command to toggle scenery's PushMode. If this is true the scene only renders when it is changed, otherwise it is
+ * continuously rendered
+ *
+ * @author Kyle Harrington
+ */
+@Plugin(type = Command::class, menuRoot = "SciView", menu = [Menu(label = "View", weight = MenuWeights.VIEW), Menu(label = "Toggle Unlimited Framerate", weight = MenuWeights.VIEW_TOGGLE_UNLIMITED_FRAMERATE)])
+class ToggleUnlimitedFramerate : Command {
+ @Parameter
+ private lateinit var sciView: SciView
+
+ override fun run() {
+ sciView.setPushMode(!sciView.getPushMode())
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/controls/behaviours/CameraTranslateControl.kt b/src/main/java/sc/iview/controls/behaviours/CameraTranslateControl.kt
index a2c99e88..4416f4ef 100644
--- a/src/main/java/sc/iview/controls/behaviours/CameraTranslateControl.kt
+++ b/src/main/java/sc/iview/controls/behaviours/CameraTranslateControl.kt
@@ -8,6 +8,7 @@ import sc.iview.SciView
* Behavior for translating a camera
*
* @author Kyle Harrington
+ * @author Vladimir Ulman
*/
class CameraTranslateControl(protected val sciView: SciView, var dragSpeed: Float) : DragBehaviour {
private var lastX = 0
diff --git a/src/main/java/sc/iview/controls/behaviours/NodeRotateControl.kt b/src/main/java/sc/iview/controls/behaviours/NodeRotateControl.kt
index b3bfad83..3e461d20 100644
--- a/src/main/java/sc/iview/controls/behaviours/NodeRotateControl.kt
+++ b/src/main/java/sc/iview/controls/behaviours/NodeRotateControl.kt
@@ -29,15 +29,16 @@ class NodeRotateControl(protected val sciView: SciView) : DragBehaviour {
override fun drag(x: Int, y: Int) {
val targetedNode = sciView.activeNode
+ val cam = sciView.camera ?: return
if (targetedNode == null || !targetedNode.lock.tryLock()) return
- val frameYaw = sciView.mouseSpeed * (x - lastX) * 0.0174533f // 0.017 = PI/180
- val framePitch = sciView.mouseSpeed * (y - lastY) * 0.0174533f
+ val frameYaw = sciView.getMouseSpeed() * (x - lastX) * 0.0174533f // 0.017 = PI/180
+ val framePitch = sciView.getMouseSpeed() * (y - lastY) * 0.0174533f
- Quaternionf().rotateAxis(frameYaw, sciView.camera.up)
+ Quaternionf().rotateAxis(frameYaw, cam.up)
.mul(targetedNode.rotation, targetedNode.rotation)
.normalize()
- Quaternionf().rotateAxis(framePitch, sciView.camera.right)
+ Quaternionf().rotateAxis(framePitch, cam.right)
.mul(targetedNode.rotation, targetedNode.rotation)
.normalize()
targetedNode.needsUpdate = true
diff --git a/src/main/java/sc/iview/controls/behaviours/NodeTranslateControl.kt b/src/main/java/sc/iview/controls/behaviours/NodeTranslateControl.kt
index 2ff65c46..56f28679 100644
--- a/src/main/java/sc/iview/controls/behaviours/NodeTranslateControl.kt
+++ b/src/main/java/sc/iview/controls/behaviours/NodeTranslateControl.kt
@@ -58,11 +58,12 @@ class NodeTranslateControl(protected val sciView: SciView) : DragBehaviour, Scro
override fun drag(x: Int, y: Int) {
val targetedNode = sciView.activeNode;
+ val cam = sciView.camera ?: return
if (targetedNode == null || !targetedNode.lock.tryLock()) return
- sciView.camera.right.mul((x - lastX) * sciView.fpsSpeedSlow * sciView.mouseSpeed, dragPosUpdater )
+ cam.right.mul((x - lastX) * sciView.getFPSSpeedSlow() * sciView.getMouseSpeed(), dragPosUpdater )
targetedNode.position.add( dragPosUpdater )
- sciView.camera.up.mul( (lastY - y) * sciView.fpsSpeedSlow * sciView.mouseSpeed, dragPosUpdater )
+ cam.up.mul( (lastY - y) * sciView.getFPSSpeedSlow() * sciView.getMouseSpeed(), dragPosUpdater )
targetedNode.position.add( dragPosUpdater )
targetedNode.needsUpdate = true
@@ -77,9 +78,10 @@ class NodeTranslateControl(protected val sciView: SciView) : DragBehaviour, Scro
override fun scroll(wheelRotation: Double, isHorizontal: Boolean, x: Int, y: Int) {
val targetedNode = sciView.activeNode;
+ val cam = sciView.camera ?: return
if (targetedNode == null || !targetedNode.lock.tryLock()) return
- sciView.camera.forward.mul( wheelRotation.toFloat() * sciView.fpsSpeedSlow * sciView.mouseScrollSpeed, scrollPosUpdater )
+ cam.forward.mul( wheelRotation.toFloat() * sciView.getFPSSpeedSlow() * sciView.getMouseSpeed(), scrollPosUpdater )
targetedNode.position.add( scrollPosUpdater );
targetedNode.needsUpdate = true
diff --git a/src/main/java/sc/iview/controls/behaviours/SceneRollControl.kt b/src/main/java/sc/iview/controls/behaviours/SceneRollControl.kt
index a15d0145..446c81cb 100644
--- a/src/main/java/sc/iview/controls/behaviours/SceneRollControl.kt
+++ b/src/main/java/sc/iview/controls/behaviours/SceneRollControl.kt
@@ -15,7 +15,7 @@ class SceneRollControl(protected val sciView: SciView, protected val byFixedAngI
private val rotQ_CCW: Quaternionf = Quaternionf().rotateAxis(-byFixedAngInRad, 0f, 0f, -1f);
override fun click(x: Int, y: Int) {
- val cam = sciView.camera
+ val cam = sciView.camera ?: return
rotQ_CW.mul(cam.rotation, cam.rotation).normalize()
}
@@ -27,7 +27,7 @@ class SceneRollControl(protected val sciView: SciView, protected val byFixedAngI
}
override fun drag(x: Int, y: Int) {
- val cam = sciView.camera
+ val cam = sciView.camera ?: return
if (x > lastX + minMouseMovementDelta) rotQ_CW.mul(cam.rotation, cam.rotation).normalize()
else if (x < lastX - minMouseMovementDelta) rotQ_CCW.mul(cam.rotation, cam.rotation).normalize()
lastX = x
diff --git a/src/main/java/sc/iview/node/Line3D.kt b/src/main/java/sc/iview/node/Line3D.kt
index cef1dfad..2addae63 100644
--- a/src/main/java/sc/iview/node/Line3D.kt
+++ b/src/main/java/sc/iview/node/Line3D.kt
@@ -1,11 +1,10 @@
package sc.iview.node
import graphics.scenery.*
+import org.joml.Vector3f
import org.scijava.util.ColorRGB
import org.scijava.util.Colors
import sc.iview.Utils
-import sc.iview.vector.JOMLVector3
-import sc.iview.vector.Vector3
import java.util.ArrayList
/**
@@ -24,7 +23,7 @@ class Line3D : Node {
edges = ArrayList()
}
- constructor(points: List, colorRGB: ColorRGB, edgeWidth: Double) {
+ constructor(points: List, colorRGB: ColorRGB, edgeWidth: Double) {
defaultColor = colorRGB
this.edgeWidth = edgeWidth
edges = ArrayList()
@@ -32,8 +31,8 @@ class Line3D : Node {
for (k in points.indices) {
if (k > 0) {
val edge: Node = Cylinder.betweenPoints(
- JOMLVector3.convert(points[k - 1]),
- JOMLVector3.convert(points[k]),
+ points[k - 1],
+ points[k],
edgeWidth.toFloat(),
1f,
15)
@@ -41,14 +40,14 @@ class Line3D : Node {
}
if (sphereJoints) {
val joint: Node = Sphere(edgeWidth.toFloat(), 15)
- joint.position = JOMLVector3.convert(points[k])
+ joint.position = points[k]
joints!!.add(joint)
addChild(joint)
}
}
}
- constructor(points: List, colors: List, edgeWidth: Double) {
+ constructor(points: List, colors: List, edgeWidth: Double) {
this.edgeWidth = edgeWidth
edges = ArrayList()
if (sphereJoints) joints = ArrayList()
@@ -60,8 +59,8 @@ class Line3D : Node {
mat.specular = c
if (k > 0) {
val edge: Node = Cylinder.betweenPoints(
- JOMLVector3.convert(points[k - 1]),
- JOMLVector3.convert(points[k]),
+ points[k - 1],
+ points[k],
edgeWidth.toFloat(),
1f,
15)
@@ -71,7 +70,7 @@ class Line3D : Node {
if (sphereJoints) {
val joint: Node = Sphere(edgeWidth.toFloat(), 15)
joint.material = mat
- joint.position = JOMLVector3.convert(points[k])
+ joint.position = points[k]
joints!!.add(joint)
addChild(joint)
}
diff --git a/src/main/java/sc/iview/process/ControlPoints.kt b/src/main/java/sc/iview/process/ControlPoints.kt
index 654a109c..666a7bcd 100644
--- a/src/main/java/sc/iview/process/ControlPoints.kt
+++ b/src/main/java/sc/iview/process/ControlPoints.kt
@@ -3,14 +3,13 @@ package sc.iview.process
import graphics.scenery.Material
import graphics.scenery.Node
import graphics.scenery.Sphere
+import org.joml.Vector3f
import org.scijava.ui.behaviour.Behaviour
import org.scijava.ui.behaviour.ClickBehaviour
import org.scijava.ui.behaviour.ScrollBehaviour
import org.scijava.util.ColorRGB
import sc.iview.SciView
import sc.iview.Utils
-import sc.iview.vector.JOMLVector3
-import sc.iview.vector.Vector3
import java.util.ArrayList
/**
@@ -20,27 +19,27 @@ import java.util.ArrayList
*/
class ControlPoints {
protected var nodes: MutableList
- private var targetPoint: Node? = null
+ private lateinit var targetPoint: Node
private var controlPointDistance = 0f
fun clearPoints() {
nodes.clear()
}
- val vertices: List
+ val vertices: List
get() {
- val points: MutableList = ArrayList()
+ val points: MutableList = ArrayList()
for (k in nodes.indices) {
- points.add(JOMLVector3(nodes[k].position))
+ points.add(Vector3f(nodes[k].position))
}
return points
}
- fun setPoints(newPoints: Array) {
+ fun setPoints(newPoints: Array) {
nodes.clear()
nodes = ArrayList()
for (k in newPoints.indices) {
val cp = Sphere(DEFAULT_RADIUS, DEFAULT_SEGMENTS)
- cp.position = JOMLVector3.convert(newPoints[k])
+ cp.position = newPoints[k]
nodes.add(cp)
}
}
@@ -55,6 +54,7 @@ class ControlPoints {
}
fun initializeSciView(sciView: SciView, controlPointDistance: Float) {
+ val cam= sciView.camera ?: return
// This is where the command should change the current inputs setup
sciView.stashControls()
sciView.sceneryInputHandler.addBehaviour("place_control_point",
@@ -72,14 +72,14 @@ class ControlPoints {
mat.ambient = Utils.convertToVector3f(TARGET_COLOR)
mat.diffuse = Utils.convertToVector3f(TARGET_COLOR)
(targetPoint as Sphere).material = mat
- (targetPoint as Sphere).position = sciView.camera.position.add(sciView.camera.forward.mul(controlPointDistance))
+ (targetPoint as Sphere).position = cam.position.add(cam.forward.mul(controlPointDistance))
sciView.addNode(targetPoint, false)
//sciView.getCamera().addChild(targetPoint);
(targetPoint as Sphere).update.add {
//targetPoint.getRotation().set(sciView.getCamera().getRotation().conjugate().rotateByAngleY((float) Math.PI));
// Set rotation before setting position
- (targetPoint as Sphere).position = sciView.camera.position.add(sciView.camera.forward.mul(controlPointDistance))
+ (targetPoint as Sphere).position = cam.position.add(cam.forward.mul(controlPointDistance))
}
}
@@ -89,8 +89,9 @@ class ControlPoints {
private fun distanceControlPointBehaviour(sciView: SciView): Behaviour {
return ScrollBehaviour { wheelRotation, _, _, _ ->
+ val cam = sciView.camera!!
controlPointDistance += wheelRotation.toFloat()
- targetPoint!!.position = sciView.camera.position.add(sciView.camera.forward.mul(controlPointDistance))
+ targetPoint.position = cam.position.add(cam.forward.mul(controlPointDistance))
}
}
@@ -102,7 +103,7 @@ class ControlPoints {
controlPoint.material = mat
//controlPoint.setPosition( sciView.getCamera().getTransformation().mult(targetPoint.getPosition().xyzw()) );
- controlPoint.position = targetPoint!!.position
+ controlPoint.position = targetPoint.position
addPoint(controlPoint)
sciView.addNode(controlPoint, false)
}
diff --git a/src/main/java/sc/iview/ui/ContextPopUpNodeChooser.kt b/src/main/java/sc/iview/ui/ContextPopUpNodeChooser.kt
index 38819e58..2954dc4f 100644
--- a/src/main/java/sc/iview/ui/ContextPopUpNodeChooser.kt
+++ b/src/main/java/sc/iview/ui/ContextPopUpNodeChooser.kt
@@ -6,10 +6,9 @@ import javax.swing.JPopupMenu
class ContextPopUpNodeChooser(sv: SciView) : JPopupMenu() {
init {
- for (m in sv.objectSelectionLastResult.matches) {
- var n = m.node
- add( JMenuItem(n.name) )
- .addActionListener { sv.activeNode = n }
+ sv.objectSelectionLastResult?.matches?.forEach { match ->
+ add( JMenuItem(match.node.name) )
+ .addActionListener { sv.setActiveNode(match.node) }
}
}
}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/ui/ProgressPie.kt b/src/main/java/sc/iview/ui/ProgressPie.kt
new file mode 100644
index 00000000..497225d7
--- /dev/null
+++ b/src/main/java/sc/iview/ui/ProgressPie.kt
@@ -0,0 +1,60 @@
+package sc.iview.ui
+
+import graphics.scenery.utils.LazyLogger
+import java.awt.Color
+import java.awt.Graphics
+import java.awt.Graphics2D
+import java.awt.Rectangle
+import javax.swing.JComponent
+import kotlin.math.roundToInt
+
+class ProgressPie: JComponent() {
+ class Slice(var value: Double, var color: Color)
+ private val logger by LazyLogger()
+
+ private var slices = arrayOf(
+ Slice(0.0, Color.WHITE), Slice(100.0, Color.LIGHT_GRAY)
+ )
+
+ init {
+ isVisible = true
+ }
+
+ var value = 0.0
+ set(value) {
+ slices[1].value = value
+ slices[0].value = 100.0 - value
+ field = value
+ }
+
+ override fun paintComponent(g: Graphics) {
+ super.paintComponent(g)
+ drawPie(g, bounds, slices)
+ }
+
+ fun drawPie(graphics: Graphics, area: Rectangle, slices: Array) {
+ val g = graphics.create() as Graphics2D
+
+ var total = 0.0
+ for (i in slices.indices) {
+ total += slices[i].value
+ }
+ var curValue = 0.0
+ var startAngle: Int
+ for (i in slices.indices) {
+ // angles for fillArc start at East, so we move back 90 degrees to start at North
+ startAngle = (curValue * 360 / total).toInt() + 90
+ val arcAngle = (slices[i].value * 360 / total).toInt()
+ g.color = slices[i].color
+
+ val relativeSize = 0.75f
+ val size = (area.height * relativeSize).roundToInt()
+ val centerX = (size*(1.0f-relativeSize)/2.0f).roundToInt()
+ val centerY = (size*(1.0f-relativeSize)/2.0f).roundToInt()
+ g.fillArc(centerX, centerY, size, size, startAngle, arcAngle)
+ curValue += slices[i].value
+ }
+
+ graphics.dispose()
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/ui/Task.kt b/src/main/java/sc/iview/ui/Task.kt
new file mode 100644
index 00000000..bc98e3bb
--- /dev/null
+++ b/src/main/java/sc/iview/ui/Task.kt
@@ -0,0 +1,3 @@
+package sc.iview.ui
+
+data class Task(val source: String, var status: String, var completion: Float = 0.0f)
\ No newline at end of file
diff --git a/src/main/java/sc/iview/ui/TaskManager.kt b/src/main/java/sc/iview/ui/TaskManager.kt
new file mode 100644
index 00000000..bbdefe23
--- /dev/null
+++ b/src/main/java/sc/iview/ui/TaskManager.kt
@@ -0,0 +1,40 @@
+package sc.iview.ui
+
+import graphics.scenery.utils.LazyLogger
+import java.util.*
+import java.util.concurrent.CopyOnWriteArrayList
+import javax.swing.JLabel
+
+class TaskManager(var update: ((Task?) -> Any)? = null) {
+ val currentTasks = CopyOnWriteArrayList()
+ val pie = ProgressPie()
+ val label = JLabel()
+ val logger by LazyLogger()
+
+ init {
+
+ val timerTask = object: TimerTask() {
+ override fun run() {
+ currentTasks.removeIf { it.completion > 99.9999f }
+ val current = currentTasks.lastOrNull()
+
+ update?.invoke(current)
+ }
+ }
+ Timer().scheduleAtFixedRate(timerTask, 0L, 200L)
+ }
+
+ fun addTask(task: Task) {
+ currentTasks.add(task)
+ }
+
+ fun newTask(source: String, status: String = ""): Task {
+ val task = Task(source, status, 0.0f)
+ currentTasks.add(task)
+ return task
+ }
+
+ fun removeTask(task: Task) {
+ currentTasks.remove(task)
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/sc/iview/vector/DoubleVector3.java b/src/main/java/sc/iview/vector/DoubleVector3.java
deleted file mode 100644
index fcdf293f..00000000
--- a/src/main/java/sc/iview/vector/DoubleVector3.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*-
- * #%L
- * Scenery-backed 3D visualization package for ImageJ.
- * %%
- * Copyright (C) 2016 - 2020 SciView developers.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-package sc.iview.vector;
-
-/**
- * {@link Vector3} backed by three {@code double}s.
- *
- * @author Curtis Rueden
- * @author Kyle Harrington
- */
-public class DoubleVector3 implements Vector3 {
-
- private double x, y, z;
-
- public DoubleVector3( double x, double y, double z ) {
- this.x = x;
- this.y = y;
- this.z = z;
- }
-
- @Override public float xf() { return (float) x; }
- @Override public float yf() { return (float) y; }
- @Override public float zf() { return (float) z; }
-
- @Override public void setX( float position ) { x = position; }
- @Override public void setY( float position ) { y = position; }
- @Override public void setZ( float position ) { z = position; }
-
- @Override public double xd() { return x; }
- @Override public double yd() { return y; }
- @Override public double zd() { return z; }
-
- @Override public void setX( double position ) { x = position; }
- @Override public void setY( double position ) { y = position; }
- @Override public void setZ( double position ) { z = position; }
-
- @Override
- public Vector3 copy() {
- return new DoubleVector3(xd(),yd(),zd());
- }
-
- @Override
- public String toString() {
- return "[" + xd() + "; " + yd() + "; " + zd() + "]";
- }
-}
diff --git a/src/main/java/sc/iview/vector/DoubleVector4.java b/src/main/java/sc/iview/vector/DoubleVector4.java
deleted file mode 100644
index b1c4ec75..00000000
--- a/src/main/java/sc/iview/vector/DoubleVector4.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*-
- * #%L
- * Scenery-backed 3D visualization package for ImageJ.
- * %%
- * Copyright (C) 2016 - 2020 SciView developers.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-package sc.iview.vector;
-
-/**
- * {@link Vector4} backed by three {@code double}s.
- *
- * @author Kyle Harrington
- */
-public class DoubleVector4 implements Vector4 {
-
- private double x, y, z, w;
-
- public DoubleVector4(double x, double y, double z, double w ) {
- this.x = x;
- this.y = y;
- this.z = z;
- this.w = w;
- }
-
- @Override public float xf() { return (float) x; }
- @Override public float yf() { return (float) y; }
- @Override public float zf() { return (float) z; }
- @Override public float wf() { return (float) w; }
-
- @Override public void setX( float position ) { x = position; }
- @Override public void setY( float position ) { y = position; }
- @Override public void setZ( float position ) { z = position; }
- @Override public void setW( float position ) { w = position; }
-
- @Override public double xd() { return x; }
- @Override public double yd() { return y; }
- @Override public double zd() { return z; }
- @Override public double wd() { return w; }
-
- @Override public void setX( double position ) { x = position; }
- @Override public void setY( double position ) { y = position; }
- @Override public void setZ( double position ) { z = position; }
- @Override public void setW( double position ) { w = position; }
-
- @Override
- public Vector4 copy() {
- return new DoubleVector4(xd(),yd(),zd(),wd());
- }
-
- @Override
- public String toString() {
- return "[" + xd() + "; " + yd() + "; " + zd() + "; " + wd() + "]";
- }
-}
diff --git a/src/main/java/sc/iview/vector/FloatVector4.java b/src/main/java/sc/iview/vector/FloatVector4.java
deleted file mode 100644
index 282bdd6d..00000000
--- a/src/main/java/sc/iview/vector/FloatVector4.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*-
- * #%L
- * Scenery-backed 3D visualization package for ImageJ.
- * %%
- * Copyright (C) 2016 - 2020 SciView developers.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-package sc.iview.vector;
-
-/**
- * {@link Vector4} backed by three {@code float}s.
- *
- * @author Kyle Harrington
- */
-public class FloatVector4 implements Vector4 {
-
- private float x, y, z, w;
-
- public FloatVector4(float x, float y, float z, float w ) {
- this.x = x;
- this.y = y;
- this.z = z;
- this.w = w;
- }
-
- @Override public float xf() { return x; }
- @Override public float yf() { return y; }
- @Override public float zf() { return z; }
- @Override public float wf() { return w; }
-
- @Override public void setX( float position ) { x = position; }
- @Override public void setY( float position ) { y = position; }
- @Override public void setZ( float position ) { z = position; }
- @Override public void setW( float position ) { w = position; }
-
- @Override
- public Vector4 copy() {
- return new FloatVector4(xf(),yf(),zf(),wf());
- }
-
- @Override
- public String toString() {
- return "[" + xf() + "; " + yf() + "; " + zf() + "; " + wf() + "]";
- }
-}
diff --git a/src/main/java/sc/iview/vector/JOMLVector3.java b/src/main/java/sc/iview/vector/JOMLVector3.java
deleted file mode 100644
index 855ca1fd..00000000
--- a/src/main/java/sc/iview/vector/JOMLVector3.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*-
- * #%L
- * Scenery-backed 3D visualization package for ImageJ.
- * %%
- * Copyright (C) 2016 - 2020 SciView developers.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-package sc.iview.vector;
-
-import org.joml.Vector3f;
-
-/**
- * {@link Vector3} backed by a JOML {@link Vector3f}.
- *
- * @author Kyle Harrington
- * @author Curtis Rueden
- */
-public class JOMLVector3 implements Vector3 {
-
- private Vector3f source;
-
- public JOMLVector3( float x, float y, float z ) {
- this( new Vector3f( x, y, z ) );
- }
-
- public JOMLVector3( Vector3f source ) {
- this.source = source;
- }
-
- public Vector3f source() { return source; }
-
- @Override public float xf() { return source.x(); }
- @Override public float yf() { return source.y(); }
- @Override public float zf() { return source.z(); }
-
- @Override public void setX( float position ) { source.set( position, yf(), zf() ); }
- @Override public void setY( float position ) { source.set( xf(), position, zf() ); }
- @Override public void setZ( float position ) { source.set( xf(), yf(), position ); }
-
- @Override
- public Vector3 copy() {
- return new JOMLVector3(xf(),yf(),zf());
- }
-
- @Override
- public String toString() {
- return "[" + xf() + "; " + yf() + "; " + zf() + "]";
- }
-
- public static Vector3f convert( Vector3 v ) {
- if( v instanceof JOMLVector3 ) return (( JOMLVector3 ) v).source();
- return new Vector3f( v.xf(), v.yf(), v.zf() );
- }
-}
diff --git a/src/main/java/sc/iview/vector/JOMLVector4.java b/src/main/java/sc/iview/vector/JOMLVector4.java
deleted file mode 100644
index ed45f396..00000000
--- a/src/main/java/sc/iview/vector/JOMLVector4.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*-
- * #%L
- * Scenery-backed 3D visualization package for ImageJ.
- * %%
- * Copyright (C) 2016 - 2020 SciView developers.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-package sc.iview.vector;
-
-import org.joml.Vector4f;
-
-/**
- * {@link Vector4} backed by a JOML {@link Vector4f}.
- *
- * @author Kyle Harrington
- */
-public class JOMLVector4 implements Vector4 {
-
- private Vector4f source;
-
- public JOMLVector4(float x, float y, float z, float w ) {
- this( new Vector4f( x, y, z, w ) );
- }
-
- public JOMLVector4(Vector4f source ) {
- this.source = source;
- }
-
- public Vector4f source() { return source; }
-
- @Override public float xf() { return source.x(); }
- @Override public float yf() { return source.y(); }
- @Override public float zf() { return source.z(); }
- @Override public float wf() { return source.w(); }
-
- @Override public void setX( float position ) { source.set( position, yf(), zf(), wf() ); }
- @Override public void setY( float position ) { source.set( xf(), position, zf(), wf() ); }
- @Override public void setZ( float position ) { source.set( xf(), yf(), position, wf() ); }
- @Override public void setW( float position ) { source.set( xf(), yf(), zf(), position ); }
-
- @Override
- public Vector4 copy() {
- return new JOMLVector4(xf(),yf(),zf(),wf());
- }
-
- @Override
- public String toString() {
- return "[" + xf() + "; " + yf() + "; " + zf() + "; " + wf() + "]";
- }
-
- public static Vector4f convert( Vector4 v ) {
- if( v instanceof JOMLVector4) return ((JOMLVector4) v).source();
- return new Vector4f( v.xf(), v.yf(), v.zf(), v.wf() );
- }
-}
diff --git a/src/main/java/sc/iview/vector/Vector3.java b/src/main/java/sc/iview/vector/Vector3.java
deleted file mode 100644
index d65a0f83..00000000
--- a/src/main/java/sc/iview/vector/Vector3.java
+++ /dev/null
@@ -1,344 +0,0 @@
-/*-
- * #%L
- * Scenery-backed 3D visualization package for ImageJ.
- * %%
- * Copyright (C) 2016 - 2020 SciView developers.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-package sc.iview.vector;
-
-import net.imglib2.Localizable;
-import net.imglib2.RealLocalizable;
-import net.imglib2.RealPositionable;
-
-/**
- * Interface for 3D vectors.
- *
- * @author Kyle Harrington
- * @author Curtis Rueden
- */
-public interface Vector3 extends RealLocalizable, RealPositionable {
-
- // -- Vector3 methods --
-
- float xf();
- float yf();
- float zf();
-
- default void moveX(float distance) { setX( xf() + distance ); }
- default void moveY(float distance) { setY( yf() + distance ); }
- default void moveZ(float distance) { setZ( zf() + distance ); }
- default void move( float xDist, float yDist, float zDist ) {
- moveX( xDist );
- moveY( yDist );
- moveZ( zDist );
- }
-
- void setX(float position);
- void setY(float position);
- void setZ(float position);
-
- default void setPosition( float x, float y, float z ) {
- setX( x );
- setY( y );
- setZ( z );
- }
-
- default double xd() { return xf(); }
- default double yd() { return yf(); }
- default double zd() { return zf(); }
-
- default void moveX(double distance) { setX( xd() + distance ); }
- default void moveY(double distance) { setY( yd() + distance ); }
- default void moveZ(double distance) { setZ( zd() + distance ); }
- default void move( double xDist, double yDist, double zDist ) {
- moveX( xDist );
- moveY( yDist );
- moveZ( zDist );
- }
-
- default void setX(double position) { setX((float) position); }
- default void setY(double position) { setY((float) position); }
- default void setZ(double position) { setZ((float) position); }
-
- default void setPosition( double x, double y, double z ) {
- setX( x );
- setY( y );
- setZ( z );
- }
-
- // -- RealLocalizable methods --
-
- @Override
- default void localize( float[] position ) {
- position[0] = xf();
- position[1] = yf();
- position[2] = zf();
- }
-
- @Override
- default void localize( double[] position ) {
- position[0] = xd();
- position[1] = yd();
- position[2] = zd();
- }
-
- @Override
- default float getFloatPosition( int d ) {
- if( d == 0 ) return xf();
- if( d == 1 ) return yf();
- if( d == 2 ) return zf();
- throw new IndexOutOfBoundsException( "" + d );
- }
-
- @Override
- default double getDoublePosition( int d ) {
- if( d == 0 ) return xd();
- if( d == 1 ) return yd();
- if( d == 2 ) return zd();
- throw new IndexOutOfBoundsException( "" + d );
- }
-
- // -- RealPositionable methods --
-
- @Override
- default void move( float distance, int d ) {
- if( d == 0 ) moveX( distance );
- else if( d == 1 ) moveY( distance );
- else if( d == 2 ) moveZ( distance );
- else throw new IndexOutOfBoundsException( "" + d );
- }
-
- @Override
- default void move( double distance, int d ) {
- if( d == 0 ) moveX( distance );
- else if( d == 1 ) moveY( distance );
- else if( d == 2 ) moveZ( distance );
- else throw new IndexOutOfBoundsException( "" + d );
- }
-
- @Override
- default void move( RealLocalizable distance ) {
- moveX( distance.getDoublePosition( 0 ) );
- moveY( distance.getDoublePosition( 1 ) );
- moveZ( distance.getDoublePosition( 2 ) );
- }
-
- @Override
- default void move( float[] distance ) {
- moveX( distance[0] );
- moveY( distance[1] );
- moveZ( distance[2] );
- }
-
- @Override
- default void move( double[] distance ) {
- moveX( distance[0] );
- moveY( distance[1] );
- moveZ( distance[2] );
- }
-
- @Override
- default void setPosition( RealLocalizable localizable ) {
- setX( localizable.getDoublePosition( 0 ) );
- setY( localizable.getDoublePosition( 1 ) );
- setZ( localizable.getDoublePosition( 2 ) );
- }
-
- @Override
- default void setPosition( float[] position ) {
- setX( position[0] );
- setY( position[1] );
- setZ( position[2] );
- }
-
- @Override
- default void setPosition( double[] position ) {
- setX( position[0] );
- setY( position[1] );
- setZ( position[2] );
- }
-
- @Override
- default void setPosition( float position, int d ) {
- if( d == 0 ) setX( position );
- else if( d == 1 ) setY( position );
- else if( d == 2 ) setZ( position );
- else throw new IndexOutOfBoundsException( "" + d );
- }
-
- @Override
- default void setPosition( double position, int d ) {
- if( d == 0 ) setX( position );
- else if( d == 1 ) setY( position );
- else if( d == 2 ) setZ( position );
- else throw new IndexOutOfBoundsException( "" + d );
- }
-
- // -- Positionable methods --
-
- @Override
- default void fwd( int d ) { move( 1, d ); }
- @Override
- default void bck( int d ) { move( 1, d ); }
-
- @Override
- default void move( int distance, int d ) {
- move( ( double ) distance, d );
- }
-
- @Override
- default void move( long distance, int d ) {
- move( ( double ) distance, d );
- }
-
- @Override
- default void move( Localizable distance ) {
- moveX( distance.getDoublePosition( 0 ) );
- moveY( distance.getDoublePosition( 1 ) );
- moveZ( distance.getDoublePosition( 2 ) );
- }
-
- @Override
- default void move( int[] distance ) {
- moveX( (double) distance[0] );
- moveY( (double) distance[1] );
- moveZ( (double) distance[2] );
- }
-
- @Override
- default void move( long[] distance ) {
- moveX( (double) distance[0] );
- moveY( (double) distance[1] );
- moveZ( (double) distance[2] );
- }
-
- @Override
- default void setPosition( Localizable localizable ) {
- setX( localizable.getDoublePosition( 0 ) );
- setY( localizable.getDoublePosition( 1 ) );
- setZ( localizable.getDoublePosition( 2 ) );
- }
-
- @Override
- default void setPosition( int[] position ) {
- setX( (double) position[0] );
- setY( (double) position[1] );
- setZ( (double) position[2] );
- }
-
- @Override
- default void setPosition( long[] position ) {
- setX( (double) position[0] );
- setY( (double) position[1] );
- setZ( (double) position[2] );
- }
-
- @Override
- default void setPosition( int position, int d ) {
- setPosition( ( double ) position, d );
- }
-
- @Override
- default void setPosition( long position, int d ) {
- setPosition( ( double ) position, d );
- }
-
- // -- EuclideanSpace methods --
-
- @Override
- default int numDimensions() { return 3; }
-
- // Extra convenience methods
- default double getLength() {
- return Math.sqrt( getDoublePosition(0) * getDoublePosition(0) + getDoublePosition(1) * getDoublePosition(1) + getDoublePosition(2) * getDoublePosition(2) );
- }
-
- default Vector3 add(Vector3 p2) {
- Vector3 result = this.copy();
- result.moveX(p2.getDoublePosition(0));
- result.moveY(p2.getDoublePosition(1));
- result.moveZ(p2.getDoublePosition(2));
- return result;
- }
-
- default Vector3 minus(Vector3 p2) {
- Vector3 result = this.copy();
- result.moveX(-p2.getDoublePosition(0));
- result.moveY(-p2.getDoublePosition(1));
- result.moveZ(-p2.getDoublePosition(2));
- return result;
- }
-
- default Vector3 multiply(float s) {
- Vector3 result = this.copy();
- result.setPosition( result.getDoublePosition(0) * s, 0 );
- result.setPosition( result.getDoublePosition(1) * s, 1 );
- result.setPosition( result.getDoublePosition(2) * s, 2 );
- return result;
- }
-
- default float[] asFloatArray() {
- float[] a = new float[3];
- a[0] = xf();
- a[1] = yf();
- a[2] = zf();
- return a;
- }
-
- default double[] asDoubleArray() {
- double[] a = new double[3];
- a[0] = xd();
- a[1] = yd();
- a[2] = zd();
- return a;
- }
-
- default Vector3 cross(Vector3 v2) {
- return new JOMLVector3(JOMLVector3.convert(this).cross(JOMLVector3.convert(v2)));
- }
-
- default Vector3 elmul(Vector3 v2) {
- Vector3 r = this.copy();
- r.setX( r.xf() * v2.xf() );
- r.setY( r.yf() * v2.yf() );
- r.setZ( r.zf() * v2.zf() );
- return r;
- }
-
- default float dot(Vector3 v2) {
- return ( this.xf() * v2.xf() + this.yf() * v2.yf() + this.zf() * v2.zf() );
- }
-
- default Vector3 normalize() {
- Vector3 r = this.copy();
- double f = 1 / this.getLength();
- r.setX(r.xf() * f);
- r.setY(r.yf() * f);
- r.setZ(r.zf() * f);
- return r;
- }
-
- Vector3 copy();
-}
diff --git a/src/main/java/sc/iview/vector/Vector4.java b/src/main/java/sc/iview/vector/Vector4.java
deleted file mode 100644
index a640cbab..00000000
--- a/src/main/java/sc/iview/vector/Vector4.java
+++ /dev/null
@@ -1,384 +0,0 @@
-/*-
- * #%L
- * Scenery-backed 3D visualization package for ImageJ.
- * %%
- * Copyright (C) 2016 - 2020 SciView developers.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-package sc.iview.vector;
-
-import net.imglib2.Localizable;
-import net.imglib2.RealLocalizable;
-import net.imglib2.RealPositionable;
-
-/**
- * Interface for 4D vectors.
- *
- * @author Kyle Harrington
- */
-public interface Vector4 extends RealLocalizable, RealPositionable {
-
- // -- Vector3 methods --
-
- float xf();
- float yf();
- float zf();
- float wf();
-
- default void moveX(float distance) { setX( xf() + distance ); }
- default void moveY(float distance) { setY( yf() + distance ); }
- default void moveZ(float distance) { setZ( zf() + distance ); }
- default void moveW(float distance) { setZ( wf() + distance ); }
- default void move(float xDist, float yDist, float zDist, float wDist) {
- moveX( xDist );
- moveY( yDist );
- moveZ( zDist );
- moveW( wDist );
- }
-
- void setX(float position);
- void setY(float position);
- void setZ(float position);
- void setW(float position);
-
- default void setPosition(float x, float y, float z, float w) {
- setX( x );
- setY( y );
- setZ( z );
- setW( w );
- }
-
- default double xd() { return xf(); }
- default double yd() { return yf(); }
- default double zd() { return zf(); }
- default double wd() { return wf(); }
-
- default void moveX(double distance) { setX( xd() + distance ); }
- default void moveY(double distance) { setY( yd() + distance ); }
- default void moveZ(double distance) { setZ( zd() + distance ); }
- default void moveW(double distance) { setW( wd() + distance ); }
- default void move(double xDist, double yDist, double zDist, double wDist) {
- moveX( xDist );
- moveY( yDist );
- moveZ( zDist );
- moveW( wDist );
- }
-
- default void setX(double position) { setX((float) position); }
- default void setY(double position) { setY((float) position); }
- default void setZ(double position) { setZ((float) position); }
- default void setW(double position) { setW((float) position); }
-
- default void setPosition(double x, double y, double z, double w) {
- setX( x );
- setY( y );
- setZ( z );
- setW( w );
- }
-
- // -- RealLocalizable methods --
-
- @Override
- default void localize(float[] position) {
- position[0] = xf();
- position[1] = yf();
- position[2] = zf();
- position[3] = wf();
- }
-
- @Override
- default void localize(double[] position) {
- position[0] = xd();
- position[1] = yd();
- position[2] = zd();
- position[3] = wd();
- }
-
- @Override
- default float getFloatPosition(int d) {
- if( d == 0 ) return xf();
- if( d == 1 ) return yf();
- if( d == 2 ) return zf();
- if( d == 3 ) return wf();
- throw new IndexOutOfBoundsException( "" + d );
- }
-
- @Override
- default double getDoublePosition(int d) {
- if( d == 0 ) return xd();
- if( d == 1 ) return yd();
- if( d == 2 ) return zd();
- if( d == 3 ) return wd();
- throw new IndexOutOfBoundsException( "" + d );
- }
-
- // -- RealPositionable methods --
-
- @Override
- default void move(float distance, int d) {
- if( d == 0 ) moveX( distance );
- else if( d == 1 ) moveY( distance );
- else if( d == 2 ) moveZ( distance );
- else if( d == 3 ) moveW( distance );
- else throw new IndexOutOfBoundsException( "" + d );
- }
-
- @Override
- default void move(double distance, int d) {
- if( d == 0 ) moveX( distance );
- else if( d == 1 ) moveY( distance );
- else if( d == 2 ) moveZ( distance );
- else if( d == 3 ) moveW( distance );
- else throw new IndexOutOfBoundsException( "" + d );
- }
-
- @Override
- default void move(RealLocalizable distance) {
- moveX( distance.getDoublePosition( 0 ) );
- moveY( distance.getDoublePosition( 1 ) );
- moveZ( distance.getDoublePosition( 2 ) );
- moveW( distance.getDoublePosition( 3 ) );
- }
-
- @Override
- default void move(float[] distance) {
- moveX( distance[0] );
- moveY( distance[1] );
- moveZ( distance[2] );
- moveW( distance[3] );
- }
-
- @Override
- default void move(double[] distance) {
- moveX( distance[0] );
- moveY( distance[1] );
- moveZ( distance[2] );
- moveW( distance[3] );
- }
-
- @Override
- default void setPosition(RealLocalizable localizable) {
- setX( localizable.getDoublePosition( 0 ) );
- setY( localizable.getDoublePosition( 1 ) );
- setZ( localizable.getDoublePosition( 2 ) );
- setW( localizable.getDoublePosition( 3 ) );
- }
-
- @Override
- default void setPosition(float[] position) {
- setX( position[0] );
- setY( position[1] );
- setZ( position[2] );
- setW( position[3] );
- }
-
- @Override
- default void setPosition(double[] position) {
- setX( position[0] );
- setY( position[1] );
- setZ( position[2] );
- setW( position[3] );
- }
-
- @Override
- default void setPosition(float position, int d) {
- if( d == 0 ) setX( position );
- else if( d == 1 ) setY( position );
- else if( d == 2 ) setZ( position );
- else if( d == 3 ) setW( position );
- else throw new IndexOutOfBoundsException( "" + d );
- }
-
- @Override
- default void setPosition(double position, int d) {
- if( d == 0 ) setX( position );
- else if( d == 1 ) setY( position );
- else if( d == 2 ) setZ( position );
- else if( d == 3 ) setW( position );
- else throw new IndexOutOfBoundsException( "" + d );
- }
-
- // -- Positionable methods --
-
- @Override
- default void fwd(int d) { move( 1, d ); }
- @Override
- default void bck(int d) { move( 1, d ); }
-
- @Override
- default void move(int distance, int d) {
- move( ( double ) distance, d );
- }
-
- @Override
- default void move(long distance, int d) {
- move( ( double ) distance, d );
- }
-
- @Override
- default void move(Localizable distance) {
- moveX( distance.getDoublePosition( 0 ) );
- moveY( distance.getDoublePosition( 1 ) );
- moveZ( distance.getDoublePosition( 2 ) );
- moveW( distance.getDoublePosition( 3 ) );
- }
-
- @Override
- default void move(int[] distance) {
- moveX( (double) distance[0] );
- moveY( (double) distance[1] );
- moveZ( (double) distance[2] );
- moveW( (double) distance[3] );
- }
-
- @Override
- default void move(long[] distance) {
- moveX( (double) distance[0] );
- moveY( (double) distance[1] );
- moveZ( (double) distance[2] );
- moveW( (double) distance[3] );
- }
-
- @Override
- default void setPosition(Localizable localizable) {
- setX( localizable.getDoublePosition( 0 ) );
- setY( localizable.getDoublePosition( 1 ) );
- setZ( localizable.getDoublePosition( 2 ) );
- setW( localizable.getDoublePosition( 3 ) );
- }
-
- @Override
- default void setPosition(int[] position) {
- setX( (double) position[0] );
- setY( (double) position[1] );
- setZ( (double) position[2] );
- setW( (double) position[3] );
- }
-
- @Override
- default void setPosition(long[] position) {
- setX( (double) position[0] );
- setY( (double) position[1] );
- setZ( (double) position[2] );
- setW( (double) position[3] );
- }
-
- @Override
- default void setPosition(int position, int d) {
- setPosition( ( double ) position, d );
- }
-
- @Override
- default void setPosition(long position, int d) {
- setPosition( ( double ) position, d );
- }
-
- // -- EuclideanSpace methods --
-
- @Override
- default int numDimensions() { return 3; }
-
- // Extra convenience methods
- default double getLength() {
- return Math.sqrt( getDoublePosition(0) * getDoublePosition(0) + //
- getDoublePosition(1) * getDoublePosition(1) + //
- getDoublePosition(2) * getDoublePosition(2) + //
- getDoublePosition(3) * getDoublePosition(3) );
- }
-
- default Vector4 add(Vector4 p2) {
- Vector4 result = this.copy();
- result.moveX(p2.getDoublePosition(0));
- result.moveY(p2.getDoublePosition(1));
- result.moveZ(p2.getDoublePosition(2));
- result.moveW(p2.getDoublePosition(3));
- return result;
- }
-
- default Vector4 minus(Vector4 p2) {
- Vector4 result = this.copy();
- result.moveX(-p2.getDoublePosition(0));
- result.moveY(-p2.getDoublePosition(1));
- result.moveZ(-p2.getDoublePosition(2));
- result.moveW(-p2.getDoublePosition(3));
- return result;
- }
-
- default Vector4 multiply(float s) {
- Vector4 result = this.copy();
- result.setPosition( result.getDoublePosition(0) * s, 0 );
- result.setPosition( result.getDoublePosition(1) * s, 1 );
- result.setPosition( result.getDoublePosition(2) * s, 2 );
- result.setPosition( result.getDoublePosition(3) * s, 3 );
- return result;
- }
-
- default float[] asFloatArray() {
- float[] a = new float[4];
- a[0] = xf();
- a[1] = yf();
- a[2] = zf();
- a[3] = wf();
- return a;
- }
-
- default double[] asDoubleArray() {
- double[] a = new double[4];
- a[0] = xd();
- a[1] = yd();
- a[2] = zd();
- a[3] = wd();
- return a;
- }
-
- default Vector4 cross(Vector4 v2) {
- JOMLVector4 v = new JOMLVector4(JOMLVector4.convert(this));
- return v.cross(new JOMLVector4(JOMLVector4.convert(v2)));
- }
-
- default Vector4 elmul(Vector4 v2) {
- Vector4 r = this.copy();
- r.setX( r.xf() * v2.xf() );
- r.setY( r.yf() * v2.yf() );
- r.setZ( r.zf() * v2.zf() );
- r.setW( r.wf() * v2.wf() );
- return r;
- }
-
- default float dot(Vector4 v2) {
- return ( this.xf() * v2.xf() + this.yf() * v2.yf() + this.zf() * v2.zf() + this.wf() * v2.wf() );
- }
-
- default Vector4 normalize() {
- Vector4 r = this.copy();
- double f = 1 / this.getLength();
- r.setX(r.xf() * f);
- r.setY(r.yf() * f);
- r.setZ(r.zf() * f);
- r.setW(r.wf() * f);
- return r;
- }
-
- Vector4 copy();
-}
diff --git a/src/test/tests/sc/iview/test/SciViewTest.java b/src/test/tests/sc/iview/test/SciViewTest.java
index 84f6be0f..87720af5 100644
--- a/src/test/tests/sc/iview/test/SciViewTest.java
+++ b/src/test/tests/sc/iview/test/SciViewTest.java
@@ -39,7 +39,6 @@
import org.scijava.thread.ThreadService;
import sc.iview.SciView;
import sc.iview.SciViewService;
-import sc.iview.vector.JOMLVector3;
public class SciViewTest {
@@ -83,7 +82,7 @@ public void nestedNodeDeletionTest() throws Exception {
final Sphere sphere = new Sphere( 1, 20 );
sphere.setMaterial( material );
- sphere.setPosition( JOMLVector3.convert( new JOMLVector3(0,0,0) ) );
+ sphere.setPosition( new Vector3f(0,0,0) );
//sphere.setParent(group);
group.addChild(sphere);
sciView.addNode(group);