Search in sources :

Example 16 with PathAnnotationObject

use of qupath.lib.objects.PathAnnotationObject in project qupath by qupath.

the class AnnotationPane method selectedPathObjectChanged.

@Override
public void selectedPathObjectChanged(final PathObject pathObjectSelected, final PathObject previousObject, Collection<PathObject> allSelected) {
    if (!Platform.isFxApplicationThread()) {
        // Platform.runLater(() -> selectedPathObjectChanged(pathObjectSelected, previousObject, allSelected));
        return;
    }
    if (suppressSelectionChanges || disableUpdates.get())
        return;
    suppressSelectionChanges = true;
    if (synchronizePrimarySelectionOnly) {
        try {
            var listSelectionModel = listAnnotations.getSelectionModel();
            listSelectionModel.clearSelection();
            if (pathObjectSelected != null && pathObjectSelected.isAnnotation()) {
                listSelectionModel.select(pathObjectSelected);
                listAnnotations.scrollTo(pathObjectSelected);
            }
            return;
        } finally {
            suppressSelectionChanges = false;
        }
    }
    try {
        var hierarchySelected = new TreeSet<>(DefaultPathObjectComparator.getInstance());
        hierarchySelected.addAll(allSelected);
        // Determine the objects to select
        MultipleSelectionModel<PathObject> model = listAnnotations.getSelectionModel();
        List<PathObject> selected = new ArrayList<>();
        for (PathObject pathObject : hierarchySelected) {
            if (pathObject == null)
                logger.warn("Selected object is null!");
            else if (pathObject.isAnnotation())
                selected.add(pathObject);
        }
        if (selected.isEmpty()) {
            if (!model.isEmpty())
                model.clearSelection();
            return;
        }
        // Check if we're making changes
        List<PathObject> currentlySelected = model.getSelectedItems();
        if (selected.size() == currentlySelected.size() && (hierarchySelected.containsAll(currentlySelected))) {
            listAnnotations.refresh();
            return;
        }
        // System.err.println(listAnnotations.getItems().size());
        if (hierarchySelected.containsAll(listAnnotations.getItems())) {
            model.selectAll();
            return;
        }
        // System.err.println("Setting " + currentlySelected + " to " + selected);
        int[] inds = new int[selected.size()];
        int i = 0;
        model.clearSelection();
        boolean firstInd = true;
        for (PathObject temp : selected) {
            int idx = listAnnotations.getItems().indexOf(temp);
            if (idx >= 0 && firstInd) {
                Arrays.fill(inds, idx);
                firstInd = false;
            }
            inds[i] = idx;
            i++;
        }
        if (inds.length == 1 && pathObjectSelected instanceof PathAnnotationObject)
            listAnnotations.scrollTo(pathObjectSelected);
        if (firstInd) {
            suppressSelectionChanges = false;
            return;
        }
        if (inds.length == 1)
            model.select(inds[0]);
        else if (inds.length > 1)
            model.selectIndices(inds[0], inds);
    } finally {
        suppressSelectionChanges = false;
    }
}
Also used : PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) PathObject(qupath.lib.objects.PathObject) TreeSet(java.util.TreeSet) ArrayList(java.util.ArrayList)

Example 17 with PathAnnotationObject

use of qupath.lib.objects.PathAnnotationObject in project qupath by qupath.

the class BrushTool method mousePressed.

