/***************************************************
*
* cismet GmbH, Saarbruecken, Germany
*
* ... and it just works.
*
****************************************************/
/*
* PFeature.java
*
* Created on 12. April 2005, 10:52
*/
package de.cismet.cismap.commons.gui.piccolo;
import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import edu.umd.cs.piccolo.PCamera;
import edu.umd.cs.piccolo.PNode;
import edu.umd.cs.piccolo.event.PInputEvent;
import edu.umd.cs.piccolo.nodes.PImage;
import edu.umd.cs.piccolo.nodes.PPath;
import edu.umd.cs.piccolo.nodes.PText;
import edu.umd.cs.piccolo.util.PBounds;
import edu.umd.cs.piccolo.util.PDimension;
import pswing.PSwing;
import java.awt.*;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import de.cismet.cismap.commons.Crs;
import de.cismet.cismap.commons.CrsTransformer;
import de.cismet.cismap.commons.Refreshable;
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.eventlistener.DrawSelectionFeature;
import de.cismet.cismap.commons.gui.piccolo.eventlistener.LinearReferencedPointFeature;
import de.cismet.cismap.commons.gui.piccolo.eventlistener.actions.HandleAddAction;
import de.cismet.cismap.commons.gui.piccolo.eventlistener.actions.HandleDeleteAction;
import de.cismet.cismap.commons.interaction.CismapBroker;
import de.cismet.tools.CurrentStackTrace;
import de.cismet.tools.collections.MultiMap;
/**
* DOCUMENT ME!
*
* @author hell
* @version $Revision$, $Date$
*/
public class PFeature extends PPath implements Highlightable, Selectable, Refreshable {
//~ Static fields/initializers ---------------------------------------------
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(PFeature.class);
private static final Color TRANSPARENT = new Color(255, 255, 255, 0);
private static final Stroke FIXED_WIDTH_STROKE = new FixedWidthStroke();
private static ImageIcon pushpinIco = new javax.swing.ImageIcon(PFeature.class.getResource(
"/de/cismet/cismap/commons/gui/res/pushpin.png")); // NOI18N
private static ImageIcon pushpinSelectedIco = new javax.swing.ImageIcon(PFeature.class.getResource(
"/de/cismet/cismap/commons/gui/res/pushpinSelected.png")); // NOI18N
private static final Map<String, SoftReference<Image>> imageCache = Collections.synchronizedMap(
new HashMap<String, SoftReference<Image>>());
//~ Instance fields --------------------------------------------------------
public ArrayList<PPath> sldStyledPolygon = new ArrayList();
public ArrayList<PTextWithDisplacement> sldStyledText = new ArrayList();
public ArrayList<PImage> sldStyledImage = new ArrayList();
public ArrayList<PImage> sldStyledSelectedImage = new ArrayList();
ArrayList splitHandlesBetween = new ArrayList();
PHandle splitLineAtHandle = null;
PHandle splitPolygonFromHandle = null;
PHandle splitPolygonToHandle = null;
PHandle ellipseHandle = null;
PFeature selectedOriginal = null;
PPath splitPolygonLine;
Point2D lineSplitPoint = null;
List<Point2D> splitPoints = new ArrayList<Point2D>();
Image origin = null;
private Feature feature;
private WorldToScreenTransform wtst;
private double x_offset = 0.0d;
private double y_offset = 0.0d;
private PNode stickyChild = null;
private PNode secondStickyChild = null;
private PNode infoNode = null;
private Point2D mid = null;
private PHandle pivotHandle = null;
private boolean selected = false;
private Paint nonSelectedPaint = null;
private boolean highlighted = false;
private Paint nonHighlightingPaint = null;
private Coordinate[][][] entityRingCoordArr = null;
private float[][][] entityRingXArr = null;
private float[][][] entityRingYArr = null;
// private final ArrayList<CoordEntity> coordEntityList = new ArrayList<CoordEntity>();
private MappingComponent viewer;
private Stroke stroke = null;
private Paint strokePaint = null;
// private ColorTintFilter tinter;
private boolean ignoreStickyFeature = false;
private InfoPanel infoPanel;
private JComponent infoComponent;
private PSwing pswingComp;
private PText primaryAnnotation = null;
private FeatureAnnotationSymbol pi = null;
private FeatureAnnotationSymbol piSelected;
private boolean snappable = true;
private int selectedEntity = -1;
private boolean selectedPiEdited = false;
private boolean wasSelected = false;
// r/w access only in synchronized(this) block
private transient PImage rdfImage;
private PropertyChangeListener annotationListener;
private TexturePaintPropertyChangeListener tPropertyChange;
//~ Constructors -----------------------------------------------------------
/**
* Creates a new instance of PFeature.
*
* @param feature the underlying Feature
* @param viewer MappingComponent
*/
public PFeature(final Feature feature, final MappingComponent viewer) {
this(feature, viewer.getWtst(), 0, 0, viewer);
}
/**
* Creates a new PFeature object.
*
* @param feature DOCUMENT ME!
* @param wtst DOCUMENT ME!
* @param x_offset DOCUMENT ME!
* @param y_offset DOCUMENT ME!
* @param viewer DOCUMENT ME!
*/
public PFeature(final Feature feature,
final WorldToScreenTransform wtst,
final double x_offset,
final double y_offset,
final MappingComponent viewer) {
this(feature, wtst, x_offset, y_offset, viewer, false);
}
/**
* Creates a new PFeature object.
*
* @param canvasPoints DOCUMENT ME!
* @param wtst DOCUMENT ME!
* @param x_offset DOCUMENT ME!
* @param y_offset DOCUMENT ME!
* @param viewer DOCUMENT ME!
*/
@Deprecated
public PFeature(final Point2D[] canvasPoints,
final WorldToScreenTransform wtst,
final double x_offset,
final double y_offset,
final MappingComponent viewer) {
this(new PureNewFeature(canvasPoints, wtst), wtst, 0, 0, viewer);
}
/**
* Creates a new PFeature object.
*
* @param coordArr DOCUMENT ME!
* @param wtst DOCUMENT ME!
* @param x_offset DOCUMENT ME!
* @param y_offset DOCUMENT ME!
* @param viewer DOCUMENT ME!
*/
@Deprecated
public PFeature(final Coordinate[] coordArr,
final WorldToScreenTransform wtst,
final double x_offset,
final double y_offset,
final MappingComponent viewer) {
this(new PureNewFeature(coordArr, wtst), wtst, 0, 0, viewer);
}
/**
* Creates a new PFeature object.
*
* @param feature DOCUMENT ME!
* @param wtst DOCUMENT ME!
* @param x_offset DOCUMENT ME!
* @param y_offset DOCUMENT ME!
* @param viewer DOCUMENT ME!
* @param ignoreStickyfeature DOCUMENT ME!
*/
@Deprecated
public PFeature(final Feature feature,
final WorldToScreenTransform wtst,
final double x_offset,
final double y_offset,
final MappingComponent viewer,
final boolean ignoreStickyfeature) {
try {
setFeature(feature);
this.ignoreStickyFeature = ignoreStickyfeature;
this.wtst = wtst;
// this.x_offset=x_offset;
// this.y_offset=y_offset;
this.x_offset = 0;
this.y_offset = 0;
this.viewer = viewer;
visualize();
addInfoNode();
refreshDesign();
// if the feature renderer implements the ScaleAwareFeatureRenderer interface,
// the scale must be checked, when the view scale wass changed
final FeatureRenderer renderer = getFeatureRenderer();
if ((feature instanceof StyledFeature)
&& (((StyledFeature)feature).getFillingPaint() instanceof SelectionAwareTexturePaint)) {
tPropertyChange = new TexturePaintPropertyChangeListener();
viewer.getCamera().addPropertyChangeListener(PCamera.PROPERTY_VIEW_TRANSFORM, tPropertyChange);
}
if ((renderer instanceof ScaleAwareFeatureRenderer) && (viewer != null) && (viewer.getCamera() != null)) {
viewer.getCamera()
.addPropertyChangeListener(PCamera.PROPERTY_VIEW_TRANSFORM, new PropertyChangeListener() {
@Override
public void propertyChange(final PropertyChangeEvent evt) {
if (!drawFeature()) {
if (pi != null) {
viewer.removeStickyNode(pi);
}
if (piSelected != null) {
viewer.removeStickyNode(piSelected);
}
if (stickyChild instanceof PSticky) {
viewer.removeStickyNode((PSticky)stickyChild);
}
removeAllChildren();
}
visualize();
}
});
}
stroke = getStroke();
strokePaint = getStrokePaint();
// tinter = new ColorTintFilter(Color.BLUE, 0.5f);
} catch (Throwable t) {
log.error("Error in constructor of PFeature", t); // NOI18N
}
}
//~ Methods ----------------------------------------------------------------
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public PNode getPrimaryAnnotationNode() {
return primaryAnnotation;
}
/**
* DOCUMENT ME!
*
* @param g DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws IllegalArgumentException DOCUMENT ME!
*/
public PBounds boundsFromRectPolygonGeom(final Geometry g) {
if (g instanceof Polygon) {
final Polygon poly = (Polygon)g;
if (poly.isRectangle()) {
final Coordinate[] coords = poly.getCoordinates();
final Coordinate first = coords[0];
final PBounds b = new PBounds();
// init
double x1 = first.x;
double x2 = first.x;
double y1 = first.y;
double y2 = first.y;
for (int i = 0; i < coords.length; ++i) {
final Coordinate c = coords[i];
if (c.x < x1) {
x1 = c.x;
}
if (c.x > x2) {
x2 = c.x;
}
if (c.y < y1) {
y1 = c.y;
}
if (c.y > y1) {
y2 = c.y;
}
}
return new PBounds(wtst.getScreenX(x1), wtst.getScreenY(y2), Math.abs(x2 - x1), Math.abs(y2 - y1));
}
}
throw new IllegalArgumentException("Geometry is not a rectangle polygon!"); // NOI18N
}
/**
* DOCUMENT ME!
*/
public void visualize() {
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("visualize()", new CurrentStackTrace()); // NOI18N
}
}
final Geometry geom = CrsTransformer.transformToGivenCrs(feature.getGeometry(), getViewerCrs().getCode());
if (feature instanceof RasterDocumentFeature) {
final RasterDocumentFeature rdf = (RasterDocumentFeature)feature;
try {
final PBounds bounds = boundsFromRectPolygonGeom(geom);
final PImage pImage = new PImage(rdf.getRasterDocument());
synchronized (this) {
if (rdfImage != null) {
if (indexOfChild(rdfImage) != -1) {
// Remove the rdfImage only, if it is really contained in this object. Otherwise, the PNode
// (this object) will throw a NullPointerException (if the children object of the PNode is
// null) or an IndexOutOfBoundsException (if the children object of the PNode is not null,
// but the object to delete does not exist)
removeChild(rdfImage);
}
}
rdfImage = pImage;
}
// x,y,with,heigth
pImage.setBounds(bounds);
addChild(pImage);
} catch (final IllegalArgumentException e) {
if (log.isInfoEnabled()) {
log.info("rasterdocumentfeature is no rectangle, we'll draw the geometry without raster image", e); // NOI18N
}
}
doGeometry(geom);
} else {
doGeometry(geom);
if (feature instanceof StyledFeature) {
if ((pi == null)
|| ((pi != null) && pi.equals(((StyledFeature)feature).getPointAnnotationSymbol()))) {
// log.debug("Sweetspot updated");
// pi = new FeatureAnnotationSymbol(((StyledFeature) getFeature()).getPointAnnotationSymbol()
// .getImage());
setFeatureAnnotationSymbols();
} else if ((pi != null) && (getFeature() != null) && (getFeature() instanceof StyledFeature)
&& (((StyledFeature)getFeature()).getPointAnnotationSymbol() != null)) {
// log.fatal("Sweetspot updated"); // NOI18N
final FeatureAnnotationSymbol piOrig = ((StyledFeature)getFeature()).getPointAnnotationSymbol();
if (log.isDebugEnabled()) {
log.debug("newSweetSpotx: "
+ piOrig.getSweetSpotX()); // NOI18N
}
final double sweetSpotX = piOrig.getSweetSpotX();
final double sweetSpotY = piOrig.getSweetSpotY();
if (piOrig.getSelectedFeatureAnnotationSymbol() == null) {
final double sweetX = (10 + (piOrig.getImage().getWidth(null) * sweetSpotX))
/ piSelected.getImage().getWidth(null);
final double sweetY = (10 + (piOrig.getImage().getHeight(null) * sweetSpotY))
/ piSelected.getImage().getHeight(null);
pi.setImage(piOrig.getImage());
pi.setSweetSpotX(sweetX);
pi.setSweetSpotY(sweetY);
piSelected.setImage(highlightImageAsSelected(
piOrig.getImage(),
new Color(0.3f, 0.3f, 1.0f, 0.4f),
new Color(0.2f, 0.2f, 1.0f, 0.8f),
10));
piSelected.setSweetSpotX(sweetX);
piSelected.setSweetSpotY(sweetY);
} else {
pi.setImage(piOrig.getImage());
pi.setSweetSpotX(piOrig.getSweetSpotX());
pi.setSweetSpotY(piOrig.getSweetSpotY());
piSelected.setImage(piOrig.getSelectedFeatureAnnotationSymbol().getImage());
piSelected.setSweetSpotX(piOrig.getSweetSpotX());
piSelected.setSweetSpotY(piOrig.getSweetSpotY());
}
}
} else if (pi == null) {
setFeatureAnnotationSymbols();
}
if (geom instanceof Polygon) {
if (pi instanceof ShowAlsoOnPolygons) {
final Point p = ((Polygon)geom).getInteriorPoint();
addAnnotation(p.getX(), p.getY());
}
} else if ((geom instanceof LineString) || (geom instanceof MultiLineString)) {
} else if (geom instanceof MultiPolygon) {
/* final com.vividsolutions.jts.geom.Point intPoint = CrsTransformer.transformToGivenCrs(
* geom, viewer.getMappingModel().getSrs().getCode()) .getInteriorPoint();
* addAnnotation(intPoint.getX(), intPoint.getY());*/
// MultiPolygon mp = (MultiPolygon) geom;
} else if ((geom instanceof Point) || (geom instanceof MultiPoint)) {
addAnnotation(entityRingCoordArr[0][0][0].x, entityRingCoordArr[0][0][0].y);
}
setSelected(isSelected());
}
}
/**
* DOCUMENT ME!
*/
private void setFeatureAnnotationSymbols() {
FeatureAnnotationSymbol piOrig = null;
if (!drawFeature()) {
return;
}
if (getFeature() instanceof StyledFeature) {
piOrig = ((StyledFeature)getFeature()).getPointAnnotationSymbol();
}
if ((piOrig == null) || (piOrig.getImage() == null)) {
// no FeatureAnnotationSymbol is set, use PushPin Icons as fallback case
pi = new FeatureAnnotationSymbol(pushpinIco.getImage());
piSelected = new FeatureAnnotationSymbol(pushpinSelectedIco.getImage());
if (log.isDebugEnabled()) {
log.debug("No PointAnnotationSymbol found use PushPinIcons"); // NOI18N
}
pi.setSweetSpotX(0.46d);
pi.setSweetSpotY(0.9d);
piSelected.setSweetSpotX(0.46d);
piSelected.setSweetSpotY(0.9d);
} else {
final double sweetSpotX = ((StyledFeature)getFeature()).getPointAnnotationSymbol().getSweetSpotX();
final double sweetSpotY = ((StyledFeature)getFeature()).getPointAnnotationSymbol().getSweetSpotY();
if ((piOrig != null) && (piOrig.getSelectedFeatureAnnotationSymbol() == null)) {
/*
* in this case we visualize the selection with a blue box around the icon of the
* FeatureAnnotationSymbol
*/
if (!selectedPiEdited) {
selectedPiEdited = true;
final Image iconImage = piOrig.getImage();
piSelected = new FeatureAnnotationSymbol(highlightImageAsSelected(
iconImage,
new Color(0.3f, 0.3f, 1.0f, 0.4f),
new Color(0.2f, 0.2f, 1.0f, 0.8f),
10));
final double sweetX = ((10 + (piOrig.getImage().getWidth(null) * sweetSpotX))
/ piSelected.getImage().getWidth(null));
final double sweetY = ((10 + (piOrig.getImage().getHeight(null) * sweetSpotY))
/ piSelected.getImage().getHeight(null));
piSelected.setSweetSpotX(sweetX);
piSelected.setSweetSpotY(sweetY);
}
} else {
piSelected = piOrig.getSelectedFeatureAnnotationSymbol();
}
if ((pi == null)) {
pi = new FeatureAnnotationSymbol();
final Image iconImage = piOrig.getImage();
final BufferedImage img = new BufferedImage(iconImage.getWidth(null),
iconImage.getHeight(null),
BufferedImage.TYPE_INT_ARGB);
final Graphics g = img.getGraphics();
g.drawImage(iconImage, 0, 0, null);
if (piOrig.getSelectedFeatureAnnotationSymbol() == null) {
/*
* draw an invisble frame around the icon, this places the info node at the same position as for the
* selected FeatureAnnotationSymbol
*/
pi.setImage(highlightImageAsSelected(img, TRANSPARENT, TRANSPARENT, 10));
final double sweetX = ((10 + (piOrig.getImage().getWidth(null) * sweetSpotX))
/ piSelected.getImage().getWidth(null));
final double sweetY = ((10 + (piOrig.getImage().getHeight(null) * sweetSpotY))
/ piSelected.getImage().getHeight(null));
pi.setSweetSpotX(sweetX);
pi.setSweetSpotY(sweetY);
} else {
pi.setImage(img);
pi.setSweetSpotX(piOrig.getSweetSpotX());
pi.setSweetSpotY(piOrig.getSweetSpotY());
}
}
pi.setSelectedFeatureAnnotationSymbol(piSelected);
}
if ((annotationListener != null) && (pi != null)) {
pi.addPropertyChangeListener(annotationListener);
}
if ((annotationListener != null) && (piSelected != null)) {
piSelected.addPropertyChangeListener(annotationListener);
}
}
/**
* DOCUMENT ME!
*
* @param real_x DOCUMENT ME!
* @param real_y DOCUMENT ME!
*/
private void addAnnotation(final double real_x, final double real_y) {
if (!drawFeature()) {
return;
}
if (!ignoreStickyFeature && drawFeature()) {
viewer.addStickyNode(pi);
viewer.addStickyNode(piSelected);
}
// Hier soll getestet werden ob bei einem Punkt der pushpin schon hinzugef\u00FCgt wurde. Wegen
// reconsider Feature
if (stickyChild == null) {
stickyChild = pi;
} else if (stickyChild instanceof StickyPText) {
secondStickyChild = pi;
}
addChild(piSelected);
piSelected.setOffset(wtst.getScreenX(real_x), wtst.getScreenY(real_y));
addChild(pi);
pi.setOffset(wtst.getScreenX(real_x), wtst.getScreenY(real_y));
}
/**
* Dupliziert eine Koordinate.
*
* @param entityPosition DOCUMENT ME!
* @param ringPosition DOCUMENT ME!
* @param coordPosition Position der zu duplizierenden Koordinate
*/
public void duplicateCoordinate(final int entityPosition, final int ringPosition, final int coordPosition) {
final Coordinate[] origCoordArr = entityRingCoordArr[entityPosition][ringPosition];
final float[] origXArr = entityRingXArr[entityPosition][ringPosition];
final float[] origYArr = entityRingYArr[entityPosition][ringPosition];
final Geometry geometry = getFeature().getGeometry();
if (((geometry instanceof Polygon) && (origCoordArr != null)
&& ((origCoordArr.length - 1) > coordPosition))
|| ((geometry instanceof LineString) && (origCoordArr != null)
&& (origCoordArr.length > coordPosition)
&& (origCoordArr.length > 2))) {
final Coordinate[] newCoordArr = new Coordinate[origCoordArr.length + 1];
final float[] newXArr = new float[origXArr.length + 1];
final float[] newYArr = new float[origYArr.length + 1];
// vorher
for (int i = 0; i <= coordPosition; ++i) {
newCoordArr[i] = origCoordArr[i];
newXArr[i] = origXArr[i];
newYArr[i] = origYArr[i];
}
// zu entferndes Element duplizieren, hier muss geklont werden
newCoordArr[coordPosition + 1] = (Coordinate)(origCoordArr[coordPosition].clone());
newXArr[coordPosition + 1] = origXArr[coordPosition];
newYArr[coordPosition + 1] = origYArr[coordPosition];
// nachher
for (int i = coordPosition + 1; i < origCoordArr.length; ++i) {
newCoordArr[i + 1] = origCoordArr[i];
newXArr[i + 1] = origXArr[i];
newYArr[i + 1] = origYArr[i];
}
// Sicherstellen dass der neue Anfangspunkt auch der Endpukt ist
if ((coordPosition == 0) && (geometry instanceof Polygon)) {
newCoordArr[newCoordArr.length - 1] = newCoordArr[0];
newXArr[newXArr.length - 1] = newXArr[0];
newYArr[newXArr.length - 1] = newYArr[0];
}
setNewCoordinates(entityPosition, ringPosition, newXArr, newYArr, newCoordArr);
}
}
/**
* Liefert eine exakte Kopie dieses PFeatures. Es besitzt denselben Inhalt, jedoch einen anderen Hashwert als das
* Original.
*
* @return Kopie dieses PFeatures
*/
@Override
public Object clone() {
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("clone()", new CurrentStackTrace()); // NOI18N
}
}
final PFeature p = new PFeature(feature, wtst, this.x_offset, y_offset, viewer);
p.splitPolygonFromHandle = splitPolygonFromHandle;
p.splitPolygonToHandle = splitPolygonToHandle;
return p;
}
/**
* DOCUMENT ME!
*
* @param coord coordEntity DOCUMENT ME!
* @param geometryFactory DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
private static Point createPoint(final Coordinate coord, final GeometryFactory geometryFactory) {
return geometryFactory.createPoint(coord);
}
/**
* DOCUMENT ME!
*
* @param coordArray DOCUMENT ME!
* @param geometryFactory DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
private static MultiPoint createMultiPoint(final Coordinate[] coordArray, final GeometryFactory geometryFactory) {
return geometryFactory.createMultiPoint(coordArray);
}
/**
* DOCUMENT ME!
*
* @param coordArray coordEntity DOCUMENT ME!
* @param geometryFactory DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
private static LineString createLineString(final Coordinate[] coordArray, final GeometryFactory geometryFactory) {
return geometryFactory.createLineString(coordArray);
}
/**
* DOCUMENT ME!
*
* @param ringCoordArray coordEntity DOCUMENT ME!
* @param geometryFactory DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
private static Polygon createPolygon(final Coordinate[][] ringCoordArray, final GeometryFactory geometryFactory) {
// ring des polygons erstellen
final LinearRing shell = geometryFactory.createLinearRing(ringCoordArray[0]);
// ringe der löscher erstellen
final Collection<LinearRing> holes = new ArrayList<LinearRing>();
for (int ringIndex = 1; ringIndex < ringCoordArray.length; ringIndex++) {
final LinearRing holeShell = geometryFactory.createLinearRing(ringCoordArray[ringIndex]);
holes.add(holeShell);
}
// polygon erstellen und hinzufügen
final Polygon polygon = geometryFactory.createPolygon(shell, holes.toArray(new LinearRing[0]));
return polygon;
}
/**
* Gleicht die Geometrie an das PFeature an. Erstellt die jeweilige Geometrie (Punkt, Linie, Polygon) und f\u00FCgt
* sie dem Feature hinzu.
*/
public void syncGeometry() {
try {
if (getFeature().isEditable()) {
// geometryfactory erzeugen
final GeometryFactory geometryFactory = new GeometryFactory(
new PrecisionModel(PrecisionModel.FLOATING),
CrsTransformer.extractSridFromCrs(getViewerCrs().getCode()));
// sonderfall multipolygon TODO eigentlich garkein sonderfall, multipoint und multilinestring müssen
// langfristig genauso behandelt werden
if ((getFeature().getGeometry() instanceof MultiPolygon)
|| ((getFeature().getGeometry() instanceof Polygon) && (entityRingCoordArr.length > 1))) {
final Collection<Polygon> polygons = new ArrayList<Polygon>(entityRingCoordArr.length);
for (int entityIndex = 0; entityIndex < entityRingCoordArr.length; entityIndex++) {
final Polygon polygon = createPolygon(entityRingCoordArr[entityIndex], geometryFactory);
polygons.add(polygon);
}
// multipolygon aus den polygonen erzeugen
final MultiPolygon multiPolygon = geometryFactory.createMultiPolygon(polygons.toArray(
new Polygon[0]));
assignSynchronizedGeometry(multiPolygon);
} else if ((getFeature().getGeometry() instanceof MultiPoint)) {
final MultiPoint multiPoint = geometryFactory.createMultiPoint(entityRingCoordArr[0][0]);
assignSynchronizedGeometry(multiPoint);
} else {
final boolean isSingle = entityRingCoordArr.length == 1;
if (isSingle) {
if (entityRingCoordArr[0][0] == null) {
log.warn("coordArr==null"); // NOI18N
} else {
final boolean isPoint = entityRingCoordArr[0][0].length == 1;
final boolean isPolygon = (entityRingCoordArr[0][0].length > 3)
&& entityRingCoordArr[0][0][0].equals(
entityRingCoordArr[0][0][entityRingCoordArr[0][0].length - 1]);
final boolean isLineString = !isPoint && !isPolygon;
if (isPoint) {
assignSynchronizedGeometry(createPoint(entityRingCoordArr[0][0][0], geometryFactory));
} else if (isLineString) {
assignSynchronizedGeometry(createLineString(entityRingCoordArr[0][0], geometryFactory));
} else if (isPolygon) {
assignSynchronizedGeometry(createPolygon(entityRingCoordArr[0], geometryFactory));
}
}
}
}
}
} catch (Exception e) {
log.error("Error while synchronising PFeature with feature.", e);
}
}
/**
* Assigns the PFeature geometry to the feature if they differ. The feature will keep its crs.
*
* @param newGeom DOCUMENT ME!
*/
private void assignSynchronizedGeometry(final Geometry newGeom) {
final Geometry oldGeom = feature.getGeometry();
final String oldCrs = CrsTransformer.createCrsFromSrid(oldGeom.getSRID());
final String newCrs = CrsTransformer.createCrsFromSrid(newGeom.getSRID());
// if (!newGeom.isValid()) {
// doGeometry(oldGeom);
// return;
// }
//
if ((newGeom.getSRID() == oldGeom.getSRID())
|| (CrsTransformer.isDefaultCrs(oldCrs) && CrsTransformer.isDefaultCrs(newCrs))) {
if (log.isDebugEnabled()) {
log.debug("feature and pfeature geometry differ, but have the same crs and will be synchronized."); // NOI18N
}
if (CrsTransformer.isDefaultCrs(newCrs)) {
newGeom.setSRID(CismapBroker.getInstance().getDefaultCrsAlias());
}
feature.setGeometry(newGeom);
} else {
try {
final CrsTransformer transformer = new CrsTransformer(newCrs);
final Geometry oldGeomWithNewSrid = transformer.transformGeometry(oldGeom, oldCrs);
if (!oldGeomWithNewSrid.equalsExact(newGeom)) {
final CrsTransformer reverseTransformer = new CrsTransformer(oldCrs);
final Geometry newGeomWithOldSrid = reverseTransformer.fastTransformGeometry(newGeom, newCrs);
if (log.isDebugEnabled()) {
log.debug("feature and pfeature geometry differ and will be synchronized."); // NOI18N
}
if (CrsTransformer.isDefaultCrs(oldCrs)) {
newGeomWithOldSrid.setSRID(CismapBroker.getInstance().getDefaultCrsAlias());
}
feature.setGeometry(newGeomWithOldSrid);
} else if (log.isDebugEnabled()) {
log.debug("feature and pfeature geometry do not differ."); // NOI18N
}
} catch (final Exception e) {
log.error("Cannot synchronize feature.", e); // NOI18N
}
}
}
/**
* Erzeugt Koordinaten- und Punktarrays aus einem gegebenen Geometry-Objekt.
*
* @param geom vorhandenes Geometry-Objekt
*/
private void doGeometry(final Geometry geom) {
entityRingCoordArr = getCoordinateArray(geom);
if ((geom != null) && drawFeature()) {
updateXpAndYp();
updatePath();
} else {
entityRingXArr = null;
entityRingYArr = null;
getPathReference().reset();
}
refreshDesign();
syncGeometry();
}
/**
* If the feature has a ScaleAwareFeatureRenderer, the geometry should possibly not be drawn in the map.
*
* @return true, if the geometry should be drawn. False otherwise
*/
private boolean drawFeature() {
final FeatureRenderer renderer = getFeatureRenderer();
if (renderer instanceof ScaleAwareFeatureRenderer) {
final int minScale = ((ScaleAwareFeatureRenderer)renderer).getMinScale();
final int maxScale = ((ScaleAwareFeatureRenderer)renderer).getMaxScale();
final double scale = viewer.getScaleDenominator();
return (maxScale <= scale) && (minScale >= scale);
}
return true;
}
/**
* Determines the feature renderer of the feature.
*
* @return the feature renderer of the feature or null, if it hasn't one
*/
private FeatureRenderer getFeatureRenderer() {
if (feature instanceof FeatureRendererAwareFeature) {
FeatureRenderer renderer = ((FeatureRendererAwareFeature)feature).getFeatureRenderer();
if (renderer == null) {
renderer = ((FeatureRendererAwareFeature)feature).getParentFeatureRenderer();
}
return renderer;
}
return null;
}
/**
* DOCUMENT ME!
*
* @param geom vorhandenes Geometry-Objekt
*
* @return DOCUMENT ME!
*/
private Coordinate[][][] getCoordinateArray(final Geometry geom) {
Coordinate[][][] otherCoords = null;
if (geom instanceof Point) {
final Point point = (Point)geom;
otherCoords = new Coordinate[][][] {
{
{ point.getCoordinate() }
}
};
} else if (geom instanceof LineString) {
final LineString lineString = (LineString)geom;
otherCoords = new Coordinate[][][] {
{ lineString.getCoordinates() }
};
} else if (geom instanceof Polygon) {
final Polygon polygon = (Polygon)geom;
final int numOfHoles = polygon.getNumInteriorRing();
otherCoords = new Coordinate[1][1 + numOfHoles][];
otherCoords[0][0] = polygon.getExteriorRing().getCoordinates();
for (int ringIndex = 1; ringIndex < otherCoords[0].length; ++ringIndex) {
otherCoords[0][ringIndex] = polygon.getInteriorRingN(ringIndex - 1).getCoordinates();
}
} else if (geom instanceof LinearRing) {
// doPolygon((Polygon)geom);
} else if (geom instanceof MultiPoint) {
otherCoords = new Coordinate[][][] {
{ ((MultiPoint)geom).getCoordinates() }
};
} else if (geom instanceof MultiLineString) {
final MultiLineString multiLineString = (MultiLineString)geom;
final int numOfGeoms = multiLineString.getNumGeometries();
otherCoords = new Coordinate[numOfGeoms][][];
for (int entityIndex = 0; entityIndex < numOfGeoms; ++entityIndex) {
final Coordinate[] coordSubArr = ((LineString)multiLineString.getGeometryN(entityIndex))
.getCoordinates();
otherCoords[entityIndex] = new Coordinate[][] { coordSubArr };
}
} else if (geom instanceof MultiPolygon) {
final MultiPolygon multiPolygon = (MultiPolygon)geom;
final int numOfEntities = multiPolygon.getNumGeometries();
otherCoords = new Coordinate[numOfEntities][][];
for (int entityIndex = 0; entityIndex < numOfEntities; ++entityIndex) {
final Polygon polygon = (Polygon)multiPolygon.getGeometryN(entityIndex);
final int numOfHoles = polygon.getNumInteriorRing();
otherCoords[entityIndex] = new Coordinate[1 + numOfHoles][];
otherCoords[entityIndex][0] = polygon.getExteriorRing().getCoordinates();
for (int ringIndex = 1; ringIndex < otherCoords[entityIndex].length; ++ringIndex) {
otherCoords[entityIndex][ringIndex] = polygon.getInteriorRingN(ringIndex - 1).getCoordinates();
}
}
} else if (geom instanceof GeometryCollection) {
final GeometryCollection gc = (GeometryCollection)geom;
final int numOfGeoms = gc.getNumGeometries();
otherCoords = new Coordinate[numOfGeoms][][];
for (int entityIndex = 0; entityIndex < numOfGeoms; ++entityIndex) {
final Coordinate[][][] coordSubArr = getCoordinateArray(gc.getGeometryN(entityIndex));
otherCoords[entityIndex] = coordSubArr[0];
}
}
return otherCoords;
}
/**
* DOCUMENT ME!
*
* @param geom DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public boolean hasSameGeometry(final Geometry geom) {
final Coordinate[][][] otherCoords = getCoordinateArray(geom);
return Arrays.deepEquals(otherCoords, entityRingCoordArr);
}
/**
* DOCUMENT ME!
*/
private void updateXpAndYp() {
entityRingXArr = new float[entityRingCoordArr.length][][];
entityRingYArr = new float[entityRingCoordArr.length][][];
for (int entityIndex = 0; entityIndex < entityRingCoordArr.length; entityIndex++) {
entityRingXArr[entityIndex] = new float[entityRingCoordArr[entityIndex].length][];
entityRingYArr[entityIndex] = new float[entityRingCoordArr[entityIndex].length][];
for (int ringIndex = 0; ringIndex < entityRingCoordArr[entityIndex].length; ringIndex++) {
final Coordinate[] transformedCoordArr = transformCoordinateArr(
entityRingCoordArr[entityIndex][ringIndex]);
final int length = transformedCoordArr.length;
entityRingXArr[entityIndex][ringIndex] = new float[length];
entityRingYArr[entityIndex][ringIndex] = new float[length];
for (int coordIndex = 0; coordIndex < length; coordIndex++) {
entityRingXArr[entityIndex][ringIndex][coordIndex] = (float)transformedCoordArr[coordIndex].x;
entityRingYArr[entityIndex][ringIndex][coordIndex] = (float)transformedCoordArr[coordIndex].y;
}
}
}
}
/**
* DOCUMENT ME!
*
* @param entityPosition DOCUMENT ME!
* @param ringPosition DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public Coordinate[] getCoordArr(final int entityPosition, final int ringPosition) {
return entityRingCoordArr[entityPosition][ringPosition];
}
/**
* DOCUMENT ME!
*
* @param entityPosition DOCUMENT ME!
* @param ringPosition DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public float[] getXp(final int entityPosition, final int ringPosition) {
return entityRingXArr[entityPosition][ringPosition];
}
/**
* DOCUMENT ME!
*
* @param entityPosition DOCUMENT ME!
* @param ringPosition DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public float[] getYp(final int entityPosition, final int ringPosition) {
return entityRingYArr[entityPosition][ringPosition];
}
/**
* F\u00FCgt dem PFeature ein weiteres Coordinate-Array hinzu. Dadurch entstehen Multipolygone und Polygone mit
* L\u00F6chern, je nachdem, ob der neue LinearRing ausserhalb oder innerhalb des PFeatures liegt.
*
* @param coordinateArr die Koordinaten des hinzuzuf\u00FCgenden Rings als Coordinate-Array
*/
private void addLinearRing(final Coordinate[] coordinateArr) {
final Coordinate[] points = transformCoordinateArr(coordinateArr);
final GeneralPath gp = new GeneralPath();
gp.reset();
if (points.length > 0) {
gp.moveTo((float)points[0].x, (float)points[0].y);
for (int i = 1; i < points.length; i++) {
gp.lineTo((float)points[i].x, (float)points[i].y);
}
}
// use getPathReference().append(gp, false); instead of append(gp, false); due to performance reasons
getPathReference().append(gp, false);
}
/**
* Erzeugt PCanvas-Koordinaten-Punktarrays aus Realworldkoordinaten.
*
* @param coordinateArr Array mit Realworld-Koordinaten
*
* @return DOCUMENT ME!
*/
private Coordinate[] transformCoordinateArr(final Coordinate[] coordinateArr) {
final Coordinate[] points = new Coordinate[coordinateArr.length];
for (int i = 0; i < coordinateArr.length; ++i) {
points[i] = new Coordinate();
if (wtst == null) {
points[i].x = (float)(coordinateArr[i].x + x_offset);
points[i].y = (float)(coordinateArr[i].y + y_offset);
} else {
points[i].x = (float)(wtst.getDestX(coordinateArr[i].x) + x_offset);
points[i].y = (float)(wtst.getDestY(coordinateArr[i].y) + y_offset);
}
}
return points;
}
/**
* Setzt die Zeichenobjekte des Features (z.B. unselektiert=rot) und st\u00F6\u00DFt ein Neuzeichnen an.
*/
public void refreshDesign() {
if (primaryAnnotation != null) {
if (indexOfChild(primaryAnnotation) != -1) {
// Remove the primaryAnnotation only, if it is really contained in this object.
// Otherwise, the PNode (this object) will throw a NullPointerException (if the children
// object of the PNode is null) or an IndexOutOfBoundsException (if the children object of the PNode
// is not null, but the object to delete does not exist)
removeChild(primaryAnnotation);
}
viewer.removeStickyNode((StickyPText)primaryAnnotation);
}
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("refreshDesign()", new CurrentStackTrace()); // NOI18N
}
}
if (getFeature().isHidden() && !getFeature().isEditable()) {
setStroke(null);
setPaint(null);
} else {
// hier muss die Anpassung bei den WFS Features hin.
Stroke overridingstroke = null;
if (getFeature() instanceof XStyledFeature) {
final XStyledFeature xsf = (XStyledFeature)getFeature();
overridingstroke = xsf.getLineStyle();
}
if (getFeature() instanceof RasterDocumentFeature) {
overridingstroke = FIXED_WIDTH_STROKE;
}
if ((getFeature() instanceof StyledFeature) && (overridingstroke == null)) {
final StyledFeature sf = (StyledFeature)getFeature();
if (sf.getLineWidth() <= 1) {
setStroke(FIXED_WIDTH_STROKE);
} else {
final CustomFixedWidthStroke old = new CustomFixedWidthStroke(sf.getLineWidth(), viewer);
setStroke(old);
}
// Falls absichtlich keine Linie gesetzt worden ist (z.B. im StyleDialog)
if (sf.getLinePaint() == null) {
setStroke(null);
}
}
if (overridingstroke != null) {
setStroke(overridingstroke);
}
if ((getFeature().getGeometry() instanceof LineString)
|| (getFeature().getGeometry() instanceof MultiLineString)) {
if ((feature instanceof StyledFeature)) {
final java.awt.Paint linePaint = ((StyledFeature)feature).getLinePaint();
if (linePaint != null) {
setStrokePaint(linePaint);
}
}
} else if ((feature instanceof StyledFeature)) {
final java.awt.Paint paint = ((StyledFeature)feature).getFillingPaint();
final java.awt.Paint linePaint = ((StyledFeature)feature).getLinePaint();
if (paint != null) {
if (paint instanceof SelectionAwareTexturePaint) {
((SelectionAwareTexturePaint)paint).setScale(viewer.getCamera().getViewScale(),
CrsTransformer.transformToGivenCrs(feature.getGeometry(), getViewerCrs().getCode()));
setPaint(((SelectionAwareTexturePaint)paint).getPaint());
} else if (paint instanceof PaintWrapper) {
setPaint(((PaintWrapper)paint).getPaint());
} else {
setPaint(paint);
}
nonHighlightingPaint = paint;
}
if (linePaint != null) {
setStrokePaint(linePaint);
}
}
if (feature instanceof SLDStyledFeature) {
((SLDStyledFeature)feature).applyStyle(this, wtst);
nonHighlightingPaint = getPaint();
}
stroke = getStroke();
strokePaint = getStrokePaint();
setSelected(this.isSelected());
// TODO:Wenn feature=labeledFeature jetzt noch Anpassungen machen
if (((feature instanceof AnnotatedFeature) && ((AnnotatedFeature)feature).isPrimaryAnnotationVisible()
&& (((AnnotatedFeature)feature).getPrimaryAnnotation() != null)) && drawFeature()) {
final AnnotatedFeature af = (AnnotatedFeature)feature;
primaryAnnotation = new StickyPText(" " + af.getPrimaryAnnotation() + " ");
primaryAnnotation.setJustification(af.getPrimaryAnnotationJustification());
if (af.isAutoscale() && !(getFeature().getGeometry() instanceof Point)) {
stickyChild = primaryAnnotation;
}
viewer.getCamera()
.addPropertyChangeListener(PCamera.PROPERTY_VIEW_TRANSFORM, new PropertyChangeListener() {
@Override
public void propertyChange(final PropertyChangeEvent evt) {
setVisibility(primaryAnnotation, af);
}
});
// if (true || af.getMaxScaleDenominator() == null || af.getMinScaleDenominator() == null ||
// af.getMaxScaleDenominator() > denom && af.getMinScaleDenominator() < denom) {
if (af.getPrimaryAnnotationPaint() != null) {
primaryAnnotation.setTextPaint(af.getPrimaryAnnotationPaint());
} else {
primaryAnnotation.setTextPaint(Color.BLACK);
}
if (af.getPrimaryAnnotationHalo() != null) {
primaryAnnotation.setPaint(af.getPrimaryAnnotationHalo());
}
if (af.getPrimaryAnnotationScaling() > 0) {
primaryAnnotation.setScale(af.getPrimaryAnnotationScaling());
}
if (af.getPrimaryAnnotationFont() != null) {
primaryAnnotation.setFont(af.getPrimaryAnnotationFont());
}
final boolean vis = primaryAnnotation.getVisible();
final Point intPoint = CrsTransformer.transformToGivenCrs(feature.getGeometry(),
getViewerCrs().getCode())
.getInteriorPoint();
if ((stickyChild != null) && (af.getPrimaryAnnotationJustification() == 0.0)
&& (getFeature().getGeometry() instanceof Point)) {
if (annotationListener == null) {
annotationListener = new PropertyChangeListener() {
@Override
public void propertyChange(final PropertyChangeEvent evt) {
justifyAnnotations((PNode)evt.getSource(), af.isAutoscale());
}
};
if (primaryAnnotation != stickyChild) {
stickyChild.addPropertyChangeListener("fullBounds", annotationListener);
}
if (pi != null) {
pi.addPropertyChangeListener("fullBounds", annotationListener);
}
if (piSelected != null) {
piSelected.addPropertyChangeListener("fullBounds", annotationListener);
}
}
} else {
primaryAnnotation.setOffset(wtst.getScreenX(intPoint.getX()), wtst.getScreenY(intPoint.getY()));
}
addChild(primaryAnnotation);
if (!ignoreStickyFeature && af.isAutoscale()) {
viewer.addStickyNode((StickyPText)primaryAnnotation);
viewer.rescaleStickyNode((StickyPText)primaryAnnotation);
}
setVisibility(primaryAnnotation, af);
}
}
}
/**
* justifies the annotations of the feature.
*
* @param source the parent symbol of the primary annotation
* @param autoScale true, if the annotation has autoscale enabled
*/
private void justifyAnnotations(final PNode source, final boolean autoScale) {
if ((primaryAnnotation != null) && (source != null)) {
final Point intPoint = CrsTransformer.transformToGivenCrs(feature.getGeometry(),
getViewerCrs().getCode()).getInteriorPoint();
final PBounds bounds = source.getFullBoundsReference();
if (autoScale) {
primaryAnnotation.setScale(source.getScale());
}
if (feature instanceof DrawingFeature) {
primaryAnnotation.setOffset(wtst.getScreenX(intPoint.getX()), wtst.getScreenY(intPoint.getY()));
} else {
primaryAnnotation.setOffset(wtst.getScreenX(intPoint.getX()) + (bounds.getWidth() / 2),
// + (bounds.getWidth() / 4),
wtst.getScreenY(intPoint.getY())
- (bounds.getHeight() / 2));
}
}
}
/**
* DOCUMENT ME!
*
* @param ptext DOCUMENT ME!
* @param af DOCUMENT ME!
*/
private void setVisibility(final PText ptext, final AnnotatedFeature af) {
final double denom = viewer.getScaleDenominator();
if ((af.getMaxScaleDenominator() == null) || (af.getMinScaleDenominator() == null)
|| ((af.getMaxScaleDenominator() > denom) && (af.getMinScaleDenominator() < denom))) {
ptext.setVisible(true);
} else {
ptext.setVisible(false);
}
}
/**
* F\u00FCgt eine neue \u00FCbergebene Koordinate in das Koordinatenarray ein, statt nur einen Punkt zu duplizieren.
*
* @param entityPosition DOCUMENT ME!
* @param ringPosition DOCUMENT ME!
* @param coordPosition die Position des neuen Punktes im Array
* @param newValueX original das Original-Array
* @param newValueY der einzuf\u00FCgende Wert
*/
public void insertCoordinate(final int entityPosition,
final int ringPosition,
final int coordPosition,
final float newValueX,
final float newValueY) {
insertCoordinate(entityPosition, ringPosition, coordPosition, newValueX, newValueY, true);
}
/**
* DOCUMENT ME!
*
* @param entityPosition DOCUMENT ME!
* @param ringPosition DOCUMENT ME!
* @param coordPosition DOCUMENT ME!
* @param newValueX DOCUMENT ME!
* @param newValueY DOCUMENT ME!
* @param addUndo DOCUMENT ME!
*/
public void insertCoordinate(final int entityPosition,
final int ringPosition,
final int coordPosition,
final float newValueX,
final float newValueY,
final boolean addUndo) {
insertCoordinateToPosition(entityPosition, ringPosition, coordPosition, newValueX, newValueY, addUndo);
if (viewer.isSnappingEnabled()
&& ((getFeature().getGeometry() instanceof LineString)
|| (getFeature().getGeometry() instanceof Polygon)
|| (getFeature().getGeometry() instanceof MultiPolygon))) { // Snapping Modus
// Features suchen bei denen der zukünftige neue
// Punkt auf einer identischen Linie sitzt
final float[] xp = getXp(entityPosition, ringPosition);
final float[] yp = getYp(entityPosition, ringPosition);
final LineSegment segment;
// neuer punkt ist auf coordPosition gelandet, die alte Linie war also
// von coordPosition - 1 zu coordPosition + 1
if (coordPosition > 0) {
segment = new LineSegment(
xp[coordPosition - 1],
yp[coordPosition - 1],
xp[coordPosition + 1],
yp[coordPosition + 1]);
} else {
segment = new LineSegment(xp[xp.length - 1], yp[yp.length - 1], xp[1], yp[1]);
}
// Alle Objekte durchlaufen
for (final Feature otherFeature : viewer.getFeatureCollection().getAllFeatures()) {
final PFeature otherPFeature = (PFeature)viewer.getPFeatureHM().get(otherFeature);
if ((otherPFeature != null) && otherPFeature.getFeature().isEditable()) {
final Geometry geometry = otherPFeature.getFeature().getGeometry();
if ((geometry instanceof Polygon) || (geometry instanceof LineString)
|| (geometry instanceof MultiPolygon)) {
for (int entityIndex = 0; entityIndex < otherPFeature.getNumOfEntities(); entityIndex++) {
for (int ringIndex = 0; ringIndex < otherPFeature.getNumOfRings(entityIndex); ringIndex++) {
final float[] otherXp = otherPFeature.getXp(entityIndex, ringIndex);
final float[] otherYp = otherPFeature.getYp(entityIndex, ringIndex);
for (int coordIndex = otherXp.length - 1; coordIndex > 0; coordIndex--) {
final LineSegment otherSegment = new LineSegment(
otherXp[coordIndex - 1],
otherYp[coordIndex - 1],
otherXp[coordIndex],
otherYp[coordIndex]);
// sind die 2 Nachbarpunkte identisch mit den 2 Nachbarn des neuen Punktes =>
// identische
if (otherSegment.equalsTopo(segment)) {
// Punkt dem jeweiligen Feature hinzufügen
otherPFeature.insertCoordinateToPosition(
entityIndex,
ringIndex,
coordIndex,
newValueX,
newValueY,
addUndo);
}
}
}
}
}
}
}
}
}
/**
* DOCUMENT ME!
*
* @param entityPosition DOCUMENT ME!
* @param ringPosition DOCUMENT ME!
* @param coordPosition DOCUMENT ME!
* @param newValueX DOCUMENT ME!
* @param newValueY DOCUMENT ME!
* @param addUndo DOCUMENT ME!
*/
private void insertCoordinateToPosition(final int entityPosition,
final int ringPosition,
final int coordPosition,
final float newValueX,
final float newValueY,
final boolean addUndo) {
final Coordinate[] originalCoordArr = entityRingCoordArr[entityPosition][ringPosition];
final float[] originalXArr = entityRingXArr[entityPosition][ringPosition];
final float[] originalYArr = entityRingYArr[entityPosition][ringPosition];
if ((((getFeature().getGeometry() instanceof Polygon) || (getFeature().getGeometry() instanceof MultiPolygon))
&& (originalXArr != null)
&& ((originalXArr.length - 1) >= coordPosition))
|| ((getFeature().getGeometry() instanceof LineString) && (originalXArr != null)
&& (originalXArr.length > coordPosition)
&& (originalXArr.length >= 2))) {
final Coordinate[] newCoordArr = new Coordinate[originalCoordArr.length + 1];
final float[] newXArr = new float[originalXArr.length + 1];
final float[] newYArr = new float[originalYArr.length + 1];
// vorher
for (int i = 0; i < coordPosition; ++i) {
newCoordArr[i] = originalCoordArr[i];
newXArr[i] = originalXArr[i];
newYArr[i] = originalYArr[i];
}
newCoordArr[coordPosition] = new Coordinate(viewer.getWtst().getSourceX(newValueX),
viewer.getWtst().getSourceY(newValueY));
newXArr[coordPosition] = newValueX;
newYArr[coordPosition] = newValueY;
// nachher
for (int i = coordPosition; i < originalCoordArr.length; ++i) {
newCoordArr[i + 1] = originalCoordArr[i];
newXArr[i + 1] = originalXArr[i];
newYArr[i + 1] = originalYArr[i];
}
if ((getFeature().getGeometry() instanceof Polygon)
|| (getFeature().getGeometry() instanceof MultiPolygon)) {
// Sicherstellen dass der neue Anfangspunkt auch der Endpukt ist
if ((coordPosition == 0) || (coordPosition == (originalCoordArr.length - 1))) {
newCoordArr[newCoordArr.length - 1] = newCoordArr[0];
newXArr[newXArr.length - 1] = newXArr[0];
newYArr[newYArr.length - 1] = newYArr[0];
}
}
setNewCoordinates(entityPosition, ringPosition, newXArr, newYArr, newCoordArr);
if (addUndo) {
viewer.getMemUndo()
.addAction(new HandleDeleteAction(
viewer,
feature,
entityPosition,
ringPosition,
coordPosition,
newValueX,
newValueY));
}
}
}
/**
* Entfernt eine Koordinate aus der Geometrie, z.B. beim L\u00F6schen eines Handles.
*
* @param entityPosition DOCUMENT ME!
* @param ringPosition DOCUMENT ME!
* @param coordPosition Position des zu l\u00F6schenden Punkes im Koordinatenarray
*/
public void removeCoordinate(final int entityPosition, final int ringPosition, final int coordPosition) {
removeCoordinate(entityPosition, ringPosition, coordPosition, true);
}
/**
* DOCUMENT ME!
*
* @param entityPosition DOCUMENT ME!
* @param ringPosition DOCUMENT ME!
* @param coordPosition DOCUMENT ME!
* @param addUndo DOCUMENT ME!
*/
public void removeCoordinate(final int entityPosition,
final int ringPosition,
final int coordPosition,
final boolean addUndo) {
final Coordinate[] originalCoordArr = entityRingCoordArr[entityPosition][ringPosition];
final float[] originalXArr = entityRingXArr[entityPosition][ringPosition];
final float[] originalYArr = entityRingYArr[entityPosition][ringPosition];
if ((((getFeature().getGeometry() instanceof Polygon) || (getFeature().getGeometry() instanceof MultiPolygon))
&& (originalCoordArr != null)
&& ((originalCoordArr.length - 1) > coordPosition))
|| ((getFeature().getGeometry() instanceof LineString) && (originalCoordArr != null)
&& (originalCoordArr.length > coordPosition)
&& (originalCoordArr.length > 2))) {
final Coordinate[] newCoordArr = new Coordinate[originalCoordArr.length - 1];
final float[] newXArr = new float[originalXArr.length - 1];
final float[] newYArr = new float[originalYArr.length - 1];
// vorher
for (int i = 0; i < coordPosition; ++i) {
newCoordArr[i] = originalCoordArr[i];
newXArr[i] = originalXArr[i];
newYArr[i] = originalYArr[i];
}
// zu entferndes Element \u00FCberspringen
final float removedX = originalXArr[coordPosition];
final float removedY = originalYArr[coordPosition];
// nachher
for (int i = coordPosition; i < newCoordArr.length; ++i) {
newCoordArr[i] = originalCoordArr[i + 1];
newXArr[i] = originalXArr[i + 1];
newYArr[i] = originalYArr[i + 1];
}
// Sicherstellen dass der neue Anfangspunkt auch der Endpukt ist (nur beim Polygon)
if (((coordPosition == 0) && (getFeature().getGeometry() instanceof Polygon))
|| (getFeature().getGeometry() instanceof MultiPolygon)) {
newCoordArr[newCoordArr.length - 1] = newCoordArr[0];
newXArr[newXArr.length - 1] = newXArr[0];
newXArr[newYArr.length - 1] = newYArr[0];
}
setNewCoordinates(entityPosition, ringPosition, newXArr, newYArr, newCoordArr);
// Jetzt sind allerdings alle Locator noch falsch und das handle existiert noch
// handleLayer.removeChild(this);
// Das w\u00E4re zwar optimal (Performance) korrigiert allerdings nicht die falschen
// Locator
if (addUndo) {
viewer.getMemUndo()
.addAction(new HandleAddAction(
viewer,
getFeature(),
entityPosition,
ringPosition,
coordPosition,
removedX,
removedY));
}
}
}
/**
* Erzeugt alle Handles f\u00FCr dieses PFeature auf dem \u00FCbergebenen HandleLayer.
*
* @param handleLayer PLayer der die Handles aufnimmt
*/
public void addHandles(final PNode handleLayer) {
if (getFeature() instanceof LinearReferencedPointFeature) {
addLinearReferencedPointPHandle(handleLayer);
} else if ((getFeature() instanceof AbstractNewFeature)
&& (((AbstractNewFeature)getFeature()).getGeometryType() == AbstractNewFeature.geomTypes.ELLIPSE)) {
addEllipseHandle(handleLayer);
} else {
for (int entityIndex = 0; entityIndex < entityRingCoordArr.length; entityIndex++) {
for (int ringIndex = 0; ringIndex < entityRingCoordArr[entityIndex].length; ringIndex++) {
final Coordinate[] coordArr = entityRingCoordArr[entityIndex][ringIndex];
int length = coordArr.length;
final Geometry geometry = getFeature().getGeometry();
if ((geometry instanceof Polygon) || (geometry instanceof MultiPolygon)) {
length--; // xp.length-1 weil der erste und letzte Punkt identisch sind
}
for (int coordIndex = 0; coordIndex < length; ++coordIndex) {
addHandle(handleLayer, entityIndex, ringIndex, coordIndex);
}
}
}
}
}
/**
* Erzeugt ein PHandle an den Koordinaten eines bestimmten Punktes des Koordinatenarrays und f\u00FCgt es dem
* HandleLayer hinzu.
*
* @param handleLayer PLayer dem das Handle als Kind hinzugef\u00FCgt wird
* @param entityPosition DOCUMENT ME!
* @param ringPosition DOCUMENT ME!
* @param coordPosition Position des Punktes im Koordinatenarray
*/
public void addHandle(final PNode handleLayer,
final int entityPosition,
final int ringPosition,
final int coordPosition) {
final int positionInArray = coordPosition;
final PHandle h = new TransformationPHandle(this, entityPosition, ringPosition, positionInArray);
// EventQueue.invokeLater(new Runnable() {
//
// public void run() {
handleLayer.addChild(h);
h.addClientProperty("coordinate", entityRingCoordArr[entityPosition][ringPosition][coordPosition]); // NOI18N
h.addClientProperty("coordinate_position_entity", new Integer(entityPosition)); // NOI18N
h.addClientProperty("coordinate_position_ring", new Integer(ringPosition)); // NOI18N
h.addClientProperty("coordinate_position_coord", new Integer(coordPosition)); // NOI18N
// }
// });
}
/**
* Pr\u00FCft alle Features, ob sie zu das gegebene PFeature \u00FCberschneiden und ein Handle besitzen das weniger
* als 1cm vom angeklickten Handle entfernt ist. Falls beides zutrifft, wird eine MultiMap mit diesen Features
* gef\u00FCllt und zur\u00FCckgegeben.
*
* @param entityPosition DOCUMENT ME!
* @param ringPosition DOCUMENT ME!
* @param coordPosition Postion des geklickten Handles im Koordinatenarray um Koordinaten herauszufinden
*
* @return MultiMap mit Features, die die Bedingungen erf\u00FCllen
*/
public de.cismet.tools.collections.MultiMap checkforGlueCoords(
final int entityPosition,
final int ringPosition,
final int coordPosition) {
final GeometryFactory gf = new GeometryFactory();
final MultiMap glueCoords = new MultiMap();
// Alle vorhandenen Features holen und pr\u00FCfen
final List<Feature> allFeatures = getViewer().getFeatureCollection().getAllFeatures();
for (final Feature f : allFeatures) {
// \u00DCberschneiden sich die Features? if (!f.equals(PFeature.this.getFeature()) &&
// f.getGeometry().intersects(PFeature.this.getFeature().getGeometry()) ){
if (!f.equals(PFeature.this.getFeature())) {
final Geometry fgeo = CrsTransformer.transformToGivenCrs(f.getGeometry(), getViewerCrs().getCode());
final Geometry thisGeo = CrsTransformer.transformToGivenCrs(PFeature.this.getFeature().getGeometry(),
getViewerCrs().getCode());
if (fgeo.buffer(0.01).intersects(thisGeo.buffer(0.01))) {
final Coordinate coord = entityRingCoordArr[entityPosition][ringPosition][coordPosition];
final Point p = gf.createPoint(coord);
// Erzeuge Array mit allen Eckpunkten
final Coordinate[] ca = fgeo.getCoordinates();
// Prüfe für alle Punkte ob der Abstand < 1cm ist
for (int i = 0; i < ca.length; ++i) {
final Point p2 = gf.createPoint(ca[i]);
final double abstand = p.distance(p2);
if (abstand < 0.01) {
glueCoords.put(getViewer().getPFeatureHM().get(f), i);
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("checkforGlueCoords() Abstand kleiner als 1cm: " + abstand + " :: " + f); // NOI18N
}
}
} else if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("checkforGlueCoords() Abstand: " + abstand); // NOI18N
}
}
}
}
}
}
return glueCoords;
}
/**
* Erzeugt alle RotaionHandles f\u00FCr dieses PFeature auf dem \u00FCbergebenen HandleLayer.
*
* @param handleLayer PLayer der die RotationHandles aufnimmt
*/
public void addRotationHandles(final PNode handleLayer) {
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("addRotationHandles(): PFeature:" + this); // NOI18N
}
}
// SchwerpunktHandle erzeugen
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("PivotHandle==" + pivotHandle); // NOI18N
}
}
if (pivotHandle == null) {
addPivotHandle(handleLayer);
} else {
boolean contains = false;
for (final Object o : handleLayer.getChildrenReference()) {
if (o == pivotHandle) {
contains = true;
break;
}
}
if (!contains) {
handleLayer.addChild(pivotHandle);
}
}
// Handles einfügen
for (int entityIndex = 0; entityIndex < entityRingCoordArr.length; entityIndex++) {
for (int ringIndex = 0; ringIndex < entityRingCoordArr[entityIndex].length; ringIndex++) {
final Coordinate[] coordArr = entityRingCoordArr[entityIndex][ringIndex];
int length = coordArr.length;
final Geometry geometry = getFeature().getGeometry();
if ((geometry instanceof Polygon) || (geometry instanceof MultiPolygon)) {
length--; // xp.length-1 weil der erste und letzte Punkt identisch sind
}
for (int coordIndex = 0; coordIndex < length; ++coordIndex) {
addRotationHandle(handleLayer, entityIndex, ringIndex, coordIndex);
}
}
}
}
/**
* F\u00FCgt dem PFeature spezielle Handles zum Rotieren des PFeatures an den Eckpunkten hinzu. Zus\u00E4tzlich ein
* Handle am Rotationsmittelpunkt, um diesen manuell \u00E4nder nzu k\u00F6nnen.
*
* @param handleLayer HandleLayer der MappingComponent
* @param entityPosition DOCUMENT ME!
* @param ringPosition DOCUMENT ME!
* @param coordPosition DOCUMENT ME!
*/
private void addRotationHandle(final PNode handleLayer,
final int entityPosition,
final int ringPosition,
final int coordPosition) {
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("addRotationHandles():add from " + coordPosition + ". RotationHandle"); // NOI18N
}
}
final PHandle rotHandle = new RotationPHandle(
this,
entityPosition,
ringPosition,
coordPosition,
mid,
pivotHandle);
rotHandle.setPaint(new Color(1f, 1f, 0f, 0.7f));
handleLayer.addChild(rotHandle);
rotHandle.addClientProperty("coordinate", entityRingCoordArr[entityPosition][ringPosition][coordPosition]); // NOI18N
rotHandle.addClientProperty("coordinate_position_entity", new Integer(entityPosition)); // NOI18N
rotHandle.addClientProperty("coordinate_position_ring", new Integer(ringPosition)); // NOI18N
rotHandle.addClientProperty("coordinate_position_coord", new Integer(coordPosition)); // NOI18N
}
/**
* Erzeugt den Rotations-Angelpunkt. Der Benutzer kann den Punkt verschieben, um die Drehung um einen anderen Punkt
* als den Mittel-/Schwerpunkt auszuf\u00FChren.
*
* @param handleLayer PLayer der das PivotHandle aufnimmt
*/
public void addPivotHandle(final PNode handleLayer) {
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("addPivotHandle()"); // NOI18N
}
}
PBounds allBounds = null;
if (getViewer().getFeatureCollection() instanceof DefaultFeatureCollection) {
final Collection selectedFeatures = getViewer().getFeatureCollection().getSelectedFeatures();
Rectangle2D tmpBounds = getBounds().getBounds2D();
for (final Object o : selectedFeatures) {
final PFeature pf = (PFeature)getViewer().getPFeatureHM().get(o);
if ((pf != null) && !(selectedFeatures.contains(pf))) {
tmpBounds = pf.getBounds().getBounds2D().createUnion(tmpBounds);
}
}
allBounds = new PBounds(tmpBounds);
}
final Collection selArr = getViewer().getFeatureCollection().getSelectedFeatures();
for (final Object o : selArr) {
final PFeature pf = (PFeature)(getViewer().getPFeatureHM().get(o));
pf.setPivotPoint(allBounds.getCenter2D());
mid = allBounds.getCenter2D();
}
if (!(getFeature() instanceof RequestForRotatingPivotLock)) {
pivotHandle = new PivotPHandle(this, mid);
pivotHandle.setPaint(new Color(0f, 0f, 0f, 0.6f));
handleLayer.addChild(pivotHandle);
for (final Object o : selArr) {
final PFeature pf = (PFeature)(getViewer().getPFeatureHM().get(o));
pf.pivotHandle = this.pivotHandle;
}
}
}
/**
* DOCUMENT ME!
*
* @param handleLayer DOCUMENT ME!
*/
public void addLinearReferencedPointPHandle(final PNode handleLayer) {
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("addLinearReferencingHandle()"); // NOI18N
}
}
final PHandle h = new LinearReferencedPointPHandle(this);
handleLayer.addChild(h);
}
/**
* DOCUMENT ME!
*
* @param handleLayer DOCUMENT ME!
*/
public void addEllipseHandle(final PNode handleLayer) {
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("addEllipseHandle()"); // NOI18N
}
}
ellipseHandle = new EllipsePHandle(this);
ellipseHandle.setPaint(new Color(0f, 0f, 0f, 0.6f));
handleLayer.addChild(ellipseHandle);
}
/**
* Sets a new pivotpoint for the roation.
*
* @param newPivot new Point2D
*/
public void setPivotPoint(final Point2D newPivot) {
this.mid = newPivot;
}
/**
* Berechnet anhand einer Rotationsmatrix die neuen Punkte des Features, diese werden dann mittels
* moveCoordinateToNewPiccoloPosition() auch auf die zugeh\u00F6rige Geometrie \u00FCbertragen.
*
* @param rad Winkel der Rotation im Bogenma\u00DF
* @param tempMid Mittelpunkt der Rotation
*/
public void rotateAllPoints(double rad, Point2D tempMid) {
final double[][] matrix = new double[2][2];
double cos;
double sin;
if (rad > 0.0d) { // Clockwise
cos = Math.cos(rad);
sin = Math.sin(rad);
matrix[0][0] = cos;
matrix[0][1] = sin * (-1);
matrix[1][0] = sin;
matrix[1][1] = cos;
} else { // Counterclockwise
rad *= -1;
cos = Math.cos(rad);
sin = Math.sin(rad);
matrix[0][0] = cos;
matrix[0][1] = sin;
matrix[1][0] = sin * (-1);
matrix[1][1] = cos;
}
if (tempMid == null) {
tempMid = mid;
}
for (int entityIndex = 0; entityIndex < entityRingCoordArr.length; entityIndex++) {
for (int ringIndex = 0; ringIndex < entityRingCoordArr[entityIndex].length; ringIndex++) {
for (int coordIndex = entityRingCoordArr[entityIndex][ringIndex].length - 1; coordIndex >= 0;
coordIndex--) {
final double dx = entityRingXArr[entityIndex][ringIndex][coordIndex] - tempMid.getX();
final double dy = entityRingYArr[entityIndex][ringIndex][coordIndex] - tempMid.getY();
// Clockwise
final float resultX = new Double(tempMid.getX() + ((dx * matrix[0][0]) + (dy * matrix[0][1])))
.floatValue();
final float resultY = new Double(tempMid.getY() + ((dx * matrix[1][0]) + (dy * matrix[1][1])))
.floatValue();
moveCoordinateToNewPiccoloPosition(entityIndex, ringIndex, coordIndex, resultX, resultY, false);
}
}
}
updatePath();
}
/**
* Bildet aus Mausposition, Mittelpunkt und Handleposition ein Dreieck und berechnet daraus, den bei der Bewegung
* zur\u00FCckgelegten Winkel und dessen Richtung.
*
* @param event PInputEvent der Mausbewegung
* @param x X-Koordinate des Handles
* @param y Y-Koordinate des Handles
*
* @return \u00FCberstrichener Winkel der Bewegung im Bogenma\u00DF
*/
public double calculateDrag(final PInputEvent event, final float x, final float y) {
final Point2D mousePos = event.getPosition();
// create vectors
final double[] mv = { (mousePos.getX() - mid.getX()), (mousePos.getY() - mid.getY()) };
final double[] hv = { (x - mid.getX()), (y - mid.getY()) };
final double cosm = ((mv[0]) / Math.hypot(mv[0], mv[1]));
final double cosh = ((hv[0]) / Math.hypot(hv[0], hv[1]));
final double resH = Math.acos(cosh);
final double resM = Math.acos(cosm);
double res = 0;
if (((mousePos.getY() - mid.getY()) > 0) && ((y - mid.getY()) > 0)) {
res = resM - resH;
} else if (((mousePos.getY() - mid.getY()) > 0) && ((y - mid.getY()) < 0)) {
res = resM - (resH * -1);
} else if ((y - mid.getY()) < 0) {
res = resH - resM;
} else if (((mousePos.getY() - mid.getY()) < 0) && ((y - mid.getY()) > 0)) {
res = (resH * -1) - resM;
}
return res;
}
/**
* Ver\u00E4ndert die PCanvas-Koordinaten eines Punkts des PFeatures.
*
* @param entityPosition DOCUMENT ME!
* @param ringPosition DOCUMENT ME!
* @param coordPosition Position des Punkts im Koordinatenarray
* @param newX neue X-Koordinate
* @param newY neue Y-Koordinate
*/
public void moveCoordinateToNewPiccoloPosition(final int entityPosition,
final int ringPosition,
final int coordPosition,
final float newX,
final float newY) {
moveCoordinateToNewPiccoloPosition(entityPosition, ringPosition, coordPosition, newX, newY, true);
}
/**
* DOCUMENT ME!
*
* @param entityPosition DOCUMENT ME!
* @param ringPosition DOCUMENT ME!
* @param coordPosition DOCUMENT ME!
* @param newX DOCUMENT ME!
* @param newY DOCUMENT ME!
* @param doUpdatePath DOCUMENT ME!
*/
public void moveCoordinateToNewPiccoloPosition(final int entityPosition,
final int ringPosition,
final int coordPosition,
final float newX,
final float newY,
final boolean doUpdatePath) {
final Coordinate[] origCoordArr = entityRingCoordArr[entityPosition][ringPosition];
final float[] origXArr = entityRingXArr[entityPosition][ringPosition];
final float[] origYArr = entityRingYArr[entityPosition][ringPosition];
final Coordinate[] newCoordArr = new Coordinate[origCoordArr.length];
System.arraycopy(origCoordArr, 0, newCoordArr, 0, newCoordArr.length);
newCoordArr[coordPosition] = new Coordinate(wtst.getSourceX(newX - x_offset),
wtst.getSourceY(newY - y_offset));
final Geometry geometry = getFeature().getGeometry();
if ((coordPosition == 0) && ((geometry instanceof Polygon) || (geometry instanceof MultiPolygon))) {
newCoordArr[origXArr.length - 1] = newCoordArr[0];
}
origXArr[coordPosition] = newX;
origYArr[coordPosition] = newY;
origCoordArr[coordPosition] = newCoordArr[coordPosition];
if ((coordPosition == 0) && ((geometry instanceof Polygon) || (geometry instanceof MultiPolygon))) {
origXArr[origXArr.length - 1] = origXArr[0];
origYArr[origYArr.length - 1] = origYArr[0];
origCoordArr[origXArr.length - 1] = origCoordArr[0];
}
if (doUpdatePath) {
updatePath();
}
}
/**
* Removes the current splitline and creates a new one from the startingpoint.
*/
private void resetSplitLine() {
removeAllChildren();
splitPolygonLine = new PPath();
splitPoints = new ArrayList<Point2D>();
splitPoints.add(getFirstSplitHandle());
splitPolygonLine.setStroke(FIXED_WIDTH_STROKE);
// splitPolygonLine.setPaint(new Color(1f,0f,0f,0.5f));
addChild(splitPolygonLine);
}
/**
* Fügt dem PFeature ein Handle hinzu mit dem man das PFeature in zwei zerlegen kann.
*
* @param p das SplitHandle
*/
public void addSplitHandle(final PHandle p) {
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("addSplitHandle()"); // NOI18N
}
}
if ((getFeature().getGeometry() instanceof Polygon) || (getFeature().getGeometry() instanceof MultiPolygon)) {
if (splitPolygonFromHandle == p) {
splitPolygonFromHandle = null;
p.setSelected(false);
} else if (splitPolygonToHandle == p) {
splitPolygonToHandle = null;
p.setSelected(false);
} else if (splitPolygonFromHandle == null) {
splitPolygonFromHandle = p;
p.setSelected(true);
resetSplitLine();
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("after addSplitHandle: splitPolygonFromHandle=" + splitPolygonFromHandle); // NOI18N
log.debug("in addSplitHandle this=" + this); // NOI18N
}
}
} else if (splitPolygonToHandle == null) {
splitPolygonToHandle = p;
p.setSelected(true);
splitPoints.add(new Point2D.Double(
splitPolygonToHandle.getLocator().locateX(),
splitPolygonToHandle.getLocator().locateY()));
} else {
p.setSelected(false);
}
} else if (getFeature().getGeometry() instanceof LineString) {
if (splitLineAtHandle == p) {
splitLineAtHandle = null;
p.setSelected(false);
} else if (splitLineAtHandle == null) {
splitLineAtHandle = p;
p.setSelected(true);
lineSplitPoint = new Point2D.Double(
splitLineAtHandle.getLocator().locateX(),
splitLineAtHandle.getLocator().locateY());
} else {
p.setSelected(false);
}
}
}
/**
* Returns the point of the handle from which the split starts.
*
* @return Point2D
*/
public Point2D getFirstSplitHandle() {
if ((splitPolygonFromHandle != null)
&& (splitPolygonFromHandle.getClientProperty("coordinate") instanceof Coordinate)) { // NOI18N
final Coordinate c = ((Coordinate)splitPolygonFromHandle.getClientProperty("coordinate")); // NOI18N
final Point2D ret = new Point2D.Double((double)splitPolygonFromHandle.getLocator().locateX(),
(double)splitPolygonFromHandle.getLocator().locateY());
return ret;
} else {
return null;
}
}
/**
* Returns if the PFeature in currently in a splitmode.
*
* @return true, if splitmode is active, else false
*/
public boolean inSplitProgress() {
final CurrentStackTrace cst = new CurrentStackTrace();
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("splitPolygonFromHandle:" + splitPolygonFromHandle, cst); // NOI18N
log.debug("splitPolygonToHandle:" + splitPolygonToHandle, cst); // NOI18N
log.debug("inSplitProgress=" + ((splitPolygonFromHandle != null) && (splitPolygonToHandle == null))); // NOI18N
log.debug("in inSplitProgress this=" + this); // NOI18N
}
}
if (getFeature() == null) {
return false;
}
if ((getFeature().getGeometry() instanceof Polygon) || (getFeature().getGeometry() instanceof MultiPolygon)) {
return ((splitPolygonFromHandle != null) && (splitPolygonToHandle == null));
} else {
return false;
}
}
/**
* Zerlegt das Feature dieses PFeatures in zwei Features an Hand einer vom Benutzer gezogenen Linie zwischen 2
* Handles.
*
* @return Feature-Array mit den Teilfeatures
*/
public Feature[] split() {
if (isSplittable()) {
final SplittedNewFeature[] splittedFeatureArr = new SplittedNewFeature[2];
// TODO multipolygon / multilinestring
final Coordinate[] coordArrOrig = entityRingCoordArr[0][0];
if ((getFeature().getGeometry() instanceof Polygon)
|| (getFeature().getGeometry() instanceof MultiPolygon)) {
int from = ((Integer)(splitPolygonFromHandle.getClientProperty("coordinate_position_coord"))); // NOI18N
int to = ((Integer)(splitPolygonToHandle.getClientProperty("coordinate_position_coord"))); // NOI18N
splitPolygonToHandle = null;
splitPolygonFromHandle = null;
// In splitPoints.get(0) steht immer from In splitPoint.get(size-1) steht immer to Werden die beiden
// vertauscht, so muss dies sp\u00E4ter bei der Reihenfolge ber\u00FCcksichtigt werden.
final boolean swapped = from > to;
if (swapped) {
final int swap = from;
from = to;
to = swap;
}
// Erstes Polygon
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("ErstesPolygon" + (to - from + splitPoints.size())); // NOI18N
}
}
final Coordinate[] coordArr1 = new Coordinate[to - from + splitPoints.size()];
int counter = 0;
for (int i = from; i <= to; ++i) {
coordArr1[counter] = (Coordinate)coordArrOrig[i].clone();
counter++;
}
if (swapped) {
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("SWAPPED"); // NOI18N
}
}
for (int i = 1; i < (splitPoints.size() - 1); ++i) {
final Point2D splitPoint = (Point2D)splitPoints.get(i);
final Coordinate splitCoord = new Coordinate(wtst.getSourceX(splitPoint.getX()),
wtst.getSourceY(splitPoint.getY()));
coordArr1[counter] = splitCoord;
counter++;
}
} else {
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("NOT_SWAPPED"); // NOI18N
}
}
for (int i = splitPoints.size() - 2; i > 0; --i) {
final Point2D splitPoint = (Point2D)splitPoints.get(i);
final Coordinate splitCoord = new Coordinate(wtst.getSourceX(splitPoint.getX()),
wtst.getSourceY(splitPoint.getY()));
coordArr1[counter] = splitCoord;
counter++;
}
}
coordArr1[counter] = (Coordinate)coordArrOrig[from].clone();
// Zweites Polygon
// Größe Array= (Anzahl vorh. Coords) - (anzahl vorh. Handles des ersten Polygons) + (SplitLinie )
final Coordinate[] coordArr2 =
new Coordinate[(coordArrOrig.length) - (to - from + 1) + splitPoints.size()];
counter = 0;
for (int i = 0; i <= from; ++i) {
coordArr2[counter] = (Coordinate)coordArrOrig[i].clone();
counter++;
}
if (swapped) {
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("SWAPPED"); // NOI18N
}
}
for (int i = splitPoints.size() - 2; i > 0; --i) {
final Point2D splitPoint = (Point2D)splitPoints.get(i);
final Coordinate splitCoord = new Coordinate(wtst.getSourceX(splitPoint.getX()),
wtst.getSourceY(splitPoint.getY()));
coordArr2[counter] = splitCoord;
counter++;
}
} else {
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("NOT_SWAPPED"); // NOI18N
}
}
for (int i = 1; i < (splitPoints.size() - 1); ++i) {
final Point2D splitPoint = (Point2D)splitPoints.get(i);
final Coordinate splitCoord = new Coordinate(wtst.getSourceX(splitPoint.getX()),
wtst.getSourceY(splitPoint.getY()));
coordArr2[counter] = splitCoord;
counter++;
}
}
for (int i = to; i < coordArrOrig.length; ++i) {
coordArr2[counter] = (Coordinate)coordArrOrig[i].clone();
counter++;
}
splittedFeatureArr[0] = new SplittedNewFeature(coordArr1, wtst, this);
splittedFeatureArr[0].setEditable(true);
splittedFeatureArr[1] = new SplittedNewFeature(coordArr2, wtst, this);
splittedFeatureArr[1].setEditable(true);
} else if (getFeature().getGeometry() instanceof LineString) {
final int at = ((Integer)(splitLineAtHandle.getClientProperty("coordinate_position_coord")));
splitLineAtHandle = null;
final Coordinate[] coordArrSplit2 = new Coordinate[coordArrOrig.length - at];
final Coordinate[] coordArrSplit1 = new Coordinate[coordArrOrig.length - coordArrSplit2.length + 1];
for (int i = 0; i < coordArrOrig.length; ++i) {
if (i <= at) {
coordArrSplit1[i] = (Coordinate)coordArrOrig[i].clone();
}
if (i >= at) {
coordArrSplit2[i - at] = (Coordinate)coordArrOrig[i].clone();
}
}
splittedFeatureArr[0] = new SplittedNewFeature(coordArrSplit1, wtst, this);
splittedFeatureArr[0].setEditable(true);
splittedFeatureArr[1] = new SplittedNewFeature(coordArrSplit2, wtst, this);
splittedFeatureArr[1].setEditable(true);
}
return splittedFeatureArr;
} else {
return null;
}
}
/**
* Moves the PFeature for a certain dimension.
*
* @param dim PDimension to move
*/
public void moveFeature(final PDimension dim) {
try {
final double scale = viewer.getCamera().getViewScale();
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("Scale=" + scale); // NOI18N
}
}
for (int entityIndex = 0; entityIndex < entityRingCoordArr.length; entityIndex++) {
for (int ringIndex = 0; ringIndex < entityRingCoordArr[entityIndex].length; ringIndex++) {
for (int coordIndex = 0; coordIndex < entityRingCoordArr[entityIndex][ringIndex].length;
++coordIndex) {
final Coordinate[] coordArr = entityRingCoordArr[entityIndex][ringIndex];
final float[] xArr = entityRingXArr[entityIndex][ringIndex];
final float[] yArr = entityRingYArr[entityIndex][ringIndex];
xArr[coordIndex] = xArr[coordIndex] + (float)(dim.getWidth() / (float)scale);
yArr[coordIndex] = yArr[coordIndex] + (float)(dim.getHeight() / (float)scale);
coordArr[coordIndex].x = wtst.getSourceX(xArr[coordIndex]); // -x_offset);
coordArr[coordIndex].y = wtst.getSourceY(yArr[coordIndex]); // -y_offset);
}
}
}
updatePath();
syncGeometry();
resetInfoNodePosition();
} catch (NullPointerException npe) {
log.warn("error at moveFeature:", npe); // NOI18N
}
}
/**
* Sets the offset of the stickychild to the interiorpoint of this PFeature.
*/
public void resetInfoNodePosition() {
if (stickyChild != null) {
final Geometry geom = CrsTransformer.transformToGivenCrs(getFeature().getGeometry(),
getViewerCrs().getCode());
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("getFeature().getGeometry():" + geom); // NOI18N
}
}
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("getFeature().getGeometry().getInteriorPoint().getY():" // NOI18N
+ geom.getInteriorPoint().getY());
}
}
stickyChild.setOffset(wtst.getScreenX(geom.getInteriorPoint().getX()),
wtst.getScreenY(geom.getInteriorPoint().getY()));
}
}
/**
* Renews the InfoNode by deleting the old and creating a new one.
*/
public void refreshInfoNode() {
if ((stickyChild == infoNode) && (infoNode != null)) {
stickyChild = null;
if (indexOfChild(infoNode) != -1) {
// Remove the infoNode only, if it is really contained in the object.
// Otherwise, the PNode (this object) will throw a NullPointerException (if the children
// object of the PNode is null) or an IndexOutOfBoundsException (if the children object of the PNode
// is not null, but the object to delete does not exist)
removeChild(infoNode);
}
} else if ((stickyChild != null) && (infoNode != null)) {
if (stickyChild.indexOfChild(infoNode) != -1) {
// Remove the infoNode only, if it is really contained in the stickyChild object.
// Otherwise, the PNode (stickyChild) will throw a NullPointerException (if the children
// object of the PNode is null) or an IndexOutOfBoundsException (if the children object of the PNode
// is not null, but the object to delete does not exist)
stickyChild.removeChild(infoNode);
}
}
addInfoNode();
}
/**
* Calls refreshInfoNode() in the EDT.
*/
@Override
public void refresh() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
if (log.isDebugEnabled()) {
log.debug("refreshInfoNode"); // NOI18N
}
PFeature.this.refreshInfoNode();
}
});
}
/**
* synchronises the feature name with the infoPanel.
*/
public void refreshName() {
if (log.isDebugEnabled()) {
log.debug("refreshInfoNodeName"); // NOI18N
}
if ((!(feature instanceof InfoNodeAwareFeature)
|| ((feature instanceof InfoNodeAwareFeature)
&& ((InfoNodeAwareFeature)feature).hasInfoNode()))
&& (feature instanceof XStyledFeature)) {
if (infoPanel != null) {
infoPanel.setTitleText(((XStyledFeature)feature).getName());
}
}
}
/**
* Creates an InfoPanel which is located in a PSwingComponent. This component will be added as child of this
* PFeature. The InfoPanel contains the featuretype as icon and the name of the PFeature.
*/
public void addInfoNode() {
try {
if ((!(getFeature() instanceof InfoNodeAwareFeature)
|| ((getFeature() instanceof InfoNodeAwareFeature)
&& ((InfoNodeAwareFeature)getFeature()).hasInfoNode()))
&& (getFeature() instanceof XStyledFeature)) {
final XStyledFeature xsf = (XStyledFeature)getFeature();
if (infoComponent == null) {
infoComponent = xsf.getInfoComponent(this);
}
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("ADD INFONODE3"); // NOI18N
}
}
if (infoPanel != null) {
viewer.getSwingWrapper().remove(infoPanel);
}
infoPanel = new InfoPanel(infoComponent);
infoPanel.setPfeature(this);
infoPanel.setTitleText(xsf.getName());
infoPanel.setTitleIcon(xsf.getIconImage());
pswingComp = new PSwing(viewer, infoPanel);
pswingComp.resetBounds();
pswingComp.setOffset(0, 0);
// PText pt=new PText(xsf.getName());
// if (getFeature().isEditable()) {
// pt.setTextPaint(new Color(255,0,0));
// } else {
// pt.setTextPaint(new Color(0,0,0));
// }
// int width=(int)(pt.getWidth()+pi.getWidth());
// int height=(int)(pi.getHeight());
// Dieser node wird gebraucht damit die Mouseover sachen funktionieren. Geht nicht mit einem PSwing.
// Auch nicht wenn das PSwing Element ParentNodeIsAPFeature & PSticky implementieren
final StickyPPath p = new StickyPPath(new Rectangle(0, 0, 1, 1));
p.setStroke(null);
p.setPaint(new Color(250, 0, 0, 0)); // letzer Wert Wert Alpha: Wenn 0 dann unsichtbar
p.setStrokePaint(null);
infoPanel.setPNodeParent(p);
infoPanel.setPSwing(pswingComp);
p.addChild(pswingComp);
pswingComp.setOffset(0, 0);
if (stickyChild != null) {
stickyChild.addChild(p);
p.setOffset(stickyChild.getWidth(), 0);
} else if (getFeature().getGeometry() != null) {
syncGeometry();
final Geometry geom = CrsTransformer.transformToGivenCrs(getFeature().getGeometry(),
getViewerCrs().getCode());
Point interiorPoint = null;
try {
interiorPoint = geom.getInteriorPoint();
} catch (TopologyException e) {
log.warn("Interior point of geometry couldn't be calculated. Try to use buffering.");
// see http://www.vividsolutions.com/JTS/bin/JTS%20Developer%20Guide.pdf, p. 11/12
}
if (interiorPoint == null) {
final GeometryFactory factory = new GeometryFactory();
final GeometryCollection collection = factory.createGeometryCollection(new Geometry[] { geom });
final Geometry union = collection.buffer(0);
interiorPoint = union.getInteriorPoint();
}
p.setOffset(wtst.getScreenX(interiorPoint.getX()),
wtst.getScreenY(interiorPoint.getY()));
addChild(p);
p.setWidth(pswingComp.getWidth());
p.setHeight(pswingComp.getHeight());
stickyChild = p;
if (!ignoreStickyFeature) {
viewer.addStickyNode(p);
viewer.rescaleStickyNodes();
}
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("addInfoNode()"); // NOI18N
}
}
}
infoNode = p;
if ((viewer != null) && (infoNode != null)) {
infoNode.setVisible(viewer.isInfoNodesVisible());
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("addInfoNode()"); // NOI18N
}
}
viewer.rescaleStickyNodes();
p.setWidth(pswingComp.getWidth());
p.setHeight(pswingComp.getHeight());
} else if (infoNode != null) {
infoNode.setVisible(false);
}
pswingComp.addPropertyChangeListener("fullBounds", new PropertyChangeListener() { // NOI18N
@Override
public void propertyChange(final PropertyChangeEvent evt) {
p.setWidth(pswingComp.getWidth());
p.setHeight(pswingComp.getHeight());
}
});
}
} catch (Throwable t) {
log.error("Error in AddInfoNode", t); // NOI18N
}
}
/**
* Deletes the InfoPanel and hides the PFeature.
*/
public void cleanup() {
if (infoPanel != null) {
infoPanel.setVisible(false);
viewer.getSwingWrapper().remove(infoPanel);
}
this.setVisible(false);
if ((tPropertyChange != null) && (viewer != null)) {
viewer.getCamera().removePropertyChangeListener(PCamera.PROPERTY_VIEW_TRANSFORM, tPropertyChange);
}
}
/**
* DOCUMENT ME!
*/
public void ensureFullVisibility() {
final PBounds all = viewer.getCamera().getViewBounds();
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("getViewBounds()" + all); // NOI18N
}
}
final PBounds newBounds = new PBounds();
newBounds.setRect(this.getFullBounds().createUnion(all.getBounds2D()));
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("getFullBounds()" + getFullBounds()); // NOI18N
}
}
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("newBounds" + newBounds); // NOI18N
}
}
viewer.getCamera().animateViewToCenterBounds(newBounds.getBounds2D(), true, viewer.getAnimationDuration());
viewer.refresh();
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public boolean isInfoNodeExpanded() {
return (infoPanel != null) && infoPanel.isExpanded();
}
/**
* DOCUMENT ME!
*
* @param expanded DOCUMENT ME!
*/
public void setInfoNodeExpanded(final boolean expanded) {
if (infoPanel != null) {
infoPanel.setExpanded(expanded, false);
}
}
/**
* DOCUMENT ME!
*
* @param selectedOriginal DOCUMENT ME!
*/
public void setSelectedOriginal(final PFeature selectedOriginal) {
this.selectedOriginal = selectedOriginal;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public PFeature getSelectedOriginal() {
return selectedOriginal;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public Feature getFeature() {
return feature;
}
/**
* DOCUMENT ME!
*
* @param feature DOCUMENT ME!
*/
public void setFeature(final Feature feature) {
this.feature = feature;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public PPath getSplitLine() {
return splitPolygonLine;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public List<Point2D> getSplitPoints() {
return splitPoints;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public boolean isSplittable() {
if (getFeature() == null) {
return false;
}
if ((getFeature().getGeometry() instanceof Polygon) || (getFeature().getGeometry() instanceof MultiPolygon)) {
return ((splitPolygonFromHandle != null) && (splitPolygonToHandle != null));
} else if (getFeature().getGeometry() instanceof LineString) {
return (splitLineAtHandle != null);
} else {
return false;
}
}
/**
* Zeichnet das PFeature bei einem RollOver um 40% heller.
*
* @param highlighting true, wenn das PFeature hervorgehoben werden soll
*/
@Override
public void setHighlighting(final boolean highlighting) {
final boolean highlightingEnabledIfStyledFeature = ((getFeature() != null)
&& !(getFeature() instanceof StyledFeature))
|| ((getFeature() != null) && ((StyledFeature)getFeature()).isHighlightingEnabled());
if (!isSelected() && (getPaint() != null) && highlightingEnabledIfStyledFeature) {
highlighted = highlighting;
if (highlighted) {
if (!(nonHighlightingPaint instanceof PaintWrapper)) {
nonHighlightingPaint = getPaint();
}
if (nonHighlightingPaint instanceof Color) {
final Color c = (Color)nonHighlightingPaint;
setPaintOnAllFeatures(getHighlightingColorFromColor(c));
} else if (nonHighlightingPaint instanceof SelectionAwareTexturePaint) {
final SelectionAwareTexturePaint texturePaint = (SelectionAwareTexturePaint)nonHighlightingPaint;
final SelectionAwareTexturePaint highlightingPaint = (SelectionAwareTexturePaint)
texturePaint.clone();
highlightingPaint.setMode(SelectionAwareTexturePaint.SelectionMode.HIGHLIGHTED);
setPaintOnAllFeatures(highlightingPaint.getPaint());
} else if (nonHighlightingPaint instanceof PaintWrapper) {
setPaintOnAllFeatures(((PaintWrapper)nonHighlightingPaint).getPaint());
} else {
setPaintOnAllFeatures(new Color(1f, 1f, 1f, 0.6f));
}
} else {
if (nonHighlightingPaint instanceof PaintWrapper) {
setPaintOnAllFeatures(((PaintWrapper)nonHighlightingPaint).getPaint());
} else {
setPaintOnAllFeatures(nonHighlightingPaint);
}
}
repaint();
}
}
/**
* DOCUMENT ME!
*
* @param c DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public static Color getHighlightingColorFromColor(final Color c) {
int red = (int)(c.getRed() + 70);
int green = (int)(c.getGreen() + 70);
int blue = (int)(c.getBlue() + 70);
if (red > 255) {
red = 255;
}
if (green > 255) {
green = 255;
}
if (blue > 255) {
blue = 255;
}
return new Color(red, green, blue, c.getAlpha());
}
/**
* DOCUMENT ME!
*
* @param newPaint DOCUMENT ME!
*/
public void setPaintOnAllFeatures(final Paint newPaint) {
if (feature instanceof SLDStyledFeature) {
if ((sldStyledPolygon == null) || (sldStyledPolygon.size() == 0)) {
super.setPaint(newPaint);
} else {
for (int i = 0; i < sldStyledPolygon.size(); ++i) {
sldStyledPolygon.get(i).setPaint(newPaint);
}
}
} else {
super.setPaint(newPaint);
}
}
/**
* Liefert ein boolean, ob das Pfeature gerade hervorgehoben wird.
*
* @return true, falls hervorgehoben
*/
@Override
public boolean getHighlighting() {
return highlighted;
}
/**
* Selektiert das PFeature je nach \u00FCbergebenem boolean-Wert.
*
* @param selected true, markiert. false, nicht markiert
*/
@Override
public void setSelected(final boolean selected) {
if (viewer.isFeatureDebugging()) {
if (log.isDebugEnabled()) {
log.debug("setSelected(" + selected + ")"); // NOI18N
}
}
this.selected = selected;
this.selectedEntity = -1;
boolean showSelected = true;
if (getFeature() instanceof DrawSelectionFeature) {
showSelected = (((DrawSelectionFeature)getFeature()).isDrawingSelection());
}
if (showSelected) {
showSelected(selected);
}
}
/**
* DOCUMENT ME!
*
* @param selected DOCUMENT ME!
*/
private void showSelected(final boolean selected) {
splitPolygonFromHandle = null;
splitPolygonToHandle = null;
if (this.selected && !selected) {
pivotHandle = null;
}
this.selected = selected;
// PUNKT
if (getFeature().getGeometry() instanceof Point) {
if ((pi != null) && (piSelected != null)) {
piSelected.setVisible(selected);
pi.setVisible(!selected);
if ((sldStyledImage != null) && (sldStyledImage.size() > 0)) {
if (selected) {
for (final PNode n : sldStyledImage) {
if (this.indexOfChild(n) > -1) {
this.removeChild(n);
}
}
for (final PNode n : sldStyledSelectedImage) {
this.addChild(n);
}
} else {
for (final PNode n : sldStyledSelectedImage) {
if (this.indexOfChild(n) > -1) {
this.removeChild(n);
}
}
for (final PNode n : sldStyledImage) {
this.addChild(n);
}
}
}
// else {
/*
* since we have two different FeatureAnnotationSymbols for selection and normal we have to switch the
* infoNode to them depending on selection state
*/
if (selected) {
wasSelected = true;
// addInfoNode();
if (infoNode != null) {
if (pi.indexOfChild(infoNode) != -1) {
// Remove the infoNode only, if the infoNode is really contained in the pi object.
// Otherwise, the PNode (piSelection) will throw a NullPointerException (if the PNode
// has no children) or an IndexOutOfBoundsException (if the children object of the PNode
// is not null, but the object to delete does not exist)
pi.removeChild(infoNode);
}
piSelected.addChild(infoNode);
}
} else if (wasSelected) {
wasSelected = false;
if (infoNode != null) {
if (piSelected.indexOfChild(infoNode) != -1) {
// Remove the infoNode only, if the infoNode is really contained in the piSelected object.
// Otherwise, the PNode (piSelection) will throw a NullPointerException (if the PNode
// has no children) or an IndexOutOfBoundsException (if the children object of the PNode
// is not null, but the object to delete does not exist)
piSelected.removeChild(infoNode);
}
pi.addChild(infoNode);
}
}
// }
viewer.rescaleStickyNode(pi);
viewer.rescaleStickyNode(piSelected);
}
} // LINESTRING
else if ((feature.getGeometry() instanceof LineString) || (feature.getGeometry() instanceof MultiLineString)) {
if (selected) {
final CustomFixedWidthStroke fws = new CustomFixedWidthStroke(5f, viewer);
setStroke(fws);
setStrokePaint(javax.swing.UIManager.getDefaults().getColor("Table.selectionBackground")); // NOI18N
setPaintOnAllFeatures(null);
} else {
// setStroke(new FixedWidthStroke());
// if (stroke != null) {
setStroke(stroke);
// } else {
// setStroke(FIXED_WIDTH_STROKE);
// }
// if (strokePaint != null) {
setStrokePaint(strokePaint);
// } else {
// setStrokePaint(Color.black);
// }
}
} // POLYGON
else {
if (stroke != null) {
setStroke(stroke);
} else {
setStroke(FIXED_WIDTH_STROKE);
}
if (selected) {
nonSelectedPaint = getPaint();
if ((nonSelectedPaint instanceof Color) && (nonHighlightingPaint instanceof Color)) {
final Color c = (Color)nonHighlightingPaint;
if (c != null) {
Color selectionColor = null;
try {
selectionColor = javax.swing.UIManager.getDefaults()
.getColor("Cismap.featureSelectionForeground");
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug(
"Error when getting javax.swing.UIManager.getDefaults().getColor(\"Cismap.featureSelectionForeground\")",
e);
}
}
if (selectionColor == null) {
selectionColor = javax.swing.UIManager.getDefaults().getColor("Table.selectionBackground");
}
final int red = (int)(selectionColor.getRed()); // NOI18N
final int green = (int)(selectionColor.getGreen()); // NOI18N
final int blue = (int)(selectionColor.getBlue()); // NOI18N
setPaintOnAllFeatures(new Color(red, green, blue, c.getAlpha() / 2));
}
} else if (nonHighlightingPaint instanceof SelectionAwareTexturePaint) {
final SelectionAwareTexturePaint texturePaint = (SelectionAwareTexturePaint)nonHighlightingPaint;
final SelectionAwareTexturePaint selectedPaint = (SelectionAwareTexturePaint)texturePaint.clone();
selectedPaint.setMode(SelectionAwareTexturePaint.SelectionMode.SELECTED);
setPaintOnAllFeatures(selectedPaint.getPaint());
} else if (nonHighlightingPaint instanceof PaintWrapper) {
setPaintOnAllFeatures(((PaintWrapper)nonHighlightingPaint).getPaint());
} else {
setPaintOnAllFeatures(new Color(172, 210, 248, 178));
}
} else {
if (nonHighlightingPaint instanceof PaintWrapper) {
setPaintOnAllFeatures(((PaintWrapper)nonHighlightingPaint).getPaint());
} else {
setPaintOnAllFeatures(nonHighlightingPaint);
}
}
}
repaint();
}
/**
* DOCUMENT ME!
*
* @param s DOCUMENT ME!
*/
@Override
public void setStroke(final Stroke s) {
// log.debug("setStroke: " + s, new CurrentStackTrace());
super.setStroke(s);
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
@Override
public boolean isSelected() {
return selected;
}
/**
* DOCUMENT ME!
*
* @param polygon DOCUMENT ME!
*/
public void addEntity(final Polygon polygon) {
if (getFeature().isEditable()) {
final int numOfHoles = polygon.getNumInteriorRing();
final Coordinate[][][] origEntityCoordArr = entityRingCoordArr;
// neues entityRingCoordArr mit entity-länge + 1, und alte daten daten darin kopieren
final Coordinate[][][] newEntityCoordArr = new Coordinate[origEntityCoordArr.length + 1][][];
System.arraycopy(origEntityCoordArr, 0, newEntityCoordArr, 0, origEntityCoordArr.length);
// neues ringCoordArr für neues entity erzeugen, und Hülle + Löcher darin speicherm
final Coordinate[][] newRingCoordArr = new Coordinate[1 + numOfHoles][];
newRingCoordArr[0] = polygon.getExteriorRing().getCoordinates();
for (int ringIndex = 1; ringIndex < newRingCoordArr.length; ++ringIndex) {
newRingCoordArr[ringIndex] = polygon.getInteriorRingN(ringIndex - 1).getCoordinates();
}
// neues entity an letzte stelle speichern, und als neues entityRingCoordArr übernehmen
newEntityCoordArr[origEntityCoordArr.length] = newRingCoordArr;
entityRingCoordArr = newEntityCoordArr;
// refresh
syncGeometry();
updateXpAndYp();
updatePath();
}
}
/**
* DOCUMENT ME!
*
* @param entityPosition DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public Polygon getEntityByPosition(final int entityPosition) {
final Coordinate[][] coords = entityRingCoordArr[entityPosition];
final int srid = CrsTransformer.extractSridFromCrs(getViewerCrs().getCode());
final GeometryFactory factory = new GeometryFactory(new PrecisionModel(PrecisionModel.FLOATING), srid);
CoordinateSequence cs = factory.getCoordinateSequenceFactory().create(coords[0]);
final LinearRing shell = new LinearRing(cs, factory);
final LinearRing[] holes = new LinearRing[coords.length - 1];
for (int i = 1; i < coords.length; ++i) {
cs = factory.getCoordinateSequenceFactory().create(coords[i]);
holes[i - 1] = new LinearRing(cs, factory);
}
return factory.createPolygon(shell, holes);
}
/**
* DOCUMENT ME!
*
* @param entityPosition DOCUMENT ME!
* @param holePosition DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public LineString getHoleByPosition(final int entityPosition, final int holePosition) {
final Coordinate[][] entityCoords = entityRingCoordArr[entityPosition];
final Coordinate[] holeCoords = entityCoords[holePosition];
final int srid = CrsTransformer.extractSridFromCrs(getViewerCrs().getCode());
final GeometryFactory factory = new GeometryFactory(new PrecisionModel(PrecisionModel.FLOATING), srid);
return factory.createLineString(holeCoords);
}
/**
* DOCUMENT ME!
*
* @param entityPosition DOCUMENT ME!
*/
public void removeEntity(final int entityPosition) {
if (getFeature().isEditable()) {
final Coordinate[][][] origEntityCoordArr = entityRingCoordArr;
final boolean isInBounds = (entityPosition >= 0) && (entityPosition < origEntityCoordArr.length);
if (isInBounds) {
if (origEntityCoordArr.length == 1) { // wenn nur ein entity drin
entityRingCoordArr = new Coordinate[0][][]; // dann nur durch leeres ersetzen
} else { // wenn mehr als ein entity drin
// neues entityRingCoordArr mit entity-länge - 1, und originaldaten daten darin kopieren außer
// entityPosition
final Coordinate[][][] newEntityCoordArr = new Coordinate[origEntityCoordArr.length - 1][][];
// alles vor entityPosition
System.arraycopy(origEntityCoordArr, 0, newEntityCoordArr, 0, entityPosition);
// alles nach entityPosition
System.arraycopy(
origEntityCoordArr,
entityPosition
+ 1,
newEntityCoordArr,
entityPosition,
newEntityCoordArr.length
- entityPosition);
// original durch neues ersetzen
entityRingCoordArr = newEntityCoordArr;
}
// refresh
syncGeometry();
updateXpAndYp();
updatePath();
}
}
}
/**
* DOCUMENT ME!
*
* @param entityPosition DOCUMENT ME!
* @param lineString DOCUMENT ME!
*/
public void addHoleToEntity(final int entityPosition, final LineString lineString) {
if (getFeature().isEditable()) {
final boolean isInBounds = (entityPosition >= 0) && (entityPosition < entityRingCoordArr.length);
if (isInBounds) {
final Coordinate[][] origRingCoordArr = entityRingCoordArr[entityPosition];
final int origLength = origRingCoordArr.length;
final Coordinate[][] newRingCoordArr = new Coordinate[origLength + 1][];
System.arraycopy(origRingCoordArr, 0, newRingCoordArr, 0, origLength);
newRingCoordArr[origLength] = lineString.getCoordinates();
entityRingCoordArr[entityPosition] = newRingCoordArr;
}
syncGeometry();
updateXpAndYp();
updatePath();
}
}
/**
* alle entities die diesen punkt beinhalten (löscher werden ignoriert, da sonst nur eine entity existieren kann).
*
* @param point coordinate DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
private List<Integer> getEntitiesPositionsUnderPoint(final Point point) {
final List<Integer> positions = new ArrayList<Integer>();
final Geometry geometry = getFeature().getGeometry();
for (int entityIndex = 0; entityIndex < geometry.getNumGeometries(); entityIndex++) {
final Geometry envelope = geometry.getEnvelope(); // ohne löscher
if (envelope.covers(point)) {
positions.add(entityIndex);
}
}
return positions;
}
/**
* DOCUMENT ME!
*
* @param point coordinate DOCUMENT ME!
*/
public void removeHoleUnderPoint(final Point point) {
final int entityPosition = getMostInnerEntityUnderPoint(point);
final boolean isEntityInBounds = (entityPosition >= 0) && (entityPosition < entityRingCoordArr.length);
if (isEntityInBounds) {
final Coordinate[][] origRingCoordArr = entityRingCoordArr[entityPosition];
final int holePosition = getHolePositionUnderPoint(point, entityPosition);
final boolean isRingInBounds = (holePosition >= 0) && (holePosition < origRingCoordArr.length);
if (isRingInBounds) {
final Polygon entityPolygon = ((Polygon)getFeature().getGeometry().getGeometryN(entityPosition));
final Geometry holeGeometry = entityPolygon.getInteriorRingN(holePosition - 1).getEnvelope(); // zu entfernende
// Geometrie, ohne
// Löcher
if (!hasEntitiesInGeometry(holeGeometry)) {
final Coordinate[][] newRingCoordArr = new Coordinate[origRingCoordArr.length - 1][];
System.arraycopy(origRingCoordArr, 0, newRingCoordArr, 0, holePosition);
System.arraycopy(
origRingCoordArr,
holePosition
+ 1,
newRingCoordArr,
holePosition,
newRingCoordArr.length
- holePosition);
// original durch neues ersetzen
entityRingCoordArr[entityPosition] = newRingCoordArr;
// refresh
syncGeometry();
updateXpAndYp();
updatePath();
}
}
}
}
/**
* DOCUMENT ME!
*
* @param point coordinate DOCUMENT ME!
* @param entityPosition DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public int getHolePositionUnderPoint(final Point point, final int entityPosition) {
final Geometry geometry = getFeature().getGeometry();
final boolean isInBounds = (entityPosition >= 0) && (entityPosition < geometry.getNumGeometries());
if (isInBounds) {
final Polygon polygon = (Polygon)geometry.getGeometryN(entityPosition);
if (polygon.getNumInteriorRing() > 0) { // hat überhaupt löscher ?
for (int ringIndex = 0; ringIndex < polygon.getNumInteriorRing(); ringIndex++) {
final Geometry envelope = polygon.getInteriorRingN(ringIndex).getEnvelope();
if (envelope.covers(point)) {
return ringIndex + 1; // +1 weil ring 0 der äußere ring ist
}
}
}
}
return -1;
}
/**
* DOCUMENT ME!
*
* @param point DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public int getMostInnerEntityUnderPoint(final Point point) {
// alle außenringe (löscher werden zunächst ignoriert) holen die grundsätzlich unter der koordinate liegen
final List<Integer> entityPositions = getEntitiesPositionsUnderPoint(point);
// interessant sind nur entities die Löscher haben
final List<Integer> entityPositionsWithHoles = new ArrayList<Integer>();
for (final int position : entityPositions) {
if (entityRingCoordArr[position].length > 1) {
entityPositionsWithHoles.add(position);
}
}
final Geometry geometry = getFeature().getGeometry();
if (entityPositionsWithHoles.size() == 1) {
return entityPositionsWithHoles.get(0); // nur eine entity mit loch, also muss sie das sein
} else {
// mehrere entities, es wird geprüft welche entity welche andere beinhaltet
for (int indexA = 0; indexA < entityPositionsWithHoles.size(); indexA++) {
final int entityPositionA = entityPositionsWithHoles.get(indexA);
final Geometry envelopeA = geometry.getGeometryN(entityPositionA).getEnvelope();
boolean containsAnyOtherRing = false;
for (int indexB = 0; indexB < entityPositionsWithHoles.size(); indexB++) {
if (indexA != indexB) {
final int entityPositionB = entityPositionsWithHoles.get(indexB);
final Geometry envelopeB = geometry.getGeometryN(entityPositionB).getEnvelope();
if (envelopeA.covers(envelopeB)) {
containsAnyOtherRing = true;
}
}
}
if (!containsAnyOtherRing) {
return entityPositionA;
}
}
return -1;
}
}
/**
* DOCUMENT ME!
*
* @param point DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public int getEntityPositionUnderPoint(final Point point) {
for (int entityIndex = 0; entityIndex < entityRingCoordArr.length; entityIndex++) {
final Geometry geometry = getFeature().getGeometry().getGeometryN(entityIndex);
if (geometry.covers(point)) {
return entityIndex;
}
}
return -1;
}
/**
* DOCUMENT ME!
*
* @param geometry DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public boolean hasEntitiesInGeometry(final Geometry geometry) {
for (int entityIndex = 0; entityIndex < entityRingCoordArr.length; entityIndex++) {
final Geometry entityGeometry = getFeature().getGeometry().getGeometryN(entityIndex);
if (geometry.covers(entityGeometry)) {
return true;
}
}
return false;
}
/**
* DOCUMENT ME!
*
* @param entityPosition DOCUMENT ME!
*/
public void setSelectedEntity(final int entityPosition) {
final boolean isInBounds = (entityPosition >= 0) && (entityPosition < entityRingCoordArr.length);
if (isInBounds) {
selectedEntity = entityPosition;
} else {
selectedEntity = -1;
}
}
/**
* DOCUMENT ME!
*
* @param toSelect DOCUMENT ME!
* @param colFill DOCUMENT ME!
* @param colEdge DOCUMENT ME!
* @param insetSize DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
private Image highlightImageAsSelected(final Image toSelect, Color colFill, Color colEdge, final int insetSize) {
if (colFill == null) {
colFill = TRANSPARENT;
}
if (colEdge == null) {
colEdge = TRANSPARENT;
}
final SoftReference<Image> selectedImageRef = imageCache.get(toSelect.toString() + colFill + colEdge);
if (selectedImageRef != null) {
if (selectedImageRef.get() != null) {
return selectedImageRef.get();
}
}
if (toSelect != null) {
final int doubleInset = 2 * insetSize;
final BufferedImage tint = new BufferedImage(toSelect.getWidth(null) + doubleInset,
toSelect.getHeight(null)
+ doubleInset,
BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2d = (Graphics2D)tint.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setPaint(colFill);
g2d.fillRoundRect(
0,
0,
toSelect.getWidth(null)
- 1
+ doubleInset,
toSelect.getHeight(null)
- 1
+ doubleInset,
10,
10);
g2d.setPaint(colEdge);
g2d.drawRoundRect(
0,
0,
toSelect.getWidth(null)
- 1
+ doubleInset,
toSelect.getHeight(null)
- 1
+ doubleInset,
10,
10);
g2d.drawImage(toSelect, insetSize, insetSize, null);
imageCache.put(toSelect.toString() + colFill + colEdge, new SoftReference<Image>(tint));
return tint;
} else {
return toSelect;
}
}
/**
* Ver\u00E4ndert die Sichtbarkeit der InfoNode.
*
* @param visible true, wenn die InfoNode sichtbar sein soll
*/
public void setInfoNodeVisible(final boolean visible) {
if (infoNode != null) {
infoNode.setVisible(visible);
}
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public MappingComponent getViewer() {
return viewer;
}
/**
* DOCUMENT ME!
*
* @param viewer DOCUMENT ME!
*/
public void setViewer(final MappingComponent viewer) {
this.viewer = viewer;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
private Crs getViewerCrs() {
return viewer.getMappingModel().getSrs();
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public MappingComponent getMappingComponent() {
return viewer;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public Paint getNonSelectedPaint() {
return nonSelectedPaint;
}
/**
* DOCUMENT ME!
*
* @param nonSelectedPaint DOCUMENT ME!
*/
public void setNonSelectedPaint(final Paint nonSelectedPaint) {
this.nonSelectedPaint = nonSelectedPaint;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public Paint getNonHighlightingPaint() {
return nonHighlightingPaint;
}
/**
* DOCUMENT ME!
*
* @param nonHighlightingPaint DOCUMENT ME!
*/
public void setNonHighlightingPaint(final Paint nonHighlightingPaint) {
this.nonHighlightingPaint = nonHighlightingPaint;
}
/**
* DOCUMENT ME!
*
* @param entityPosition coordEntity DOCUMENT ME!
* @param ringPosition DOCUMENT ME!
* @param xp DOCUMENT ME!
* @param yp DOCUMENT ME!
* @param coordArr DOCUMENT ME!
*/
private void setNewCoordinates(final int entityPosition,
final int ringPosition,
final float[] xp,
final float[] yp,
final Coordinate[] coordArr) {
if (isValidWithThisCoordinates(entityPosition, ringPosition, coordArr)) {
entityRingCoordArr[entityPosition][ringPosition] = coordArr;
entityRingXArr[entityPosition][ringPosition] = xp;
entityRingYArr[entityPosition][ringPosition] = yp;
syncGeometry();
updatePath();
getViewer().showHandles(false);
final Collection<Feature> features = new ArrayList<Feature>();
features.add(getFeature());
((DefaultFeatureCollection)getViewer().getFeatureCollection()).fireFeaturesChanged(features);
}
}
/**
* DOCUMENT ME!
*
* @param entityPosition DOCUMENT ME!
* @param ringPosition DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public boolean isValid(final int entityPosition, final int ringPosition) {
return isValidWithThisCoordinates(
entityPosition,
ringPosition,
getCoordArr(entityPosition, ringPosition));
}
/**
* DOCUMENT ME!
*
* @param entityPosition DOCUMENT ME!
* @param ringCoordArr DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
private boolean isValidWithThisEntity(final int entityPosition, final Coordinate[][] ringCoordArr) {
// polygon für die prüfung erzeugen
final Geometry newGeometry;
try {
final GeometryFactory geometryFactory = new GeometryFactory(
new PrecisionModel(PrecisionModel.FLOATING),
CrsTransformer.extractSridFromCrs(getViewerCrs().getCode()));
if ((getFeature().getGeometry() instanceof Polygon)
|| (getFeature().getGeometry() instanceof MultiPolygon)) {
newGeometry = createPolygon(ringCoordArr, geometryFactory);
} else if ((getFeature().getGeometry() instanceof LineString)
|| (getFeature().getGeometry() instanceof MultiLineString)) {
newGeometry = createLineString(ringCoordArr[0], geometryFactory);
} else if ((getFeature().getGeometry() instanceof Point)
|| (getFeature().getGeometry() instanceof MultiPoint)) {
newGeometry = createPoint(ringCoordArr[0][0], geometryFactory);
} else {
if (log.isDebugEnabled()) {
log.debug("unknown geometry type");
}
return false;
}
if (!newGeometry.isValid()) {
return false;
}
final Geometry geometry = getFeature().getGeometry();
for (int entityIndex = 0; entityIndex < geometry.getNumGeometries(); entityIndex++) {
if ((entityPosition < 0) || (entityIndex != entityPosition)) { // nicht mit sich (bzw seinem alten
// selbst) selbst vergleichen
final Geometry otherGeometry = geometry.getGeometryN(entityIndex);
if (newGeometry.intersects(otherGeometry)) {
// polygon schneidet ein anderes teil-polygon
return false;
}
}
}
// alles ok
return true;
} catch (final Exception ex) {
if (log.isDebugEnabled()) {
// verändertes teil-polygon ist selbst schon nicht gültig;
log.debug("invalid geometry", ex);
}
return false;
}
}
/**
* DOCUMENT ME!
*
* @param coordArr DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public boolean isValidWithThisNewEntityCoordinates(final Coordinate[] coordArr) {
final Coordinate[][] tempRingCoordArr = new Coordinate[1][];
tempRingCoordArr[0] = coordArr;
return isValidWithThisEntity(-1, tempRingCoordArr);
}
/**
* DOCUMENT ME!
*
* @param entityPosition DOCUMENT ME!
* @param coordArr DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public boolean isValidWithThisNewHoleCoordinates(final int entityPosition, final Coordinate[] coordArr) {
final Coordinate[][] tempRingCoordArr = new Coordinate[entityRingCoordArr[entityPosition].length + 1][];
System.arraycopy(
entityRingCoordArr[entityPosition],
0,
tempRingCoordArr,
0,
entityRingCoordArr[entityPosition].length);
tempRingCoordArr[entityRingCoordArr[entityPosition].length] = coordArr;
return isValidWithThisEntity(entityPosition, tempRingCoordArr);
}
/**
* DOCUMENT ME!
*
* @param entityPosition DOCUMENT ME!
* @param ringPosition DOCUMENT ME!
* @param coordArr DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public boolean isValidWithThisCoordinates(final int entityPosition,
final int ringPosition,
final Coordinate[] coordArr) {
// copy von original teil-polygon machen
final Coordinate[][] tempRingCoordArr = new Coordinate[entityRingCoordArr[entityPosition].length][];
System.arraycopy(
entityRingCoordArr[entityPosition],
0,
tempRingCoordArr,
0,
entityRingCoordArr[entityPosition].length);
// ring in der kopie austauschen
tempRingCoordArr[ringPosition] = coordArr;
return isValidWithThisEntity(entityPosition, tempRingCoordArr);
}
/**
* DOCUMENT ME!
*/
public void updatePath() {
getPathReference().reset();
Geometry geom;
if (feature instanceof DefaultFeatureServiceFeature) {
geom = ((DefaultFeatureServiceFeature)feature).getSimpleGeometry();
} else {
geom = feature.getGeometry();
}
if (geom instanceof Point) {
setPathToPolyline(
new float[] { entityRingXArr[0][0][0], entityRingXArr[0][0][0] },
new float[] { entityRingYArr[0][0][0], entityRingYArr[0][0][0] });
} else if ((geom instanceof LineString) || (geom instanceof MultiPoint)) {
setPathToPolyline(entityRingXArr[0][0], entityRingYArr[0][0]);
} else if ((geom instanceof Polygon) || (geom instanceof MultiPolygon)) {
getPathReference().setWindingRule(GeneralPath.WIND_EVEN_ODD);
for (int entityIndex = 0; entityIndex < entityRingCoordArr.length; entityIndex++) {
for (int ringIndex = 0; ringIndex < entityRingCoordArr[entityIndex].length; ringIndex++) {
final Coordinate[] coordArr = entityRingCoordArr[entityIndex][ringIndex];
addLinearRing(coordArr);
}
}
// the next three lines are required, because the addLinearRing() method uses getPathReference().append(gp,
// false) instead of append(gp, false), due to performance reasons
firePropertyChange(PROPERTY_CODE_PATH, PROPERTY_PATH, null, getPathReference());
updateBoundsFromPath();
invalidatePaint();
} else if (geom instanceof MultiLineString) {
for (int entityIndex = 0; entityIndex < entityRingCoordArr.length; entityIndex++) {
for (int ringIndex = 0; ringIndex < entityRingCoordArr[entityIndex].length; ringIndex++) {
final Coordinate[] coordArr = entityRingCoordArr[entityIndex][ringIndex];
addLinearRing(coordArr);
}
}
// the next three lines are required, because the addLinearRing() method uses getPathReference().append(gp,
// false) instead of append(gp, false), due to performance reasons
firePropertyChange(PROPERTY_CODE_PATH, PROPERTY_PATH, null, getPathReference());
updateBoundsFromPath();
invalidatePaint();
}
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public PNode getInfoNode() {
return infoNode;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public PNode getStickyChild() {
return stickyChild;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public boolean hasSecondStickyChild() {
return (secondStickyChild != null);
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public boolean hasHole() {
final int polygons = entityRingCoordArr.length;
for (int i = 0; i < polygons; i++) {
final int rings = entityRingCoordArr[i].length;
if (rings > 1) {
return true;
}
}
return false;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public PNode getSecondStickyChild() {
return secondStickyChild;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public boolean isSnappable() {
return snappable;
}
/**
* DOCUMENT ME!
*
* @param snappable DOCUMENT ME!
*/
public void setSnappable(final boolean snappable) {
this.snappable = snappable;
}
/**
* DOCUMENT ME!
*
* @param coordArr DOCUMENT ME!
*
* @deprecated DOCUMENT ME!
*/
public void setCoordArr(final Coordinate[] coordArr) {
entityRingCoordArr = new Coordinate[][][] {
{ coordArr }
};
updateXpAndYp();
}
/**
* DOCUMENT ME!
*
* @param entityPosition DOCUMENT ME!
* @param ringPosition DOCUMENT ME!
* @param coordArr DOCUMENT ME!
*/
public void setCoordArr(final int entityPosition, final int ringPosition, final Coordinate[] coordArr) {
entityRingCoordArr[entityPosition][ringPosition] = coordArr;
updateXpAndYp();
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public int getNumOfEntities() {
return entityRingCoordArr.length;
}
/**
* DOCUMENT ME!
*
* @param entityIndex DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public int getNumOfRings(final int entityIndex) {
return entityRingCoordArr[entityIndex].length;
}
/**
* DOCUMENT ME!
*/
public void releaseResources() {
if (pi != null) {
viewer.removeStickyNode(pi);
}
if (piSelected != null) {
viewer.removeStickyNode(piSelected);
}
if ((stickyChild != null) && (stickyChild instanceof PSticky)) {
viewer.removeStickyNode((PSticky)stickyChild);
}
if ((secondStickyChild != null) && (stickyChild instanceof PSticky)) {
viewer.removeStickyNode((PSticky)secondStickyChild);
}
if (sldStyledImage != null) {
for (final PImage i : sldStyledImage) {
if (i instanceof PSticky) {
viewer.removeStickyNode((PSticky)i);
}
}
}
if (sldStyledSelectedImage != null) {
for (final PImage i : sldStyledSelectedImage) {
if (i instanceof PSticky) {
viewer.removeStickyNode((PSticky)i);
}
}
}
if (sldStyledText != null) {
for (final PTextWithDisplacement text : sldStyledText) {
if (text instanceof PSticky) {
viewer.removeStickyNode((PSticky)text);
}
}
}
if ((tPropertyChange != null) && (viewer != null)) {
viewer.getCamera().removePropertyChangeListener(PCamera.PROPERTY_VIEW_TRANSFORM, tPropertyChange);
}
}
//~ Inner Classes ----------------------------------------------------------
/**
* Adjusts the scale of the SelectionAwareTexturePaint object.
*
* @version $Revision$, $Date$
*/
class TexturePaintPropertyChangeListener implements PropertyChangeListener {
//~ Instance fields ----------------------------------------------------
double scale = 0;
//~ Methods ------------------------------------------------------------
@Override
public void propertyChange(final PropertyChangeEvent evt) {
if (scale != viewer.getCamera().getViewScale()) {
if (nonHighlightingPaint instanceof SelectionAwareTexturePaint) {
((SelectionAwareTexturePaint)nonHighlightingPaint).setScale(viewer.getCamera().getViewScale(),
CrsTransformer.transformToGivenCrs(feature.getGeometry(), getViewerCrs().getCode()));
PFeature.this.repaint();
}
scale = viewer.getCamera().getViewScale();
}
}
}
/**
* DOCUMENT ME!
*
* @version $Revision$, $Date$
*/
class StickyPPath extends PPath implements ParentNodeIsAPFeature, PSticky {
//~ Instance fields ----------------------------------------------------
int transparency = 0;
Color c = null;
//~ Constructors -------------------------------------------------------
/**
* Creates a new StickyPPath object.
*
* @param s DOCUMENT ME!
*/
public StickyPPath(final Shape s) {
super(s);
}
}
/**
* StickyPText represents the annotation of a PFeature.
*
* @version $Revision$, $Date$
*/
public class StickyPText extends PText implements ParentNodeIsAPFeature, PSticky {
//~ Constructors -------------------------------------------------------
/**
* Creates a new StickyPText object.
*/
public StickyPText() {
super();
}
/**
* Creates a new StickyPText object.
*
* @param text DOCUMENT ME!
*/
public StickyPText(final String text) {
super(text);
}
}
/**
* DOCUMENT ME!
*
* @version $Revision$, $Date$
*/
public class PTextWithDisplacement extends PText implements PSticky {
//~ Instance fields ----------------------------------------------------
double displacementX;
double displacementY;
private SLDStyledFeature.UOM uom;
private double anchorPointX;
private double anchorPointY;
private WorldToScreenTransform wtst;
private double scaledDisplacementX;
private double scaledDisplacementY;
//~ Methods ------------------------------------------------------------
@Override
public void setScale(final double scale) {
offset(-scaledDisplacementX, -scaledDisplacementY);
super.setScale(scale);
scaledDisplacementX = (displacementX + ((-anchorPointX) * (double)this.getWidth())) / scale;
scaledDisplacementY = (displacementY + ((anchorPointY) * (double)this.getHeight())) / scale;
offset(scaledDisplacementX, scaledDisplacementY);
}
/**
* DOCUMENT ME!
*
* @param uomFromDeegree DOCUMENT ME!
* @param displacementX DOCUMENT ME!
* @param displacementY DOCUMENT ME!
* @param anchorPointX DOCUMENT ME!
* @param anchorPointY DOCUMENT ME!
* @param wtst DOCUMENT ME!
*/
public void setDisplacement(final SLDStyledFeature.UOM uomFromDeegree,
final double displacementX,
final double displacementY,
final double anchorPointX,
final double anchorPointY,
final WorldToScreenTransform wtst) {
this.uom = uomFromDeegree;
this.displacementX = displacementX;
this.displacementY = displacementY;
this.anchorPointX = anchorPointX;
this.anchorPointY = anchorPointY;
this.wtst = wtst;
}
}
}