/*
* 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 java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
/**
* This class is used to label LineString on the map.
*
* @author Alec
*/
public class LineStringLabel extends MapLabel {
private ArrayList<LabelInstruction> instructions;
/**
* Basic constructor for LineStringLabel, sets all options to default.
*/
public LineStringLabel(Graphics2D g2) {
this.complete = false;
this.fillColor = new Color(75, 68, 60);
this.labelFont = new Font(Font.SANS_SERIF, Font.PLAIN, 11);
this.fontMetrics = g2.getFontMetrics(labelFont);
this.instructions = new ArrayList<LabelInstruction>();
}
/**
* Creates a new draw instruction and adds it to the list of daw instructions.
*
* @param angle The angle to draw this potion of the label.
* @param rotationFocus The focus of the rotation.
* @param textX The x position of where to draw the label.
* @param textY The y position of where to draw the label.
* @param text The text representing this portion of the label.
*/
public void addLabelInstruction(float angle, Point2D rotationFocus, float textX, float textY, String text) {
instructions.add(new LabelInstruction(angle, rotationFocus, textX, textY, text));
}
/**
* Draws the label on the given graphics class.
*
* @param g2
*/
@Override
public void drawLabel(Graphics2D g2) {
AffineTransform at, originalTransform;
originalTransform = g2.getTransform();
g2.setFont(labelFont);
for (LabelInstruction li: instructions) {
at = g2.getTransform();
if (li.angle != 0) {
at.rotate(li.angle, li.rotationFocus.getX(), li.rotationFocus.getY());
g2.setTransform(at);
}
//draw outline
if (this.outlineColor != null) {
g2.setColor(outlineColor);
g2.drawString(li.text, (li.textX - 1), (li.textY + 0));
g2.drawString(li.text, (li.textX + 1), (li.textY - 0));
g2.drawString(li.text, (li.textX - 0), (li.textY + 1));
g2.drawString(li.text, (li.textX + 0), (li.textY - 1));
}
g2.setColor(fillColor);
g2.drawString(li.text, li.textX, li.textY);
g2.setTransform(originalTransform);
}
}
/**
* Tests to see if this LineStringLabel is equal to another.
* TODO: Complete
*
* @param lsl
* @return
*/
public boolean equal(LineStringLabel lsl) {
ArrayList<LabelInstruction> i1, i2;
boolean equal;
equal = false;
i1 = this.getLabelInstruction();
i2 = lsl.getLabelInstruction();
if (i1.size() == i2.size()) {
for (int i = 0; i < i1.size(); i++) {
if (i1.get(i).equals(i2.get(i))) {
equal = true;
} else {
equal = false;
break;
}
}
} else {
equal = false;
}
return false;
}
/**
* Generates a Rectangle2D representing the area of this label.
*
* @param g2
*/
public void generateLabelArea(Graphics2D g2) {
double x, y, w, h;
double sectionX, sectionY, sectionW, sectionH;
double xMod, yMod;
Rectangle2D sectionBounds, totalBounds;
totalBounds = null;
fontMetrics = g2.getFontMetrics(labelFont);
//TODO: Finish this method.
for (LabelInstruction li: instructions) {
sectionBounds = fontMetrics.getStringBounds(li.text, g2);
xMod = (sectionBounds.getHeight() * 0.153);
yMod = (sectionBounds.getHeight() / 1.4);
//initial values
if (totalBounds == null) {
x = li.textX;
y = li.textY;
w = 0;
h = 0;
totalBounds = new Rectangle2D.Float(0,0,0,0);
} else {
x = totalBounds.getX();
y = totalBounds.getY();
w = totalBounds.getWidth();
h = totalBounds.getHeight();
}
if (li.text.length() > 0) {
if (li.angle == Math.toRadians(0)) {
sectionX = sectionBounds.getX() + li.textX;
sectionY = sectionBounds.getY() + li.textY;
if (sectionX < x)
x = sectionX;
if (sectionY < y)
y = sectionY;
if (sectionBounds.getWidth() > w)
w = sectionBounds.getWidth();
if (sectionBounds.getHeight() > h)
h = sectionBounds.getHeight();
} else if (li.angle < 0 && li.angle > Math.toRadians(-90)) {
sectionX = (li.textX - xMod);
sectionY = (li.textY - yMod);
sectionW = sectionBounds.getWidth() + xMod;
sectionH = sectionBounds.getHeight() + yMod;
if (sectionX < totalBounds.getX())
x = sectionX;
if (sectionY < totalBounds.getY())
y = sectionY;
if (sectionW > w)
w = sectionW;
if (sectionH > h)
h = sectionH;
} else {
sectionX = (li.textX - xMod);
sectionY = (li.textY - yMod);
sectionW = sectionBounds.getWidth() + xMod;
sectionH = sectionBounds.getHeight() + yMod;
if (sectionX < totalBounds.getX())
x = sectionX;
if (sectionY < totalBounds.getY())
y = sectionY;
if (sectionW > w)
w = sectionW;
if (sectionH > h)
h = sectionH;
}
//set new bounds
totalBounds.setRect(x, y, w, h);
}
}
this.labelArea = totalBounds;
}
/**
* Returns a Rectangle2D representing the area of this label.
*
* @return
*/
@Override
public Rectangle2D getLabelArea() {
return labelArea;
}
/**
* Returns the ArrayList of LabelInstructions for this Label;
*
* @return
*/
public ArrayList<LabelInstruction> getLabelInstruction() {
return instructions;
}
/**
* Returns the number of draw instructions for this label.
*
* @return
*/
public int getNumberOfInstructions() {
return instructions.size();
}
/**
* Returns if the construction of this label is complete.
*
* @return
*/
@Override
public boolean isComplete() {
return complete;
}
/**
* Returns if this label overlaps another.
*
* @param label
* @return
*/
@Override
public boolean overlapsLabel(MapLabel label) {
// return false;
if (labelArea != null) {
boolean value = false;
Rectangle2D testArea = label.getLabelArea();
if (labelArea.equals(testArea))
value = true;
if (labelArea != null && testArea != null)
value = labelArea.intersects(testArea);
return value;
} else {
return false;
}
}
/**
* Sets if the construction of this label is complete, having all the
* necessary draw instructions saved.
*
* @param complete
*/
public void setComplete(boolean complete) {
this.complete = complete;
}
}