Search in sources :

Example 16 with Point2

use of qupath.lib.geom.Point2 in project qupath by qupath.

the class PathHierarchyPaintingHelper method paintPoints.

private static void paintPoints(ROI pathPoints, Graphics2D g2d, double radius, Color colorStroke, Stroke stroke, Color colorFill, double downsample) {
    PointsROI pathPointsROI = pathPoints instanceof PointsROI ? (PointsROI) pathPoints : null;
    if (pathPointsROI != null && PathPrefs.showPointHullsProperty().get()) {
        ROI convexHull = pathPointsROI.getConvexHull();
        if (convexHull != null) {
            Color colorHull = colorFill != null ? colorFill : colorStroke;
            colorHull = ColorToolsAwt.getColorWithOpacity(colorHull, 0.1);
            if (colorHull != null)
                paintShape(RoiTools.getShape(convexHull), g2d, null, null, colorHull);
        // getConvexHull().draw(g, null, colorHull);
        }
    }
    RectangularShape ellipse;
    // double radius = pathPointsROI == null ? PointsROI.defaultPointRadiusProperty().get() : pathPointsROI.getPointRadius();
    // Ensure that points are drawn with at least a radius of one, after any transforms have been applied
    double scale = Math.max(1, downsample);
    radius = (Math.max(1 / scale, radius));
    // Get clip bounds
    Rectangle2D bounds = g2d.getClipBounds();
    if (bounds != null) {
        bounds.setRect(bounds.getX() - radius, bounds.getY() - radius, bounds.getWidth() + radius * 2, bounds.getHeight() + radius * 2);
    }
    // Don't fill if we have a small radius, and use a rectangle instead of an ellipse (as this repaints much faster)
    Graphics2D g = g2d;
    if (radius / downsample < 0.5) {
        if (colorStroke == null)
            colorStroke = colorFill;
        colorFill = null;
        ellipse = new Rectangle2D.Double();
        // Use opacity to avoid obscuring points completely
        int rule = AlphaComposite.SRC_OVER;
        float alpha = (float) (radius / downsample);
        var composite = g.getComposite();
        if (composite instanceof AlphaComposite) {
            var temp = (AlphaComposite) composite;
            rule = temp.getRule();
            alpha = temp.getAlpha() * alpha;
        }
        // If we are close to completely transparent, do not paint
        if (alpha < 0.01f)
            return;
        composite = AlphaComposite.getInstance(rule, alpha);
        g = (Graphics2D) g2d.create();
        g.setComposite(composite);
    // ellipse = new Ellipse2D.Double();
    } else
        ellipse = new Ellipse2D.Double();
    g.setStroke(stroke);
    for (Point2 p : pathPoints.getAllPoints()) {
        if (bounds != null && !bounds.contains(p.getX(), p.getY()))
            continue;
        ellipse.setFrame(p.getX() - radius, p.getY() - radius, radius * 2, radius * 2);
        if (colorFill != null) {
            g.setColor(colorFill);
            g.fill(ellipse);
        }
        if (colorStroke != null) {
            g.setColor(colorStroke);
            g.draw(ellipse);
        }
    }
    if (g != g2d)
        g.dispose();
}
Also used : AlphaComposite(java.awt.AlphaComposite) Color(java.awt.Color) Rectangle2D(java.awt.geom.Rectangle2D) PointsROI(qupath.lib.roi.PointsROI) EllipseROI(qupath.lib.roi.EllipseROI) PointsROI(qupath.lib.roi.PointsROI) RectangleROI(qupath.lib.roi.RectangleROI) LineROI(qupath.lib.roi.LineROI) ROI(qupath.lib.roi.interfaces.ROI) Graphics2D(java.awt.Graphics2D) Point2(qupath.lib.geom.Point2) RectangularShape(java.awt.geom.RectangularShape)

Example 17 with Point2

use of qupath.lib.geom.Point2 in project qupath by qupath.

the class PointIO method readPointsObjectFromString.

/**
 * Helper method for readPointsObjectList(), will be removed in future releases.
 * @param s
 * @return
 */
