diff --git a/pom.xml b/pom.xml
index a95bff9d8..5643027dc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
org.janelia.saalfeldlab
paintera
- 1.7.1-SNAPSHOT
+ 1.8.0-SNAPSHOT
Paintera
New Era Painting and annotation tool
@@ -68,7 +68,7 @@
org.janelia.saalfeldlab.paintera.Paintera
Paintera
paintera
- 1.7.0
+ 1.8.0
javafx.base,javafx.controls,javafx.fxml,javafx.media,javafx.swing,javafx.web,javafx.graphics,java.naming,java.management,java.sql
UTF-8
diff --git a/src/main/java/org/janelia/saalfeldlab/paintera/ui/PainteraAlerts.java b/src/main/java/org/janelia/saalfeldlab/paintera/ui/PainteraAlerts.java
index 48c18e2bd..c6cfdde80 100644
--- a/src/main/java/org/janelia/saalfeldlab/paintera/ui/PainteraAlerts.java
+++ b/src/main/java/org/janelia/saalfeldlab/paintera/ui/PainteraAlerts.java
@@ -100,7 +100,11 @@ public static Alert alert(final Alert.AlertType type) {
public static Alert alert(final Alert.AlertType type, boolean isResizable) {
final AtomicReference alertRef = new AtomicReference<>();
- PlatformImpl.runAndWait(() -> alertRef.set(new Alert(type)));
+ try {
+ InvokeOnJavaFXApplicationThread.invokeAndWait(() -> alertRef.set(new Alert(type)));
+ } catch (InterruptedException e) {
+ LOG.error("Could not create alert", e);
+ }
final Alert alert = alertRef.get();
alert.setTitle(Constants.NAME);
alert.setResizable(isResizable);
diff --git a/src/main/kotlin/org/janelia/saalfeldlab/paintera/Paintera.kt b/src/main/kotlin/org/janelia/saalfeldlab/paintera/Paintera.kt
index 0930e37c9..f841f82e8 100644
--- a/src/main/kotlin/org/janelia/saalfeldlab/paintera/Paintera.kt
+++ b/src/main/kotlin/org/janelia/saalfeldlab/paintera/Paintera.kt
@@ -51,6 +51,8 @@ class Paintera : Application() {
private lateinit var painteraArgs: PainteraCommandLineArgs
private var projectDir: String? = null
+ internal lateinit var mainWindow : PainteraMainWindow
+
init {
application = this
/* add window listener for scenes */
@@ -59,7 +61,7 @@ class Paintera : Application() {
override fun init() {
paintable = false
if (!::commandlineArguments.isInitialized) {
- commandlineArguments = parameters.raw.toTypedArray()
+ commandlineArguments = parameters?.raw?.toTypedArray() ?: emptyArray()
}
painteraArgs = PainteraCommandLineArgs()
if (commandlineArguments.isNotEmpty() && !parsePainteraCommandLine(*commandlineArguments)) {
@@ -67,7 +69,9 @@ class Paintera : Application() {
return
}
Platform.setImplicitExit(true)
- paintera = PainteraMainWindow()
+ paintera = PainteraMainWindow().also {
+ mainWindow = it
+ }
projectDir = painteraArgs.project()
val projectPath = projectDir?.let { File(it).absoluteFile }
diff --git a/src/main/kotlin/org/janelia/saalfeldlab/paintera/PainteraMainWindow.kt b/src/main/kotlin/org/janelia/saalfeldlab/paintera/PainteraMainWindow.kt
index 5ddc54a7f..f3dbbf334 100644
--- a/src/main/kotlin/org/janelia/saalfeldlab/paintera/PainteraMainWindow.kt
+++ b/src/main/kotlin/org/janelia/saalfeldlab/paintera/PainteraMainWindow.kt
@@ -189,11 +189,13 @@ class PainteraMainWindow(val gateway: PainteraGateway = PainteraGateway()) {
}
private fun showSaveCompleteNotification(owner: Any = baseView.node.scene.window) {
- Notifications.create()
+ val saveNotification = Notifications.create()
.graphic(FontAwesome[FontAwesomeIcon.CHECK_CIRCLE])
.title("Save Project")
.text("Save Complete")
.owner(owner)
+ saveNotification
+ .threshold(1, saveNotification)
.show()
}
diff --git a/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/ShapeInterpolationController.kt b/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/ShapeInterpolationController.kt
index 0978a331c..4b5ff8d68 100644
--- a/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/ShapeInterpolationController.kt
+++ b/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/ShapeInterpolationController.kt
@@ -33,7 +33,9 @@ import net.imglib2.type.numeric.RealType
import net.imglib2.type.numeric.integer.UnsignedLongType
import net.imglib2.type.numeric.real.FloatType
import net.imglib2.type.volatiles.VolatileUnsignedLongType
-import net.imglib2.util.*
+import net.imglib2.util.ConstantUtils
+import net.imglib2.util.Intervals
+import net.imglib2.util.Util
import net.imglib2.view.ExtendedRealRandomAccessibleRealInterval
import net.imglib2.view.IntervalView
import net.imglib2.view.Views
@@ -64,7 +66,6 @@ import java.math.RoundingMode
import java.util.concurrent.CancellationException
import java.util.concurrent.atomic.AtomicReference
import java.util.function.Supplier
-import kotlin.Pair
import kotlin.math.absoluteValue
import kotlin.math.sqrt
@@ -473,21 +474,16 @@ class ShapeInterpolationController>(
if (freezeInterpolation) return
synchronized(source) {
source.resetMasks(false)
- /* If preview is on, hide all except the first and last fill mask */
val fillMasks: MutableList> = mutableListOf()
val slices = slicesAndInterpolants.slices
slices.forEachIndexed { idx, slice ->
- if (idx == 0 || idx == slices.size - 1 || !includeInterpolant) {
- fillMasks += slice.mask.run {
- viewerImg
- .expandborder(0, 0, 1)
- .extendValue(Label.INVALID)
- .interpolateNearestNeighbor()
- .affineReal(initialGlobalToMaskTransform.inverse())
- .realInterval(slice.globalBoundingBox!!)
- }
-
-
+ fillMasks += slice.mask.run {
+ viewerImg
+ .expandborder(0, 0, 1)
+ .extendValue(Label.INVALID)
+ .interpolateNearestNeighbor()
+ .affineReal(initialGlobalToMaskTransform.inverse())
+ .realInterval(slice.globalBoundingBox!!)
}
}
val invalidLabel = UnsignedLongType(Label.INVALID)
@@ -586,7 +582,7 @@ class ShapeInterpolationController>(
try {
setCompositeMask()
} catch (e: MaskInUse) {
- LOG.error { "Label source already has an active mask" }
+ LOG.error(e) { "Label source already has an active mask" }
}
}
}
diff --git a/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/modes/ShapeInterpolationMode.kt b/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/modes/ShapeInterpolationMode.kt
index 3e09125e6..fade18cc6 100644
--- a/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/modes/ShapeInterpolationMode.kt
+++ b/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/modes/ShapeInterpolationMode.kt
@@ -1,14 +1,19 @@
package org.janelia.saalfeldlab.paintera.control.modes
import bdv.fx.viewer.render.RenderUnitState
+import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView
import io.github.oshai.kotlinlogging.KotlinLogging
+import javafx.beans.property.SimpleBooleanProperty
import javafx.beans.value.ChangeListener
import javafx.collections.FXCollections
import javafx.collections.ObservableList
import javafx.event.Event
+import javafx.scene.input.KeyCode
import javafx.scene.input.KeyEvent.KEY_PRESSED
import javafx.scene.input.KeyEvent.KEY_RELEASED
+import javafx.util.Subscription
+import kotlinx.coroutines.runBlocking
import net.imglib2.Interval
import net.imglib2.algorithm.labeling.ConnectedComponents
import net.imglib2.algorithm.morphology.distance.DistanceTransform
@@ -21,16 +26,12 @@ import net.imglib2.type.numeric.integer.UnsignedLongType
import net.imglib2.util.Intervals
import net.imglib2.view.IntervalView
import net.imglib2.view.Views
+import org.controlsfx.control.Notifications
import org.janelia.saalfeldlab.bdv.fx.viewer.getDataSourceAndConverter
import org.janelia.saalfeldlab.control.mcu.MCUButtonControl
-import org.janelia.saalfeldlab.fx.actions.ActionSet
+import org.janelia.saalfeldlab.fx.actions.*
import org.janelia.saalfeldlab.fx.actions.ActionSet.Companion.installActionSet
import org.janelia.saalfeldlab.fx.actions.ActionSet.Companion.removeActionSet
-import org.janelia.saalfeldlab.fx.actions.DragActionSet
-import org.janelia.saalfeldlab.fx.actions.NamedKeyBinding
-import org.janelia.saalfeldlab.fx.actions.painteraActionSet
-import org.janelia.saalfeldlab.fx.actions.painteraDragActionSet
-import org.janelia.saalfeldlab.fx.actions.painteraMidiActionSet
import org.janelia.saalfeldlab.fx.midi.MidiButtonEvent
import org.janelia.saalfeldlab.fx.midi.MidiToggleEvent
import org.janelia.saalfeldlab.fx.midi.ToggleAction
@@ -57,6 +58,7 @@ import org.janelia.saalfeldlab.paintera.control.tools.Tool
import org.janelia.saalfeldlab.paintera.control.tools.paint.Fill2DTool
import org.janelia.saalfeldlab.paintera.control.tools.paint.PaintBrushTool
import org.janelia.saalfeldlab.paintera.control.tools.paint.SamPredictor
+import org.janelia.saalfeldlab.paintera.control.tools.paint.SamPredictor.SparseLabel
import org.janelia.saalfeldlab.paintera.control.tools.paint.SamTool
import org.janelia.saalfeldlab.paintera.control.tools.shapeinterpolation.ShapeInterpolationFillTool
import org.janelia.saalfeldlab.paintera.control.tools.shapeinterpolation.ShapeInterpolationPaintBrushTool
@@ -65,8 +67,9 @@ import org.janelia.saalfeldlab.paintera.control.tools.shapeinterpolation.ShapeIn
import org.janelia.saalfeldlab.paintera.data.mask.MaskInfo
import org.janelia.saalfeldlab.paintera.data.mask.MaskedSource
import org.janelia.saalfeldlab.paintera.paintera
+import org.janelia.saalfeldlab.paintera.ui.FontAwesome
import org.janelia.saalfeldlab.util.*
-import kotlin.collections.set
+import kotlin.math.roundToLong
class ShapeInterpolationMode>(val controller: ShapeInterpolationController, private val previousMode: ControlMode) : AbstractToolMode() {
@@ -161,6 +164,8 @@ class ShapeInterpolationMode>(val controller: ShapeInterpolat
converter.activeFragmentAlphaProperty().set((activeSelectionAlpha * 255).toInt())
}
+ internal val samStyleBoxToggle = SimpleBooleanProperty(true)
+
private fun modeActions(): List {
return mutableListOf(
painteraActionSet(CANCEL, ignoreDisable = true) {
@@ -225,6 +230,7 @@ class ShapeInterpolationMode>(val controller: ShapeInterpolat
},
painteraDragActionSet("drag activate SAM mode with box", PaintActionType.Paint, ignoreDisable = true, consumeMouseClicked = true) {
onDragDetected {
+ verify("primary click drag only ") { it.isPrimaryButtonDown && !it.isSecondaryButtonDown && !it.isMiddleButtonDown }
verify("can't trigger box prompt with active tool") { activeTool in listOf(NavigationTool, shapeInterpolationTool, samTool) }
switchTool(samTool)
}
@@ -234,6 +240,29 @@ class ShapeInterpolationMode>(val controller: ShapeInterpolat
}
}
},
+ painteraActionSet("change auto sam style") {
+ KEY_PRESSED(KeyCode.B) {
+ onAction {
+ samStyleBoxToggle.set(!samStyleBoxToggle.get())
+ data class SamStyleToggle(val icon: FontAwesomeIcon, val title: String, val text: String)
+ val (toggle, title, text) = if (samStyleBoxToggle.get())
+ SamStyleToggle(FontAwesomeIcon.TOGGLE_RIGHT, "Toggle Sam Style", "Style: Interpolant Interval")
+ else
+ SamStyleToggle(FontAwesomeIcon.TOGGLE_LEFT, "Toggle Sam Style", "Style: Interpolant Distance Point")
+
+ InvokeOnJavaFXApplicationThread {
+ val notification = Notifications.create()
+ .graphic(FontAwesome[toggle])
+ .title(title)
+ .text(text)
+ .owner(paintera.baseView.node)
+ notification
+ .threshold(1, notification)
+ .show()
+ }
+ }
+ }
+ },
DeviceManager.xTouchMini?.let { device ->
activeViewerProperty.get()?.viewer()?.let { viewer ->
painteraMidiActionSet("midi paint tool switch actions", device, viewer, PaintActionType.Paint) {
@@ -331,13 +360,32 @@ class ShapeInterpolationMode>(val controller: ShapeInterpolat
).filterNotNull()
}
+ internal fun applyShapeInterpolationAndExitMode() {
+ with(controller) {
+ var applyMaskTriggered = false
+ var selfReference: Subscription? = null
+ val subscription = source.isApplyingMaskProperty.subscribe { applyingMask ->
+ if (applyMaskTriggered && !applyingMask) {
+ selfReference?.unsubscribe()
+ InvokeOnJavaFXApplicationThread {
+ paintera.baseView.changeMode(previousMode)
+ }
+ }
+
+ }
+ selfReference = subscription
+ applyMaskTriggered = true
+ if (!applyMask())
+ subscription?.unsubscribe()
+ }
+ }
fun switchAndApplyShapeInterpolationActions(toolActions: ActionSet) {
with(toolActions) {
KEY_PRESSED(CANCEL) {
name = "cancel_to_shape_interpolation_tool"
onAction {
- switchTool(shapeInterpolationTool)
+ runBlocking { switchTool(shapeInterpolationTool)?.join() }
controller.setMaskOverlay(replaceExistingInterpolants = true)
}
handleException {
@@ -346,11 +394,13 @@ class ShapeInterpolationMode>(val controller: ShapeInterpolat
}
KEY_PRESSED(SHAPE_INTERPOLATION__ACCEPT_INTERPOLATION) {
onAction {
- switchTool(shapeInterpolationTool)
- if (controller.applyMask())
- paintera.baseView.changeMode(previousMode)
+ runBlocking { switchTool(shapeInterpolationTool)?.join() }
+ applyShapeInterpolationAndExitMode()
+ }
+ handleException {
+ LOG.error(it) {}
+ paintera.baseView.changeMode(previousMode)
}
- handleException { paintera.baseView.changeMode(previousMode) }
}
}
}
@@ -384,7 +434,7 @@ class ShapeInterpolationMode>(val controller: ShapeInterpolat
}
}
- internal fun cacheLoadSamSliceInfo(depth: Double, translate: Boolean = depth != controller.currentDepth, provideGlobalToViewerTransform : AffineTransform3D? = null): SamSliceInfo {
+ internal fun cacheLoadSamSliceInfo(depth: Double, translate: Boolean = depth != controller.currentDepth, provideGlobalToViewerTransform: AffineTransform3D? = null): SamSliceInfo {
return samSliceCache[depth] ?: with(controller) {
val viewerAndTransforms = this@ShapeInterpolationMode.activeViewerProperty.value!!
val viewer = viewerAndTransforms.viewer()!!
@@ -397,11 +447,12 @@ class ShapeInterpolationMode>(val controller: ShapeInterpolat
else -> AffineTransform3D().also { viewerAndTransforms.viewer().state.getViewerTransform(it) }
}
- val predictionPositions = provideGlobalToViewerTransform?.let { listOf(doubleArrayOf(width / 2.0, height / 2.0, 0.0)) } ?: let {
- controller.getInterpolationImg(globalToViewerTransform, closest = true)?.let {
- val interpolantInViewer = if (translate) alignTransformAndViewCenter(it, globalToViewerTransform, width, height) else it
- interpolantInViewer.getComponentMaxDistancePosition()
- } ?: listOf(doubleArrayOf(width / 2.0, height / 2.0, 0.0))
+ val fallbackPrompt = listOf(doubleArrayOf(width / 2.0, height / 2.0, 0.0) to SparseLabel.IN)
+ val predictionPositions = provideGlobalToViewerTransform?.let { fallbackPrompt } ?: let {
+ controller.getInterpolationImg(globalToViewerTransform, closest = true)?.let {
+ val interpolantInViewer = if (translate) alignTransformAndViewCenter(it, globalToViewerTransform, width, height) else it
+ interpolantInViewer.getInterpolantPrompt(samStyleBoxToggle.get())
+ } ?: fallbackPrompt
}
@@ -411,12 +462,11 @@ class ShapeInterpolationMode>(val controller: ShapeInterpolat
val activeSource = activeSourceStateProperty.value!!.sourceAndConverter!!.spimSource
val sources = mask.viewer.state.sources
.filter { it.spimSource !== activeSource }
- .map { sac -> getDataSourceAndConverter (sac) } // to ensure non-volatile
+ .map { sac -> getDataSourceAndConverter(sac) } // to ensure non-volatile
.toList()
val renderState = RenderUnitState(mask.initialGlobalToViewerTransform.copy(), mask.info.time, sources, width.toLong(), height.toLong())
- val predictionRequest = SamPredictor.SparsePrediction(predictionPositions.map { (x, y) -> renderState.getSamPoint(x, y, SamPredictor.SparseLabel.IN) })
-
+ val predictionRequest = SamPredictor.SparsePrediction(predictionPositions.map { (pos, label) -> renderState.getSamPoint(pos[0], pos[1], label) })
SamSliceInfo(renderState, mask, predictionRequest, null, false).also {
SamEmbeddingLoaderCache.load(renderState)
samSliceCache[depth] = it
@@ -523,11 +573,26 @@ class ShapeInterpolationMode>(val controller: ShapeInterpolat
}
}
-internal fun RenderUnitState.getSamPoint(screenX: Double, screenY: Double, label: SamPredictor.SparseLabel): SamPredictor.SamPoint {
+internal fun RenderUnitState.getSamPoint(screenX: Double, screenY: Double, label: SparseLabel): SamPredictor.SamPoint {
val screenScaleFactor = calculateTargetSamScreenScaleFactor()
return SamPredictor.SamPoint(screenX * screenScaleFactor, screenY * screenScaleFactor, label)
}
+internal fun IntervalView.getInterpolantPrompt(box: Boolean): List> {
+ return if (box)
+ getMinMaxIntervalPositions().mapIndexed { idx, it -> it to if (idx == 0) SparseLabel.TOP_LEFT_BOX else SparseLabel.BOTTOM_RIGHT_BOX }
+ else
+ getComponentMaxDistancePosition().map { it to SparseLabel.IN }
+}
+
+internal fun IntervalView.getMinMaxIntervalPositions(): List {
+ val interval = Intervals.expand(this, *dimensionsAsLongArray().map { (it * .1).roundToLong() }.toLongArray())
+ return listOf(
+ interval.minAsDoubleArray(),
+ interval.maxAsDoubleArray()
+ )
+}
+
internal fun IntervalView.getComponentMaxDistancePosition(): List {
/* find the max point to initialize with */
val invalidBorderRai = extendValue(Label.INVALID).interval(Intervals.expand(this, 1, 1, 0))
@@ -614,11 +679,16 @@ internal data class SamSliceInfo(val renderState: RenderUnitState, val mask: Vie
val preGenerated get() = sliceInfo == null
val globalToViewerTransform get() = renderState.transform
- fun updatePrediction(viewerX: Double, viewerY: Double, label: SamPredictor.SparseLabel = SamPredictor.SparseLabel.IN) {
+ fun updatePrediction(viewerX: Double, viewerY: Double, label: SparseLabel = SparseLabel.IN) {
prediction = SamPredictor.SparsePrediction(listOf(renderState.getSamPoint(viewerX, viewerY, label)))
}
- fun updatePrediction(viewerPositions: List, label: SamPredictor.SparseLabel = SamPredictor.SparseLabel.IN) {
+ fun updatePrediction(viewerPositions: List, label: SparseLabel = SparseLabel.IN) {
prediction = SamPredictor.SparsePrediction(viewerPositions.map { (x, y) -> renderState.getSamPoint(x, y, label) })
}
+
+ fun updatePrediction(viewerPositionsAndLabels: List>) {
+ prediction = SamPredictor.SparsePrediction(viewerPositionsAndLabels.map { (pos, label) -> renderState.getSamPoint(pos[0], pos[1], label) })
+
+ }
}
\ No newline at end of file
diff --git a/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/tools/paint/SamTool.kt b/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/tools/paint/SamTool.kt
index a14d95489..24b9bd879 100644
--- a/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/tools/paint/SamTool.kt
+++ b/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/tools/paint/SamTool.kt
@@ -725,7 +725,7 @@ open class SamTool(activeSourceStateProperty: SimpleObjectProperty drawPromptPoints(points)
diff --git a/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/tools/shapeinterpolation/ShapeInterpolationSAMTool.kt b/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/tools/shapeinterpolation/ShapeInterpolationSAMTool.kt
index 4a0fc8048..5b1d6d4b2 100644
--- a/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/tools/shapeinterpolation/ShapeInterpolationSAMTool.kt
+++ b/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/tools/shapeinterpolation/ShapeInterpolationSAMTool.kt
@@ -37,7 +37,12 @@ internal class ShapeInterpolationSAMTool(private val controller: ShapeInterpolat
/* If we are requesting a new embedding that isn't already pre-cached,
* then likely the existing requests are no longer needed.
* Cancel any that have not yet returned. */
- shapeInterpolationMode.samSliceCache[controller.currentDepth] ?: let { SamEmbeddingLoaderCache.cancelPendingRequests() }
+ var drawPrompt = false
+ shapeInterpolationMode.samSliceCache[controller.currentDepth]?.let {
+ drawPrompt = true
+ } ?: let {
+ SamEmbeddingLoaderCache.cancelPendingRequests()
+ }
val info = shapeInterpolationMode.cacheLoadSamSliceInfo(controller.currentDepth)
maskedSource?.resetMasks(false)
@@ -46,7 +51,9 @@ internal class ShapeInterpolationSAMTool(private val controller: ShapeInterpolat
super.activate()
- temporaryPrompt = !info.locked
+ if (drawPrompt)
+ info.prediction.drawPrompt()
+
requestPrediction(info.prediction)
}
diff --git a/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/tools/shapeinterpolation/ShapeInterpolationTool.kt b/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/tools/shapeinterpolation/ShapeInterpolationTool.kt
index cee453d0e..7608f23bd 100644
--- a/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/tools/shapeinterpolation/ShapeInterpolationTool.kt
+++ b/src/main/kotlin/org/janelia/saalfeldlab/paintera/control/tools/shapeinterpolation/ShapeInterpolationTool.kt
@@ -1,6 +1,7 @@
package org.janelia.saalfeldlab.paintera.control.tools.shapeinterpolation
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView
+import io.github.oshai.kotlinlogging.KotlinLogging
import javafx.beans.property.SimpleIntegerProperty
import javafx.beans.property.SimpleStringProperty
import javafx.scene.input.KeyCode
@@ -9,7 +10,7 @@ import javafx.scene.input.MouseButton
import javafx.scene.input.MouseEvent
import javafx.scene.input.MouseEvent.MOUSE_CLICKED
import javafx.util.Duration
-import kotlinx.coroutines.*
+import kotlinx.coroutines.Job
import net.imglib2.realtransform.AffineTransform3D
import org.janelia.saalfeldlab.fx.actions.*
import org.janelia.saalfeldlab.fx.actions.ActionSet.Companion.installActionSet
@@ -29,13 +30,17 @@ import org.janelia.saalfeldlab.paintera.cache.SamEmbeddingLoaderCache
import org.janelia.saalfeldlab.paintera.control.ShapeInterpolationController
import org.janelia.saalfeldlab.paintera.control.actions.NavigationActionType
import org.janelia.saalfeldlab.paintera.control.actions.PaintActionType
-import org.janelia.saalfeldlab.paintera.control.modes.*
+import org.janelia.saalfeldlab.paintera.control.modes.ControlMode
+import org.janelia.saalfeldlab.paintera.control.modes.NavigationTool
+import org.janelia.saalfeldlab.paintera.control.modes.ShapeInterpolationMode
+import org.janelia.saalfeldlab.paintera.control.modes.getInterpolantPrompt
import org.janelia.saalfeldlab.paintera.control.navigation.TranslationController
import org.janelia.saalfeldlab.paintera.control.tools.ViewerTool
import org.janelia.saalfeldlab.paintera.control.tools.paint.Fill2DTool
import org.janelia.saalfeldlab.paintera.control.tools.paint.SamTool
import org.janelia.saalfeldlab.paintera.paintera
-import org.janelia.saalfeldlab.util.*
+import org.janelia.saalfeldlab.util.extendValue
+import org.janelia.saalfeldlab.util.get
internal class ShapeInterpolationTool(
private val controller: ShapeInterpolationController<*>,
@@ -129,7 +134,7 @@ internal class ShapeInterpolationTool(
)
}
- private fun requestSamPredictionAtViewerPoint(vat : ViewerAndTransforms, requestMidPoint : Boolean = true, runAfter : () -> Unit = {}) {
+ private fun requestSamPredictionAtViewerPoint(vat: ViewerAndTransforms, requestMidPoint: Boolean = true, runAfter: () -> Unit = {}) {
with(controller) {
val viewer = vat.viewer()
val dX = viewer.width / 2 - viewer.mouseXProperty.value
@@ -149,7 +154,7 @@ internal class ShapeInterpolationTool(
val depth = depthAt(resultActiveGlobalToViewer)
if (!requestMidPoint) {
- requestSamPrediction(depth, refresh = true, provideGlobalToViewerTransform = resultActiveGlobalToViewer) {runAfter() }
+ requestSamPrediction(depth, refresh = true, provideGlobalToViewerTransform = resultActiveGlobalToViewer) { runAfter() }
} else {
requestSamPrediction(depth, refresh = true, provideGlobalToViewerTransform = resultActiveGlobalToViewer) {
val depths = sortedSliceDepths
@@ -170,7 +175,6 @@ internal class ShapeInterpolationTool(
}
-
internal fun requestEmbedding(depth: Double) {
shapeInterpolationMode.cacheLoadSamSliceInfo(depth)
}
@@ -196,9 +200,11 @@ internal class ShapeInterpolationTool(
val samSliceInfo = shapeInterpolationMode.cacheLoadSamSliceInfo(depth, provideGlobalToViewerTransform = provideGlobalToViewerTransform)
if (!newPrediction && refresh) {
- controller.getInterpolationImg(samSliceInfo.globalToViewerTransform, closest = true)?.getComponentMaxDistancePosition()?.let { positions ->
- samSliceInfo.updatePrediction(positions)
+ controller.getInterpolationImg(samSliceInfo.globalToViewerTransform, closest = true)?.run {
+ val points = getInterpolantPrompt(shapeInterpolationMode.samStyleBoxToggle.get())
+ samSliceInfo.updatePrediction(points)
}
+
}
val viewerMask = samSliceInfo.mask
@@ -265,13 +271,9 @@ internal class ShapeInterpolationTool(
verifyAll(KEY_PRESSED) { isControllerActive }
KEY_PRESSED(SHAPE_INTERPOLATION__ACCEPT_INTERPOLATION) {
graphic = { GlyphScaleView(FontAwesomeIconView().apply { styleClass += listOf("accept", "accept-shape-interpolation") }) }
- onAction {
- if (applyMask()) {
- paintera.baseView.changeMode(previousMode)
- }
- }
+ onAction { shapeInterpolationMode.applyShapeInterpolationAndExitMode() }
handleException {
- it.printStackTrace()
+ LOG.error(it) {}
paintera.baseView.changeMode(previousMode)
}
}
@@ -556,4 +558,8 @@ internal class ShapeInterpolationTool(
}
}
}
+
+ companion object {
+ private val LOG = KotlinLogging.logger { }
+ }
}
\ No newline at end of file