package org.esa.snap.ui;
import com.bc.ceres.glayer.swing.LayerCanvas;
import com.bc.ceres.grender.Rendering;
import org.esa.snap.core.datamodel.GeoCoding;
import org.esa.snap.core.datamodel.GeoPos;
import org.esa.snap.core.datamodel.PixelPos;
import org.esa.snap.core.datamodel.Product;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
/**
* This class is an overlay that draws products from a {@link WorldMapPaneDataModel} and lets client decide how to
* render the selected product.
*
* @author Thomas Storm
* @author Tonio Fincke
* @author Marco Peters
*/
public abstract class BoundaryOverlay implements LayerCanvas.Overlay {
private final WorldMapPaneDataModel dataModel;
private LayerCanvas layerCanvas;
protected BoundaryOverlay(WorldMapPaneDataModel dataModel) {
this.dataModel = dataModel;
}
@Override
public void paintOverlay(LayerCanvas canvas, Rendering rendering) {
layerCanvas = canvas;
for (final GeoPos[] extraGeoBoundary : dataModel.getAdditionalGeoBoundaries()) {
drawGeoBoundary(rendering.getGraphics(), extraGeoBoundary, false, null, null);
}
final Product selectedProduct = dataModel.getSelectedProduct();
for (final Product product : dataModel.getProducts()) {
if (selectedProduct != product) {
drawProduct(rendering.getGraphics(), product, false);
}
}
handleSelectedProduct(rendering, selectedProduct);
}
protected abstract void handleSelectedProduct(Rendering rendering, Product selectedProduct);
protected void drawProduct(final Graphics2D g2d, final Product product, final boolean isCurrent) {
final GeoCoding geoCoding = product.getSceneGeoCoding();
if (geoCoding == null) {
return;
}
GeneralPath[] boundaryPaths = WorldMapPane.getGeoBoundaryPaths(product);
final String text = String.valueOf(product.getRefNo());
final PixelPos textCenter = getProductCenter(product);
drawGeoBoundary(g2d, boundaryPaths, isCurrent, text, textCenter);
}
private void drawGeoBoundary(final Graphics2D g2d, final GeneralPath[] boundaryPaths, final boolean isCurrent,
final String text, final PixelPos textCenter) {
final AffineTransform transform = layerCanvas.getViewport().getModelToViewTransform();
for (GeneralPath boundaryPath : boundaryPaths) {
boundaryPath.transform(transform);
drawPath(isCurrent, g2d, boundaryPath, 0.0f);
}
drawText(g2d, text, textCenter, 0.0f);
}
private void drawGeoBoundary(final Graphics2D g2d, final GeoPos[] geoBoundary, final boolean isCurrent,
final String text, final PixelPos textCenter) {
final GeneralPath gp = convertToPixelPath(geoBoundary);
drawPath(isCurrent, g2d, gp, 0.0f);
drawText(g2d, text, textCenter, 0.0f);
}
private void drawPath(final boolean isCurrent, Graphics2D g2d, final GeneralPath gp, final float offsetX) {
g2d = prepareGraphics2D(offsetX, g2d);
if (isCurrent) {
g2d.setColor(new Color(255, 200, 200, 30));
} else {
g2d.setColor(new Color(255, 255, 255, 30));
}
g2d.fill(gp);
if (isCurrent) {
g2d.setColor(new Color(255, 0, 0));
} else {
g2d.setColor(Color.WHITE);
}
g2d.draw(gp);
}
private GeneralPath convertToPixelPath(final GeoPos[] geoBoundary) {
final GeneralPath gp = new GeneralPath();
for (int i = 0; i < geoBoundary.length; i++) {
final GeoPos geoPos = geoBoundary[i];
final AffineTransform m2vTransform = layerCanvas.getViewport().getModelToViewTransform();
final Point2D viewPos = m2vTransform.transform(new PixelPos.Double(geoPos.lon, geoPos.lat), null);
if (i == 0) {
gp.moveTo(viewPos.getX(), viewPos.getY());
} else {
gp.lineTo(viewPos.getX(), viewPos.getY());
}
}
gp.closePath();
return gp;
}
private void drawText(Graphics2D g2d, final String text, final PixelPos textCenter, final float offsetX) {
if (text == null || textCenter == null) {
return;
}
g2d = prepareGraphics2D(offsetX, g2d);
final FontMetrics fontMetrics = g2d.getFontMetrics();
final Color color = g2d.getColor();
g2d.setColor(Color.black);
g2d.drawString(text,
(float)(textCenter.x - fontMetrics.stringWidth(text) / 2.0f),
(float)(textCenter.y + fontMetrics.getAscent() / 2.0f));
g2d.setColor(color);
}
private Graphics2D prepareGraphics2D(final float offsetX, Graphics2D g2d) {
if (offsetX != 0.0f) {
g2d = (Graphics2D) g2d.create();
final AffineTransform transform = g2d.getTransform();
final AffineTransform offsetTrans = new AffineTransform();
offsetTrans.setToTranslation(+offsetX, 0);
transform.concatenate(offsetTrans);
g2d.setTransform(transform);
}
return g2d;
}
private PixelPos getProductCenter(final Product product) {
final GeoCoding geoCoding = product.getSceneGeoCoding();
PixelPos centerPos = null;
if (geoCoding != null) {
final double pixelX = Math.floor(0.5f * product.getSceneRasterWidth()) + 0.5f;
final double pixelY = Math.floor(0.5f * product.getSceneRasterHeight()) + 0.5f;
final GeoPos geoPos = geoCoding.getGeoPos(new PixelPos(pixelX, pixelY), null);
final AffineTransform transform = layerCanvas.getViewport().getModelToViewTransform();
final Point2D point2D = transform.transform(new Point2D.Double(geoPos.getLon(), geoPos.getLat()), null);
centerPos = new PixelPos(point2D.getX(), point2D.getY());
}
return centerPos;
}
}