/** * 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.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.ObjectFactory; import net.opengis.se._2_0.core.PointLabelType; 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.Uom; import org.orbisgis.coremap.renderer.se.parameter.ParameterException; import org.orbisgis.coremap.renderer.se.parameter.SeParameterFactory; import org.orbisgis.coremap.renderer.se.parameter.real.RealLiteral; import org.orbisgis.coremap.renderer.se.parameter.real.RealParameter; import org.orbisgis.coremap.renderer.se.parameter.real.RealParameterContext; /** * A label located at a single point. In addition to all the {@code Label} characteristics, * it has two additional properties : * <ul><li>A rotation angle, in degrees.</li> * <li>An exclusion zone, ie a zone around the label where no other text will be displayed.</li> * </ul> * @author Alexis Guéganno, Maxence Laurent */ public final class PointLabel extends Label { private RealParameter rotation; private ExclusionZone exclusionZone; /** * Creates a new {@code PointLabel} with default values as detailed in * {@link org.orbisgis.coremap.renderer.se.label.Label#Label() Label} and * {@link org.orbisgis.coremap.renderer.se.label.StyledText#StyledText() StyledText}. * This {@code PointLabel} will be top and right aligned. */ public PointLabel() { super(); rotation = new RealLiteral(0.0); setVerticalAlign(VerticalAlignment.TOP); setHorizontalAlign(HorizontalAlignment.CENTER); } /** * Creates a new {@code PointLabel} from a {@code PointLabelType} instance. * @param plt The input JaXB type * @throws org.orbisgis.coremap.renderer.se.SeExceptions.InvalidStyle */ public PointLabel(PointLabelType plt) throws InvalidStyle { super(plt); if (plt.getExclusionZone() != null) { setExclusionZone(ExclusionZone.createFromJAXBElement(plt.getExclusionZone())); } if (plt.getRotation() != null) { setRotation(SeParameterFactory.createRealParameter(plt.getRotation())); } } /** * Creates a new {@code PointLabel} from a {@code JAXBElement} instance. * @param pl The input JaXB type. * @throws org.orbisgis.coremap.renderer.se.SeExceptions.InvalidStyle */ PointLabel(JAXBElement<PointLabelType> pl) throws InvalidStyle { this(pl.getValue()); } /** * Get the exclusion zone defined for this {@code PointLabel}. In this zone, * we won't draw any other text. * @return * An {@link ExclusionZone} instance. */ public ExclusionZone getExclusionZone() { return exclusionZone; } /** * Set the exclusion zone defined for this {@code PointLabel}. * @param exclusionZone The new exclusion zone */ public void setExclusionZone(ExclusionZone exclusionZone) { this.exclusionZone = exclusionZone; if (exclusionZone != null) { exclusionZone.setParent(this); } } /** * Get the rotation that must be applied to this {@code PointLabel} before rendering. * @return * The rotation, in degrees, as a {@link RealParameter} */ public RealParameter getRotation() { return rotation; } /** * Set the rotation that must be applied to this {@code PointLabel} before rendering. * @param rotation The new rotation to be used. */ public void setRotation(RealParameter rotation) { this.rotation = rotation; if (this.rotation != null) { this.rotation.setContext(RealParameterContext.REAL_CONTEXT); this.rotation.setParent(this); } } @Override public void draw(Graphics2D g2, Map<String, Object> map, Shape shp, boolean selected, MapTransform mt) throws ParameterException, IOException { double x; double y; // TODO RenderPermission ! double deltaX = 0; double deltaY = 0; Rectangle2D bounds = getLabel().getBounds(g2, map, mt); x = shp.getBounds2D().getCenterX() + getHorizontalDisplacement(bounds); y = shp.getBounds2D().getCenterY() + bounds.getHeight() / 2; if (this.exclusionZone != null) { if (this.exclusionZone instanceof ExclusionRadius) { double radius = ((ExclusionRadius) (this.exclusionZone)).getRadius().getValue(map); radius = Uom.toPixel(radius, getUom(), mt.getDpi(), mt.getScaleDenominator(), null); deltaX = radius; deltaY = radius; } else { deltaX = ((ExclusionRectangle) (this.exclusionZone)).getX().getValue(map); deltaY = ((ExclusionRectangle) (this.exclusionZone)).getY().getValue(map); deltaX = Uom.toPixel(deltaX, getUom(), mt.getDpi(), mt.getScaleDenominator(), null); deltaY = Uom.toPixel(deltaY, getUom(), mt.getDpi(), mt.getScaleDenominator(), null); } } AffineTransform at = AffineTransform.getTranslateInstance(x + deltaX, y + deltaY); getLabel().draw(g2, map, selected, mt, at, this.getVerticalAlign()); } /** * Gets the horizontal displacement to the given bounds according to the currently configured * HorizontalAlignment. * @param bounds The bounds of the text to be drawn * @return The displacement. */ private double getHorizontalDisplacement(Rectangle2D bounds){ HorizontalAlignment ha = getHorizontalAlign(); switch(ha){ case CENTER: return -bounds.getWidth()/2.0; case LEFT: return -bounds.getWidth(); default: return 0.0; } } @Override public JAXBElement<PointLabelType> getJAXBElement() { ObjectFactory of = new ObjectFactory(); return of.createPointLabel(getJAXBType()); } /** * Get a JAXB representation of this element. * @return This object as a PointLabelType instance. */ public PointLabelType getJAXBType() { PointLabelType pl = new PointLabelType(); setJAXBProperties(pl); if (exclusionZone != null) { pl.setExclusionZone(exclusionZone.getJAXBElement()); } if (rotation != null) { pl.setRotation(rotation.getJAXBParameterValueType()); } return pl; } @Override public List<SymbolizerNode> getChildren() { List<SymbolizerNode> ls = new ArrayList<SymbolizerNode>(); if (getLabel() != null) { ls.add(getLabel()); } if (exclusionZone != null) { ls.add(exclusionZone); } if (rotation != null) { ls.add(rotation); } return ls; } }