use of qupath.lib.roi.RoiEditor in project qupath by qupath.
the class PointsTool method mouseReleased.
@Override
public void mouseReleased(MouseEvent e) {
super.mouseReleased(e);
if (e.getButton() != MouseButton.PRIMARY || e.isConsumed()) {
return;
}
PointsROI points = getCurrentPoints();
if (points == null)
return;
var viewer = getViewer();
RoiEditor editor = viewer.getROIEditor();
editor.resetActiveHandle();
var currentObject = viewer.getSelectedObject();
viewer.getHierarchy().updateObject(currentObject, false);
// viewer.getHierarchy().fireHierarchyChangedEvent(this, vcurrentObject);
// // Find out the coordinates in the image domain & update the adjustment
// Point2D p = viewer.componentPointToImagePoint(e.getX(), e.getY(), null, false);
// points.finishAdjusting(p.getX(), p.getY(), e.isShiftDown());
// points.resetMeasurements();
}
use of qupath.lib.roi.RoiEditor in project qupath by qupath.
the class MoveTool method mouseReleased.
@Override
public void mouseReleased(MouseEvent e) {
super.mouseReleased(e);
if (e.isConsumed())
return;
var viewer = getViewer();
RoiEditor editor = viewer.getROIEditor();
if (editor != null && (editor.hasActiveHandle() || editor.isTranslating())) {
boolean roiChanged = (editor.isTranslating() && editor.finishTranslation()) || editor.hasActiveHandle();
editor.resetActiveHandle();
// if (editor.isTranslating())
// editor.finishTranslation();
e.consume();
PathObject pathObject = viewer.getSelectedObject();
if (requestParentClipping(e) && pathObject instanceof PathAnnotationObject) {
ROI roiNew = refineROIByParent(pathObject.getROI());
((PathAnnotationObject) pathObject).setROI(roiNew);
}
if (pathObject != null && pathObject.hasROI() && pathObject.getROI().isEmpty()) {
if (pathObject.getParent() != null)
viewer.getHierarchy().removeObject(pathObject, true);
viewer.setSelectedObject(null);
} else {
PathObjectHierarchy hierarchy = viewer.getHierarchy();
if (pathObject instanceof TMACoreObject) {
hierarchy.fireHierarchyChangedEvent(pathObject);
} else if (pathObject != null) {
// Handle ROI changes only if required
if (roiChanged) {
var updatedROI = editor.getROI();
if (pathObject.getROI() != updatedROI && pathObject instanceof PathROIObject)
((PathROIObject) pathObject).setROI(updatedROI);
// PathObject parentPrevious = pathObject.getParent();
hierarchy.removeObjectWithoutUpdate(pathObject, true);
if (getCurrentParent() == null || !PathPrefs.clipROIsForHierarchyProperty().get() || e.isShiftDown())
hierarchy.addPathObject(pathObject);
else
hierarchy.addPathObjectBelowParent(getCurrentParent(), pathObject, true);
// PathObject parentNew = pathObject.getParent();
// if (parentPrevious == parentNew)
// hierarchy.fireHierarchyChangedEvent(this, parentPrevious);
// else
// hierarchy.fireHierarchyChangedEvent(this);
}
}
viewer.setSelectedObject(pathObject);
}
}
// Optionally continue a dragging movement until the canvas comes to a standstill
if (pDragging != null && requestDynamicDragging && System.currentTimeMillis() - lastDragTimestamp < 100 && (dx * dx + dy * dy > viewer.getDownsampleFactor())) {
mover = new ViewerMover(viewer);
mover.startMoving(dx, dy, false);
} else
viewer.setDoFasterRepaint(false);
// Make sure we don't have a previous point (to prevent weird dragging artefacts)
pDragging = null;
// // If we were translating, stop
// if (editor.isTranslating()) {
// editor.finishTranslation();
// // TODO: Make this more efficient!
// viewer.getPathObjectHierarchy().fireHierarchyChangedEvent();
// return;
// }
}
use of qupath.lib.roi.RoiEditor in project qupath by qupath.
the class AbstractPathROITool method mousePressed.
@Override
public void mousePressed(MouseEvent e) {
super.mousePressed(e);
if (!e.isPrimaryButtonDown() || e.isConsumed()) {
return;
}
var viewer = getViewer();
PathObjectHierarchy hierarchy = viewer.getHierarchy();
if (hierarchy == null)
return;
PathObject currentObject = viewer.getSelectedObject();
ROI currentROI = currentObject == null ? null : currentObject.getROI();
RoiEditor editor = viewer.getROIEditor();
boolean adjustingPolygon = (currentROI instanceof PolygonROI || currentROI instanceof PolylineROI) && editor.getROI() == currentROI && (editor.isTranslating() || editor.hasActiveHandle());
// If we're adjusting a polygon/polyline with an appropriate tool, return at leave it up to the tool to handle the custom things
if (adjustingPolygon) {
if (viewer.getActiveTool() == PathTools.POLYGON || viewer.getActiveTool() == PathTools.POLYLINE)
return;
else {
viewer.getHierarchy().getSelectionModel().clearSelection();
viewer.getHierarchy().fireHierarchyChangedEvent(currentObject);
}
}
// Find out the coordinates in the image domain
Point2D p2 = mouseLocationToImage(e, false, requestPixelSnapping());
double xx = p2.getX();
double yy = p2.getY();
if (xx < 0 || yy < 0 || xx >= viewer.getServerWidth() || yy >= viewer.getServerHeight())
return;
// If we are double-clicking & we don't have a polygon, see if we can access a ROI
if (!PathPrefs.selectionModeProperty().get() && e.getClickCount() > 1) {
// Reset parent... for now
resetConstrainedAreaParent();
tryToSelect(xx, yy, e.getClickCount() - 2, false);
e.consume();
return;
}
// Set the current parent object based on the first click
setConstrainedAreaParent(hierarchy, xx, yy, Collections.emptyList());
// Create a new annotation
PathObject pathObject = createNewAnnotation(e, xx, yy);
if (pathObject == null)
return;
// Start editing the ROI immediately
editor.setROI(pathObject.getROI());
editor.grabHandle(xx, yy, viewer.getMaxROIHandleSize() * 1.5, e.isShiftDown());
}
use of qupath.lib.roi.RoiEditor 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.RoiEditor 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();
}
Aggregations