@Deprecated
private static PathObject readPointsObjectFromString(String s) {
    List<Point2> pointsList = new ArrayList<>();
    Scanner scanner = new Scanner(s);
    String name = scanner.nextLine().split("\t")[1].trim();
    Integer color = Integer.parseInt(scanner.nextLine().split("\t")[1]);
    // Skip the coordinate count line...
    int count = Integer.parseInt(scanner.nextLine().split("\t")[1]);
    while (scanner.hasNextLine()) {
        String line = scanner.nextLine().trim();
        if (line.length() == 0)
            break;
        String[] splits = line.split("\t");
        double x = Double.parseDouble(splits[0]);
        double y = Double.parseDouble(splits[1]);
        pointsList.add(new Point2(x, y));
    }
    scanner.close();
    if (count != pointsList.size())
        logger.warn("Warning: {} points expected, {} points found", count, pointsList.size());
    ROI points = ROIs.createPointsROI(pointsList, ImagePlane.getDefaultPlane());
    PathObject pathObject = PathObjects.createAnnotationObject(points);
    if (name != null && name.length() > 0 && !"null".equals(name))
        pathObject.setName(name);
    pathObject.setColorRGB(color);
    return pathObject;
}
Also used : Scanner(java.util.Scanner) Point2(qupath.lib.geom.Point2) PathObject(qupath.lib.objects.PathObject) ArrayList(java.util.ArrayList) PointsROI(qupath.lib.roi.PointsROI) ROI(qupath.lib.roi.interfaces.ROI)

Example 18 with Point2

use of qupath.lib.geom.Point2 in project qupath by qupath.

the class PathObjectTools method containsROI.

/**
 * Test whether one ROI is can completely contain a second ROI.
 * Returns false if either ROI is null.
 * <p>
 * Note: This is not a perfect test, since it really only checks if the vertices of the child ROI fall within the parent - it is possible
 * that connecting lines stray outside the parent, yet it still returns true.  This behavior may change in later versions.
 * <p>
 * TODO: Consider improving 'containsROI' method accuracy.
 *
 * @param parentROI
 * @param childROI
 * @return
 */
@Deprecated
public static boolean containsROI(final ROI parentROI, final ROI childROI) {
    // Check for nulls... just to be sure
    if (parentROI == null || childROI == null || !parentROI.isArea() || childROI.isEmpty() || parentROI.isEmpty())
        return false;
    // Check points
    if (childROI != null && childROI.isPoint()) {
        for (Point2 p : childROI.getAllPoints()) {
            if (!parentROI.contains(p.getX(), p.getY()))
                return false;
        }
        return true;
    }
    // Check areas - child can't have a larger area
    if (childROI.isArea()) {
        if (childROI.getArea() > parentROI.getArea())
            return false;
    }
    // Check bounds dimensions
    if (childROI.getBoundsWidth() > parentROI.getBoundsWidth() || childROI.getBoundsHeight() > parentROI.getBoundsHeight())
        return false;
    // Check bounds
    double px = parentROI.getBoundsX();
    double py = parentROI.getBoundsY();
    double px2 = px + parentROI.getBoundsWidth();
    double py2 = py + parentROI.getBoundsHeight();
    double cx = childROI.getBoundsX();
    double cy = childROI.getBoundsY();
    double cx2 = px + childROI.getBoundsWidth();
    double cy2 = py + childROI.getBoundsHeight();
    if (!(cx >= px && cx2 <= px2 && cy >= py && cy2 <= py2))
        return false;
    // Check shapes
    for (Point2 p : childROI.getAllPoints()) {
        if (!parentROI.contains(p.getX(), p.getY()))
            return false;
    }
    if (parentROI.isArea() && childROI.isArea())
        return parentROI.getGeometry().covers(childROI.getGeometry());
    // }
    return true;
// logger.info("Doing standard (AWT) test...");
// return PathROIToolsAwt.containsShape(parentArea, (PathShape)childROI);
// return false;
// // Check for lines
// if (childROI instanceof PathLineROI) {
// PathLineROI line = (PathLineROI)childROI;
// return parentROI.contains(line.getX1(), line.getY1()) && parentROI.contains(line.getX2(), line.getY2());
// }
// 
// // If we have areas, check these
// if (parentROI instanceof PathArea && childROI instanceof PathArea) {
// double area = ((PathArea)parentROI).getArea();
// if (!Double.isNaN(area) && area < ((PathArea)childROI).getArea())
// return false;
// }
// 
// // Check bounds
// //		if (!parentROI.getBounds2D().contains(childROI.getBounds2D())
// Rectangle2D childBounds = childROI.getBounds2D();
// if (!parentROI.intersects(childBounds))
// return false;
// 
// // If we have shapes, do a proper test
// if ((parentROI instanceof PathShape) && (childROI instanceof PathShape)) {
// PathShape parentShape = (PathShape)parentROI;
// if (parentShape.contains(childBounds))
// return true;
// PathShape childShape = (PathShape)childROI;
// Area areaDifference = parentShape.getShapeAsArea();
// areaDifference.subtract(childShape.getShapeAsArea());
// return areaDifference.isEmpty();
// }
// return true;
}
Also used : Point2(qupath.lib.geom.Point2)

