/*************************************************** * * 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.rasterservice.georeferencing; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.util.AffineTransformation; import com.vividsolutions.jts.geom.util.AffineTransformationBuilder; import lombok.Getter; import java.awt.Dimension; import java.awt.Point; import java.awt.Rectangle; import java.io.File; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import de.cismet.cismap.commons.BoundingBox; import de.cismet.cismap.commons.features.Feature; import de.cismet.cismap.commons.features.FeatureCollection; import de.cismet.cismap.commons.gui.MappingComponent; import de.cismet.cismap.commons.gui.piccolo.eventlistener.RasterGeoRefFeature; import de.cismet.cismap.commons.interaction.ActiveLayerListener; import de.cismet.cismap.commons.interaction.CismapBroker; import de.cismet.cismap.commons.interaction.events.ActiveLayerEvent; import de.cismet.cismap.commons.rasterservice.ImageFileMetaData; import de.cismet.cismap.commons.rasterservice.ImageFileUtils; import de.cismet.cismap.commons.rasterservice.ImageRasterService; import static de.cismet.cismap.commons.rasterservice.georeferencing.RasterGeoReferencingHandler.createAverageTransformation; /** * DOCUMENT ME! * * @author jruiz * @version $Revision$, $Date$ */ public class RasterGeoReferencingBackend { //~ Static fields/initializers --------------------------------------------- private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger( RasterGeoReferencingBackend.class); //~ Instance fields -------------------------------------------------------- @Getter private final Map<File, RasterGeoReferencingHandler> metaDataMap = new HashMap<>(); @Getter private final ActiveLayerListenerHandler activeLayerListenerHandler = new ActiveLayerListenerHandler(); //~ Constructors ----------------------------------------------------------- /** * Creates a new RasterGeoReferencingBackend object. */ private RasterGeoReferencingBackend() { } //~ Methods ---------------------------------------------------------------- /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public static RasterGeoReferencingBackend getInstance() { return LazyInitialiser.INSTANCE; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public static MappingComponent getMainMap() { return CismapBroker.getInstance().getMappingComponent(); } /** * DOCUMENT ME! * * @param imageFile DOCUMENT ME! * * @return DOCUMENT ME! */ public RasterGeoReferencingHandler getHandler(final File imageFile) { return getMetaDataMap().get(imageFile); } /** * DOCUMENT ME! * * @param service DOCUMENT ME! * @param imageFile DOCUMENT ME! * * @return DOCUMENT ME! * * @throws Exception DOCUMENT ME! */ private static RasterGeoReferencingHandler createInitHandler(final ImageRasterService service, final File imageFile) throws Exception { final Dimension imageDimension = ImageFileUtils.getImageDimension(imageFile); final Rectangle imageBounds = new Rectangle( 0, 0, (int)imageDimension.getWidth(), (int)imageDimension.getHeight()); final BoundingBox bb = getMainMap().getCurrentBoundingBoxFromCamera(); final double scale; if ((bb.getWidth() / bb.getHeight()) > (imageBounds.getWidth() / imageBounds.getHeight())) { scale = bb.getHeight() / imageBounds.getHeight(); } else { scale = bb.getWidth() / imageBounds.getWidth(); } final Coordinate mapCenterCoordinate = new Coordinate( bb.getX1() + ((bb.getX2() - bb.getX1()) / 2d), bb.getY2() + ((bb.getY1() - bb.getY2()) / 2d)); final Envelope imageEnvelope = new Envelope( mapCenterCoordinate.x - ((imageBounds.getWidth() * scale) / 2d), mapCenterCoordinate.x + ((imageBounds.getWidth() * scale) / 2d), mapCenterCoordinate.y + ((imageBounds.getHeight() * scale) / 2d), mapCenterCoordinate.y - ((imageBounds.getHeight() * scale) / 2d)); final PointCoordinatePair[] pairs = new PointCoordinatePair[] { // upper left new PointCoordinatePair( new Point(0, 0), new Coordinate(imageEnvelope.getMinX(), imageEnvelope.getMaxY())), // upper right new PointCoordinatePair( new Point((int)imageBounds.getWidth(), 0), new Coordinate(imageEnvelope.getMaxX(), imageEnvelope.getMaxY())), // bottom middle new PointCoordinatePair( new Point((int)imageBounds.getWidth() / 2, (int)imageBounds.getHeight()), new Coordinate( imageEnvelope.getMaxX() - (imageEnvelope.getWidth() / 2d), imageEnvelope.getMinY())) }; final AffineTransformation transform = calculateAvgTransformation(pairs); final ImageFileMetaData metaData = new ImageFileMetaData( imageBounds, imageEnvelope, transform, pairs); return new RasterGeoReferencingHandler(service, metaData); } /** * DOCUMENT ME! * * @param handler DOCUMENT ME! * * @throws Exception DOCUMENT ME! */ public void save(final RasterGeoReferencingHandler handler) throws Exception { final File imageFile = handler.getService().getImageFile(); final File worldFile = ImageFileUtils.getWorldFileWithoutCheck(imageFile); final PrintWriter pw = new PrintWriter(worldFile); final AffineTransformation at = handler.getMetaData().getTransform(); final double[] matrix = at.getMatrixEntries(); pw.append(Double.toString(matrix[0])).append("\n"); pw.append(Double.toString(matrix[3])).append("\n"); pw.append(Double.toString(matrix[1])).append("\n"); pw.append(Double.toString(matrix[4])).append("\n"); pw.append(Double.toString(matrix[2])).append("\n"); pw.append(Double.toString(matrix[5])).append("\n"); pw.append("#cidsgeoref;") .append(Integer.toString(handler.getCompletePairs().length)) .append(";") .append(getMainMap().getMappingModel().getSrs().getShortname()) .append("\n"); for (final PointCoordinatePair pair : handler.getCompletePairs()) { final Point point = pair.getPoint(); final Coordinate coordinate = pair.getCoordinate(); pw.append("#") .append(Integer.toString((int)point.getX())) .append(",") .append(Integer.toString((int)point.getY())) .append(";") .append(Double.toString(coordinate.x)) .append(",") .append(Double.toString(coordinate.y)) .append("\n"); } pw.close(); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public static RasterGeoReferencingWizard getWizard() { return RasterGeoReferencingWizard.getInstance(); } /** * DOCUMENT ME! * * @param completePairs DOCUMENT ME! * * @return DOCUMENT ME! */ public static AffineTransformation calculateAvgTransformation(final PointCoordinatePair[] completePairs) { final List<AffineTransformation> transforms = new ArrayList<>(); if (completePairs.length >= 3) { for (final Object[] arr : RasterGeoReferencingHandler.getCombinations(completePairs, 3)) { final PointCoordinatePair pair0 = (PointCoordinatePair)arr[0]; final PointCoordinatePair pair1 = (PointCoordinatePair)arr[1]; final PointCoordinatePair pair2 = (PointCoordinatePair)arr[2]; final AffineTransformationBuilder builder = new AffineTransformationBuilder( new Coordinate(pair0.getPoint().getX(), pair0.getPoint().getY()), new Coordinate(pair1.getPoint().getX(), pair1.getPoint().getY()), new Coordinate(pair2.getPoint().getX(), pair2.getPoint().getY()), pair0.getCoordinate(), pair1.getCoordinate(), pair2.getCoordinate()); final AffineTransformation transform = builder.getTransformation(); if (transform != null) { transforms.add(transform); } } final AffineTransformation avgTransform = createAverageTransformation(transforms); return avgTransform; } return null; } //~ Inner Classes ---------------------------------------------------------- /** * DOCUMENT ME! * * @version $Revision$, $Date$ */ private class ActiveLayerListenerHandler implements ActiveLayerListener { //~ Methods ------------------------------------------------------------ @Override public void layerAdded(final ActiveLayerEvent e) { final Object layer = e.getLayer(); if (!RasterGeoReferencingWizard.getInstance().getIgnoreLayerList().contains(layer)) { try { if (layer instanceof ImageRasterService) { final ImageRasterService irs = (ImageRasterService)layer; if (ImageFileUtils.Mode.GEO_REFERENCED == irs.getMode()) { final File imagefile = irs.getImageFile(); if (!getMetaDataMap().containsKey(imagefile)) { try { final File worldFile = ImageFileUtils.getWorldFile(imagefile); final RasterGeoReferencingHandler handler; if (worldFile == null) { handler = createInitHandler(irs, imagefile); } else { final ImageFileMetaData metaData = ImageFileUtils.getWorldFileMetaData( imagefile, worldFile); handler = new RasterGeoReferencingHandler(irs, metaData); for (final PointCoordinatePair pair : metaData.getPairs()) { handler.addPair(pair); } } getMetaDataMap().put(imagefile, handler); handler.addListener(new RasterGeoReferencingHandlerListener() { @Override public void transformationChanged() { if (handler.isComplete()) { if (imagefile.equals(irs.getImageFile())) { irs.retrieve(true); } } } @Override public void positionAdded(final int position) { } @Override public void positionRemoved(final int position) { } @Override public void positionChanged(final int position) { } }); final Feature feature = handler.getFeature(); final FeatureCollection featureCollection = getMainMap().getFeatureCollection(); if ((feature != null) && (featureCollection != null) && !featureCollection.contains(feature)) { featureCollection.addFeature(feature); } } catch (final Exception ex) { LOG.warn(ex, ex); } } // load handler into the wizard if it is the only handler if (getMetaDataMap().size() == 1) { getWizard().setHandler(getMetaDataMap().get(imagefile)); } } } } catch (final Throwable t) { LOG.fatal(t, t); } } } @Override public void layerRemoved(final ActiveLayerEvent e) { final Object layer = e.getLayer(); if (!RasterGeoReferencingWizard.getInstance().getIgnoreLayerList().contains(layer)) { if (layer instanceof ImageRasterService) { final ImageRasterService irs = (ImageRasterService)layer; if (ImageFileUtils.Mode.GEO_REFERENCED == irs.getMode()) { final File imageFile = irs.getImageFile(); if (getMetaDataMap().containsKey(imageFile)) { final RasterGeoRefFeature feature = getHandler(imageFile).getFeature(); getWizard().setHandler(null); final FeatureCollection featureCollection = getMainMap().getFeatureCollection(); if ((feature != null) && (featureCollection != null) && featureCollection.contains(feature)) { featureCollection.removeFeature(feature); getWizard().removeListener(feature); } getMetaDataMap().remove(imageFile); } } } } } @Override public void layerPositionChanged(final ActiveLayerEvent e) { } @Override public void layerVisibilityChanged(final ActiveLayerEvent e) { } @Override public void layerAvailabilityChanged(final ActiveLayerEvent e) { } @Override public void layerInformationStatusChanged(final ActiveLayerEvent e) { } @Override public void layerSelectionChanged(final ActiveLayerEvent e) { RasterGeoReferencingHandler handler = null; final Object layer = e.getLayer(); if (!RasterGeoReferencingWizard.getInstance().getIgnoreLayerList().contains(layer)) { if (layer instanceof ImageRasterService) { final ImageRasterService irs = (ImageRasterService)layer; if (ImageFileUtils.Mode.GEO_REFERENCED == irs.getMode()) { final File imagefile = irs.getImageFile(); if (getMetaDataMap().containsKey(imagefile)) { handler = getMetaDataMap().get(imagefile); } } } getWizard().setHandler(handler); } } } /** * DOCUMENT ME! * * @version $Revision$, $Date$ */ private static final class LazyInitialiser { //~ Static fields/initializers ----------------------------------------- private static final RasterGeoReferencingBackend INSTANCE = new RasterGeoReferencingBackend(); //~ Constructors ------------------------------------------------------- /** * Creates a new LazyInitialiser object. */ private LazyInitialiser() { } } }