/***************************************************
*
* cismet GmbH, Saarbruecken, Germany
*
* ... and it just works.
*
****************************************************/
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package de.cismet.cismap.commons.gui.piccolo.eventlistener;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.PrecisionModel;
import com.vividsolutions.jts.geom.util.AffineTransformation;
import edu.umd.cs.piccolo.PNode;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import org.apache.log4j.Logger;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import de.cismet.cismap.commons.CrsTransformer;
import de.cismet.cismap.commons.Refreshable;
import de.cismet.cismap.commons.features.ChildNodesProvider;
import de.cismet.cismap.commons.features.DefaultStyledFeature;
import de.cismet.cismap.commons.features.FeatureCollectionEvent;
import de.cismet.cismap.commons.features.FeatureCollectionListener;
import de.cismet.cismap.commons.features.RequestForHidingHandles;
import de.cismet.cismap.commons.features.RequestForNonreflectingFeature;
import de.cismet.cismap.commons.features.RequestForRotatingPivotLock;
import de.cismet.cismap.commons.features.RequestForUnaddableHandles;
import de.cismet.cismap.commons.features.RequestForUnmoveableHandles;
import de.cismet.cismap.commons.features.RequestForUnremovableHandles;
import de.cismet.cismap.commons.features.XStyledFeature;
import de.cismet.cismap.commons.gui.MappingComponent;
import de.cismet.cismap.commons.gui.piccolo.PFeature;
import de.cismet.cismap.commons.interaction.CismapBroker;
import de.cismet.cismap.commons.rasterservice.georeferencing.PointCoordinatePair;
import de.cismet.cismap.commons.rasterservice.georeferencing.RasterGeoReferencingHandler;
import de.cismet.cismap.commons.rasterservice.georeferencing.RasterGeoReferencingHandlerListener;
import de.cismet.cismap.commons.rasterservice.georeferencing.RasterGeoReferencingWizard;
import de.cismet.cismap.commons.rasterservice.georeferencing.RasterGeoReferencingWizardListener;
/**
* DOCUMENT ME!
*
* @author jruiz
* @version $Revision$, $Date$
*/
public class RasterGeoRefFeature extends DefaultStyledFeature implements XStyledFeature,
ChildNodesProvider,
RequestForUnaddableHandles,
RequestForUnmoveableHandles,
RequestForUnremovableHandles,
RequestForRotatingPivotLock,
RequestForNonreflectingFeature,
RequestForHidingHandles,
RasterGeoReferencingHandlerListener,
RasterGeoReferencingWizardListener {
//~ Static fields/initializers ---------------------------------------------
private static final BufferedImage GEOREF_DOT_IMAGE;
private static final BufferedImage GEOREF_CROSS_IMAGE;
private static final ImageIcon GEOREF_ICON;
private static final transient Logger LOG = Logger.getLogger(RasterGeoRefFeature.class);
static {
BufferedImage geoRefDotImage = null;
try {
geoRefDotImage = ImageIO.read(RasterGeoRefFeature.class.getResource(
"/de/cismet/cismap/commons/rasterservice/georeferencing/georef_dot.png"));
} catch (final IOException ex) {
LOG.error("could not load the georref_dot image from resources");
}
GEOREF_DOT_IMAGE = geoRefDotImage;
BufferedImage geoRefCrossImage = null;
try {
geoRefCrossImage = ImageIO.read(RasterGeoRefFeature.class.getResource(
"/de/cismet/cismap/commons/rasterservice/georeferencing/georef_cross.png"));
} catch (final IOException ex) {
LOG.error("could not load the georref_cross image from resources");
}
GEOREF_CROSS_IMAGE = geoRefCrossImage;
BufferedImage geoRefIconImage = null;
try {
geoRefIconImage = ImageIO.read(RasterGeoRefFeature.class.getResource(
"/de/cismet/cismap/commons/rasterservice/georeferencing/georef.png"));
} catch (final IOException ex) {
LOG.error("could not load the georref_cross image from resources");
}
GEOREF_ICON = new ImageIcon(geoRefIconImage.getScaledInstance(13, 13, java.awt.Image.SCALE_SMOOTH));
}
//~ Instance fields --------------------------------------------------------
@Getter(AccessLevel.PRIVATE)
private final ArrayList<PNode> children = new ArrayList<>();
@Getter(AccessLevel.PRIVATE)
private final RasterGeoReferencingHandler handler;
@Getter
@Setter(AccessLevel.PRIVATE)
private boolean refreshing;
//~ Constructors -----------------------------------------------------------
/**
* Creates a new RasterGeoRefFeature object.
*
* @param handler DOCUMENT ME!
*/
public RasterGeoRefFeature(final RasterGeoReferencingHandler handler) {
this.handler = handler;
getHandler().addListener(this);
RasterGeoReferencingWizard.getInstance().addListener(this);
updateGeometry();
CismapBroker.getInstance()
.getMappingComponent()
.getFeatureCollection()
.addFeatureCollectionListener(new FeatureCollectionListener() {
boolean ignoreSelection = false;
@Override
public void featuresAdded(final FeatureCollectionEvent fce) {
// if (!isRefreshing() && fce.getEventFeatures().contains(RasterGeoRefFeature.this)) {
// CismapBroker.getInstance().getMappingComponent().setInteractionMode(MappingComponent.GEO_REF);
// }
}
@Override
public void allFeaturesRemoved(final FeatureCollectionEvent fce) {
}
@Override
public void featuresRemoved(final FeatureCollectionEvent fce) {
// if (!isRefreshing()) { if (fce.getEventFeatures().contains(RasterGeoRefFeature.this)) {
// CismapBroker.getInstance().getMappingComponent().setInteractionMode(MappingComponent.SELECT);
// } }
}
@Override
public void featuresChanged(final FeatureCollectionEvent fce) {
}
@Override
public void featureSelectionChanged(final FeatureCollectionEvent fce) {
if (fce.getEventFeatures().contains(RasterGeoRefFeature.this)) {
if (fce.getFeatureCollection().getSelectedFeatures().contains(
RasterGeoRefFeature.this)) {
if (!ignoreSelection) {
ignoreSelection = true;
try {
RasterGeoReferencingWizard.getInstance().setHandler(handler);
CismapBroker.getInstance()
.getMappingComponent()
.getFeatureCollection()
.select(handler.getFeature());
CismapBroker.getInstance()
.getMappingComponent()
.setInteractionMode(MappingComponent.GEO_REF);
} finally {
ignoreSelection = false;
}
}
}
}
}
@Override
public void featureReconsiderationRequested(final FeatureCollectionEvent fce) {
}
@Override
public void featureCollectionChanged() {
}
});
}
//~ Methods ----------------------------------------------------------------
/**
* DOCUMENT ME!
*/
private void updateGeometry() {
final Rectangle envelope = getHandler().getMetaData().getImageBounds();
final AffineTransformation transform = getHandler().getMetaData().getTransform();
if ((envelope != null) && (transform != null)) {
final Coordinate upperLeftCoordinate = transform.transform(new Coordinate(
envelope.getMinX(),
envelope.getMinY()),
new Coordinate());
final Coordinate upperRightCoordinate = transform.transform(new Coordinate(
envelope.getMaxX(),
envelope.getMinY()),
new Coordinate());
final Coordinate lowerRightCoordinate = transform.transform(new Coordinate(
envelope.getMaxX(),
envelope.getMaxY()),
new Coordinate());
final Coordinate lowerLeftCoordinate = transform.transform(new Coordinate(
envelope.getMinX(),
envelope.getMaxY()),
new Coordinate());
final Coordinate[] coordinates = new Coordinate[] {
upperLeftCoordinate,
upperRightCoordinate,
lowerRightCoordinate,
lowerLeftCoordinate,
upperLeftCoordinate
};
final GeometryFactory factory = new GeometryFactory(
new PrecisionModel(),
CrsTransformer.extractSridFromCrs(CismapBroker.getInstance().getSrs().getCode()));
final LinearRing linear = factory.createLinearRing(coordinates);
setGeometry(factory.createPolygon(linear, null));
}
}
@Override
public ImageIcon getIconImage() {
return GEOREF_ICON;
}
@Override
public String getType() {
return "RasterGeoRef";
}
@Override
public JComponent getInfoComponent(final Refreshable refresh) {
return null;
}
@Override
public Stroke getLineStyle() {
return null;
}
@Override
public String getName() {
return getHandler().getService().getName();
}
/**
* DOCUMENT ME!
*
* @param parent DOCUMENT ME!
*/
private void init(final PFeature parent) {
final int numOfPairs = getHandler().getPairs().length;
for (int position = 0; position < numOfPairs; position++) {
addPointChild(parent, position);
addCoordinateChild(parent, position);
}
}
/**
* DOCUMENT ME!
*
* @param parent DOCUMENT ME!
* @param position pair DOCUMENT ME!
*/
private void addCoordinateChild(final PFeature parent, final int position) {
final PointCoordinatePair pair = getHandler().getPair(position);
if ((pair != null) && (pair.getCoordinate() != null)) {
final DerivedFixedPImage coordinateDFP = new DerivedFixedPImage(
GEOREF_CROSS_IMAGE,
parent,
new DeriveRule() {
@Override
public Geometry derive(final Geometry in) {
final GeometryFactory factory = new GeometryFactory(
new PrecisionModel(),
CrsTransformer.extractSridFromCrs(CismapBroker.getInstance().getSrs().getCode()));
return factory.createPoint(pair.getCoordinate());
}
});
coordinateDFP.setMultiplier(0.25);
coordinateDFP.setSweetSpotX(0.5);
coordinateDFP.setSweetSpotY(0.5);
getChildren().add(coordinateDFP);
final DerivedFixedPImage textDFP = new DerivedFixedPImage(createImageFromText(
Integer.toString(position + 1),
30,
30),
parent,
new DeriveRule() {
@Override
public Geometry derive(final Geometry in) {
final GeometryFactory factory = new GeometryFactory(
new PrecisionModel(),
CrsTransformer.extractSridFromCrs(CismapBroker.getInstance().getSrs().getCode()));
final Point center = factory.createPoint(pair.getCoordinate());
return center;
}
});
textDFP.setSweetSpotX(1);
textDFP.setSweetSpotY(1);
getChildren().add(textDFP);
}
}
/**
* DOCUMENT ME!
*
* @param parent DOCUMENT ME!
* @param position pair DOCUMENT ME!
*/
private void addPointChild(final PFeature parent, final int position) {
final PointCoordinatePair pair = getHandler().getPair(position);
if ((pair != null) && (pair.getPoint() != null)) {
final AffineTransformation transform = getHandler().getMetaData().getTransform();
if (transform != null) {
final DerivedFixedPImage pointDFP = new DerivedFixedPImage(
GEOREF_DOT_IMAGE,
parent,
new DeriveRule() {
@Override
public Geometry derive(final Geometry in) {
final GeometryFactory factory = new GeometryFactory(
new PrecisionModel(),
CrsTransformer.extractSridFromCrs(
CismapBroker.getInstance().getSrs().getCode()));
return transform.transform(
factory.createPoint(
new Coordinate(
pair.getPoint().getX(),
pair.getPoint().getY())));
}
});
pointDFP.setMultiplier(0.25);
pointDFP.setSweetSpotX(0.5);
pointDFP.setSweetSpotY(0.5);
getChildren().add(pointDFP);
final DerivedFixedPImage textDFP = new DerivedFixedPImage(createImageFromText(
Integer.toString(position + 1),
30,
30),
parent,
new DeriveRule() {
@Override
public Geometry derive(final Geometry in) {
final GeometryFactory factory = new GeometryFactory(
new PrecisionModel(),
CrsTransformer.extractSridFromCrs(
CismapBroker.getInstance().getSrs().getCode()));
return transform.transform(
factory.createPoint(
new Coordinate(
pair.getPoint().getX(),
pair.getPoint().getY())));
}
});
textDFP.setSweetSpotX(0);
textDFP.setSweetSpotY(0);
getChildren().add(textDFP);
}
}
}
/**
* DOCUMENT ME!
*
* @param text DOCUMENT ME!
* @param width DOCUMENT ME!
* @param height DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
private BufferedImage createImageFromText(final String text, final int width, final int height) {
final Font font = new Font("Arial", Font.BOLD, 12);
final BufferedImage image = new BufferedImage(width,
height,
BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2d = image.createGraphics();
g2d.setComposite(AlphaComposite.Clear);
g2d.fillRect(0, 0, width, height);
g2d.setComposite(AlphaComposite.Src);
g2d.setColor(Color.BLACK);
g2d.setFont(font);
final FontMetrics metrics = g2d.getFontMetrics(font);
g2d.drawString(
text,
(float)((width / 2f) - (metrics.stringWidth(text) / 2f)),
(float)((height / 2f) - (metrics.getHeight() / 2f) + metrics.getAscent()));
g2d.dispose();
return image;
}
@Override
public Collection<PNode> provideChildren(final PFeature parent) {
if (getChildren().isEmpty()) {
init(parent);
}
return getChildren();
}
/**
* DOCUMENT ME!
*/
private void refresh() {
getChildren().clear();
updateGeometry();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
setRefreshing(true);
CismapBroker.getInstance()
.getMappingComponent()
.getFeatureCollection()
.removeFeature(RasterGeoRefFeature.this);
if (getGeometry() != null) {
CismapBroker.getInstance()
.getMappingComponent()
.getFeatureCollection()
.addFeature(RasterGeoRefFeature.this);
}
} finally {
setRefreshing(false);
}
}
});
}
@Override
public void positionAdded(final int position) {
refresh();
}
@Override
public void positionRemoved(final int position) {
refresh();
}
@Override
public void positionChanged(final int position) {
refresh();
}
@Override
public void transformationChanged() {
refresh();
}
@Override
public void pointSelected(final int position) {
}
@Override
public void coordinateSelected(final int position) {
}
@Override
public void handlerChanged(final RasterGeoReferencingHandler handler) {
if ((handler != null) && handler.equals(getHandler())) {
refresh();
}
}
}