Example 19 with Point2

use of qupath.lib.geom.Point2 in project qupath by qupath.

the class PathObjectTools method mergePointsForSelectedObjectClasses.

// private static void addPathObjectsRecursively(Collection<PathObject> pathObjectsInput, Collection<PathObject> pathObjects, Class<? extends PathObject> cls) {
// Collection<PathObject> buffer = null;
// for (PathObject childObject : pathObjectsInput) {
// if (cls == null || cls.isInstance(childObject)) {
// pathObjects.add(childObject);
// }
// if (childObject.hasChildren()) {
// if (buffer == null)
// buffer = new ArrayList<>();
// else
// buffer.clear();
// childObject.getChildObjects(buffer);
// addPathObjectsRecursively(buffer, pathObjects, cls);
// }
// }
// }
// /**
// * Split annotations containing multi-point ROIs into separate single-point ROIs.
// *
// * @param hierarchy the object hierarchy
// * @param selectedOnly if true, consider only annotations that are currently selected; if false, consider all point annotations in the hierarchy
// * @return true if changes are made to the hierarchy, false otherwise
// */
// public static boolean splitPoints(PathObjectHierarchy hierarchy, boolean selectedOnly) {
// if (hierarchy == null) {
// logger.debug("No hierarchy available, cannot split points!");
// return false;
// }
// return splitPoints(hierarchy, selectedOnly ? hierarchy.getSelectionModel().getSelectedObjects() : hierarchy.getAnnotationObjects());
// }
// 
// /**
// * Split annotations containing multi-point ROIs into separate single-point ROIs.
// *
// * @param hierarchy the object hierarchy
// * @param pathObjects a collection of point annotations to split; non-points and non-annotations will be ignored
// * @return pathObjects if changes are made to the hierarchy, false otherwise
// */
// public static boolean splitPoints(PathObjectHierarchy hierarchy, Collection<PathObject> pathObjects) {
// var points = pathObjects.stream().filter(p -> p.isAnnotation() && p.getROI().isPoint() && p.getROI().getNumPoints() > 1).collect(Collectors.toList());
// if (points.isEmpty()) {
// logger.debug("No (multi)point ROIs available to split!");
// return false;
// }
// List<PathObject> newObjects = new ArrayList<>();
// for (PathObject pathObject : points) {
// ROI p = pathObject.getROI();
// ImagePlane plane = p.getImagePlane();
// PathClass pathClass = pathObject.getPathClass();
// for (Point2 p2 : p.getAllPoints()) {
// PathObject temp = PathObjects.createAnnotationObject(ROIs.createPointsROI(p2.getX(), p2.getY(), plane), pathClass);
// newObjects.add(temp);
// }
// }
// hierarchy.removeObjects(points, true);
// hierarchy.addPathObjects(newObjects);
// // Reset the selection
// hierarchy.getSelectionModel().clearSelection();
// return true;
// }
/**
 * Merge point annotations sharing the same {@link PathClass} and {@link ImagePlane} as the selected annotations,
 * creating multi-point annotations for all matching points and removing the (previously-separated) annotations.
 *
 * @param hierarchy object hierarchy to modify
 * @return true if changes are made to the hierarchy, false otherwise
 */
