use of qupath.lib.gui.viewer.overlays.AbstractOverlay in project qupath by qupath.
the class QuPathViewer method paintViewer.
protected void paintViewer(Graphics g, int w, int h) {
ImageServer<BufferedImage> server = getServer();
if (server == null) {
g.setColor(background);
g.fillRect(0, 0, w, h);
updateRepaintTimestamp();
return;
}
// // Get dimensions
// int w = getWidth();
// int h = getHeight();
Rectangle clip = g.getClipBounds();
boolean clipFull;
if (clip == null) {
clip = new Rectangle(0, 0, w, h);
g.setClip(0, 0, w, h);
clipFull = true;
} else
clipFull = clip.x == 0 && clip.y == 0 && clip.width == w && clip.height == h;
// Ensure we have a sufficiently-large buffer
if (imgBuffer == null || imgBuffer.getWidth() != w || imgBuffer.getHeight() != h) {
// Create buffered images & buffers for RGB pixel values
imgBuffer = createBufferedImage(w, h);
imgBuffer.setAccelerationPriority(1f);
logger.trace("New buffered image created: {}", imgBuffer);
// imgVolatile = createVolatileImage(w, h);
imageUpdated = true;
// If the size changed, ensure the AffineTransform is up-to-date
updateAffineTransform();
}
// Get the displayed region
Shape shapeRegion = getDisplayedRegionShape();
// The visible shape must have changed if there wasn't one previously...
// Otherwise check if it has changed & update accordingly
// This will be used to notify listeners soon
boolean shapeChanged = lastVisibleShape == null || !lastVisibleShape.equals(shapeRegion);
long t1 = System.currentTimeMillis();
// Only repaint the image if this is requested, otherwise only overlays need to be repainted
if (imageUpdated || locationUpdated) {
// || imgVolatile.contentsLost()) {
// Set flags that image no longer requiring an update
// By setting them early, they might still be reset during this run... in which case we don't want to thwart the re-run
imageUpdated = false;
locationUpdated = false;
// updateBufferedImage(imgVolatile, shapeRegion, w, h);
updateBufferedImage(imgBuffer, shapeRegion, w, h);
}
// if (imageUpdated || locationUpdated) {
// updateBufferedImage(imgVolatile, shapeRegion, w, h);
// // updateBufferedImage(imgBuffer, shapeRegion, w, h);
// // logger.info("INITIAL Image drawing time: " + (System.currentTimeMillis() - t1));
// imgVolatile.createGraphics().drawImage(imgBuffer, 0, 0, this);
// }
// while (imgVolatile.contentsLost()) {
// imgVolatile.createGraphics().drawImage(imgBuffer, 0, 0, this);
// }
// Store the last shape visible
lastVisibleShape = shapeRegion;
// Draw the image from the buffer
// The call to super.paintComponent is delayed until here to try to stop occasional flickering on Apple's Java 6
g.setColor(background);
if (clipFull)
paintFinalImage(g, imgBuffer, this);
else
// g2d.drawImage(imgBuffer, 0, 0, getWidth(), getHeight(), this);
g.drawImage(imgBuffer, clip.x, clip.y, clip.x + clip.width, clip.y + clip.height, clip.x, clip.y, clip.x + clip.width, clip.y + clip.height, null);
if (logger.isTraceEnabled()) {
long t2 = System.currentTimeMillis();
logger.trace("Final image drawing time: {}", (t2 - t1));
}
// Really useful only for debugging graphics
if (!(g instanceof Graphics2D)) {
imageUpdated = false;
// Notify any listeners of shape changes
if (shapeChanged)
fireVisibleRegionChangedEvent(lastVisibleShape);
return;
}
double downsample = getDownsampleFactor();
float opacity = overlayOptions.getOpacity();
Graphics2D g2d = (Graphics2D) g.create();
// Apply required transform to the graphics object (rotation, scaling, shifting...)
g2d.transform(transform);
Composite previousComposite = g2d.getComposite();
boolean paintCompletely = thumbnailIsFullImage || !doFasterRepaint;
// var regionBounds = AwtTools.getImageRegion(clip, getZPosition(), getTPosition());
if (opacity > 0 || PathPrefs.alwaysPaintSelectedObjectsProperty().get()) {
if (opacity < 1) {
AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity);
g2d.setComposite(composite);
}
Color color = getSuggestedOverlayColor();
// Paint the overlay layers
var imageData = this.imageDataProperty.get();
for (PathOverlay overlay : allOverlayLayers.toArray(PathOverlay[]::new)) {
logger.trace("Painting overlay: {}", overlay);
if (overlay instanceof AbstractOverlay)
((AbstractOverlay) overlay).setPreferredOverlayColor(color);
// overlay.paintOverlay(g2d, regionBounds, downsample, null, paintCompletely);
overlay.paintOverlay(g2d, getServerBounds(), downsample, imageData, paintCompletely);
}
// if (hierarchyOverlay != null) {
// hierarchyOverlay.setPreferredOverlayColor(color);
// hierarchyOverlay.paintOverlay(g2d, getServerBounds(), downsampleFactor, null, paintCompletely);
// }
}
// Paint the selected object
PathObjectHierarchy hierarchy = getHierarchy();
PathObject mainSelectedObject = getSelectedObject();
Rectangle2D boundsRect = null;
boolean useSelectedColor = PathPrefs.useSelectedColorProperty().get();
boolean paintSelectedBounds = PathPrefs.paintSelectedBoundsProperty().get();
for (PathObject selectedObject : hierarchy.getSelectionModel().getSelectedObjects().toArray(new PathObject[0])) {
// TODO: Simplify this...
if (selectedObject != null && selectedObject.hasROI() && selectedObject.getROI().getZ() == getZPosition() && selectedObject.getROI().getT() == getTPosition()) {
if (!selectedObject.isDetection()) {
// Ensure a selected ROI can be seen clearly
if (previousComposite != null)
g2d.setComposite(previousComposite);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}
Rectangle boundsDisplayed = shapeRegion.getBounds();
ROI pathROI = selectedObject.getROI();
// if ((PathPrefs.getPaintSelectedBounds() || (selectedObject.isDetection() && !PathPrefs.getUseSelectedColor())) && !(pathROI instanceof RectangleROI)) {
if (pathROI != null && (paintSelectedBounds || (!useSelectedColor)) && !(pathROI instanceof RectangleROI) && !pathROI.isEmpty()) {
Shape boundsShape = null;
if (pathROI.isPoint()) {
var hull = pathROI.getConvexHull();
if (hull != null)
boundsShape = hull.getShape();
}
if (boundsShape == null) {
boundsRect = AwtTools.getBounds2D(pathROI, boundsRect);
boundsShape = boundsRect;
}
// Tried to match to pixel boundaries... but resulted in too much jiggling
// boundsShape.setFrame(
// Math.round(boundsShape.getX()/downsampleFactor)*downsampleFactor-downsampleFactor,
// Math.round(boundsShape.getY()/downsampleFactor)*downsampleFactor-downsampleFactor,
// Math.round(boundsShape.getWidth()/downsampleFactor)*downsampleFactor+2*downsampleFactor,
// Math.round(boundsShape.getHeight()/downsampleFactor)*downsampleFactor+2*downsampleFactor);
// boundsShape.setFrame(boundsShape.getX()-downsampleFactor, boundsShape.getY()-downsampleFactor, boundsShape.getWidth()+2*downsampleFactor, boundsShape.getHeight()+2*downsampleFactor);
PathHierarchyPaintingHelper.paintShape(boundsShape, g2d, getSuggestedOverlayColor(), PathHierarchyPaintingHelper.getCachedStroke(Math.max(downsample, 1) * 2), null);
// boundsShape.setFrame(boundsShape.getX()+downsampleFactor, boundsShape.getY()-downsampleFactor, boundsShape.getWidth(), boundsShape.getHeight());
// PathHierarchyPaintingHelper.paintShape(boundsShape, g2d, new Color(1f, 1f, 1f, 0.75f), PathHierarchyPaintingHelper.getCachedStroke(Math.max(downsampleFactor, 1)*2), null, downsampleFactor);
}
// in a cached way
if ((selectedObject.isDetection() && PathPrefs.useSelectedColorProperty().get()) || !PathObjectTools.hierarchyContainsObject(hierarchy, selectedObject))
PathHierarchyPaintingHelper.paintObject(selectedObject, false, g2d, boundsDisplayed, overlayOptions, getHierarchy().getSelectionModel(), downsample);
// Paint ROI handles, if required
if (selectedObject == mainSelectedObject && roiEditor.hasROI()) {
Stroke strokeThick = PathHierarchyPaintingHelper.getCachedStroke(PathPrefs.annotationStrokeThicknessProperty().get() * downsample);
Color color = useSelectedColor ? ColorToolsAwt.getCachedColor(PathPrefs.colorSelectedObjectProperty().get()) : null;
if (color == null)
color = ColorToolsAwt.getCachedColor(ColorToolsFX.getDisplayedColorARGB(selectedObject));
g2d.setStroke(strokeThick);
// Draw ROI handles using adaptive size
double maxHandleSize = getMaxROIHandleSize();
double minHandleSize = downsample;
PathHierarchyPaintingHelper.paintHandles(roiEditor, g2d, minHandleSize, maxHandleSize, color, ColorToolsAwt.getTranslucentColor(color));
}
}
}
// Notify any listeners of shape changes
if (shapeChanged)
fireVisibleRegionChangedEvent(lastVisibleShape);
updateRepaintTimestamp();
}
Aggregations