@Override
public void mousePressed(MouseEvent e) {
    // super.mousePressed(e);
    if (!e.isPrimaryButtonDown() || e.isConsumed()) {
        return;
    }
    ensureCursorType(getRequestedCursor());
    var viewer = getViewer();
    PathObjectHierarchy hierarchy = viewer.getHierarchy();
    if (hierarchy == null)
        return;
    PathObject currentObject = viewer.getSelectedObject();
    // Determine if we are creating a new object
    // boolean createNew = currentObject == null || e.getClickCount() > 1;// || (!currentObject.getROI().contains(p.getX(), p.getY()) && !e.isAltDown());
    Point2D p = mouseLocationToImage(e, false, requestPixelSnapping());
    double xx = p.getX();
    double yy = p.getY();
    if (xx < 0 || yy < 0 || xx >= viewer.getServerWidth() || yy >= viewer.getServerHeight())
        return;
    // boolean createNew = currentObject == null || !(currentObject instanceof PathAnnotationObject) || (currentObject.hasChildren()) || (PathPrefs.getBrushCreateNewObjects() && !ROIHelpers.areaContains(currentObject.getROI(), p.getX(), p.getY()) && !isSubtractMode(e));
    boolean createNew = currentObject == null || PathPrefs.selectionModeProperty().get() || !(currentObject instanceof PathAnnotationObject) || (!currentObject.isEditable()) || currentObject.getROI().getZ() != viewer.getZPosition() || currentObject.getROI().getT() != viewer.getTPosition() || (!e.isShiftDown() && PathPrefs.brushCreateNewObjectsProperty().get() && !RoiTools.areaContains(currentObject.getROI(), p.getX(), p.getY()) && !isSubtractMode(e));
    if (isSubtractMode(e))
        createNew = false;
    // See if, rather than creating something, we can instead reactivate a current object
    boolean multipleClicks = e.getClickCount() > 1;
    if (!PathPrefs.selectionModeProperty().get() && (multipleClicks || (createNew && !e.isShiftDown()))) {
        // See if, rather than creating something, we can instead reactivate a current object
        if (multipleClicks) {
            PathObject objectSelectable = getSelectableObject(p.getX(), p.getY(), e.getClickCount() - 1);
            if (objectSelectable != null && objectSelectable.isEditable() && objectSelectable.hasROI() && objectSelectable.getROI().isArea()) {
                createNew = false;
                viewer.setSelectedObject(objectSelectable);
                currentObject = objectSelectable;
            } else if (createNew) {
                viewer.setSelectedObject(null);
                currentObject = null;
            }
        } else if (!PathPrefs.selectionModeProperty().get()) {
            List<PathObject> listSelectable = getSelectableObjectList(p.getX(), p.getY());
            PathObject objectSelectable = null;
            for (int i = listSelectable.size() - 1; i >= 0; i--) {
                PathObject temp = listSelectable.get(i);
                if (temp.isEditable() && temp instanceof PathAnnotationObject && temp.hasROI() && temp.getROI().isArea()) {
                    // temp.getROI() instanceof AreaROI) {
                    objectSelectable = temp;
                    break;
                }
            }
            if (objectSelectable != null) {
                createNew = false;
                viewer.setSelectedObject(objectSelectable);
                currentObject = objectSelectable;
            } else if (createNew) {
                viewer.setSelectedObject(null);
                currentObject = null;
            }
        }
    }
    // Can only modify annotations
    if (!createNew && !(currentObject != null && currentObject.isAnnotation() && currentObject.isEditable() && RoiTools.isShapeROI(currentObject.getROI())))
        return;
    // Get the parent, in case we need to constrain the shape
    // PathObject parent = null;
    // if (currentObject != null) {
    // parent = currentObject.getParent();
    // }
    // var currentObject2 = currentObject;
    // if (parent == null || parent.isDetection()) {
    // parent = getSelectableObjectList(p.getX(), p.getY())
    // .stream()
    // .filter(o -> !o.isDetection() && o != currentObject2)
    // .findFirst()
    // .orElseGet(() -> null);
    // }
    // setConstrainedAreaParent(hierarchy, parent, currentObject);
    setConstrainedAreaParent(hierarchy, xx, yy, Collections.singleton(currentObject));
    // Need to remove the object from the hierarchy while editing it
    if (!createNew && currentObject != null) {
        hierarchy.removeObjectWithoutUpdate(currentObject, true);
    }
    ROI shapeROI = createNew ? null : currentObject.getROI();
    if (createNew) {
        // Reset this
        creatingTiledROI = false;
        this.currentObject = createNewAnnotation(e, p.getX(), p.getY());
        viewer.getROIEditor().setROI(null);
    } else {
        this.currentObject = getUpdatedObject(e, shapeROI, currentObject, -1);
        viewer.setSelectedObject(this.currentObject);
        // Avoids handles appearing?
        viewer.getROIEditor().setROI(null);
    }
    lastPoint = p;
}
Also used : PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) PathObject(qupath.lib.objects.PathObject) Point2D(java.awt.geom.Point2D) List(java.util.List) RectangleROI(qupath.lib.roi.RectangleROI) ROI(qupath.lib.roi.interfaces.ROI)

Example 18 with PathAnnotationObject

use of qupath.lib.objects.PathAnnotationObject in project qupath by qupath.

