From 4f10060ceb6f7a405b914159a62110e5be16f9e1 Mon Sep 17 00:00:00 2001 From: Kimberly Meechan Date: Thu, 17 Aug 2023 21:34:26 +0100 Subject: [PATCH 01/13] updates to javadoc --- .../schwab/crosshair/bdv/BdvBehaviours.java | 10 + .../schwab/crosshair/bdv/ModeOverlay.java | 7 + .../de/embl/schwab/crosshair/io/IoHelper.java | 11 ++ .../crosshair/io/STLResourceLoader.java | 174 ++++++++++-------- .../PlaneSettingsMapDeserializer.java | 11 ++ .../io/serialise/VertexPointAdapter.java | 18 ++ .../crosshair/legacy/OldFormatSettings.java | 3 + .../legacy/OldFormatSettingsReader.java | 11 ++ .../legacy/SettingsFormatConverter.java | 12 ++ .../schwab/crosshair/microtome/Cutting.java | 20 +- .../schwab/crosshair/microtome/Microtome.java | 137 ++++++++++++++ .../schwab/crosshair/plane/BlockPlane.java | 11 ++ .../de/embl/schwab/crosshair/plane/Plane.java | 33 ++++ .../schwab/crosshair/plane/PlaneCreator.java | 26 +++ .../schwab/crosshair/plane/PlaneManager.java | 115 +++++++++++- .../points/overlays/Point3dOverlay.java | 24 +++ .../points/overlays/PointOverlay2d.java | 24 ++- .../overlays/PointsToFitPlane2dOverlay.java | 11 ++ .../overlays/VertexPoints2dOverlay.java | 11 ++ src/test/java/develop/OpenImageJ.java | 12 -- 20 files changed, 580 insertions(+), 101 deletions(-) delete mode 100644 src/test/java/develop/OpenImageJ.java diff --git a/src/main/java/de/embl/schwab/crosshair/bdv/BdvBehaviours.java b/src/main/java/de/embl/schwab/crosshair/bdv/BdvBehaviours.java index e8d74c9..fd585fe 100644 --- a/src/main/java/de/embl/schwab/crosshair/bdv/BdvBehaviours.java +++ b/src/main/java/de/embl/schwab/crosshair/bdv/BdvBehaviours.java @@ -15,12 +15,22 @@ import javax.swing.*; +/** + * Class to control custom interactions with the BigDataViewer window + * For example, clicking to add points or fitting a plane to points + */ public class BdvBehaviours { private BdvHandle bdvHandle; private PlaneManager planeManager; private MicrotomeManager microtomeManager; + /** + * Adds custom behaviours to the BigDataViewer window referenced by bdvHandle + * @param bdvHandle bdvHandle of the BigDataViewer window + * @param planeManager Crosshair plane manager + * @param microtomeManager Crosshair microtome manager + */ public BdvBehaviours (BdvHandle bdvHandle, PlaneManager planeManager, MicrotomeManager microtomeManager) { this.bdvHandle = bdvHandle; this.planeManager = planeManager; diff --git a/src/main/java/de/embl/schwab/crosshair/bdv/ModeOverlay.java b/src/main/java/de/embl/schwab/crosshair/bdv/ModeOverlay.java index 4a86360..75a890b 100644 --- a/src/main/java/de/embl/schwab/crosshair/bdv/ModeOverlay.java +++ b/src/main/java/de/embl/schwab/crosshair/bdv/ModeOverlay.java @@ -5,11 +5,18 @@ import java.awt.*; +/** + * Class to display the current Crosshair mode as an overlay on the BigDataViewer window + */ public class ModeOverlay extends BdvOverlay { private PlaneManager planeManager; private Color colModeText = new Color(255, 255, 255); + /** + * Create a BigDataViewer overlay for the Crosshair mode text + * @param planeManager Crosshair plane manager + */ public ModeOverlay( PlaneManager planeManager ) { this.planeManager = planeManager; } diff --git a/src/main/java/de/embl/schwab/crosshair/io/IoHelper.java b/src/main/java/de/embl/schwab/crosshair/io/IoHelper.java index 505a722..12000d3 100644 --- a/src/main/java/de/embl/schwab/crosshair/io/IoHelper.java +++ b/src/main/java/de/embl/schwab/crosshair/io/IoHelper.java @@ -4,10 +4,17 @@ import javax.swing.filechooser.FileNameExtensionFilter; import java.io.File; +/** + * Class with IO utility functions + */ public class IoHelper { private static String lastDirPath; + /** + * Opens a file chooser to select a json file + * @return filepath of the chosen file + */ public static String chooseOpenFilePath() { String filePath = null; JFileChooser chooser = new JFileChooser(lastDirPath); @@ -21,6 +28,10 @@ public static String chooseOpenFilePath() { return filePath; } + /** + * Opens a file chooser to select where to save a json file + * @return filepath to save json + */ public static String chooseSaveFilePath() { String filePath = null; JFileChooser chooser = new JFileChooser(lastDirPath); diff --git a/src/main/java/de/embl/schwab/crosshair/io/STLResourceLoader.java b/src/main/java/de/embl/schwab/crosshair/io/STLResourceLoader.java index fe879c4..5ac979c 100644 --- a/src/main/java/de/embl/schwab/crosshair/io/STLResourceLoader.java +++ b/src/main/java/de/embl/schwab/crosshair/io/STLResourceLoader.java @@ -11,101 +11,115 @@ import java.util.Map; import java.io.IOException; -// adapted from https://github.com/fiji/3D_Viewer/blob/master/src/main/java/customnode/STLLoader.java to use -// input stream, and load from resource name +/** + * Class to load 3D models saved in STL file format from the resources directory + * adapted from https://github.com/fiji/3D_Viewer/blob/master/src/main/java/customnode/STLLoader.java to use + * input stream, and load from resource name + */ public class STLResourceLoader { - private HashMap meshes; - private ArrayList vertices = new ArrayList(); - private String name = null; - private final Point3f normal = new Point3f(0.0F, 0.0F, 0.0F); - private int triangles; - - public static Map load(String name) throws IOException { - STLResourceLoader sl = new STLResourceLoader(); - - try { - sl.parse(name); - } catch (RuntimeException var3) { - IJ.log("error reading " + sl.name); - throw var3; - } + private HashMap meshes; + private ArrayList vertices = new ArrayList(); + private String name = null; + private final Point3f normal = new Point3f(0.0F, 0.0F, 0.0F); + private int triangles; - return sl.meshes; - } + private STLResourceLoader() { + } - private STLResourceLoader() { + /** + * Load the named STL 3D model from resources + * @param name Name of the STL model e.g. "/arc.stl" + * @return Map of STL model name to mesh + */ + public static Map loadSTL(String name) { + try { + return STLResourceLoader.load(name); + } catch (Exception var2) { + var2.printStackTrace(); + return null; } + } - private void parse(String name) throws IOException { - this.name = name; - InputStream inputStream = getClass().getResourceAsStream(name); - byte[] buffer = new byte[84]; - inputStream.read(buffer, 0, 84); - this.triangles = (buffer[83] & 255) << 24 | (buffer[82] & 255) << 16 | (buffer[81] & 255) << 8 | buffer[80] & 255; - inputStream.close(); - this.parseBinary(); + /** + * Load the named STL 3D model from resources + * @param name Name of the STL model e.g. "/arc.stl" + * @return Map of STL model name to mesh + * @throws IOException + */ + public static Map load(String name) throws IOException { + STLResourceLoader sl = new STLResourceLoader(); + + try { + sl.parse(name); + } catch (RuntimeException var3) { + IJ.log("error reading " + sl.name); + throw var3; } - public static Map loadSTL(String name) { - try { - return STLResourceLoader.load(name); - } catch (Exception var2) { - var2.printStackTrace(); - return null; - } - } + return sl.meshes; + } - private void parseBinary() { - InputStream inputStream = getClass().getResourceAsStream(name); - this.meshes = new HashMap(); - this.vertices = new ArrayList(); + private void parse(String name) throws IOException { + this.name = name; + InputStream inputStream = getClass().getResourceAsStream(name); + byte[] buffer = new byte[84]; + inputStream.read(buffer, 0, 84); + this.triangles = (buffer[83] & 255) << 24 | (buffer[82] & 255) << 16 | (buffer[81] & 255) << 8 | buffer[80] & 255; + inputStream.close(); + this.parseBinary(); + } - try { - int t; - for (t = 0; t < 84; ++t) { - inputStream.read(); - } + private void parseBinary() { + InputStream inputStream = getClass().getResourceAsStream(name); + this.meshes = new HashMap(); + this.vertices = new ArrayList(); - for (t = 0; t < this.triangles; ++t) { - byte[] tri = new byte[50]; - inputStream.read(tri); - - this.normal.x = this.leBytesToFloat(tri[0], tri[1], tri[2], tri[3]); - this.normal.y = this.leBytesToFloat(tri[4], tri[5], tri[6], tri[7]); - this.normal.z = this.leBytesToFloat(tri[8], tri[9], tri[10], tri[11]); - - int i; - for (i = 0; i < 3; ++i) { - int j = i * 12 + 12; - float px = this.leBytesToFloat(tri[j], tri[j + 1], tri[j + 2], tri[j + 3]); - float py = this.leBytesToFloat(tri[j + 4], tri[j + 5], tri[j + 6], tri[j + 7]); - float pz = this.leBytesToFloat(tri[j + 8], tri[j + 9], tri[j + 10], tri[j + 11]); - Point3f p = new Point3f(px, py, pz); - this.vertices.add(p); - } - } - - inputStream.close(); - } catch (IOException var10) { - var10.printStackTrace(); + try { + int t; + for (t = 0; t < 84; ++t) { + inputStream.read(); + } + for (t = 0; t < this.triangles; ++t) { + byte[] tri = new byte[50]; + inputStream.read(tri); + + this.normal.x = this.leBytesToFloat(tri[0], tri[1], tri[2], tri[3]); + this.normal.y = this.leBytesToFloat(tri[4], tri[5], tri[6], tri[7]); + this.normal.z = this.leBytesToFloat(tri[8], tri[9], tri[10], tri[11]); + + int i; + for (i = 0; i < 3; ++i) { + int j = i * 12 + 12; + float px = this.leBytesToFloat(tri[j], tri[j + 1], tri[j + 2], tri[j + 3]); + float py = this.leBytesToFloat(tri[j + 4], tri[j + 5], tri[j + 6], tri[j + 7]); + float pz = this.leBytesToFloat(tri[j + 8], tri[j + 9], tri[j + 10], tri[j + 11]); + Point3f p = new Point3f(px, py, pz); + this.vertices.add(p); + } } - CustomMesh cm = this.createCustomMesh(); - this.meshes.put(this.name, cm); - } + inputStream.close(); + } catch (IOException var10) { + var10.printStackTrace(); - private float leBytesToFloat(byte b0, byte b1, byte b2, byte b3) { - return Float.intBitsToFloat((b3 & 255) << 24 | (b2 & 255) << 16 | (b1 & 255) << 8 | b0 & 255); } - private CustomMesh createCustomMesh() { - if (this.vertices.size() == 0) { - return null; - } else { - CustomMesh cm = null; - cm = new CustomTriangleMesh(this.vertices); - return cm; - } + CustomMesh cm = this.createCustomMesh(); + this.meshes.put(this.name, cm); + } + + private float leBytesToFloat(byte b0, byte b1, byte b2, byte b3) { + return Float.intBitsToFloat((b3 & 255) << 24 | (b2 & 255) << 16 | (b1 & 255) << 8 | b0 & 255); + } + + private CustomMesh createCustomMesh() { + if (this.vertices.size() == 0) { + return null; + } else { + CustomMesh cm = null; + cm = new CustomTriangleMesh(this.vertices); + return cm; } } +} diff --git a/src/main/java/de/embl/schwab/crosshair/io/serialise/PlaneSettingsMapDeserializer.java b/src/main/java/de/embl/schwab/crosshair/io/serialise/PlaneSettingsMapDeserializer.java index 4e100a7..a8cfaa3 100644 --- a/src/main/java/de/embl/schwab/crosshair/io/serialise/PlaneSettingsMapDeserializer.java +++ b/src/main/java/de/embl/schwab/crosshair/io/serialise/PlaneSettingsMapDeserializer.java @@ -8,9 +8,20 @@ import java.util.HashMap; import java.util.Map; +/** + * Json Deserializer for map of plane names to plane settings + */ public class PlaneSettingsMapDeserializer implements JsonDeserializer> { + /** + * Deserializes json element to a map of plane names to plane settings + * @param json json element + * @param typeOfT type of the object to deserialize to + * @param context json deserialization context + * @return Map of plane names to plane settings + * @throws JsonParseException + */ @Override public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context ) throws JsonParseException { diff --git a/src/main/java/de/embl/schwab/crosshair/io/serialise/VertexPointAdapter.java b/src/main/java/de/embl/schwab/crosshair/io/serialise/VertexPointAdapter.java index bcf70b1..6b1a469 100644 --- a/src/main/java/de/embl/schwab/crosshair/io/serialise/VertexPointAdapter.java +++ b/src/main/java/de/embl/schwab/crosshair/io/serialise/VertexPointAdapter.java @@ -5,15 +5,33 @@ import java.lang.reflect.Type; +/** + * Class to handle json serialization and deserialization for VertexPoint + */ public class VertexPointAdapter implements JsonDeserializer, JsonSerializer { + /** + * Deserializes json element to a VertexPoint + * @param json json element + * @param typeOfT type of the object to deserialize to + * @param context json deserialization context + * @return a VertexPoint object + * @throws JsonParseException + */ @Override public VertexPoint deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context ) throws JsonParseException { return VertexPoint.fromString( json.getAsString() ); } + /** + * Serialises VertexPoint to a json element + * @param vertexPoint VertexPoint object + * @param typeOfSrc the actual type (fully genericized version) of the source object + * @param context json serialization context + * @return a json element + */ @Override public JsonElement serialize( VertexPoint vertexPoint, Type typeOfSrc, JsonSerializationContext context ) { return new JsonPrimitive( vertexPoint.toString() ); diff --git a/src/main/java/de/embl/schwab/crosshair/legacy/OldFormatSettings.java b/src/main/java/de/embl/schwab/crosshair/legacy/OldFormatSettings.java index 470640d..62ab826 100644 --- a/src/main/java/de/embl/schwab/crosshair/legacy/OldFormatSettings.java +++ b/src/main/java/de/embl/schwab/crosshair/legacy/OldFormatSettings.java @@ -8,6 +8,9 @@ import java.util.HashMap; import java.util.Map; +/** + * Class for old format Crosshair settings + */ public class OldFormatSettings { public final Map planeNormals = new HashMap<>(); diff --git a/src/main/java/de/embl/schwab/crosshair/legacy/OldFormatSettingsReader.java b/src/main/java/de/embl/schwab/crosshair/legacy/OldFormatSettingsReader.java index f175a4a..c54cbab 100644 --- a/src/main/java/de/embl/schwab/crosshair/legacy/OldFormatSettingsReader.java +++ b/src/main/java/de/embl/schwab/crosshair/legacy/OldFormatSettingsReader.java @@ -6,10 +6,21 @@ import java.io.FileReader; import java.io.IOException; +/** + * Class to read old format Crosshair settings + */ public class OldFormatSettingsReader { + /** + * Create a settings reader + */ public OldFormatSettingsReader() {} + /** + * Read settings from a json file + * @param filePath file path of settings json file + * @return Crosshair settings (in the old format) + */ public OldFormatSettings readSettings( String filePath ) { Gson gson = new Gson(); try ( FileReader fileReader = new FileReader(filePath) ) { diff --git a/src/main/java/de/embl/schwab/crosshair/legacy/SettingsFormatConverter.java b/src/main/java/de/embl/schwab/crosshair/legacy/SettingsFormatConverter.java index 56676d6..8fed140 100644 --- a/src/main/java/de/embl/schwab/crosshair/legacy/SettingsFormatConverter.java +++ b/src/main/java/de/embl/schwab/crosshair/legacy/SettingsFormatConverter.java @@ -13,11 +13,19 @@ import java.util.HashMap; import java.util.Map; +/** + * Class to convert old format Crosshair settings files to the new format + */ public class SettingsFormatConverter { private final File oldFormatJson; private final File newFormatJson; + /** + * Create a settings format converter + * @param oldFormatJson Settings json file in old format to convert + * @param newFormatJson Settings json file to write new format settings into + */ public SettingsFormatConverter( File oldFormatJson, File newFormatJson ) { this.oldFormatJson = oldFormatJson; this.newFormatJson = newFormatJson; @@ -75,6 +83,10 @@ private Map makeImageSettings( OldFormatSettings o return imageNameToSettings; } + /** + * Reads settings from the old format settings json file, converts them to the new format, + * then writes to the new format settings json file + */ public void convertOldSettingsToNew() { OldFormatSettings oldSettings = new OldFormatSettingsReader().readSettings( oldFormatJson.getAbsolutePath() ); Settings settings = new Settings(); diff --git a/src/main/java/de/embl/schwab/crosshair/microtome/Cutting.java b/src/main/java/de/embl/schwab/crosshair/microtome/Cutting.java index 619f97d..2341956 100644 --- a/src/main/java/de/embl/schwab/crosshair/microtome/Cutting.java +++ b/src/main/java/de/embl/schwab/crosshair/microtome/Cutting.java @@ -18,6 +18,9 @@ import static de.embl.schwab.crosshair.utils.GeometryUtils.findClosestPointOnPlane; import static java.lang.Math.*; +/** + * Class to handle Crosshair's cutting mode + */ class Cutting { private Microtome microtome; @@ -30,6 +33,10 @@ class Cutting { private Vector3d firstTouchPointCutting; private Vector3d NSZero; + /** + * Create a new Cutting object, to handle Crosshair's cutting mode + * @param microtome microtome + */ Cutting (Microtome microtome) { this.microtome = microtome; this.imageContent = microtome.getImageContent(); @@ -45,9 +52,11 @@ class Cutting { return cuttingDepthMax; } + /** + * Make a plane to represent the cutting location in the 3D viewer. This is centred on the current knife centre + * with width and height of 2*max distance in image (corner to corner) + */ void initialiseCuttingPlane () { - // Make a plane centred on current knife centre with width and height of 2*max distance in image (corner to corner) - // Get maximum distance in image Point3d min = new Point3d(); Point3d max = new Point3d(); @@ -142,10 +151,17 @@ private void setCuttingBounds () { cuttingDepthMax = microtome.getCurrentHolderFront().getY() - NSZero.getY(); } + /** + * Remove the cutting plane from the 3D viewer + */ public void removeCuttingPlane() { universe.removeContent("CuttingPlane"); } + /** + * Update the position of the cutting plane in the 3D viewer and BigDataViewer window. + * @param currentDepth the current cutting depth + */ void updateCut(double currentDepth) { // Update position of cutting plane diff --git a/src/main/java/de/embl/schwab/crosshair/microtome/Microtome.java b/src/main/java/de/embl/schwab/crosshair/microtome/Microtome.java index 4dd9d9f..5f11815 100644 --- a/src/main/java/de/embl/schwab/crosshair/microtome/Microtome.java +++ b/src/main/java/de/embl/schwab/crosshair/microtome/Microtome.java @@ -10,6 +10,9 @@ import org.scijava.vecmath.Matrix4d; import org.scijava.vecmath.Vector3d; +/** + * Class to represent the current state of the ultramicrotome + */ public class Microtome { private final Image3DUniverse universe; private final PlaneManager planeManager; @@ -70,6 +73,13 @@ public class Microtome { private double knifeTargetAngleThreshold; + /** + * Create a microtome + * @param universe universe of the 3D viewer + * @param planeManager plane manager + * @param bdvStackSource BigDataViewer stack source + * @param imageContent image content displayed in 3D viewer + */ public Microtome (Image3DUniverse universe, PlaneManager planeManager, BdvStackSource bdvStackSource, Content imageContent) { this.universe = universe; this.planeManager = planeManager; @@ -88,144 +98,268 @@ public Microtome (Image3DUniverse universe, PlaneManager planeManager, BdvStackS } + /** + * @return Current knife angle in degrees + */ public double getKnife() { return knife; } + /** + * @return Current sample tilt angle in degrees + */ public double getTilt() { return tilt; } + /** + * @return Current sample rotation angle in degrees + */ public double getRotation() { return rotation; } + /** + * @return Initial sample tilt angle in degrees + */ public double getInitialTiltAngle() { return initialTiltAngle; } + /** + * @return Initial knife angle in degrees + */ public double getInitialKnifeAngle() { return initialKnifeAngle; } + /** + * @return universe of the 3D viewer + */ public Image3DUniverse getUniverse() { return universe; } + /** + * @return Crosshair plane manager + */ public PlaneManager getPlaneManager() { return planeManager; } + /** + * @return position of centre of knife in 3D viewer + */ public Vector3d getCurrentKnifeCentre() { return currentKnifeCentre; } + /** + * @return Knife normal vector at current rotation (in 3D viewer) + */ public Vector3d getCurrentKnifeNormal() { return currentKnifeNormal; } + /** + * @return position of centre of arc in 3D viewer + */ public Vector3d getCurrentArcCentre() { return currentArcCentre; } + /** + * @return position of front of sample holder in 3D viewer + */ public Vector3d getCurrentHolderFront() { return currentHolderFront; } + /** + * @return image content displayed in 3D viewer + */ public Content getImageContent() { return imageContent; } + /** + * @return Initial target offset angle in degrees (calculated from the input planes & points, + * offset from block face to target) + */ public double getInitialTargetOffset() { return initialTargetOffset; } + /** + * @return Initial target tilt angle in degrees (calculated from the input planes & points, + * tilt from block face to target) + */ public double getInitialTargetTilt() { return initialTargetTilt; } + /** + * @return Transformation matrix for block to current position (under current microtome settings) + */ public Matrix4d getCurrentBlockTransform() { return currentBlockTransform; } + /** + * @return Vector from left to right along knife edge under current knife angle + */ public Vector3d getCurrentEdgeVector() { return currentEdgeVector; } + /** + * @return BigDataViewer stack source + */ public BdvStackSource getBdvStackSource() { return bdvStackSource; } + /** + * @return angle in degrees between the current knife normal and current target plane normal + */ public double getAngleKnifeTarget() { return angleKnifeTarget; } + /** + * Set transformation matrix of arc components (arc + holder front + holder back) + * @param arcComponentsInitialTransform Transformation matrix + */ void setArcComponentsInitialTransform(Matrix4d arcComponentsInitialTransform) { this.arcComponentsInitialTransform = arcComponentsInitialTransform; } + /** + * Set current position of arc centre in 3D viewer + * @param currentArcCentre position of arc centre + */ void setCurrentArcCentre(Vector3d currentArcCentre) { this.currentArcCentre = currentArcCentre; } + /** + * Set current position of sample holder front in 3D viewer + * @param currentHolderFront position of sample holder front + */ void setCurrentHolderFront(Vector3d currentHolderFront) { this.currentHolderFront = currentHolderFront; } + /** + * Set initial target plane normal vector + * @param initialTargetNormal normal vector + */ void setInitialTargetNormal(Vector3d initialTargetNormal) { this.initialTargetNormal = initialTargetNormal; } + /** + * Set current target plane normal vector + * @param currentTargetNormal normal vector + */ void setCurrentTargetNormal(Vector3d currentTargetNormal) { this.currentTargetNormal = currentTargetNormal; } + /** + * Set angle in degrees between the current knife normal and current target plane normal + * @param angleKnifeTarget angle in degrees + */ void setAngleKnifeTarget(double angleKnifeTarget) { this.angleKnifeTarget = angleKnifeTarget; } + /** + * Set initial target plane offset angle + * @param initialTargetOffset target offset angle in degrees + */ void setInitialTargetOffset(double initialTargetOffset) { this.initialTargetOffset = initialTargetOffset; } + /** + * Set initial target plane tilt angle + * @param initialTargetTilt target tilt angle in degrees + */ void setInitialTargetTilt(double initialTargetTilt) { this.initialTargetTilt = initialTargetTilt; } + /** + * Set initial block transform + * @param initialBlockTransform transformation matrix + */ void setInitialBlockTransform(Matrix4d initialBlockTransform) { this.initialBlockTransform = initialBlockTransform; } + /** + * Set initial knife angle + * @param initialKnifeAngle initial knife angle in degrees + */ void setInitialKnifeAngle(double initialKnifeAngle) { this.initialKnifeAngle = initialKnifeAngle; } + /** + * Set initial sample tilt angle + * @param initialTiltAngle initial sample tilt angle in degrees + */ void setInitialTiltAngle(double initialTiltAngle) { this.initialTiltAngle = initialTiltAngle; } + /** + * Set knife initial transform + * @param knifeInitialTransform transformation matrix + */ void setKnifeInitialTransform(Matrix4d knifeInitialTransform) { this.knifeInitialTransform = knifeInitialTransform; } + /** + * Set current position of knife centre in 3D viewer + * @param currentKnifeCentre position of knife centre + */ void setCurrentKnifeCentre(Vector3d currentKnifeCentre) { this.currentKnifeCentre = currentKnifeCentre; } + /** + * Set microtome object names + * @param microtomeObjectNames Array of object names + */ void setMicrotomeObjectNames(String[] microtomeObjectNames) { this.microtomeObjectNames = microtomeObjectNames; } + /** + * Set sample rotation angle + * @param rotation sample rotation angle in degrees + */ void setRotation(double rotation) { this.rotation = rotation; updateTiltRotationBlock(); } + /** + * Set sample tilt angle + * @param tilt sample tilt angle in degrees + */ void setTilt(double tilt) { this.tilt = tilt; updateTiltRotationBlock(); } + /** + * Set knife angle + * @param knife knife angle in degrees + */ void setKnife(double knife) { this.knife = knife; Vector3d axis = new Vector3d(new double[] {0, 0, 1}); @@ -305,6 +439,9 @@ private void updateAngleKnifeTarget() { } } + /** + * Reset the ultramicrotome + */ void resetMicrotome () { initialBlockTransform.setIdentity(); diff --git a/src/main/java/de/embl/schwab/crosshair/plane/BlockPlane.java b/src/main/java/de/embl/schwab/crosshair/plane/BlockPlane.java index a92f7de..ab24bb0 100644 --- a/src/main/java/de/embl/schwab/crosshair/plane/BlockPlane.java +++ b/src/main/java/de/embl/schwab/crosshair/plane/BlockPlane.java @@ -6,10 +6,21 @@ import ij3d.Content; import org.scijava.vecmath.Vector3d; +/** + * Class to represent the block face (block plane) + */ public class BlockPlane extends Plane { private final VertexDisplay vertexDisplay; + /** + * Create a block plane + * @param settings block plane settings + * @param centroid Centroid of block plane mesh + * @param mesh 3D custom triangle mesh of block plane + * @param pointsToFitPlaneDisplay points to fit plane display + * @param vertexDisplay vertex display + */ public BlockPlane(BlockPlaneSettings settings, Vector3d centroid, Content mesh, PointsToFitPlaneDisplay pointsToFitPlaneDisplay, VertexDisplay vertexDisplay ) { diff --git a/src/main/java/de/embl/schwab/crosshair/plane/Plane.java b/src/main/java/de/embl/schwab/crosshair/plane/Plane.java index 5808c0f..6fee315 100644 --- a/src/main/java/de/embl/schwab/crosshair/plane/Plane.java +++ b/src/main/java/de/embl/schwab/crosshair/plane/Plane.java @@ -10,6 +10,9 @@ import java.awt.*; +/** + * Class to represent a plane + */ public class Plane { private String name; @@ -29,6 +32,13 @@ public class Plane { private double distanceBetweenPlanesThreshold = 1E-10; // distance used to be 'on' plane + /** + * Create a plane + * @param planeSettings plane settings + * @param centroid centroid of plane mesh + * @param mesh 3D custom triangle mesh of plane + * @param pointsToFitPlaneDisplay points to fit plane display + */ public Plane(PlaneSettings planeSettings, Vector3d centroid, Content mesh, PointsToFitPlaneDisplay pointsToFitPlaneDisplay ) { this.name = planeSettings.name; this.normal = planeSettings.normal; @@ -43,6 +53,13 @@ public Plane(PlaneSettings planeSettings, Vector3d centroid, Content mesh, Point this.pointsToFitPlaneDisplay = pointsToFitPlaneDisplay; } + /** + * Update plane orientation + * @param normal plane normal + * @param point plane point + * @param centroid centroid of plane 3D mesh + * @param mesh 3D custom triangle mesh of plane + */ public void updatePlaneOrientation(Vector3d normal, Vector3d point, Vector3d centroid, Content mesh ) { this.normal = normal; this.point = point; @@ -106,14 +123,27 @@ public PointsToFitPlaneDisplay getPointsToFitPlaneDisplay() { return pointsToFitPlaneDisplay; } + /** + * @return distance to be considered 'on' the plane i.e. if a point is less than this distance away, then it is + * on the plane. + */ public double getDistanceBetweenPlanesThreshold() { return distanceBetweenPlanesThreshold; } + /** + * @param distanceBetweenPlanesThreshold distance to be considered 'on' the plane i.e. if a point is + * less than this distance away, then it is on the plane. + */ public void setDistanceBetweenPlanesThreshold( double distanceBetweenPlanesThreshold ) { this.distanceBetweenPlanesThreshold = distanceBetweenPlanesThreshold; } + /** + * Check if the given point is on the plane + * @param point a 3D point + * @return whether the point is on the plane + */ public boolean isPointOnPlane( RealPoint point ) { double[] position = new double[3]; @@ -130,6 +160,9 @@ public boolean isPointOnPlane( RealPoint point ) { } } + /** + * @return whether the orientation of the plane has been initialised + */ public boolean isOrientationSet() { return normal != null && point != null; } diff --git a/src/main/java/de/embl/schwab/crosshair/plane/PlaneCreator.java b/src/main/java/de/embl/schwab/crosshair/plane/PlaneCreator.java index 4ed35ee..8fb013c 100644 --- a/src/main/java/de/embl/schwab/crosshair/plane/PlaneCreator.java +++ b/src/main/java/de/embl/schwab/crosshair/plane/PlaneCreator.java @@ -18,6 +18,9 @@ import java.util.ArrayList; +/** + * Class to handle creation of planes + */ public class PlaneCreator { private final Image3DUniverse universe; // universe to add all planes to @@ -25,6 +28,13 @@ public class PlaneCreator { private final Bdv bdv; // bdv instance to assign to plane, needed to keep 2d point overlays up to date private final Point3dOverlay point3dOverlay; // 3d point overlay to assign to plane + /** + * Create a plane creator + * @param universe universe of the 3D viewer + * @param imageContent image content displayed in 3D viewer (used to define bounds of the planes) + * @param bdv BigDataViewer window + * @param point3dOverlay point overlay for 3D viewer + */ public PlaneCreator(Image3DUniverse universe, Content imageContent, Bdv bdv, Point3dOverlay point3dOverlay ) { this.universe = universe; this.imageContent = imageContent; @@ -37,6 +47,11 @@ private class CentroidAndMesh { public Content mesh; } + /** + * Create a plane with the given settings + * @param planeSettings plane settings + * @return a Plane object + */ public Plane createPlane( PlaneSettings planeSettings ) { PointsToFitPlaneDisplay pointsToFitPlaneDisplay = new PointsToFitPlaneDisplay( @@ -50,6 +65,11 @@ public Plane createPlane( PlaneSettings planeSettings ) { } } + /** + * Create a block plane (representing the block face) + * @param blockPlaneSettings block plane settings + * @return a block plane object + */ public BlockPlane createBlockPlane( BlockPlaneSettings blockPlaneSettings ) { PointsToFitPlaneDisplay pointsToFitPlaneDisplay = new PointsToFitPlaneDisplay( @@ -70,6 +90,12 @@ private boolean isOrientationSet( PlaneSettings settings ) { return settings.normal != null && settings.point != null; } + /** + * Update plane orientation + * @param plane plane to update + * @param newNormal the new plane normal + * @param newPoint the new plane point + */ public void updatePlaneOrientation( Plane plane, Vector3d newNormal, Vector3d newPoint ) { if ( universe.contains( plane.getName() ) ) { universe.removeContent( plane.getName() ); diff --git a/src/main/java/de/embl/schwab/crosshair/plane/PlaneManager.java b/src/main/java/de/embl/schwab/crosshair/plane/PlaneManager.java index 767ee20..8b7b6cd 100644 --- a/src/main/java/de/embl/schwab/crosshair/plane/PlaneManager.java +++ b/src/main/java/de/embl/schwab/crosshair/plane/PlaneManager.java @@ -27,6 +27,9 @@ import static de.embl.cba.bdv.utils.BdvUtils.getBdvWindowCentre; import static de.embl.cba.bdv.utils.BdvUtils.moveToPosition; +/** + * Class to manage all current planes + */ public class PlaneManager { private boolean isTrackingPlane = false; @@ -47,8 +50,14 @@ public class PlaneManager { // TODO - make this threshold user definable - makes sense for microns, but possibly not for other units private final double distanceBetweenPlanesThreshold = 1E-10; - // Given image content is used to define the extent of planes (only shown within bounds of that image) - // and where points are shown (again attached to that image) + /** + * Create a plane manager + * @param bdvStackSource BigDataViewer stack source + * @param universe universe of the 3D viewer + * @param imageContent image content displayed in 3D viewer (This image content is used to define the + * extent of planes (only shown within bounds of that image) and where points are shown + * (again attached to that image)) + */ public PlaneManager( BdvStackSource bdvStackSource, Image3DUniverse universe, Content imageContent ) { planeNameToPlane = new HashMap<>(); @@ -83,8 +92,14 @@ public Collection getPlanes() { return planeNameToPlane.values(); } + /** + * @return whether a plane is currently being tracked + */ public boolean isTrackingPlane() { return isTrackingPlane; } + /** + * @param tracking whether a plane is currently being tracked + */ public void setTrackingPlane( boolean tracking ) { isTrackingPlane = tracking; } public void setTrackedPlaneName(String trackedPlaneName) { @@ -95,17 +110,29 @@ public String getTrackedPlaneName() { return trackedPlaneName; } + /** + * @return whether Crosshair is in 'point mode' i.e. click to add points to fit plane + */ public boolean isInPointMode() { return isInPointMode; } + /** + * @param isInPointMode whether Crosshair is in 'point mode' i.e. click to add points to fit plane + */ public void setPointMode( boolean isInPointMode ) { this.isInPointMode = isInPointMode; bdvHandle.getViewerPanel().requestRepaint(); } + /** + * @return whether Crosshair is in 'vertex mode' i.e. click to add vertices to the block plane + */ public boolean isInVertexMode() { return isInVertexMode; } + /** + * @param isInVertexMode whether Crosshair is in 'vertex mode' i.e. click to add vertices to the block plane + */ public void setVertexMode( boolean isInVertexMode ) { this.isInVertexMode = isInVertexMode; bdvHandle.getViewerPanel().requestRepaint(); @@ -123,11 +150,21 @@ public boolean checkNamedPlaneExistsAndOrientationIsSet( String name ) { } } + /** + * Add a plane with given settings + * @param planeSettings plane settings + */ public void addPlane( PlaneSettings planeSettings ){ Plane plane = planeCreator.createPlane( planeSettings ); planeNameToPlane.put( planeSettings.name, plane); } + /** + * Add a plane with the given name and orientation + * @param planeName plane name + * @param planeNormal plane normal vector + * @param planePoint plane point + */ public void addPlane( String planeName, Vector3d planeNormal, Vector3d planePoint ) { PlaneSettings planeSettings = new PlaneSettings(); planeSettings.name = planeName; @@ -137,7 +174,10 @@ public void addPlane( String planeName, Vector3d planeNormal, Vector3d planePoin addPlane( planeSettings ); } - // add block plane with point overlays, but no mesh generated + /** + * Add a plane with point overlays, but no mesh generated + * @param planeName name of plane + */ public void addPlane( String planeName ) { PlaneSettings settings = new PlaneSettings(); settings.name = planeName; @@ -145,16 +185,30 @@ public void addPlane( String planeName ) { addPlane( settings ); } + /** + * Add a plane with position + orientation matching the current view in the BigDataViewer window + * @param planeName plane name + */ public void addPlaneAtCurrentView( String planeName ){ ArrayList planeDefinition = getPlaneDefinitionOfCurrentView(); addPlane( planeName, planeDefinition.get(0), planeDefinition.get(1) ); } + /** + * Add a block plane with given settings + * @param blockPlaneSettings block plane settings + */ public void addBlockPlane( BlockPlaneSettings blockPlaneSettings ) { BlockPlane plane = planeCreator.createBlockPlane( blockPlaneSettings ); planeNameToPlane.put( blockPlaneSettings.name, plane ); } + /** + * Add block plane with the given name and orientation + * @param planeName plane name + * @param planeNormal plane normal vector + * @param planePoint plane point + */ public void addBlockPlane( String planeName, Vector3d planeNormal, Vector3d planePoint ) { BlockPlaneSettings settings = new BlockPlaneSettings(); settings.name = planeName; @@ -164,7 +218,10 @@ public void addBlockPlane( String planeName, Vector3d planeNormal, Vector3d plan addBlockPlane( settings ); } - // add block plane with point overlays, but no mesh generated + /** + * Add block plane with point overlays, but no mesh generated + * @param planeName plane name + */ public void addBlockPlane( String planeName ) { BlockPlaneSettings settings = new BlockPlaneSettings(); settings.name = planeName; @@ -172,6 +229,10 @@ public void addBlockPlane( String planeName ) { addBlockPlane( settings ); } + /** + * Add a block plane with position + orientation matching the current view in the BigDataViewer window + * @param planeName plane name + */ public void addBlockPlaneAtCurrentView( String planeName ) { ArrayList planeDefinition = getPlaneDefinitionOfCurrentView(); addBlockPlane( planeName, planeDefinition.get(0), planeDefinition.get(1) ); @@ -185,12 +246,22 @@ public VertexDisplay getVertexDisplay( String planeName ) { return getBlockPlane( planeName ).getVertexDisplay(); } + /** + * Update orientation of named plane + * @param planeNormal new plane normal + * @param planePoint new plane point + * @param planeName name of plane to update + */ public void updatePlane( Vector3d planeNormal, Vector3d planePoint, String planeName ) { if ( checkNamedPlaneExists( planeName ) ) { planeCreator.updatePlaneOrientation( getPlane( planeName ), planeNormal, planePoint ); } } + /** + * Set colour of named plane to the aligned colour + * @param planeName plane name + */ public void setPlaneColourToAligned( String planeName ) { Color3f currentColour = universe.getContent( planeName ).getColor(); Color3f alignedColour = new Color3f( alignedPlaneColour ); @@ -199,6 +270,10 @@ public void setPlaneColourToAligned( String planeName ) { } } + /** + * Set colour of named plane to the unaligned colour + * @param planeName plane name + */ public void setPlaneColourToUnaligned( String planeName ) { Color3f currentColour = universe.getContent( planeName ).getColor(); Color3f notAlignedColour = new Color3f( planeNameToPlane.get(planeName).getColor() ); @@ -207,16 +282,28 @@ public void setPlaneColourToUnaligned( String planeName ) { } } + /** + * Update orientation of named plane to match given BigDataViewer affine transform + * @param affineTransform3D 3D affine transform of BigDataViewer window + * @param planeName plane name + */ public void updatePlaneOnTransformChange(AffineTransform3D affineTransform3D, String planeName) { ArrayList planeDefinition = getPlaneDefinitionFromViewTransform(affineTransform3D); updatePlane(planeDefinition.get(0), planeDefinition.get(1), planeName); } + /** + * Update orientation of named plane to match current view in the BigDataViewer window + * @param planeName plane name + */ public void updatePlaneCurrentView (String planeName) { ArrayList planeDefinition = getPlaneDefinitionOfCurrentView(); updatePlane(planeDefinition.get(0), planeDefinition.get(1), planeName); } + /** + * Re-draw all planes in the 3D viewer + */ public void redrawCurrentPlanes () { for ( String planeName: planeNameToPlane.keySet() ) { Plane plane = planeNameToPlane.get( planeName ); @@ -230,6 +317,10 @@ private void fitToPoints( String planeName, ArrayList points ) { getPlane( planeName ).setVisible( true ); } + /** + * Fit named plane to the points in its 'points to fit plane display' + * @param planeName plane name + */ public void fitToPoints( String planeName ) { ArrayList points = getPointsToFitPlaneDisplay( planeName ).getPointsToFitPlane(); @@ -252,6 +343,10 @@ public ArrayList getAll2dPointOverlays() { return pointOverlays; } + /** + * Get plane definition of the current view in the BigDataViewer window + * @return ArrayList of 2 vectors: the first being the plane normal, and the second the plane point + */ public ArrayList getPlaneDefinitionOfCurrentView () { final AffineTransform3D transform = new AffineTransform3D(); bdvHandle.getViewerPanel().state().getViewerTransform( transform ); @@ -287,6 +382,10 @@ private ArrayList getPlaneDefinitionFromViewTransform(AffineTransform3 return planeDefinition; } + /** + * Get global point at centre of the current view in the BigDataViewer window + * @return global centre point of BigDataViewer window + */ public double[] getGlobalViewCentre () { final AffineTransform3D transform = new AffineTransform3D(); bdvHandle.getViewerPanel().state().getViewerTransform( transform ); @@ -297,6 +396,10 @@ public double[] getGlobalViewCentre () { return centrePointGlobal; } + /** + * Move BigDataViewer window view to match the named plane + * @param name plane name + */ public void moveViewToNamedPlane (String name) { // check if you're already at the plane ArrayList planeDefinition = getPlaneDefinitionOfCurrentView(); @@ -337,6 +440,10 @@ private SourceAndConverter getMatchingBdvSource( String name ) { return null; } + /** + * Remove plane with given name + * @param name plane name + */ public void removeNamedPlane (String name) { if ( checkNamedPlaneExists(name) ) { PointsToFitPlaneDisplay pointsToFitPlaneDisplay = getPointsToFitPlaneDisplay( name ); diff --git a/src/main/java/de/embl/schwab/crosshair/points/overlays/Point3dOverlay.java b/src/main/java/de/embl/schwab/crosshair/points/overlays/Point3dOverlay.java index 05505a0..9ceeb3a 100644 --- a/src/main/java/de/embl/schwab/crosshair/points/overlays/Point3dOverlay.java +++ b/src/main/java/de/embl/schwab/crosshair/points/overlays/Point3dOverlay.java @@ -8,6 +8,9 @@ import java.util.Iterator; import java.util.List; +/** + * Class to manage points in the 3D viewer + */ // TODO - all 3D points / vertices for all planes are currently in the same point list. This means that overlapping // points are not allowed (while this is allowed in the 2D viewer, as each plane gets its own 2D overlay). // This is a limitation of ImageJ 3D Viewer. All point lists must be assocated with an imagecontent, and only one per @@ -17,16 +20,28 @@ public class Point3dOverlay { private Content imageContent; + /** + * Make a 3D point overlay for the given image content + * @param imageContent image content (displayed in 3D viewer) to associate points with + */ public Point3dOverlay( Content imageContent ) { this.imageContent = imageContent; } + /** + * Add point + * @param point 3D point + */ public void addPoint( RealPoint point ) { double[] position = new double[3]; point.localize(position); imageContent.getPointList().add("", position[0], position[1], position[2]); } + /** + * Remove given points + * @param points List of 3D points to remove + */ public void removePoints( List points ) { for( RealPoint point: points ) { removePointFromPointList( point ); @@ -35,6 +50,10 @@ public void removePoints( List points ) { refreshPoints(); } + /** + * Remove given point + * @param point 3D point + */ public void removePoint( RealPoint point ) { removePointFromPointList( point ); refreshPoints(); @@ -61,6 +80,11 @@ private void refreshPoints() { } } + /** + * Rename the given 3D point + * @param point 3D point to rename + * @param name new name + */ public void renamePoint3D( RealPoint point, String name ) { // rename any points with that name to "" to enforce only one point with each name BenesNamedPoint existingPointWithName = imageContent.getPointList().get(name); diff --git a/src/main/java/de/embl/schwab/crosshair/points/overlays/PointOverlay2d.java b/src/main/java/de/embl/schwab/crosshair/points/overlays/PointOverlay2d.java index c43d7d9..6f5eae4 100644 --- a/src/main/java/de/embl/schwab/crosshair/points/overlays/PointOverlay2d.java +++ b/src/main/java/de/embl/schwab/crosshair/points/overlays/PointOverlay2d.java @@ -8,10 +8,13 @@ import java.util.List; import java.util.Map; +/** + * Class for point overlay in the 2D BigDataViewer window + * same as https://github.com/bigdataviewer/bigdataviewer-vistools/blob/master/src/main/java/bdv/util/PointsOverlay.java + * but sets size to zero after certain distance + */ public abstract class PointOverlay2d extends BdvOverlay { - // same as https://github.com/bigdataviewer/bigdataviewer-vistools/blob/master/src/main/java/bdv/util/PointsOverlay.java - // but sets size to zero after certain distance - // could make it nicer like in the bdv workshop, where they make the size taper off in a sphere + // TODO- could make it nicer like in the bdv workshop, where they make the size taper off in a sphere private boolean showPoints = true; @@ -19,6 +22,9 @@ public boolean checkPointsVisible () { return showPoints; } + /** + * Toggle visibility of points + */ public void toggleShowPoints () { if (showPoints) { showPoints = false; @@ -27,6 +33,12 @@ public void toggleShowPoints () { } } + /** + * Draw points in the BigDataViewer window + * @param points 3D points to draw + * @param color colour of points + * @param graphics graphics 2D + */ protected void drawPoints( List< ? extends RealLocalizable> points, Color color, final Graphics2D graphics ) { if ( !showPoints ) { @@ -53,6 +65,12 @@ protected void drawPoints( List< ? extends RealLocalizable> points, Color color, } } + /** + * Draw text next to points in the BigDataViewer window + * @param pointLabelToPoint map of text labels to 3D points + * @param color colour of text + * @param graphics graphics 2D + */ protected void drawTextOnPoints( Map< String, ? extends RealLocalizable> pointLabelToPoint, Color color, final Graphics2D graphics ) { diff --git a/src/main/java/de/embl/schwab/crosshair/points/overlays/PointsToFitPlane2dOverlay.java b/src/main/java/de/embl/schwab/crosshair/points/overlays/PointsToFitPlane2dOverlay.java index c11ff5b..d236c5b 100644 --- a/src/main/java/de/embl/schwab/crosshair/points/overlays/PointsToFitPlane2dOverlay.java +++ b/src/main/java/de/embl/schwab/crosshair/points/overlays/PointsToFitPlane2dOverlay.java @@ -4,15 +4,26 @@ import java.awt.*; +/** + * Class for point to fit plane overlay in the 2D BigDataViewer window + */ public class PointsToFitPlane2dOverlay extends PointOverlay2d { private final PointsToFitPlaneDisplay pointsToFitPlaneDisplay; private final Color colPoint = new Color( 51, 255, 51);; + /** + * Create a points to fit plane overlay + * @param pointsToFitPlaneDisplay points to fit plane display + */ public PointsToFitPlane2dOverlay( PointsToFitPlaneDisplay pointsToFitPlaneDisplay ) { this.pointsToFitPlaneDisplay = pointsToFitPlaneDisplay; } + /** + * Draw points to BigDataViewer window + * @param g graphics 2D + */ @Override protected void draw( Graphics2D g ) { drawPoints( pointsToFitPlaneDisplay.getPointsToFitPlane(), colPoint, g ); diff --git a/src/main/java/de/embl/schwab/crosshair/points/overlays/VertexPoints2dOverlay.java b/src/main/java/de/embl/schwab/crosshair/points/overlays/VertexPoints2dOverlay.java index d260853..f00db6b 100644 --- a/src/main/java/de/embl/schwab/crosshair/points/overlays/VertexPoints2dOverlay.java +++ b/src/main/java/de/embl/schwab/crosshair/points/overlays/VertexPoints2dOverlay.java @@ -9,6 +9,9 @@ import java.util.HashMap; import java.util.Map; +/** + * Class for vertex points overlay in the 2D BigDataViewer window + */ public class VertexPoints2dOverlay extends PointOverlay2d { private final VertexDisplay vertexDisplay; @@ -16,10 +19,18 @@ public class VertexPoints2dOverlay extends PointOverlay2d { private final Color colVertex = new Color(0, 255, 255); private final Color colSelected = new Color(153, 0, 76); + /** + * Create a vertex overlay + * @param vertexDisplay vertex display + */ public VertexPoints2dOverlay( VertexDisplay vertexDisplay ) { this.vertexDisplay = vertexDisplay; } + /** + * Draw vertex points to BigDataViewer window + * @param g graphics 2D + */ @Override protected void draw(Graphics2D g) { if ( vertexDisplay.isVertexSelected() ) { diff --git a/src/test/java/develop/OpenImageJ.java b/src/test/java/develop/OpenImageJ.java deleted file mode 100644 index 6af2183..0000000 --- a/src/test/java/develop/OpenImageJ.java +++ /dev/null @@ -1,12 +0,0 @@ -package develop; - -import net.imagej.ImageJ; - -public class OpenImageJ -{ - public static void main( String[] args ) - { - final ImageJ imageJ = new net.imagej.ImageJ(); - imageJ.ui().showUI(); - } -} \ No newline at end of file From f94aa5610f9511d035e3607ac1649f22a70bac62 Mon Sep 17 00:00:00 2001 From: Kimberly Meechan Date: Sun, 26 Nov 2023 20:57:41 +0000 Subject: [PATCH 02/13] add tests for solution reader and writer --- .../settings/SettingsReaderTest.java | 23 +++++++++- .../solution/SolutionReaderTest.java | 44 ++++++++++++++++++ .../solution/SolutionWriterTest.java | 46 +++++++++++++++++++ 3 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 src/test/java/de/embl/schwab/crosshair/solution/SolutionReaderTest.java create mode 100644 src/test/java/de/embl/schwab/crosshair/solution/SolutionWriterTest.java diff --git a/src/test/java/de/embl/schwab/crosshair/settings/SettingsReaderTest.java b/src/test/java/de/embl/schwab/crosshair/settings/SettingsReaderTest.java index 0cd9d12..8976472 100644 --- a/src/test/java/de/embl/schwab/crosshair/settings/SettingsReaderTest.java +++ b/src/test/java/de/embl/schwab/crosshair/settings/SettingsReaderTest.java @@ -2,8 +2,11 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import java.io.File; +import java.nio.file.Path; +import java.util.Map; import static org.junit.jupiter.api.Assertions.*; @@ -21,6 +24,24 @@ public void setUp() { void readSettings() { ClassLoader classLoader = this.getClass().getClassLoader(); File json = new File(classLoader.getResource("exampleBlock.json").getFile()); - settingsReader.readSettings( json.getAbsolutePath() ); + Settings settings = settingsReader.readSettings( json.getAbsolutePath() ); + + Map planeNameToSettings = settings.planeNameToSettings; + Map< String, ImageContentSettings> imageNameToSettings = settings.imageNameToSettings; + + assertEquals(planeNameToSettings.size(), 2); + assertTrue(planeNameToSettings.containsKey("block")); + assertTrue(planeNameToSettings.containsKey("target")); + + assertEquals(imageNameToSettings.size(), 1); + assertTrue(imageNameToSettings.containsKey("image")); + } + + @Test + void readInvalidSettings( @TempDir Path tempDir ) { + File invalidJsonPath = tempDir.resolve( "invalid.json" ).toFile(); + Settings settings = settingsReader.readSettings( invalidJsonPath.getAbsolutePath() ); + + assertNull( settings ); } } \ No newline at end of file diff --git a/src/test/java/de/embl/schwab/crosshair/solution/SolutionReaderTest.java b/src/test/java/de/embl/schwab/crosshair/solution/SolutionReaderTest.java new file mode 100644 index 0000000..1919163 --- /dev/null +++ b/src/test/java/de/embl/schwab/crosshair/solution/SolutionReaderTest.java @@ -0,0 +1,44 @@ +package de.embl.schwab.crosshair.solution; + +import de.embl.schwab.crosshair.points.VertexPoint; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.*; + +class SolutionReaderTest { + + private SolutionReader solutionReader; + + @BeforeEach + public void setUp() { solutionReader = new SolutionReader(); } + + @Test + void readSolution() { + ClassLoader classLoader = this.getClass().getClassLoader(); + File json = new File(classLoader.getResource("exampleBlockSolution.json").getFile()); + Solution solution = solutionReader.readSolution( json.getAbsolutePath() ); + + assertEquals(solution.getInitialKnifeAngle(), 10.0); + assertEquals(solution.getInitialTiltAngle(), 5.0); + assertEquals(solution.getKnife(), 14.9449); + assertEquals(solution.getTilt(), -9.8089); + assertEquals(solution.getRotation(), 15.0); + assertEquals(solution.getFirstTouch(), VertexPoint.BottomRight); + assertEquals(solution.getDistanceToCut(), 210.8122); + assertEquals(solution.getAnglesUnit(), "degrees"); + assertEquals(solution.getDistanceUnit(), "microns"); + } + + @Test + void readInvalidSolution( @TempDir Path tempDir ) { + File invalidJsonPath = tempDir.resolve( "invalid.json" ).toFile(); + Solution solution = solutionReader.readSolution( invalidJsonPath.getAbsolutePath() ); + + assertNull( solution ); + } +} \ No newline at end of file diff --git a/src/test/java/de/embl/schwab/crosshair/solution/SolutionWriterTest.java b/src/test/java/de/embl/schwab/crosshair/solution/SolutionWriterTest.java new file mode 100644 index 0000000..8e0f779 --- /dev/null +++ b/src/test/java/de/embl/schwab/crosshair/solution/SolutionWriterTest.java @@ -0,0 +1,46 @@ +package de.embl.schwab.crosshair.solution; + +import de.embl.schwab.crosshair.points.VertexPoint; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.*; + +class SolutionWriterTest { + + @Test + void writeSolution( @TempDir Path tempDir ) { + + double initialKnifeAngle = 10.0 ; + double initialTiltAngle = 5.0; + double knife = 3.0; + double tilt = 8.0; + double rotation = 12.0; + VertexPoint firstTouch = VertexPoint.BottomLeft; + double distanceToCut = 100.0; + String distanceUnit = "microns"; + + File newJson = tempDir.resolve( "newBlock.json" ).toFile(); + Solution solution = new Solution( + initialKnifeAngle, initialTiltAngle, knife, + tilt, rotation, firstTouch, distanceToCut, distanceUnit); + + SolutionWriter solutionWriter = new SolutionWriter(solution, newJson.getAbsolutePath()); + solutionWriter.writeSolution(); + + assertTrue( newJson.exists() ); + + Solution newSolution = new SolutionReader().readSolution( newJson.getAbsolutePath() ); + assertEquals(newSolution.getInitialKnifeAngle(), initialKnifeAngle); + assertEquals(newSolution.getInitialTiltAngle(), initialTiltAngle); + assertEquals(newSolution.getKnife(), knife); + assertEquals(newSolution.getTilt(), tilt); + assertEquals(newSolution.getRotation(), rotation); + assertEquals(newSolution.getFirstTouch(), firstTouch); + assertEquals(newSolution.getDistanceToCut(), distanceToCut); + assertEquals(newSolution.getDistanceUnit(), distanceUnit); + } +} \ No newline at end of file From 59aaf5e67b8b3533b628c07018e0cf52d092e7be Mon Sep 17 00:00:00 2001 From: Kimberly Meechan Date: Sun, 26 Nov 2023 21:19:25 +0000 Subject: [PATCH 03/13] old format tests and stl resource tests --- .../crosshair/io/STLResourceLoaderTest.java | 26 +++++++++++++++++++ .../legacy/OldFormatSettingsReaderTest.java | 17 ++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 src/test/java/de/embl/schwab/crosshair/io/STLResourceLoaderTest.java diff --git a/src/test/java/de/embl/schwab/crosshair/io/STLResourceLoaderTest.java b/src/test/java/de/embl/schwab/crosshair/io/STLResourceLoaderTest.java new file mode 100644 index 0000000..16ac2eb --- /dev/null +++ b/src/test/java/de/embl/schwab/crosshair/io/STLResourceLoaderTest.java @@ -0,0 +1,26 @@ +package de.embl.schwab.crosshair.io; + +import customnode.CustomMesh; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +class STLResourceLoaderTest { + + @ParameterizedTest + @ValueSource(strings = {"/arc.stl", "/holder_back.stl", "/holder_front.stl", "/knife.stl"}) + void loadSTL(String modelName) { + Map currentStl = STLResourceLoader.loadSTL(modelName); + assertNotNull(currentStl); + } + + @Test + void loadInvalidSTL() { + Map currentStl = STLResourceLoader.loadSTL("invalid.stl"); + assertNull(currentStl); + } +} \ No newline at end of file diff --git a/src/test/java/de/embl/schwab/crosshair/legacy/OldFormatSettingsReaderTest.java b/src/test/java/de/embl/schwab/crosshair/legacy/OldFormatSettingsReaderTest.java index 70092f7..fd80d7c 100644 --- a/src/test/java/de/embl/schwab/crosshair/legacy/OldFormatSettingsReaderTest.java +++ b/src/test/java/de/embl/schwab/crosshair/legacy/OldFormatSettingsReaderTest.java @@ -2,9 +2,10 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import java.io.File; -import java.io.IOException; +import java.nio.file.Path; import static org.junit.jupiter.api.Assertions.*; @@ -22,6 +23,18 @@ public void setUp() { void readSettings() { ClassLoader classLoader = this.getClass().getClassLoader(); File oldJson = new File(classLoader.getResource("legacy/exampleBlock.json").getFile()); - oldFormatSettingsReader.readSettings( oldJson.getAbsolutePath() ); + OldFormatSettings settings = oldFormatSettingsReader.readSettings( oldJson.getAbsolutePath() ); + + assertEquals(settings.planeNormals.size(), 2); + assertTrue(settings.planeNormals.containsKey("block")); + assertTrue(settings.planeNormals.containsKey("target")); + } + + @Test + void readInvalidSettings( @TempDir Path tempDir ) { + File invalidJsonPath = tempDir.resolve( "invalid.json" ).toFile(); + OldFormatSettings settings = oldFormatSettingsReader.readSettings( invalidJsonPath.getAbsolutePath() ); + + assertNull( settings ); } } \ No newline at end of file From 3b161796abe7e154f2a195a8a583c8639154d69b Mon Sep 17 00:00:00 2001 From: Kimberly Meechan Date: Mon, 27 Nov 2023 20:57:51 +0000 Subject: [PATCH 04/13] refactor opening crosshair --- .../de/embl/schwab/crosshair/Crosshair.java | 61 ++++++++++++++++++- .../OpenCrosshairFromBdvXmlCommand.java | 28 +-------- .../OpenCrosshairFromCurrentImageCommand.java | 52 +--------------- .../openexamples/OpenExampleBlock.java | 10 +++ 4 files changed, 72 insertions(+), 79 deletions(-) diff --git a/src/main/java/de/embl/schwab/crosshair/Crosshair.java b/src/main/java/de/embl/schwab/crosshair/Crosshair.java index 9d9c646..5762f85 100644 --- a/src/main/java/de/embl/schwab/crosshair/Crosshair.java +++ b/src/main/java/de/embl/schwab/crosshair/Crosshair.java @@ -1,13 +1,19 @@ package de.embl.schwab.crosshair; import bdv.util.*; +import bdv.viewer.Source; import de.embl.schwab.crosshair.bdv.BdvBehaviours; import de.embl.schwab.crosshair.microtome.MicrotomeManager; import de.embl.schwab.crosshair.plane.PlaneManager; import de.embl.schwab.crosshair.ui.swing.CrosshairFrame; import ij3d.Content; import ij3d.Image3DUniverse; +import net.imglib2.img.Img; +import net.imglib2.img.display.imagej.ImageJFunctions; +import net.imglib2.type.numeric.ARGBType; +import ij.ImagePlus; +import static de.embl.cba.tables.ij3d.UniverseUtils.addSourceToUniverse; import static de.embl.schwab.crosshair.utils.Utils.spaceOutWindows; // TODO - neaten up code structure, possibly clearer labelling of which coordinate system & units are being used @@ -33,7 +39,59 @@ public class Crosshair { public static final String block = "block"; public static final String image = "image"; - public Crosshair (BdvStackSource bdvStackSource, Image3DUniverse universe, Content imageContent, String unit) { + // TODO - make generic? Not just 8 bit + private final int min = 0; + private final int max = 255; + private final float transparency = 0.7f; + + /** + * Open Crosshair from a Source (normally from a bdv style file e.g. hdf5 / n5) + * @param imageSource image source + */ + public Crosshair(Source imageSource) { + + BdvStackSource bdvStackSource = BdvFunctions.show(imageSource, 1); + Image3DUniverse universe = new Image3DUniverse(); + universe.show(); + + String unit = imageSource.getVoxelDimensions().unit(); + + // Set to arbitrary colour + ARGBType colour = new ARGBType( ARGBType.rgba( 0, 0, 0, 0 ) ); + Content imageContent = addSourceToUniverse(universe, imageSource, 300 * 300 * 300, + Content.VOLUME, colour, transparency, min, max ); + // Reset colour to default for 3D viewer + imageContent.setColor(null); + + initialiseCrosshair(bdvStackSource, universe, imageContent, unit); + } + + /** + * Open Crosshair from an ImagePlus (normally by pulling current image from ImageJ) + * @param imagePlus image + */ + public Crosshair(ImagePlus imagePlus) { + + Image3DUniverse universe = new Image3DUniverse(); + Content imageContent = universe.addContent(imagePlus, Content.VOLUME); + imageContent.setTransparency(transparency); + universe.show(); + + final double pw = imagePlus.getCalibration().pixelWidth; + final double ph = imagePlus.getCalibration().pixelHeight; + final double pd = imagePlus.getCalibration().pixelDepth; + final String unit = imagePlus.getCalibration().getUnit(); + + final Img wrap = ImageJFunctions.wrap(imagePlus); + BdvStackSource bdvStackSource = BdvFunctions.show(wrap, "raw", Bdv.options() + .sourceTransform(pw, ph, pd)); + + initialiseCrosshair(bdvStackSource, universe, imageContent, unit); + } + + private void initialiseCrosshair(BdvStackSource bdvStackSource, Image3DUniverse universe, Content imageContent, String unit) { + + bdvStackSource.setDisplayRange(min, max); BdvHandle bdvHandle = bdvStackSource.getBdvHandle(); imageContent.setLocked(true); @@ -54,4 +112,5 @@ public Crosshair (BdvStackSource bdvStackSource, Image3DUniverse universe, Conte spaceOutWindows( bdvHandle, crosshairFrame, universe ); } + } diff --git a/src/main/java/de/embl/schwab/crosshair/ui/command/OpenCrosshairFromBdvXmlCommand.java b/src/main/java/de/embl/schwab/crosshair/ui/command/OpenCrosshairFromBdvXmlCommand.java index 89b7d1c..919d416 100644 --- a/src/main/java/de/embl/schwab/crosshair/ui/command/OpenCrosshairFromBdvXmlCommand.java +++ b/src/main/java/de/embl/schwab/crosshair/ui/command/OpenCrosshairFromBdvXmlCommand.java @@ -1,17 +1,11 @@ package de.embl.schwab.crosshair.ui.command; -import bdv.util.BdvFunctions; -import bdv.util.BdvStackSource; import de.embl.cba.bdv.utils.sources.LazySpimSource; import de.embl.schwab.crosshair.Crosshair; -import ij3d.Content; -import ij3d.Image3DUniverse; -import net.imglib2.type.numeric.ARGBType; import org.scijava.command.Command; import org.scijava.plugin.Plugin; import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; -import static de.embl.cba.tables.ij3d.UniverseUtils.addSourceToUniverse; @Plugin(type = Command.class, menuPath = "Plugins>Crosshair>Open>Target Bdv File" ) public class OpenCrosshairFromBdvXmlCommand implements Command { @@ -36,26 +30,6 @@ public void run() { public void openPathInCrosshair() { final LazySpimSource imageSource = new LazySpimSource("raw", bdvXmlFilePath); - BdvStackSource bdvStackSource = BdvFunctions.show(imageSource, 1); - bdvStackSource.setDisplayRange(0, 255); - - Image3DUniverse universe = new Image3DUniverse(); - universe.show(); - - String unit = imageSource.getVoxelDimensions().unit(); - - // Set to arbitrary colour - ARGBType colour = new ARGBType( ARGBType.rgba( 0, 0, 0, 0 ) ); - Content imageContent = addSourceToUniverse(universe, imageSource, 300 * 300 * 300, Content.VOLUME, colour, 0.7f, 0, 255 ); - // Reset colour to default for 3D viewer - imageContent.setColor(null); - - new Crosshair(bdvStackSource, universe, imageContent, unit); - } - - public static void main( String[] args ) { - OpenCrosshairFromBdvXmlCommand command = new OpenCrosshairFromBdvXmlCommand(); - command.bdvXmlFilePath = "C:\\Users\\meechan\\Documents\\test_images\\Flipped_imaged_before.xml"; - command.openPathInCrosshair(); + new Crosshair(imageSource); } } diff --git a/src/main/java/de/embl/schwab/crosshair/ui/command/OpenCrosshairFromCurrentImageCommand.java b/src/main/java/de/embl/schwab/crosshair/ui/command/OpenCrosshairFromCurrentImageCommand.java index e399e9d..c0762f3 100644 --- a/src/main/java/de/embl/schwab/crosshair/ui/command/OpenCrosshairFromCurrentImageCommand.java +++ b/src/main/java/de/embl/schwab/crosshair/ui/command/OpenCrosshairFromCurrentImageCommand.java @@ -1,15 +1,7 @@ package de.embl.schwab.crosshair.ui.command; -import bdv.util.Bdv; -import bdv.util.BdvFunctions; -import bdv.util.BdvStackSource; import de.embl.schwab.crosshair.Crosshair; -import ij.IJ; import ij.ImagePlus; -import ij3d.Content; -import ij3d.Image3DUniverse; -import net.imglib2.img.Img; -import net.imglib2.img.display.imagej.ImageJFunctions; import org.scijava.command.Command; import org.scijava.plugin.Parameter; import org.scijava.plugin.Plugin; @@ -23,48 +15,6 @@ public class OpenCrosshairFromCurrentImageCommand implements Command @Override public void run() { - Image3DUniverse universe = new Image3DUniverse(); - Content imageContent = universe.addContent(imagePlus, Content.VOLUME); - imageContent.setTransparency(0.7F); - universe.show(); - - final double pw = imagePlus.getCalibration().pixelWidth; - final double ph = imagePlus.getCalibration().pixelHeight; - final double pd = imagePlus.getCalibration().pixelDepth; - final String unit = imagePlus.getCalibration().getUnit(); - - final Img wrap = ImageJFunctions.wrap(imagePlus); - BdvStackSource bdvStackSource = BdvFunctions.show(wrap, "raw", Bdv.options() - .sourceTransform(pw, ph, pd)); - // TODO - make generic? Not just 8 bit - bdvStackSource.setDisplayRange(0, 255); - - new Crosshair(bdvStackSource, universe, imageContent, unit); - - } - - public static void main( String[] args ) - { - // final String INPUT_IMAGE = "C:\\Users\\meechan\\Documents\\test_3d_larger_anisotropic\\test_3d_larger_anisotropic.tif"; - final String INPUT_IMAGE = "C:\\Users\\meechan\\Documents\\test_images\\Flipped_images_before.tif"; - ImagePlus imagePlus = IJ.openImage(INPUT_IMAGE); - Image3DUniverse universe = new Image3DUniverse(); - Content imageContent = universe.addContent(imagePlus, Content.VOLUME); - imageContent.setTransparency(0.7F); - universe.show(); - - final double pw = imagePlus.getCalibration().pixelWidth; - final double ph = imagePlus.getCalibration().pixelHeight; - final double pd = imagePlus.getCalibration().pixelDepth; - final String unit = imagePlus.getCalibration().getUnit(); - - final Img wrap = ImageJFunctions.wrap(imagePlus); - BdvStackSource bdvStackSource = BdvFunctions.show(wrap, "raw", Bdv.options() - .sourceTransform(pw, ph, pd)); - // TODO - make generic? Not just 8 bit - bdvStackSource.setDisplayRange(0, 255); - - new Crosshair(bdvStackSource, universe, imageContent, unit); - + new Crosshair(imagePlus); } } diff --git a/src/test/java/develop/openexamples/OpenExampleBlock.java b/src/test/java/develop/openexamples/OpenExampleBlock.java index ef82082..1d37082 100644 --- a/src/test/java/develop/openexamples/OpenExampleBlock.java +++ b/src/test/java/develop/openexamples/OpenExampleBlock.java @@ -1,12 +1,22 @@ package develop.openexamples; +import com.formdev.flatlaf.FlatLightLaf; import de.embl.schwab.crosshair.ui.command.OpenCrosshairFromBdvXmlCommand; +import javax.swing.*; import java.io.File; public class OpenExampleBlock { public void open() { + + // Match Fiji's new default look and feel + try { + UIManager.setLookAndFeel(new FlatLightLaf() ); + } catch (UnsupportedLookAndFeelException e) { + throw new RuntimeException(e); + } + OpenCrosshairFromBdvXmlCommand command = new OpenCrosshairFromBdvXmlCommand(); ClassLoader classLoader = this.getClass().getClassLoader(); File headFile = new File(classLoader.getResource("exampleBlock.xml").getFile()); From f3e9f02653ecc5a56559f3f0e91edb59002c56df Mon Sep 17 00:00:00 2001 From: Kimberly Meechan Date: Sun, 10 Dec 2023 11:22:48 +0000 Subject: [PATCH 05/13] fix junit version --- pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 331dfab..2ad0bc5 100644 --- a/pom.xml +++ b/pom.xml @@ -76,7 +76,6 @@ de.embl.schwab.crosshair bsd_2 EMBL - C:\Users\meechan\Documents\CrosshairUpload\Fiji.app true @@ -120,7 +119,7 @@ org.junit.jupiter junit-jupiter - RELEASE + ${junit-jupiter.version} test From a3de9a23fba1460f42761c3b44096d51158d3a22 Mon Sep 17 00:00:00 2001 From: Kimberly Meechan Date: Sun, 10 Dec 2023 18:29:04 +0000 Subject: [PATCH 06/13] refactor and add javadoc for point displays --- .../schwab/crosshair/plane/PlaneCreator.java | 12 ++-- .../schwab/crosshair/plane/PlaneManager.java | 5 +- .../schwab/crosshair/points/PointHelper.java | 47 +++++++------ .../points/PointsToFitPlaneDisplay.java | 40 ++++++++--- .../crosshair/points/VertexDisplay.java | 66 +++++++++++++++---- .../schwab/crosshair/points/VertexPoint.java | 3 + .../points/overlays/Point3dOverlay.java | 12 ++-- .../overlays/PointsToFitPlane2dOverlay.java | 3 +- .../overlays/VertexPoints2dOverlay.java | 3 +- 9 files changed, 128 insertions(+), 63 deletions(-) diff --git a/src/main/java/de/embl/schwab/crosshair/plane/PlaneCreator.java b/src/main/java/de/embl/schwab/crosshair/plane/PlaneCreator.java index 8fb013c..8e0ef38 100644 --- a/src/main/java/de/embl/schwab/crosshair/plane/PlaneCreator.java +++ b/src/main/java/de/embl/schwab/crosshair/plane/PlaneCreator.java @@ -4,7 +4,6 @@ import customnode.CustomTriangleMesh; import de.embl.schwab.crosshair.points.PointsToFitPlaneDisplay; import de.embl.schwab.crosshair.points.VertexDisplay; -import de.embl.schwab.crosshair.points.overlays.Point3dOverlay; import de.embl.schwab.crosshair.settings.BlockPlaneSettings; import de.embl.schwab.crosshair.settings.PlaneSettings; import de.embl.schwab.crosshair.utils.GeometryUtils; @@ -26,20 +25,17 @@ public class PlaneCreator { private final Image3DUniverse universe; // universe to add all planes to private final Content imageContent; // 3d image content used to define bounds of plane private final Bdv bdv; // bdv instance to assign to plane, needed to keep 2d point overlays up to date - private final Point3dOverlay point3dOverlay; // 3d point overlay to assign to plane /** * Create a plane creator * @param universe universe of the 3D viewer * @param imageContent image content displayed in 3D viewer (used to define bounds of the planes) * @param bdv BigDataViewer window - * @param point3dOverlay point overlay for 3D viewer */ - public PlaneCreator(Image3DUniverse universe, Content imageContent, Bdv bdv, Point3dOverlay point3dOverlay ) { + public PlaneCreator(Image3DUniverse universe, Content imageContent, Bdv bdv ) { this.universe = universe; this.imageContent = imageContent; this.bdv = bdv; - this.point3dOverlay = point3dOverlay; } private class CentroidAndMesh { @@ -55,7 +51,7 @@ private class CentroidAndMesh { public Plane createPlane( PlaneSettings planeSettings ) { PointsToFitPlaneDisplay pointsToFitPlaneDisplay = new PointsToFitPlaneDisplay( - planeSettings.pointsToFitPlane, planeSettings.name, bdv, point3dOverlay ); + planeSettings.pointsToFitPlane, planeSettings.name, bdv, imageContent ); if ( isOrientationSet( planeSettings ) ) { CentroidAndMesh centroidAndMesh = createCentroidAndMesh(planeSettings); @@ -73,9 +69,9 @@ public Plane createPlane( PlaneSettings planeSettings ) { public BlockPlane createBlockPlane( BlockPlaneSettings blockPlaneSettings ) { PointsToFitPlaneDisplay pointsToFitPlaneDisplay = new PointsToFitPlaneDisplay( - blockPlaneSettings.pointsToFitPlane, blockPlaneSettings.name, bdv, point3dOverlay ); + blockPlaneSettings.pointsToFitPlane, blockPlaneSettings.name, bdv, imageContent ); VertexDisplay vertexDisplay = new VertexDisplay( - blockPlaneSettings.vertices, blockPlaneSettings.assignedVertices, blockPlaneSettings.name, bdv, point3dOverlay ); + blockPlaneSettings.vertices, blockPlaneSettings.assignedVertices, blockPlaneSettings.name, bdv, imageContent ); if ( isOrientationSet( blockPlaneSettings ) ) { CentroidAndMesh centroidAndMesh = createCentroidAndMesh( blockPlaneSettings ); diff --git a/src/main/java/de/embl/schwab/crosshair/plane/PlaneManager.java b/src/main/java/de/embl/schwab/crosshair/plane/PlaneManager.java index 8b7b6cd..d865d0b 100644 --- a/src/main/java/de/embl/schwab/crosshair/plane/PlaneManager.java +++ b/src/main/java/de/embl/schwab/crosshair/plane/PlaneManager.java @@ -8,7 +8,6 @@ import de.embl.schwab.crosshair.bdv.ModeOverlay; import de.embl.schwab.crosshair.points.PointsToFitPlaneDisplay; import de.embl.schwab.crosshair.points.VertexDisplay; -import de.embl.schwab.crosshair.points.overlays.Point3dOverlay; import de.embl.schwab.crosshair.points.overlays.PointOverlay2d; import de.embl.schwab.crosshair.settings.BlockPlaneSettings; import de.embl.schwab.crosshair.settings.PlaneSettings; @@ -44,7 +43,6 @@ public class PlaneManager { private final BdvHandle bdvHandle; private final BdvStackSource bdvStackSource; private final Image3DUniverse universe; - private final Point3dOverlay point3dOverlay; private final Color3f alignedPlaneColour = new Color3f(1, 0, 0); // TODO - make this threshold user definable - makes sense for microns, but possibly not for other units @@ -66,9 +64,8 @@ public PlaneManager( BdvStackSource bdvStackSource, Image3DUniverse universe, Co Bdv.options().addTo( bdvStackSource ) ); this.bdvHandle = bdvStackSource.getBdvHandle(); this.universe = universe; - this.point3dOverlay = new Point3dOverlay( imageContent ); - this.planeCreator = new PlaneCreator( universe, imageContent, bdvStackSource, point3dOverlay ); + this.planeCreator = new PlaneCreator( universe, imageContent, bdvStackSource ); } public Plane getPlane( String planeName ) { diff --git a/src/main/java/de/embl/schwab/crosshair/points/PointHelper.java b/src/main/java/de/embl/schwab/crosshair/points/PointHelper.java index 0752c74..b26ea3b 100644 --- a/src/main/java/de/embl/schwab/crosshair/points/PointHelper.java +++ b/src/main/java/de/embl/schwab/crosshair/points/PointHelper.java @@ -9,28 +9,35 @@ public class PointHelper { + /** + * Get current position of mouse in BigDataViewer window (in global coordinates) + * @param bdvHandle BigDataViewer handle + * @return mouse position + */ public static RealPoint getCurrentMousePosition ( BdvHandle bdvHandle ) { RealPoint point = new RealPoint(3); bdvHandle.getViewerPanel().getGlobalMouseCoordinates(point); return point; } - public static boolean pointIsNearExistingPoint( ArrayList points, RealPoint point, BdvHandle bdvHandle ) { - double[] pointViewerCoords = convertToViewerCoordinates( point, bdvHandle ); - - for ( int i = 0; i < points.size(); i++ ) - { - RealPoint currentPoint = points.get(i); - double[] currentPointViewerCoords = convertToViewerCoordinates( currentPoint, bdvHandle ); - double distance = GeometryUtils.distanceBetweenPoints(pointViewerCoords, currentPointViewerCoords); - if (distance < 5) { - return true; - } - } - - return false; + /** + * Get current position of mouse in BigDataViewer window (in viewer coordinates) + * @param bdvHandle BigDataViewer handle + * @return mouse position + */ + public static double[] getCurrentPositionViewerCoordinates ( BdvHandle bdvHandle ) { + RealPoint point = getCurrentMousePosition( bdvHandle ); + return convertToViewerCoordinates( point, bdvHandle ); } + /** + * Check if the given 'point' is within a small distance of any of the 'points'. If so, return the first matching + * point (distance between points is checked in viewer coordinates of Bdv) + * @param points Points to match to + * @param point Point + * @param bdvHandle BigDataViewer handle + * @return Matching point (if any) or null + */ public static RealPoint getMatchingPointWithinDistance( ArrayList points, RealPoint point, BdvHandle bdvHandle ) { double[] pointViewerCoords = convertToViewerCoordinates( point, bdvHandle ); @@ -47,12 +54,12 @@ public static RealPoint getMatchingPointWithinDistance( ArrayList poi return null; } - public static double[] getCurrentPositionViewerCoordinates ( BdvHandle bdvHandle ) { - RealPoint point = getCurrentMousePosition( bdvHandle ); - return convertToViewerCoordinates( point, bdvHandle ); - } - - + /** + * Convert global coordinates to viewer coordinates (for the given BigDataViewer window) + * @param point Point to convert + * @param bdvHandle BigDataViewer handle + * @return Point in viewer coordinates + */ public static double[] convertToViewerCoordinates ( RealPoint point, BdvHandle bdvHandle ) { final AffineTransform3D transform = new AffineTransform3D(); bdvHandle.getViewerPanel().state().getViewerTransform( transform ); diff --git a/src/main/java/de/embl/schwab/crosshair/points/PointsToFitPlaneDisplay.java b/src/main/java/de/embl/schwab/crosshair/points/PointsToFitPlaneDisplay.java index 9ca1aad..2116ffe 100644 --- a/src/main/java/de/embl/schwab/crosshair/points/PointsToFitPlaneDisplay.java +++ b/src/main/java/de/embl/schwab/crosshair/points/PointsToFitPlaneDisplay.java @@ -4,6 +4,7 @@ import bdv.util.BdvFunctions; import de.embl.schwab.crosshair.points.overlays.Point3dOverlay; import de.embl.schwab.crosshair.points.overlays.PointsToFitPlane2dOverlay; +import ij3d.Content; import net.imglib2.RealPoint; import java.util.ArrayList; @@ -11,22 +12,39 @@ import static de.embl.schwab.crosshair.points.PointHelper.getCurrentMousePosition; import static de.embl.schwab.crosshair.points.PointHelper.getMatchingPointWithinDistance; +/** + * Class to control 2D and 3D display of points used to fit a specific plane + * Each plane will get its own PointsToFitPlaneDisplay. + */ public class PointsToFitPlaneDisplay { private final ArrayList pointsToFitPlane; // points used to fit this plane - private Bdv bdv; - private Point3dOverlay point3dOverlay; - private PointsToFitPlane2dOverlay point2dOverlay; - private String sourceName; - - public PointsToFitPlaneDisplay( String name, Bdv bdv, Point3dOverlay point3dOverlay ) { - this( new ArrayList<>(), name, bdv, point3dOverlay ); + private final Bdv bdv; + private final Point3dOverlay point3dOverlay; + private final PointsToFitPlane2dOverlay point2dOverlay; + private final String sourceName; + + /** + * Create a points to fit plane display (starting with no points) + * @param name Plane name + * @param bdv BigDataViewer window to show 2D points on + * @param imageContent image content (displayed in 3D viewer) to show 3D points on + */ + public PointsToFitPlaneDisplay( String name, Bdv bdv, Content imageContent ) { + this( new ArrayList<>(), name, bdv, imageContent ); } - public PointsToFitPlaneDisplay( ArrayList pointsToFitPlane, String name, Bdv bdv, Point3dOverlay point3dOverlay ) { + /** + * Create a points to fit plane display (starting with list of points) + * @param pointsToFitPlane List of points to fit plane + * @param name Plane name + * @param bdv BigDataViewer window to show 2D points on + * @param imageContent image content (displayed in 3D viewer) to show 3D points on + */ + public PointsToFitPlaneDisplay( ArrayList pointsToFitPlane, String name, Bdv bdv, Content imageContent ) { this.pointsToFitPlane = pointsToFitPlane; this.point2dOverlay = new PointsToFitPlane2dOverlay( this ); - this.point3dOverlay = point3dOverlay; + this.point3dOverlay = new Point3dOverlay( imageContent ); this.bdv = bdv; this.sourceName = name + "-points_to_fit_plane"; BdvFunctions.showOverlay( point2dOverlay, sourceName, @@ -49,6 +67,10 @@ public String getSourceName() { return sourceName; } + /** + * Add point at current mouse position in BigDataViewer window. If there's already a point there, then + * remove it instead. + */ public void addOrRemoveCurrentPositionFromPointsToFitPlane() { RealPoint point = getCurrentMousePosition( bdv.getBdvHandle() ); diff --git a/src/main/java/de/embl/schwab/crosshair/points/VertexDisplay.java b/src/main/java/de/embl/schwab/crosshair/points/VertexDisplay.java index 34ac235..cca4f46 100644 --- a/src/main/java/de/embl/schwab/crosshair/points/VertexDisplay.java +++ b/src/main/java/de/embl/schwab/crosshair/points/VertexDisplay.java @@ -7,6 +7,7 @@ import de.embl.schwab.crosshair.points.overlays.VertexPoints2dOverlay; import de.embl.schwab.crosshair.utils.GeometryUtils; import ij.IJ; +import ij3d.Content; import net.imglib2.RealPoint; import java.util.ArrayList; @@ -16,6 +17,10 @@ import static de.embl.schwab.crosshair.points.PointHelper.getCurrentMousePosition; import static de.embl.schwab.crosshair.points.PointHelper.getMatchingPointWithinDistance; +/** + * Class to control 2D and 3D display of vertices (i.e. named block face corners) + * Each block plane will get its own VertexDisplay. + */ public class VertexDisplay { private final ArrayList vertices; // all vertex points placed on the block plane @@ -24,24 +29,38 @@ public class VertexDisplay { private transient boolean isVertexSelected; private transient RealPoint selectedVertex; - private VertexPoints2dOverlay vertex2dOverlay; - private Point3dOverlay vertex3dOverlay; - private Bdv bdv; - private String name; - private String sourceName; - - public VertexDisplay( String name, Bdv bdv, Point3dOverlay point3dOverlay ) { - this( new ArrayList<>(), new HashMap<>(), name, bdv, point3dOverlay ); - } - + private final VertexPoints2dOverlay vertex2dOverlay; + private final Point3dOverlay vertex3dOverlay; + private final Bdv bdv; + private final String name; + private final String sourceName; + + /** + * Create a vertex display (starting with no vertices) + * @param name Block plane name + * @param bdv BigDataViewer window to show 2D vertices on + * @param imageContent image content (displayed in 3D viewer) to show 3D vertices on + */ + public VertexDisplay( String name, Bdv bdv, Content imageContent ) { + this( new ArrayList<>(), new HashMap<>(), name, bdv, imageContent ); + } + + /** + * Create a vertex display (starting with list of vertices) + * @param vertices List of vertices + * @param assignedVertices Map of vertex assignment to vertex (e.g. top left, top right..) + * @param name Block plane name + * @param bdv BigDataViewer window to show 2D vertices on + * @param imageContent image content (displayed in 3D viewer) to show 3D vertices on + */ public VertexDisplay( ArrayList vertices, Map assignedVertices, - String name, Bdv bdv, Point3dOverlay vertex3dOverlay ) { + String name, Bdv bdv, Content imageContent ) { this.vertices = vertices; this.assignedVertices = assignedVertices; this.isVertexSelected = false; this.vertex2dOverlay = new VertexPoints2dOverlay( this ); - this.vertex3dOverlay = vertex3dOverlay; + this.vertex3dOverlay = new Point3dOverlay( imageContent ); this.bdv = bdv; this.name = name; this.sourceName = name + "-vertex_points"; @@ -97,6 +116,10 @@ public String getSourceName() { return sourceName; } + /** + * Assign selected vertex as top left, top right etc... + * @param vertexPoint Assignment + */ public void assignSelectedVertex(VertexPoint vertexPoint ) { if ( !isVertexSelected ) { IJ.log("No vertex selected"); @@ -105,6 +128,11 @@ public void assignSelectedVertex(VertexPoint vertexPoint ) { } } + /** + * Assign given vertex as top left, top right etc... + * @param vertexPoint Assignment + * @param vertex vertex to assign + */ public void assignVertex( VertexPoint vertexPoint, RealPoint vertex ) { // enforce unique vertex point assignments i.e. remove any already assigned to that vertex removeAssignedVertex( vertex ); @@ -119,7 +147,11 @@ private void displayAssignedVertex( VertexPoint vertexPoint, RealPoint vertex ) bdv.getBdvHandle().getViewerPanel().requestRepaint(); } - // enforce lies on certain plane + /** + * Add vertex at current mouse position in BigDataViewer window - only if it lies on the given plane! + * If there's already a vertex there, then remove it instead. + * @param plane Plane vertex must lie on + */ public void addOrRemoveCurrentPositionFromVertices( Plane plane ) { // Check if on the current block plane RealPoint point = getCurrentMousePosition( bdv.getBdvHandle() ); @@ -130,12 +162,18 @@ public void addOrRemoveCurrentPositionFromVertices( Plane plane ) { } } - // don't enforce lies on certain plane + /** + * Add vertex at current mouse position in BigDataViewer window (no requirement to be on specific plane) + * If there's already a vertex there, then remove it instead. + */ public void addOrRemoveCurrentPositionFromVertices() { RealPoint point = getCurrentMousePosition( bdv.getBdvHandle() ); addOrRemoveVertex( point ); } + /** + * If there's a vertex at the current mouse position (in BigDataViewer window), then toggle its selection status. + */ public void toggleSelectedVertexCurrentPosition () { RealPoint point = getCurrentMousePosition( bdv.getBdvHandle() ); diff --git a/src/main/java/de/embl/schwab/crosshair/points/VertexPoint.java b/src/main/java/de/embl/schwab/crosshair/points/VertexPoint.java index 43c8974..1c47ec6 100644 --- a/src/main/java/de/embl/schwab/crosshair/points/VertexPoint.java +++ b/src/main/java/de/embl/schwab/crosshair/points/VertexPoint.java @@ -1,5 +1,8 @@ package de.embl.schwab.crosshair.points; +/** + * Enum for vertex assignments (i.e. block face corner assignments) + */ public enum VertexPoint { TopLeft, diff --git a/src/main/java/de/embl/schwab/crosshair/points/overlays/Point3dOverlay.java b/src/main/java/de/embl/schwab/crosshair/points/overlays/Point3dOverlay.java index 9ceeb3a..6b718a2 100644 --- a/src/main/java/de/embl/schwab/crosshair/points/overlays/Point3dOverlay.java +++ b/src/main/java/de/embl/schwab/crosshair/points/overlays/Point3dOverlay.java @@ -9,13 +9,13 @@ import java.util.List; /** - * Class to manage points in the 3D viewer + * Class to manage display of points in the 3D viewer + * Note: all 3D points / vertices for all planes are currently in the same point list. This means that overlapping + * points are not allowed (while this is allowed in the 2D viewer, as each plane gets its own 2D overlay). + * This is a limitation of ImageJ 3D Viewer. All point lists must be associated with an imagecontent (of which we + * only have 1), and only one per imageContent. Swapping to SciView at some point would be a good plan + * (this can be done with point meshes in the 3d viewer, but points can't be named, and are harder to remove) */ -// TODO - all 3D points / vertices for all planes are currently in the same point list. This means that overlapping -// points are not allowed (while this is allowed in the 2D viewer, as each plane gets its own 2D overlay). -// This is a limitation of ImageJ 3D Viewer. All point lists must be assocated with an imagecontent, and only one per -// imageContent. Swapping to SciView at some point would be a good plan -// (this can be done with point meshes in the 3d viewer, but points can't be named, and are harder to remove) public class Point3dOverlay { private Content imageContent; diff --git a/src/main/java/de/embl/schwab/crosshair/points/overlays/PointsToFitPlane2dOverlay.java b/src/main/java/de/embl/schwab/crosshair/points/overlays/PointsToFitPlane2dOverlay.java index d236c5b..878305d 100644 --- a/src/main/java/de/embl/schwab/crosshair/points/overlays/PointsToFitPlane2dOverlay.java +++ b/src/main/java/de/embl/schwab/crosshair/points/overlays/PointsToFitPlane2dOverlay.java @@ -5,7 +5,8 @@ import java.awt.*; /** - * Class for point to fit plane overlay in the 2D BigDataViewer window + * Class for points to fit plane overlay in the 2D BigDataViewer window + * There is one of these per plane displayed in Crosshair */ public class PointsToFitPlane2dOverlay extends PointOverlay2d { diff --git a/src/main/java/de/embl/schwab/crosshair/points/overlays/VertexPoints2dOverlay.java b/src/main/java/de/embl/schwab/crosshair/points/overlays/VertexPoints2dOverlay.java index f00db6b..7337cb9 100644 --- a/src/main/java/de/embl/schwab/crosshair/points/overlays/VertexPoints2dOverlay.java +++ b/src/main/java/de/embl/schwab/crosshair/points/overlays/VertexPoints2dOverlay.java @@ -11,6 +11,7 @@ /** * Class for vertex points overlay in the 2D BigDataViewer window + * There is one of these per block plane displayed in Crosshair */ public class VertexPoints2dOverlay extends PointOverlay2d { @@ -20,7 +21,7 @@ public class VertexPoints2dOverlay extends PointOverlay2d { private final Color colSelected = new Color(153, 0, 76); /** - * Create a vertex overlay + * Create a 2D vertex overlay * @param vertexDisplay vertex display */ public VertexPoints2dOverlay( VertexDisplay vertexDisplay ) { From 46bfaa39511207a5b689a85e3d6e9263a9ea2f23 Mon Sep 17 00:00:00 2001 From: Kimberly Meechan Date: Mon, 12 Feb 2024 16:30:11 +0000 Subject: [PATCH 07/13] fix dependencies in pom --- pom.xml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2ad0bc5..031d5ca 100644 --- a/pom.xml +++ b/pom.xml @@ -80,7 +80,7 @@ - 0.6.4-SNAPSHOT + 0.6.4 @@ -111,6 +111,16 @@ sc.fiji 3D_Viewer + + org.jogamp.gluegen + gluegen-rt + ${scijava.natives.classifier.gluegen} + + + org.jogamp.jogl + jogl-all + ${scijava.natives.classifier.jogl} + de.embl.cba imagej-utils From 9843b1a860b7a8dfba132d78fd6039ee9d44a398 Mon Sep 17 00:00:00 2001 From: Kimberly Meechan <24316371+K-Meech@users.noreply.github.com> Date: Sat, 15 Jun 2024 13:02:38 +0100 Subject: [PATCH 08/13] update javadoc for ui --- .../crosshair/ui/swing/CrosshairFrame.java | 12 + .../crosshair/ui/swing/ImagesPanel.java | 19 +- .../crosshair/ui/swing/MicrotomePanel.java | 10 +- .../schwab/crosshair/ui/swing/OtherPanel.java | 18 +- .../schwab/crosshair/ui/swing/PlanePanel.java | 551 +++++++++--------- .../schwab/crosshair/ui/swing/SavePanel.java | 7 + .../crosshair/ui/swing/SliderPanelDouble.java | 5 +- .../ui/swing/VertexAssignmentPanel.java | 7 + 8 files changed, 347 insertions(+), 282 deletions(-) diff --git a/src/main/java/de/embl/schwab/crosshair/ui/swing/CrosshairFrame.java b/src/main/java/de/embl/schwab/crosshair/ui/swing/CrosshairFrame.java index 9665dd6..9265093 100644 --- a/src/main/java/de/embl/schwab/crosshair/ui/swing/CrosshairFrame.java +++ b/src/main/java/de/embl/schwab/crosshair/ui/swing/CrosshairFrame.java @@ -9,6 +9,9 @@ import javax.swing.*; import java.util.ArrayList; +/** + * Class for main Crosshair UI, to hold all the various panels + */ public class CrosshairFrame extends JFrame { private Image3DUniverse universe; @@ -27,6 +30,15 @@ public class CrosshairFrame extends JFrame { private String unit; + /** + * Create the main Crosshair UI + * @param universe universe of the 3D viewer + * @param imageContent image content displayed in 3D viewer + * @param planeManager plane manager + * @param microtomeManager microtome manager + * @param bdvHandle bdvHandle of the BigDataViewer window + * @param unit pixel size unit e.g. mm + */ public CrosshairFrame(Image3DUniverse universe, Content imageContent, PlaneManager planeManager, MicrotomeManager microtomeManager, BdvHandle bdvHandle, String unit) { diff --git a/src/main/java/de/embl/schwab/crosshair/ui/swing/ImagesPanel.java b/src/main/java/de/embl/schwab/crosshair/ui/swing/ImagesPanel.java index 5c7d148..e2da221 100644 --- a/src/main/java/de/embl/schwab/crosshair/ui/swing/ImagesPanel.java +++ b/src/main/java/de/embl/schwab/crosshair/ui/swing/ImagesPanel.java @@ -14,8 +14,9 @@ import java.util.HashMap; import java.util.Map; -// similar to mobie source panel - https://github.com/mobie/mobie-viewer-fiji/blob/master/src/main/java/de/embl/cba/mobie/ui/viewer/SourcesPanel.java - +/** + * Class for UI Panel containing controls for 3D image display + */ public class ImagesPanel extends CrosshairPanel { private Map imageNameToContent; @@ -24,6 +25,12 @@ public class ImagesPanel extends CrosshairPanel { public ImagesPanel() {} + /** + * Initialise panel + * @param imageNameToContent Map of image names to their image content displayed in 3D viewer + * @param otherPanel UI panel controlling visibility of various items in the viewers + * @param universe universe of the 3D viewer + */ public void initialisePanel( Map imageNameToContent, OtherPanel otherPanel, Image3DUniverse universe ) { this.imageNameToContent = imageNameToContent; this.otherPanel = otherPanel; @@ -39,6 +46,10 @@ public void initialisePanel( Map imageNameToContent, OtherPanel } } + /** + * Initialise panel from settings in main Crosshair UI + * @param crosshairFrame main crosshair UI + */ public void initialisePanel ( CrosshairFrame crosshairFrame ) { Map imageNameToContent = new HashMap<>(); imageNameToContent.put( Crosshair.image, crosshairFrame.getImageContent() ); @@ -119,7 +130,7 @@ private void refreshGui() { this.repaint(); } - public void addTransparencyButton(JPanel panel, int[] buttonDimensions, + private void addTransparencyButton(JPanel panel, int[] buttonDimensions, String imageName ) { JButton button = new JButton("T"); button.setPreferredSize(new Dimension( @@ -168,7 +179,7 @@ public void addTransparencyButton(JPanel panel, int[] buttonDimensions, panel.add(button); } - public class TransparencyUpdateListener implements BoundedValueDouble.UpdateListener { + private class TransparencyUpdateListener implements BoundedValueDouble.UpdateListener { final private BoundedValueDouble transparencyValue; private final SliderPanelDouble transparencySlider; private final String imageName; diff --git a/src/main/java/de/embl/schwab/crosshair/ui/swing/MicrotomePanel.java b/src/main/java/de/embl/schwab/crosshair/ui/swing/MicrotomePanel.java index 0919858..93ee939 100644 --- a/src/main/java/de/embl/schwab/crosshair/ui/swing/MicrotomePanel.java +++ b/src/main/java/de/embl/schwab/crosshair/ui/swing/MicrotomePanel.java @@ -15,9 +15,9 @@ import java.awt.event.ActionListener; import java.util.*; - -// similar to mobie source panel - https://github.com/mobie/mobie-viewer-fiji/blob/master/src/main/java/de/embl/cba/mobie/ui/viewer/SourcesPanel.java - +/** + * Class for UI Panels controlling the microtome display + */ public class MicrotomePanel extends CrosshairPanel { private final String cuttingDepthString = "Cutting Depth"; @@ -70,6 +70,10 @@ public class MicrotomePanel extends CrosshairPanel { public MicrotomePanel() {} + /** + * Initialise panel from settings in main Crosshair UI + * @param crosshairFrame main crosshair UI + */ public void initialisePanel( CrosshairFrame crosshairFrame ) { this.crosshairFrame = crosshairFrame; microtomeManager = crosshairFrame.getMicrotomeManager(); diff --git a/src/main/java/de/embl/schwab/crosshair/ui/swing/OtherPanel.java b/src/main/java/de/embl/schwab/crosshair/ui/swing/OtherPanel.java index 3eacbf0..a0c72be 100644 --- a/src/main/java/de/embl/schwab/crosshair/ui/swing/OtherPanel.java +++ b/src/main/java/de/embl/schwab/crosshair/ui/swing/OtherPanel.java @@ -11,8 +11,9 @@ import java.awt.Dimension; import java.util.ArrayList; -// similar to mobie source panel - https://github.com/mobie/mobie-viewer-fiji/blob/master/src/main/java/de/embl/cba/mobie/ui/viewer/SourcesPanel.java - +/** + * Class for UI Panel containing controls for visibility of various items + */ public class OtherPanel extends CrosshairPanel { private ArrayList imageContents; @@ -24,6 +25,15 @@ public class OtherPanel extends CrosshairPanel { public OtherPanel() {} + /** + * Initialise panel + * @param imageContents image contents displayed in 3D viewer + * @param universe universe of the 3D viewer + * @param planeManager plane manager + * @param bdvHandle bdvHandle of the BigDataViewer window + * @param includeMicrotomeButtons whether to include buttons to control visibility of microtome pieces in + * the 3D viewer + */ public void initialisePanel( ArrayList imageContents, Image3DUniverse universe, PlaneManager planeManager, BdvHandle bdvHandle, boolean includeMicrotomeButtons ) { @@ -51,6 +61,10 @@ public void initialisePanel( ArrayList imageContents, Image3DUniverse u } } + /** + * Initialise panel from settings in main Crosshair UI + * @param crosshairFrame main crosshair UI + */ public void initialisePanel( CrosshairFrame crosshairFrame ) { ArrayList imageContents = new ArrayList<>(); imageContents.add( crosshairFrame.getImageContent() ); diff --git a/src/main/java/de/embl/schwab/crosshair/ui/swing/PlanePanel.java b/src/main/java/de/embl/schwab/crosshair/ui/swing/PlanePanel.java index b00ab8b..968587f 100644 --- a/src/main/java/de/embl/schwab/crosshair/ui/swing/PlanePanel.java +++ b/src/main/java/de/embl/schwab/crosshair/ui/swing/PlanePanel.java @@ -17,343 +17,354 @@ import java.util.List; import java.util.Map; -// similar to mobie source panel - https://github.com/mobie/mobie-viewer-fiji/blob/master/src/main/java/de/embl/cba/mobie/ui/viewer/SourcesPanel.java - - public class PlanePanel extends CrosshairPanel { - - private PlaneManager planeManager; - private Map trackingButtons; - private Map goToButtons; - private Map> planeNameToButtonsAffectedByTracking; - private List planeNames; - private List blockPlaneNames; - - public PlanePanel() {} - - public void initialisePanel( PlaneManager planeManager, List planeNames, List blockPlaneNames ) { - this.planeManager = planeManager; - trackingButtons = new HashMap<>(); - goToButtons = new HashMap<>(); - planeNameToButtonsAffectedByTracking = new HashMap<>(); - this.planeNames = planeNames; - this.blockPlaneNames = blockPlaneNames; - - setBorder(BorderFactory.createCompoundBorder( - BorderFactory.createTitledBorder("Planes"), - BorderFactory.createEmptyBorder(5,5,5,5))); - - setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); - for ( String planeName: planeNames ) { - addPlaneToPanel( planeName ); - } - for ( String planeName: blockPlaneNames ) { - addPlaneToPanel( planeName ); - } +/** + * Class for UI Panel containing controls for plane display + */ +public class PlanePanel extends CrosshairPanel { + + private PlaneManager planeManager; + private Map trackingButtons; + private Map goToButtons; + private Map> planeNameToButtonsAffectedByTracking; + private List planeNames; + private List blockPlaneNames; + + public PlanePanel() {} + + /** + * Initialise panel + * @param planeManager plane manager + * @param planeNames names of planes to display + * @param blockPlaneNames names of block planes to display + */ + public void initialisePanel( PlaneManager planeManager, List planeNames, List blockPlaneNames ) { + this.planeManager = planeManager; + trackingButtons = new HashMap<>(); + goToButtons = new HashMap<>(); + planeNameToButtonsAffectedByTracking = new HashMap<>(); + this.planeNames = planeNames; + this.blockPlaneNames = blockPlaneNames; + + setBorder(BorderFactory.createCompoundBorder( + BorderFactory.createTitledBorder("Planes"), + BorderFactory.createEmptyBorder(5,5,5,5))); + + setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); + for ( String planeName: planeNames ) { + addPlaneToPanel( planeName ); } - - public void initialisePanel( CrosshairFrame crosshairFrame ) { - ArrayList planeNames = new ArrayList<>(); - planeNames.add( Crosshair.target ); - ArrayList blockPlaneNames = new ArrayList<>(); - blockPlaneNames.add( Crosshair.block ); - initialisePanel( crosshairFrame.getPlaneManager(), planeNames, blockPlaneNames ); + for ( String planeName: blockPlaneNames ) { + addPlaneToPanel( planeName ); } + } - private void addColorButton(JPanel panel, int[] buttonDimensions, String planeName) { - JButton colorButton; - colorButton = new JButton("C"); + /** + * Initialise panel from settings in main Crosshair UI + * @param crosshairFrame main crosshair UI + */ + public void initialisePanel( CrosshairFrame crosshairFrame ) { + ArrayList planeNames = new ArrayList<>(); + planeNames.add( Crosshair.target ); + ArrayList blockPlaneNames = new ArrayList<>(); + blockPlaneNames.add( Crosshair.block ); + initialisePanel( crosshairFrame.getPlaneManager(), planeNames, blockPlaneNames ); + } - colorButton.setPreferredSize( - new Dimension(buttonDimensions[0], buttonDimensions[1])); + private void addColorButton(JPanel panel, int[] buttonDimensions, String planeName) { + JButton colorButton; + colorButton = new JButton("C"); - colorButton.addActionListener(e -> { - Color colour = JColorChooser.showDialog(null, "", null); + colorButton.setPreferredSize( + new Dimension(buttonDimensions[0], buttonDimensions[1])); - if (colour == null) return; + colorButton.addActionListener(e -> { + Color colour = JColorChooser.showDialog(null, "", null); - if ( planeManager.checkNamedPlaneExists( planeName ) ) { - planeManager.getPlane( planeName ).setColor( colour ); - } else { - IJ.log( planeName + " plane not initialised" ); - } + if (colour == null) return; - }); + if ( planeManager.checkNamedPlaneExists( planeName ) ) { + planeManager.getPlane( planeName ).setColor( colour ); + } else { + IJ.log( planeName + " plane not initialised" ); + } - addButtonAffectedByTracking( planeName, colorButton ); - panel.add(colorButton); - } + }); - private void addGOTOButton(JPanel panel, int[] buttonDimensions, String planeName) { - JButton goToButton; - goToButton = new JButton("GO TO"); + addButtonAffectedByTracking( planeName, colorButton ); + panel.add(colorButton); + } - goToButton.setPreferredSize( - new Dimension(2*buttonDimensions[0], buttonDimensions[1])); + private void addGOTOButton(JPanel panel, int[] buttonDimensions, String planeName) { + JButton goToButton; + goToButton = new JButton("GO TO"); - goToButton.addActionListener(e -> { - if (planeManager.checkNamedPlaneExistsAndOrientationIsSet(planeName)) { - planeManager.moveViewToNamedPlane(planeName); - } else { - IJ.log("Plane not initialised"); - } - }); + goToButton.setPreferredSize( + new Dimension(2*buttonDimensions[0], buttonDimensions[1])); - goToButtons.put( planeName, goToButton ); - panel.add(goToButton); - } + goToButton.addActionListener(e -> { + if (planeManager.checkNamedPlaneExistsAndOrientationIsSet(planeName)) { + planeManager.moveViewToNamedPlane(planeName); + } else { + IJ.log("Plane not initialised"); + } + }); - private void addTrackingButton(JPanel panel, int[] buttonDimensions, String planeName) { - JButton trackButton; - trackButton = new JButton("TRACK"); + goToButtons.put( planeName, goToButton ); + panel.add(goToButton); + } - trackButton.setPreferredSize( - new Dimension(2*buttonDimensions[0], buttonDimensions[1])); + private void addTrackingButton(JPanel panel, int[] buttonDimensions, String planeName) { + JButton trackButton; + trackButton = new JButton("TRACK"); - trackButton.addActionListener(e -> { - toggleTracking( trackButton, planeName ); - }); + trackButton.setPreferredSize( + new Dimension(2*buttonDimensions[0], buttonDimensions[1])); - trackingButtons.put(planeName, trackButton); - panel.add(trackButton); - } + trackButton.addActionListener(e -> { + toggleTracking( trackButton, planeName ); + }); - private void disableButtonsAffectedByTracking( String planeName ) { - for ( JButton button : planeNameToButtonsAffectedByTracking.get( planeName ) ) { - button.setEnabled(false); - } + trackingButtons.put(planeName, trackButton); + panel.add(trackButton); + } + + private void disableButtonsAffectedByTracking( String planeName ) { + for ( JButton button : planeNameToButtonsAffectedByTracking.get( planeName ) ) { + button.setEnabled(false); } + } - private void enableButtonsAffectedByTracking( String planeName ) { - for ( JButton button : planeNameToButtonsAffectedByTracking.get( planeName ) ) { - button.setEnabled(true); - } + private void enableButtonsAffectedByTracking( String planeName ) { + for ( JButton button : planeNameToButtonsAffectedByTracking.get( planeName ) ) { + button.setEnabled(true); } + } + + private void toggleTracking( JButton trackButton, String planeName ) { + if ( !planeManager.isTrackingPlane() ) { + if ( planeManager.checkNamedPlaneExists( planeName ) ) { - private void toggleTracking( JButton trackButton, String planeName ) { - if ( !planeManager.isTrackingPlane() ) { - if ( planeManager.checkNamedPlaneExists( planeName ) ) { - - // check if there are already vertex points - Plane plane = planeManager.getPlane(planeName); - if (plane instanceof BlockPlane && ((BlockPlane) plane).getVertexDisplay().getVertices().size() > 0) { - int result = JOptionPane.showConfirmDialog(null, "If you track a block plane, you will lose all current vertex points. Continue?", "Are you sure?", - JOptionPane.YES_NO_OPTION, - JOptionPane.QUESTION_MESSAGE); - if (result == JOptionPane.YES_OPTION) { - ((BlockPlane) plane).getVertexDisplay().removeAllVertices(); - enablePlaneTracking(trackButton, planeName); - } - } else { + // check if there are already vertex points + Plane plane = planeManager.getPlane(planeName); + if (plane instanceof BlockPlane && ((BlockPlane) plane).getVertexDisplay().getVertices().size() > 0) { + int result = JOptionPane.showConfirmDialog(null, "If you track a block plane, you will lose all current vertex points. Continue?", "Are you sure?", + JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE); + if (result == JOptionPane.YES_OPTION) { + ((BlockPlane) plane).getVertexDisplay().removeAllVertices(); enablePlaneTracking(trackButton, planeName); } } else { - enablePlaneTracking( trackButton, planeName ); + enablePlaneTracking(trackButton, planeName); } - } else if ( planeManager.getTrackedPlaneName().equals( planeName ) ) { - disablePlaneTracking( trackButton, planeName ); + } else { + enablePlaneTracking( trackButton, planeName ); } + } else if ( planeManager.getTrackedPlaneName().equals( planeName ) ) { + disablePlaneTracking( trackButton, planeName ); } + } - private void enablePlaneTracking( JButton trackButton, String planeName ) { - planeManager.setTrackingPlane( true ); - planeManager.setTrackedPlaneName( planeName ); + private void enablePlaneTracking( JButton trackButton, String planeName ) { + planeManager.setTrackingPlane( true ); + planeManager.setTrackedPlaneName( planeName ); - if ( planeManager.checkNamedPlaneExists( planeName ) ) { - planeManager.updatePlaneCurrentView(planeName); + if ( planeManager.checkNamedPlaneExists( planeName ) ) { + planeManager.updatePlaneCurrentView(planeName); + } else { + if ( blockPlaneNames.contains( planeName ) ) { + planeManager.addBlockPlaneAtCurrentView( planeName ); } else { - if ( blockPlaneNames.contains( planeName ) ) { - planeManager.addBlockPlaneAtCurrentView( planeName ); - } else { - planeManager.addPlaneAtCurrentView( planeName ); - } + planeManager.addPlaneAtCurrentView( planeName ); } - planeManager.getPlane(planeName).setVisible(true); - trackButton.setBackground(new Color (255, 0,0)); - disableButtonsAffectedByTracking( planeName ); - disableAllTrackingButtonsExceptNamed( planeName ); - disableAllGoToButtons(); - } - - private void disablePlaneTracking( JButton trackButton, String planeName ) { - planeManager.setTrackingPlane( false ); - trackButton.setBackground(null); - enableButtonsAffectedByTracking( planeName ); - enableAllTrackingButtons(); - enableAllGoToButtons(); } + planeManager.getPlane(planeName).setVisible(true); + trackButton.setBackground(new Color (255, 0,0)); + disableButtonsAffectedByTracking( planeName ); + disableAllTrackingButtonsExceptNamed( planeName ); + disableAllGoToButtons(); + } - private void addVisibilityButton (JPanel panel, int[] buttonDimensions, String planeName) { - JButton visbilityButton; - visbilityButton = new JButton("V"); - - visbilityButton.setPreferredSize( - new Dimension(buttonDimensions[0], buttonDimensions[1])); + private void disablePlaneTracking( JButton trackButton, String planeName ) { + planeManager.setTrackingPlane( false ); + trackButton.setBackground(null); + enableButtonsAffectedByTracking( planeName ); + enableAllTrackingButtons(); + enableAllGoToButtons(); + } - visbilityButton.addActionListener(e -> { - if ( planeManager.checkNamedPlaneExists( planeName ) ) { - planeManager.getPlane( planeName ).toggleVisible(); - } else { - IJ.log(planeName + " plane not initialised" ); - } - }); + private void addVisibilityButton (JPanel panel, int[] buttonDimensions, String planeName) { + JButton visbilityButton; + visbilityButton = new JButton("V"); - addButtonAffectedByTracking( planeName, visbilityButton ); - panel.add(visbilityButton); - } + visbilityButton.setPreferredSize( + new Dimension(buttonDimensions[0], buttonDimensions[1])); - private void addPlaneToPanel(String planeName) { + visbilityButton.addActionListener(e -> { + if ( planeManager.checkNamedPlaneExists( planeName ) ) { + planeManager.getPlane( planeName ).toggleVisible(); + } else { + IJ.log(planeName + " plane not initialised" ); + } + }); - JPanel panel = new JPanel(); - panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS)); - panel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); - panel.add(Box.createHorizontalGlue()); + addButtonAffectedByTracking( planeName, visbilityButton ); + panel.add(visbilityButton); + } - JLabel sourceNameLabel = new JLabel(planeName); - sourceNameLabel.setHorizontalAlignment(SwingUtilities.CENTER); + private void addPlaneToPanel(String planeName) { - int[] buttonDimensions = new int[]{50, 30}; + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS)); + panel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); + panel.add(Box.createHorizontalGlue()); - panel.add(sourceNameLabel); + JLabel sourceNameLabel = new JLabel(planeName); + sourceNameLabel.setHorizontalAlignment(SwingUtilities.CENTER); - addColorButton(panel, buttonDimensions, planeName); - addTransparencyButton(panel, buttonDimensions, planeName); - addVisibilityButton(panel, buttonDimensions, planeName); - addTrackingButton(panel, buttonDimensions, planeName); - addGOTOButton(panel, buttonDimensions, planeName); + int[] buttonDimensions = new int[]{50, 30}; - add(panel); - refreshGui(); - } + panel.add(sourceNameLabel); - private void refreshGui() { - this.revalidate(); - this.repaint(); - } + addColorButton(panel, buttonDimensions, planeName); + addTransparencyButton(panel, buttonDimensions, planeName); + addVisibilityButton(panel, buttonDimensions, planeName); + addTrackingButton(panel, buttonDimensions, planeName); + addGOTOButton(panel, buttonDimensions, planeName); + add(panel); + refreshGui(); + } - public void addTransparencyButton(JPanel panel, int[] buttonDimensions, - String planeName) { - JButton button = new JButton("T"); - button.setPreferredSize(new Dimension( - buttonDimensions[0], - buttonDimensions[1])); + private void refreshGui() { + this.revalidate(); + this.repaint(); + } - button.addActionListener(e -> - { - JFrame frame = new JFrame("Transparency"); - frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - float currentTransparency = 0.7f; - if ( planeManager.checkNamedPlaneExists( planeName ) ) { - currentTransparency = planeManager.getPlane( planeName ).getTransparency(); - } else { - IJ.log(planeName + " plane not initialised"); - } + private void addTransparencyButton(JPanel panel, int[] buttonDimensions, + String planeName) { + JButton button = new JButton("T"); + button.setPreferredSize(new Dimension( + buttonDimensions[0], + buttonDimensions[1])); - // as here https://github.com/K-Meech/crosshair/blob/b7bdece786c1593969ec469916adf9737a7768bb/src/main/java/de/embl/cba/bdv/utils/BdvDialogs.java - final BoundedValueDouble transparencyValue = - new BoundedValueDouble( - 0, - 1, - currentTransparency); - - double spinnerStepSize = 0.1; - - JPanel transparencyPanel = new JPanel(); - transparencyPanel.setLayout(new BoxLayout(transparencyPanel, BoxLayout.PAGE_AXIS)); - final SliderPanelDouble transparencySlider = new SliderPanelDouble("Transparency", transparencyValue, spinnerStepSize); - transparencySlider.setNumColummns(7); - transparencySlider.setDecimalFormat("####E0"); - transparencyValue.setUpdateListener(new TransparencyUpdateListener(transparencyValue, - transparencySlider, planeName, planeManager)); - - transparencyPanel.add(transparencySlider); - frame.setContentPane(transparencyPanel); - - //Display the window. - frame.setBounds(MouseInfo.getPointerInfo().getLocation().x, - MouseInfo.getPointerInfo().getLocation().y, - 120, 10); - frame.setResizable(false); - frame.pack(); - frame.setVisible(true); - }); - - addButtonAffectedByTracking( planeName, button ); - panel.add(button); - } + button.addActionListener(e -> + { + JFrame frame = new JFrame("Transparency"); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - public void addButtonAffectedByTracking( String planeName, JButton button ) { - if ( !planeNameToButtonsAffectedByTracking.containsKey( planeName ) ) { - ArrayList buttons = new ArrayList<>(); - buttons.add(button); - planeNameToButtonsAffectedByTracking.put( planeName, buttons ); + float currentTransparency = 0.7f; + if ( planeManager.checkNamedPlaneExists( planeName ) ) { + currentTransparency = planeManager.getPlane( planeName ).getTransparency(); } else { - planeNameToButtonsAffectedByTracking.get( planeName ).add( button ); + IJ.log(planeName + " plane not initialised"); } - } - public void disableAllTrackingButtons() { - for ( JButton button: trackingButtons.values() ) { - button.setEnabled( false ); - } + // as here https://github.com/K-Meech/crosshair/blob/b7bdece786c1593969ec469916adf9737a7768bb/src/main/java/de/embl/cba/bdv/utils/BdvDialogs.java + final BoundedValueDouble transparencyValue = + new BoundedValueDouble( + 0, + 1, + currentTransparency); + + double spinnerStepSize = 0.1; + + JPanel transparencyPanel = new JPanel(); + transparencyPanel.setLayout(new BoxLayout(transparencyPanel, BoxLayout.PAGE_AXIS)); + final SliderPanelDouble transparencySlider = new SliderPanelDouble("Transparency", transparencyValue, spinnerStepSize); + transparencySlider.setNumColummns(7); + transparencySlider.setDecimalFormat("####E0"); + transparencyValue.setUpdateListener(new TransparencyUpdateListener(transparencyValue, + transparencySlider, planeName, planeManager)); + + transparencyPanel.add(transparencySlider); + frame.setContentPane(transparencyPanel); + + //Display the window. + frame.setBounds(MouseInfo.getPointerInfo().getLocation().x, + MouseInfo.getPointerInfo().getLocation().y, + 120, 10); + frame.setResizable(false); + frame.pack(); + frame.setVisible(true); + }); + + addButtonAffectedByTracking( planeName, button ); + panel.add(button); + } + + public void addButtonAffectedByTracking( String planeName, JButton button ) { + if ( !planeNameToButtonsAffectedByTracking.containsKey( planeName ) ) { + ArrayList buttons = new ArrayList<>(); + buttons.add(button); + planeNameToButtonsAffectedByTracking.put( planeName, buttons ); + } else { + planeNameToButtonsAffectedByTracking.get( planeName ).add( button ); } + } - public void disableAllTrackingButtonsExceptNamed( String planeName ) { - for (String key : trackingButtons.keySet()) { - if ( !key.equals(planeName) ) { - trackingButtons.get(key).setEnabled(false); - } - } + public void disableAllTrackingButtons() { + for ( JButton button: trackingButtons.values() ) { + button.setEnabled( false ); } + } - public void enableAllTrackingButtons() { - for ( JButton button: trackingButtons.values() ) { - button.setEnabled( true ); + private void disableAllTrackingButtonsExceptNamed( String planeName ) { + for (String key : trackingButtons.keySet()) { + if ( !key.equals(planeName) ) { + trackingButtons.get(key).setEnabled(false); } } + } - public Map getTrackingButtons() { - return trackingButtons; + public void enableAllTrackingButtons() { + for ( JButton button: trackingButtons.values() ) { + button.setEnabled( true ); } + } - public void enableAllGoToButtons() { - for ( JButton button: goToButtons.values() ) { - button.setEnabled( true ); - } + public Map getTrackingButtons() { + return trackingButtons; + } + + private void enableAllGoToButtons() { + for ( JButton button: goToButtons.values() ) { + button.setEnabled( true ); } + } - public void disableAllGoToButtons() { - for ( JButton button: goToButtons.values() ) { - button.setEnabled( false ); - } + private void disableAllGoToButtons() { + for ( JButton button: goToButtons.values() ) { + button.setEnabled( false ); } + } - public class TransparencyUpdateListener implements BoundedValueDouble.UpdateListener { - final private BoundedValueDouble transparencyValue; - private final SliderPanelDouble transparencySlider; - private final String planeName; - PlaneManager planeManager; - - public TransparencyUpdateListener(BoundedValueDouble transparencyValue, - SliderPanelDouble transparencySlider, - String planeName, - PlaneManager planeManager) { - this.transparencyValue = transparencyValue; - this.transparencySlider = transparencySlider; - this.planeName = planeName; - this.planeManager = planeManager; - } + private class TransparencyUpdateListener implements BoundedValueDouble.UpdateListener { + final private BoundedValueDouble transparencyValue; + private final SliderPanelDouble transparencySlider; + private final String planeName; + PlaneManager planeManager; + + public TransparencyUpdateListener(BoundedValueDouble transparencyValue, + SliderPanelDouble transparencySlider, + String planeName, + PlaneManager planeManager) { + this.transparencyValue = transparencyValue; + this.transparencySlider = transparencySlider; + this.planeName = planeName; + this.planeManager = planeManager; + } - @Override - public void update() { - transparencySlider.update(); - if ( planeManager.checkNamedPlaneExists( planeName ) ) { - planeManager.getPlane( planeName ).setTransparency( (float) transparencyValue.getCurrentValue() ); - } else { - IJ.log(planeName + " plane not initialised"); - } + @Override + public void update() { + transparencySlider.update(); + if ( planeManager.checkNamedPlaneExists( planeName ) ) { + planeManager.getPlane( planeName ).setTransparency( (float) transparencyValue.getCurrentValue() ); + } else { + IJ.log(planeName + " plane not initialised"); } } - } + +} diff --git a/src/main/java/de/embl/schwab/crosshair/ui/swing/SavePanel.java b/src/main/java/de/embl/schwab/crosshair/ui/swing/SavePanel.java index 9734833..fb96c6d 100644 --- a/src/main/java/de/embl/schwab/crosshair/ui/swing/SavePanel.java +++ b/src/main/java/de/embl/schwab/crosshair/ui/swing/SavePanel.java @@ -18,6 +18,9 @@ import static de.embl.schwab.crosshair.io.IoHelper.chooseOpenFilePath; import static de.embl.schwab.crosshair.io.IoHelper.chooseSaveFilePath; +/** + * Class for UI Panel controlling saving/loading of settings and solutions + */ public class SavePanel extends CrosshairPanel { private PlaneManager planeManager; private MicrotomeManager microtomeManager; @@ -33,6 +36,10 @@ public class SavePanel extends CrosshairPanel { public SavePanel() {} + /** + * Initialise panel from settings in main Crosshair UI + * @param crosshairFrame main crosshair UI + */ public void initialisePanel( CrosshairFrame crosshairFrame ) { this.crosshairFrame = crosshairFrame; this.planeManager = crosshairFrame.getPlaneManager(); diff --git a/src/main/java/de/embl/schwab/crosshair/ui/swing/SliderPanelDouble.java b/src/main/java/de/embl/schwab/crosshair/ui/swing/SliderPanelDouble.java index 2f17907..78f6756 100644 --- a/src/main/java/de/embl/schwab/crosshair/ui/swing/SliderPanelDouble.java +++ b/src/main/java/de/embl/schwab/crosshair/ui/swing/SliderPanelDouble.java @@ -29,8 +29,6 @@ * #L% */ -// from bdv.tools.brightness with added method to commit spinner edits explicitly - import java.awt.BorderLayout; import java.awt.Component; import java.awt.event.ComponentAdapter; @@ -52,7 +50,8 @@ /** * A {@link JSlider} with a {@link JSpinner} next to it, both modifying the same - * {@link BoundedValue value}. + * {@link BoundedValue value}. This is copied from bdv.tools.brightness with an added method to commit spinner edits + * explicitly. */ public class SliderPanelDouble extends JPanel implements BoundedValueDouble.UpdateListener { diff --git a/src/main/java/de/embl/schwab/crosshair/ui/swing/VertexAssignmentPanel.java b/src/main/java/de/embl/schwab/crosshair/ui/swing/VertexAssignmentPanel.java index d8670ba..2fa2cf8 100644 --- a/src/main/java/de/embl/schwab/crosshair/ui/swing/VertexAssignmentPanel.java +++ b/src/main/java/de/embl/schwab/crosshair/ui/swing/VertexAssignmentPanel.java @@ -11,6 +11,9 @@ import java.util.HashMap; import java.util.Map; +/** + * Class for UI Panel allowing assignment of vertices as top left / top right etc... + */ public class VertexAssignmentPanel extends CrosshairPanel { private PlaneManager planeManager; @@ -19,6 +22,10 @@ public class VertexAssignmentPanel extends CrosshairPanel { public VertexAssignmentPanel() {} + /** + * Initialise panel from settings in main Crosshair UI + * @param crosshairFrame main crosshair UI + */ public void initialisePanel ( CrosshairFrame crosshairFrame ) { this.crosshairFrame = crosshairFrame; this.planeManager = crosshairFrame.getPlaneManager(); From b06e08dafc19bd68b0e50a288df197e4ff578b32 Mon Sep 17 00:00:00 2001 From: Kimberly Meechan <24316371+K-Meech@users.noreply.github.com> Date: Sat, 15 Jun 2024 13:10:23 +0100 Subject: [PATCH 09/13] fix tracking button colour --- .../java/de/embl/schwab/crosshair/ui/swing/PlanePanel.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/embl/schwab/crosshair/ui/swing/PlanePanel.java b/src/main/java/de/embl/schwab/crosshair/ui/swing/PlanePanel.java index 968587f..800728f 100644 --- a/src/main/java/de/embl/schwab/crosshair/ui/swing/PlanePanel.java +++ b/src/main/java/de/embl/schwab/crosshair/ui/swing/PlanePanel.java @@ -28,6 +28,7 @@ public class PlanePanel extends CrosshairPanel { private Map> planeNameToButtonsAffectedByTracking; private List planeNames; private List blockPlaneNames; + private Color defaultButtonColour; public PlanePanel() {} @@ -123,6 +124,7 @@ private void addTrackingButton(JPanel panel, int[] buttonDimensions, String plan trackButton.addActionListener(e -> { toggleTracking( trackButton, planeName ); }); + defaultButtonColour = trackButton.getBackground(); trackingButtons.put(planeName, trackButton); panel.add(trackButton); @@ -187,7 +189,7 @@ private void enablePlaneTracking( JButton trackButton, String planeName ) { private void disablePlaneTracking( JButton trackButton, String planeName ) { planeManager.setTrackingPlane( false ); - trackButton.setBackground(null); + trackButton.setBackground(defaultButtonColour); enableButtonsAffectedByTracking( planeName ); enableAllTrackingButtons(); enableAllGoToButtons(); From c5d7cc38d87c5bafd0c671cade15d8d37f856f8b Mon Sep 17 00:00:00 2001 From: Kimberly Meechan <24316371+K-Meech@users.noreply.github.com> Date: Sat, 15 Jun 2024 21:31:04 +0100 Subject: [PATCH 10/13] improve mesh topology and rendering --- .../crosshair/microtome/MicrotomeSetup.java | 10 ++++++++++ src/main/resources/arc.stl | Bin 2884 -> 2684 bytes src/main/resources/holder_back.stl | Bin 684 -> 684 bytes src/main/resources/holder_front.stl | Bin 6284 -> 6284 bytes src/main/resources/knife.stl | Bin 884 -> 484 bytes 5 files changed, 10 insertions(+) diff --git a/src/main/java/de/embl/schwab/crosshair/microtome/MicrotomeSetup.java b/src/main/java/de/embl/schwab/crosshair/microtome/MicrotomeSetup.java index 4270c6e..76bbf3a 100644 --- a/src/main/java/de/embl/schwab/crosshair/microtome/MicrotomeSetup.java +++ b/src/main/java/de/embl/schwab/crosshair/microtome/MicrotomeSetup.java @@ -18,6 +18,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import org.scijava.java3d.PolygonAttributes; import static java.lang.Math.abs; @@ -56,8 +57,17 @@ private void loadMicrotomeMeshes() { String[] stlFiles = {"/arc.stl", "/holder_back.stl", "/holder_front.stl", "/knife.stl"}; for (String file: stlFiles) { Map currentStl = STLResourceLoader.loadSTL(file); + // in case there are multiple objects in single stl file for (String key : currentStl.keySet()) { + CustomMesh mesh = currentStl.get(key); + + // In later versions of the 3D viewer, meshes were rendering strangely with certain faces appearing + // transparent from certain angles. Setting the back face normal flip and cull face + // (as in this issue - https://github.com/fiji/3D_Viewer/issues/23) improves this greatly. + mesh.getAppearance().getPolygonAttributes().setBackFaceNormalFlip(false); + mesh.getAppearance().getPolygonAttributes().setCullFace(PolygonAttributes.CULL_BACK); + mesh.setTransparency(0); microtomeSTLs.put(key, currentStl.get(key)); } } diff --git a/src/main/resources/arc.stl b/src/main/resources/arc.stl index 76911af4cdee01c66e65992e4a5c637024cedde1..f00202da3d5b1ebb29b8bf166bb8a375cab2cab1 100644 GIT binary patch literal 2684 zcmb`JO-NKx6vuCv6r)H^V!Nnx6O!c2U{Eyg1&K|IR^h@3(~yL$kdzQ%n2iXUC5{vY zn!yl)qRo4{YUaI4hla4wW}&9xRtORmA`G%~?tOPWZ|2!5SBH7$chCQP-791N_s?e? z=h|*nP7e*)7gfuNP$A^8e|W$TO8gC=_j;mQ0VRgCfiNZ^zqKFJiiqJv zP%o&0-$sO@kVjALhM#_+1lpKWVr0RJu@@n|@FZ!Ys*v*ZWR0Ht@V5RHz7#L@s?phU zh2}(K3nJBAu7_71*a+%{bg;ck&1)I8RNb8kDsN)R^RzxR2F7M=Se^gyTw}~v8Ln_5 zs2A9VMR*t+oywnVtY0){bDGQrILlSmsZQuI-gC6aEnD`V_ajsX#3u(rdO>x0t#Eoc z!R|mFfp{`bCl2yR&#PV4U}ZS!L{Kl96R)nhc*(6bE}!wzTA_`-(V#cjbF8k*s&2@9 zT-2f6?>=H9s2AFFu0mEej6v6ob~wx1GHTmF{9RT-s1o^S6VeL_S!u?;RQbH_?N)Oi z>^YqVs*2{s*ypNA4T(Q5>;(0~TFD8utHN_p3GM;Smd5)xAuEam=J8sO!R(fGY(?+Q z1kFe+8K==RRKX;UgMn`i`da6vhPAS0m+zq5 zBD!5X59JCFZ5aghLR(gZu?TEbGpMSG^Bqh_r>by{55tVPK9yVZ;Y3g`sFi=0cw5)+ z9Zb}lDRJ+nt4Mo5XMwTs$4B}zAiif1)C+A{5ix@oVQW)4O$yBrW5{gn9UPy^_gw~J z-hq&P&W_OwstT`d`0*~G`$27_@m^tU6*BJwBG-YCUi4NHdE~*gSHSy0s|ZTcJ%Ieu zySX<(y{K9~CA^Qv50u(&2GMhV*LrCG1yK@kYcm|nx1P_L|hz>N~p56!uBdM?xl_EEfj**8OJpkI$fj@k(7MdJxo z7^7?Ks_k{A1dS(%9CkzhReaV)P%o%%`ac{&oPyhDy>rt;Go%xas^rTch-x6T41#*0 IEvwGhU;7=ecK`qY literal 2884 zcmb7`e@K;Q6vrR1A8N}ATZ_TyLbVlrK^9pwOHht9)@x8xU{jcBlbad^F zX2U<68u=w>GO1K=_@}WRKiQ$Q9h)WlVEei7HLKVZDJfv=}*&#Y0oS`r^1Q)`5NFtfB^g8}It!=%L(05$foEtJomD zP=YGI|JQYjWep}yw?2%ahi%Tvx-@MtoxPk)J^Otc0}r^+Wm99>{}t4NIg*7Z+hv4?rM#$xf5|z z$J{x?HM1Sz%eV5y^H=HWOeJ0zPd8CD?CSuh{st`S>hb!58ZdOJX=a(+s5I_Po zh<0uX)`*&KG~OK=|G)~MhbnjGoNYaiLe%Wu6J!fLZ1YU~7#}v-*1IVLf8QQm8}Jf3 zinaAw5aMFV#-ZPrxa;s{=+26{tO6^*eb_$AkNUD~SfzQ9%=h9VNoKiLfRiXa>ziGJ{wx zO|5hRS5j(x_Ico}Rc79!caSr|v!u_MyN*X+&?6;oNl;+j=D-J}#RHO=cYBTgF-Uzk6j6F-64d`tz#Bej+CRh0vLx zwo)Y(C-aZcew-_{>u~Nqin8~g@5I4>j_I>Nw@C5l>k~~x93TQc_&Vd>Nafdv_>6kx zCG-xmp07NK|LWFsq)c`qXv5TWN_vDzl~SYwo->i&jt??G43HS3bmDb32Da= AFaQ7m diff --git a/src/main/resources/holder_back.stl b/src/main/resources/holder_back.stl index 3a8c4ef68222726d8709ded066cf8b041351c396..5381fc6795756185608808fb760a3518b63e9258 100644 GIT binary patch literal 684 zcmb`Eu@%BF5JRs?$0*DYGfx(vy+u+`Qq#v9WCuEGCLlUTMt(`CNTrv%Z%MYqLb?TJj8!Rwgk6u5_Ll)ne^~jw?eOeeGpza-w@owNz~Z&TnICr zh(@O-)iJ^BLX=eSN$^=FydTXT9=x~6;|Bz@EAjP+F7S{f)bL}E-$dOKVnV9Y0YW^Y Shx%!cN<{OWS3{3_BW5287w^{q literal 684 zcmZ>*D9A4=Nlj5mE6UGRaLP%|OGz!#HPSP;RM03cO;Rw>WFQIf09F70U%wxwseCi* z{*~vl9CQ}G*oVZn1F=6noC^}S!_)zjK~jaRdmqg7273?-T@{jUdl(x-2V4fI8^#9P z0o4Jt1LzO1`A|EMRl(RGf7nC)2k{4r4wwv*Dv%v8-3Whx!wV<_3oDShFg92REDYiP zfa!qQj;snoKyjFTsICI( PfXg763(^e>E1(Vl1W*B8 diff --git a/src/main/resources/holder_front.stl b/src/main/resources/holder_front.stl index 74c6a5a33126921c038307ba431f8ee59e391fdf..5911e2b3f7bc81935e8ef01e91b0f522d3315ade 100644 GIT binary patch literal 6284 zcmb`Le@sPrO#y|J|+NpjXC-=W%wy&d_L?yYTtb zF(EFO=kPqWz?pj++v~dHCeltWeOkfsP%hyqy>jc;F-JDYAy^%WW(Q>RlCfc}xM!y*%8743b zt0kI!sKkkH%TMuee%{w=JqC^^Vxo>91 z@lXV2VYNgr^K((X!0WwJITf9HiTj`XirR8kh&FBxYxEQ1c4b}f?GS-kSS?W>KNkn@ zu8YjS*W7>j#3}3X=AzoPHtrj&(NBo|OgtPSFbk_CT7Rj=`DnbMkcW3OyW4tvSe%vC z#y!khyv0w5yFZi_9t{zgh1C*mytu)cb!4oNhqrX3&3aT{See$w-NIVD#V<2~Sy(O6 z3$scc9YFaB!Bjz*z^brXqNTT*`xDoPPxAiZZ!WIoJ<9GMUX|5$|4@EJ&oS}EjnnrL zSQS=F^w3Cy7p!o94b=Gaqgh_y@$tNFPqeWb{fOo<(K2wpH%wp_R!j8t?lJ4ZyMe#= z>PqYJ<+V0Xv~dHCelrAx3CzN3iT*Cm^@HoUGN;sU9I3M&O~>jz(Z&rl`ppm&CNK-D zC3@^oiC?rWzleu_XJ4!J`22Xn6K&kjSfd}&BTNK+wIoDf7FJ7it*OFaKRH>*!|U1H zWjz)TW~a4ri&&#yW&*RYS}x~qmERLzSlAP9_sR!S)+296N55#}KFwOZ#ZQRtczYoa zMPL?IYj*=bdx00(QaKf@;nw4W1370z8~1J2=qE&VWnH8?L|_(HOLUT-i(M1zdQ z#`ne>`gp`fvb(Lvr^Q)mZQL`gWe#QDgvc8$>+?edX5p*{eIEQJ?X}KpnzLxxH z0wd>!vTcRso4V4oP-bUA6F66RwR(1ik*Y9)vyk~ZFoK<-I}trFg3mkYmvYR?)v(afdoeIyra)oKqN83_aioa zF4ZSXAP6IP#?@zPBrt-fd;K^Dtd z1bYm-M-v#qUcz3`1V-@wRBkzzEJ8&WI*3g0q0v zrwNSUHDR@yzz9}|-ikex_brx;h|5j?*uQC%dyOM=7O%z$y z?(yjTX`;%(X9B;^pdV2I6G2sB0<*AMqVkIy{KZGc`go-GZP|t8iIP2Bb_UrKGZUDF zdr44F@RxLge`Sr5_hp$~dC$Z*y&y0669Oahe8?LezEes5G=UN6D|uJLw--%d1m8dK zJwX!~!IM6o$TfixSxe-kk7r*^U__oMIaA{)Qxh1G6;4jCvQx_`Qxh1G=R?jrcsDhH z5$qB?YiR-_*zMSrn!pHlJAU`m1V-@79e!cc1V&^{lrMMqElU#^k<~}Ok>OV(O<+V; zYWW(4Pk|;df}M{&tqF`^A7h7V0wdU!*l(J^2=*9uk0vmJ9fQ4~35?+V$2+SDjNskG z`=kks;Jv|F*91mzrg086ff1ZHoDof61ZM%SPZJoyYr<+Rk(^!=F@hDMxAwpY`r$7T F{R=94${YXy literal 6284 zcmb7|e{7Xk8ONW58pmR0rs;y2HE4`wF>Xku7pJ}Vg;2#ZHO?AEq0Va|B=1=9g55&c zdSjU75A7I*MWxl-Et)~t&Ddq7F>9}XC~=E!>qv?NjrPu>!Omri#F4eZ?>XnK@8@-Y z**|)p&${nS?T`M=-z5Slv?WK>cxi$C6m8R_wFblG*HE2J`2ujgMcO?k_Nl^gBD6^3G%YhLiGGHan>QW(y*yggEwD zY{~2o56yXE@44QD2w9{D&u{b|&s{jCToP1597isTerEq_Zz;H^y12Znz%0_=o4wzA z96kP^Jgy|f%Oa?RIF4KvTQXZdvfg`a*x#BEA&c}sjy&Q$rcZRsg9Mcj$I&@u(N8@; z)Z;zAy|9pH7U|=Ck9&{KnPxXuAgF{mjy|g_wq*9^ze|NT#v8Rib&lnkMf$7LHSe)$ z;L#4Vt0Mg9il7qWIOf*$i;^`aT8lGep>Cq=t7h1dDTD5QTzr-gTK_$d-^bKXPC9~p-{e^#yH`;zW zKRCrK(wCZ57xMU7d()KJT_Ro+@e2`DLL5h<%3@1qJ6`DZW3{X@mk=R~^txHqg*^5= zzfm3}sDwCOvl!LyySgHWAL_9U`cNIQCieGaH#-$UCC@Xiq|f zEYg=QsxIX5<(-eqg9Mcj$3BaGX5YMh%zHGhmg>wRefWUtLLNVQwkD5_BK}$}u9*`- zNnNmQ&*?^>&zm3V~6TO z9;a_ODG%)*`tSFTI+YN|K8r2+-M|ytKN2Ejkv@E0bs>-6UO1-Q-#;|xiF-v*332SR z=x27Vy`}D+>fG|Kga}!rhh|k5@;G$-LA6eTN{C~hML)Cmj;!|{x&5tmW|4mFi0VQf zXHRs?<0cW)wPIVF2r40tqhBkFEty?7)Z;z2E-Xwji*&V5bs>+nGtKh&V?umQ1eFlS zQJb>Zk_PF`lJ_{-IhGJ1i}aRh)rCAhFz~3}yN;OGJFzN)N{Hj={mP=B-#@&^o?VNR z%p$EfwfFe`k99V(J5)(-1_wk?32_|Vqb#;$c1m^Oh|_NkyB$Yug)GuPc|vuee*A8g z&ROeEGY}u)EmX#9XE)i5h9Q!Q# zxz_b|xHeEfT(JqBae1cZ89pU?UjNkumF@$o9zDs(v$Z_E17TLK-zN_$><7m!C0s;> zGsqPa2-lC+N_m_L*Dh-%^|*eloTI|3}`KE1zpR_4rbJV4MoqF;{5n;UX$r zm0WKr@x{353>B_1uAY>*Q~jXA6~ncV5?@z8sBr$@KId+%;<#y?3TKn^6g=E~6yv5G z70wMuJtbU3g(J-|%o0>MZXA(7xPE-tn#ZYd6xhG42Nm{-Pn&wUhzg&O-dTbQ{n(P( zhi)J9`^V+0rDQh(3087t&5XGI)y*18!>BwUv5b2 z?kr+N#IOh|^kYk*=UOF&S1aWS67Q3cq+{zf3F< z$1CL=l`!YwTSoR90Elrap+3S_gY0eF5w0HxE9Em(!kmYjclKVJde{UN-b}MM$R%R5 zQeHD_Zgx(+pAx>p0wyviFZAkAvC=sqhBzKPP=}QZ8)L zSWyXe9!~w)GxgF_?W~mBsf71#IA3Q^uS|oS0&e5AY4B>wMS9m8sq9oi7S<} zIVxN+Tnj0oJ*u4w=btm1?FSXkCg&;j&|aIP!nxt7r^FrFKd5k|Ifg0GDuN2fjU$rn l2NjM2`1xu%p~`KZq^$@%nxs+a8GxQVRqkhFSaDPoA>_ z%Ge|6u*agq9cP%8^Y*>nI~(-NY>4hWob=!7}AFuBIbjzV0HkuDwPu}vNt!e~RxB)TO9)q^xWMf8YuQ!oHUlPB0 zN+kEnvysrQgs`lk!%0NC@p-I6hjf~$Q9&iIRf2VVN9c$I(?K_8FAq-doRvM#KU;qh z$b(9=p~Hz2_BUY%oRxOSI_ia}y+bmR6N#9k>CEHKbylRR+7v-krA}0b4D6OF)K2D> zevC1r-rz2BRZz)as!f-)F)!bbd2_wzE}x!v;44IWExU^Q7BFu_AkPRj$ GV}1Yui)U{D From 3444d3832b501b7e4c726297203466c47b22a430 Mon Sep 17 00:00:00 2001 From: Kimberly Meechan <24316371+K-Meech@users.noreply.github.com> Date: Tue, 18 Jun 2024 21:02:54 +0100 Subject: [PATCH 11/13] move items from CrosshairFrame to Crosshair --- .../de/embl/schwab/crosshair/Crosshair.java | 45 +++++++++++++-- .../crosshair/ui/swing/CrosshairFrame.java | 55 +++---------------- .../crosshair/ui/swing/ImagesPanel.java | 5 +- .../crosshair/ui/swing/MicrotomePanel.java | 6 +- .../schwab/crosshair/ui/swing/OtherPanel.java | 8 +-- .../schwab/crosshair/ui/swing/PlanePanel.java | 2 +- .../schwab/crosshair/ui/swing/SavePanel.java | 7 +-- .../ui/swing/VertexAssignmentPanel.java | 2 +- 8 files changed, 62 insertions(+), 68 deletions(-) diff --git a/src/main/java/de/embl/schwab/crosshair/Crosshair.java b/src/main/java/de/embl/schwab/crosshair/Crosshair.java index 5762f85..d22f8db 100644 --- a/src/main/java/de/embl/schwab/crosshair/Crosshair.java +++ b/src/main/java/de/embl/schwab/crosshair/Crosshair.java @@ -4,6 +4,7 @@ import bdv.viewer.Source; import de.embl.schwab.crosshair.bdv.BdvBehaviours; import de.embl.schwab.crosshair.microtome.MicrotomeManager; +import de.embl.schwab.crosshair.plane.Plane; import de.embl.schwab.crosshair.plane.PlaneManager; import de.embl.schwab.crosshair.ui.swing.CrosshairFrame; import ij3d.Content; @@ -44,6 +45,13 @@ public class Crosshair { private final int max = 255; private final float transparency = 0.7f; + private BdvHandle bdvHandle; // bdvHandle of the BigDataViewer window + private Image3DUniverse universe; // universe of the 3D viewer + private Content imageContent; // image content displayed in 3D viewer + private PlaneManager planeManager; + private MicrotomeManager microtomeManager; + private String unit; // pixel size unit e.g. mm + /** * Open Crosshair from a Source (normally from a bdv style file e.g. hdf5 / n5) * @param imageSource image source @@ -93,7 +101,11 @@ private void initialiseCrosshair(BdvStackSource bdvStackSource, Image3DUniverse bdvStackSource.setDisplayRange(min, max); - BdvHandle bdvHandle = bdvStackSource.getBdvHandle(); + this.bdvHandle = bdvStackSource.getBdvHandle(); + this.imageContent = imageContent; + this.universe = universe; + this.unit = unit; + imageContent.setLocked(true); imageContent.showPointList(true); universe.getPointListDialog().setVisible(false); @@ -103,14 +115,37 @@ private void initialiseCrosshair(BdvStackSource bdvStackSource, Image3DUniverse // Still places so (0,0) of image == (0,0) in global coordinate system, just bounding box is wrapped tight to // only regions of the image > 0 - PlaneManager planeManager = new PlaneManager(bdvStackSource, universe, imageContent); + planeManager = new PlaneManager(bdvStackSource, universe, imageContent); - MicrotomeManager microtomeManager = new MicrotomeManager(planeManager, universe, imageContent, bdvStackSource, unit); + microtomeManager = new MicrotomeManager(planeManager, universe, imageContent, bdvStackSource, unit); new BdvBehaviours(bdvHandle, planeManager, microtomeManager); - CrosshairFrame crosshairFrame = new CrosshairFrame(universe, imageContent, planeManager, microtomeManager, bdvHandle, unit); + CrosshairFrame crosshairFrame = new CrosshairFrame(this); spaceOutWindows( bdvHandle, crosshairFrame, universe ); } - + + public BdvHandle getBdvHandle() { + return bdvHandle; + } + + public Content getImageContent() { + return imageContent; + } + + public Image3DUniverse getUniverse() { + return universe; + } + + public MicrotomeManager getMicrotomeManager() { + return microtomeManager; + } + + public PlaneManager getPlaneManager() { + return planeManager; + } + + public String getUnit() { + return unit; + } } diff --git a/src/main/java/de/embl/schwab/crosshair/ui/swing/CrosshairFrame.java b/src/main/java/de/embl/schwab/crosshair/ui/swing/CrosshairFrame.java index 9265093..2cd52b6 100644 --- a/src/main/java/de/embl/schwab/crosshair/ui/swing/CrosshairFrame.java +++ b/src/main/java/de/embl/schwab/crosshair/ui/swing/CrosshairFrame.java @@ -1,10 +1,7 @@ package de.embl.schwab.crosshair.ui.swing; -import bdv.util.BdvHandle; -import de.embl.schwab.crosshair.plane.PlaneManager; +import de.embl.schwab.crosshair.Crosshair; import de.embl.schwab.crosshair.microtome.MicrotomeManager; -import ij3d.Content; -import ij3d.Image3DUniverse; import javax.swing.*; import java.util.ArrayList; @@ -14,12 +11,7 @@ */ public class CrosshairFrame extends JFrame { - private Image3DUniverse universe; - private Content imageContent; - private PlaneManager planeManager; - private MicrotomeManager microtomeManager; - private BdvHandle bdvHandle; - + private Crosshair crosshair; private ImagesPanel imagesPanel; private PlanePanel planePanel; private OtherPanel otherPanel; @@ -28,27 +20,13 @@ public class CrosshairFrame extends JFrame { private SavePanel savePanel; private ArrayList allPanels; - private String unit; - /** * Create the main Crosshair UI - * @param universe universe of the 3D viewer - * @param imageContent image content displayed in 3D viewer - * @param planeManager plane manager - * @param microtomeManager microtome manager - * @param bdvHandle bdvHandle of the BigDataViewer window - * @param unit pixel size unit e.g. mm + * @param crosshair crosshair */ - public CrosshairFrame(Image3DUniverse universe, Content imageContent, PlaneManager planeManager, MicrotomeManager microtomeManager, - BdvHandle bdvHandle, String unit) { - - this.universe = universe; - this.imageContent = imageContent; - this.planeManager = planeManager; - this.microtomeManager = microtomeManager; - this.bdvHandle = bdvHandle; - this.unit = unit; + public CrosshairFrame(Crosshair crosshair) { + this.crosshair = crosshair; allPanels = new ArrayList<>(); this.setTitle("Crosshair"); @@ -79,6 +57,7 @@ public CrosshairFrame(Image3DUniverse universe, Content imageContent, PlaneManag panel.initialisePanel( this ); } + MicrotomeManager microtomeManager = crosshair.getMicrotomeManager(); microtomeManager.setMicrotomePanel(microtomePanel); microtomeManager.setVertexAssignmentPanel(vertexAssignmentPanel); @@ -118,25 +97,7 @@ public VertexAssignmentPanel getVertexAssignmentPanel() { return vertexAssignmentPanel; } - public Content getImageContent() { - return imageContent; - } - - public PlaneManager getPlaneManager() { - return planeManager; - } - - public Image3DUniverse getUniverse() { - return universe; - } - - public BdvHandle getBdvHandle() { - return bdvHandle; + public Crosshair getCrosshair() { + return crosshair; } - - public MicrotomeManager getMicrotomeManager() { - return microtomeManager; - } - - public String getUnit() { return unit; } } diff --git a/src/main/java/de/embl/schwab/crosshair/ui/swing/ImagesPanel.java b/src/main/java/de/embl/schwab/crosshair/ui/swing/ImagesPanel.java index e2da221..ea665d7 100644 --- a/src/main/java/de/embl/schwab/crosshair/ui/swing/ImagesPanel.java +++ b/src/main/java/de/embl/schwab/crosshair/ui/swing/ImagesPanel.java @@ -52,9 +52,10 @@ public void initialisePanel( Map imageNameToContent, OtherPanel */ public void initialisePanel ( CrosshairFrame crosshairFrame ) { Map imageNameToContent = new HashMap<>(); - imageNameToContent.put( Crosshair.image, crosshairFrame.getImageContent() ); + imageNameToContent.put( Crosshair.image, crosshairFrame.getCrosshair().getImageContent() ); - initialisePanel( imageNameToContent, crosshairFrame.getPointsPanel(), crosshairFrame.getUniverse() ); + initialisePanel( imageNameToContent, crosshairFrame.getPointsPanel(), + crosshairFrame.getCrosshair().getUniverse() ); } public Map getImageNameToContent() { diff --git a/src/main/java/de/embl/schwab/crosshair/ui/swing/MicrotomePanel.java b/src/main/java/de/embl/schwab/crosshair/ui/swing/MicrotomePanel.java index 93ee939..08be951 100644 --- a/src/main/java/de/embl/schwab/crosshair/ui/swing/MicrotomePanel.java +++ b/src/main/java/de/embl/schwab/crosshair/ui/swing/MicrotomePanel.java @@ -76,13 +76,13 @@ public MicrotomePanel() {} */ public void initialisePanel( CrosshairFrame crosshairFrame ) { this.crosshairFrame = crosshairFrame; - microtomeManager = crosshairFrame.getMicrotomeManager(); + microtomeManager = crosshairFrame.getCrosshair().getMicrotomeManager(); otherPanel = crosshairFrame.getPointsPanel(); vertexAssignmentPanel = crosshairFrame.getVertexAssignmentPanel(); - planeManager = crosshairFrame.getPlaneManager(); + planeManager = crosshairFrame.getCrosshair().getPlaneManager(); planePanel = crosshairFrame.getPlanePanel(); savePanel = crosshairFrame.getSavePanel(); - unit = crosshairFrame.getUnit(); + unit = crosshairFrame.getCrosshair().getUnit(); displayDecimalPlaces = 4; diff --git a/src/main/java/de/embl/schwab/crosshair/ui/swing/OtherPanel.java b/src/main/java/de/embl/schwab/crosshair/ui/swing/OtherPanel.java index a0c72be..8592aa9 100644 --- a/src/main/java/de/embl/schwab/crosshair/ui/swing/OtherPanel.java +++ b/src/main/java/de/embl/schwab/crosshair/ui/swing/OtherPanel.java @@ -67,11 +67,11 @@ public void initialisePanel( ArrayList imageContents, Image3DUniverse u */ public void initialisePanel( CrosshairFrame crosshairFrame ) { ArrayList imageContents = new ArrayList<>(); - imageContents.add( crosshairFrame.getImageContent() ); + imageContents.add( crosshairFrame.getCrosshair().getImageContent() ); - initialisePanel( imageContents, crosshairFrame.getUniverse(), - crosshairFrame.getPlaneManager(), - crosshairFrame.getBdvHandle(), true ); + initialisePanel( imageContents, crosshairFrame.getCrosshair().getUniverse(), + crosshairFrame.getCrosshair().getPlaneManager(), + crosshairFrame.getCrosshair().getBdvHandle(), true ); } public boolean check3DPointsVisible() { diff --git a/src/main/java/de/embl/schwab/crosshair/ui/swing/PlanePanel.java b/src/main/java/de/embl/schwab/crosshair/ui/swing/PlanePanel.java index 800728f..78f2232 100644 --- a/src/main/java/de/embl/schwab/crosshair/ui/swing/PlanePanel.java +++ b/src/main/java/de/embl/schwab/crosshair/ui/swing/PlanePanel.java @@ -68,7 +68,7 @@ public void initialisePanel( CrosshairFrame crosshairFrame ) { planeNames.add( Crosshair.target ); ArrayList blockPlaneNames = new ArrayList<>(); blockPlaneNames.add( Crosshair.block ); - initialisePanel( crosshairFrame.getPlaneManager(), planeNames, blockPlaneNames ); + initialisePanel( crosshairFrame.getCrosshair().getPlaneManager(), planeNames, blockPlaneNames ); } private void addColorButton(JPanel panel, int[] buttonDimensions, String planeName) { diff --git a/src/main/java/de/embl/schwab/crosshair/ui/swing/SavePanel.java b/src/main/java/de/embl/schwab/crosshair/ui/swing/SavePanel.java index fb96c6d..611afd1 100644 --- a/src/main/java/de/embl/schwab/crosshair/ui/swing/SavePanel.java +++ b/src/main/java/de/embl/schwab/crosshair/ui/swing/SavePanel.java @@ -8,7 +8,6 @@ import de.embl.schwab.crosshair.settings.SettingsWriter; import de.embl.schwab.crosshair.solution.Solution; import de.embl.schwab.crosshair.solution.SolutionWriter; -import ij3d.Content; import javax.swing.*; import java.awt.GridLayout; @@ -24,7 +23,6 @@ public class SavePanel extends CrosshairPanel { private PlaneManager planeManager; private MicrotomeManager microtomeManager; - private Content imageContent; private MicrotomePanel microtomePanel; private OtherPanel otherPanel; private ImagesPanel imagesPanel; @@ -42,9 +40,8 @@ public SavePanel() {} */ public void initialisePanel( CrosshairFrame crosshairFrame ) { this.crosshairFrame = crosshairFrame; - this.planeManager = crosshairFrame.getPlaneManager(); - this.microtomeManager = crosshairFrame.getMicrotomeManager(); - this.imageContent = crosshairFrame.getImageContent(); + this.planeManager = crosshairFrame.getCrosshair().getPlaneManager(); + this.microtomeManager = crosshairFrame.getCrosshair().getMicrotomeManager(); this.microtomePanel = crosshairFrame.getMicrotomePanel(); this.otherPanel = crosshairFrame.getPointsPanel(); this.imagesPanel = crosshairFrame.getImagesPanel(); diff --git a/src/main/java/de/embl/schwab/crosshair/ui/swing/VertexAssignmentPanel.java b/src/main/java/de/embl/schwab/crosshair/ui/swing/VertexAssignmentPanel.java index 2fa2cf8..c24ca41 100644 --- a/src/main/java/de/embl/schwab/crosshair/ui/swing/VertexAssignmentPanel.java +++ b/src/main/java/de/embl/schwab/crosshair/ui/swing/VertexAssignmentPanel.java @@ -28,7 +28,7 @@ public VertexAssignmentPanel() {} */ public void initialisePanel ( CrosshairFrame crosshairFrame ) { this.crosshairFrame = crosshairFrame; - this.planeManager = crosshairFrame.getPlaneManager(); + this.planeManager = crosshairFrame.getCrosshair().getPlaneManager(); buttons = new HashMap<>(); setBorder(BorderFactory.createCompoundBorder( From 950f1dace67553b43f0246c69fc1de993a22c278 Mon Sep 17 00:00:00 2001 From: Kimberly Meechan <24316371+K-Meech@users.noreply.github.com> Date: Tue, 25 Jun 2024 19:57:09 +0100 Subject: [PATCH 12/13] increase version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 031d5ca..b70d41a 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ crosshair https://github.com/K-Meech/crosshair - 1.0.3 + 1.0.4 Crosshair Assisted 3D targeting via an ultramicrotome 2020 From 8fefd9226ce54ec9494fff1adcf2ab14d8666753 Mon Sep 17 00:00:00 2001 From: Kimberly Meechan <24316371+K-Meech@users.noreply.github.com> Date: Tue, 25 Jun 2024 20:21:54 +0100 Subject: [PATCH 13/13] use xvfb for tests --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b2d712c..44cae25 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -47,7 +47,7 @@ jobs: # - name: Install blosc # run: sudo apt install libblosc-dev -# - name: Install xvfb -# run: sudo apt-get install xvfb + - name: Install xvfb + run: sudo apt-get install xvfb - name: Build with maven - run: mvn -B package --file pom.xml # for testing with graphics prepend: xvfb-run --auto-servernum + run: xvfb-run --auto-servernum mvn -B package --file pom.xml