public static boolean mergePointsForSelectedObjectClasses(PathObjectHierarchy hierarchy) {
    var pathClasses = hierarchy.getSelectionModel().getSelectedObjects().stream().filter(p -> p.isAnnotation() && p.getROI().isPoint()).map(p -> p.getPathClass()).collect(Collectors.toSet());
    boolean changes = false;
    for (PathClass pathClass : pathClasses) changes = changes || mergePointsForClass(hierarchy, pathClass);
    return changes;
}
Also used : PathClassTools(qupath.lib.objects.classes.PathClassTools) LoggerFactory(org.slf4j.LoggerFactory) HashMap(java.util.HashMap) PathClassFactory(qupath.lib.objects.classes.PathClassFactory) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) Function(java.util.function.Function) ArrayList(java.util.ArrayList) MeasurementList(qupath.lib.measurements.MeasurementList) EllipseROI(qupath.lib.roi.EllipseROI) HashSet(java.util.HashSet) ROIs(qupath.lib.roi.ROIs) PointsROI(qupath.lib.roi.PointsROI) Point2(qupath.lib.geom.Point2) ImageRegion(qupath.lib.regions.ImageRegion) Map(java.util.Map) PreparedGeometry(org.locationtech.jts.geom.prep.PreparedGeometry) LinkedHashSet(java.util.LinkedHashSet) LineROI(qupath.lib.roi.LineROI) Line2D(java.awt.geom.Line2D) RoiTools(qupath.lib.roi.RoiTools) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) Predicate(java.util.function.Predicate) Collection(java.util.Collection) PathClass(qupath.lib.objects.classes.PathClass) Set(java.util.Set) AffineTransform(java.awt.geom.AffineTransform) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) ROI(qupath.lib.roi.interfaces.ROI) List(java.util.List) Entry(java.util.Map.Entry) ImagePlane(qupath.lib.regions.ImagePlane) Geometry(org.locationtech.jts.geom.Geometry) Comparator(java.util.Comparator) TMAGrid(qupath.lib.objects.hierarchy.TMAGrid) Collections(java.util.Collections) PreparedGeometryFactory(org.locationtech.jts.geom.prep.PreparedGeometryFactory) STRtree(org.locationtech.jts.index.strtree.STRtree) PathClass(qupath.lib.objects.classes.PathClass)

Example 20 with Point2

use of qupath.lib.geom.Point2 in project qupath by qupath.

the class CountingPane method copyCoordinatesToClipboard.

public static void copyCoordinatesToClipboard(PathObject pathObject) {
    // PathObject pathObject = viewer.getPathObjectHierarchy().getSelectionModel().getSelectedPathObject();
    if (pathObject == null || !pathObject.hasROI() || !(pathObject.getROI() instanceof PointsROI)) {
        Dialogs.showErrorMessage("Copy points to clipboard", "No points selected!");
        return;
    }
    StringBuilder sb = new StringBuilder();
    String name = pathObject.getDisplayedName();
    PointsROI points = (PointsROI) pathObject.getROI();
    for (Point2 p : points.getAllPoints()) sb.append(name).append("\t").append(p.getX()).append("\t").append(p.getY()).append("\n");
    StringSelection stringSelection = new StringSelection(sb.toString());
    Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
    clipboard.setContents(stringSelection, null);
}
Also used : Point2(qupath.lib.geom.Point2) PointsROI(qupath.lib.roi.PointsROI) Clipboard(java.awt.datatransfer.Clipboard) StringSelection(java.awt.datatransfer.StringSelection)

Aggregations

Point2 (qupath.lib.geom.Point2)33 ArrayList (java.util.ArrayList)19 PathObject (qupath.lib.objects.PathObject)7 List (java.util.List)6 PointsROI (qupath.lib.roi.PointsROI)6 ROI (qupath.lib.roi.interfaces.ROI)6 HashMap (java.util.HashMap)5 ImagePlane (qupath.lib.regions.ImagePlane)5 Map (java.util.Map)4 PathClass (qupath.lib.objects.classes.PathClass)4 PathClassFactory (qupath.lib.objects.classes.PathClassFactory)4 ROIs (qupath.lib.roi.ROIs)4 PathIterator (java.awt.geom.PathIterator)3 IOException (java.io.IOException)3 Arrays (java.util.Arrays)3 HashSet (java.util.HashSet)3 Collectors (java.util.stream.Collectors)3 Test (org.junit.jupiter.api.Test)3 PathObjects (qupath.lib.objects.PathObjects)3 AlphaComposite (java.awt.AlphaComposite)2