use of qupath.lib.roi.interfaces.ROI in project qupath by qupath.
the class MoveTool method mousePressed.
@Override
public void mousePressed(MouseEvent e) {
if (mover != null)
mover.stopMoving();
super.mousePressed(e);
if (!e.isPrimaryButtonDown() || e.isConsumed())
return;
var viewer = getViewer();
boolean snapping = false;
Point2D p = mouseLocationToImage(e, false, snapping);
double xx = p.getX();
double yy = p.getY();
// TODO: Consider whether Alt & the Shortcut key should both have the same effect
if (e.getClickCount() > 1 || e.isAltDown() || e.isShortcutDown()) {
boolean selected = false;
if (e.isAltDown() || e.isShortcutDown())
selected = tryToSelect(xx, yy, e.getClickCount() - 1, true, true);
else
selected = tryToSelect(xx, yy, e.getClickCount() - 2, false);
e.consume();
pDragging = null;
if (!selected && PathPrefs.doubleClickToZoomProperty().get()) {
double downsample = viewer.getDownsampleFactor();
if (e.isAltDown() || e.isShortcutDown())
downsample *= 2;
else
downsample /= 2;
viewer.setDownsampleFactor(downsample, e.getX(), e.getY());
}
return;
}
if (!viewer.isSpaceDown() && viewer.getHierarchy() != null) {
// Set the current parent object based on the first click
PathObject currentObject = viewer.getSelectedObject();
// PathObject parent = currentObject == null ? null : currentObject.getParent();
// if (parent != null && parent.isDetection())
// parent = null;
// setConstrainedAreaParent(viewer.getHierarchy(), parent, currentObject);
setConstrainedAreaParent(viewer.getHierarchy(), xx, yy, Collections.singleton(currentObject));
// See if we can get a handle to edit the ROI
// Don't want to edit detections / TMA cores
ROI currentROI = viewer.getCurrentROI();
RoiEditor editor = viewer.getROIEditor();
// Try dealing with having a ROI first
if (currentROI != null) {
if (editor.getROI() == currentROI) {
// 1.5 increases the range; the handle radius alone is too small a distance, especially if the handles are painted as squares -
// because 1.5 >~ sqrt(2) it ensures that at least the entire square is 'active' (and a bit beyond it)
double search = viewer.getMaxROIHandleSize() * 0.75;
// search = 1;
if (editor.grabHandle(xx, yy, search, e.isShiftDown()))
e.consume();
}
if (!e.isConsumed() && canAdjust(currentObject) && (RoiTools.areaContains(currentROI, xx, yy) || getSelectableObjectList(xx, yy).contains(currentObject))) {
// If we have a translatable ROI, try starting translation
if (editor.startTranslation(xx, yy, PathPrefs.usePixelSnappingProperty().get() && currentROI.isArea()))
e.consume();
}
if (e.isConsumed()) {
pDragging = null;
return;
}
}
}
// Store point for drag-to-pan
pDragging = p;
// viewer.setDoFasterRepaint(true); // Turn on if dragging is too slow
}
use of qupath.lib.roi.interfaces.ROI in project qupath by qupath.
the class MoveTool method mouseDragged.
@Override
public void mouseDragged(MouseEvent e) {
if (mover != null)
mover.stopMoving();
super.mouseDragged(e);
if (!e.isPrimaryButtonDown() || e.isConsumed())
return;
// Handle ROIs if the spacebar isn't down
var viewer = getViewer();
if (!viewer.isSpaceDown()) {
RoiEditor editor = viewer.getROIEditor();
Point2D p = mouseLocationToImage(e, true, false);
// Try moving handle
if (editor != null && editor.hasActiveHandle()) {
double x = p.getX();
double y = p.getY();
if (PathPrefs.usePixelSnappingProperty().get() && editor.getROI() != null && editor.getROI().isArea()) {
x = (int) x;
y = (int) y;
}
ROI updatedROI = editor.setActiveHandlePosition(x, y, viewer.getDownsampleFactor() / 2.0, e.isShiftDown());
if (updatedROI == null)
// This shouldn't occur...?
logger.warn("Updated ROI is null! Will be skipped...");
else {
PathObject selectedObject = viewer.getSelectedObject();
if (selectedObject.getROI() != updatedROI && selectedObject instanceof PathROIObject)
((PathROIObject) selectedObject).setROI(updatedROI);
// TODO: Check event firing frequency!
viewer.getHierarchy().fireObjectsChangedEvent(this, Collections.singleton(selectedObject), true);
// viewer.repaint();
e.consume();
return;
}
}
// Try to translate, if that's what is happening
ROI currentROI = viewer.getCurrentROI();
if (editor != null && editor.isTranslating()) {
Rectangle2D boundsBefore = AwtTools.getBounds2D(currentROI);
ROI translatedROI = editor.updateTranslation(p.getX(), p.getY(), viewer.getServerBounds());
if (translatedROI != null) {
Rectangle2D boundsAfter = AwtTools.getBounds2D(currentROI);
Rectangle2D boundsIntersection = new Rectangle2D.Double();
Rectangle2D.union(boundsBefore, boundsAfter, boundsIntersection);
((PathROIObject) viewer.getSelectedObject()).setROI(translatedROI);
viewer.getHierarchy().fireObjectsChangedEvent(this, Collections.singleton(viewer.getSelectedObject()), true);
// System.err.println("Changing... " + viewer.getHierarchy().nObjects());
// viewer.repaintImageRegion(boundsIntersection, false);
}
pDragging = null;
return;
}
// Try to select objects, if alt is down
if (e.isAltDown()) {
tryToSelect(p.getX(), p.getY(), e.getClickCount() - 1, true, false);
e.consume();
return;
}
}
// Don't allow dragging if 'zoom to fit' selected
if (viewer.getZoomToFit())
return;
// If we don't have a previous point, we aren't dragging (e.g. there was an alt-click)
if (pDragging == null)
return;
// Extract previous coordinates so we can reuse the Point2D object
double xPrevious = pDragging.getX();
double yPrevious = pDragging.getY();
// Calculate how much the image was dragged
pDragging = mouseLocationToImage(e, false, false);
dx = pDragging.getX() - xPrevious;
dy = pDragging.getY() - yPrevious;
// Update the viewer
viewer.setDoFasterRepaint(true);
viewer.setCenterPixelLocation(viewer.getCenterPixelX() - dx, viewer.getCenterPixelY() - dy);
// viewer.setDoFasterRepaint(false);
pDragging = mouseLocationToImage(e, false, false);
lastDragTimestamp = System.currentTimeMillis();
}
use of qupath.lib.roi.interfaces.ROI in project qupath by qupath.
the class AbstractPathDraggingROITool method mouseDragged.
@Override
public void mouseDragged(MouseEvent e) {
super.mouseDragged(e);
if (!e.isPrimaryButtonDown()) {
return;
}
var viewer = getViewer();
ROI currentROI = viewer.getCurrentROI() instanceof ROI ? (ROI) viewer.getCurrentROI() : null;
RoiEditor editor = viewer.getROIEditor();
if (currentROI != null && editor.getROI() == currentROI && editor.hasActiveHandle()) {
PathObject pathObject = viewer.getSelectedObject();
Point2D p = mouseLocationToImage(e, true, requestPixelSnapping());
ROI roiUpdated = editor.setActiveHandlePosition(p.getX(), p.getY(), 0.25, e.isShiftDown());
if (roiUpdated != currentROI) {
((PathROIObject) pathObject).setROI(roiUpdated);
viewer.repaint();
}
viewer.getHierarchy().fireObjectsChangedEvent(this, Collections.singleton(pathObject), true);
// editor.setActiveHandlePosition(x, y, minDisplacement, shiftDown)
// currentROI.updateAdjustment(p.getX(), p.getY(), e.isShiftDown());
viewer.repaint();
}
}
use of qupath.lib.roi.interfaces.ROI 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;
}
use of qupath.lib.roi.interfaces.ROI in project qupath by qupath.
the class PointsTool method handleAltClick.
/**
* Alt-clicks remove the selected point, or selects a new 'family' of points (i.e. a different object) if
* a point from the current object isn't clicked.
*
* @param x
* @param y
* @param currentObject
* @return
*/
private boolean handleAltClick(double x, double y, PathObject currentObject) {
var viewer = getViewer();
var viewerPlane = viewer.getImagePlane();
PathObjectHierarchy hierarchy = viewer.getHierarchy();
double distance = PathPrefs.pointRadiusProperty().get();
// Remove a point if the current selection has one
if (currentObject != null && PathObjectTools.hasPointROI(currentObject)) {
PointsROI points = (PointsROI) currentObject.getROI();
if (points.getImagePlane().equals(viewerPlane)) {
ROI points2 = removeNearbyPoint(points, x, y, distance);
if (points != points2) {
((PathROIObject) currentObject).setROI(points2);
hierarchy.updateObject(currentObject, false);
// hierarchy.fireHierarchyChangedEvent(this, currentObject);
return true;
}
}
}
// Activate a points object if there is one
for (PathObject pathObject : hierarchy.getPointObjects(PathObject.class)) {
// Don't check the current object again
if (pathObject == currentObject || !pathObject.getROI().getImagePlane().equals(viewerPlane))
continue;
// See if we've almost clicked on a point
if (((PointsROI) pathObject.getROI()).getNearest(x, y, distance) != null) {
viewer.setSelectedObject(pathObject);
// hierarchy.getSelectionModel().setSelectedPathObject(pathObject);
return true;
}
}
// Select nothing
viewer.setSelectedObject(null);
return true;
}
Aggregations