/* * 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.labeling; import co.foldingmap.map.themes.LabelStyle; import java.awt.Graphics2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.util.ArrayList; /** * * @author Alec */ public class PointLabel extends MapLabel { public final static int NORTH = 1; public final static int EAST = 3; public final static int SOUTH = 5; public final static int WEST = 7; protected double theta; protected int lineX1, lineX2; protected int lineY1, lineY2; protected int posistion; protected int signifiedX, signifiedY; protected String labelText; protected String line1, line2; /** * Constructor for objects of class PointLabel * * @param String labelText The text of the label. * @param LabelStyle labelStyle The labelStyle object used to style the text. * @param int signifiedX The horizontal location of the object being labeled. * @param int signifiedY The vertical location of the object being labeled. * @param double theta The angle to draw the label; the angle of rotation is in radians. * */ public PointLabel(String labelText, LabelStyle labelStyle, int signifiedX, int signifiedY, double theta) { this.labelFont = labelStyle.getFont(); this.labelText = labelText; this.labelStyle = labelStyle; this.posistion = SOUTH; this.signifiedX = signifiedX; this.signifiedY = signifiedY; this.theta = theta; } /** * Creates the label to be displayed on the map. * * @param g2 * @param posistion */ private void createLabel(Graphics2D g2, int posistion) { Rectangle2D lineArea1, lineArea2; line1 = ""; line2 = ""; lineX1 = 0; lineX2 = 0; lineY1 = 0; lineY2 = 0; ArrayList<String> lines = getLabelLines(); try { if (lines.size() > 1) { line1 = lines.get(0); line2 = lines.get(1); lineArea1 = fontMetrics.getStringBounds(line1, g2); lineArea2 = fontMetrics.getStringBounds(line2, g2); if (posistion == EAST) { lineX1 = (signifiedX + 6); lineX2 = (signifiedX + 6); } else if (posistion == SOUTH) { lineX1 = (int) (signifiedX - (lineArea1.getWidth() / 2)); lineX2 = (int) (signifiedX - (lineArea2.getWidth() / 2)); lineY1 = signifiedY; lineY2 = signifiedY + 12; } labelArea = new Rectangle2D.Double(lineArea1.getX(), lineArea1.getY(), Math.max(lineArea1.getWidth(), lineArea2.getWidth()), lineArea1.getHeight() + lineArea2.getHeight() + 12); } else { if (posistion == EAST) { lineArea1 = fontMetrics.getStringBounds(lines.get(0), g2); labelArea = lineArea1; lineX1 = signifiedX + 6; lineY1 = signifiedY - 14; line1 = labelText; } else if (posistion == SOUTH) { lineArea1 = fontMetrics.getStringBounds(lines.get(0), g2); labelArea = lineArea1; lineX1 = (int) (signifiedX - (lineArea1.getWidth() / 2)); lineY1 = signifiedY; line1 = labelText; } } } catch (Exception e) { System.err.println("Error in PointLabel.createLabel(g2, int) - " + e); } } /** * Draws this TextLabel object. * * @param Graphics2D g2 The graphics object used to draw. */ @Override public void drawLabel(Graphics2D g2) { try { if (theta != 0) { g2.rotate(theta * -1); drawLabel(labelStyle, g2); g2.rotate(theta); } else { drawLabel(labelStyle, g2); } } catch (Exception e) { System.err.println("Error in PointLabel.drawLabel(Graphics2D) - " + e); } } private void drawLabel(LabelStyle labelStyle, Graphics2D g2) { try { fontMetrics = g2.getFontMetrics(labelFont); g2.setFont(labelFont); createLabel(g2, posistion); if (labelStyle.isLabelVisible()) { //draw outline g2.setColor(labelStyle.getOutlineColor()); g2.drawString(line1, (lineX1 - 1), (lineY1 + 0)); g2.drawString(line1, (lineX1 + 1), (lineY1 - 0)); g2.drawString(line1, (lineX1 - 0), (lineY1 + 1)); g2.drawString(line1, (lineX1 + 0), (lineY1 - 1)); g2.drawString(line2, (lineX2 - 1), (lineY2 + 0)); g2.drawString(line2, (lineX2 + 1), (lineY2 + 0)); g2.drawString(line2, (lineX2 - 0), (lineY2 + 1)); g2.drawString(line2, (lineX2 + 0), (lineY2 - 1)); //draw center g2.setColor(labelStyle.getFillColor()); g2.drawString(line2, (lineX2 + 0), (lineY2)); g2.drawString(line1, (lineX1 + 0), (lineY1)); } } catch (Exception e) { System.err.println("Error in PointLabel.drawLabel(LabelStyle, Graphics2D, int, int) - " + e); } } /** * Creates the Rectangle2D that represents this Label's area. * Used to help prevent overlapping of labels. * * @param g2 * @param labelPosistion */ public void generateLabelArea(Graphics2D g2, int labelPosistion) { ArrayList<String> labelLines; Rectangle2D lineArea1, lineArea2; try { labelLines = getLabelLines(); posistion = labelPosistion; fontMetrics = g2.getFontMetrics(labelFont); if (labelLines.size() > 1) { line1 = labelLines.get(0); line2 = labelLines.get(1); lineArea1 = fontMetrics.getStringBounds(line1, g2); lineArea2 = fontMetrics.getStringBounds(line2, g2); if (labelPosistion == EAST) { lineX1 = (signifiedX + 6); lineX2 = (signifiedX + 6); lineY1 = signifiedY - 14; } else if (labelPosistion == SOUTH) { lineX1 = (int) (signifiedX - (lineArea1.getWidth() / 2)); lineX2 = (int) (signifiedX - (lineArea2.getWidth() / 2)); lineY1 = signifiedY; lineY2 = signifiedY + 12; } labelArea = new Rectangle2D.Double(lineArea1.getX(), lineArea1.getY(), Math.max(lineArea1.getWidth(), lineArea2.getWidth()), lineArea1.getHeight() + lineArea2.getHeight() + 12); } else { if (labelPosistion == EAST) { lineArea1 = fontMetrics.getStringBounds(labelLines.get(0), g2); lineX1 = signifiedX + 0; lineY1 = signifiedY - 10; line1 = labelText; labelArea = new Rectangle2D.Double(lineX1, lineY1, lineArea1.getWidth() + 10, lineArea1.getHeight() + 10); } else if (labelPosistion == SOUTH) { lineArea1 = fontMetrics.getStringBounds(labelLines.get(0), g2); lineX1 = (int) (signifiedX - (lineArea1.getWidth() / 2) - 5); lineY1 = signifiedY - 5; line1 = labelText; labelArea = new Rectangle2D.Double(lineX1, lineY1, lineArea1.getWidth() + 10, lineArea1.getHeight() + 10); } } } catch (Exception e) { System.err.println("Error in PointLabel.generateLabelArea() - " + e); } } /** * Returns the Rectangle2D representing the area of this label. * * @return */ @Override public Rectangle2D getLabelArea() { return labelArea; } /** * Returns the label text broken up into lines to be displayed. * * @return */ private ArrayList<String> getLabelLines() { ArrayList<String> lines = new ArrayList<String>(); String subText; try { if (labelText.length() > 12) { for (int i = labelText.length(); i > 0; i--) { subText = labelText.substring(i - 1, i); if (subText.equals(" ") || subText.equals("-")) { lines.add(labelText.substring(0, i)); lines.add(labelText.substring(i)); } } if (lines.isEmpty()) { lines.add(labelText); } } else { lines.add(labelText); } } catch (Exception e) { System.err.println("Error in PointLabel.getLabelLines() - " + e); } return lines; } /** * Creates a point that indicates the on screen location that the first line * of this label will be drawn. * * @return */ public Point2D.Float getLine1StartPoint() { return new Point2D.Float(lineX1, lineY1); } /** * Creates a point that indicates the on screen location that the second * line of this label will be drawn. * * @return */ public Point2D.Float getLine2StartPoint() { return new Point2D.Float(lineX2, lineY2); } /** * Returns a String for the first line of this label * @return */ public String getLine1Text() { return line1; } /** * Returns a String for the first line of this label * @return */ public String getLine2Text() { return line1; } /** * Returns if this label overlaps another label. * * @param otherLabel * @return */ @Override public boolean overlapsLabel(MapLabel otherLabel) { boolean value = false; Rectangle2D testArea = otherLabel.getLabelArea(); if (labelArea.equals(testArea)) value = true; if (labelArea != null && testArea != null) value = labelArea.intersects(testArea); return value; } }