package org.esa.snap.rcp.imgfilter; import org.esa.snap.rcp.imgfilter.model.Filter; import javax.swing.JPanel; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Insets; import java.awt.geom.Rectangle2D; /** * A canvas that displays the filter's kernel matrix. * * @author Norman */ public class FilterKernelCanvas extends JPanel implements Filter.Listener { private final Filter filter; private double maxAbsElementValue; public FilterKernelCanvas(Filter filter) { this.filter = filter; setFont(new Font("Verdana", Font.PLAIN, 10)); this.filter.addListener(this); maxAbsElementValue = -1; } public Filter getFilter() { return filter; } @Override public void filterChanged(Filter filter, String propertyName) { updateMaxAbsElementValue(); repaint(); } @Override public Dimension getPreferredSize() { return new Dimension( Math.max(filter.getKernelWidth() * 16, 200), Math.max(filter.getKernelHeight() * 16, 200)); } public int getKernelElementIndex(int x, int y) { Insets insets = getInsets(); int w = getWidth() - (insets.left + insets.right); int h = getHeight() - (insets.top + insets.bottom); int kernelWidth = filter.getKernelWidth(); int kernelHeight = filter.getKernelHeight(); int cellSize = Math.min(w / kernelWidth, h / kernelHeight); int x0 = insets.left + (w - cellSize * kernelWidth) / 2; int y0 = insets.top + (h - cellSize * kernelHeight) / 2; int i = (x - x0) / cellSize; int j = (y - y0) / cellSize; if (i >= 0 && i < kernelWidth && j >= 0 && j < kernelHeight) { return j * kernelWidth + i; } return -1; } @Override protected void paintComponent(Graphics g) { if (filter == null) { return; } if (maxAbsElementValue < 0) { updateMaxAbsElementValue(); } g.setColor(getBackground()); g.fillRect(0, 0, getWidth(), getHeight()); Insets insets = getInsets(); int w = getWidth() - (insets.left + insets.right); int h = getHeight() - (insets.top + insets.bottom); int kernelWidth = filter.getKernelWidth(); int kernelHeight = filter.getKernelHeight(); int cellSize = Math.min(w / kernelWidth, h / kernelHeight); int x0 = insets.left + (w - cellSize * kernelWidth) / 2; int y0 = insets.top + (h - cellSize * kernelHeight) / 2; for (int j = 0; j < kernelHeight; j++) { int y = y0 + j * cellSize; for (int i = 0; i < kernelWidth; i++) { int x = x0 + i * cellSize; paintKernelElement(g, x, y, cellSize, cellSize, j * kernelWidth + i); } } g.setColor(Color.GRAY); g.drawRect(x0, y0, kernelWidth * cellSize, kernelHeight * cellSize); } private void paintKernelElement(Graphics g, int x, int y, int cw, int ch, int index) { if (filter.getOperation() == Filter.Operation.CONVOLVE) { paintConvolutionElement(g, x, y, cw, ch, index); } else { paintStructuringElement(g, x, y, cw, ch, index); } } private void paintConvolutionElement(Graphics g, int x, int y, int cw, int ch, int index) { double value = filter.getKernelElement(index); Color color = Color.WHITE; if (value > 0) { int comp = 255 - (int) (maxAbsElementValue == 0 ? 0 : (100 * value) / maxAbsElementValue); color = new Color(255, comp, comp); } else if (value < 0) { int comp = 255 - (int) (maxAbsElementValue == 0 ? 0 : (100 * -value) / maxAbsElementValue); color = new Color(comp, comp, 255); } g.setColor(color); g.fillRect(x, y, cw, ch); int cellSize = Math.min(cw, ch); //System.out.println("cellSize = " + cellSize); if (cellSize >= 4) { g.setColor(Color.GRAY); g.drawRect(x, y, cw, ch); if (isOffsetIndex(index)) { g.setColor(Color.GRAY); g.drawRect(x + 1, y + 1, cw - 2, ch - 2); } } if (cellSize > 12) { float fontSize = Math.min(16.0f, 0.5f * cellSize); String text = value == (int) value ? String.valueOf((int) value) : String.valueOf(value); g.setFont(getFont().deriveFont(fontSize)); Rectangle2D bounds = g.getFontMetrics().getStringBounds(text, g); int x1 = x + (int) (0.5 * cw - 0.5 * bounds.getWidth()); int y1 = y + (int) (ch - 0.5 * bounds.getHeight()); g.setColor(filter.isEditable() ? getForeground() : Color.DARK_GRAY); g.drawString(text, x1, y1); } } private boolean isOffsetIndex(int index) { return index == filter.getKernelOffsetY() * filter.getKernelWidth() + filter.getKernelOffsetX(); } private void paintStructuringElement(Graphics g, int x, int y, int cw, int ch, int index) { g.setColor(filter.getKernelElement(index) != 0.0 ? Color.DARK_GRAY : Color.WHITE); g.fillRect(x, y, cw, ch); int cellSize = Math.min(cw, ch); //System.out.println("cellSize = " + cellSize); if (cellSize >= 4) { g.setColor(Color.GRAY); g.drawRect(x, y, cw, ch); if (isOffsetIndex(index)) { g.setColor(Color.GRAY); g.drawRect(x + 1, y + 1, cw - 2, ch - 2); } } } private void updateMaxAbsElementValue() { maxAbsElementValue = 0; if (filter != null) { for (double v : filter.getKernelElements()) { maxAbsElementValue = Math.max(maxAbsElementValue, Math.abs(v)); } } } }