/***************************************************
*
* cismet GmbH, Saarbruecken, Germany
*
* ... and it just works.
*
****************************************************/
package de.cismet.cismap.commons.gui.piccolo.eventlistener;
import com.vividsolutions.jts.geom.*;
import edu.umd.cs.piccolo.event.PBasicInputEventHandler;
import edu.umd.cs.piccolo.event.PInputEvent;
import edu.umd.cs.piccolox.event.PNotificationCenter;
import org.apache.log4j.Logger;
import org.openide.util.Lookup;
import java.awt.Color;
import java.awt.geom.Point2D;
import java.util.Collection;
import de.cismet.cismap.commons.CrsTransformer;
import de.cismet.cismap.commons.WorldToScreenTransform;
import de.cismet.cismap.commons.features.*;
import de.cismet.cismap.commons.gui.MappingComponent;
import de.cismet.cismap.commons.gui.piccolo.PFeature;
import de.cismet.cismap.commons.gui.piccolo.eventlistener.actions.FeatureDeleteAction;
import de.cismet.cismap.commons.gui.piccolo.eventlistener.actions.FeatureRemoveEntityAction;
import de.cismet.cismap.commons.gui.piccolo.eventlistener.actions.FeatureRemoveHoleAction;
import de.cismet.cismap.commons.tools.PFeatureTools;
/**
* DOCUMENT ME!
*
* @author jruiz
* @version $Revision$, $Date$
*/
public class CreateNewGeometryListener extends CreateGeometryListener {
//~ Static fields/initializers ---------------------------------------------
private static final Logger LOG = Logger.getLogger(CreateNewGeometryListener.class);
private static Collection<? extends GeometryCheckInterface> geometryChecks;
static {
geometryChecks = Lookup.getDefault().lookupAll(GeometryCheckInterface.class);
}
//~ Instance fields --------------------------------------------------------
// delegate to enable zoom during creation.
private final PBasicInputEventHandler zoomDelegate;
private PFeature selectedPFeature = null;
private int selectedEntityPosition = -1;
private boolean creatingHole = false;
private InvalidPolygonTooltip multiPolygonPointerAnnotation = new InvalidPolygonTooltip();
//~ Constructors -----------------------------------------------------------
/**
* Creates a new CreateNewGeometryListener object.
*
* @param mc DOCUMENT ME!
*/
public CreateNewGeometryListener(final MappingComponent mc) {
this(mc, PureNewFeature.class);
}
/**
* Creates a new instance of CreateNewGeometryListener.
*
* @param mc DOCUMENT ME!
* @param geometryFeatureClass DOCUMENT ME!
*/
private CreateNewGeometryListener(final MappingComponent mc, final Class geometryFeatureClass) {
super(mc, geometryFeatureClass);
zoomDelegate = new RubberBandZoomListener();
mc.getCamera().addChild(multiPolygonPointerAnnotation);
}
//~ Methods ----------------------------------------------------------------
@Override
protected Color getFillingColor() {
return new Color(1f, 0f, 0f, 0.5f);
}
/**
* DOCUMENT ME!
*
* @param mousePosition DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
private Point getMousePoint(final Point2D mousePosition) {
final WorldToScreenTransform wtst = getMappingComponent().getWtst();
final double mouseCoordX = wtst.getSourceX(mousePosition.getX() - getMappingComponent().getClip_offset_x());
final double mouseCoordY = wtst.getSourceY(mousePosition.getY() - getMappingComponent().getClip_offset_y());
final Coordinate mouseCoord = new Coordinate(mouseCoordX, mouseCoordY);
final int currentSrid = CrsTransformer.extractSridFromCrs(getMappingComponent().getMappingModel().getSrs()
.getCode());
final GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(PrecisionModel.FLOATING),
currentSrid);
final Point mousePoint = CrsTransformer.transformToGivenCrs(geometryFactory.createPoint(
mouseCoord),
CrsTransformer.createCrsFromSrid(
selectedPFeature.getFeature().getGeometry().getSRID()));
return mousePoint;
}
@Override
public void mousePressed(final PInputEvent pInputEvent) {
final AbstractNewFeature tempFeature = getCurrentNewFeature();
if ((tempFeature != null) && (pInputEvent.getClickCount() == 1)) {
final Geometry tempGeometry = tempFeature.getGeometry();
if ((geometryChecks != null) && !geometryChecks.isEmpty()) {
final Point2D lastPoint = pInputEvent.getPosition();
final WorldToScreenTransform wtst = mappingComponent.getWtst();
final Coordinate lastCoordinate = new Coordinate(wtst.getSourceX((float)lastPoint.getX()),
wtst.getSourceY((float)lastPoint.getY()));
boolean ignoreLastGeometryCoordinate = false;
if (points.size() < tempGeometry.getCoordinates().length) {
ignoreLastGeometryCoordinate = true;
}
for (final GeometryCheckInterface check : geometryChecks) {
if (!check.check(tempGeometry, lastCoordinate, ignoreLastGeometryCoordinate)) {
return;
}
}
}
}
multiPolygonPointerAnnotation.setVisible(false);
if (pInputEvent.isLeftMouseButton()) {
if (pInputEvent.getClickCount() == 1) {
if (!isInProgress()) {
if (pInputEvent.isAltDown()
&& (isInMode(POLYGON) || isInMode(ELLIPSE) || isInMode(RECTANGLE)
|| isInMode(RECTANGLE_FROM_LINE))) {
final Collection selectedFeatures = getMappingComponent().getFeatureCollection()
.getSelectedFeatures();
if ((selectedPFeature != null) && (selectedFeatures.size() == 1)) {
final PFeature pFeature = getMappingComponent().getPFeatureHM()
.get((Feature)selectedFeatures.toArray()[0]);
if ((pFeature != null)
&& ((pFeature.getFeature().getGeometry() instanceof MultiPolygon)
|| (pFeature.getFeature().getGeometry() instanceof Polygon))) {
final Point mousePoint = getMousePoint(pInputEvent.getPosition());
selectedEntityPosition = pFeature.getEntityPositionUnderPoint(mousePoint);
creatingHole = selectedEntityPosition != -1;
super.mousePressed(pInputEvent);
}
} else {
final PFeature pFeature = (PFeature)PFeatureTools.getFirstValidObjectUnderPointer(
pInputEvent,
new Class[] { PFeature.class });
if ((pFeature != null)
&& ((pFeature.getFeature().getGeometry() instanceof MultiPolygon)
|| (pFeature.getFeature().getGeometry() instanceof Polygon))) {
getMappingComponent().getFeatureCollection().select(pFeature.getFeature());
selectedPFeature = pFeature;
}
}
} else if (isInMode(TEXT)) {
super.mousePressed(pInputEvent);
} else { // es wird ein normales polygon angefangen
selectedPFeature = null;
super.mousePressed(pInputEvent);
}
} else {
super.mousePressed(pInputEvent);
}
} else if (pInputEvent.getClickCount() == 2) {
if ((selectedPFeature == null) || isTempFeatureValid()) {
super.mousePressed(pInputEvent);
}
} else {
super.mousePressed(pInputEvent);
}
} else {
selectedPFeature = null;
super.mousePressed(pInputEvent);
}
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
private boolean isTempFeatureValid() {
final AbstractNewFeature tempFeature = getCurrentNewFeature();
final Coordinate[] tempFeatureCoordinates = tempFeature.getGeometry().getCoordinates();
if (tempFeatureCoordinates.length == 3) {
final int currentSrid = selectedPFeature.getFeature().getGeometry().getSRID();
final GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(PrecisionModel.FLOATING),
currentSrid);
final Point point = geometryFactory.createPoint(tempFeatureCoordinates[1]);
if (creatingHole) {
return selectedPFeature.getEntityPositionUnderPoint(point) == selectedEntityPosition;
} else {
return selectedPFeature.getEntityPositionUnderPoint(point) == -1;
}
}
if (creatingHole) {
return selectedPFeature.isValidWithThisNewHoleCoordinates(selectedEntityPosition, tempFeatureCoordinates);
} else {
return selectedPFeature.isValidWithThisNewEntityCoordinates(tempFeatureCoordinates);
}
}
@Override
protected void reset() {
super.reset();
selectedPFeature = null;
selectedEntityPosition = -1;
creatingHole = false;
}
@Override
public void mouseMoved(final PInputEvent pInputEvent) {
super.mouseMoved(pInputEvent);
if (isInMode(POLYGON) || isInMode(ELLIPSE) || isInMode(RECTANGLE) || isInMode(RECTANGLE_FROM_LINE)) {
multiPolygonPointerAnnotation.setOffset(
pInputEvent.getCanvasPosition().getX()
+ 20.0d,
pInputEvent.getCanvasPosition().getY()
+ 20.0d);
final Collection selectedFeatures = getMappingComponent().getFeatureCollection().getSelectedFeatures();
if ((selectedPFeature == null) || (selectedFeatures.size() != 1)) {
if (pInputEvent.isAltDown()) {
multiPolygonPointerAnnotation.setMode(InvalidPolygonTooltip.Mode.SELECT_FEATURE);
multiPolygonPointerAnnotation.setVisible(true);
} else {
multiPolygonPointerAnnotation.setVisible(false);
}
} else {
if (isInProgress()) {
if (!isTempFeatureValid()) {
if (creatingHole) {
multiPolygonPointerAnnotation.setMode(InvalidPolygonTooltip.Mode.HOLE_ERROR);
} else {
multiPolygonPointerAnnotation.setMode(InvalidPolygonTooltip.Mode.ENTITY_ERROR);
}
multiPolygonPointerAnnotation.setVisible(true);
} else {
multiPolygonPointerAnnotation.setVisible(false);
}
} else {
multiPolygonPointerAnnotation.setVisible(false);
}
}
} else {
multiPolygonPointerAnnotation.setVisible(false);
final AbstractNewFeature tempFeature = getCurrentNewFeature();
if (tempFeature != null) {
final Geometry tempGeometry = tempFeature.getGeometry();
boolean errorFound = false;
if ((geometryChecks != null) && !geometryChecks.isEmpty()) {
final Point2D lastPoint = pInputEvent.getPosition();
final WorldToScreenTransform wtst = mappingComponent.getWtst();
final Coordinate lastCoordinate = new Coordinate(wtst.getSourceX(lastPoint.getX()),
wtst.getSourceY(lastPoint.getY()));
for (final GeometryCheckInterface check : geometryChecks) {
if (!check.check(tempGeometry, lastCoordinate, true)) {
multiPolygonPointerAnnotation.setCustomText("Geometrie ungültig", check.getErrorText());
errorFound = true;
}
}
}
multiPolygonPointerAnnotation.setVisible(errorFound);
}
}
}
@Override
protected void finishGeometry(final AbstractNewFeature newFeature) {
super.finishGeometry(newFeature);
if (newFeature != null) {
if (selectedPFeature == null) {
newFeature.setEditable(true);
getMappingComponent().getFeatureCollection().addFeature(newFeature);
getMappingComponent().getFeatureCollection().holdFeature(newFeature);
final PNotificationCenter pn = PNotificationCenter.defaultCenter();
pn.postNotification(
CreateGeometryListener.GEOMETRY_CREATED_NOTIFICATION,
(AbstractNewFeature)newFeature);
getMappingComponent().getMemUndo()
.addAction(new FeatureDeleteAction(getMappingComponent(), newFeature));
getMappingComponent().getMemRedo().clear();
} else {
final Polygon polygon = (Polygon)newFeature.getGeometry();
if (creatingHole) {
selectedPFeature.addHoleToEntity(selectedEntityPosition, polygon.getExteriorRing());
getMappingComponent().getMemUndo()
.addAction(new FeatureRemoveHoleAction(
getMappingComponent(),
selectedPFeature.getFeature(),
selectedEntityPosition,
polygon.getExteriorRing()));
} else {
selectedPFeature.addEntity(polygon);
getMappingComponent().getMemUndo()
.addAction(new FeatureRemoveEntityAction(
mappingComponent,
selectedPFeature.getFeature(),
polygon));
}
getMappingComponent().getMemRedo().clear();
}
}
}
@Override
public void mouseWheelRotated(final PInputEvent pie) {
// delegate zoom event
zoomDelegate.mouseWheelRotated(pie);
// trigger full repaint
mouseMoved(pie);
}
}