/* * Copyright (C) 2014 Alec Dhuse * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package co.foldingmap.map.vector; import co.foldingmap.Logger; import co.foldingmap.map.MapView; import co.foldingmap.map.ObjectNotWithinBoundsException; import co.foldingmap.map.Visibility; import co.foldingmap.map.labeling.PointImage; import co.foldingmap.map.labeling.PointLabel; import co.foldingmap.map.themes.ColorStyle; import co.foldingmap.map.themes.IconStyle; import co.foldingmap.map.themes.LabelStyle; import co.foldingmap.xml.XmlOutput; import java.awt.BasicStroke; import java.awt.Graphics2D; import java.awt.geom.Ellipse2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.image.ByteLookupTable; import java.awt.image.LookupOp; import java.util.HashMap; import javax.swing.ImageIcon; /** * * @author Alec */ public class MapPoint extends VectorObject { protected boolean pointLeftInit, pointCenterInit, pointRightInit; protected BufferedImage iconImage; protected byte byteLookupTable[]; protected Ellipse2D pointLeft, pointCenter, pointRight; protected float iconX1, iconX2, iconX3, iconY; protected IconStyle pointIcon; protected ImageIcon objectImage; protected LabelStyle labelStyle; protected Point2D.Float p2dLeft, p2dCenter, p2dRight; protected Rectangle2D imageArea; protected MapPoint() { } /** * Constructor * * @param name * @param objectClass * @param description * @param coordinate */ public MapPoint(String name, String objectClass, String description, Coordinate coordinate) { try { init(); this.objectClass = objectClass; this.objectName = name; this.objectDescription = description; coordinates.add(coordinate); loadByteLookupTable(); } catch (Exception e) { Logger.log(Logger.ERR, "Error in MapPoint Constructor(String, String, String, Coordinate) - " + e); } } public MapPoint(String name, Coordinate c, HashMap<String,String> customFields) { try { init(); this.coordinates.add(c); this.objectName = name; this.customDataFields = customFields; this.objectDescription = ""; } catch (Exception e) { Logger.log(Logger.ERR, "Error in MapPoint Constructor(String, Coordinate, HashMap) - " + e); } } public MapPoint(String name, String objectClass, String description, CoordinateList<Coordinate> coordinates) { try { init(); this.coordinates = coordinates; this.objectClass = objectClass; this.objectName = name; this.objectDescription = description; loadByteLookupTable(); } catch (Exception e) { Logger.log(Logger.ERR, "Error in MapPoint Constructor(String, String, String, CoordinateList) - " + e); } } @Override public VectorObject copy() { MapPoint newMapPoint = new MapPoint(this.objectName, this.objectClass, this.objectDescription, this.coordinates); newMapPoint.setCustomDataFields(this.customDataFields); newMapPoint.setParentLayer(this.getParentLayer()); return newMapPoint; } /** * * @param g2 * @param mapView * @param colorStyle */ @Override public void drawObject(Graphics2D g2, MapView mapView, ColorStyle colorStyle) { boolean drawObject; try { if (mapView.displayAll()) { drawObject = true; } else { drawObject = this.isVisible(mapView); } if (drawObject) { //Figure out which IconStyle to use if (colorStyle == null) { pointIcon = (IconStyle) mapView.getMapTheme().getStyle(this, mapView.getZoomLevel()); if (pointIcon == null) pointIcon = new IconStyle(); } else { pointIcon = (IconStyle) colorStyle; } //Check to see if the Icon Style is imposing a Visibility Visibility vis = pointIcon.getVisibility(); if (vis != null && this.visibility == null) { if (vis.isVisible(mapView.getZoomLevel()) == false) return; } //initialize pointLeftInit = false; pointCenterInit = false; pointRightInit = false; p2dLeft = null; p2dRight = null; lineStyle = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER); labelStyle = pointIcon.getLabel(); g2.setStroke(lineStyle); //is left wrapping needed if (mapView.getMapProjection().isLeftShown()) { p2dLeft = coordinates.get(0).getLeftPoint(); pointLeft = new Ellipse2D.Double( (p2dLeft.x - 2), (p2dLeft.y - 2), 4, 4 ); pointLeftInit = true; } //right wrapping is needed if (mapView.getMapProjection().isRightShown()) { p2dRight = coordinates.get(0).getRightPoint(); pointRight = new Ellipse2D.Double( (p2dRight.x - 2), (p2dRight.y - 2), 4, 4 ); pointRightInit = true; } //center if (coordinates.get(0).getCenterPoint() != null) { p2dCenter = coordinates.get(0).getCenterPoint(); pointCenter = new Ellipse2D.Double( (p2dCenter.x - 2), (p2dCenter.y - 2), 4, 4 ); pointCenterInit = true; } else { pointCenterInit = false; Logger.log(Logger.ERR, "MapPoint.drawObject(Graphics2D, MapView) - Coordinate Seems to be Missing from Node Map, adding it."); parentLayer.getParentMap().addCoordinateNode(coordinates.get(0)); } if (labelStyle != null) { if (pointCenterInit) mapView.getLabelManager().addLabel(g2, new PointLabel(objectName, labelStyle, (int) p2dCenter.x, (int) (p2dCenter.y + 15), 0)); if (pointLeftInit) mapView.getLabelManager().addLabel(g2, new PointLabel(objectName, labelStyle, (int) p2dLeft.x, (int) (p2dLeft.y + 15), 0)); if (pointRightInit) mapView.getLabelManager().addLabel(g2, new PointLabel(objectName, labelStyle, (int) p2dRight.x, (int) (p2dRight.y + 15), 0)); }//end isLabelVisible if (pointIcon.getObjectImage() != null) { objectImage = pointIcon.getObjectImage(); if (pointCenterInit) iconX1 = p2dCenter.x - (objectImage.getIconWidth() / 2.0f); if (pointLeftInit) iconX2 = p2dLeft.x - (objectImage.getIconWidth() / 2.0f); if (pointRightInit) iconX3 = p2dRight.x - (objectImage.getIconWidth() / 2.0f); //adjust the marker so that the bottom is the point. if (pointIcon.getID().equalsIgnoreCase("Marker")) { iconY = p2dCenter.y - (objectImage.getIconHeight()); } else { iconY = p2dCenter.y - (objectImage.getIconHeight() / 2.0f); } imageArea = new Rectangle2D.Float(iconX1, iconY, objectImage.getIconWidth(), objectImage.getIconHeight()); if (highlighted) { //temportay code for selection, may replace later ByteLookupTable blut = new ByteLookupTable(0, byteLookupTable); LookupOp lop = new LookupOp(blut, null); iconImage = new BufferedImage(objectImage.getImage().getWidth(null), objectImage.getImage().getHeight(null), BufferedImage.TYPE_4BYTE_ABGR ); Graphics2D g = (Graphics2D) iconImage.getGraphics(); g.drawImage(objectImage.getImage(), 0, 0, null); if (drawObject) { if (pointCenterInit) mapView.getLabelManager().addLabel(g2, new PointImage(iconImage, lop, iconX1, iconY)); if (pointLeftInit) mapView.getLabelManager().addLabel(g2, new PointImage(iconImage, lop, iconX2, iconY)); if (pointRightInit) mapView.getLabelManager().addLabel(g2, new PointImage(iconImage, lop, iconX3, iconY)); } } else { if (drawObject) { if (pointCenterInit) mapView.getLabelManager().addLabel(g2, new PointImage(objectImage, iconX1, iconY)); if (pointLeftInit) mapView.getLabelManager().addLabel(g2, new PointImage(objectImage, iconX2, iconY)); if (pointRightInit) mapView.getLabelManager().addLabel(g2, new PointImage(objectImage, iconX3, iconY)); } }//end if highlited } else { //Draw an elipse there is no image if (highlighted) { g2.setColor(pointIcon.getSelectedOutlineColor()); } else { g2.setColor(pointIcon.getOutlineColor()); } if (pointIcon.isOutlined()) { if (pointCenterInit) g2.draw(pointCenter); if (pointLeftInit) g2.draw(pointLeft); if (pointRightInit) g2.draw(pointRight); } if (highlighted) { g2.setColor(pointIcon.getSelectedFillColor()); } else { g2.setColor(pointIcon.getFillColor()); } if (pointCenterInit) g2.fill(pointCenter); if (pointLeftInit) g2.fill(pointLeft); if (pointRightInit) g2.fill(pointRight); } } } catch (Exception e) { Logger.log(Logger.ERR, "Error in MapPoint.drawObject(Graphics2D, MapView) - " + e); } } /** * Draws the outline for this Point. * Not used for MapPoint. * * @param g2 * @param mapView * @param inMultiGeometry */ @Override public void drawOutline(Graphics2D g2, MapView mapView, boolean inMultiGeometry) { } /** * Draws the points that make up this object. * * @param g2 * @param mapView */ @Override public void drawPoints(Graphics2D g2, MapView mapView) { //do nothing for MapPoint } /** * If the object is within the boundary it will be returned. If not throw * an error. * * @param boundry * @return * @throws ObjectNotWithinBoundsException */ @Override public VectorObject fitToBoundry(LatLonAltBox boundry) throws ObjectNotWithinBoundsException { MapPoint fittedObject; if (boundry.contains(this.coordinates.get(0))) { fittedObject = this; } else { throw new ObjectNotWithinBoundsException(this, boundry); } return fittedObject; } /** * Creates a box that gives the bounds of the coordinate of this object. */ @Override public void generateBoundingBox() { Coordinate c = coordinates.get(0); this.boundingBox = new LatLonAltBox((float) (c.getLatitude() - 0.0001), (float) (c.getLatitude() + 0.0001), (float) (c.getLongitude() + 0.0001), (float) (c.getLongitude() - 0.0001), (float) (c.getAltitude()), (float) (c.getAltitude())); } /** * If the Screen Point is within the range return it, as its Coordinate. * If it is not within the range, return null. * * @param range * @return */ @Override public Coordinate getCoordinateWithinRectangle(Rectangle2D range) { Coordinate returnCoordinate = null; Point2D screenPoint = this.coordinates.get(0).getCenterPoint(); if (range.contains(screenPoint.getX(), screenPoint.getY())) returnCoordinate = coordinates.get(0); return returnCoordinate; } /** * Used in place of calling super(). This is mainly to initiate the * CoordinateList to a single Coordinate to save mem. * */ protected final void init() { //Default Settings; coordinates = new CoordinateList(1); customDataFields = new HashMap<String, String>(); selectedCoordinate = Coordinate.UNKNOWN_COORDINATE; reference = 0; } /** * Used to detect if an object is to be selected. * If all or part of the object is within the range this method will * return true. * * @param range * @return */ @Override public boolean isObjectWithinRectangle(Rectangle2D range) { boolean returnVal = false; try { if (pointLeftInit) { if (pointLeft.intersects(range)) returnVal = true; } if (pointCenterInit) { if (pointCenter.intersects(range)) returnVal = true; } if (pointRightInit) { if (pointRight.intersects(range)) returnVal = true; } } catch (Exception e) { Logger.log(Logger.ERR, "Error in MapPoint.isObjectWithinRectangle(Rectangle2D range) - " + e); } return returnVal; } /** * Loads the byte lookup table, * this is for when points with icons are selected. */ private void loadByteLookupTable() { try { this.byteLookupTable = new byte[256]; //setup the seletion lookup table for (int j = 0; j < 127; j++) byteLookupTable[j] = (byte)(128-j); for (int j = 128; j < 256; j++) byteLookupTable[j] = (byte) ((128-j) * -1); } catch (Exception e) { Logger.log(Logger.ERR, "Error in MapPoint.loadByteLookupTable() - " + e); } } /** * Sets the MapPoint as Highlighted and selects it's one and only coordinate * as the selected coordinate; * * @param highlighted If the MapPoint is highlighted or not. */ @Override public void setHighlighted(boolean highlighted) { try { this.highlighted = highlighted; this.selectedCoordinate = this.coordinates.get(0); } catch (Exception e) { Logger.log(Logger.ERR, "Error in MapPoint.setHighlighter(boolean) - " + e); } } @Override public void toXML(XmlOutput xmlWriter) { xmlWriter.openTag ("Point class=\"" + getObjectClass() + "\" id=\"" + getName() + "\""); xmlWriter.writeTag("Ref", Long.toString(getReference())); xmlWriter.writeTag("coordinates", getCoordinateString()); if (hasDisplayableText(getDescription()) && !getDescription().equalsIgnoreCase("null")) xmlWriter.writeTag("description", "<![CDATA[" + getDescription() + "]]>"); if (visibility != null) visibility.toXML(xmlWriter); writeCustomDataFieldsAsXML(xmlWriter); xmlWriter.closeTag("Point"); } }