use of qupath.lib.objects.PathObject in project qupath by qupath.
the class PathObjectTileCache method removeFromCache.
/**
* This doesn't acquire the lock! The locking is done first.
*
* @param pathObject
* @param removeChildren
*/
private void removeFromCache(PathObject pathObject, boolean removeChildren) {
// If the cache isn't active, then nothing to remove
if (!isActive())
return;
SpatialIndex mapObjects = map.get(pathObject.getClass());
// We can remove objects from a Quadtree
if (mapObjects instanceof Quadtree) {
Envelope envelope = lastEnvelopeMap.get(pathObject);
envelope = MAX_ENVELOPE;
if (envelope != null) {
if (mapObjects.remove(envelope, pathObject)) {
logger.debug("Removed {} from cache", pathObject);
} else
logger.debug("Unable to remove {} from cache", pathObject);
} else {
logger.debug("No envelope found for {}", pathObject);
}
// Remove the children
if (removeChildren) {
for (PathObject child : pathObject.getChildObjectsAsArray()) removeFromCache(child, removeChildren);
}
} else if (mapObjects instanceof SpatialIndex && !removeChildren) {
// We can't remove objects from a STRtree, but since we're just removing one object we can rebuild only the cache for this class
constructCache(pathObject.getClass());
} else {
// If we need to remove multiple objects, better to just rebuild the entire cache
constructCache(null);
}
}
use of qupath.lib.objects.PathObject in project qupath by qupath.
the class PathObjectHierarchy method addPathObjects.
/**
* Add multiple objects to the hierarchy.
* @param pathObjects
* @return
*/
public synchronized boolean addPathObjects(Collection<? extends PathObject> pathObjects) {
boolean changes = false;
int n = pathObjects.size();
int counter = 0;
for (PathObject pathObject : pathObjects) {
if (n > 10000) {
if (counter % 1000 == 0)
logger.debug("Adding {} of {}", counter, n);
} else if (n > 1000 && counter % 100 == 0)
logger.debug("Adding {} of {}", counter, n);
changes = addPathObjectToList(getRootObject(), pathObject, false) || changes;
counter++;
}
if (changes)
fireHierarchyChangedEvent(getRootObject());
// fireChangeEvent(getRootObject());
return changes;
}
use of qupath.lib.objects.PathObject in project qupath by qupath.
the class PathObjectHierarchy method insertPathObject.
/**
* Insert a path object at the appropriate place in the hierarchy, without making other changes.
* @param pathObjectParent the first potential parent; this can be used to help filter out 'impossible' parents to aid performance
* @param pathObject the object to insert
* @param fireChangeEvents if true, fire hierarchy change events after inserting the object
* @param resetCache if true, reset the tile cache after adding the object; this is only used if fireChangeEvents is false
* @return
*/
private synchronized boolean insertPathObject(PathObject pathObjectParent, PathObject pathObject, boolean fireChangeEvents, boolean resetCache) {
if (pathObject.isTMACore()) {
logger.warn("TMA core objects cannot be inserted - use resolveHierarchy() instead");
return false;
}
// Get all the annotations that might be a parent of this object
var region = ImageRegion.createInstance(pathObject.getROI());
Collection<PathObject> tempSet = new HashSet<>();
tempSet.add(getRootObject());
tileCache.getObjectsForRegion(PathAnnotationObject.class, region, tempSet, true);
if (tmaGrid != null)
tileCache.getObjectsForRegion(TMACoreObject.class, region, tempSet, true);
if (pathObjectParent != null) {
tempSet.removeIf(p -> p != pathObjectParent && !PathObjectTools.isAncestor(p, pathObjectParent));
}
var possibleParentObjects = new ArrayList<PathObject>(tempSet);
Collections.sort(possibleParentObjects, HIERARCHY_COMPARATOR);
for (PathObject possibleParent : possibleParentObjects) {
if (possibleParent == pathObject || possibleParent.isDetection())
continue;
boolean addObject;
if (possibleParent.isRootObject()) {
// If we've reached the root, definitely add
addObject = true;
} else {
// If we're adding a detection, check centroid; otherwise check covers
if (pathObject.isDetection())
addObject = tileCache.containsCentroid(possibleParent, pathObject);
else
addObject = pathObjectParent != null && possibleParent == pathObjectParent || tileCache.covers(possibleParent, pathObject);
}
if (addObject) {
// Don't add if we're already where we should be
if (pathObject.getParent() == possibleParent)
return false;
// Reassign child objects if we need to
Collection<PathObject> previousChildren = pathObject.isDetection() ? new ArrayList<>() : new ArrayList<>(possibleParent.getChildObjects());
// Can't reassign TMA core objects (these must be directly below the root object)
previousChildren.removeIf(p -> p.isTMACore());
// Beware that we could have 'orphaned' detections
if (possibleParent.isTMACore())
possibleParent.getParent().getChildObjects().stream().filter(p -> p.isDetection()).forEach(previousChildren::add);
possibleParent.addPathObject(pathObject);
if (!previousChildren.isEmpty()) {
pathObject.addPathObjects(filterObjectsForROI(pathObject.getROI(), previousChildren));
}
// Notify listeners of changes, if required
if (fireChangeEvents)
fireObjectAddedEvent(this, pathObject);
else if (resetCache)
tileCache.resetCache();
return true;
}
}
return true;
}
use of qupath.lib.objects.PathObject in project qupath by qupath.
the class PathObjectSelectionModel method setSelectedObject.
/**
* Set the specified object to be selected, deselecting all others.
* @param pathObject
*/
public void setSelectedObject(PathObject pathObject) {
// Here we fire even when the object is the same... this is because sometimes the object is selected but not
// in the hierarchy - and some listeners respond differently depending upon which is the case
// if (this.pathObjectSelected == pathObject)
// return;
PathObject previousObject = pathObjectSelected;
pathObjectSelected = pathObject;
selectedSet.clear();
if (pathObjectSelected != null)
selectedSet.add(pathObjectSelected);
firePathObjectSelectionChangedEvent(pathObjectSelected, previousObject);
}
use of qupath.lib.objects.PathObject in project qupath by qupath.
the class PathObjectSelectionModel method deselectObject.
/**
* Ensure that the specified object is removed from the selection.
* @param pathObject
*/
public void deselectObject(PathObject pathObject) {
PathObject previousSelected = pathObjectSelected;
boolean changes = selectedSet.remove(pathObject);
if (pathObjectSelected == previousSelected) {
pathObjectSelected = null;
updateToLastSelectedObject();
changes = true;
}
if (changes)
firePathObjectSelectionChangedEvent(pathObjectSelected, previousSelected);
}
Aggregations