/* * Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at your option) * any later version. * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see http://www.gnu.org/licenses/ */ package org.esa.snap.ui.product; import com.bc.ceres.grender.Rendering; import com.bc.ceres.swing.figure.AbstractPointFigure; import com.bc.ceres.swing.figure.FigureStyle; import com.bc.ceres.swing.figure.Handle; import com.bc.ceres.swing.figure.Symbol; import com.bc.ceres.swing.figure.support.DefaultFigureStyle; import com.bc.ceres.swing.figure.support.NamedSymbol; import com.bc.ceres.swing.figure.support.PointHandle; import com.bc.ceres.swing.figure.support.ShapeSymbol; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.impl.CoordinateArraySequence; import org.esa.snap.core.datamodel.Placemark; import org.esa.snap.core.datamodel.SceneTransformProvider; import org.esa.snap.core.util.AwtGeomToJtsGeomConverter; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.opengis.feature.simple.SimpleFeature; import org.opengis.referencing.operation.TransformException; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.Shape; import java.awt.Stroke; import java.awt.font.GlyphVector; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; /** * A figure representing point features. * * @author Norman Fomferra */ public class SimpleFeaturePointFigure extends AbstractPointFigure implements SimpleFeatureFigure { private static final Font labelFont = new Font("Helvetica", Font.BOLD, 14); private static final int[] labelOutlineAlphas = new int[]{64, 128, 192, 255}; private static final Stroke[] labelOutlineStrokes = new Stroke[labelOutlineAlphas.length]; private static final Color[] labelOutlineColors = new Color[labelOutlineAlphas.length]; private static final Color labelFontColor = Color.WHITE; private static final Color labelOutlineColor = Color.BLACK; private static final String[] labelAttributeNames = new String[] { Placemark.PROPERTY_NAME_LABEL, "Label", }; private SceneTransformProvider sceneTransformProvider; private SimpleFeature simpleFeature; private Point geometry; static { for (int i = 0; i < labelOutlineAlphas.length; i++) { labelOutlineStrokes[i] = new BasicStroke((labelOutlineAlphas.length - i)); labelOutlineColors[i] = new Color(labelOutlineColor.getRed(), labelOutlineColor.getGreen(), labelOutlineColor.getBlue(), labelOutlineAlphas[i]); } } public SimpleFeaturePointFigure(SimpleFeature simpleFeature, SceneTransformProvider provider, FigureStyle style) { this(simpleFeature, provider, style, style); } public SimpleFeaturePointFigure(SimpleFeature simpleFeature, SceneTransformProvider provider, FigureStyle normalStyle, FigureStyle selectedStyle) { super(normalStyle, selectedStyle); this.simpleFeature = simpleFeature; sceneTransformProvider = provider; Object o = simpleFeature.getDefaultGeometry(); if (!(o instanceof Point)) { throw new IllegalArgumentException("simpleFeature"); } setGeometry((Point) o); setSelectable(true); } @Override public Object createMemento() { return getGeometry().clone(); } @Override public void setMemento(Object memento) { Point point = (Point) memento; simpleFeature.setDefaultGeometry(point); forceRegeneration(); fireFigureChanged(); } @Override public SimpleFeature getSimpleFeature() { return simpleFeature; } @Override public Point getGeometry() { return (Point) simpleFeature.getDefaultGeometry(); } @Override public void setGeometry(Geometry geometry) { Point point = (Point) geometry; final Point2D.Double sceneCoords = new Point2D.Double(point.getX(), point.getY()); Point2D.Double modelCoords = new Point2D.Double(); Coordinate coordinate; try { sceneTransformProvider.getSceneToModelTransform().transform(sceneCoords, modelCoords); coordinate = new Coordinate(modelCoords.getX(), modelCoords.getY()); } catch (TransformException e) { coordinate = new Coordinate(Double.NaN, Double.NaN); } this.geometry = new Point(new CoordinateArraySequence(new Coordinate[]{coordinate}), point.getFactory()); } @Override public void forceRegeneration() { setGeometry((Geometry) simpleFeature.getDefaultGeometry()); } @Override public double getX() { return geometry.getX(); } @Override public double getY() { return geometry.getY(); } @Override public void setLocation(double x, double y) { Coordinate coordinate = geometry.getCoordinate(); coordinate.x = x; coordinate.y = y; final Point2D.Double modelCoords = new Point2D.Double(x, y); final Point2D.Double sceneCoords = new Point2D.Double(); try { sceneTransformProvider.getModelToSceneTransform().transform(modelCoords, sceneCoords); simpleFeature.setDefaultGeometry(new AwtGeomToJtsGeomConverter().createPoint(sceneCoords)); } catch (TransformException e) { coordinate.x = Double.NaN; coordinate.y = Double.NaN; } geometry.geometryChanged(); fireFigureChanged(); } @Override public double getRadius() { return 1E-10; // = any small, non-zero value will be ok } @Override public Object clone() { SimpleFeaturePointFigure clone = (SimpleFeaturePointFigure) super.clone(); SimpleFeatureBuilder builder = new SimpleFeatureBuilder(simpleFeature.getFeatureType()); builder.init(simpleFeature); clone.simpleFeature = builder.buildFeature(null); clone.simpleFeature.setDefaultGeometry(getGeometry().clone()); clone.geometry = (Point) geometry.clone(); clone.sceneTransformProvider = sceneTransformProvider; return clone; } @Override protected void drawPoint(Rendering rendering) { super.drawPoint(rendering); String label = getLabel(); if (label != null && !label.trim().isEmpty()) { drawLabel(rendering, label); } } private String getLabel() { for (String labelAttributeName : labelAttributeNames) { Object labelAttribute = simpleFeature.getAttribute(labelAttributeName); if (labelAttribute instanceof String) { return (String) labelAttribute; } } return null; } private void drawLabel(Rendering rendering, String label) { final Graphics2D graphics = rendering.getGraphics(); final Font oldFont = graphics.getFont(); final Stroke oldStroke = graphics.getStroke(); final Paint oldPaint = graphics.getPaint(); try { graphics.setFont(labelFont); GlyphVector glyphVector = labelFont.createGlyphVector(graphics.getFontRenderContext(), label); Rectangle2D logicalBounds = glyphVector.getLogicalBounds(); float tx = (float) (logicalBounds.getX() - 0.5 * logicalBounds.getWidth()); float ty = (float) (getSymbol().getBounds().getMaxY() + logicalBounds.getHeight() + 1.0); Shape labelOutline = glyphVector.getOutline(tx, ty); for (int i = 0; i < labelOutlineAlphas.length; i++) { graphics.setStroke(labelOutlineStrokes[i]); graphics.setPaint(labelOutlineColors[i]); graphics.draw(labelOutline); } graphics.setPaint(labelFontColor); graphics.fill(labelOutline); } finally { graphics.setPaint(oldPaint); graphics.setStroke(oldStroke); graphics.setFont(oldFont); } } @Override public int getMaxSelectionStage() { return 1; } @Override public Handle[] createHandles(int selectionStage) { if (selectionStage == 1) { DefaultFigureStyle handleStyle = new DefaultFigureStyle(); handleStyle.setStrokeColor(Color.YELLOW); handleStyle.setStrokeOpacity(0.8); handleStyle.setStrokeWidth(1.0); handleStyle.setFillColor(Color.YELLOW); handleStyle.setFillOpacity(0.4); Symbol symbol = getSymbol(); if (symbol instanceof NamedSymbol) { NamedSymbol namedSymbol = (NamedSymbol) symbol; symbol = namedSymbol.getSymbol(); } if (symbol instanceof ShapeSymbol) { ShapeSymbol shapeSymbol = (ShapeSymbol) symbol; return new Handle[]{new PointHandle(this, handleStyle, shapeSymbol.getShape())}; } return new Handle[]{new PointHandle(this, handleStyle)}; } return super.createHandles(selectionStage); } }