the class Commands method promptToSimplifySelectedAnnotations.

/**
 * Show a prompt to selected annotations in a hierarchy.
 * @param imageData the current image data
 * @param altitudeThreshold default altitude value for simplification
 */
public static void promptToSimplifySelectedAnnotations(ImageData<?> imageData, double altitudeThreshold) {
    PathObjectHierarchy hierarchy = imageData.getHierarchy();
    List<PathObject> pathObjects = hierarchy.getSelectionModel().getSelectedObjects().stream().filter(p -> p.isAnnotation() && p.hasROI() && p.isEditable() && !p.getROI().isPoint()).collect(Collectors.toList());
    if (pathObjects.isEmpty()) {
        Dialogs.showErrorMessage("Simplify annotations", "No unlocked shape annotations selected!");
        return;
    }
    String input = Dialogs.showInputDialog("Simplify shape", "Set altitude threshold in pixels.\nHigher values give simpler shapes.", Double.toString(altitudeThreshold));
    if (input == null || !(input instanceof String) || ((String) input).trim().length() == 0)
        return;
    try {
        altitudeThreshold = Double.parseDouble(((String) input).trim());
    } catch (NumberFormatException e) {
        logger.error("Could not parse altitude threshold from {}", input);
        return;
    }
    if (altitudeThreshold <= 0) {
        Dialogs.showErrorMessage("Simplify shape", "Amplitude threshold should be greater than zero!");
        return;
    }
    long startTime = System.currentTimeMillis();
    for (var pathObject : pathObjects) {
        ROI pathROI = pathObject.getROI();
        if (pathROI instanceof PolygonROI) {
            PolygonROI polygonROI = (PolygonROI) pathROI;
            pathROI = ShapeSimplifier.simplifyPolygon(polygonROI, altitudeThreshold);
        } else {
            pathROI = ShapeSimplifier.simplifyShape(pathROI, altitudeThreshold);
        }
        ((PathAnnotationObject) pathObject).setROI(pathROI);
    }
    long endTime = System.currentTimeMillis();
    logger.debug("Shapes simplified in " + (endTime - startTime) + " ms");
    hierarchy.fireObjectsChangedEvent(hierarchy, pathObjects);
}
Also used : Arrays(java.util.Arrays) ServerTools(qupath.lib.images.servers.ServerTools) PathTileObject(qupath.lib.objects.PathTileObject) StackPane(javafx.scene.layout.StackPane) ImageWriter(qupath.lib.images.writers.ImageWriter) ParameterList(qupath.lib.plugins.parameters.ParameterList) ImageRegion(qupath.lib.regions.ImageRegion) Map(java.util.Map) PathObjects(qupath.lib.objects.PathObjects) Screen(javafx.stage.Screen) WorkflowStep(qupath.lib.plugins.workflow.WorkflowStep) PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) Project(qupath.lib.projects.Project) ShapeFeatures(qupath.lib.analysis.features.ObjectMeasurements.ShapeFeatures) MeasurementMapPane(qupath.lib.gui.panes.MeasurementMapPane) BorderPane(javafx.scene.layout.BorderPane) StringProperty(javafx.beans.property.StringProperty) RectangleROI(qupath.lib.roi.RectangleROI) CheckBoxListCell(javafx.scene.control.cell.CheckBoxListCell) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) Supplier(java.util.function.Supplier) Bindings(javafx.beans.binding.Bindings) ViewTrackerControlPane(qupath.lib.gui.viewer.recording.ViewTrackerControlPane) Projects(qupath.lib.projects.Projects) ArrayList(java.util.ArrayList) CheckListView(org.controlsfx.control.CheckListView) ROIs(qupath.lib.roi.ROIs) ShapeSimplifier(qupath.lib.roi.ShapeSimplifier) TextAlignment(javafx.scene.text.TextAlignment) PathClassPane(qupath.lib.gui.panes.PathClassPane) GridPane(javafx.scene.layout.GridPane) Files(java.nio.file.Files) GeneralTools(qupath.lib.common.GeneralTools) RegionRequest(qupath.lib.regions.RegionRequest) Window(java.awt.Window) DistanceTools(qupath.lib.analysis.DistanceTools) IOException(java.io.IOException) File(java.io.File) OverlayOptions(qupath.lib.gui.viewer.OverlayOptions) PathObjectTools(qupath.lib.objects.PathObjectTools) ROI(qupath.lib.roi.interfaces.ROI) QP(qupath.lib.scripting.QP) GridLines(qupath.lib.gui.viewer.GridLines) PathPrefs(qupath.lib.gui.prefs.PathPrefs) RenderedImageServer(qupath.lib.gui.images.servers.RenderedImageServer) PaneTools(qupath.lib.gui.tools.PaneTools) PathIO(qupath.lib.io.PathIO) Button(javafx.scene.control.Button) Pos(javafx.geometry.Pos) ImageServer(qupath.lib.images.servers.ImageServer) CombineOp(qupath.lib.roi.RoiTools.CombineOp) LoggerFactory(org.slf4j.LoggerFactory) ObservableDoubleValue(javafx.beans.value.ObservableDoubleValue) ComboBox(javafx.scene.control.ComboBox) ImageServers(qupath.lib.images.servers.ImageServers) PolygonROI(qupath.lib.roi.PolygonROI) QuPathGUI(qupath.lib.gui.QuPathGUI) Pane(javafx.scene.layout.Pane) TextField(javafx.scene.control.TextField) BufferedImage(java.awt.image.BufferedImage) Collection(java.util.Collection) Collectors(java.util.stream.Collectors) PathDetectionObject(qupath.lib.objects.PathDetectionObject) PathObject(qupath.lib.objects.PathObject) QuPathViewer(qupath.lib.gui.viewer.QuPathViewer) Priority(javafx.scene.layout.Priority) List(java.util.List) DefaultScriptableWorkflowStep(qupath.lib.plugins.workflow.DefaultScriptableWorkflowStep) ProjectIO(qupath.lib.projects.ProjectIO) GuiTools(qupath.lib.gui.tools.GuiTools) TMASummaryViewer(qupath.lib.gui.tma.TMASummaryViewer) ImagePlane(qupath.lib.regions.ImagePlane) PathCellObject(qupath.lib.objects.PathCellObject) Scene(javafx.scene.Scene) WorkflowCommandLogView(qupath.lib.gui.panes.WorkflowCommandLogView) TextArea(javafx.scene.control.TextArea) ButtonType(javafx.scene.control.ButtonType) Action(org.controlsfx.control.action.Action) HashMap(java.util.HashMap) DoubleProperty(javafx.beans.property.DoubleProperty) Function(java.util.function.Function) Dialogs(qupath.lib.gui.dialogs.Dialogs) Insets(javafx.geometry.Insets) ActionTools(qupath.lib.gui.ActionTools) Tooltip(javafx.scene.control.Tooltip) WeakHashMap(java.util.WeakHashMap) ImageData(qupath.lib.images.ImageData) RoiTools(qupath.lib.roi.RoiTools) Modality(javafx.stage.Modality) Logger(org.slf4j.Logger) Label(javafx.scene.control.Label) Iterator(java.util.Iterator) ImageWriterTools(qupath.lib.images.writers.ImageWriterTools) TMACoreObject(qupath.lib.objects.TMACoreObject) Stage(javafx.stage.Stage) Collections(java.util.Collections) ContentDisplay(javafx.scene.control.ContentDisplay) DialogButton(qupath.lib.gui.dialogs.Dialogs.DialogButton) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) PolygonROI(qupath.lib.roi.PolygonROI) PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) PathObject(qupath.lib.objects.PathObject) RectangleROI(qupath.lib.roi.RectangleROI) ROI(qupath.lib.roi.interfaces.ROI) PolygonROI(qupath.lib.roi.PolygonROI)

