package com.androidol.feature; import java.util.HashMap; import com.androidol.basetypes.Pixel; import com.androidol.style.Style; import com.androidol.util.Util; import com.androidol.util.geometry.JTSGeometryUtils; import com.androidol.util.geometry.MoveCoordinateFilter; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.Polygon; /** * Vector features use the Geometry classes as geometry description. * They have an �attributes� property, which is the data object, and a �style� property, * the default values of which are defined in the OpenLayers.Feature.Vector.style objects */ public class Vector extends Feature { // =========================================================== // Fields // =========================================================== protected String fid = null; protected Geometry geometry = null; protected String state = null; protected Style style = null; protected Style originalStyle = null; protected String renderIntent = "default"; /** * Constructor * * @param geometry * @param attributes * @param style */ public Vector(Geometry geometry, HashMap<String, String> attributes, Style style) { super(null, null, attributes); this.coordinate = null; this.state = null; if(geometry != null) { this.geometry = geometry; } this.attributes = new HashMap<String, String>(); if(attributes != null) { this.attributes = Util.extend(this.attributes, attributes); } if(style != null) { this.style = style; } } /** * API Method: destroy * nullify references to prevent circular references and memory leaks */ public void destroy() { if(this.layer != null) { // TODO: remove this feature from layer? //this.layer.removeFeatures(this); this.layer = null; } this.geometry = null; super.destroy(); } /** * API Method: clone * Create a clone of this vector feature. Does not set any non-standard * properties. * * @return {Vector} An exact clone of this vector feature. */ public Vector clone() { if(this.geometry != null) { return new Vector((Geometry)this.geometry.clone(), this.attributes, this.style); } else { return new Vector(null, this.attributes, this.style); } } /** * API Method: onScreen * Determine whether the feature is within the map viewport. This method * tests for an intersection between the geometry and the viewport * bounds. If a more effecient but less precise geometry bounds * intersection is desired, call the method with the boundsOnly * parameter true. * * @param boundsOnly - {boolean} Only test whether a feature's bounds intersects * the viewport bounds. Default is false. If false, the feature's * geometry must intersect the viewport for onScreen to return true. * * @return {boolean} The feature is currently visible on screen (optionally * based on its bounds if boundsOnly is true). */ public boolean onScreen(boolean boundsOnly) { boolean onScreen = false; if(this.layer!=null && this.layer.getMap()!=null) { Envelope screenBounds = this.layer.getMap().getExtent(); if(boundsOnly) { Envelope featureBounds = this.geometry.getEnvelopeInternal(); onScreen = screenBounds.intersects(featureBounds); } else { //Polygon screenPoly = JTSGeometryUtils.envelopeToPolygon(screenBounds); // TODO: implement polygon interesects //onScreen = screenPoly.intersects(this.geometry); } } return onScreen; } /** * * @return */ /* @Override public Marker createMarker() {} */ /** * */ /* @Override public void destroyMarker() {} */ /** * * @param closeBox * @return */ /* @Override public Popup createPopup(boolean closeBox) {} */ /** * */ /* @Override public void destroyPopup() {} */ /** * API Method: atPoint * Determines whether the feature intersects with the specified location. * * @param lonlat - {LonLat} * @param toleranceLon - {double} Optional tolerance in Geometric Coords * @param toleranceLat - {double} Optional tolerance in Geographic Coords * * @return {boolean} Whether or not the feature is at the specified location */ public boolean atPoint(Coordinate coord, double toleranceX, double toleranceY) { boolean atPoint = false; if(this.geometry != null) { Envelope envelope = this.geometry.getEnvelopeInternal(); envelope.expandBy(toleranceX, toleranceY); atPoint = envelope.contains(coord); } return atPoint; } /** * API Method: move * Moves the feature and redraws it at its new location * * Parameters: * state - {OpenLayers.LonLat or OpenLayers.Pixel} the * location to which to move the feature. */ public void move(Coordinate location) { if(this.layer==null) { return; } Pixel pixel = this.layer.getViewPortPxFromCoordinate(location); Pixel lastPixel = this.layer.getViewPortPxFromCoordinate(this.geometry.getEnvelopeInternal().centre()); double res = this.layer.getMap().getResolution(); // TODO: check how performance could be affected by this this.geometry.apply(new MoveCoordinateFilter(res*(pixel.getX()-lastPixel.getX()), res*(lastPixel.getY()-pixel.getY()))); } /** * API Method: toState * Sets the new state * * @param state - {String} */ public void toState(String state) { if(state.equalsIgnoreCase(State.UPDATE) == true) { if(this.state.equalsIgnoreCase(State.UNKNOWN) || this.state.equalsIgnoreCase(State.DELETE)) { this.state = state; } } else if(state.equalsIgnoreCase(State.INSERT) == true) { if(this.state.equalsIgnoreCase(State.UNKNOWN)==false) { this.state = state; } } else if(state.equalsIgnoreCase(State.DELETE) == true) { if(this.state.equalsIgnoreCase(State.UNKNOWN) || this.state.equalsIgnoreCase(State.UPDATE)) { this.state = state; } } else if(state.equalsIgnoreCase(State.UNKNOWN) == true) { this.state = state; } } /** * @return the style */ public Style getStyle() { return style; } /** * @param style the style to set */ public void setStyle(Style style) { this.style = style; } /** * @return the geometry */ public Geometry getGeometry() { return geometry; } /** * @param geometry the geometry to set */ public void setGeometry(Geometry geometry) { this.geometry = geometry; } /** * @return the renderIntent */ public String getRenderIntent() { return renderIntent; } /** * @param renderIntent the renderIntent to set */ public void setRenderIntent(String renderIntent) { this.renderIntent = renderIntent; } /** * @return the fid */ public String getFid() { return fid; } /** * @param fid the fid to set */ public void setFid(String fid) { this.fid = fid; } }