/**
* OrbisGIS is a java GIS application dedicated to research in GIScience.
* OrbisGIS is developed by the GIS group of the DECIDE team of the
* Lab-STICC CNRS laboratory, see <http://www.lab-sticc.fr/>.
*
* The GIS group of the DECIDE team is located at :
*
* Laboratoire Lab-STICC – CNRS UMR 6285
* Equipe DECIDE
* UNIVERSITÉ DE BRETAGNE-SUD
* Institut Universitaire de Technologie de Vannes
* 8, Rue Montaigne - BP 561 56017 Vannes Cedex
*
* OrbisGIS is distributed under GPL 3 license.
*
* Copyright (C) 2007-2014 CNRS (IRSTV FR CNRS 2488)
* Copyright (C) 2015-2017 CNRS (Lab-STICC UMR CNRS 6285)
*
* This file is part of OrbisGIS.
*
* OrbisGIS 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.
*
* OrbisGIS 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
* OrbisGIS. If not, see <http://www.gnu.org/licenses/>.
*
* For more information, please consult: <http://www.orbisgis.org/>
* or contact directly:
* info_at_ orbisgis.org
*/
package org.orbisgis.coremap.renderer.se.label;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBElement;
import net.opengis.se._2_0.core.LineLabelType;
import net.opengis.se._2_0.core.ObjectFactory;
import org.orbisgis.coremap.map.MapTransform;
import org.orbisgis.coremap.renderer.se.SeExceptions.InvalidStyle;
import org.orbisgis.coremap.renderer.se.SymbolizerNode;
import org.orbisgis.coremap.renderer.se.common.RelativeOrientation;
import org.orbisgis.coremap.renderer.se.common.ShapeHelper;
import org.orbisgis.coremap.renderer.se.parameter.ParameterException;
/**
* A {@code LineLabel} is a text of some kinf associated to a Line (polygon or not).
* @author Alexis Guéganno, Maxence Laurent
* @todo implements
*/
public class LineLabel extends Label {
private RelativeOrientation orientation;
/**
* Build a new default {@code LineLabel}, using the defaults in
* {@link org.orbisgis.coremap.renderer.se.label.StyledText#StyledText() StyledText}.
* The label will be centered (horizontally), and in the middle (vertically)
* of the graphic.
*/
public LineLabel() {
super();
setVerticalAlign(VerticalAlignment.MIDDLE);
setHorizontalAlign(HorizontalAlignment.CENTER);
}
/**
* Build a {@code LineLabel} from a {@code LineLabelType}
* @param t
* @throws org.orbisgis.coremap.renderer.se.SeExceptions.InvalidStyle
*/
public LineLabel(LineLabelType t) throws InvalidStyle {
super(t);
if(t.getRelativeOrientation() != null){
setOrientation(RelativeOrientation.readFromToken(t.getRelativeOrientation()));
}
}
/**
* Build a {@code LineLabel} from a JAXBElement.
* @param l
* @throws org.orbisgis.coremap.renderer.se.SeExceptions.InvalidStyle
*/
public LineLabel(JAXBElement<LineLabelType> l) throws InvalidStyle {
this(l.getValue());
}
/**
* Gets the orientation of the characters along the line.
*/
public final RelativeOrientation getOrientation() {
return orientation;
}
/**
* Sets the orientation of the characters along the line.
* @param orientation
*/
public final void setOrientation(RelativeOrientation orientation) {
this.orientation = orientation;
}
/**
*
*/
@Override
public void draw(Graphics2D g2, Map<String,Object> map,
Shape shp, boolean selected, MapTransform mt)
throws ParameterException, IOException {
Rectangle2D bounds = getLabel().getBounds(g2, map, mt);
double totalWidth = bounds.getWidth();
// TODO, is shp a polygon ? Yes so create a line like:
/**
* ___________
* _____/ \
* \ \
* / - - - - - - \
* / \
* |_____________________/
*
* And plot label as:
* ___________
* _____/ \
* \ \
* / A L P E S \
* / \
* |_____________________/
*
* Rather than:
* ___________
* _____/ \
* \ \
* / ALPES \
* / \
* |_____________________/
*
*/
VerticalAlignment vA = getVerticalAlign();
HorizontalAlignment hA = getHorizontalAlign();
RelativeOrientation ra = getOrientation();
if (vA == null) {
vA = VerticalAlignment.TOP;
//The four important lines, here, according to the SE norm, are the
//middle line, the baseline, the ascent line and the descent line.
}
if (hA == null) {
hA = HorizontalAlignment.CENTER;
}
if(ra == null) {
ra= RelativeOrientation.NORMAL_UP;
}
double lineLength = ShapeHelper.getLineLength(shp);
double startAt;
double stopAt;
switch (hA) {
case RIGHT:
startAt = lineLength - totalWidth;
stopAt = lineLength;
break;
case LEFT:
startAt = 0.0;
stopAt = totalWidth;
break;
default:
case CENTER:
startAt = (lineLength - totalWidth) / 2.0;
stopAt = (lineLength + totalWidth) / 2.0;
break;
}
if (startAt < 0.0) {
startAt = 0.0;
}
if (stopAt > lineLength){
stopAt = lineLength;
}
Point2D.Double ptStart = ShapeHelper.getPointAt(shp, startAt);
Point2D.Double ptStop = ShapeHelper.getPointAt(shp, stopAt);
int way = 1;
// Do not laid out the label upside-down !
if (ptStart.x > ptStop.x){
// invert line way
way = -1;
startAt = stopAt;
}
double currentPos = startAt;
double glyphWidth;
String text = getLabel().getText().getValue(map);
String[] glyphs = text.split("");
ArrayList<Shape> outlines = new ArrayList<Shape>();
for (String glyph : glyphs) {
if (glyph != null && !glyph.isEmpty()) {
Rectangle2D gBounds = getLabel().getBounds(g2, glyph, map, mt);
glyphWidth = gBounds.getWidth()*way;
Point2D.Double pAt = ShapeHelper.getPointAt(shp, currentPos);
Point2D.Double pAfter = ShapeHelper.getPointAt(shp, currentPos + glyphWidth);
//We compute the angle we must use to rotate our glyph.
double theta = Math.atan2(pAfter.y - pAt.y, pAfter.x - pAt.x);
//We compute the place where we will draw the chatacter, and
//the orientation it must have.
AffineTransform at = AffineTransform.getTranslateInstance(pAt.x, pAt.y);
at.concatenate(AffineTransform.getRotateInstance(theta));
currentPos += glyphWidth;
outlines.add(getLabel().getOutline(g2, glyph, map, mt, at, vA));
} else {
//System.out.println ("Space...");
//currentPos += emWidth*way;
}
}
getLabel().drawOutlines(g2, outlines, map, selected, mt);
}
@Override
public JAXBElement<LineLabelType> getJAXBElement() {
ObjectFactory of = new ObjectFactory();
return of.createLineLabel(this.getJAXBType());
}
/**
* Get a JAXB representation of this {@code LineLabelType}.
* @return
*/
public LineLabelType getJAXBType() {
LineLabelType ll = new LineLabelType();
setJAXBProperties(ll);
return ll;
}
@Override
public List<SymbolizerNode> getChildren() {
List<SymbolizerNode> ls = new ArrayList<SymbolizerNode>();
if (getLabel() != null) {
ls.add(getLabel());
}
return ls;
}
}