Example 19 with PathAnnotationObject

use of qupath.lib.objects.PathAnnotationObject in project qupath by qupath.

the class GuiTools method promptToSetAnnotationProperties.

private static boolean promptToSetAnnotationProperties(final PathAnnotationObject annotation, Collection<PathAnnotationObject> otherAnnotations) {
    GridPane panel = new GridPane();
    panel.setVgap(5);
    panel.setHgap(5);
    TextField textField = new TextField();
    if (annotation.getName() != null)
        textField.setText(annotation.getName());
    textField.setPrefColumnCount(20);
    // Post focus request to run later, after dialog displayed
    Platform.runLater(() -> textField.requestFocus());
    panel.add(new Label("Name "), 0, 0);
    panel.add(textField, 1, 0);
    boolean promptForColor = true;
    ColorPicker colorPicker = null;
    var originalColor = ColorToolsFX.getDisplayedColor(annotation);
    // Track if the user changed anything, so that we don't set the color unnecessarily
    var colorChanged = new SimpleBooleanProperty(false);
    if (promptForColor) {
        colorPicker = new ColorPicker(originalColor);
        // If we don't touch the color picker, don't set the color (because it might be the default)
        colorPicker.valueProperty().addListener((v, o, n) -> colorChanged.set(true));
        panel.add(new Label("Color "), 0, 1);
        panel.add(colorPicker, 1, 1);
        colorPicker.prefWidthProperty().bind(textField.widthProperty());
    }
    Label labDescription = new Label("Description");
    TextArea textAreaDescription = new TextArea(annotation.getDescription());
    textAreaDescription.setPrefRowCount(3);
    textAreaDescription.setPrefColumnCount(25);
    labDescription.setLabelFor(textAreaDescription);
    panel.add(labDescription, 0, 2);
    panel.add(textAreaDescription, 1, 2);
    CheckBox cbLocked = new CheckBox("");
    cbLocked.setSelected(annotation.isLocked());
    Label labelLocked = new Label("Locked");
    panel.add(labelLocked, 0, 3);
    labelLocked.setLabelFor(cbLocked);
    panel.add(cbLocked, 1, 3);
    CheckBox cbAll = new CheckBox("");
    boolean hasOthers = otherAnnotations != null && !otherAnnotations.isEmpty();
    cbAll.setSelected(hasOthers);
    Label labelApplyToAll = new Label("Apply to all");
    cbAll.setTooltip(new Tooltip("Apply properties to all " + (otherAnnotations.size() + 1) + " selected annotations"));
    if (hasOthers) {
        panel.add(labelApplyToAll, 0, 4);
        labelApplyToAll.setLabelFor(cbAll);
        panel.add(cbAll, 1, 4);
    }
    if (!Dialogs.showConfirmDialog("Set annotation properties", panel))
        return false;
    List<PathAnnotationObject> toChange = new ArrayList<>();
    toChange.add(annotation);
    if (cbAll.isSelected())
        toChange.addAll(otherAnnotations);
    String name = textField.getText().trim();
    for (var temp : toChange) {
        if (name.length() > 0)
            temp.setName(name);
        else
            temp.setName(null);
        if (promptForColor && colorChanged.get())
            temp.setColorRGB(ColorToolsFX.getARGB(colorPicker.getValue()));
        // Set the description only if we have to
        String description = textAreaDescription.getText();
        if (description == null || description.isEmpty())
            temp.setDescription(null);
        else
            temp.setDescription(description);
        temp.setLocked(cbLocked.isSelected());
    }
    return true;
}
Also used : SimpleBooleanProperty(javafx.beans.property.SimpleBooleanProperty) GridPane(javafx.scene.layout.GridPane) ColorPicker(javafx.scene.control.ColorPicker) TextArea(javafx.scene.control.TextArea) Tooltip(javafx.scene.control.Tooltip) Label(javafx.scene.control.Label) ArrayList(java.util.ArrayList) PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) CheckBox(javafx.scene.control.CheckBox) TextField(javafx.scene.control.TextField)

Aggregations

PathAnnotationObject (qupath.lib.objects.PathAnnotationObject)19 PathObject (qupath.lib.objects.PathObject)16 ArrayList (java.util.ArrayList)11 ROI (qupath.lib.roi.interfaces.ROI)11 TMACoreObject (qupath.lib.objects.TMACoreObject)9 PathObjectHierarchy (qupath.lib.objects.hierarchy.PathObjectHierarchy)7 BufferedImage (java.awt.image.BufferedImage)6 List (java.util.List)6 TextArea (javafx.scene.control.TextArea)5 Tooltip (javafx.scene.control.Tooltip)5 IOException (java.io.IOException)4 Collections (java.util.Collections)4 Collectors (java.util.stream.Collectors)4 Point2D (java.awt.geom.Point2D)3 File (java.io.File)3 Collection (java.util.Collection)3 LinkedHashMap (java.util.LinkedHashMap)3 Bindings (javafx.beans.binding.Bindings)3 SimpleBooleanProperty (javafx.beans.property.SimpleBooleanProperty)3 Scene (javafx.scene.Scene)3